feat: permanent upnp mappings

This commit is contained in:
ThaUnknown 2024-04-19 18:30:20 +02:00
parent 7a2367f4a5
commit a1ca14caf8
14 changed files with 211 additions and 157 deletions

View file

@ -12,5 +12,6 @@ export const SUPPORTS = {
torrentPersist: false,
keybinds: false,
isAndroid: true,
externalPlayer: false
externalPlayer: false,
permamentNAT: false // no way of safely closing app
}

View file

@ -1,23 +1,23 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["./*"],
"three": ["./types.d.ts"],
"rxjs": ["./types.d.ts"],
},
"checkJs": true,
"target": "ESNext",
"moduleResolution": "bundler",
"moduleResolution": "node",
"module": "ESNext",
"allowSyntheticDefaultImports": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"resolveJsonModule": true,
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"module": "ESNext",
"types": ["./types.d.ts"],
"allowSyntheticDefaultImports": true
"baseUrl": "./",
"paths": {
"@/*": ["./*"],
"three": ["./types.d.ts"],
"rxjs": ["./types.d.ts"],
},
},
"exclude": [
"node_modules", "dist", "build", "git_modules", ".svelte-kit", "public", "android", "@types/three",

View file

@ -13,5 +13,6 @@ export const SUPPORTS = {
keybinds: true,
extensions: true,
isAndroid: false,
externalPlayer: true
externalPlayer: true,
permamentNAT: true
}

View file

@ -39,6 +39,8 @@ export default class TorrentClient extends WebTorrent {
playerProcess = null
torrentPath = ''
ipc
constructor (ipc, storageQuota, serverMode, torrentPath, controller) {
const settings = { ...defaults, ...storedSettings }
super({
@ -47,8 +49,10 @@ export default class TorrentClient extends WebTorrent {
downloadLimit: settings.torrentSpeed * 1048576 || 0,
uploadLimit: settings.torrentSpeed * 1572864 || 0, // :trolled:
torrentPort: settings.torrentPort || 0,
dhtPort: settings.dhtPort || 0
dhtPort: settings.dhtPort || 0,
natUpnp: SUPPORTS.permamentNAT ? 'permanent' : true
})
this.ipc = ipc
this.torrentPath = torrentPath
this._ready = new Promise(resolve => {
ipc.on('port', ({ ports }) => {
@ -279,8 +283,11 @@ export default class TorrentClient extends WebTorrent {
}
destroy () {
if (this.destroyed) return
this.parser?.destroy()
this.server.close()
super.destroy()
super.destroy(() => {
this.ipc.send('destroyed')
})
}
}

View file

@ -6,9 +6,11 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
/** @type {(parentDir: string, alias?: Record<string, string>, aliasFields?: (string | string[]), filename?: string) => import('webpack').WebpackOptionsNormalized} */
module.exports = (parentDir, alias = {}, aliasFields = 'browser', filename = 'app') => ({
devtool: 'source-map',
entry: [join(__dirname, 'main.js')],
entry: join(__dirname, 'main.js'),
stats: { warnings: false },
output: {
path: join(parentDir, 'build'),
filename: 'renderer.js'

View file

@ -7,7 +7,7 @@
"main": "build/main.js",
"homepage": "https://github.com/ThaUnknown/miru#readme",
"scripts": {
"start": "cross-env NODE_ENV=development concurrently --kill-others \"npm run web:watch\" \"npm run electron:start\"",
"start": "cross-env NODE_ENV=development webpack build && concurrently --kill-others \"npm run web:watch\" \"npm run electron:start\"",
"web:watch": "webpack serve",
"web:build": "cross-env NODE_ENV=production webpack build",
"electron:start": "electron ./build/main.js",
@ -25,6 +25,7 @@
"webpack-merge": "^5.10.0"
},
"dependencies": {
"@paymoapp/electron-shutdown-handler": "^1.0.15",
"utp-native": "^2.5.3"
},
"standard": {

134
electron/src/main/app.js Normal file
View file

@ -0,0 +1,134 @@
import { join } from 'node:path'
import process from 'node:process'
import { BrowserWindow, MessageChannelMain, app, dialog, ipcMain, powerMonitor, shell } from 'electron'
import electronShutdownHandler from '@paymoapp/electron-shutdown-handler'
import { development } from './util.js'
import Discord from './discord.js'
import Protocol from './protocol.js'
import Updater from './updater.js'
import Dialog from './dialog.js'
import store from './store.js'
export default class App {
webtorrentWindow = new BrowserWindow({
show: development,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
nodeIntegration: true,
contextIsolation: false,
backgroundThrottling: false
}
})
mainWindow = new BrowserWindow({
width: 1600,
height: 900,
frame: process.platform === 'darwin', // Only keep the native frame on Mac
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#17191c',
symbolColor: '#eee',
height: 28
},
backgroundColor: '#17191c',
autoHideMenuBar: true,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
enableBlinkFeatures: 'FontAccess, AudioVideoTracks',
backgroundThrottling: false,
preload: join(__dirname, '/preload.js')
},
icon: join(__dirname, '/logo_filled.png'),
show: false
})
discord = new Discord(this.mainWindow)
protocol = new Protocol(this.mainWindow)
updater = new Updater(this.mainWindow)
dialog = new Dialog(this.webtorrentWindow)
constructor () {
this.mainWindow.setMenuBarVisibility(false)
this.mainWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))
this.mainWindow.once('ready-to-show', () => this.mainWindow.show())
this.mainWindow.on('minimize', () => this.mainWindow.webContents.postMessage('visibilitychange', 'hidden'))
this.mainWindow.on('restore', () => this.mainWindow.webContents.postMessage('visibilitychange', 'visible'))
ipcMain.on('devtools', () => this.webtorrentWindow.webContents.openDevTools())
this.mainWindow.on('closed', () => this.destroy())
ipcMain.on('close', () => this.destroy())
app.on('before-quit', e => {
if (this.destroyed) return
e.preventDefault()
this.destroy()
})
powerMonitor.on('shutdown', e => {
if (this.destroyed) return
e.preventDefault()
this.destroy()
})
if (process.platform === 'win32') {
// this message usually fires in dev-mode from the parent process
process.on('message', data => {
if (data === 'graceful-exit') this.destroy()
})
electronShutdownHandler.setWindowHandle(this.mainWindow.getNativeWindowHandle())
electronShutdownHandler.blockShutdown('Saving torrent data...')
electronShutdownHandler.on('shutdown', async () => {
await this.destroy()
electronShutdownHandler.releaseShutdown()
})
} else {
process.on('SIGTERM', () => this.destroy())
}
const torrentLoad = this.webtorrentWindow.loadURL(development ? 'http://localhost:5000/background.html' : `file://${join(__dirname, '/background.html')}`)
this.mainWindow.loadURL(development ? 'http://localhost:5000/app.html' : `file://${join(__dirname, '/app.html')}`)
if (development) {
this.webtorrentWindow.webContents.openDevTools()
this.mainWindow.webContents.openDevTools()
}
let crashcount = 0
this.mainWindow.webContents.on('render-process-gone', async (e, { reason }) => {
if (reason === 'crashed') {
if (++crashcount > 10) {
await dialog.showMessageBox({ message: 'Crashed too many times.', title: 'Miru', detail: 'App crashed too many times. For a fix visit https://miru.watch/faq/', icon: '/renderer/public/logo_filled.png' })
shell.openExternal('https://miru.watch/faq/')
} else {
app.relaunch()
}
app.quit()
}
})
ipcMain.on('portRequest', async ({ sender }) => {
const { port1, port2 } = new MessageChannelMain()
await torrentLoad
this.webtorrentWindow.webContents.postMessage('port', null, [port1])
this.webtorrentWindow.webContents.postMessage('player', store.get('player'))
this.webtorrentWindow.webContents.postMessage('torrentPath', store.get('torrentPath'))
sender.postMessage('port', null, [port2])
})
}
destroyed = false
async destroy () {
if (this.destroyed) return
this.webtorrentWindow.webContents.postMessage('destroy', null)
await new Promise(resolve => {
ipcMain.once('destroyed', resolve)
setTimeout(resolve, 5000).unref?.()
})
this.destroyed = true
app.quit()
}
}

View file

@ -23,18 +23,15 @@ export default class Discord {
}
}
discord
discord = new Client({ transport: 'ipc' })
/** @type {Discord['defaultStatus'] | undefined} */
allowDiscordDetails
/** @type {Discord['defaultStatus'] | undefined} */
cachedPresence
/**
* @param {import('electron').BrowserWindow} window
*/
/** @param {import('electron').BrowserWindow} window */
constructor (window) {
this.discord = new Client({
transport: 'ipc'
})
ipcMain.on('show-discord-status', (event, data) => {
this.allowDiscordDetails = data
this.debouncedDiscordRPC(this.allowDiscordDetails ? this.cachedPresence : undefined)

View file

@ -1,125 +1,16 @@
/* eslint-disable no-new */
import { app, BrowserWindow, shell, ipcMain, dialog, MessageChannelMain } from 'electron'
import path from 'path'
import Discord from './discord.js'
import Updater from './updater.js'
import Protocol from './protocol.js'
import { development } from './util.js'
import Dialog from './dialog.js'
import store from './store.js'
import { app } from 'electron'
import App from './app.js'
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
let webtorrentWindow
let main
function createWindow () {
// Create the browser window.
webtorrentWindow = new BrowserWindow({
show: development,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
nodeIntegration: true,
contextIsolation: false,
backgroundThrottling: false
}
})
mainWindow = new BrowserWindow({
width: 1600,
height: 900,
frame: process.platform === 'darwin', // Only keep the native frame on Mac
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#17191c',
symbolColor: '#eee',
height: 28
},
backgroundColor: '#17191c',
autoHideMenuBar: true,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
enableBlinkFeatures: 'FontAccess, AudioVideoTracks',
backgroundThrottling: false,
preload: path.join(__dirname, '/preload.js')
},
icon: path.join(__dirname, '/logo_filled.png'),
show: false
})
new Discord(mainWindow)
new Protocol(mainWindow)
new Updater(mainWindow)
new Dialog(webtorrentWindow)
mainWindow.setMenuBarVisibility(false)
mainWindow.webContents.setWindowOpenHandler(() => {
return { action: 'deny' }
})
const torrentLoad = webtorrentWindow.loadURL(development ? 'http://localhost:5000/background.html' : `file://${path.join(__dirname, '/background.html')}`)
mainWindow.loadURL(development ? 'http://localhost:5000/app.html' : `file://${path.join(__dirname, '/app.html')}`)
if (development) {
webtorrentWindow.webContents.openDevTools()
mainWindow.webContents.openDevTools()
}
ipcMain.on('devtools', () => {
webtorrentWindow.webContents.openDevTools()
})
mainWindow.on('minimize', () => mainWindow.webContents.postMessage('visibilitychange', 'hidden'))
mainWindow.on('restore', () => mainWindow.webContents.postMessage('visibilitychange', 'visible'))
mainWindow.on('closed', () => {
mainWindow = null
try {
webtorrentWindow.webContents.postMessage('destroy', null)
} catch (e) {}
app.quit()
})
ipcMain.on('close', () => {
mainWindow = null
try {
webtorrentWindow.webContents.postMessage('destroy', null)
} catch (e) {}
app.quit()
})
let crashcount = 0
mainWindow.webContents.on('render-process-gone', (e, { reason }) => {
if (reason === 'crashed') {
if (++crashcount > 10) {
dialog.showMessageBox({ message: 'Crashed too many times.', title: 'Miru', detail: 'App crashed too many times. For a fix visit https://miru.watch/faq/', icon: '/renderer/public/logo_filled.png' }).then(() => {
shell.openExternal('https://miru.watch/faq/')
app.quit()
})
} else {
app.relaunch()
app.quit()
}
}
})
// Emitted when the window is ready to be shown
// This helps in showing the window gracefully.
mainWindow.once('ready-to-show', () => {
mainWindow.show()
})
ipcMain.on('portRequest', async ({ sender }) => {
const { port1, port2 } = new MessageChannelMain()
await torrentLoad
webtorrentWindow.webContents.postMessage('port', null, [port1])
webtorrentWindow.webContents.postMessage('player', store.get('player'))
webtorrentWindow.webContents.postMessage('torrentPath', store.get('torrentPath'))
sender.postMessage('port', null, [port2])
})
main = new App()
}
app.on('ready', createWindow)
app.on('activate', () => {
if (mainWindow === null) createWindow()
if (main === null) createWindow()
})

View file

@ -60,6 +60,9 @@ export default class Protocol {
})
}
/**
* @param {string} line
*/
sendToken (line) {
let token = line.split('access_token=')[1].split('&token_type')[0]
if (token) {
@ -68,6 +71,9 @@ export default class Protocol {
}
}
/**
* @param {string} text
*/
handleProtocol (text) {
const match = text.match(this.protocolRx)
if (match) this.protocolMap[match[1]]?.(match[2])

View file

@ -3,22 +3,37 @@ import { join } from 'node:path'
import { writeFileSync, readFileSync } from 'node:fs'
class Store {
/**
* @param {string} configName
* @param {{ angle: string; player: string; torrentPath: string; }} defaults
*/
constructor (configName, defaults) {
this.path = join(app.getPath('userData'), configName + '.json')
this.data = parseDataFile(this.path, defaults)
}
/**
* @param {string} key
*/
get (key) {
return this.data[key]
}
/**
* @param {string} key
* @param {string} val
*/
set (key, val) {
this.data[key] = val
writeFileSync(this.path, JSON.stringify(this.data))
}
}
/**
* @param {import("fs").PathOrFileDescriptor} filePath
* @param {any} defaults
*/
function parseDataFile (filePath, defaults) {
try {
return { ...defaults, ...JSON.parse(readFileSync(filePath).toString()) }

View file

@ -5,9 +5,11 @@ const mode = process.env.NODE_ENV?.trim() || 'development'
const commonConfig = require('common/webpack.config.cjs')
/** @type {import('webpack').WebpackOptionsNormalized[]} */
module.exports = [
{
devtool: 'source-map',
stats: { warnings: false },
entry: join(__dirname, 'src', 'background', 'background.js'),
output: {
path: join(__dirname, 'build'),
@ -44,6 +46,7 @@ module.exports = [
commonConfig(__dirname),
{
devtool: 'source-map',
stats: { warnings: false },
entry: join(__dirname, 'src', 'preload', 'preload.js'),
output: {
path: join(__dirname, 'build'),

View file

@ -22,5 +22,5 @@
"node_modules", "dist", "build", "git_modules", ".svelte-kit", "public", "android", "@types/three",
"**/node_modules", "**/dist", "**/build", "**/git_modules", "**/.svelte-kit", "**/public", "**/android", "**/@types/three",
"**/node_modules/*", "**/dist/*", "**/build/*", "**/git_modules/*", "**/.svelte-kit/*", "**/public/*", "**/android/*", "**@types/three/*.d.ts"
]
]
}

View file

@ -193,6 +193,9 @@ importers:
electron:
dependencies:
'@paymoapp/electron-shutdown-handler':
specifier: ^1.0.15
version: 1.0.15
utp-native:
specifier: ^2.5.3
version: 2.5.3
@ -973,6 +976,14 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
/@paymoapp/electron-shutdown-handler@1.0.15:
resolution: {integrity: sha512-u3Pd81f58a/gyYVLeZ3UFpz27wLDUYJ+J6EVikiQPqj8C5Peh/nvCZBolVur0AOUhcXw8HkTDbmB0hulLx8NVw==}
requiresBuild: true
dependencies:
node-addon-api: 5.1.0
prebuild-install: 7.1.1
dev: false
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@ -2392,7 +2403,6 @@ packages:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
dev: true
/block-iterator@1.1.1:
resolution: {integrity: sha512-DrjdVWZemVO4iBf4tiOXjUrY5cNesjzy0t7sIiu2rdl8cOCHRxAgKjSJFc3vBZYYMMmshUAxajl8QQh/uxXTKQ==}
@ -2511,7 +2521,6 @@ packages:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: true
/bufferutil@4.0.8:
resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==}
@ -2708,7 +2717,6 @@ packages:
/chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: true
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
@ -3425,7 +3433,6 @@ packages:
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
dev: true
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@ -3535,7 +3542,6 @@ packages:
/detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
dev: true
/detect-node@2.1.0:
resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
@ -4376,7 +4382,6 @@ packages:
/expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
dev: true
/express@4.18.3:
resolution: {integrity: sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==}
@ -4668,7 +4673,6 @@ packages:
/fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: true
/fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
@ -4871,7 +4875,6 @@ packages:
/github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
dev: true
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
@ -5315,7 +5318,6 @@ packages:
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
requiresBuild: true
dev: true
/ignore-by-default@1.0.1:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
@ -5374,7 +5376,6 @@ packages:
/ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
dev: true
/ini@2.0.0:
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
@ -6311,7 +6312,6 @@ packages:
/mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
dev: true
/mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
@ -6363,7 +6363,6 @@ packages:
/napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
dev: true
/napi-macros@2.2.2:
resolution: {integrity: sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==}
@ -6420,7 +6419,6 @@ packages:
engines: {node: '>=10'}
dependencies:
semver: 7.6.0
dev: true
/node-addon-api@1.7.2:
resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==}
@ -6431,6 +6429,10 @@ packages:
resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==}
dev: true
/node-addon-api@5.1.0:
resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
dev: false
/node-addon-api@6.1.0:
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
dev: true
@ -7092,7 +7094,6 @@ packages:
simple-get: 4.0.1
tar-fs: 2.1.1
tunnel-agent: 0.6.0
dev: true
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
@ -7248,7 +7249,6 @@ packages:
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
dev: true
/read-config-file@6.3.2:
resolution: {integrity: sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==}
@ -8267,7 +8267,6 @@ packages:
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
dev: true
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
@ -8475,7 +8474,6 @@ packages:
mkdirp-classic: 0.5.3
pump: 3.0.0
tar-stream: 2.2.0
dev: true
/tar-fs@3.0.4:
resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
@ -8494,7 +8492,6 @@ packages:
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
dev: true
/tar-stream@3.1.6:
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
@ -8777,7 +8774,6 @@ packages:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
dependencies:
safe-buffer: 5.2.1
dev: true
/tweetnacl@0.14.5:
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}