mirror of
https://github.com/Eugeny/tabby.git
synced 2025-07-25 21:28:34 +00:00
Compare commits
101 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c7bee48199 | ||
![]() |
1326fd7355 | ||
![]() |
ee368a3716 | ||
![]() |
c9367d04c3 | ||
![]() |
2f63a1ebbb | ||
![]() |
c956ee1183 | ||
![]() |
f76a5505ec | ||
![]() |
4aafcf82e8 | ||
![]() |
76ffef751c | ||
![]() |
5c22e22caa | ||
![]() |
c98fd2042d | ||
![]() |
ac45f24bf9 | ||
![]() |
60c85c49cc | ||
![]() |
2a1b5d6a30 | ||
![]() |
931335ec31 | ||
![]() |
f3ddb54499 | ||
![]() |
275f9e5633 | ||
![]() |
b988c36bf9 | ||
![]() |
381ee6f1b2 | ||
![]() |
a423447532 | ||
![]() |
bb386f7f8a | ||
![]() |
99a86e7ff5 | ||
![]() |
2e9d8f609e | ||
![]() |
71e6caff0a | ||
![]() |
235a53018e | ||
![]() |
dd22aba099 | ||
![]() |
2db700a77f | ||
![]() |
f5fdf6cf44 | ||
![]() |
8f02239815 | ||
![]() |
e462e207de | ||
![]() |
24210dee38 | ||
![]() |
87a98288b9 | ||
![]() |
be2015a833 | ||
![]() |
75a59769fc | ||
![]() |
c28b474f24 | ||
![]() |
e9ea8b0506 | ||
![]() |
44367465cc | ||
![]() |
c017c42b70 | ||
![]() |
26117dfce0 | ||
![]() |
ae809e9ee2 | ||
![]() |
58516718d6 | ||
![]() |
9dac5cdf9d | ||
![]() |
dbc291ff8c | ||
![]() |
dc5f7991b8 | ||
![]() |
df2e60150c | ||
![]() |
516572f9d9 | ||
![]() |
b3cca4f789 | ||
![]() |
e59ebb76ac | ||
![]() |
0476ef35bb | ||
![]() |
8b3139719a | ||
![]() |
66ebc0dd71 | ||
![]() |
11328d5880 | ||
![]() |
af2fd17c34 | ||
![]() |
d21d019b5c | ||
![]() |
f4a825f67b | ||
![]() |
4ce916241a | ||
![]() |
4780a6b913 | ||
![]() |
58710cfdbe | ||
![]() |
8a6b3a6fbb | ||
![]() |
40897c278b | ||
![]() |
d54dbc3c50 | ||
![]() |
789ca2c635 | ||
![]() |
eacc30bc82 | ||
![]() |
dc7fc30d27 | ||
![]() |
6de6fd8f40 | ||
![]() |
fb9fb57a18 | ||
![]() |
e434fe5a8a | ||
![]() |
1b1127ab28 | ||
![]() |
fe8dd891b4 | ||
![]() |
f7b603a631 | ||
![]() |
44040ba54b | ||
![]() |
f87efcf5bd | ||
![]() |
e2d467046b | ||
![]() |
220ae6ccaa | ||
![]() |
3c6374be19 | ||
![]() |
d32e31d45e | ||
![]() |
d7a33dc0ce | ||
![]() |
bc736dd13a | ||
![]() |
7cf8f8d58e | ||
![]() |
ff0cd36b6a | ||
![]() |
767bc8e56f | ||
![]() |
8801839c7a | ||
![]() |
642293dbdb | ||
![]() |
99e3144ddf | ||
![]() |
c38b684b56 | ||
![]() |
f8871cb1c5 | ||
![]() |
7ab3238617 | ||
![]() |
6d89d7a8d0 | ||
![]() |
e277c52f71 | ||
![]() |
2cafd97751 | ||
![]() |
ad78f38210 | ||
![]() |
a647b394e5 | ||
![]() |
4ec4620cd5 | ||
![]() |
4f32908c48 | ||
![]() |
682b336784 | ||
![]() |
0687e31d21 | ||
![]() |
2e7de08649 | ||
![]() |
88f4c7e835 | ||
![]() |
de3218522e | ||
![]() |
f7ed97b8a4 | ||
![]() |
67190e9622 |
56
.github/dependabot.yml
vendored
Normal file
56
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: npm
|
||||
directory: "/app"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: npm
|
||||
directory: "/terminus-core"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: npm
|
||||
directory: "/terminus-settings"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: npm
|
||||
directory: "/terminus-terminal"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: npm
|
||||
directory: "/terminus-community-color-schemes"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: npm
|
||||
directory: "/terminus-plugin-manager"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: npm
|
||||
directory: "/terminus-ssh"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 20
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Installing Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
node-version: 15
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
|
17
.github/workflows/linux.yml
vendored
17
.github/workflows/linux.yml
vendored
@@ -2,7 +2,7 @@ name: Linux Build
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-16.04
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -15,6 +15,7 @@ jobs:
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo apt-get install bsdtar
|
||||
npm i -g yarn@1.19.1
|
||||
cd app
|
||||
yarn
|
||||
@@ -57,6 +58,8 @@ jobs:
|
||||
mv dist/*.deb artifact-deb/ || true
|
||||
mkdir artifact-rpm
|
||||
mv dist/*.rpm artifact-rpm/ || true
|
||||
mkdir artifact-pacman
|
||||
mv dist/*.pacman artifact-pacman/ || true
|
||||
mkdir artifact-snap
|
||||
mv dist/*.snap artifact-snap/ || true
|
||||
mkdir artifact-tar.gz
|
||||
@@ -65,19 +68,25 @@ jobs:
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload DEB
|
||||
with:
|
||||
name: Linux .deb
|
||||
name: Linux DEB
|
||||
path: artifact-deb
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload RPM
|
||||
with:
|
||||
name: Linux .rpm
|
||||
name: Linux RPM
|
||||
path: artifact-rpm
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload Pacman Package
|
||||
with:
|
||||
name: Linux Pacman
|
||||
path: artifact-pacman
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
name: Upload Snap
|
||||
with:
|
||||
name: Linux .snap
|
||||
name: Linux Snap
|
||||
path: artifact-snap
|
||||
|
||||
- uses: actions/upload-artifact@master
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@ sentry.properties
|
||||
sentry-symbols.js
|
||||
|
||||
terminus-ssh/util/pagent.exe
|
||||
*.psd
|
||||
|
@@ -47,6 +47,7 @@ export class Application {
|
||||
}
|
||||
|
||||
app.commandLine.appendSwitch('disable-http-cache')
|
||||
app.commandLine.appendSwitch('max-active-webgl-contexts', '9000')
|
||||
app.commandLine.appendSwitch('lang', 'EN')
|
||||
app.allowRendererProcessReuse = false
|
||||
|
||||
@@ -211,13 +212,8 @@ export class Application {
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{ role: 'reload' },
|
||||
{ role: 'forceReload' },
|
||||
{ role: 'toggleDevTools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom' },
|
||||
{ role: 'zoomIn' },
|
||||
{ role: 'zoomOut' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' },
|
||||
],
|
||||
},
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import * as nodePTY from 'node-pty'
|
||||
import * as nodePTY from '@terminus-term/node-pty'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { ipcMain } from 'electron'
|
||||
import { Application } from './app'
|
||||
@@ -39,12 +39,22 @@ class PTYDataQueue {
|
||||
totalLength += this.buffers[0].length
|
||||
buffersToSend.push(this.buffers.shift())
|
||||
}
|
||||
|
||||
if (buffersToSend.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let toSend = Buffer.concat(buffersToSend)
|
||||
this.buffers.unshift(toSend.slice(this.maxChunk))
|
||||
toSend = toSend.slice(0, this.maxChunk)
|
||||
if (toSend.length > this.maxChunk) {
|
||||
this.buffers.unshift(toSend.slice(this.maxChunk))
|
||||
toSend = toSend.slice(0, this.maxChunk)
|
||||
}
|
||||
this.onData(toSend)
|
||||
this.delta += toSend.length
|
||||
this.buffers = []
|
||||
|
||||
if (this.buffers.length) {
|
||||
setImmediate(() => this.maybeEmit())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +117,7 @@ export class PTY {
|
||||
}
|
||||
|
||||
export class PTYManager {
|
||||
private ptys: Record<string, PTY> = {}
|
||||
private ptys: Record<string, PTY|undefined> = {}
|
||||
|
||||
init (app: Application): void {
|
||||
//require('./bufferizedPTY')(nodePTY) // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
@@ -122,23 +132,23 @@ export class PTYManager {
|
||||
})
|
||||
|
||||
ipcMain.on('pty:get-pid', (event, id) => {
|
||||
event.returnValue = this.ptys[id].getPID()
|
||||
event.returnValue = this.ptys[id]?.getPID()
|
||||
})
|
||||
|
||||
ipcMain.on('pty:resize', (_event, id, columns, rows) => {
|
||||
this.ptys[id].resize(columns, rows)
|
||||
this.ptys[id]?.resize(columns, rows)
|
||||
})
|
||||
|
||||
ipcMain.on('pty:write', (_event, id, data) => {
|
||||
this.ptys[id].write(Buffer.from(data))
|
||||
this.ptys[id]?.write(Buffer.from(data))
|
||||
})
|
||||
|
||||
ipcMain.on('pty:kill', (_event, id, signal) => {
|
||||
this.ptys[id].kill(signal)
|
||||
this.ptys[id]?.kill(signal)
|
||||
})
|
||||
|
||||
ipcMain.on('pty:ack-data', (_event, id, length) => {
|
||||
this.ptys[id].ackData(length)
|
||||
this.ptys[id]?.ackData(length)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -117,13 +117,16 @@ export class Window {
|
||||
})
|
||||
|
||||
this.window.on('blur', () => {
|
||||
if (this.configStore.appearance?.dockHideOnBlur) {
|
||||
if (this.configStore.appearance.dock !== 'off' && this.configStore.appearance?.dockHideOnBlur) {
|
||||
this.hide()
|
||||
}
|
||||
})
|
||||
|
||||
this.window.loadURL(`file://${app.getAppPath()}/dist/index.html?${this.window.id}`, { extraHeaders: 'pragma: no-cache\n' })
|
||||
|
||||
this.window.webContents.setVisualZoomLevelLimits(1, 1)
|
||||
this.window.webContents.setZoomFactor(1)
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
this.window.setMenu(null)
|
||||
}
|
||||
|
@@ -21,23 +21,23 @@
|
||||
"@angular/forms": "^11.1.1",
|
||||
"@angular/platform-browser": "^11.1.1",
|
||||
"@angular/platform-browser-dynamic": "^11.1.1",
|
||||
"@electron/remote": "^1.0.4",
|
||||
"@electron/remote": "1.0.4",
|
||||
"@ng-bootstrap/ng-bootstrap": "^7.0.0",
|
||||
"@terminus-term/node-pty": "0.10.0-terminus.3",
|
||||
"any-promise": "^1.3.0",
|
||||
"electron-config": "2.0.0",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-promise-ipc": "^2.2.4",
|
||||
"fontmanager-redux": "1.0.0",
|
||||
"glasstron": "0.0.7",
|
||||
"js-yaml": "4.0.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"keytar": "^7.6.0",
|
||||
"mz": "^2.7.0",
|
||||
"native-process-working-directory": "^1.0.2",
|
||||
"ngx-toastr": "^13.2.1",
|
||||
"node-pty": "^0.10.0",
|
||||
"npm": "6",
|
||||
"path": "0.12.7",
|
||||
"rxjs": "^6.6.6",
|
||||
"rxjs": "^6.6.7",
|
||||
"yargs": "^16.2.0",
|
||||
"zone.js": "^0.11.4"
|
||||
},
|
||||
@@ -46,12 +46,12 @@
|
||||
"serialport": "^9.0.7",
|
||||
"windows-blurbehind": "^1.0.1",
|
||||
"windows-native-registry": "^3.0.0",
|
||||
"windows-process-tree": "^0.2.4"
|
||||
"windows-process-tree": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mz": "2.7.3",
|
||||
"@types/node": "14.14.35",
|
||||
"node-abi": "^2.21.0",
|
||||
"node-abi": "^2.26.0",
|
||||
"source-map-support": "^0.5.19"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@@ -21,7 +21,7 @@ if (process.platform === 'win32' && !('HOME' in process.env)) {
|
||||
process.env.HOME = `${process.env.HOMEDRIVE}${process.env.HOMEPATH}`
|
||||
}
|
||||
|
||||
if (process.env.TERMINUS_DEV) {
|
||||
if (process.env.TERMINUS_DEV && !process.env.TERMINUS_FORCE_ANGULAR_PROD) {
|
||||
console.warn('Running in debug mode')
|
||||
} else {
|
||||
enableProdMode()
|
||||
|
@@ -17,6 +17,10 @@ body {
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
& > svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -104,3 +108,33 @@ ngb-typeahead-window {
|
||||
max-height: 60vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
.hover-reveal {
|
||||
opacity: 0;
|
||||
|
||||
.hover-reveal-parent:hover &,
|
||||
*:hover > &,
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes terminalShakeFrames {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
25% {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(-5px);
|
||||
}
|
||||
75% {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
@@ -44,7 +44,7 @@ module.exports = {
|
||||
glasstron: 'commonjs glasstron',
|
||||
mz: 'commonjs mz',
|
||||
npm: 'commonjs npm',
|
||||
'node-pty': 'commonjs node-pty',
|
||||
'@terminus-term/node-pty': 'commonjs @terminus-term/node-pty',
|
||||
path: 'commonjs path',
|
||||
rxjs: 'commonjs rxjs',
|
||||
'rxjs/operators': 'commonjs rxjs/operators',
|
||||
|
@@ -51,7 +51,7 @@
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@electron/remote@^1.0.4":
|
||||
"@electron/remote@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-1.0.4.tgz#f1c8cf3560bab762b462bfae9991919cced8bc33"
|
||||
integrity sha512-kguDJRhL3ZynHrkbX8Tr7xoAzGsNgh4eqXkycXb6cgXbOgehGqkBVe+MnjSVMXz3QJykerGKPy28gqcM7AFGYw==
|
||||
@@ -143,6 +143,13 @@
|
||||
dependencies:
|
||||
debug "^4.3.1"
|
||||
|
||||
"@terminus-term/node-pty@0.10.0-terminus.3":
|
||||
version "0.10.0-terminus.3"
|
||||
resolved "https://registry.yarnpkg.com/@terminus-term/node-pty/-/node-pty-0.10.0-terminus.3.tgz#9dbd64d52afda5079e66265a89d313fe42affab7"
|
||||
integrity sha512-HvIOts22dnoBXhRfLiK9DyPasuixYVgEUvgqZmOr0B0Ki9tF8e074oYPUtzLRll6Y553QiUzTWhriCS99MChNQ==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
|
||||
"@types/mz@2.7.3":
|
||||
version "2.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/mz/-/mz-2.7.3.tgz#e42a21e73f5f9340fe4a176981fafb1eb8cc6c12"
|
||||
@@ -250,12 +257,7 @@ ansistyles@~0.1.3:
|
||||
resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz"
|
||||
integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=
|
||||
|
||||
any-promise@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz"
|
||||
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
|
||||
|
||||
any-promise@^1.3.0:
|
||||
any-promise@^1.0.0, any-promise@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
|
||||
@@ -1316,9 +1318,9 @@ has@^1.0.3:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
hosted-git-info@^2.1.4, hosted-git-info@^2.7.1, hosted-git-info@^2.8.8:
|
||||
version "2.8.8"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
|
||||
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
|
||||
version "2.8.9"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
||||
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
|
||||
|
||||
http-cache-semantics@^3.8.1:
|
||||
version "3.8.1"
|
||||
@@ -1595,10 +1597,10 @@ isstream@~0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz"
|
||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||
|
||||
js-yaml@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f"
|
||||
integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
|
||||
js-yaml@4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
|
||||
@@ -2103,10 +2105,10 @@ ngx-toastr@^13.2.1:
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
node-abi@^2.20.0, node-abi@^2.21.0, node-abi@^2.7.0:
|
||||
version "2.21.0"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.21.0.tgz#c2dc9ebad6f4f53d6ea9b531e7b8faad81041d48"
|
||||
integrity sha512-smhrivuPqEM3H5LmnY3KU6HfYv0u4QklgAxfFyRNujKUzbUcYZ+Jc2EhukB9SRcD2VpqhxM7n/MIcp1Ua1/JMg==
|
||||
node-abi@^2.20.0, node-abi@^2.26.0, node-abi@^2.7.0:
|
||||
version "2.26.0"
|
||||
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.26.0.tgz#355d5d4bc603e856f74197adbf3f5117a396ba40"
|
||||
integrity sha512-ag/Vos/mXXpWLLAYWsAoQdgS+gW7IwvgMLOgqopm/DbzAjazLltzgzpVMsFlgmo9TzG5hGXeaBZx2AI731RIsQ==
|
||||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
@@ -2146,13 +2148,6 @@ node-gyp@^5.0.2, node-gyp@^5.1.0:
|
||||
tar "^4.4.12"
|
||||
which "^1.3.1"
|
||||
|
||||
node-pty@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.0.tgz#c98d23967b076b35c9fb216c542a04d0b5db4821"
|
||||
integrity sha512-Q65ookKbjhqWUYKmtZ6iPn0nnqNdzpm3YJOBmzwWJde/TrenBxK9FgqGGtSW0Wjz4YsR1grQF4a7RS5nBwuW9A==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
|
||||
noop-logger@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz"
|
||||
@@ -3026,10 +3021,10 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
||||
dependencies:
|
||||
aproba "^1.1.1"
|
||||
|
||||
rxjs@^6.6.6:
|
||||
version "6.6.6"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70"
|
||||
integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==
|
||||
rxjs@^6.6.7:
|
||||
version "6.6.7"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
|
||||
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
@@ -3226,9 +3221,9 @@ sshpk@^1.7.0:
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
ssri@^6.0.0, ssri@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
|
||||
integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5"
|
||||
integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==
|
||||
dependencies:
|
||||
figgy-pudding "^3.5.1"
|
||||
|
||||
@@ -3673,10 +3668,10 @@ windows-native-registry@^3.0.0:
|
||||
dependencies:
|
||||
node-addon-api "^3.0.0"
|
||||
|
||||
windows-process-tree@^0.2.4:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.2.4.tgz#747af587b54cc6c996f2be0836cc8a8fd0dc038f"
|
||||
integrity sha512-9gag9AHm3Iin/4YC1EwoIfZlqW/rG2eV7rJZ4Fy5NnAMGdewmnwsie5Rz+CJo2vSolqzzfw7hPeu3oOdniNejg==
|
||||
windows-process-tree@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.3.0.tgz#cf0d9291b22fba2a7f5a687c8272866e28fbcafd"
|
||||
integrity sha512-0bKI4gcd5MOsOpn2TdStCSlnjThtH6BdHrocekY9qCgTqgEtdaUs0B5BaqyzF9jXoTSwz38NMdE1F55o4fgv9Q==
|
||||
dependencies:
|
||||
nan "^2.13.2"
|
||||
|
||||
@@ -3745,9 +3740,9 @@ xtend@~4.0.1:
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
y18n@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
||||
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
|
||||
integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
|
||||
|
||||
y18n@^4.0.0:
|
||||
version "4.0.1"
|
||||
|
BIN
build/icons/Icon-MacOS-512x512@2x.png
Normal file
BIN
build/icons/Icon-MacOS-512x512@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 166 KiB |
Binary file not shown.
@@ -70,6 +70,8 @@ linux:
|
||||
artifactName: terminus-${version}-linux.${ext}
|
||||
executableArgs:
|
||||
- "--no-sandbox"
|
||||
desktop:
|
||||
StartupWMClass: terminus
|
||||
snap:
|
||||
plugs:
|
||||
- default
|
||||
@@ -86,9 +88,12 @@ deb:
|
||||
- libxtst6
|
||||
- libnss3
|
||||
afterInstall: build/linux/after-install.tpl
|
||||
pacman:
|
||||
depends:
|
||||
- gnome-keyring
|
||||
- libsecret
|
||||
rpm:
|
||||
depends:
|
||||
- screen
|
||||
- gnome-keyring
|
||||
fpm:
|
||||
- '--rpm-rpmbuild-define'
|
||||
|
16
package.json
16
package.json
@@ -1,30 +1,30 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||
"@sentry/cli": "^1.63.1",
|
||||
"@sentry/cli": "^1.64.2",
|
||||
"@sentry/electron": "^2.4.0",
|
||||
"@terminus-term/to-string-loader": "1.1.7-beta.1",
|
||||
"@types/electron-config": "^3.2.2",
|
||||
"@types/electron-debug": "^2.1.0",
|
||||
"@types/fs-extra": "^9.0.9",
|
||||
"@types/fs-extra": "^9.0.11",
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
"@types/node": "14.14.35",
|
||||
"@types/webpack-env": "^1.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.14.1",
|
||||
"@typescript-eslint/parser": "^4.17.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
"apply-loader": "2.0.0",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"compare-versions": "^3.6.0",
|
||||
"core-js": "^3.9.1",
|
||||
"core-js": "^3.12.1",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "5.2.0",
|
||||
"electron": "12.0.2",
|
||||
"electron": "12.0.6",
|
||||
"electron-builder": "22.10.5",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-installer-snap": "^5.1.0",
|
||||
"electron-notarize": "^1.0.0",
|
||||
"electron-rebuild": "^2.3.5",
|
||||
"eslint": "^7.18.0",
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-plugin-import": "^2.21.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"graceful-fs": "^4.2.6",
|
||||
@@ -33,7 +33,7 @@
|
||||
"lru-cache": "^6.0.0",
|
||||
"macos-release": "^2.4.1",
|
||||
"node-abi": "^2.21.0",
|
||||
"node-gyp": "^7.1.2",
|
||||
"node-gyp": "^8.0.0",
|
||||
"node-sass": "^5.0.0",
|
||||
"npmlog": "4.1.2",
|
||||
"npx": "^10.2.2",
|
||||
@@ -52,7 +52,7 @@
|
||||
"style-loader": "^2.0.0",
|
||||
"svg-inline-loader": "^0.8.2",
|
||||
"tslib": "^2.1.0",
|
||||
"typedoc": "^0.20.32",
|
||||
"typedoc": "^0.20.36",
|
||||
"typescript": "^3.9.9",
|
||||
"url-loader": "^4.1.1",
|
||||
"val-loader": "3.1.0",
|
||||
|
@@ -7,7 +7,7 @@ const isCI = !!process.env.GITHUB_REF
|
||||
|
||||
builder({
|
||||
dir: true,
|
||||
linux: ['deb', 'tar.gz', 'rpm'],
|
||||
linux: ['deb', 'tar.gz', 'rpm', 'pacman'],
|
||||
config: {
|
||||
extraMetadata: {
|
||||
version: vars.version,
|
||||
|
@@ -9,7 +9,7 @@ sh.exec(`${sentryCli} releases new ${vars.version}`)
|
||||
if (process.platform === 'darwin') {
|
||||
for (const path of [
|
||||
'app/node_modules/@serialport/bindings/build/Release/bindings.node',
|
||||
'app/node_modules/node-pty/build/Release/pty.node',
|
||||
'app/node_modules/@terminus-term/node-pty/build/Release/pty.node',
|
||||
'app/node_modules/fontmanager-redux/build/Release/fontmanager.node',
|
||||
'app/node_modules/macos-native-processlist/build/Release/native.node',
|
||||
]) {
|
||||
|
@@ -17,7 +17,7 @@
|
||||
"author": "Eugene Pankov",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@electron/remote": "^1.0.4",
|
||||
"@electron/remote": "1.0.4",
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
"@types/shell-escape": "^0.2.0",
|
||||
"@types/winston": "^2.3.6",
|
||||
@@ -31,7 +31,7 @@
|
||||
"mixpanel": "^0.10.2",
|
||||
"ng2-dnd": "^5.0.2",
|
||||
"ngx-perfect-scrollbar": "^10.1.0",
|
||||
"readable-stream": "2.3.7",
|
||||
"readable-stream": "3.6.0",
|
||||
"shell-escape": "^0.2.0",
|
||||
"uuid": "^8.0.0",
|
||||
"winston": "^3.3.3"
|
||||
|
@@ -1,3 +1,4 @@
|
||||
export { BaseComponent, SubscriptionContainer } from '../components/base.component'
|
||||
export { BaseTabComponent, BaseTabProcess } from '../components/baseTab.component'
|
||||
export { TabHeaderComponent } from '../components/tabHeader.component'
|
||||
export { SplitTabComponent, SplitContainer } from '../components/splitTab.component'
|
||||
|
@@ -146,7 +146,7 @@ $side-tab-width: 200px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
left: 100%;
|
||||
left: -1000%;
|
||||
|
||||
&.content-tab-active {
|
||||
left: 0;
|
||||
|
54
terminus-core/src/components/base.component.ts
Normal file
54
terminus-core/src/components/base.component.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Observable, Subscription } from 'rxjs'
|
||||
|
||||
interface CancellableEvent {
|
||||
element: HTMLElement
|
||||
event: string
|
||||
handler: EventListenerOrEventListenerObject
|
||||
options?: boolean|AddEventListenerOptions
|
||||
}
|
||||
|
||||
export class SubscriptionContainer {
|
||||
private subscriptions: Subscription[] = []
|
||||
private events: CancellableEvent[] = []
|
||||
|
||||
addEventListener (element: HTMLElement, event: string, handler: EventListenerOrEventListenerObject, options?: boolean|AddEventListenerOptions): void {
|
||||
element.addEventListener(event, handler, options)
|
||||
this.events.push({
|
||||
element,
|
||||
event,
|
||||
handler,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
subscribe <T> (observable: Observable<T>, handler: (v: T) => void): void {
|
||||
this.subscriptions.push(observable.subscribe(handler))
|
||||
}
|
||||
|
||||
cancelAll (): void {
|
||||
for (const s of this.subscriptions) {
|
||||
s.unsubscribe()
|
||||
}
|
||||
for (const e of this.events) {
|
||||
e.element.removeEventListener(e.event, e.handler, e.options)
|
||||
}
|
||||
this.subscriptions = []
|
||||
this.events = []
|
||||
}
|
||||
}
|
||||
|
||||
export class BaseComponent {
|
||||
private subscriptionContainer = new SubscriptionContainer()
|
||||
|
||||
addEventListenerUntilDestroyed (element: HTMLElement, event: string, handler: EventListenerOrEventListenerObject, options?: boolean|AddEventListenerOptions): void {
|
||||
this.subscriptionContainer.addEventListener(element, event, handler, options)
|
||||
}
|
||||
|
||||
subscribeUntilDestroyed <T> (observable: Observable<T>, handler: (v: T) => void): void {
|
||||
this.subscriptionContainer.subscribe(observable, handler)
|
||||
}
|
||||
|
||||
ngOnDestroy (): void {
|
||||
this.subscriptionContainer.cancelAll()
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { ViewRef } from '@angular/core'
|
||||
import { RecoveryToken } from '../api/tabRecovery'
|
||||
import { BaseComponent } from './base.component'
|
||||
|
||||
/**
|
||||
* Represents an active "process" inside a tab,
|
||||
@@ -13,7 +14,7 @@ export interface BaseTabProcess {
|
||||
/**
|
||||
* Abstract base class for custom tab components
|
||||
*/
|
||||
export abstract class BaseTabComponent {
|
||||
export abstract class BaseTabComponent extends BaseComponent {
|
||||
/**
|
||||
* Parent tab (usually a SplitTabComponent)
|
||||
*/
|
||||
@@ -69,6 +70,7 @@ export abstract class BaseTabComponent {
|
||||
get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint }
|
||||
|
||||
protected constructor () {
|
||||
super()
|
||||
this.focused$.subscribe(() => {
|
||||
this.hasFocus = true
|
||||
})
|
||||
@@ -158,10 +160,17 @@ export abstract class BaseTabComponent {
|
||||
this.blurred.complete()
|
||||
this.titleChange.complete()
|
||||
this.progress.complete()
|
||||
this.activity.complete()
|
||||
this.recoveryStateChangedHint.complete()
|
||||
if (!skipDestroyedEvent) {
|
||||
this.destroyed.next()
|
||||
}
|
||||
this.destroyed.complete()
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
ngOnDestroy (): void {
|
||||
this.destroy()
|
||||
super.ngOnDestroy()
|
||||
}
|
||||
}
|
||||
|
@@ -17,3 +17,8 @@
|
||||
.title {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Observable, Subject, Subscription } from 'rxjs'
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { Component, Injectable, ViewChild, ViewContainerRef, EmbeddedViewRef, AfterViewInit, OnDestroy } from '@angular/core'
|
||||
import { BaseTabComponent, BaseTabProcess } from './baseTab.component'
|
||||
import { TabRecoveryProvider, RecoveredTab, RecoveryToken } from '../api/tabRecovery'
|
||||
@@ -163,7 +163,6 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
/** @hidden */
|
||||
private focusedTab: BaseTabComponent|null = null
|
||||
private maximizedTab: BaseTabComponent|null = null
|
||||
private hotkeysSubscription: Subscription
|
||||
private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
|
||||
|
||||
private tabAdded = new Subject<BaseTabComponent>()
|
||||
@@ -210,7 +209,7 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
})
|
||||
this.blurred$.subscribe(() => this.getAllTabs().forEach(x => x.emitBlurred()))
|
||||
|
||||
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
this.subscribeUntilDestroyed(this.hotkeys.matchedHotkey, hotkey => {
|
||||
if (!this.hasFocus || !this.focusedTab) {
|
||||
return
|
||||
}
|
||||
@@ -272,7 +271,9 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
|
||||
/** @hidden */
|
||||
ngOnDestroy (): void {
|
||||
this.hotkeysSubscription.unsubscribe()
|
||||
this.tabAdded.complete()
|
||||
this.tabRemoved.complete()
|
||||
super.ngOnDestroy()
|
||||
}
|
||||
|
||||
/** @returns Flat list of all sub-tabs */
|
||||
@@ -497,18 +498,18 @@ export class SplitTabComponent extends BaseTabComponent implements AfterViewInit
|
||||
const ref = this.viewContainer.insert(tab.hostView) as EmbeddedViewRef<any> // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
this.viewRefs.set(tab, ref)
|
||||
|
||||
ref.rootNodes[0].addEventListener('click', () => this.focus(tab))
|
||||
tab.addEventListenerUntilDestroyed(ref.rootNodes[0], 'click', () => this.focus(tab))
|
||||
|
||||
tab.titleChange$.subscribe(t => this.setTitle(t))
|
||||
tab.activity$.subscribe(a => a ? this.displayActivity() : this.clearActivity())
|
||||
tab.progress$.subscribe(p => this.setProgress(p))
|
||||
tab.subscribeUntilDestroyed(tab.titleChange$, t => this.setTitle(t))
|
||||
tab.subscribeUntilDestroyed(tab.activity$, a => a ? this.displayActivity() : this.clearActivity())
|
||||
tab.subscribeUntilDestroyed(tab.progress$, p => this.setProgress(p))
|
||||
if (tab.title) {
|
||||
this.setTitle(tab.title)
|
||||
}
|
||||
tab.recoveryStateChangedHint$.subscribe(() => {
|
||||
tab.subscribeUntilDestroyed(tab.recoveryStateChangedHint$, () => {
|
||||
this.recoveryStateChangedHint.next()
|
||||
})
|
||||
tab.destroyed$.subscribe(() => {
|
||||
tab.subscribeUntilDestroyed(tab.destroyed$, () => {
|
||||
this.removeTab(tab)
|
||||
})
|
||||
}
|
||||
|
@@ -66,7 +66,7 @@ $tabs-height: 38px;
|
||||
$button-size: 26px;
|
||||
width: $button-size;
|
||||
height: $button-size;
|
||||
border-radius: $button-size / 2;
|
||||
border-radius: $button-size / 6;
|
||||
line-height: $button-size;
|
||||
align-self: center;
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import { ElectronService } from '../services/electron.service'
|
||||
import { AppService } from '../services/app.service'
|
||||
import { HostAppService, Platform } from '../services/hostApp.service'
|
||||
import { ConfigService } from '../services/config.service'
|
||||
import { BaseComponent } from './base.component'
|
||||
|
||||
/** @hidden */
|
||||
export interface SortableComponentProxy {
|
||||
@@ -23,7 +24,7 @@ export interface SortableComponentProxy {
|
||||
template: require('./tabHeader.component.pug'),
|
||||
styles: [require('./tabHeader.component.scss')],
|
||||
})
|
||||
export class TabHeaderComponent {
|
||||
export class TabHeaderComponent extends BaseComponent {
|
||||
@Input() index: number
|
||||
@Input() @HostBinding('class.active') active: boolean
|
||||
@Input() tab: BaseTabComponent
|
||||
@@ -41,7 +42,8 @@ export class TabHeaderComponent {
|
||||
@Inject(SortableComponent) private parentDraggable: SortableComponentProxy,
|
||||
@Optional() @Inject(TabContextMenuItemProvider) protected contextMenuProviders: TabContextMenuItemProvider[],
|
||||
) {
|
||||
this.hotkeys.matchedHotkey.subscribe((hotkey) => {
|
||||
super()
|
||||
this.subscribeUntilDestroyed(this.hotkeys.matchedHotkey, (hotkey) => {
|
||||
if (this.app.activeTab === this.tab) {
|
||||
if (hotkey === 'rename-tab') {
|
||||
this.showRenameTabModal()
|
||||
@@ -52,7 +54,7 @@ export class TabHeaderComponent {
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.tab.progress$.subscribe(progress => {
|
||||
this.subscribeUntilDestroyed(this.tab.progress$, progress => {
|
||||
this.zone.run(() => {
|
||||
this.progress = progress
|
||||
})
|
||||
|
@@ -32,7 +32,7 @@ export class ElectronService {
|
||||
this.clipboard = electron.clipboard
|
||||
this.ipcRenderer = electron.ipcRenderer
|
||||
|
||||
this.process = remote.process
|
||||
this.process = remote.getGlobal('process')
|
||||
this.app = remote.app
|
||||
this.screen = remote.screen
|
||||
this.dialog = remote.dialog
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Injectable, Inject, NgZone, EventEmitter } from '@angular/core'
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { HotkeyDescription, HotkeyProvider } from '../api/hotkeyProvider'
|
||||
import { stringifyKeySequence } from './hotkeys.util'
|
||||
import { stringifyKeySequence, EventData } from './hotkeys.util'
|
||||
import { ConfigService } from './config.service'
|
||||
import { ElectronService } from './electron.service'
|
||||
import { HostAppService } from './hostApp.service'
|
||||
@@ -14,10 +14,6 @@ export interface PartialHotkeyMatch {
|
||||
|
||||
const KEY_TIMEOUT = 2000
|
||||
|
||||
interface EventBufferEntry {
|
||||
event: KeyboardEvent
|
||||
time: number
|
||||
}
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class HotkeysService {
|
||||
@@ -32,7 +28,7 @@ export class HotkeysService {
|
||||
get hotkey$ (): Observable<string> { return this._hotkey }
|
||||
|
||||
private _hotkey = new Subject<string>()
|
||||
private currentKeystrokes: EventBufferEntry[] = []
|
||||
private currentKeystrokes: EventData[] = []
|
||||
private disabledLevel = 0
|
||||
private hotkeyDescriptions: HotkeyDescription[] = []
|
||||
|
||||
@@ -73,7 +69,16 @@ export class HotkeysService {
|
||||
*/
|
||||
pushKeystroke (name: string, nativeEvent: KeyboardEvent): void {
|
||||
(nativeEvent as any).event = name
|
||||
this.currentKeystrokes.push({ event: nativeEvent, time: performance.now() })
|
||||
this.currentKeystrokes.push({
|
||||
ctrlKey: nativeEvent.ctrlKey,
|
||||
metaKey: nativeEvent.metaKey,
|
||||
altKey: nativeEvent.altKey,
|
||||
shiftKey: nativeEvent.shiftKey,
|
||||
code: nativeEvent.code,
|
||||
key: nativeEvent.key,
|
||||
eventName: name,
|
||||
time: performance.now(),
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +109,7 @@ export class HotkeysService {
|
||||
|
||||
getCurrentKeystrokes (): string[] {
|
||||
this.currentKeystrokes = this.currentKeystrokes.filter(x => performance.now() - x.time < KEY_TIMEOUT)
|
||||
return stringifyKeySequence(this.currentKeystrokes.map(x => x.event))
|
||||
return stringifyKeySequence(this.currentKeystrokes)
|
||||
}
|
||||
|
||||
getCurrentFullyMatchedHotkey (): string|null {
|
||||
|
@@ -10,15 +10,26 @@ export const altKeyName = {
|
||||
linux: 'Alt',
|
||||
}[process.platform]
|
||||
|
||||
export interface EventData {
|
||||
ctrlKey: boolean
|
||||
metaKey: boolean
|
||||
altKey: boolean
|
||||
shiftKey: boolean
|
||||
key: string
|
||||
code: string
|
||||
eventName: string
|
||||
time: number
|
||||
}
|
||||
|
||||
const REGEX_LATIN_KEYNAME = /^[A-Za-z]$/
|
||||
|
||||
export function stringifyKeySequence (events: KeyboardEvent[]): string[] {
|
||||
export function stringifyKeySequence (events: EventData[]): string[] {
|
||||
const items: string[] = []
|
||||
events = events.slice()
|
||||
|
||||
while (events.length > 0) {
|
||||
const event = events.shift()!
|
||||
if ((event as any).event === 'keydown') {
|
||||
if (event.eventName === 'keydown') {
|
||||
const itemKeys: string[] = []
|
||||
if (event.ctrlKey) {
|
||||
itemKeys.push('Ctrl')
|
||||
@@ -51,8 +62,8 @@ export function stringifyKeySequence (events: KeyboardEvent[]): string[] {
|
||||
Period: '.',
|
||||
Slash: '/',
|
||||
Backslash: '\\',
|
||||
IntlBackslash: '\\',
|
||||
Backquote: '`',
|
||||
IntlBackslash: '`',
|
||||
Backquote: '~', // Electron says it's the tilde
|
||||
Minus: '-',
|
||||
Equal: '=',
|
||||
Semicolon: ';',
|
||||
|
@@ -84,7 +84,12 @@ export class UpdaterService {
|
||||
this.electron.autoUpdater.on('error', onError)
|
||||
this.electron.autoUpdater.on('update-not-available', onNoUpdate)
|
||||
this.electron.autoUpdater.on('update-available', onUpdate)
|
||||
this.electron.autoUpdater.checkForUpdates()
|
||||
try {
|
||||
this.electron.autoUpdater.checkForUpdates()
|
||||
} catch (e) {
|
||||
this.electronUpdaterAvailable = false
|
||||
this.logger.info('Electron updater unavailable, falling back', e)
|
||||
}
|
||||
})
|
||||
|
||||
this.electron.autoUpdater.on('update-available', () => {
|
||||
|
@@ -239,10 +239,6 @@ hotkey-input-modal {
|
||||
border: none;
|
||||
border-top: 1px solid rgba(255, 255, 255, .1);
|
||||
|
||||
&:not(.combi) {
|
||||
padding: $list-group-item-padding-y $list-group-item-padding-x;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
@@ -46,7 +46,6 @@ $body-color: #ccc;
|
||||
$body-bg: #131d27;
|
||||
$body-bg2: #20333e;
|
||||
|
||||
|
||||
$font-family-sans-serif: "Source Sans Pro";
|
||||
$font-family-monospace: "Source Code Pro";
|
||||
$font-size-base: 14rem / 16;
|
||||
@@ -55,6 +54,12 @@ $font-size-sm: .85rem;
|
||||
|
||||
$line-height-base: 1.6;
|
||||
|
||||
$border-radius: .4rem;
|
||||
$border-radius-lg: .6rem;
|
||||
$border-radius-sm: .2rem;
|
||||
|
||||
// -----
|
||||
|
||||
$headings-color: #ced9e2;
|
||||
$headings-font-weight: lighter;
|
||||
|
||||
|
@@ -11,20 +11,20 @@
|
||||
enabled "2.0.x"
|
||||
kuler "^2.0.0"
|
||||
|
||||
"@electron/remote@^1.0.4":
|
||||
"@electron/remote@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-1.0.4.tgz#f1c8cf3560bab762b462bfae9991919cced8bc33"
|
||||
integrity sha512-kguDJRhL3ZynHrkbX8Tr7xoAzGsNgh4eqXkycXb6cgXbOgehGqkBVe+MnjSVMXz3QJykerGKPy28gqcM7AFGYw==
|
||||
|
||||
"@types/js-yaml@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.0.tgz#d1a11688112091f2c711674df3a65ea2f47b5dfb"
|
||||
integrity sha512-4vlpCM5KPCL5CfGmTbpjwVKbISRYhduEJvvUWsH5EB7QInhEj94XPZ3ts/9FPiLZFqYO0xoW4ZL8z2AabTGgJA==
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.1.tgz#5544730b65a480b18ace6b6ce914e519cec2d43b"
|
||||
integrity sha512-xdOvNmXmrZqqPy3kuCQ+fz6wA0xU5pji9cd1nDrflWaAWtYLLGk5ykW0H6yg5TVyehHP1pfmuuSaZkhP+kspVA==
|
||||
|
||||
"@types/semver@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb"
|
||||
integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==
|
||||
"@types/semver@^7.3.5":
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.5.tgz#74deebbbcb1e86634dbf10a5b5e8798626f5a597"
|
||||
integrity sha512-iotVxtCCsPLRAvxMFFgxL8HD2l4mAZ2Oin7/VJ2ooWO0VOK4EGOGmZWZn1uCq7RofR3I/1IOSjCHlFT71eVK0Q==
|
||||
|
||||
"@types/shell-escape@^0.2.0":
|
||||
version "0.2.0"
|
||||
@@ -55,11 +55,6 @@ async@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
|
||||
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
|
||||
|
||||
at-least-node@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
|
||||
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
|
||||
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
@@ -72,10 +67,10 @@ bootstrap@^4.1.3:
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.3.tgz#c6a72b355aaf323920be800246a6e4ef30997fe6"
|
||||
integrity sha512-o9ppKQioXGqhw8Z7mah6KdTYpNQY//tipnkxppWhPbiSWdD+1raYsnhwEZjkTHYbGee4cVQ0Rx65EhOY/HNLcQ==
|
||||
|
||||
builder-util-runtime@8.7.3:
|
||||
version "8.7.3"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.3.tgz#0aaafa52d25295c939496f62231ca9ff06c30e40"
|
||||
integrity sha512-1Q2ReBqFblimF5g/TLg2+0M5Xzv0Ih5LxJ/BMWXvEy/e6pQKeeEpbkPMGsN6OiQgkygaZo5VXCXIjOkOQG5EoQ==
|
||||
builder-util-runtime@8.7.5:
|
||||
version "8.7.5"
|
||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.7.5.tgz#fbe59e274818885e0d2e358d5b7017c34ae6b0f5"
|
||||
integrity sha512-fgUFHKtMNjdvH6PDRFntdIGUPgwZ69sXsAqEulCtoiqgWes5agrMq/Ud274zjJRTbckYh2PHh8/1CpFc6dpsbQ==
|
||||
dependencies:
|
||||
debug "^4.3.2"
|
||||
sax "^1.2.4"
|
||||
@@ -136,9 +131,9 @@ colorspace@1.1.x:
|
||||
text-hex "1.0.x"
|
||||
|
||||
core-js@^3.1.2:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.1.tgz#cec8de593db8eb2a85ffb0dbdeb312cb6e5460ae"
|
||||
integrity sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==
|
||||
version "3.12.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.12.1.tgz#6b5af4ff55616c08a44d386f1f510917ff204112"
|
||||
integrity sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
@@ -165,17 +160,18 @@ deepmerge@^4.1.1:
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
electron-updater@^4.0.6:
|
||||
version "4.3.8"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.8.tgz#94f1731682a756385726183e2b04b959cb319456"
|
||||
integrity sha512-/tB82Ogb2LqaXrUzAD8waJC+TZV52Pr0Znfj7w+i4D+jA2GgrKFI3Pxjp+36y9FcBMQz7kYsMHcB6c5zBJao+A==
|
||||
version "4.3.9"
|
||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.3.9.tgz#247c660bafad7c07935e1b81acd3e9a5fd733154"
|
||||
integrity sha512-LCNfedSwZfS4Hza+pDyPR05LqHtGorCStaBgVpRnfKxOlZcvpYEX0AbMeH5XUtbtGRoH2V8osbbf2qKPNb7AsA==
|
||||
dependencies:
|
||||
"@types/semver" "^7.3.4"
|
||||
builder-util-runtime "8.7.3"
|
||||
fs-extra "^9.1.0"
|
||||
js-yaml "^4.0.0"
|
||||
"@types/semver" "^7.3.5"
|
||||
builder-util-runtime "8.7.5"
|
||||
fs-extra "^10.0.0"
|
||||
js-yaml "^4.1.0"
|
||||
lazy-val "^1.0.4"
|
||||
lodash.escaperegexp "^4.1.2"
|
||||
lodash.isequal "^4.5.0"
|
||||
semver "^7.3.4"
|
||||
semver "^7.3.5"
|
||||
|
||||
enabled@2.0.x:
|
||||
version "2.0.0"
|
||||
@@ -214,12 +210,11 @@ follow-redirects@^1.10.0:
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||
|
||||
fs-extra@^9.1.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
|
||||
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
|
||||
fs-extra@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"
|
||||
integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==
|
||||
dependencies:
|
||||
at-least-node "^1.0.0"
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
@@ -269,10 +264,10 @@ isobject@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||
|
||||
js-yaml@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f"
|
||||
integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
|
||||
js-yaml@^4.0.0, js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
|
||||
@@ -300,6 +295,11 @@ lazy-val@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.4.tgz#882636a7245c2cfe6e0a4e3ba6c5d68a137e5c65"
|
||||
integrity sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==
|
||||
|
||||
lodash.escaperegexp@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
|
||||
integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=
|
||||
|
||||
lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
@@ -341,9 +341,9 @@ ng2-dnd@^5.0.2:
|
||||
integrity sha512-5mWWBePwvEPsNd/HkdbD543Q9mPyJofL6zkNydl8/Ah3qrrvZT2DaEPbknY08OgkXpI2qUGksc01OzzVlRQ9dQ==
|
||||
|
||||
ngx-perfect-scrollbar@^10.1.0:
|
||||
version "10.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ngx-perfect-scrollbar/-/ngx-perfect-scrollbar-10.1.0.tgz#6f7e2d8c849e595077b1c71992b6b544d56084d7"
|
||||
integrity sha512-CQ4pthb+UOoccTh3dOVcmBJsUILpHNBsKMHatif6AB2jsvhH6y2O6elMaoslhQEFqpv1fJlrU25AKIUJQZIA4A==
|
||||
version "10.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ngx-perfect-scrollbar/-/ngx-perfect-scrollbar-10.1.1.tgz#f89832b9109e89bb59d516184638accd028e9735"
|
||||
integrity sha512-f9IaDJGlBzSxnJ3Ki76n2JdzfQngUFyCf0E+CuVLaR5jL0IJDcTu7vOs8wexXunRMTd8xvIv0+sdIxf8hXAGWg==
|
||||
dependencies:
|
||||
perfect-scrollbar "1.5.0"
|
||||
resize-observer-polyfill "^1.5.0"
|
||||
@@ -366,7 +366,16 @@ process-nextick-args@~2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
readable-stream@2.3.7, readable-stream@^2.3.7:
|
||||
readable-stream@3.6.0, readable-stream@^3.4.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
dependencies:
|
||||
inherits "^2.0.3"
|
||||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
readable-stream@^2.3.7:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
||||
@@ -379,15 +388,6 @@ readable-stream@2.3.7, readable-stream@^2.3.7:
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@^3.4.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
dependencies:
|
||||
inherits "^2.0.3"
|
||||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
resize-observer-polyfill@^1.5.0:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
|
||||
@@ -408,10 +408,10 @@ sax@^1.2.4:
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
semver@^7.3.4:
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
|
||||
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
|
||||
semver@^7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
|
@@ -57,6 +57,7 @@ export class PluginManagerService {
|
||||
}))),
|
||||
map(plugins => plugins.filter(x => x.packageName.startsWith(NAME_PREFIX))),
|
||||
map(plugins => plugins.filter(x => !BLACKLIST.includes(x.packageName))),
|
||||
map(plugins => plugins.sort((a, b) => a.name.localeCompare(b.name))),
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -188,9 +188,9 @@ object.entries@^1.1.3:
|
||||
has "^1.0.3"
|
||||
|
||||
semver@^7.1.1:
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
|
||||
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
|
@@ -6,7 +6,6 @@ import { first } from 'rxjs/operators'
|
||||
import { BaseTerminalTabComponent } from 'terminus-terminal'
|
||||
import { SerialService } from '../services/serial.service'
|
||||
import { SerialConnection, SerialSession, BAUD_RATES } from '../api'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
@@ -20,7 +19,6 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
session: SerialSession|null = null
|
||||
serialPort: any
|
||||
private serialService: SerialService
|
||||
private homeEndSubscription: Subscription
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
constructor (
|
||||
@@ -33,7 +31,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
ngOnInit () {
|
||||
this.logger = this.log.create('terminalTab')
|
||||
|
||||
this.homeEndSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
this.subscribeUntilDestroyed(this.hotkeys.matchedHotkey, hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
return
|
||||
}
|
||||
@@ -94,18 +92,18 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
}
|
||||
|
||||
protected attachSessionHandlers () {
|
||||
this.attachSessionHandler(this.session!.serviceMessage$.subscribe(msg => {
|
||||
this.attachSessionHandler(this.session!.serviceMessage$, msg => {
|
||||
this.write(`\r\n${colors.black.bgWhite(' Serial ')} ${msg}\r\n`)
|
||||
this.session?.resize(this.size.columns, this.size.rows)
|
||||
}))
|
||||
this.attachSessionHandler(this.session!.destroyed$.subscribe(() => {
|
||||
})
|
||||
this.attachSessionHandler(this.session!.destroyed$, () => {
|
||||
this.write('Press any key to reconnect\r\n')
|
||||
this.input$.pipe(first()).subscribe(() => {
|
||||
if (!this.session?.open) {
|
||||
this.reconnect()
|
||||
}
|
||||
})
|
||||
}))
|
||||
})
|
||||
super.attachSessionHandlers()
|
||||
}
|
||||
|
||||
@@ -130,9 +128,4 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
|
||||
this.serialPort.update({ baudRate: rate })
|
||||
this.connection!.baudrate = rate
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.homeEndSubscription.unsubscribe()
|
||||
super.ngOnDestroy()
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { trigger, transition, style, animate } from '@angular/animations'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { HotkeysService } from 'terminus-core'
|
||||
import { HotkeysService, BaseComponent } from 'terminus-core'
|
||||
|
||||
const INPUT_TIMEOUT = 1000
|
||||
|
||||
@@ -36,11 +35,10 @@ const INPUT_TIMEOUT = 1000
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class HotkeyInputModalComponent {
|
||||
export class HotkeyInputModalComponent extends BaseComponent {
|
||||
@Input() value: string[] = []
|
||||
@Input() timeoutProgress = 0
|
||||
|
||||
private keySubscription: Subscription
|
||||
private lastKeyEvent: number|null = null
|
||||
private keyTimeoutInterval: number|null = null
|
||||
|
||||
@@ -48,8 +46,9 @@ export class HotkeyInputModalComponent {
|
||||
private modalInstance: NgbActiveModal,
|
||||
public hotkeys: HotkeysService,
|
||||
) {
|
||||
super()
|
||||
this.hotkeys.clearCurrentKeystrokes()
|
||||
this.keySubscription = hotkeys.key.subscribe((event) => {
|
||||
this.subscribeUntilDestroyed(hotkeys.key, (event) => {
|
||||
this.lastKeyEvent = performance.now()
|
||||
this.value = this.hotkeys.getCurrentKeystrokes()
|
||||
event.preventDefault()
|
||||
@@ -75,10 +74,10 @@ export class HotkeyInputModalComponent {
|
||||
}
|
||||
|
||||
ngOnDestroy (): void {
|
||||
this.keySubscription.unsubscribe()
|
||||
this.hotkeys.clearCurrentKeystrokes()
|
||||
this.hotkeys.enable()
|
||||
clearInterval(this.keyTimeoutInterval!)
|
||||
super.ngOnDestroy()
|
||||
}
|
||||
|
||||
close (): void {
|
||||
|
@@ -17,6 +17,7 @@
|
||||
> .nav {
|
||||
padding: 20px 10px;
|
||||
width: 190px;
|
||||
flex: none;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import * as yaml from 'js-yaml'
|
||||
import { debounce } from 'utils-decorators/dist/cjs'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Component, Inject, Input, HostBinding, NgZone } from '@angular/core'
|
||||
import {
|
||||
ElectronService,
|
||||
@@ -33,7 +32,6 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
checkingForUpdate = false
|
||||
updateAvailable = false
|
||||
@HostBinding('class.pad-window-controls') padWindowControls = false
|
||||
private configSubscription: Subscription
|
||||
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
@@ -58,7 +56,7 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
&& config.store.appearance.tabsLocation !== 'top'
|
||||
}
|
||||
|
||||
this.configSubscription = config.changed$.subscribe(onConfigChange)
|
||||
this.subscribeUntilDestroyed(config.changed$, onConfigChange)
|
||||
onConfigChange()
|
||||
}
|
||||
|
||||
@@ -76,7 +74,6 @@ export class SettingsTabComponent extends BaseTabComponent {
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
this.configSubscription.unsubscribe()
|
||||
this.config.save()
|
||||
}
|
||||
|
||||
|
@@ -9,6 +9,7 @@ import {
|
||||
Platform,
|
||||
isWindowsBuild,
|
||||
WIN_BUILD_FLUENT_BG_SUPPORTED,
|
||||
BaseComponent,
|
||||
} from 'terminus-core'
|
||||
|
||||
|
||||
@@ -17,7 +18,7 @@ import {
|
||||
selector: 'window-settings-tab',
|
||||
template: require('./windowSettingsTab.component.pug'),
|
||||
})
|
||||
export class WindowSettingsTabComponent {
|
||||
export class WindowSettingsTabComponent extends BaseComponent {
|
||||
screens: any[]
|
||||
Platform = Platform
|
||||
isFluentVibrancySupported = false
|
||||
@@ -29,10 +30,11 @@ export class WindowSettingsTabComponent {
|
||||
public zone: NgZone,
|
||||
@Inject(Theme) public themes: Theme[],
|
||||
) {
|
||||
super()
|
||||
this.screens = this.docking.getScreens()
|
||||
this.themes = config.enabledServices(this.themes)
|
||||
|
||||
hostApp.displaysChanged$.subscribe(() => {
|
||||
this.subscribeUntilDestroyed(hostApp.displaysChanged$, () => {
|
||||
this.zone.run(() => this.screens = this.docking.getScreens())
|
||||
})
|
||||
|
||||
|
@@ -29,7 +29,7 @@
|
||||
"ssh2": "^0.8.9",
|
||||
"ssh2-streams": "Eugeny/ssh2-streams#75f6d3425d071ac73a18fd46e2f5e738bfe897c5",
|
||||
"sshpk": "^1.16.1",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"strip-ansi": "^7.0.0",
|
||||
"temp": "^0.9.1"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@@ -6,6 +6,7 @@ import { Server, Socket, createServer, createConnection } from 'net'
|
||||
import { Client, ClientChannel } from 'ssh2'
|
||||
import { Logger } from 'terminus-core'
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { ProxyCommandStream } from './services/ssh.service'
|
||||
|
||||
export interface LoginScript {
|
||||
expect: string
|
||||
@@ -42,6 +43,8 @@ export interface SSHConnection {
|
||||
agentForward?: boolean
|
||||
warnOnClose?: boolean
|
||||
algorithms?: Record<string, string[]>
|
||||
proxyCommand?: string
|
||||
forwardedPorts?: ForwardedPortConfig[]
|
||||
}
|
||||
|
||||
export enum PortForwardType {
|
||||
@@ -50,7 +53,15 @@ export enum PortForwardType {
|
||||
Dynamic = 'Dynamic',
|
||||
}
|
||||
|
||||
export class ForwardedPort {
|
||||
export interface ForwardedPortConfig {
|
||||
type: PortForwardType
|
||||
host: string
|
||||
port: number
|
||||
targetAddress: string
|
||||
targetPort: number
|
||||
}
|
||||
|
||||
export class ForwardedPort implements ForwardedPortConfig {
|
||||
type: PortForwardType
|
||||
host = '127.0.0.1'
|
||||
port: number
|
||||
@@ -117,6 +128,7 @@ export class SSHSession extends BaseSession {
|
||||
forwardedPorts: ForwardedPort[] = []
|
||||
logger: Logger
|
||||
jumpStream: any
|
||||
proxyCommandStream: ProxyCommandStream|null = null
|
||||
|
||||
get serviceMessage$ (): Observable<string> { return this.serviceMessage }
|
||||
private serviceMessage = new Subject<string>()
|
||||
@@ -136,6 +148,11 @@ export class SSHSession extends BaseSession {
|
||||
async start (): Promise<void> {
|
||||
this.open = true
|
||||
|
||||
this.proxyCommandStream?.on('error', err => {
|
||||
this.emitServiceMessage(colors.bgRed.black(' X ') + ` ${err.message}`)
|
||||
this.destroy()
|
||||
})
|
||||
|
||||
try {
|
||||
this.shell = await this.openShellChannel({ x11: this.connection.x11 })
|
||||
} catch (err) {
|
||||
@@ -361,6 +378,7 @@ export class SSHSession extends BaseSession {
|
||||
|
||||
async destroy (): Promise<void> {
|
||||
this.serviceMessage.complete()
|
||||
this.proxyCommandStream?.destroy()
|
||||
await super.destroy()
|
||||
}
|
||||
|
||||
@@ -407,11 +425,6 @@ export class SSHSession extends BaseSession {
|
||||
}
|
||||
}
|
||||
|
||||
export interface SSHConnectionGroup {
|
||||
name: string
|
||||
connections: SSHConnection[]
|
||||
}
|
||||
|
||||
export const ALGORITHM_BLACKLIST = [
|
||||
// cause native crashes in node crypto, use EC instead
|
||||
'diffie-hellman-group-exchange-sha256',
|
||||
|
@@ -17,10 +17,11 @@
|
||||
type='text',
|
||||
placeholder='Ungrouped',
|
||||
[(ngModel)]='connection.group',
|
||||
[ngbTypeahead]='groupTypeahead',
|
||||
)
|
||||
|
||||
.d-flex
|
||||
.form-group
|
||||
.d-flex.w-100(*ngIf='!useProxyCommand')
|
||||
.form-group.w-100.mr-4
|
||||
label Host
|
||||
input.form-control(
|
||||
type='text',
|
||||
@@ -35,6 +36,9 @@
|
||||
[(ngModel)]='connection.port',
|
||||
)
|
||||
|
||||
.alert.alert-info(*ngIf='useProxyCommand')
|
||||
.mr-auto Using a proxy command instead of a network connection
|
||||
|
||||
.form-group
|
||||
label Username
|
||||
input.form-control(
|
||||
@@ -42,9 +46,9 @@
|
||||
[(ngModel)]='connection.user',
|
||||
)
|
||||
|
||||
.form-line
|
||||
.header
|
||||
.title Authentication
|
||||
.form-group
|
||||
label Authentication method
|
||||
|
||||
.btn-group.w-100(
|
||||
[(ngModel)]='connection.auth',
|
||||
ngbRadioGroup
|
||||
@@ -96,10 +100,19 @@
|
||||
button.btn.btn-secondary((click)='selectPrivateKey()')
|
||||
i.fas.fa-folder-open
|
||||
|
||||
li(ngbNavItem)
|
||||
a(ngbNavLink) Ports
|
||||
ng-template(ngbNavContent)
|
||||
ssh-port-forwarding-config(
|
||||
[model]='connection.forwardedPorts',
|
||||
(forwardAdded)='onForwardAdded($event)',
|
||||
(forwardRemoved)='onForwardRemoved($event)'
|
||||
)
|
||||
|
||||
li(ngbNavItem)
|
||||
a(ngbNavLink) Advanced
|
||||
ng-template(ngbNavContent)
|
||||
.form-line
|
||||
.form-line(*ngIf='!useProxyCommand')
|
||||
.header
|
||||
.title Jump host
|
||||
select.form-control([(ngModel)]='connection.jumpHost')
|
||||
@@ -165,6 +178,19 @@
|
||||
[(ngModel)]='connection.readyTimeout',
|
||||
)
|
||||
|
||||
.form-line(*ngIf='!connection.jumpHost')
|
||||
.header
|
||||
.title Use a proxy command
|
||||
.description Command's stdin/stdout is used instead of a network connection
|
||||
toggle([(ngModel)]='useProxyCommand')
|
||||
|
||||
.form-group(*ngIf='useProxyCommand && !connection.jumpHost')
|
||||
label Proxy command
|
||||
input.form-control(
|
||||
type='text',
|
||||
[(ngModel)]='connection.proxyCommand',
|
||||
)
|
||||
|
||||
li(ngbNavItem)
|
||||
a(ngbNavLink) Ciphers
|
||||
ng-template(ngbNavContent)
|
||||
|
@@ -1,9 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component } from '@angular/core'
|
||||
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Observable } from 'rxjs'
|
||||
import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'
|
||||
|
||||
import { ElectronService, HostAppService, ConfigService } from 'terminus-core'
|
||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||
import { SSHConnection, LoginScript, SSHAlgorithmType, ALGORITHM_BLACKLIST } from '../api'
|
||||
import { SSHConnection, LoginScript, ForwardedPortConfig, SSHAlgorithmType, ALGORITHM_BLACKLIST } from '../api'
|
||||
import { PromptModalComponent } from './promptModal.component'
|
||||
import { ALGORITHMS } from 'ssh2-streams/lib/constants'
|
||||
|
||||
@@ -14,11 +17,14 @@ import { ALGORITHMS } from 'ssh2-streams/lib/constants'
|
||||
export class EditConnectionModalComponent {
|
||||
connection: SSHConnection
|
||||
hasSavedPassword: boolean
|
||||
useProxyCommand: boolean
|
||||
|
||||
supportedAlgorithms: Record<string, string> = {}
|
||||
defaultAlgorithms: Record<string, string[]> = {}
|
||||
algorithms: Record<string, Record<string, boolean>> = {}
|
||||
|
||||
private groupNames: string[]
|
||||
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
private modalInstance: NgbActiveModal,
|
||||
@@ -43,14 +49,26 @@ export class EditConnectionModalComponent {
|
||||
this.supportedAlgorithms[k] = ALGORITHMS[supportedAlg].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
||||
this.defaultAlgorithms[k] = ALGORITHMS[defaultAlg].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
||||
}
|
||||
|
||||
this.groupNames = [...new Set(config.store.ssh.connections.map(x => x.group))] as string[]
|
||||
this.groupNames = this.groupNames.filter(x => x).sort()
|
||||
}
|
||||
|
||||
groupTypeahead = (text$: Observable<string>) =>
|
||||
text$.pipe(
|
||||
debounceTime(200),
|
||||
distinctUntilChanged(),
|
||||
map(q => this.groupNames.filter(x => !q || x.toLowerCase().includes(q.toLowerCase())))
|
||||
)
|
||||
|
||||
async ngOnInit () {
|
||||
this.hasSavedPassword = !!await this.passwordStorage.loadPassword(this.connection)
|
||||
this.connection.algorithms = this.connection.algorithms ?? {}
|
||||
this.connection.scripts = this.connection.scripts ?? []
|
||||
this.connection.auth = this.connection.auth ?? null
|
||||
|
||||
this.useProxyCommand = !!this.connection.proxyCommand
|
||||
|
||||
for (const k of Object.values(SSHAlgorithmType)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!this.connection.algorithms[k]) {
|
||||
@@ -102,6 +120,9 @@ export class EditConnectionModalComponent {
|
||||
.filter(([_, v]) => !!v)
|
||||
.map(([key, _]) => key)
|
||||
}
|
||||
if (!this.useProxyCommand) {
|
||||
this.connection.proxyCommand = undefined
|
||||
}
|
||||
this.modalInstance.close(this.connection)
|
||||
}
|
||||
|
||||
@@ -152,4 +173,13 @@ export class EditConnectionModalComponent {
|
||||
}
|
||||
this.connection.scripts.push({ expect: '', send: '' })
|
||||
}
|
||||
|
||||
onForwardAdded (fw: ForwardedPortConfig) {
|
||||
this.connection.forwardedPorts = this.connection.forwardedPorts ?? []
|
||||
this.connection.forwardedPorts.push(fw)
|
||||
}
|
||||
|
||||
onForwardRemoved (fw: ForwardedPortConfig) {
|
||||
this.connection.forwardedPorts = this.connection.forwardedPorts?.filter(x => x !== fw)
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,61 @@
|
||||
.list-group-light.mb-3
|
||||
.list-group-item.d-flex.align-items-center(*ngFor='let fw of model')
|
||||
strong(*ngIf='fw.type === PortForwardType.Local') Local
|
||||
strong(*ngIf='fw.type === PortForwardType.Remote') Remote
|
||||
strong(*ngIf='fw.type === PortForwardType.Dynamic') Dynamic
|
||||
.ml-3 {{fw.host}}:{{fw.port}}
|
||||
.ml-2 →
|
||||
.ml-2(*ngIf='fw.type !== PortForwardType.Dynamic') {{fw.targetAddress}}:{{fw.targetPort}}
|
||||
.ml-2(*ngIf='fw.type === PortForwardType.Dynamic') SOCKS proxy
|
||||
button.btn.btn-link.ml-auto((click)='remove(fw)')
|
||||
i.fas.fa-trash-alt.mr-2
|
||||
span Remove
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type === PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type !== PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
.input-group-append
|
||||
.input-group-text →
|
||||
input.form-control(type='text', [(ngModel)]='newForward.targetAddress')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.targetPort')
|
||||
|
||||
.d-flex
|
||||
.btn-group.mr-auto(
|
||||
[(ngModel)]='newForward.type',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Local'
|
||||
)
|
||||
| Local
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Remote'
|
||||
)
|
||||
| Remote
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Dynamic'
|
||||
)
|
||||
| Dynamic
|
||||
|
||||
button.btn.btn-primary((click)='addForward()')
|
||||
i.fas.fa-check.mr-2
|
||||
span Forward port
|
@@ -0,0 +1,44 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core'
|
||||
import { ForwardedPortConfig, PortForwardType } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
selector: 'ssh-port-forwarding-config',
|
||||
template: require('./sshPortForwardingConfig.component.pug'),
|
||||
})
|
||||
export class SSHPortForwardingConfigComponent {
|
||||
@Input() model: ForwardedPortConfig[]
|
||||
@Output() forwardAdded = new EventEmitter<ForwardedPortConfig>()
|
||||
@Output() forwardRemoved = new EventEmitter<ForwardedPortConfig>()
|
||||
newForward: ForwardedPortConfig
|
||||
PortForwardType = PortForwardType
|
||||
|
||||
constructor (
|
||||
) {
|
||||
this.reset()
|
||||
}
|
||||
|
||||
reset () {
|
||||
this.newForward = {
|
||||
type: PortForwardType.Local,
|
||||
host: '127.0.0.1',
|
||||
port: 8000,
|
||||
targetAddress: '127.0.0.1',
|
||||
targetPort: 80,
|
||||
}
|
||||
}
|
||||
|
||||
async addForward () {
|
||||
try {
|
||||
this.forwardAdded.emit(this.newForward)
|
||||
this.reset()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
remove (fw: ForwardedPortConfig) {
|
||||
this.forwardRemoved.emit(fw)
|
||||
}
|
||||
}
|
@@ -2,64 +2,8 @@
|
||||
h5.m-0 Port forwarding
|
||||
|
||||
.modal-body.pt-0
|
||||
.list-group-light.mb-3
|
||||
.list-group-item.d-flex.align-items-center(*ngFor='let fw of session.forwardedPorts')
|
||||
strong(*ngIf='fw.type === PortForwardType.Local') Local
|
||||
strong(*ngIf='fw.type === PortForwardType.Remote') Remote
|
||||
strong(*ngIf='fw.type === PortForwardType.Dynamic') Dynamic
|
||||
.ml-3 {{fw.host}}:{{fw.port}}
|
||||
.ml-2 →
|
||||
.ml-2(*ngIf='fw.type !== PortForwardType.Dynamic') {{fw.targetAddress}}:{{fw.targetPort}}
|
||||
.ml-2(*ngIf='fw.type === PortForwardType.Dynamic') SOCKS proxy
|
||||
button.btn.btn-link.ml-auto((click)='remove(fw)')
|
||||
i.fas.fa-trash-alt.mr-2
|
||||
span Remove
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type === PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
|
||||
.input-group.mb-2(*ngIf='newForward.type !== PortForwardType.Dynamic')
|
||||
input.form-control(type='text', [(ngModel)]='newForward.host')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.port')
|
||||
.input-group-append
|
||||
.input-group-text →
|
||||
input.form-control(type='text', [(ngModel)]='newForward.targetAddress')
|
||||
.input-group-append
|
||||
.input-group-text :
|
||||
input.form-control(type='number', [(ngModel)]='newForward.targetPort')
|
||||
|
||||
.d-flex
|
||||
.btn-group.mr-auto(
|
||||
[(ngModel)]='newForward.type',
|
||||
ngbRadioGroup
|
||||
)
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Local'
|
||||
)
|
||||
| Local
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Remote'
|
||||
)
|
||||
| Remote
|
||||
label.btn.btn-secondary.m-0(ngbButtonLabel)
|
||||
input(
|
||||
type='radio',
|
||||
ngbButton,
|
||||
[value]='PortForwardType.Dynamic'
|
||||
)
|
||||
| Dynamic
|
||||
|
||||
button.btn.btn-primary((click)='addForward()')
|
||||
i.fas.fa-check.mr-2
|
||||
span Forward port
|
||||
ssh-port-forwarding-config(
|
||||
[model]='session.forwardedPorts',
|
||||
(forwardAdded)='onForwardAdded($event)',
|
||||
(forwardRemoved)='onForwardRemoved($event)'
|
||||
)
|
||||
|
@@ -1,43 +1,21 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ForwardedPort, PortForwardType, SSHSession } from '../api'
|
||||
import { ForwardedPort, ForwardedPortConfig, SSHSession } from '../api'
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
template: require('./sshPortForwardingModal.component.pug'),
|
||||
// styles: [require('./sshPortForwardingModal.component.scss')],
|
||||
})
|
||||
export class SSHPortForwardingModalComponent {
|
||||
@Input() session: SSHSession
|
||||
newForward = new ForwardedPort()
|
||||
PortForwardType = PortForwardType
|
||||
|
||||
constructor (
|
||||
public modalInstance: NgbActiveModal,
|
||||
) {
|
||||
this.reset()
|
||||
onForwardAdded (fw: ForwardedPortConfig) {
|
||||
const newForward = new ForwardedPort()
|
||||
Object.assign(newForward, fw)
|
||||
this.session.addPortForward(newForward)
|
||||
}
|
||||
|
||||
reset () {
|
||||
this.newForward = new ForwardedPort()
|
||||
this.newForward.type = PortForwardType.Local
|
||||
this.newForward.host = '127.0.0.1'
|
||||
this.newForward.port = 8000
|
||||
this.newForward.targetAddress = '127.0.0.1'
|
||||
this.newForward.targetPort = 80
|
||||
}
|
||||
|
||||
async addForward () {
|
||||
try {
|
||||
await this.session.addPortForward(this.newForward)
|
||||
this.reset()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
remove (fw: ForwardedPort) {
|
||||
this.session.removePortForward(fw)
|
||||
onForwardRemoved (fw: ForwardedPortConfig) {
|
||||
this.session.removePortForward(fw as ForwardedPort)
|
||||
}
|
||||
}
|
||||
|
@@ -1,33 +1,55 @@
|
||||
h3 Connections
|
||||
.d-flex.align-items-center.mb-3
|
||||
h3.m-0 SSH Connections
|
||||
|
||||
.list-group.list-group-flush.mt-3.mb-3
|
||||
button.btn.btn-primary.ml-auto((click)='createConnection()')
|
||||
i.fas.fa-fw.fa-plus
|
||||
span.ml-2 Add connection
|
||||
|
||||
.input-group.mb-3
|
||||
.input-group-prepend
|
||||
.input-group-text
|
||||
i.fas.fa-fw.fa-search
|
||||
input.form-control(type='search', placeholder='Filter', [(ngModel)]='filter')
|
||||
|
||||
.list-group.list-group-light.mt-3.mb-3
|
||||
ng-container(*ngFor='let group of childGroups')
|
||||
.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||
(click)='groupCollapsed[group.name] = !groupCollapsed[group.name]'
|
||||
)
|
||||
.fa.fa-fw.fa-chevron-right(*ngIf='groupCollapsed[group.name]')
|
||||
.fa.fa-fw.fa-chevron-down(*ngIf='!groupCollapsed[group.name]')
|
||||
span.ml-3.mr-auto {{group.name || "Ungrouped"}}
|
||||
button.btn.btn-outline-info.ml-2((click)='editGroup(group)')
|
||||
i.fas.fa-edit
|
||||
button.btn.btn-outline-danger.ml-1((click)='deleteGroup(group)')
|
||||
i.fas.fa-trash
|
||||
ng-container(*ngIf='!groupCollapsed[group.name]')
|
||||
.list-group-item.list-group-item-action.pl-5.d-flex.align-items-center(
|
||||
*ngFor='let connection of group.connections',
|
||||
(click)='editConnection(connection)'
|
||||
ng-container(*ngIf='isGroupVisible(group)')
|
||||
.list-group-item.list-group-item-action.d-flex.align-items-center(
|
||||
(click)='groupCollapsed[group.name] = !groupCollapsed[group.name]'
|
||||
)
|
||||
.mr-auto
|
||||
div {{connection.name}}
|
||||
.text-muted {{connection.host}}
|
||||
button.btn.btn-outline-info.ml-1((click)='$event.stopPropagation(); copyConnection(connection)')
|
||||
i.fas.fa-copy
|
||||
button.btn.btn-outline-danger.ml-1((click)='$event.stopPropagation(); deleteConnection(connection)')
|
||||
.fa.fa-fw.fa-chevron-right(*ngIf='groupCollapsed[group.name]')
|
||||
.fa.fa-fw.fa-chevron-down(*ngIf='!groupCollapsed[group.name]')
|
||||
span.ml-3.mr-auto {{group.name || "Ungrouped"}}
|
||||
button.btn.btn-sm.btn-link.hover-reveal.ml-2(
|
||||
[class.invisible]='!group.name',
|
||||
(click)='$event.stopPropagation(); editGroup(group)'
|
||||
)
|
||||
i.fas.fa-edit
|
||||
button.btn.btn-sm.btn-link.hover-reveal.ml-2(
|
||||
[class.invisible]='!group.name',
|
||||
(click)='$event.stopPropagation(); deleteGroup(group)'
|
||||
)
|
||||
i.fas.fa-trash
|
||||
|
||||
button.btn.btn-primary((click)='createConnection()')
|
||||
i.fas.fa-fw.fa-plus
|
||||
span.ml-2 Add connection
|
||||
ng-container(*ngIf='!groupCollapsed[group.name]')
|
||||
ng-container(*ngFor='let connection of group.connections')
|
||||
.list-group-item.list-group-item-action.pl-5.d-flex.align-items-center(
|
||||
*ngIf='isConnectionVisible(connection)',
|
||||
(click)='editConnection(connection)'
|
||||
)
|
||||
.mr-3 {{connection.name}}
|
||||
.mr-auto.text-muted {{connection.host}}
|
||||
|
||||
.hover-reveal(ngbDropdown, placement='bottom-right')
|
||||
button.btn.btn-link(ngbDropdownToggle, (click)='$event.stopPropagation()')
|
||||
i.fas.fa-fw.fa-ellipsis-v
|
||||
div(ngbDropdownMenu)
|
||||
button.dropdown-item((click)='$event.stopPropagation(); copyConnection(connection)')
|
||||
i.fas.fa-copy
|
||||
span Duplicate
|
||||
button.dropdown-item((click)='$event.stopPropagation(); deleteConnection(connection)')
|
||||
i.fas.fa-trash
|
||||
span Delete
|
||||
|
||||
h3.mt-5 Options
|
||||
|
||||
|
@@ -0,0 +1,3 @@
|
||||
.list-group-item {
|
||||
padding: 0.3rem 1rem;
|
||||
}
|
@@ -4,18 +4,25 @@ import { Component } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ConfigService, ElectronService, HostAppService } from 'terminus-core'
|
||||
import { PasswordStorageService } from '../services/passwordStorage.service'
|
||||
import { SSHConnection, SSHConnectionGroup } from '../api'
|
||||
import { SSHConnection } from '../api'
|
||||
import { EditConnectionModalComponent } from './editConnectionModal.component'
|
||||
import { PromptModalComponent } from './promptModal.component'
|
||||
|
||||
interface SSHConnectionGroup {
|
||||
name: string|null
|
||||
connections: SSHConnection[]
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
template: require('./sshSettingsTab.component.pug'),
|
||||
styles: [require('./sshSettingsTab.component.scss')],
|
||||
})
|
||||
export class SSHSettingsTabComponent {
|
||||
connections: SSHConnection[]
|
||||
childGroups: SSHConnectionGroup[]
|
||||
groupCollapsed: Record<string, boolean> = {}
|
||||
filter = ''
|
||||
|
||||
constructor (
|
||||
public config: ConfigService,
|
||||
@@ -133,7 +140,7 @@ export class SSHSettingsTabComponent {
|
||||
let group = this.childGroups.find(x => x.name === connection.group)
|
||||
if (!group) {
|
||||
group = {
|
||||
name: connection.group!,
|
||||
name: connection.group,
|
||||
connections: [],
|
||||
}
|
||||
this.childGroups.push(group)
|
||||
@@ -141,4 +148,12 @@ export class SSHSettingsTabComponent {
|
||||
group.connections.push(connection)
|
||||
}
|
||||
}
|
||||
|
||||
isGroupVisible (group: SSHConnectionGroup): boolean {
|
||||
return !this.filter || group.connections.some(x => this.isConnectionVisible(x))
|
||||
}
|
||||
|
||||
isConnectionVisible (connection: SSHConnection): boolean {
|
||||
return !this.filter || `${connection.name}$${connection.host}`.toLowerCase().includes(this.filter.toLowerCase())
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ import { BaseTerminalTabComponent } from 'terminus-terminal'
|
||||
import { SSHService } from '../services/ssh.service'
|
||||
import { SSHConnection, SSHSession } from '../api'
|
||||
import { SSHPortForwardingModalComponent } from './sshPortForwardingModal.component'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
|
||||
/** @hidden */
|
||||
@@ -22,9 +21,15 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
connection?: SSHConnection
|
||||
session: SSHSession|null = null
|
||||
private sessionStack: SSHSession[] = []
|
||||
private homeEndSubscription: Subscription
|
||||
private recentInputs = ''
|
||||
private reconnectOffered = false
|
||||
private spinner = new Spinner({
|
||||
text: 'Connecting',
|
||||
stream: {
|
||||
write: x => this.write(x),
|
||||
},
|
||||
})
|
||||
private spinnerActive = false
|
||||
|
||||
constructor (
|
||||
injector: Injector,
|
||||
@@ -43,7 +48,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
|
||||
this.enableDynamicTitle = !this.connection.disableDynamicTitle
|
||||
|
||||
this.homeEndSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
this.subscribeUntilDestroyed(this.hotkeys.matchedHotkey, hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
return
|
||||
}
|
||||
@@ -87,13 +92,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
|
||||
await this.setupOneSession(jumpSession)
|
||||
|
||||
this.attachSessionHandler(
|
||||
jumpSession.destroyed$.subscribe(() => {
|
||||
if (session.open) {
|
||||
session.destroy()
|
||||
}
|
||||
})
|
||||
)
|
||||
this.attachSessionHandler(jumpSession.destroyed$, () => {
|
||||
if (session.open) {
|
||||
session.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut(
|
||||
'127.0.0.1', 0, session.connection.host, session.connection.port ?? 22,
|
||||
@@ -113,32 +116,22 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
this.sessionStack.push(session)
|
||||
}
|
||||
|
||||
this.attachSessionHandler(session.serviceMessage$.subscribe(msg => {
|
||||
this.write(`\r\n${colors.black.bgWhite(' SSH ')} ${msg}\r\n`)
|
||||
session.resize(this.size.columns, this.size.rows)
|
||||
}))
|
||||
this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` Connecting to ${session.connection.host}\r\n`)
|
||||
|
||||
this.startSpinner()
|
||||
|
||||
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` Connecting to ${session.connection.host}\r\n`)
|
||||
|
||||
const spinner = new Spinner({
|
||||
text: 'Connecting',
|
||||
stream: {
|
||||
write: x => this.write(x),
|
||||
},
|
||||
this.attachSessionHandler(session.serviceMessage$, msg => {
|
||||
this.pauseSpinner(() => {
|
||||
this.write(`\r${colors.black.bgWhite(' SSH ')} ${msg}\r\n`)
|
||||
session.resize(this.size.columns, this.size.rows)
|
||||
})
|
||||
})
|
||||
spinner.setSpinnerString(6)
|
||||
spinner.start()
|
||||
|
||||
try {
|
||||
await this.ssh.connectSession(session, (message: string) => {
|
||||
spinner.stop(true)
|
||||
this.write(message + '\r\n')
|
||||
spinner.start()
|
||||
})
|
||||
spinner.stop(true)
|
||||
await this.ssh.connectSession(session)
|
||||
this.stopSpinner()
|
||||
} catch (e) {
|
||||
spinner.stop(true)
|
||||
this.stopSpinner()
|
||||
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
|
||||
return
|
||||
}
|
||||
@@ -146,7 +139,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
|
||||
protected attachSessionHandlers (): void {
|
||||
const session = this.session!
|
||||
this.attachSessionHandler(session.destroyed$.subscribe(() => {
|
||||
this.attachSessionHandler(session.destroyed$, () => {
|
||||
if (
|
||||
// Ctrl-D
|
||||
this.recentInputs.charCodeAt(this.recentInputs.length - 1) === 4 ||
|
||||
@@ -156,7 +149,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
this.destroy()
|
||||
} else {
|
||||
// Session was closed abruptly
|
||||
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` ${session.connection.host}: session closed\r\n`)
|
||||
this.write('\r\n' + colors.black.bgWhite(' SSH ') + ` ${session.connection.host}: session closed\r\n`)
|
||||
if (!this.reconnectOffered) {
|
||||
this.reconnectOffered = true
|
||||
this.write('Press any key to reconnect\r\n')
|
||||
@@ -167,7 +160,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
})
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
super.attachSessionHandlers()
|
||||
}
|
||||
|
||||
@@ -228,8 +221,23 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
|
||||
)).response === 1
|
||||
}
|
||||
|
||||
ngOnDestroy (): void {
|
||||
this.homeEndSubscription.unsubscribe()
|
||||
super.ngOnDestroy()
|
||||
private startSpinner () {
|
||||
this.spinner.setSpinnerString(6)
|
||||
this.spinner.start()
|
||||
this.spinnerActive = true
|
||||
}
|
||||
|
||||
private stopSpinner () {
|
||||
this.spinner.stop(true)
|
||||
this.spinnerActive = false
|
||||
}
|
||||
|
||||
private pauseSpinner (work: () => void) {
|
||||
const wasActive = this.spinnerActive
|
||||
this.stopSpinner()
|
||||
work()
|
||||
if (wasActive) {
|
||||
this.startSpinner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import TerminusTerminalModule from 'terminus-terminal'
|
||||
|
||||
import { EditConnectionModalComponent } from './components/editConnectionModal.component'
|
||||
import { SSHPortForwardingModalComponent } from './components/sshPortForwardingModal.component'
|
||||
import { SSHPortForwardingConfigComponent } from './components/sshPortForwardingConfig.component'
|
||||
import { PromptModalComponent } from './components/promptModal.component'
|
||||
import { SSHSettingsTabComponent } from './components/sshSettingsTab.component'
|
||||
import { SSHTabComponent } from './components/sshTab.component'
|
||||
@@ -49,6 +50,7 @@ import { WinSCPContextMenu } from './winSCPIntegration'
|
||||
EditConnectionModalComponent,
|
||||
PromptModalComponent,
|
||||
SSHPortForwardingModalComponent,
|
||||
SSHPortForwardingConfigComponent,
|
||||
SSHSettingsTabComponent,
|
||||
SSHTabComponent,
|
||||
],
|
||||
|
@@ -5,26 +5,44 @@ import * as keytar from 'keytar'
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PasswordStorageService {
|
||||
async savePassword (connection: SSHConnection, password: string): Promise<void> {
|
||||
let key = `ssh@${connection.host}`
|
||||
if (connection.port) {
|
||||
key = `ssh@${connection.host}:${connection.port}`
|
||||
}
|
||||
const key = this.getKeyForConnection(connection)
|
||||
return keytar.setPassword(key, connection.user, password)
|
||||
}
|
||||
|
||||
async deletePassword (connection: SSHConnection): Promise<void> {
|
||||
let key = `ssh@${connection.host}`
|
||||
if (connection.port) {
|
||||
key = `ssh@${connection.host}:${connection.port}`
|
||||
}
|
||||
const key = this.getKeyForConnection(connection)
|
||||
await keytar.deletePassword(key, connection.user)
|
||||
}
|
||||
|
||||
async loadPassword (connection: SSHConnection): Promise<string|null> {
|
||||
const key = this.getKeyForConnection(connection)
|
||||
return keytar.getPassword(key, connection.user)
|
||||
}
|
||||
|
||||
async savePrivateKeyPassword (id: string, password: string): Promise<void> {
|
||||
const key = this.getKeyForPrivateKey(id)
|
||||
return keytar.setPassword(key, 'user', password)
|
||||
}
|
||||
|
||||
async deletePrivateKeyPassword (id: string): Promise<void> {
|
||||
const key = this.getKeyForPrivateKey(id)
|
||||
await keytar.deletePassword(key, 'user')
|
||||
}
|
||||
|
||||
async loadPrivateKeyPassword (id: string): Promise<string|null> {
|
||||
const key = this.getKeyForPrivateKey(id)
|
||||
return keytar.getPassword(key, 'user')
|
||||
}
|
||||
|
||||
private getKeyForConnection (connection: SSHConnection): string {
|
||||
let key = `ssh@${connection.host}`
|
||||
if (connection.port) {
|
||||
key = `ssh@${connection.host}:${connection.port}`
|
||||
}
|
||||
return keytar.getPassword(key, connection.user)
|
||||
return key
|
||||
}
|
||||
|
||||
private getKeyForPrivateKey (id: string): string {
|
||||
return `ssh-private-key:${id}`
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import colors from 'ansi-colors'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import { Duplex } from 'stream'
|
||||
import * as crypto from 'crypto'
|
||||
import { open as openTemp } from 'temp'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
@@ -7,14 +8,17 @@ import { Client } from 'ssh2'
|
||||
import { SSH2Stream } from 'ssh2-streams'
|
||||
import * as fs from 'mz/fs'
|
||||
import { execFile } from 'mz/child_process'
|
||||
import { exec } from 'child_process'
|
||||
import * as path from 'path'
|
||||
import * as sshpk from 'sshpk'
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { HostAppService, Platform, Logger, LogService, ElectronService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core'
|
||||
import { SettingsTabComponent } from 'terminus-settings'
|
||||
import { ALGORITHM_BLACKLIST, SSHConnection, SSHSession } from '../api'
|
||||
import { ALGORITHM_BLACKLIST, ForwardedPort, SSHConnection, SSHSession } from '../api'
|
||||
import { PromptModalComponent } from '../components/promptModal.component'
|
||||
import { PasswordStorageService } from './passwordStorage.service'
|
||||
import { SSHTabComponent } from '../components/sshTab.component'
|
||||
import { ChildProcess } from 'node:child_process'
|
||||
|
||||
const WINDOWS_OPENSSH_AGENT_PIPE = '\\\\.\\pipe\\openssh-ssh-agent'
|
||||
|
||||
@@ -51,51 +55,29 @@ export class SSHService {
|
||||
return session
|
||||
}
|
||||
|
||||
async loadPrivateKeyForSession (session: SSHSession, logCallback?: SSHLogCallback): Promise<string|null> {
|
||||
async loadPrivateKeyForSession (session: SSHSession): Promise<string|null> {
|
||||
let privateKey: string|null = null
|
||||
let privateKeyPath = session.connection.privateKey
|
||||
|
||||
if (!privateKeyPath) {
|
||||
const userKeyPath = path.join(process.env.HOME!, '.ssh', 'id_rsa')
|
||||
if (await fs.exists(userKeyPath)) {
|
||||
logCallback?.('Using user\'s default private key')
|
||||
session.emitServiceMessage('Using user\'s default private key')
|
||||
privateKeyPath = userKeyPath
|
||||
}
|
||||
}
|
||||
|
||||
if (privateKeyPath) {
|
||||
logCallback?.('Loading private key from ' + colors.bgWhite.blackBright(' ' + privateKeyPath + ' '))
|
||||
session.emitServiceMessage('Loading private key from ' + colors.bgWhite.blackBright(' ' + privateKeyPath + ' '))
|
||||
try {
|
||||
privateKey = (await fs.readFile(privateKeyPath)).toString()
|
||||
} catch (error) {
|
||||
logCallback?.(colors.bgRed.black(' X ') + 'Could not read the private key file')
|
||||
session.emitServiceMessage(colors.bgRed.black(' X ') + 'Could not read the private key file')
|
||||
this.notifications.error('Could not read the private key file')
|
||||
}
|
||||
|
||||
if (privateKey) {
|
||||
let parsedKey: any = null
|
||||
try {
|
||||
parsedKey = sshpk.parsePrivateKey(privateKey, 'auto')
|
||||
} catch (e) {
|
||||
if (e instanceof sshpk.KeyEncryptedError) {
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
logCallback?.(colors.bgYellow.yellow.black(' ! ') + ' Key requires passphrase')
|
||||
modal.componentInstance.prompt = 'Private key passphrase'
|
||||
modal.componentInstance.password = true
|
||||
let passphrase = ''
|
||||
try {
|
||||
const result = await modal.result
|
||||
passphrase = result?.value
|
||||
} catch { }
|
||||
parsedKey = sshpk.parsePrivateKey(
|
||||
privateKey,
|
||||
'auto',
|
||||
{ passphrase: passphrase }
|
||||
)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
const parsedKey = await this.parsePrivateKey(privateKey)
|
||||
|
||||
const sshFormatKey = parsedKey.toString('openssh')
|
||||
const temp = await openTemp()
|
||||
@@ -130,15 +112,40 @@ export class SSHService {
|
||||
return privateKey
|
||||
}
|
||||
|
||||
async connectSession (session: SSHSession, logCallback?: SSHLogCallback): Promise<void> {
|
||||
if (!logCallback) {
|
||||
logCallback = () => null
|
||||
}
|
||||
async parsePrivateKey (privateKey: string): Promise<any> {
|
||||
const keyHash = crypto.createHash('sha512').update(privateKey).digest('hex')
|
||||
let passphrase: string|null = await this.passwordStorage.loadPrivateKeyPassword(keyHash)
|
||||
while (true) {
|
||||
try {
|
||||
return sshpk.parsePrivateKey(privateKey, 'auto', { passphrase })
|
||||
} catch (e) {
|
||||
this.notifications.error('Could not read the private key', e.toString())
|
||||
if (e instanceof sshpk.KeyEncryptedError || e instanceof sshpk.KeyParseError) {
|
||||
await this.passwordStorage.deletePrivateKeyPassword(keyHash)
|
||||
|
||||
const log = (s: any) => {
|
||||
logCallback!(s)
|
||||
this.logger.info(stripAnsi(s))
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = 'Private key passphrase'
|
||||
modal.componentInstance.password = true
|
||||
modal.componentInstance.showRememberCheckbox = true
|
||||
|
||||
try {
|
||||
const result = await modal.result
|
||||
passphrase = result?.value
|
||||
if (passphrase && result.remember) {
|
||||
this.passwordStorage.savePrivateKeyPassword(keyHash, passphrase)
|
||||
}
|
||||
} catch {
|
||||
throw e
|
||||
}
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async connectSession (session: SSHSession): Promise<void> {
|
||||
const log = (s: any) => session.emitServiceMessage(s)
|
||||
|
||||
let privateKey: string|null = null
|
||||
|
||||
@@ -150,12 +157,18 @@ export class SSHService {
|
||||
for (const key of Object.keys(session.connection.algorithms ?? {})) {
|
||||
algorithms[key] = session.connection.algorithms![key].filter(x => !ALGORITHM_BLACKLIST.includes(x))
|
||||
}
|
||||
await new Promise(async (resolve, reject) => {
|
||||
|
||||
const resultPromise: Promise<void> = new Promise(async (resolve, reject) => {
|
||||
ssh.on('ready', () => {
|
||||
connected = true
|
||||
if (savedPassword) {
|
||||
this.passwordStorage.savePassword(session.connection, savedPassword)
|
||||
}
|
||||
|
||||
for (const fw of session.connection.forwardedPorts ?? []) {
|
||||
session.addPortForward(Object.assign(new ForwardedPort(), fw))
|
||||
}
|
||||
|
||||
this.zone.run(resolve)
|
||||
})
|
||||
ssh.on('error', error => {
|
||||
@@ -207,126 +220,143 @@ export class SSHService {
|
||||
log(banner)
|
||||
}
|
||||
})
|
||||
|
||||
let agent: string|null = null
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
if (await fs.exists(WINDOWS_OPENSSH_AGENT_PIPE)) {
|
||||
agent = WINDOWS_OPENSSH_AGENT_PIPE
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const pageantRunning = await new Promise<boolean>(resolve => {
|
||||
windowsProcessTreeNative.getProcessList(list => { // eslint-disable-line block-scoped-var
|
||||
resolve(list.some(x => x.name === 'pageant.exe'))
|
||||
}, 0)
|
||||
})
|
||||
if (pageantRunning) {
|
||||
agent = 'pageant'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
agent = process.env.SSH_AUTH_SOCK!
|
||||
}
|
||||
|
||||
const authMethodsLeft = ['none']
|
||||
if (!session.connection.auth || session.connection.auth === 'publicKey') {
|
||||
privateKey = await this.loadPrivateKeyForSession(session, log)
|
||||
if (!privateKey) {
|
||||
log('\r\nPrivate key auth selected, but no key is loaded\r\n')
|
||||
} else {
|
||||
authMethodsLeft.push('publickey')
|
||||
}
|
||||
}
|
||||
if (!session.connection.auth || session.connection.auth === 'agent') {
|
||||
if (!agent) {
|
||||
log('\r\nAgent auth selected, but no running agent is detected\r\n')
|
||||
} else {
|
||||
authMethodsLeft.push('agent')
|
||||
}
|
||||
}
|
||||
if (!session.connection.auth || session.connection.auth === 'password') {
|
||||
authMethodsLeft.push('password')
|
||||
}
|
||||
if (!session.connection.auth || session.connection.auth === 'keyboardInteractive') {
|
||||
authMethodsLeft.push('keyboard-interactive')
|
||||
}
|
||||
authMethodsLeft.push('hostbased')
|
||||
|
||||
try {
|
||||
ssh.connect({
|
||||
host: session.connection.host,
|
||||
port: session.connection.port ?? 22,
|
||||
username: session.connection.user,
|
||||
password: session.connection.privateKey ? undefined : '',
|
||||
privateKey: privateKey ?? undefined,
|
||||
tryKeyboard: true,
|
||||
agent: agent ?? undefined,
|
||||
agentForward: session.connection.agentForward && !!agent,
|
||||
keepaliveInterval: session.connection.keepaliveInterval ?? 15000,
|
||||
keepaliveCountMax: session.connection.keepaliveCountMax,
|
||||
readyTimeout: session.connection.readyTimeout,
|
||||
hostVerifier: (digest: string) => {
|
||||
log(colors.bgWhite(' ') + ' Host key fingerprint:')
|
||||
log(colors.bgWhite(' ') + ' ' + colors.black.bgWhite(' SHA256 ') + colors.bgBlackBright(' ' + digest + ' '))
|
||||
return true
|
||||
},
|
||||
hostHash: 'sha256' as any,
|
||||
algorithms,
|
||||
sock: session.jumpStream,
|
||||
authHandler: methodsLeft => {
|
||||
while (true) {
|
||||
const method = authMethodsLeft.shift()
|
||||
if (!method) {
|
||||
return false
|
||||
}
|
||||
if (methodsLeft && !methodsLeft.includes(method) && method !== 'agent') {
|
||||
// Agent can still be used even if not in methodsLeft
|
||||
this.logger.info('Server does not support auth method', method)
|
||||
continue
|
||||
}
|
||||
return method
|
||||
}
|
||||
},
|
||||
} as any)
|
||||
} catch (e) {
|
||||
this.notifications.error(e.message)
|
||||
return reject(e)
|
||||
}
|
||||
|
||||
let keychainPasswordUsed = false
|
||||
|
||||
;(ssh as any).config.password = () => this.zone.run(async () => {
|
||||
if (session.connection.password) {
|
||||
log('Using preset password')
|
||||
return session.connection.password
|
||||
}
|
||||
|
||||
if (!keychainPasswordUsed) {
|
||||
const password = await this.passwordStorage.loadPassword(session.connection)
|
||||
if (password) {
|
||||
log('Trying saved password')
|
||||
keychainPasswordUsed = true
|
||||
return password
|
||||
}
|
||||
}
|
||||
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = `Password for ${session.connection.user}@${session.connection.host}`
|
||||
modal.componentInstance.password = true
|
||||
modal.componentInstance.showRememberCheckbox = true
|
||||
try {
|
||||
const result = await modal.result
|
||||
if (result) {
|
||||
if (result.remember) {
|
||||
savedPassword = result.value
|
||||
}
|
||||
return result.value
|
||||
}
|
||||
return ''
|
||||
} catch (_) {
|
||||
return ''
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let agent: string|null = null
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
if (await fs.exists(WINDOWS_OPENSSH_AGENT_PIPE)) {
|
||||
agent = WINDOWS_OPENSSH_AGENT_PIPE
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const pageantRunning = await new Promise<boolean>(resolve => {
|
||||
windowsProcessTreeNative.getProcessList(list => { // eslint-disable-line block-scoped-var
|
||||
resolve(list.some(x => x.name === 'pageant.exe'))
|
||||
}, 0)
|
||||
})
|
||||
if (pageantRunning) {
|
||||
agent = 'pageant'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
agent = process.env.SSH_AUTH_SOCK!
|
||||
}
|
||||
|
||||
const authMethodsLeft = ['none']
|
||||
if (!session.connection.auth || session.connection.auth === 'publicKey') {
|
||||
try {
|
||||
privateKey = await this.loadPrivateKeyForSession(session)
|
||||
} catch (e) {
|
||||
session.emitServiceMessage(colors.bgYellow.yellow.black(' ! ') + ` Failed to load private key: ${e}`)
|
||||
}
|
||||
if (!privateKey) {
|
||||
session.emitServiceMessage(colors.bgYellow.yellow.black(' ! ') + ` Private key auth selected, but no key is loaded`)
|
||||
} else {
|
||||
authMethodsLeft.push('publickey')
|
||||
}
|
||||
}
|
||||
if (!session.connection.auth || session.connection.auth === 'agent') {
|
||||
if (!agent) {
|
||||
session.emitServiceMessage(colors.bgYellow.yellow.black(' ! ') + ` Agent auth selected, but no running agent is detected`)
|
||||
} else {
|
||||
authMethodsLeft.push('agent')
|
||||
}
|
||||
}
|
||||
if (!session.connection.auth || session.connection.auth === 'password') {
|
||||
authMethodsLeft.push('password')
|
||||
}
|
||||
if (!session.connection.auth || session.connection.auth === 'keyboardInteractive') {
|
||||
authMethodsLeft.push('keyboard-interactive')
|
||||
}
|
||||
authMethodsLeft.push('hostbased')
|
||||
|
||||
try {
|
||||
if (session.connection.proxyCommand) {
|
||||
session.emitServiceMessage(colors.bgBlue.black(' Proxy command ') + ` Using ${session.connection.proxyCommand}`)
|
||||
session.proxyCommandStream = new ProxyCommandStream(session.connection.proxyCommand)
|
||||
|
||||
session.proxyCommandStream.output$.subscribe((message: string) => {
|
||||
session.emitServiceMessage(colors.bgBlue.black(' Proxy command ') + ' ' + message.trim())
|
||||
})
|
||||
|
||||
await session.proxyCommandStream.start()
|
||||
}
|
||||
|
||||
ssh.connect({
|
||||
host: session.connection.host,
|
||||
port: session.connection.port ?? 22,
|
||||
sock: session.proxyCommandStream ?? session.jumpStream,
|
||||
username: session.connection.user,
|
||||
password: session.connection.privateKey ? undefined : '',
|
||||
privateKey: privateKey ?? undefined,
|
||||
tryKeyboard: true,
|
||||
agent: agent ?? undefined,
|
||||
agentForward: session.connection.agentForward && !!agent,
|
||||
keepaliveInterval: session.connection.keepaliveInterval ?? 15000,
|
||||
keepaliveCountMax: session.connection.keepaliveCountMax,
|
||||
readyTimeout: session.connection.readyTimeout,
|
||||
hostVerifier: (digest: string) => {
|
||||
log('Host key fingerprint:')
|
||||
log(colors.white.bgBlack(' SHA256 ') + colors.bgBlackBright(' ' + digest + ' '))
|
||||
return true
|
||||
},
|
||||
hostHash: 'sha256' as any,
|
||||
algorithms,
|
||||
authHandler: methodsLeft => {
|
||||
while (true) {
|
||||
const method = authMethodsLeft.shift()
|
||||
if (!method) {
|
||||
return false
|
||||
}
|
||||
if (methodsLeft && !methodsLeft.includes(method) && method !== 'agent') {
|
||||
// Agent can still be used even if not in methodsLeft
|
||||
this.logger.info('Server does not support auth method', method)
|
||||
continue
|
||||
}
|
||||
return method
|
||||
}
|
||||
},
|
||||
} as any)
|
||||
} catch (e) {
|
||||
this.notifications.error(e.message)
|
||||
throw e
|
||||
}
|
||||
|
||||
let keychainPasswordUsed = false
|
||||
|
||||
;(ssh as any).config.password = () => this.zone.run(async () => {
|
||||
if (session.connection.password) {
|
||||
log('Using preset password')
|
||||
return session.connection.password
|
||||
}
|
||||
|
||||
if (!keychainPasswordUsed) {
|
||||
const password = await this.passwordStorage.loadPassword(session.connection)
|
||||
if (password) {
|
||||
log('Trying saved password')
|
||||
keychainPasswordUsed = true
|
||||
return password
|
||||
}
|
||||
}
|
||||
|
||||
const modal = this.ngbModal.open(PromptModalComponent)
|
||||
modal.componentInstance.prompt = `Password for ${session.connection.user}@${session.connection.host}`
|
||||
modal.componentInstance.password = true
|
||||
modal.componentInstance.showRememberCheckbox = true
|
||||
try {
|
||||
const result = await modal.result
|
||||
if (result) {
|
||||
if (result.remember) {
|
||||
savedPassword = result.value
|
||||
}
|
||||
return result.value
|
||||
}
|
||||
return ''
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
return resultPromise
|
||||
}
|
||||
|
||||
async showConnectionSelector (): Promise<void> {
|
||||
@@ -448,6 +478,52 @@ export class SSHService {
|
||||
}
|
||||
}
|
||||
|
||||
export class ProxyCommandStream extends Duplex {
|
||||
private process: ChildProcess
|
||||
|
||||
get output$ (): Observable<string> { return this.output }
|
||||
private output = new Subject<string>()
|
||||
|
||||
constructor (private command: string) {
|
||||
super({
|
||||
allowHalfOpen: false,
|
||||
})
|
||||
}
|
||||
|
||||
async start (): Promise<void> {
|
||||
this.process = exec(this.command, {
|
||||
windowsHide: true,
|
||||
encoding: 'buffer',
|
||||
})
|
||||
this.process.on('exit', code => {
|
||||
this.destroy(new Error(`Proxy command has exited with code ${code}`))
|
||||
})
|
||||
this.process.stdout?.on('data', data => {
|
||||
this.push(data)
|
||||
})
|
||||
this.process.stdout?.on('error', (err) => {
|
||||
this.destroy(err)
|
||||
})
|
||||
this.process.stderr?.on('data', data => {
|
||||
this.output.next(data.toString())
|
||||
})
|
||||
}
|
||||
|
||||
_read (size: number): void {
|
||||
process.stdout.read(size)
|
||||
}
|
||||
|
||||
_write (chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void): void {
|
||||
this.process.stdin?.write(chunk, callback)
|
||||
}
|
||||
|
||||
_destroy (error: Error|null, callback: (error: Error|null) => void): void {
|
||||
this.process.kill()
|
||||
this.output.complete()
|
||||
callback(error)
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-disable */
|
||||
const _authPassword = SSH2Stream.prototype.authPassword
|
||||
SSH2Stream.prototype.authPassword = async function (username, passwordFn: any) {
|
||||
|
@@ -27,10 +27,10 @@ ansi-colors@^4.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
|
||||
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
|
||||
|
||||
ansi-regex@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
|
||||
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
|
||||
ansi-regex@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.0.tgz#ecc7f5933cbe5ac7b33e209a5ff409ab1669c6b2"
|
||||
integrity sha512-tAaOSrWCHF+1Ear1Z4wnJCXA9GGox4K6Ic85a5qalES2aeEwQGr7UC93mwef49536PkCYjzkp0zIxfFvexJ6zQ==
|
||||
|
||||
asn1@~0.2.0, asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
@@ -333,12 +333,12 @@ streamsearch@~0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
|
||||
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
|
||||
|
||||
strip-ansi@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
|
||||
integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
|
||||
strip-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.0.tgz#1dc49b980c3a4100366617adac59327eefdefcb0"
|
||||
integrity sha512-UhDTSnGF1dc0DRbUqr1aXwNoY3RgVkSWG8BrpnuFIxhP57IqbS7IRta2Gfiavds4yCxc5+fEAVVOgBZWnYkvzg==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
ansi-regex "^6.0.0"
|
||||
|
||||
temp@^0.9.1:
|
||||
version "0.9.4"
|
||||
|
@@ -29,13 +29,14 @@
|
||||
"ps-node": "^0.1.6",
|
||||
"runes": "^0.4.2",
|
||||
"slugify": "^1.4.0",
|
||||
"utils-decorators": "^1.8.1",
|
||||
"xterm": "^4.9.0-beta.7",
|
||||
"xterm-addon-fit": "^0.5.0",
|
||||
"xterm-addon-ligatures": "^0.4.0",
|
||||
"xterm-addon-ligatures": "^0.5.0",
|
||||
"xterm-addon-search": "^0.8.0",
|
||||
"xterm-addon-serialize": "^0.5.0",
|
||||
"xterm-addon-unicode11": "^0.2.0",
|
||||
"xterm-addon-webgl": "^0.10.0",
|
||||
"xterm-addon-webgl": "^0.11.0",
|
||||
"zmodem.js": "^0.1.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@@ -4,7 +4,7 @@ import { first } from 'rxjs/operators'
|
||||
import colors from 'ansi-colors'
|
||||
import { NgZone, OnInit, OnDestroy, Injector, ViewChild, HostBinding, Input, ElementRef, InjectFlags } from '@angular/core'
|
||||
import { trigger, transition, style, animate, AnimationTriggerMetadata } from '@angular/animations'
|
||||
import { AppService, ConfigService, BaseTabComponent, ElectronService, HostAppService, HotkeysService, NotificationsService, Platform, LogService, Logger, TabContextMenuItemProvider, SplitTabComponent } from 'terminus-core'
|
||||
import { AppService, ConfigService, BaseTabComponent, ElectronService, HostAppService, HotkeysService, NotificationsService, Platform, LogService, Logger, TabContextMenuItemProvider, SplitTabComponent, SubscriptionContainer } from 'terminus-core'
|
||||
|
||||
import { BaseSession, SessionsService } from '../services/sessions.service'
|
||||
import { TerminalFrontendService } from '../services/terminalFrontend.service'
|
||||
@@ -95,12 +95,10 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
protected logger: Logger
|
||||
protected output = new Subject<string>()
|
||||
protected sessionChanged = new Subject<BaseSession|null>()
|
||||
private sessionCloseSubscription: Subscription
|
||||
private hotkeysSubscription: Subscription
|
||||
private bellPlayer: HTMLAudioElement
|
||||
private termContainerSubscriptions: Subscription[] = []
|
||||
private termContainerSubscriptions = new SubscriptionContainer()
|
||||
private allFocusModeSubscription: Subscription|null = null
|
||||
private sessionHandlers: Subscription[] = []
|
||||
private sessionHandlers = new SubscriptionContainer()
|
||||
|
||||
get input$ (): Observable<Buffer> {
|
||||
if (!this.frontend) {
|
||||
@@ -149,7 +147,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
this.logger = this.log.create('baseTerminalTab')
|
||||
this.setTitle('Terminal')
|
||||
|
||||
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(async hotkey => {
|
||||
this.subscribeUntilDestroyed(this.hotkeys.matchedHotkey, async hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
return
|
||||
}
|
||||
@@ -225,7 +223,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
}
|
||||
})
|
||||
this.bellPlayer = document.createElement('audio')
|
||||
this.bellPlayer.src = require<string>('../bell.ogg')
|
||||
this.bellPlayer.src = require('../bell.ogg').default
|
||||
|
||||
this.contextMenuProviders.sort((a, b) => a.weight - b.weight)
|
||||
}
|
||||
@@ -475,7 +473,13 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
|
||||
/** @hidden */
|
||||
ngOnDestroy (): void {
|
||||
super.ngOnDestroy()
|
||||
}
|
||||
|
||||
async destroy (): Promise<void> {
|
||||
this.frontend?.detach(this.content.nativeElement)
|
||||
this.frontend = undefined
|
||||
this.content.nativeElement.remove()
|
||||
this.detachTermContainerHandlers()
|
||||
this.config.enabledServices(this.decorators).forEach(decorator => {
|
||||
try {
|
||||
@@ -484,14 +488,8 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
this.logger.warn('Decorator attach() throws', e)
|
||||
}
|
||||
})
|
||||
this.hotkeysSubscription.unsubscribe()
|
||||
if (this.sessionCloseSubscription) {
|
||||
this.sessionCloseSubscription.unsubscribe()
|
||||
}
|
||||
this.output.complete()
|
||||
}
|
||||
|
||||
async destroy (): Promise<void> {
|
||||
super.destroy()
|
||||
if (this.session?.open) {
|
||||
await this.session.destroy()
|
||||
@@ -499,10 +497,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
}
|
||||
|
||||
protected detachTermContainerHandlers (): void {
|
||||
for (const subscription of this.termContainerSubscriptions) {
|
||||
subscription.unsubscribe()
|
||||
}
|
||||
this.termContainerSubscriptions = []
|
||||
this.termContainerSubscriptions.cancelAll()
|
||||
}
|
||||
|
||||
protected attachTermContainerHandlers (): void {
|
||||
@@ -518,71 +513,69 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
}
|
||||
}
|
||||
|
||||
this.termContainerSubscriptions = [
|
||||
this.frontend.title$.subscribe(title => this.zone.run(() => {
|
||||
if (this.enableDynamicTitle) {
|
||||
this.setTitle(title)
|
||||
this.termContainerSubscriptions.subscribe(this.frontend.title$, title => this.zone.run(() => {
|
||||
if (this.enableDynamicTitle) {
|
||||
this.setTitle(title)
|
||||
}
|
||||
}))
|
||||
|
||||
this.termContainerSubscriptions.subscribe(this.focused$, () => this.frontend && (this.frontend.enableResizing = true))
|
||||
this.termContainerSubscriptions.subscribe(this.blurred$, () => this.frontend && (this.frontend.enableResizing = false))
|
||||
|
||||
this.termContainerSubscriptions.subscribe(this.frontend.mouseEvent$, async event => {
|
||||
if (event.type === 'mousedown') {
|
||||
if (event.which === 2) {
|
||||
if (this.config.store.terminal.pasteOnMiddleClick) {
|
||||
this.paste()
|
||||
}
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
}
|
||||
})),
|
||||
|
||||
this.focused$.subscribe(() => this.frontend && (this.frontend.enableResizing = true)),
|
||||
this.blurred$.subscribe(() => this.frontend && (this.frontend.enableResizing = false)),
|
||||
|
||||
this.frontend.mouseEvent$.subscribe(async event => {
|
||||
if (event.type === 'mousedown') {
|
||||
if (event.which === 2) {
|
||||
if (this.config.store.terminal.pasteOnMiddleClick) {
|
||||
this.paste()
|
||||
}
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
}
|
||||
if (event.which === 3 || event.which === 1 && event.ctrlKey) {
|
||||
if (this.config.store.terminal.rightClick === 'menu') {
|
||||
this.hostApp.popupContextMenu(await this.buildContextMenu())
|
||||
} else if (this.config.store.terminal.rightClick === 'paste') {
|
||||
this.paste()
|
||||
}
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
if (event.which === 3 || event.which === 1 && event.ctrlKey) {
|
||||
if (this.config.store.terminal.rightClick === 'menu') {
|
||||
this.hostApp.popupContextMenu(await this.buildContextMenu())
|
||||
} else if (this.config.store.terminal.rightClick === 'paste') {
|
||||
this.paste()
|
||||
}
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return
|
||||
}
|
||||
if (event.type === 'mousewheel') {
|
||||
let wheelDeltaY = 0
|
||||
}
|
||||
if (event.type === 'mousewheel') {
|
||||
let wheelDeltaY = 0
|
||||
|
||||
if ('wheelDeltaY' in event) {
|
||||
wheelDeltaY = (event as MouseWheelEvent)['wheelDeltaY']
|
||||
} else {
|
||||
wheelDeltaY = (event as MouseWheelEvent)['deltaY']
|
||||
}
|
||||
|
||||
if (event.altKey) {
|
||||
event.preventDefault()
|
||||
const delta = Math.round(wheelDeltaY / 50)
|
||||
this.sendInput((delta > 0 ? '\u001bOA' : '\u001bOB').repeat(Math.abs(delta)))
|
||||
}
|
||||
if ('wheelDeltaY' in event) {
|
||||
wheelDeltaY = (event as MouseWheelEvent)['wheelDeltaY']
|
||||
} else {
|
||||
wheelDeltaY = (event as MouseWheelEvent)['deltaY']
|
||||
}
|
||||
}),
|
||||
|
||||
this.frontend.input$.subscribe(data => {
|
||||
this.sendInput(data)
|
||||
}),
|
||||
if (event.altKey) {
|
||||
event.preventDefault()
|
||||
const delta = Math.round(wheelDeltaY / 50)
|
||||
this.sendInput((delta > 0 ? '\u001bOA' : '\u001bOB').repeat(Math.abs(delta)))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.frontend.resize$.subscribe(({ columns, rows }) => {
|
||||
this.logger.debug(`Resizing to ${columns}x${rows}`)
|
||||
this.size = { columns, rows }
|
||||
this.zone.run(() => {
|
||||
if (this.session?.open) {
|
||||
this.session.resize(columns, rows)
|
||||
}
|
||||
})
|
||||
}),
|
||||
this.termContainerSubscriptions.subscribe(this.frontend.input$, data => {
|
||||
this.sendInput(data)
|
||||
})
|
||||
|
||||
this.hostApp.displayMetricsChanged$.subscribe(maybeConfigure),
|
||||
this.hostApp.windowMoved$.subscribe(maybeConfigure),
|
||||
]
|
||||
this.termContainerSubscriptions.subscribe(this.frontend.resize$, ({ columns, rows }) => {
|
||||
this.logger.debug(`Resizing to ${columns}x${rows}`)
|
||||
this.size = { columns, rows }
|
||||
this.zone.run(() => {
|
||||
if (this.session?.open) {
|
||||
this.session.resize(columns, rows)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
this.termContainerSubscriptions.subscribe(this.hostApp.displayMetricsChanged$, maybeConfigure)
|
||||
this.termContainerSubscriptions.subscribe(this.hostApp.windowMoved$, maybeConfigure)
|
||||
}
|
||||
|
||||
setSession (session: BaseSession|null, destroyOnSessionClose = false): void {
|
||||
@@ -600,8 +593,8 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
this.sessionChanged.next(session)
|
||||
}
|
||||
|
||||
protected attachSessionHandler (subscription: Subscription): void {
|
||||
this.sessionHandlers.push(subscription)
|
||||
protected attachSessionHandler <T> (observable: Observable<T>, handler: (v: T) => void): void {
|
||||
this.sessionHandlers.subscribe(observable, handler)
|
||||
}
|
||||
|
||||
protected attachSessionHandlers (destroyOnSessionClose = false): void {
|
||||
@@ -610,29 +603,26 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
|
||||
}
|
||||
|
||||
// this.session.output$.bufferTime(10).subscribe((datas) => {
|
||||
this.attachSessionHandler(this.session.output$.subscribe(data => {
|
||||
this.attachSessionHandler(this.session.output$, data => {
|
||||
if (this.enablePassthrough) {
|
||||
this.output.next(data)
|
||||
this.write(data)
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
if (destroyOnSessionClose) {
|
||||
this.attachSessionHandler(this.sessionCloseSubscription = this.session.closed$.subscribe(() => {
|
||||
this.attachSessionHandler(this.session.closed$, () => {
|
||||
this.frontend?.destroy()
|
||||
this.destroy()
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
this.attachSessionHandler(this.session.destroyed$.subscribe(() => {
|
||||
this.attachSessionHandler(this.session.destroyed$, () => {
|
||||
this.setSession(null)
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
protected detachSessionHandlers (): void {
|
||||
for (const s of this.sessionHandlers) {
|
||||
s.unsubscribe()
|
||||
}
|
||||
this.sessionHandlers = []
|
||||
this.sessionHandlers.cancelAll()
|
||||
}
|
||||
}
|
||||
|
@@ -114,7 +114,7 @@ h3.mb-3 Appearance
|
||||
.header
|
||||
.title Custom CSS
|
||||
|
||||
textarea.form-control(
|
||||
textarea.form-control.mb-5(
|
||||
[(ngModel)]='config.store.appearance.css',
|
||||
(ngModelChange)='saveConfiguration()',
|
||||
)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { Observable } from 'rxjs'
|
||||
import { debounce } from 'utils-decorators/dist/cjs'
|
||||
import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'
|
||||
import { exec } from 'mz/child_process'
|
||||
const fontManager = require('fontmanager-redux') // eslint-disable-line
|
||||
@@ -23,11 +24,7 @@ export class AppearanceSettingsTabComponent {
|
||||
async ngOnInit () {
|
||||
if (this.hostApp.platform === Platform.Windows || this.hostApp.platform === Platform.macOS) {
|
||||
const fonts = await new Promise<any[]>((resolve) => fontManager.findFonts({ monospace: true }, resolve))
|
||||
if (this.hostApp.platform === Platform.Windows) {
|
||||
this.fonts = fonts.map(x => `${x.family} ${x.style}`.trim())
|
||||
} else {
|
||||
this.fonts = fonts.map(x => x.family.trim())
|
||||
}
|
||||
this.fonts = fonts.map(x => x.family.trim())
|
||||
this.fonts.sort()
|
||||
}
|
||||
if (this.hostApp.platform === Platform.Linux) {
|
||||
@@ -54,4 +51,12 @@ export class AppearanceSettingsTabComponent {
|
||||
getPreviewFontFamily () {
|
||||
return getCSSFontFamily(this.config.store)
|
||||
}
|
||||
|
||||
@debounce(500)
|
||||
saveConfiguration (requireRestart?: boolean) {
|
||||
this.config.save()
|
||||
if (requireRestart) {
|
||||
this.config.requestRestart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Component, Input, Injector } from '@angular/core'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { BaseTabProcess, WIN_BUILD_CONPTY_SUPPORTED, isWindowsBuild } from 'terminus-core'
|
||||
import { BaseTerminalTabComponent } from '../api/baseTerminalTab.component'
|
||||
import { SessionOptions } from '../api/interfaces'
|
||||
@@ -14,7 +13,6 @@ import { Session } from '../services/sessions.service'
|
||||
})
|
||||
export class TerminalTabComponent extends BaseTerminalTabComponent {
|
||||
@Input() sessionOptions: SessionOptions
|
||||
private homeEndSubscription: Subscription
|
||||
session: Session|null = null
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
@@ -30,7 +28,7 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
|
||||
|
||||
const isConPTY = isWindowsBuild(WIN_BUILD_CONPTY_SUPPORTED) && this.config.store.terminal.useConPTY
|
||||
|
||||
this.homeEndSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
|
||||
this.subscribeUntilDestroyed(this.hotkeys.matchedHotkey, hotkey => {
|
||||
if (!this.hasFocus) {
|
||||
return
|
||||
}
|
||||
@@ -106,7 +104,6 @@ export class TerminalTabComponent extends BaseTerminalTabComponent {
|
||||
}
|
||||
|
||||
ngOnDestroy (): void {
|
||||
this.homeEndSubscription.unsubscribe()
|
||||
super.ngOnDestroy()
|
||||
this.session?.destroy()
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ export class DebugDecorator extends TerminalDecorator {
|
||||
}
|
||||
}))
|
||||
|
||||
terminal.content.nativeElement.addEventListener('keyup', e => {
|
||||
terminal.addEventListenerUntilDestroyed(terminal.content.nativeElement, 'keyup', (e: KeyboardEvent) => {
|
||||
// Ctrl-Shift-Alt-1
|
||||
if (e.which === 49 && e.ctrlKey && e.shiftKey && e.altKey) {
|
||||
this.doSaveState(terminal)
|
||||
|
@@ -24,6 +24,7 @@ export class XTermFrontend extends Frontend {
|
||||
protected xtermCore: any
|
||||
protected enableWebGL = false
|
||||
private xterm: Terminal
|
||||
private element?: HTMLElement
|
||||
private configuredFontSize = 0
|
||||
private configuredLinePadding = 0
|
||||
private zoom = 0
|
||||
@@ -34,7 +35,9 @@ export class XTermFrontend extends Frontend {
|
||||
private fitAddon = new FitAddon()
|
||||
private serializeAddon = new SerializeAddon()
|
||||
private ligaturesAddon?: LigaturesAddon
|
||||
private webGLAddon?: WebglAddon
|
||||
private opened = false
|
||||
private resizeObserver?: any
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
@@ -61,6 +64,9 @@ export class XTermFrontend extends Frontend {
|
||||
this.copySelection()
|
||||
}
|
||||
})
|
||||
this.xterm.onBell(() => {
|
||||
this.bell.next()
|
||||
})
|
||||
|
||||
this.xterm.loadAddon(this.fitAddon)
|
||||
this.xterm.loadAddon(this.serializeAddon)
|
||||
@@ -133,6 +139,7 @@ export class XTermFrontend extends Frontend {
|
||||
|
||||
async attach (host: HTMLElement): Promise<void> {
|
||||
this.configure()
|
||||
this.element = host
|
||||
|
||||
this.xterm.open(host)
|
||||
this.opened = true
|
||||
@@ -141,7 +148,8 @@ export class XTermFrontend extends Frontend {
|
||||
await new Promise(resolve => setTimeout(resolve, process.env.XWEB ? 1000 : 0))
|
||||
|
||||
if (this.enableWebGL) {
|
||||
this.xterm.loadAddon(new WebglAddon())
|
||||
this.webGLAddon = new WebglAddon()
|
||||
this.xterm.loadAddon(this.webGLAddon)
|
||||
}
|
||||
|
||||
this.ready.next()
|
||||
@@ -160,12 +168,19 @@ export class XTermFrontend extends Frontend {
|
||||
host.addEventListener('mouseup', event => this.mouseEvent.next(event))
|
||||
host.addEventListener('mousewheel', event => this.mouseEvent.next(event as MouseEvent))
|
||||
|
||||
const ro = new window['ResizeObserver'](() => setTimeout(() => this.resizeHandler()))
|
||||
ro.observe(host)
|
||||
this.resizeObserver = new window['ResizeObserver'](() => setTimeout(() => this.resizeHandler()))
|
||||
this.resizeObserver.observe(host)
|
||||
}
|
||||
|
||||
detach (_host: HTMLElement): void {
|
||||
window.removeEventListener('resize', this.resizeHandler)
|
||||
this.resizeObserver?.disconnect()
|
||||
}
|
||||
|
||||
destroy (): void {
|
||||
super.destroy()
|
||||
this.webGLAddon?.dispose()
|
||||
this.xterm.dispose()
|
||||
}
|
||||
|
||||
getSelection (): string {
|
||||
@@ -207,7 +222,12 @@ export class XTermFrontend extends Frontend {
|
||||
}
|
||||
|
||||
visualBell (): void {
|
||||
this.xtermCore.bell()
|
||||
if (this.element) {
|
||||
this.element.style.animation = 'none'
|
||||
setTimeout(() => {
|
||||
this.element!.style.animation = 'terminalShakeFrames 0.3s ease'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
scrollToBottom (): void {
|
||||
|
@@ -147,6 +147,7 @@ export abstract class BaseSession {
|
||||
/** @hidden */
|
||||
export class Session extends BaseSession {
|
||||
private pty: PTYProxy|null = null
|
||||
private ptyClosed = false
|
||||
private pauseAfterExit = false
|
||||
private guessedCWD: string|null = null
|
||||
private reportedCWD: string
|
||||
@@ -175,6 +176,8 @@ export class Session extends BaseSession {
|
||||
...this.config.store.terminal.environment || {},
|
||||
}
|
||||
|
||||
delete env['']
|
||||
|
||||
if (process.platform === 'darwin' && !process.env.LC_ALL) {
|
||||
const locale = process.env.LC_CTYPE ?? 'en_US.UTF-8'
|
||||
Object.assign(env, {
|
||||
@@ -244,6 +247,7 @@ export class Session extends BaseSession {
|
||||
})
|
||||
|
||||
this.pty.subscribe('close', () => {
|
||||
this.ptyClosed = true
|
||||
if (this.pauseAfterExit) {
|
||||
this.emitOutput(Buffer.from('\r\nPress any key to close\r\n'))
|
||||
} else if (this.open) {
|
||||
@@ -265,12 +269,11 @@ export class Session extends BaseSession {
|
||||
}
|
||||
|
||||
write (data: Buffer): void {
|
||||
if (this.ptyClosed) {
|
||||
this.destroy()
|
||||
}
|
||||
if (this.open) {
|
||||
this.pty?.write(data)
|
||||
// TODO if (this.pty._writable) {
|
||||
// } else {
|
||||
// this.destroy()
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -119,13 +119,13 @@ font-finder@^1.0.3, font-finder@^1.1.0:
|
||||
get-system-fonts "^2.0.0"
|
||||
promise-stream-reader "^1.0.1"
|
||||
|
||||
font-ligatures@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/font-ligatures/-/font-ligatures-1.3.3.tgz#63fff18dc8adb3a11fe5eec1f4e8d7edfa8075b9"
|
||||
integrity sha512-NSGpHgVNX81M7AWS1XylK1UZbN3QllfUIDAAuPv6TUcl5O2b781JcKS5L2RopAU0AqlTyX3ZuX/04eaMpbVrHA==
|
||||
font-ligatures@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/font-ligatures/-/font-ligatures-1.4.0.tgz#6a7b370d96be1358dddfad67830e82fbfd59e6dc"
|
||||
integrity sha512-n7DFnnEpJ0NrVoLqZIL4tMGVs+CnFwQc92m80LWyrbgAFO4x234+t2/H9o4eOYA1eh6ta9dZAEEsJAwsBdNezA==
|
||||
dependencies:
|
||||
font-finder "^1.0.3"
|
||||
lru-cache "^4.1.3"
|
||||
lru-cache "^6.0.0"
|
||||
opentype.js "^0.8.0"
|
||||
|
||||
function-bind@^1.1.1:
|
||||
@@ -198,13 +198,12 @@ is-symbol@^1.0.2:
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
lru-cache@^4.1.3:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
|
||||
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
pseudomap "^1.0.2"
|
||||
yallist "^2.1.2"
|
||||
yallist "^4.0.0"
|
||||
|
||||
mz@^2.6.0:
|
||||
version "2.7.0"
|
||||
@@ -280,11 +279,6 @@ ps-node@^0.1.6:
|
||||
dependencies:
|
||||
table-parser "^0.1.3"
|
||||
|
||||
pseudomap@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||
|
||||
regexp.prototype.flags@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
|
||||
@@ -350,18 +344,30 @@ tiny-inflate@^1.0.2, tiny-inflate@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4"
|
||||
integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==
|
||||
|
||||
tinyqueue@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
|
||||
integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
|
||||
|
||||
utils-decorators@^1.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/utils-decorators/-/utils-decorators-1.8.1.tgz#6e7e2cf46c05a9554c05f004e5235696142bd5f7"
|
||||
integrity sha512-UpqzJj40jdTknZpxdeYL7p+8Ynl3bpHP6yoxoY+RmuDCOaelTiOz4GcDpScPvfZhv/ivHTV1bPJZeQd8tlxczA==
|
||||
dependencies:
|
||||
tinyqueue "^2.0.3"
|
||||
|
||||
xterm-addon-fit@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
|
||||
integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==
|
||||
|
||||
xterm-addon-ligatures@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-ligatures/-/xterm-addon-ligatures-0.4.0.tgz#23235d831988c5780ca1e28002b750ec0b1a78ca"
|
||||
integrity sha512-on+2TgzioEL5Mz60WchsTiuR2SvYzG3xVro39HIpYFM641lpMuPM83Pdm3W/ogkaGrpGm29Ysq2S2LCl/h7rhw==
|
||||
xterm-addon-ligatures@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-ligatures/-/xterm-addon-ligatures-0.5.0.tgz#08cd4dd3bcd3c4faa657a1995a5a8a6a6c39c496"
|
||||
integrity sha512-1HFeEReL2yfw1oz7iZHE09ipWOA23Pg7yRAgDnuKeWkuItKRZZ9SbKXn8saviAkHYX/s6HgADVwPjRY8m2lyZA==
|
||||
dependencies:
|
||||
font-finder "^1.1.0"
|
||||
font-ligatures "^1.3.3"
|
||||
font-ligatures "^1.4.0"
|
||||
|
||||
xterm-addon-search@^0.8.0:
|
||||
version "0.8.0"
|
||||
@@ -378,20 +384,20 @@ xterm-addon-unicode11@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.2.0.tgz#9ed0c482b353908bba27778893ca80823382737c"
|
||||
integrity sha512-rjFDItPc/IDoSiEnoDFwKroNwLD/7t9vYKENjrcKVZg5tgJuuUj8D4rZtP6iVCjSB1LTLYmUs4L/EmCqIyLR/Q==
|
||||
|
||||
xterm-addon-webgl@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.10.0.tgz#e99366fdc4cbd46b798a5e2fc114ecc19f9fd4b7"
|
||||
integrity sha512-MJzyWie5yw+PH6p//fXlXzmsULLtpBo992EWEKl2uv5M5Zj9etTwfuutCUK7o98mr6itDl+vS/CYIMP68jCf8w==
|
||||
xterm-addon-webgl@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.0.tgz#9601ee21cbd092c35c5b01b6ba6ea63767209515"
|
||||
integrity sha512-ohrvmACebnbYyTALbx6AC8GKqfK/heCeO9WWIProjoKatVYFTUD5m8KD6Mk2mbBZOOMgEwLajpcl0ujO2YH9Uw==
|
||||
|
||||
xterm@^4.9.0-beta.7:
|
||||
version "4.11.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.11.0.tgz#d7dabc7af5299579e4663fedf2b3a179af9aaff9"
|
||||
integrity sha512-NeJH909WTO2vth/ZlC0gkP3AGzupbvVHVlmtrpBw56/sGFXaF9bNdKgqKa3tf8qbGvXMzL2JhCcHVklqFztIRw==
|
||||
version "4.12.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.12.0.tgz#db09b425b4dcae5b96f8cbbaaa93b3bc60997ca9"
|
||||
integrity sha512-K5mF/p3txUV18mjiZFlElagoHFpqXrm5OYHeoymeXSu8GG/nMaOO/+NRcNCwfdjzAbdQ5VLF32hEHiWWKKm0bw==
|
||||
|
||||
yallist@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
||||
zmodem.js@^0.1.9:
|
||||
version "0.1.10"
|
||||
|
@@ -7,7 +7,7 @@ const bundleAnalyzer = new BundleAnalyzerPlugin({
|
||||
|
||||
module.exports = options => {
|
||||
const isDev = !!process.env.TERMINUS_DEV
|
||||
const devtool = isDev && process.platform === 'win32' ? 'eval-cheap-module-source-map' : 'cheap-module-source-map'
|
||||
const devtool = process.env.WEBPACK_DEVTOOL ?? (isDev && process.platform === 'win32' ? 'eval-cheap-module-source-map' : 'cheap-module-source-map')
|
||||
const config = {
|
||||
target: 'node',
|
||||
entry: 'src/index.ts',
|
||||
|
539
yarn.lock
539
yarn.lock
@@ -82,10 +82,10 @@
|
||||
dir-compare "^2.4.0"
|
||||
fs-extra "^9.0.1"
|
||||
|
||||
"@eslint/eslintrc@^0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547"
|
||||
integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==
|
||||
"@eslint/eslintrc@^0.4.1":
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14"
|
||||
integrity sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.1.1"
|
||||
@@ -130,6 +130,14 @@
|
||||
"@nodelib/fs.scandir" "2.1.4"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@npmcli/move-file@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674"
|
||||
integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==
|
||||
dependencies:
|
||||
mkdirp "^1.0.4"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
"@polka/url@^1.0.0-next.9":
|
||||
version "1.0.0-next.12"
|
||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.12.tgz#431ec342a7195622f86688bbda82e3166ce8cb28"
|
||||
@@ -145,14 +153,15 @@
|
||||
"@sentry/utils" "5.27.6"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/cli@^1.63.1":
|
||||
version "1.63.1"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.63.1.tgz#306a0591190432574082d4ce4a72363201972461"
|
||||
integrity sha512-qksIcrnObkGvtubs1FmW4EMXLo7R43Dobgzuxnyoebo1Y5KfRLziiw6H+ux8D4c1Nui4SuvDGDq0ObAfO5oE6Q==
|
||||
"@sentry/cli@^1.64.2":
|
||||
version "1.64.2"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.64.2.tgz#38a68d31692675061fdedd27d4006a249bc915a9"
|
||||
integrity sha512-hBF8cswn878W7YqAgeg/vcQ51BgtpeiklGV6Q5MEXqGXtbjaKTBYBcKTkhzpkkcUtTu5bFkVcdGzVtpl4oBe+g==
|
||||
dependencies:
|
||||
https-proxy-agent "^5.0.0"
|
||||
mkdirp "^0.5.5"
|
||||
node-fetch "^2.6.0"
|
||||
npmlog "^4.1.2"
|
||||
progress "^2.0.3"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
@@ -268,6 +277,11 @@
|
||||
dependencies:
|
||||
loader-utils "^1.0.0"
|
||||
|
||||
"@tootallnate/once@1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@types/babel-types@*", "@types/babel-types@^7.0.0":
|
||||
version "7.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.9.tgz#01d7b86949f455402a94c788883fe4ba574cad41"
|
||||
@@ -330,10 +344,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe"
|
||||
integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==
|
||||
|
||||
"@types/fs-extra@^9.0.1", "@types/fs-extra@^9.0.7", "@types/fs-extra@^9.0.9":
|
||||
version "9.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.9.tgz#11ed43b3f3c6b3490f1ef9bd17f58da896e2d861"
|
||||
integrity sha512-5TqDycCl0oMzwzd1cIjSJWMKMvLCDVErle4ZTjU4EmHDURR/+yZghe6GDHMCpHtcVfq0x0gMoOM546/5TbYHrg==
|
||||
"@types/fs-extra@^9.0.1", "@types/fs-extra@^9.0.11", "@types/fs-extra@^9.0.7":
|
||||
version "9.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.11.tgz#8cc99e103499eab9f347dbc6ca4e99fb8d2c2b87"
|
||||
integrity sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
@@ -382,7 +396,12 @@
|
||||
resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz"
|
||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||
|
||||
"@types/node@*", "@types/node@14.14.35", "@types/node@^14.6.2":
|
||||
"@types/node@*":
|
||||
version "15.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.2.tgz#51e9c0920d1b45936ea04341aa3e2e58d339fb67"
|
||||
integrity sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==
|
||||
|
||||
"@types/node@14.14.35", "@types/node@^14.6.2":
|
||||
version "14.14.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313"
|
||||
integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==
|
||||
@@ -450,14 +469,14 @@
|
||||
eslint-scope "^5.0.0"
|
||||
eslint-utils "^2.0.0"
|
||||
|
||||
"@typescript-eslint/parser@^4.17.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.18.0.tgz#a211edb14a69fc5177054bec04c95b185b4dde21"
|
||||
integrity sha512-W3z5S0ZbecwX3PhJEAnq4mnjK5JJXvXUDBYIYGoweCyWyuvAKfGHvzmpUzgB5L4cRBb+cTu9U/ro66dx7dIimA==
|
||||
"@typescript-eslint/parser@^4.23.0":
|
||||
version "4.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.23.0.tgz#239315d38e42e852bef43a4b0b01bef78f78911c"
|
||||
integrity sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "4.18.0"
|
||||
"@typescript-eslint/types" "4.18.0"
|
||||
"@typescript-eslint/typescript-estree" "4.18.0"
|
||||
"@typescript-eslint/scope-manager" "4.23.0"
|
||||
"@typescript-eslint/types" "4.23.0"
|
||||
"@typescript-eslint/typescript-estree" "4.23.0"
|
||||
debug "^4.1.1"
|
||||
|
||||
"@typescript-eslint/scope-manager@4.18.0":
|
||||
@@ -468,11 +487,24 @@
|
||||
"@typescript-eslint/types" "4.18.0"
|
||||
"@typescript-eslint/visitor-keys" "4.18.0"
|
||||
|
||||
"@typescript-eslint/scope-manager@4.23.0":
|
||||
version "4.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz#8792ef7eacac122e2ec8fa2d30a59b8d9a1f1ce4"
|
||||
integrity sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "4.23.0"
|
||||
"@typescript-eslint/visitor-keys" "4.23.0"
|
||||
|
||||
"@typescript-eslint/types@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.18.0.tgz#bebe323f81f2a7e2e320fac9415e60856267584a"
|
||||
integrity sha512-/BRociARpj5E+9yQ7cwCF/SNOWwXJ3qhjurMuK2hIFUbr9vTuDeu476Zpu+ptxY2kSxUHDGLLKy+qGq2sOg37A==
|
||||
|
||||
"@typescript-eslint/types@4.23.0":
|
||||
version "4.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.23.0.tgz#da1654c8a5332f4d1645b2d9a1c64193cae3aa3b"
|
||||
integrity sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw==
|
||||
|
||||
"@typescript-eslint/typescript-estree@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.18.0.tgz#756d3e61da8c16ab99185532c44872f4cd5538cb"
|
||||
@@ -486,6 +518,19 @@
|
||||
semver "^7.3.2"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/typescript-estree@4.23.0":
|
||||
version "4.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz#0753b292097523852428a6f5a1aa8ccc1aae6cd9"
|
||||
integrity sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "4.23.0"
|
||||
"@typescript-eslint/visitor-keys" "4.23.0"
|
||||
debug "^4.1.1"
|
||||
globby "^11.0.1"
|
||||
is-glob "^4.0.1"
|
||||
semver "^7.3.2"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/visitor-keys@4.18.0":
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.18.0.tgz#4e6fe2a175ee33418318a029610845a81e2ff7b6"
|
||||
@@ -494,6 +539,14 @@
|
||||
"@typescript-eslint/types" "4.18.0"
|
||||
eslint-visitor-keys "^2.0.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@4.23.0":
|
||||
version "4.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz#7215cc977bd3b4ef22467b9023594e32f9e4e455"
|
||||
integrity sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "4.23.0"
|
||||
eslint-visitor-keys "^2.0.0"
|
||||
|
||||
"@webassemblyjs/ast@1.11.0":
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f"
|
||||
@@ -723,6 +776,23 @@ agentkeepalive@^3.3.0:
|
||||
dependencies:
|
||||
humanize-ms "^1.2.1"
|
||||
|
||||
agentkeepalive@^4.1.3:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b"
|
||||
integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
depd "^1.1.2"
|
||||
humanize-ms "^1.2.1"
|
||||
|
||||
aggregate-error@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
|
||||
integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
|
||||
dependencies:
|
||||
clean-stack "^2.0.0"
|
||||
indent-string "^4.0.0"
|
||||
|
||||
ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
|
||||
version "3.5.2"
|
||||
resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz"
|
||||
@@ -1367,6 +1437,29 @@ builtins@^1.0.3:
|
||||
resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz"
|
||||
integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og=
|
||||
|
||||
cacache@^15.0.5:
|
||||
version "15.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.6.tgz#65a8c580fda15b59150fb76bf3f3a8e45d583099"
|
||||
integrity sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==
|
||||
dependencies:
|
||||
"@npmcli/move-file" "^1.0.1"
|
||||
chownr "^2.0.0"
|
||||
fs-minipass "^2.0.0"
|
||||
glob "^7.1.4"
|
||||
infer-owner "^1.0.4"
|
||||
lru-cache "^6.0.0"
|
||||
minipass "^3.1.1"
|
||||
minipass-collect "^1.0.2"
|
||||
minipass-flush "^1.0.5"
|
||||
minipass-pipeline "^1.2.2"
|
||||
mkdirp "^1.0.3"
|
||||
p-map "^4.0.0"
|
||||
promise-inflight "^1.0.1"
|
||||
rimraf "^3.0.2"
|
||||
ssri "^8.0.1"
|
||||
tar "^6.0.2"
|
||||
unique-filename "^1.1.1"
|
||||
|
||||
cacache@^9.2.9, cacache@~9.2.9:
|
||||
version "9.2.9"
|
||||
resolved "https://registry.npmjs.org/cacache/-/cacache-9.2.9.tgz"
|
||||
@@ -1603,6 +1696,11 @@ clean-css@^4.1.11, clean-css@^4.2.3:
|
||||
dependencies:
|
||||
source-map "~0.6.0"
|
||||
|
||||
clean-stack@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
|
||||
|
||||
cli-boxes@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz"
|
||||
@@ -1749,12 +1847,7 @@ color-name@~1.1.4:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
colorette@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz"
|
||||
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
|
||||
|
||||
colorette@^1.2.2:
|
||||
colorette@^1.2.1, colorette@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
|
||||
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
|
||||
@@ -1968,10 +2061,10 @@ core-js@^2.4.0:
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
|
||||
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
|
||||
|
||||
core-js@^3.6.5, core-js@^3.9.1:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.9.1.tgz#cec8de593db8eb2a85ffb0dbdeb312cb6e5460ae"
|
||||
integrity sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==
|
||||
core-js@^3.12.1, core-js@^3.6.5:
|
||||
version "3.12.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.12.1.tgz#6b5af4ff55616c08a44d386f1f510917ff204112"
|
||||
integrity sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw==
|
||||
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
@@ -2115,7 +2208,7 @@ debug@3.1.0:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2:
|
||||
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz"
|
||||
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
|
||||
@@ -2136,13 +2229,6 @@ debug@^3.0.0, debug@^3.1.0, debug@^3.2.6:
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.0.1, debug@^4.1.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
|
||||
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
debuglog@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz"
|
||||
@@ -2238,6 +2324,11 @@ delegates@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
depd@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
|
||||
|
||||
detect-indent@~5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz"
|
||||
@@ -2560,10 +2651,10 @@ electron-to-chromium@^1.3.621:
|
||||
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz"
|
||||
integrity sha512-iSPPJtPvHrMAvYOt+9cdbDmTasPqwnwz4lkP8Dn200gDNUBQOLQ96xUsWXBwXslAo5XxdoXAoQQ3RAy4uao9IQ==
|
||||
|
||||
electron@12.0.2:
|
||||
version "12.0.2"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-12.0.2.tgz#d92be205f1937627bd6718aad44ac161382b4c2d"
|
||||
integrity sha512-14luh9mGzfL4e0sncyy0+kW37IU7Y0Y1tvI97FDRSW0ZBQxi5cmAwSs5dmPmNBFBIGtzkaGaEB01j9RjZuCmow==
|
||||
electron@12.0.6:
|
||||
version "12.0.6"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-12.0.6.tgz#2d72fa5a7db553dca3a771b22aa13a676122b4af"
|
||||
integrity sha512-+fqhpdG6Fd6LzsizMdaSPC1I8tfsMT8/7fsYBgABED3hEWdus/rt6CQ54P3/EWZyQebtyHR6HXtlofUqKMV3KQ==
|
||||
dependencies:
|
||||
"@electron/get" "^1.0.1"
|
||||
"@types/node" "^14.6.2"
|
||||
@@ -2601,6 +2692,13 @@ encoding@^0.1.11:
|
||||
dependencies:
|
||||
iconv-lite "~0.4.13"
|
||||
|
||||
encoding@^0.1.12:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
|
||||
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
|
||||
dependencies:
|
||||
iconv-lite "^0.6.2"
|
||||
|
||||
end-of-stream@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz"
|
||||
@@ -2659,6 +2757,11 @@ err-code@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz"
|
||||
integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=
|
||||
|
||||
err-code@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
|
||||
integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
|
||||
|
||||
errlop@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/errlop/-/errlop-4.1.0.tgz#8e7b8f4f1bf0a6feafce4d14f0c0cf4bf5ef036b"
|
||||
@@ -2840,13 +2943,13 @@ eslint-visitor-keys@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
|
||||
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
|
||||
|
||||
eslint@^7.18.0:
|
||||
version "7.22.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.22.0.tgz#07ecc61052fec63661a2cab6bd507127c07adc6f"
|
||||
integrity sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg==
|
||||
eslint@^7.26.0:
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.26.0.tgz#d416fdcdcb3236cd8f282065312813f8c13982f6"
|
||||
integrity sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "7.12.11"
|
||||
"@eslint/eslintrc" "^0.4.0"
|
||||
"@eslint/eslintrc" "^0.4.1"
|
||||
ajv "^6.10.0"
|
||||
chalk "^4.0.0"
|
||||
cross-spawn "^7.0.2"
|
||||
@@ -3467,7 +3570,7 @@ glob-to-regexp@^0.4.1:
|
||||
resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz"
|
||||
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1:
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1, glob@~7.1.2:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz"
|
||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||
@@ -3479,18 +3582,6 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, gl
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.5, glob@^7.1.1, glob@~7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz"
|
||||
integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
global-agent@^2.0.2:
|
||||
version "2.1.12"
|
||||
resolved "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz"
|
||||
@@ -3826,7 +3917,7 @@ http-cache-semantics@^3.7.3:
|
||||
resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.7.3.tgz"
|
||||
integrity sha1-LzXFMuzSnx5UE7mvgztySjxvf3I=
|
||||
|
||||
http-cache-semantics@^4.0.0:
|
||||
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
|
||||
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==
|
||||
@@ -3839,6 +3930,15 @@ http-proxy-agent@^2.0.0:
|
||||
agent-base "4"
|
||||
debug "3.1.0"
|
||||
|
||||
http-proxy-agent@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
|
||||
integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
|
||||
dependencies:
|
||||
"@tootallnate/once" "1"
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
http-signature@~1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz"
|
||||
@@ -3985,11 +4085,21 @@ indent-string@^2.1.0:
|
||||
dependencies:
|
||||
repeating "^2.0.0"
|
||||
|
||||
indent-string@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
||||
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
|
||||
|
||||
indexes-of@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz"
|
||||
integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
|
||||
|
||||
infer-owner@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
|
||||
integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
|
||||
|
||||
inflight@^1.0.4, inflight@~1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
@@ -4042,7 +4152,7 @@ invert-kv@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz"
|
||||
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
|
||||
|
||||
ip@^1.1.4:
|
||||
ip@^1.1.4, ip@^1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz"
|
||||
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
|
||||
@@ -4229,6 +4339,11 @@ is-interactive@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz"
|
||||
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
|
||||
|
||||
is-lambda@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5"
|
||||
integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=
|
||||
|
||||
is-negative-zero@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz"
|
||||
@@ -4979,6 +5094,27 @@ make-fetch-happen@^2.4.13:
|
||||
socks-proxy-agent "^3.0.0"
|
||||
ssri "^4.1.6"
|
||||
|
||||
make-fetch-happen@^8.0.14:
|
||||
version "8.0.14"
|
||||
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222"
|
||||
integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==
|
||||
dependencies:
|
||||
agentkeepalive "^4.1.3"
|
||||
cacache "^15.0.5"
|
||||
http-cache-semantics "^4.1.0"
|
||||
http-proxy-agent "^4.0.1"
|
||||
https-proxy-agent "^5.0.0"
|
||||
is-lambda "^1.0.1"
|
||||
lru-cache "^6.0.0"
|
||||
minipass "^3.1.3"
|
||||
minipass-collect "^1.0.2"
|
||||
minipass-fetch "^1.3.2"
|
||||
minipass-flush "^1.0.5"
|
||||
minipass-pipeline "^1.2.4"
|
||||
promise-retry "^2.0.1"
|
||||
socks-proxy-agent "^5.0.0"
|
||||
ssri "^8.0.0"
|
||||
|
||||
map-age-cleaner@^0.1.1:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz"
|
||||
@@ -5003,10 +5139,10 @@ map-visit@^1.0.0:
|
||||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
marked@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-2.0.1.tgz#5e7ed7009bfa5c95182e4eb696f85e948cefcee3"
|
||||
integrity sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==
|
||||
marked@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-2.0.3.tgz#3551c4958c4da36897bda2a16812ef1399c8d6b0"
|
||||
integrity sha512-5otztIIcJfPc2qGTN8cVtOJEjNJZ0jwa46INMagrYfk0EvqtRuEHLsEe0LrFS0/q+ZRKT0+kXK7P2T1AN5lWRA==
|
||||
|
||||
matcher@^3.0.0:
|
||||
version "3.0.0"
|
||||
@@ -5129,6 +5265,45 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minipass-collect@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
|
||||
integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-fetch@^1.3.2:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.3.3.tgz#34c7cea038c817a8658461bf35174551dce17a0a"
|
||||
integrity sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ==
|
||||
dependencies:
|
||||
minipass "^3.1.0"
|
||||
minipass-sized "^1.0.3"
|
||||
minizlib "^2.0.0"
|
||||
optionalDependencies:
|
||||
encoding "^0.1.12"
|
||||
|
||||
minipass-flush@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373"
|
||||
integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c"
|
||||
integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-sized@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70"
|
||||
integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz"
|
||||
@@ -5137,7 +5312,7 @@ minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
|
||||
minipass@^3.0.0:
|
||||
minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz"
|
||||
integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==
|
||||
@@ -5151,7 +5326,7 @@ minizlib@^1.2.1:
|
||||
dependencies:
|
||||
minipass "^2.9.0"
|
||||
|
||||
minizlib@^2.1.1:
|
||||
minizlib@^2.0.0, minizlib@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz"
|
||||
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
|
||||
@@ -5190,7 +5365,7 @@ mixin-deep@^1.2.0:
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
mkdirp@^1.0.3:
|
||||
mkdirp@^1.0.3, mkdirp@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
@@ -5237,10 +5412,10 @@ nan@^2.13.2:
|
||||
resolved "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz"
|
||||
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
|
||||
|
||||
nanoid@^3.1.20:
|
||||
version "3.1.20"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
|
||||
integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
|
||||
nanoid@^3.1.23:
|
||||
version "3.1.23"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
|
||||
integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
@@ -5322,7 +5497,7 @@ node-fetch@^2.6.0:
|
||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-gyp@^7.1.0, node-gyp@^7.1.2:
|
||||
node-gyp@^7.1.0:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz"
|
||||
integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==
|
||||
@@ -5338,6 +5513,22 @@ node-gyp@^7.1.0, node-gyp@^7.1.2:
|
||||
tar "^6.0.2"
|
||||
which "^2.0.2"
|
||||
|
||||
node-gyp@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.0.0.tgz#225af2b06b8419ae81f924bf25ae4c167f6378a5"
|
||||
integrity sha512-Jod6NxyWtcwrpAQe0O/aXOpC5QfncotgtG73dg65z6VW/C6g/G4jiajXQUBIJ8pk/VfM6mBYE9BN/HvudTunUQ==
|
||||
dependencies:
|
||||
env-paths "^2.2.0"
|
||||
glob "^7.1.4"
|
||||
graceful-fs "^4.2.6"
|
||||
make-fetch-happen "^8.0.14"
|
||||
nopt "^5.0.0"
|
||||
npmlog "^4.1.2"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.0"
|
||||
which "^2.0.2"
|
||||
|
||||
node-gyp@~3.6.2:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz"
|
||||
@@ -5407,7 +5598,7 @@ node-sass@^5.0.0:
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@^4.0.1:
|
||||
nopt@^4.0.1, nopt@~4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz"
|
||||
integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==
|
||||
@@ -5422,14 +5613,6 @@ nopt@^5.0.0:
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@~4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz"
|
||||
integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
osenv "^0.1.4"
|
||||
|
||||
normalize-package-data@^2.0.0, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz"
|
||||
@@ -5870,15 +6053,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
|
||||
resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
|
||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||
|
||||
osenv@0, osenv@~0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz"
|
||||
integrity sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=
|
||||
dependencies:
|
||||
os-homedir "^1.0.0"
|
||||
os-tmpdir "^1.0.0"
|
||||
|
||||
osenv@^0.1.4, osenv@^0.1.5:
|
||||
osenv@0, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz"
|
||||
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
|
||||
@@ -5953,6 +6128,13 @@ p-locate@^4.1.0:
|
||||
dependencies:
|
||||
p-limit "^2.2.0"
|
||||
|
||||
p-map@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
|
||||
integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
|
||||
dependencies:
|
||||
aggregate-error "^3.0.0"
|
||||
|
||||
p-try@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz"
|
||||
@@ -6274,12 +6456,12 @@ postcss-value-parser@^4.1.0:
|
||||
integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
|
||||
|
||||
postcss@^8.2.8:
|
||||
version "8.2.8"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.8.tgz#0b90f9382efda424c4f0f69a2ead6f6830d08ece"
|
||||
integrity sha512-1F0Xb2T21xET7oQV9eKuctbM9S7BC0fetoHCc4H13z0PT6haiRLP4T0ZY4XWh7iLP0usgqykT6p9B2RtOf4FPw==
|
||||
version "8.2.15"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65"
|
||||
integrity sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==
|
||||
dependencies:
|
||||
colorette "^1.2.2"
|
||||
nanoid "^3.1.20"
|
||||
nanoid "^3.1.23"
|
||||
source-map "^0.6.1"
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
@@ -6336,6 +6518,14 @@ promise-retry@^1.1.1:
|
||||
err-code "^1.0.0"
|
||||
retry "^0.10.0"
|
||||
|
||||
promise-retry@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
|
||||
integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
|
||||
dependencies:
|
||||
err-code "^2.0.2"
|
||||
retry "^0.12.0"
|
||||
|
||||
promise@^7.0.1:
|
||||
version "7.3.1"
|
||||
resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz"
|
||||
@@ -6945,7 +7135,33 @@ repeating@^2.0.0:
|
||||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
request@2, request@^2.74.0, request@~2.81.0:
|
||||
request@2, request@^2.45.0, request@^2.74.0, request@^2.88.0, request@^2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
request@~2.81.0:
|
||||
version "2.81.0"
|
||||
resolved "https://registry.npmjs.org/request/-/request-2.81.0.tgz"
|
||||
integrity sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=
|
||||
@@ -6973,32 +7189,6 @@ request@2, request@^2.74.0, request@~2.81.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.0.0"
|
||||
|
||||
request@^2.45.0, request@^2.88.0, request@^2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
|
||||
@@ -7086,6 +7276,11 @@ retry@^0.10.0, retry@~0.10.1:
|
||||
resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz"
|
||||
integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
|
||||
|
||||
retry@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
|
||||
|
||||
reusify@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
|
||||
@@ -7243,10 +7438,10 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4:
|
||||
version "7.3.4"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz"
|
||||
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
|
||||
semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
@@ -7402,7 +7597,7 @@ smart-buffer@^1.0.13:
|
||||
resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz"
|
||||
integrity sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=
|
||||
|
||||
smart-buffer@^4.0.2:
|
||||
smart-buffer@^4.0.2, smart-buffer@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz"
|
||||
integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==
|
||||
@@ -7452,6 +7647,15 @@ socks-proxy-agent@^3.0.0:
|
||||
agent-base "^4.0.1"
|
||||
socks "^1.1.10"
|
||||
|
||||
socks-proxy-agent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60"
|
||||
integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA==
|
||||
dependencies:
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
socks "^2.3.3"
|
||||
|
||||
socks@^1.1.10:
|
||||
version "1.1.10"
|
||||
resolved "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz"
|
||||
@@ -7460,6 +7664,14 @@ socks@^1.1.10:
|
||||
ip "^1.1.4"
|
||||
smart-buffer "^1.0.13"
|
||||
|
||||
socks@^2.3.3:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.0.tgz#6b984928461d39871b3666754b9000ecf39dfac2"
|
||||
integrity sha512-mNmr9owlinMplev0Wd7UHFlqI4ofnBnNzFuzrm63PPaHgbkqCFe4T5LzwKmtQ/f2tX0NTpcdVLyD/FHxFBstYw==
|
||||
dependencies:
|
||||
ip "^1.1.5"
|
||||
smart-buffer "^4.1.0"
|
||||
|
||||
sorted-object@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz"
|
||||
@@ -7613,6 +7825,13 @@ ssri@^4.1.2, ssri@^4.1.6, ssri@~4.1.6:
|
||||
dependencies:
|
||||
safe-buffer "^5.1.0"
|
||||
|
||||
ssri@^8.0.0, ssri@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af"
|
||||
integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==
|
||||
dependencies:
|
||||
minipass "^3.1.1"
|
||||
|
||||
stat-mode@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz"
|
||||
@@ -7918,10 +8137,10 @@ tar@^4:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.3"
|
||||
|
||||
tar@^6.0.2, tar@^6.0.5:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz"
|
||||
integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==
|
||||
tar@^6.0.2, tar@^6.0.5, tar@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83"
|
||||
integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==
|
||||
dependencies:
|
||||
chownr "^2.0.0"
|
||||
fs-minipass "^2.0.0"
|
||||
@@ -8254,27 +8473,27 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typedoc-default-themes@^0.12.9:
|
||||
version "0.12.9"
|
||||
resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.12.9.tgz#97dfecb74faca36f8aff81d3be984b095d2bbbd8"
|
||||
integrity sha512-Jd5fYTiqzinZdoIY382W7tQXTwAzWRdg8KbHfaxmb78m1/3jL9riXtk23oBOKwhi8GFVykCOdPzEJKY87/D0LQ==
|
||||
typedoc-default-themes@^0.12.10:
|
||||
version "0.12.10"
|
||||
resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz#614c4222fe642657f37693ea62cad4dafeddf843"
|
||||
integrity sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==
|
||||
|
||||
typedoc@^0.20.32:
|
||||
version "0.20.32"
|
||||
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.20.32.tgz#d06fc4cce12dca66797220bbd289bac9f4481b5b"
|
||||
integrity sha512-GSopd/tiqoKE3fEdvhoaEpR9yrEPsR9tknAjkoeSPL6p1Rq5aVsKxBhhF6cwoDJ7oWjpvnm8vs0rQN0BxEHuWQ==
|
||||
typedoc@^0.20.36:
|
||||
version "0.20.36"
|
||||
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.20.36.tgz#ee5523c32f566ad8283fc732aa8ea322d1a45f6a"
|
||||
integrity sha512-qFU+DWMV/hifQ9ZAlTjdFO9wbUIHuUBpNXzv68ZyURAP9pInjZiO4+jCPeAzHVcaBCHER9WL/+YzzTt6ZlN/Nw==
|
||||
dependencies:
|
||||
colors "^1.4.0"
|
||||
fs-extra "^9.1.0"
|
||||
handlebars "^4.7.7"
|
||||
lodash "^4.17.21"
|
||||
lunr "^2.3.9"
|
||||
marked "^2.0.1"
|
||||
marked "^2.0.3"
|
||||
minimatch "^3.0.0"
|
||||
progress "^2.0.3"
|
||||
shelljs "^0.8.4"
|
||||
shiki "^0.9.3"
|
||||
typedoc-default-themes "^0.12.9"
|
||||
typedoc-default-themes "^0.12.10"
|
||||
|
||||
typescript@^3.9.9:
|
||||
version "3.9.9"
|
||||
@@ -8336,6 +8555,13 @@ unique-filename@^1.1.0, unique-filename@~1.1.0:
|
||||
dependencies:
|
||||
unique-slug "^2.0.0"
|
||||
|
||||
unique-filename@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
|
||||
integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
|
||||
dependencies:
|
||||
unique-slug "^2.0.0"
|
||||
|
||||
unique-slug@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz"
|
||||
@@ -8500,16 +8726,11 @@ uuid@^3.1.0, uuid@^3.3.2:
|
||||
resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
v8-compile-cache@^2.0.3, v8-compile-cache@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
|
||||
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
|
||||
|
||||
v8-compile-cache@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz"
|
||||
integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==
|
||||
|
||||
val-loader@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/val-loader/-/val-loader-3.1.0.tgz#6f83b6dea65ecb7928cf7340098e2cd43c8021e1"
|
||||
@@ -8676,14 +8897,7 @@ which-module@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz"
|
||||
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
|
||||
|
||||
which@1, which@^1.2.12, which@^1.2.8, which@~1.2.14:
|
||||
version "1.2.14"
|
||||
resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz"
|
||||
integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU=
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
which@^1.2.9, which@^1.3.0:
|
||||
which@1, which@^1.2.12, which@^1.2.8, which@^1.2.9, which@^1.3.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz"
|
||||
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
|
||||
@@ -8697,6 +8911,13 @@ which@^2.0.1, which@^2.0.2:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
which@~1.2.14:
|
||||
version "1.2.14"
|
||||
resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz"
|
||||
integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU=
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz"
|
||||
@@ -8892,9 +9113,9 @@ xtend@~2.1.1:
|
||||
object-keys "~0.4.0"
|
||||
|
||||
y18n@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz"
|
||||
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
|
||||
integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
|
||||
|
||||
y18n@^4.0.0:
|
||||
version "4.0.1"
|
||||
|
Reference in New Issue
Block a user