@ -1,8 +0,0 @@ | |||||
DB_TYPE = mysql | |||||
DB_HOST = database | |||||
DB_PORT = 3306 | |||||
DB_USER = root | |||||
DB_PASSWORD_FILE = /run/secrets/mysql_root_password | |||||
DB_DATABASE = autoplex_torrent | |||||
IPC_SOCKET_PATH = /var/autoplex/ipc/torrent_client.sock |
@ -1,36 +0,0 @@ | |||||
# Alpine results in segfaults, will stick with slim for now... | |||||
FROM node:14-slim AS base | |||||
WORKDIR /app | |||||
RUN mkdir /var/autoplex && chown node:node -R /var/autoplex | |||||
RUN apt-get update | |||||
RUN apt-get full-upgrade -y | |||||
RUN apt-get install -y libasound2 iputils-ping curl gnupg1 apt-transport-https dirmngr | |||||
# Speedtest utilities | |||||
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 379CE192D401AB61 && \ | |||||
echo "deb https://ookla.bintray.com/debian generic main" | tee /etc/apt/sources.list.d/speedtest.list && \ | |||||
apt-get update && \ | |||||
apt-get install speedtest | |||||
RUN apt-get autoremove --purge -y | |||||
RUN rm -rf /var/lib/apt/lists/* | |||||
# An image containing necessary components for building | |||||
FROM base AS builder | |||||
COPY package.json yarn.lock tsconfig.json ./ | |||||
RUN rm -rf node_modules && yarn install --frozen-lockfile | |||||
COPY src src | |||||
COPY patches patches | |||||
# An image to build the app | |||||
FROM builder AS build | |||||
RUN yarn run build | |||||
# An image containing the built app and production dependencies | |||||
FROM base AS prod | |||||
COPY --from=build /app/build ./build | |||||
COPY patches patches | |||||
COPY package.json yarn.lock ./ | |||||
RUN rm -rf node_modules && yarn install --production --frozen-lockfile | |||||
CMD [ "yarn", "run", "start" ] |
@ -1,3 +0,0 @@ | |||||
# Autoplex Torrent Client | |||||
The torrent client for Autoplex. |
@ -1,7 +0,0 @@ | |||||
{ | |||||
"cli": { | |||||
"entitiesDir": "src/database/entities", | |||||
"migrationsDir": "src/database/migrations", | |||||
"subscribersDir": "src/database/subscribers" | |||||
} | |||||
} |
@ -1,42 +0,0 @@ | |||||
{ | |||||
"name": "@autoplex-service/torrent", | |||||
"version": "0.0.1", | |||||
"description": "A dedicated torrent client for Autoplex", | |||||
"main": "./dist/index.js", | |||||
"scripts": { | |||||
"clean": "rimraf ./dist", | |||||
"build": "tsc", | |||||
"start": "NODE_ENV=production; node .", | |||||
"start:dev": "nodemon", | |||||
"test": "echo \"Error: no test specified\" && exit 1", | |||||
"postinstall": "patch-package" | |||||
}, | |||||
"keywords": [], | |||||
"author": "David Ludwig", | |||||
"license": "ISC", | |||||
"devDependencies": { | |||||
"@types/glob": "^7.1.3", | |||||
"@types/node": "^14.14.37", | |||||
"@types/parse-torrent": "^5.8.3", | |||||
"@types/rimraf": "^3.0.0", | |||||
"@types/websocket": "^1.0.2", | |||||
"nodemon": "^2.0.7", | |||||
"postinstall-postinstall": "^2.1.0", | |||||
"ts-node": "^9.1.1", | |||||
"typescript": "^4.2.3" | |||||
}, | |||||
"dependencies": { | |||||
"@autoplex/microservice": "^0.0.0", | |||||
"@autoplex/utils": "^0.0.0", | |||||
"bitfield": "^4.0.0", | |||||
"mysql": "^2.18.1", | |||||
"node-ipc": "^9.1.4", | |||||
"parse-torrent": "^9.1.3", | |||||
"patch-package": "^6.4.7", | |||||
"reflect-metadata": "^0.1.13", | |||||
"rimraf": "^3.0.2", | |||||
"typeorm": "^0.2.32", | |||||
"websocket": "^1.0.33", | |||||
"webtorrent-hybrid": "^4.0.3" | |||||
} | |||||
} |
@ -1,26 +0,0 @@ | |||||
diff --git a/node_modules/webtorrent/lib/file.js b/node_modules/webtorrent/lib/file.js | |||||
index caa395d..80234de 100644 | |||||
--- a/node_modules/webtorrent/lib/file.js | |||||
+++ b/node_modules/webtorrent/lib/file.js | |||||
@@ -21,6 +21,7 @@ class File extends EventEmitter { | |||||
this.length = file.length | |||||
this.offset = file.offset | |||||
+ this.isSelected = true | |||||
this.done = false | |||||
const start = file.offset | |||||
@@ -85,11 +86,13 @@ class File extends EventEmitter { | |||||
select (priority) { | |||||
if (this.length === 0) return | |||||
+ this.isSelected = true | |||||
this._torrent.select(this._startPiece, this._endPiece, priority) | |||||
} | |||||
deselect () { | |||||
if (this.length === 0) return | |||||
+ this.isSelected = false | |||||
this._torrent.deselect(this._startPiece, this._endPiece, false) | |||||
} | |||||
@ -1,29 +0,0 @@ | |||||
export interface ISerializedFile { | |||||
path : string; | |||||
size : number; | |||||
downloaded: number; | |||||
progress : number; | |||||
selected : boolean; | |||||
} | |||||
export interface ISerializedTorrent { | |||||
name : string; | |||||
infoHash : string; | |||||
downloaded : number; | |||||
uploaded : number; | |||||
ratio : number; | |||||
size : number; | |||||
downloadSpeed: number; | |||||
uploadSpeed : number; | |||||
numPeers : number; | |||||
progress : number; | |||||
path : string; | |||||
state : TorrentState; | |||||
files : ISerializedFile[]; | |||||
} | |||||
export enum TorrentState { | |||||
Ready = 0x1, | |||||
Paused = 0x2, | |||||
Done = 0x4 | |||||
} |
@ -1,73 +0,0 @@ | |||||
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm"; | |||||
import WebTorrent from "webtorrent-hybrid"; | |||||
@Entity() | |||||
export default class Torrent extends BaseEntity | |||||
{ | |||||
static fromWebTorrent(torrent: WebTorrent.Torrent) { | |||||
let entity = new Torrent(); | |||||
entity.infoHash = torrent.infoHash; | |||||
entity.torrentFile = torrent.torrentFile; | |||||
entity.setSelectedFiles(torrent.files); | |||||
entity.downloadPath = torrent.path; | |||||
return entity; | |||||
} | |||||
@PrimaryGeneratedColumn() | |||||
id!: number; | |||||
@Column() | |||||
infoHash!: string; | |||||
@Column("mediumblob") | |||||
torrentFile!: Buffer; | |||||
@Column({nullable: true}) | |||||
selectOnly?: string; | |||||
@Column() | |||||
downloadPath!: string; | |||||
/** | |||||
* Get the list of selected files | |||||
*/ | |||||
selectedFiles() { | |||||
let result: number[] = []; | |||||
for (let range of (this.selectOnly ?? "").split(',')) { | |||||
// @TODO Check this map function... it's weird | |||||
let [index, end] = range.split('-').map(num => parseInt(num)); | |||||
do { | |||||
result.push(index); | |||||
} while(index++ < end); | |||||
} | |||||
return result; | |||||
} | |||||
/** | |||||
* Update the selected files from the torrent | |||||
*/ | |||||
setSelectedFiles(files: WebTorrent.TorrentFile[]) { | |||||
let ranges: string[] = []; | |||||
let offset: number | null = null; | |||||
let range: number = 0; | |||||
files.forEach((file, i) => { | |||||
if (file.isSelected) { | |||||
if (offset === null) { | |||||
offset = i; | |||||
range = 0; | |||||
} else { | |||||
range++; | |||||
} | |||||
} else { | |||||
if (offset !== null) { | |||||
ranges.push(offset + (range > 0 ? `-${offset + range}` : "")); | |||||
offset = null; | |||||
} | |||||
} | |||||
}); | |||||
if (offset !== null) { | |||||
ranges.push(offset + (range > 0 ? `-${offset + range}` : "")); | |||||
} | |||||
this.selectOnly = ranges.join(','); | |||||
} | |||||
} |
@ -1,5 +0,0 @@ | |||||
import Torrent from "./Torrent"; | |||||
export default [ | |||||
Torrent | |||||
]; |
@ -1,18 +0,0 @@ | |||||
import { createConnection } from "typeorm"; | |||||
import entities from "./entities"; | |||||
export default async function connectToDatabase(host: string, port: number, username: string, | |||||
password: string, database: string) | |||||
{ | |||||
return createConnection({ | |||||
type: "mysql", | |||||
host, | |||||
port, | |||||
username, | |||||
password, | |||||
database, | |||||
synchronize: true, | |||||
entities, | |||||
migrations: ["src/migrations/*.ts"] | |||||
}); | |||||
} |
@ -1,11 +0,0 @@ | |||||
import { Microservice } from "@autoplex/microservice"; | |||||
import * as services from "./services"; | |||||
// Create the application | |||||
let app = new Microservice(); | |||||
// Install the services | |||||
app.installServices(Object.values(services)); | |||||
// Execute the app | |||||
app.exec().then(process.exit); |
@ -1,36 +0,0 @@ | |||||
import { Connection } from "typeorm"; | |||||
import connectToDatabase from "../database"; | |||||
import { env, secret } from "@autoplex/utils"; | |||||
import { InternalService } from "@autoplex/microservice"; | |||||
export default class Database extends InternalService | |||||
{ | |||||
/** | |||||
* The active database connection | |||||
*/ | |||||
public connection!: Connection; | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "Database"; | |||||
/** | |||||
* Boot the database service | |||||
*/ | |||||
public async boot() { | |||||
let host = env("DB_HOST"); | |||||
let port = parseInt(env("DB_PORT")); | |||||
let username = env("DB_USER"); | |||||
let password = await secret(env("DB_PASSWORD_FILE")); | |||||
let database = env("DB_DATABASE"); | |||||
this.connection = await connectToDatabase(host, port, username, password, database); | |||||
} | |||||
/** | |||||
* Shutdown the database service | |||||
*/ | |||||
public async shutdown() { | |||||
await this.connection.close(); | |||||
} | |||||
} |
@ -1,114 +0,0 @@ | |||||
import assert from "assert"; | |||||
import WebTorrent from "webtorrent-hybrid"; | |||||
import TorrentClient from "./TorrentClient"; | |||||
import { IpcServerService } from "@autoplex/microservice"; | |||||
import { env } from "@autoplex/utils"; | |||||
type IAddTorrent = string | { | |||||
type: "Buffer", | |||||
data: number[] | |||||
} | |||||
export default class IpcInterface extends IpcServerService | |||||
{ | |||||
/** | |||||
* The torrent client instance | |||||
*/ | |||||
protected torrentClient!: TorrentClient; | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "IPC"; | |||||
/** | |||||
* The path to the socket file | |||||
*/ | |||||
protected readonly SOCKET_PATH = env("IPC_SOCKET_PATH"); | |||||
/** | |||||
* Boot the IPC interface | |||||
*/ | |||||
public async boot() { | |||||
this.torrentClient = this.app.service<TorrentClient>("Torrent Client"); | |||||
await super.boot(); | |||||
} | |||||
/** | |||||
* Install the the event handlers | |||||
*/ | |||||
protected installMessageHandlers() { | |||||
this.addMessageHandler("add", this.addTorrent); | |||||
this.addMessageHandler("remove", this.removeTorrent); | |||||
this.addMessageHandler("list", this.listTorrents); | |||||
this.addMessageHandler("details", this.torrentDetails); | |||||
this.torrentClient.on("torrent_finished", this.torrentFinished.bind(this)); | |||||
} | |||||
// Interface Methods --------------------------------------------------------------------------- | |||||
/** | |||||
* Add a torrent to the client | |||||
*/ | |||||
// protected async addTorrent(torrentInfo: IAddTorrent, downloadPath?: string) { | |||||
protected async addTorrent(payload: { torrent: IAddTorrent, downloadPath?: string }) { | |||||
let torrent: WebTorrent.Torrent; | |||||
if (typeof payload.torrent == "string") { | |||||
torrent = await this.torrentClient.add(payload.torrent, { downloadPath: payload.downloadPath }); | |||||
} else { | |||||
torrent = await this.torrentClient.add(Buffer.from(payload.torrent.data), { downloadPath: payload.downloadPath }); | |||||
} | |||||
return torrent.infoHash; | |||||
} | |||||
/** | |||||
* Remove a torrent from the | |||||
* @param message Add | |||||
*/ | |||||
protected async removeTorrent(torrentId: string) { | |||||
try { | |||||
await this.torrentClient.remove(torrentId); | |||||
} catch(e) {} | |||||
} | |||||
protected async listTorrents() { | |||||
return this.torrentClient.torrents.map(torrent => Object({ | |||||
name: torrent.name, | |||||
infoHash: torrent.infoHash, | |||||
progress: torrent.progress, | |||||
state: this.torrentClient.torrentState(torrent) | |||||
})); | |||||
} | |||||
protected async torrentDetails(torrentIds: string[]) { | |||||
let torrents: WebTorrent.Torrent[]; | |||||
if (torrentIds.length == 0) { | |||||
torrents = this.torrentClient.torrents; | |||||
} else { | |||||
torrents = torrentIds.map(torrentId => { | |||||
let torrent = this.torrentClient.get(torrentId); | |||||
assert(torrent != null, `Unknown torrent ID provided: ${torrentId}`); | |||||
return torrent; | |||||
}); | |||||
} | |||||
return torrents.map(torrent => this.torrentClient.serializeTorrent(torrent)); | |||||
} | |||||
// Subscription Interface Methods -------------------------------------------------------------- | |||||
/** | |||||
* Broadcast a message to the connected clients | |||||
*/ | |||||
// protected broadcast(method: string, ...message: any[]) { | |||||
// for (let socket of <Socket[]>(<any>ipc.server).sockets) { | |||||
// this.server.emit(socket, method, message); | |||||
// } | |||||
// } | |||||
/** | |||||
* Notify connected clients that a torrent has finished | |||||
*/ | |||||
public torrentFinished(torrent: WebTorrent.Torrent) { | |||||
this.broadcast("torrent_finished", torrent.infoHash); | |||||
} | |||||
} |
@ -1,298 +0,0 @@ | |||||
import { InternalService } from "@autoplex/microservice"; | |||||
import assert from "assert"; | |||||
import MagnetUri from "magnet-uri"; | |||||
import WebTorrent from "webtorrent-hybrid"; | |||||
import parseTorrent from "parse-torrent"; | |||||
import { extname, join, sep } from "path"; | |||||
import Torrent from "../database/entities/Torrent"; | |||||
import rimraf from "rimraf"; | |||||
import { ISerializedTorrent, TorrentState } from "../common"; | |||||
import { Database } from "."; | |||||
interface IAddOptions { | |||||
downloadPath?: string; | |||||
extensions?: string | string[]; | |||||
} | |||||
/** | |||||
* Available events in the torrent client | |||||
*/ | |||||
interface TorrentClientEvents { | |||||
"torrent_finished": (torrent: WebTorrent.Torrent) => void; | |||||
} | |||||
/** | |||||
* Declare the event types in the torrent client | |||||
*/ | |||||
export declare interface TorrentClient { | |||||
emit<U extends keyof TorrentClientEvents>( | |||||
event: U, ...args: Parameters<TorrentClientEvents[U]> | |||||
): boolean; | |||||
on<U extends keyof TorrentClientEvents>( | |||||
event: U, listener: TorrentClientEvents[U] | |||||
): this; | |||||
} | |||||
export class TorrentClient extends InternalService | |||||
{ | |||||
/** | |||||
* The current WebTorrent instance (available after boot) | |||||
*/ | |||||
private __webtorrent!: WebTorrent.Instance; | |||||
// --------------------------------------------------------------------------------------------- | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "Torrent Client"; | |||||
/** | |||||
* Boot the service | |||||
*/ | |||||
public async boot() { | |||||
this.__webtorrent = new WebTorrent(); | |||||
this.__webtorrent.on("error", error => this.onError(error)); | |||||
this.__webtorrent.on("torrent", torrent => { | |||||
torrent.on("done", () => this.onTorrentFinish(torrent)); | |||||
// torrent.on("download", (...args) => this.onTorrentDownload(torrent, ...args)); | |||||
// torrent.on("upload", (...args) => this.onTorrentUpload(torrent, ...args)); | |||||
torrent.on("error", (...args) => this.onTorrentError(torrent, ...args)); | |||||
torrent.on("noPeers", (...args) => this.onTorrentNoPeers(torrent, ...args)); | |||||
torrent.on("wire", (...args) => this.onTorrentWire(torrent, ...args)); | |||||
}); | |||||
} | |||||
/** | |||||
* @TODO really this is kinda bad putting this here... | |||||
* Start the torrent client | |||||
*/ | |||||
public start() { | |||||
this.loadTorrents(); | |||||
} | |||||
// Event Handling ------------------------------------------------------------------------------ | |||||
/** | |||||
* Invoked when a WebTorrent client error occurs | |||||
*/ | |||||
protected onError(error: string | Error) { | |||||
console.error("A Webtorrent client error occurred:", error); | |||||
} | |||||
/** | |||||
* Invoked when a torrent error occurs | |||||
*/ | |||||
protected onTorrentError(torrent: WebTorrent.Torrent, error: string | Error) { | |||||
console.error("Torrent error occurred:", torrent.name, error); | |||||
Torrent.delete({ infoHash: torrent.infoHash }); | |||||
} | |||||
/** | |||||
* Invoked when a torrent has finished | |||||
*/ | |||||
protected onTorrentFinish(torrent: WebTorrent.Torrent) { | |||||
console.log("Torrent finished:", torrent.name); | |||||
this.emit("torrent_finished", torrent); | |||||
} | |||||
/** | |||||
* @NOTE: Ignoring these two events for performance purposes | |||||
*/ | |||||
// protected onTorrentDownload(torrent: WebTorrent.Torrent, bytes: number) {} | |||||
// protected onTorrentUpload(torrent: WebTorrent.Torrent, bytes: number) {} | |||||
protected onTorrentNoPeers(torrent: WebTorrent.Torrent, announceTypes: "tracker" | "dht") { | |||||
} | |||||
protected onTorrentWire(torrent: WebTorrent.Torrent, wire: any, address: string | undefined) { | |||||
} | |||||
// Torrent Storage ----------------------------------------------------------------------------- | |||||
/** | |||||
* Load the torrents from the database | |||||
*/ | |||||
protected async loadTorrents() { | |||||
let torrents = await Torrent.find(); | |||||
for (let torrent of torrents) { | |||||
try { | |||||
let torrentInfo = parseTorrent(torrent.torrentFile); | |||||
this.addTorrent(torrentInfo, torrent.downloadPath, torrent.selectedFiles()); | |||||
} catch(e) { | |||||
torrent.remove(); | |||||
continue; | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Delete a torrent from storage | |||||
*/ | |||||
protected async deleteTorrent(torrent: WebTorrent.Torrent) { | |||||
return await Torrent.delete({ infoHash: torrent.infoHash }); | |||||
} | |||||
/** | |||||
* Store a torrent in the database | |||||
*/ | |||||
protected async storeTorrent(torrent: WebTorrent.Torrent) { | |||||
return await Torrent.fromWebTorrent(torrent).save(); | |||||
} | |||||
/** | |||||
* Delete the download files from a torrent | |||||
*/ | |||||
protected async removeTorrentFiles(torrent: WebTorrent.Torrent) { | |||||
return new Promise<void>((resolve, reject) => { | |||||
let toRemove = new Set<string>(); | |||||
torrent.files.forEach(file => { | |||||
toRemove.add(file.path.split(sep)[0]); | |||||
}); | |||||
toRemove.forEach(path => { | |||||
rimraf(join(torrent.path, path), (err) => { | |||||
if (err) { | |||||
return reject(err); | |||||
} | |||||
resolve(); | |||||
}); | |||||
}); | |||||
}); | |||||
} | |||||
// Torrent Handling ---------------------------------------------------------------------------- | |||||
/** | |||||
* Add a torrent to the client | |||||
*/ | |||||
protected addTorrent(torrent: MagnetUri.Instance, downloadPath: string, selectOnly?: number[]) { | |||||
// Select only: Select no files by default due to broken selection mechanism in Webtorrent | |||||
torrent.so = selectOnly ?? []; | |||||
console.log("Torrent added:", torrent.infoHash); | |||||
return this.__webtorrent.add(torrent, { path: downloadPath }); | |||||
} | |||||
/** | |||||
* Remove a torrent from the client | |||||
*/ | |||||
protected removeTorrent(torrent: WebTorrent.Torrent) { | |||||
this.deleteTorrent(torrent); | |||||
// console.log("Torrent removed:", torrent.infoHash); | |||||
this.__webtorrent.remove(torrent); | |||||
} | |||||
/** | |||||
* Select the initial list of files to download on a newly added torrent | |||||
*/ | |||||
protected filterSelectFiles(torrent: WebTorrent.Torrent, extensions?: string | string[]) { | |||||
if (extensions === undefined) { | |||||
torrent.files.forEach(file => file.select()); | |||||
return; | |||||
} | |||||
let exts = new Set(typeof extensions === "string" ? extensions.split(',') : extensions); | |||||
torrent.files.forEach(file => { | |||||
if (exts.has(extname(file.path).slice(1))) { | |||||
file.select(); | |||||
} else { | |||||
file.deselect(); | |||||
} | |||||
}); | |||||
} | |||||
// Torrent Client Interface -------------------------------------------------------------------- | |||||
/** | |||||
* Add a torrent to the client | |||||
*/ | |||||
public async add(info: string | Buffer, options: IAddOptions = {}) { | |||||
// Parse the torrent | |||||
let torrentInfo = parseTorrent(info); | |||||
assert(typeof torrentInfo.infoHash === "string" && torrentInfo.infoHash.length > 0, "Invalid magnet link provided"); | |||||
// If the torrent already exists, skip it | |||||
assert(this.__webtorrent.get(torrentInfo.infoHash) === null, "Torrent has already been added"); | |||||
// Add the torrent to the client | |||||
let torrent = this.addTorrent(torrentInfo, options.downloadPath ?? "/mnt/storage/Downloads"); | |||||
// When the metadata has beened fetched, select the files to download and store the torrent | |||||
torrent.once("metadata", () => { | |||||
this.filterSelectFiles(torrent, options.extensions); | |||||
this.storeTorrent(torrent); | |||||
console.log(torrent.path); | |||||
}); | |||||
return torrent; | |||||
} | |||||
/** | |||||
* Remove a torrent from the client | |||||
*/ | |||||
public async remove(info: string | Buffer, withData: boolean = false) { | |||||
// Parse the torrent | |||||
let torrentInfo = parseTorrent(info); | |||||
assert(typeof torrentInfo.infoHash === "string"); | |||||
// Get the torrent and ensure it exists it exists | |||||
let torrent = this.__webtorrent.get(torrentInfo.infoHash); | |||||
assert(torrent !== null, "Torrent has not been added"); | |||||
// Remove the torrent | |||||
this.removeTorrent(torrent); | |||||
// Delete data if necessary | |||||
if (withData) { | |||||
this.removeTorrentFiles(torrent); | |||||
} | |||||
} | |||||
public has(infoHash: string) { | |||||
return this.__webtorrent.get(infoHash) != null; | |||||
} | |||||
public get(infoHash: string) { | |||||
return this.__webtorrent.get(infoHash); | |||||
} | |||||
public torrentState(torrent: WebTorrent.Torrent) { | |||||
let state = 0; | |||||
state |= <number>(torrent.ready && TorrentState.Ready); | |||||
state |= <number>(torrent.paused && TorrentState.Paused); | |||||
state |= <number>(torrent.done && TorrentState.Done); | |||||
return <TorrentState>state; | |||||
} | |||||
public serializeTorrent(torrent: WebTorrent.Torrent) { | |||||
return <ISerializedTorrent>{ | |||||
name: torrent.name, | |||||
infoHash: torrent.infoHash, | |||||
downloaded: torrent.downloaded, | |||||
uploaded: torrent.uploaded, | |||||
ratio: torrent.ratio, | |||||
size: torrent.length, | |||||
downloadSpeed: torrent.downloadSpeed, | |||||
uploadSpeed: torrent.uploadSpeed, | |||||
numPeers: torrent.numPeers, | |||||
progress: torrent.progress, | |||||
path: torrent.path, | |||||
state: this.torrentState(torrent), | |||||
files: torrent.files.map(file => Object({ | |||||
path: file.path, | |||||
size: file.length, | |||||
downloaded: file.downloaded, | |||||
progress: file.progress, | |||||
selected: file.isSelected | |||||
})) | |||||
}; | |||||
} | |||||
get torrents() { | |||||
return this.__webtorrent.torrents; | |||||
} | |||||
} | |||||
export default TorrentClient; |
@ -1,9 +0,0 @@ | |||||
import Database from "./Database"; | |||||
import IpcInterface from "./IpcInterface"; | |||||
import TorrentClient from "./TorrentClient"; | |||||
export { | |||||
Database, | |||||
IpcInterface, | |||||
TorrentClient | |||||
} |
@ -1,31 +0,0 @@ | |||||
declare const MagnetUri: MagnetUri.MagnetUri; | |||||
declare module "magnet-uri" { | |||||
declare namespace MagnetUri { | |||||
interface MagnetUri { | |||||
(uri: string): Instance; | |||||
decode(uri: string): Instance; | |||||
encode(parsed: Instance): string; | |||||
} | |||||
interface Instance extends Object { | |||||
dn?: string | string[]; | |||||
tr?: string | string[]; | |||||
xs?: string | string[]; | |||||
as?: string | string[]; | |||||
ws?: string | string[]; | |||||
kt?: string[]; | |||||
ix?: number | number[]; | |||||
xt?: string | string[]; | |||||
so?: number[]; | |||||
infoHash?: string; | |||||
infoHashBuffer?: Buffer; | |||||
name?: string | string[]; | |||||
keywords?: string | string[]; | |||||
announce?: string[]; | |||||
urlList?: string[]; | |||||
} | |||||
} | |||||
export = MagnetUri; | |||||
} |
@ -1,350 +0,0 @@ | |||||
/// <reference types="node"/> | |||||
declare module "node-ipc" { | |||||
import { Socket } from "net"; | |||||
declare const NodeIPC: NodeIPC.NodeIPC; | |||||
declare namespace NodeIPC { | |||||
interface NodeIPC extends IPC | |||||
{} | |||||
interface IPC { | |||||
/** | |||||
* Set these variables in the ipc.config scope to overwrite or set default values | |||||
*/ | |||||
config: Config; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#log | |||||
*/ | |||||
log(...args: any[]): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connectto | |||||
* Used for connecting as a client to local Unix Sockets and Windows Sockets. | |||||
* This is the fastest way for processes on the same machine to communicate | |||||
* because it bypasses the network card which TCP and UDP must both use. | |||||
* @param id is the string id of the socket being connected to. | |||||
* The socket with this id is added to the ipc.of object when created. | |||||
* @param path is the path of the Unix Domain Socket File, if the System is Windows, | |||||
* this will automatically be converted to an appropriate pipe with the same information as the Unix Domain Socket File. | |||||
* If not set this will default to ipc.config.socketRoot+ipc.config.appspace+id | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectTo(id: string, path?: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connectto | |||||
* Used for connecting as a client to local Unix Sockets and Windows Sockets. | |||||
* This is the fastest way for processes on the same machine to communicate | |||||
* because it bypasses the network card which TCP and UDP must both use. | |||||
* @param id is the string id of the socket being connected to. | |||||
* The socket with this id is added to the ipc.of object when created. | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectTo(id: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connecttonet | |||||
* Used to connect as a client to a TCP or TLS socket via the network card. | |||||
* This can be local or remote, if local, it is recommended that you use the Unix | |||||
* and Windows Socket Implementaion of connectTo instead as it is much faster since it avoids the network card altogether. | |||||
* For TLS and SSL Sockets see the node-ipc TLS and SSL docs. | |||||
* They have a few additional requirements, and things to know about and so have their own doc. | |||||
* @param id is the string id of the socket being connected to. For TCP & TLS sockets, | |||||
* this id is added to the ipc.of object when the socket is created with a reference to the socket | |||||
* @param host is the host on which the TCP or TLS socket resides. | |||||
* This will default to ipc.config.networkHost if not specified | |||||
* @param port the port on which the TCP or TLS socket resides | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectToNet(id: string, host?: string, port?: number, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connecttonet | |||||
* Used to connect as a client to a TCP or TLS socket via the network card. | |||||
* This can be local or remote, if local, it is recommended that you use the Unix | |||||
* and Windows Socket Implementaion of connectTo instead as it is much faster since it avoids the network card altogether. | |||||
* For TLS and SSL Sockets see the node-ipc TLS and SSL docs. | |||||
* They have a few additional requirements, and things to know about and so have their own doc. | |||||
* @param id is the string id of the socket being connected to. For TCP & TLS sockets, | |||||
* this id is added to the ipc.of object when the socket is created with a reference to the socket | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectToNet(id: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#connecttonet | |||||
* Used to connect as a client to a TCP or TLS socket via the network card. | |||||
* This can be local or remote, if local, it is recommended that you use the Unix | |||||
* and Windows Socket Implementaion of connectTo instead as it is much faster since it avoids the network card altogether. | |||||
* For TLS and SSL Sockets see the node-ipc TLS and SSL docs. | |||||
* They have a few additional requirements, and things to know about and so have their own doc. | |||||
* @param id is the string id of the socket being connected to. | |||||
* For TCP & TLS sockets, this id is added to the ipc.of object when the socket is created with a reference to the socket | |||||
* @param host is the host on which the TCP or TLS socket resides. This will default to ipc.config.networkHost if not specified | |||||
* @param port the port on which the TCP or TLS socket resides | |||||
* @param callback this is the function to execute when the socket has been created | |||||
*/ | |||||
connectToNet(id: string, hostOrPort: number | string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#disconnect | |||||
* Used to disconnect a client from a Unix, Windows, TCP or TLS socket. | |||||
* The socket and its refrence will be removed from memory and the ipc.of scope. | |||||
* This can be local or remote. UDP clients do not maintain connections and so there are no Clients and this method has no value to them | |||||
* @param id is the string id of the socket from which to disconnect | |||||
*/ | |||||
disconnect(id: string): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#serve | |||||
* Used to create local Unix Socket Server or Windows Socket Server to which Clients can bind. | |||||
* The server can emit events to specific Client Sockets, or broadcast events to all known Client Sockets | |||||
* @param path This is the path of the Unix Domain Socket File, if the System is Windows, | |||||
* this will automatically be converted to an appropriate pipe with the same information as the Unix Domain Socket File. | |||||
* If not set this will default to ipc.config.socketRoot+ipc.config.appspace+id | |||||
* @param callback This is a function to be called after the Server has started. | |||||
* This can also be done by binding an event to the start event like ipc.server.on('start',function(){}); | |||||
*/ | |||||
serve(path: string, callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#serve | |||||
* Used to create local Unix Socket Server or Windows Socket Server to which Clients can bind. | |||||
* The server can emit events to specific Client Sockets, or broadcast events to all known Client Sockets | |||||
* @param callback This is a function to be called after the Server has started. | |||||
* This can also be done by binding an event to the start event like ipc.server.on('start',function(){}); | |||||
*/ | |||||
serve(callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#serve | |||||
* Used to create local Unix Socket Server or Windows Socket Server to which Clients can bind. | |||||
* The server can emit events to specific Client Sockets, or broadcast events to all known Client Sockets | |||||
*/ | |||||
serve(callback: null): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param host If not specified this defaults to the first address in os.networkInterfaces(). | |||||
* For TCP, TLS & UDP servers this is most likely going to be 127.0.0.1 or ::1 | |||||
* @param port The port on which the TCP, UDP, or TLS Socket server will be bound, this defaults to 8000 if not specified | |||||
* @param UDPType If set this will create the server as a UDP socket. 'udp4' or 'udp6' are valid values. | |||||
* This defaults to not being set. When using udp6 make sure to specify a valid IPv6 host, like ::1 | |||||
* @param callback Function to be called when the server is created | |||||
*/ | |||||
serveNet(host?: string, port?: number, UDPType?: "udp4" | "udp6", callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param UDPType If set this will create the server as a UDP socket. 'udp4' or 'udp6' are valid values. | |||||
* This defaults to not being set. When using udp6 make sure to specify a valid IPv6 host, like ::1 | |||||
* @param callback Function to be called when the server is created | |||||
*/ | |||||
serveNet(UDPType: "udp4" | "udp6", callback?: () => void): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param callback Function to be called when the server is created | |||||
* @param port The port on which the TCP, UDP, or TLS Socket server will be bound, this defaults to 8000 if not specified | |||||
*/ | |||||
serveNet(callbackOrPort: EmptyCallback | number): void; | |||||
/** | |||||
* https://www.npmjs.com/package/node-ipc#servenet | |||||
* @param host If not specified this defaults to the first address in os.networkInterfaces(). | |||||
* For TCP, TLS & UDP servers this is most likely going to be 127.0.0.1 or ::1 | |||||
* @param port The port on which the TCP, UDP, or TLS Socket server will be bound, this defaults to 8000 if not specified | |||||
* @param callback Function to be called when the server is created | |||||
*/ | |||||
serveNet(host: string, port: number, callback?: () => void): void; | |||||
/** | |||||
* This is where socket connection refrences will be stored when connecting to them as a client via the ipc.connectTo | |||||
* or iupc.connectToNet. They will be stored based on the ID used to create them, eg : ipc.of.mySocket | |||||
*/ | |||||
of: any; | |||||
/** | |||||
* This is a refrence to the server created by ipc.serve or ipc.serveNet | |||||
*/ | |||||
server: Server; | |||||
} | |||||
type EmptyCallback = () => void; | |||||
interface Client { | |||||
/** | |||||
* triggered when a JSON message is received. The event name will be the type string from your message | |||||
* and the param will be the data object from your message eg : { type:'myEvent',data:{a:1}} | |||||
*/ | |||||
on(event: string, callback: (message: any, socket: Socket) => void): Client; | |||||
/** | |||||
* triggered when an error has occured | |||||
*/ | |||||
on(event: "error", callback: (err: any) => void): Client; | |||||
/** | |||||
* connect - triggered when socket connected | |||||
* disconnect - triggered by client when socket has disconnected from server | |||||
* destroy - triggered when socket has been totally destroyed, no further auto retries will happen and all references are gone | |||||
*/ | |||||
on(event: "connect" | "disconnect" | "destroy", callback: () => void): Client; | |||||
/** | |||||
* triggered by server when a client socket has disconnected | |||||
*/ | |||||
on(event: "socket.disconnected", callback: (socket: Socket, destroyedSocketID: string) => void): Client; | |||||
/** | |||||
* triggered when ipc.config.rawBuffer is true and a message is received | |||||
*/ | |||||
on(event: "data", callback: (buffer: Buffer) => void): Client; | |||||
emit(event: string, value?: any): Client; | |||||
/** | |||||
* Unbind subscribed events | |||||
*/ | |||||
off(event: string, handler: any): Client; | |||||
} | |||||
interface Server extends Client { | |||||
/** | |||||
* start serving need top call serve or serveNet first to set up the server | |||||
*/ | |||||
start(): void; | |||||
/** | |||||
* close the server and stop serving | |||||
*/ | |||||
stop(): void; | |||||
emit(value: any): Client; | |||||
emit(event: string, value: any): Client; | |||||
emit(socket: Socket | SocketConfig, event: string, value?: any): Server; | |||||
emit(socketConfig: Socket | SocketConfig, value?: any): Server; | |||||
} | |||||
interface SocketConfig { | |||||
address?: string; | |||||
port?: number; | |||||
} | |||||
interface Config { | |||||
/** | |||||
* Default: 'app.' | |||||
* Used for Unix Socket (Unix Domain Socket) namespacing. | |||||
* If not set specifically, the Unix Domain Socket will combine the socketRoot, appspace, | |||||
* and id to form the Unix Socket Path for creation or binding. | |||||
* This is available incase you have many apps running on your system, you may have several sockets with the same id, | |||||
* but if you change the appspace, you will still have app specic unique sockets | |||||
*/ | |||||
appspace: string; | |||||
/** | |||||
* Default: '/tmp/' | |||||
* The directory in which to create or bind to a Unix Socket | |||||
*/ | |||||
socketRoot: string; | |||||
/** | |||||
* Default: os.hostname() | |||||
* The id of this socket or service | |||||
*/ | |||||
id: string; | |||||
/** | |||||
* Default: 'localhost' | |||||
* The local or remote host on which TCP, TLS or UDP Sockets should connect | |||||
* Should resolve to 127.0.0.1 or ::1 see the table below related to this | |||||
*/ | |||||
networkHost: string; | |||||
/** | |||||
* Default: 8000 | |||||
* The default port on which TCP, TLS, or UDP sockets should connect | |||||
*/ | |||||
networkPort: number; | |||||
/** | |||||
* Default: 'utf8' | |||||
* the default encoding for data sent on sockets. Mostly used if rawBuffer is set to true. | |||||
* Valid values are : ascii utf8 utf16le ucs2 base64 hex | |||||
*/ | |||||
encoding: "ascii" | "utf8" | "utf16le" | "ucs2" | "base64" | "hex"; | |||||
/** | |||||
* Default: false | |||||
* If true, data will be sent and received as a raw node Buffer NOT an Object as JSON. | |||||
* This is great for Binary or hex IPC, and communicating with other processes in languages like C and C++ | |||||
*/ | |||||
rawBuffer: boolean; | |||||
/** | |||||
* Default: false | |||||
* Synchronous requests. Clients will not send new requests until the server answers | |||||
*/ | |||||
sync: boolean; | |||||
/** | |||||
* Default: false | |||||
* Turn on/off logging default is false which means logging is on | |||||
*/ | |||||
silent: boolean; | |||||
/** | |||||
* Default: true | |||||
* Turn on/off util.inspect colors for ipc.log | |||||
*/ | |||||
logInColor: boolean; | |||||
/** | |||||
* Default: 5 | |||||
* Set the depth for util.inspect during ipc.log | |||||
*/ | |||||
logDepth: number; | |||||
/** | |||||
* Default: console.log | |||||
* The function which receives the output from ipc.log; should take a single string argument | |||||
*/ | |||||
logger(msg: string): void; | |||||
/** | |||||
* Default: 100 | |||||
* This is the max number of connections allowed to a socket. It is currently only being set on Unix Sockets. | |||||
* Other Socket types are using the system defaults | |||||
*/ | |||||
maxConnections: number; | |||||
/** | |||||
* Default: 500 | |||||
* This is the time in milliseconds a client will wait before trying to reconnect to a server if the connection is lost. | |||||
* This does not effect UDP sockets since they do not have a client server relationship like Unix Sockets and TCP Sockets | |||||
*/ | |||||
retry: number; | |||||
/* */ | |||||
/** | |||||
* Default: false | |||||
* if set, it represents the maximum number of retries after each disconnect before giving up | |||||
* and completely killing a specific connection | |||||
*/ | |||||
maxRetries: boolean | number; | |||||
/** | |||||
* Default: false | |||||
* Defaults to false meaning clients will continue to retry to connect to servers indefinitely at the retry interval. | |||||
* If set to any number the client will stop retrying when that number is exceeded after each disconnect. | |||||
* If set to true in real time it will immediately stop trying to connect regardless of maxRetries. | |||||
* If set to 0, the client will NOT try to reconnect | |||||
*/ | |||||
stopRetrying: boolean; | |||||
/** | |||||
* Default: true | |||||
* Defaults to true meaning that the module will take care of deleting the IPC socket prior to startup. | |||||
* If you use node-ipc in a clustered environment where there will be multiple listeners on the same socket, | |||||
* you must set this to false and then take care of deleting the socket in your own code. | |||||
*/ | |||||
unlink: boolean; | |||||
/** | |||||
* Primarily used when specifying which interface a client should connect through. | |||||
* see the socket.connect documentation in the node.js api https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener | |||||
*/ | |||||
interfaces: { | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
localAddress?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
localPort?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
family?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
hints?: boolean; | |||||
/** | |||||
* Default: false | |||||
*/ | |||||
lookup?: boolean; | |||||
}; | |||||
tls: { | |||||
rejectUnauthorized?: boolean; | |||||
public?: string; | |||||
private?: string; | |||||
}; | |||||
} | |||||
} | |||||
export = NodeIPC | |||||
// declare const RootIPC: NodeIPC.IPC & { IPC: new () => NodeIPC.IPC }; | |||||
// export = RootIPC; | |||||
} | |||||
@ -1,38 +0,0 @@ | |||||
import * as glob from "glob"; | |||||
import * as fs from "fs"; | |||||
declare function rimraf(path: string, options: rimraf.Options, callback: (error?: Error) => void): void; | |||||
declare function rimraf(path: string, callback: (error?: Error) => void): void; | |||||
declare namespace rimraf { | |||||
/** | |||||
* It can remove stuff synchronously, too. | |||||
* But that's not so good. Use the async API. | |||||
* It's better. | |||||
*/ | |||||
function sync(path: string, options?: Options): void; | |||||
/** | |||||
* see {@link https://github.com/isaacs/rimraf/blob/79b933fb362b2c51bedfa448be848e1d7ed32d7e/README.md#options} | |||||
*/ | |||||
interface Options { | |||||
maxBusyTries?: number; | |||||
emfileWait?: number; | |||||
/** @default false */ | |||||
disableGlob?: boolean; | |||||
glob?: glob.IOptions | false; | |||||
unlink?: typeof fs.unlink; | |||||
chmod?: typeof fs.chmod; | |||||
stat?: typeof fs.stat; | |||||
lstat?: typeof fs.lstat; | |||||
rmdir?: typeof fs.rmdir; | |||||
readdir?: typeof fs.readdir; | |||||
unlinkSync?: typeof fs.unlinkSync; | |||||
chmodSync?: typeof fs.chmodSync; | |||||
statSync?: typeof fs.statSync; | |||||
lstatSync?: typeof fs.lstatSync; | |||||
rmdirSync?: typeof fs.rmdirSync; | |||||
readdirSync?: typeof fs.readdirSync; | |||||
} | |||||
} | |||||
export = rimraf; |
@ -1,232 +0,0 @@ | |||||
// declare module "webtorrent-hybrid" { | |||||
// declare class WebTorrent { | |||||
// } | |||||
// declare const WebTorrent: WebTorrent.WebTorrent; | |||||
// declare namespace WebTorrent { | |||||
// interface WebTorrent { | |||||
// new (config?: Options): Instance; | |||||
// (config?: Options): Instance; | |||||
// WEBRTC_SUPPORT: boolean; | |||||
// } | |||||
// } | |||||
// export = WebTorrent; | |||||
// } | |||||
// Type definitions for WebTorrent 0.109 | |||||
// Project: https://github.com/feross/webtorrent, https://webtorrent.io | |||||
// Definitions by: Bazyli Brzóska <https://github.com/niieani> | |||||
// Tomasz Łaziuk <https://github.com/tlaziuk> | |||||
// Gabriel Juchault <https://github.com/gjuchault> | |||||
// Adam Crowder <https://github.com/cheeseandcereal> | |||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped | |||||
/// <reference types="node" /> | |||||
declare module "webtorrent-hybrid" { | |||||
import { Instance as MagnetUri } from 'magnet-uri'; | |||||
import { Instance as ParseTorrent } from 'parse-torrent'; | |||||
import { Instance as SimplePeer } from 'simple-peer'; | |||||
import { RequestOptions, Server } from 'http'; | |||||
import { Wire } from 'bittorrent-protocol'; | |||||
declare const WebTorrent: WebTorrent.WebTorrent; | |||||
declare namespace WebTorrent { | |||||
interface WebTorrent { | |||||
new (config?: Options): Instance; | |||||
(config?: Options): Instance; | |||||
WEBRTC_SUPPORT: boolean; | |||||
} | |||||
interface Options { | |||||
maxConns?: number; | |||||
nodeId?: string | Buffer; | |||||
peerId?: string | Buffer; | |||||
tracker?: boolean | {}; | |||||
dht?: boolean | {}; | |||||
webSeeds?: boolean; | |||||
utp?: boolean; | |||||
} | |||||
interface TorrentOptions { | |||||
announce?: any[]; | |||||
getAnnounceOpts?(): void; | |||||
maxWebConns?: number; | |||||
path?: string; | |||||
store?(chunkLength: number, storeOpts: { length: number, files: File[], torrent: Torrent, }): any; | |||||
private?: boolean; | |||||
} | |||||
interface TorrentDestroyOptions { | |||||
destroyStore?: boolean; | |||||
} | |||||
interface Instance extends NodeJS.EventEmitter { | |||||
on(event: 'torrent', callback: (torrent: Torrent) => void): this; | |||||
on(event: 'error', callback: (err: Error | string) => void): this; | |||||
add(torrent: string | Buffer | File | ParseTorrent | MagnetUri, opts?: TorrentOptions, cb?: (torrent: Torrent) => any): Torrent; | |||||
add(torrent: string | Buffer | File | ParseTorrent | MagnetUri, cb?: (torrent: Torrent) => any): Torrent; | |||||
seed(input: string | string[] | File | File[] | FileList | Buffer | Buffer[] | NodeJS.ReadableStream | NodeJS.ReadableStream[], opts?: TorrentOptions, cb?: (torrent: Torrent) => any): Torrent; | |||||
seed(input: string | string[] | File | File[] | FileList | Buffer | Buffer[] | NodeJS.ReadableStream | NodeJS.ReadableStream[], cb?: (torrent: Torrent) => any): Torrent; | |||||
remove(torrentId: Torrent | string | Buffer, opts?: TorrentDestroyOptions, callback?: (err: Error | string) => void): void; | |||||
destroy(callback?: (err: Error | string) => void): void; | |||||
readonly torrents: Torrent[]; | |||||
get(torrentId: Torrent | string | Buffer): Torrent | null; | |||||
readonly downloadSpeed: number; | |||||
readonly uploadSpeed: number; | |||||
readonly progress: number; | |||||
readonly ratio: number; | |||||
} | |||||
interface Torrent extends NodeJS.EventEmitter { | |||||
readonly infoHash: string; | |||||
readonly magnetURI: string; | |||||
readonly torrentFile: Buffer; | |||||
readonly torrentFileBlobURL: string; | |||||
readonly files: TorrentFile[]; | |||||
readonly announce: string[]; | |||||
readonly pieces: Array<TorrentPiece | null>; | |||||
readonly timeRemaining: number; | |||||
readonly received: number; | |||||
readonly downloaded: number; | |||||
readonly uploaded: number; | |||||
readonly downloadSpeed: number; | |||||
readonly uploadSpeed: number; | |||||
readonly progress: number; | |||||
readonly ratio: number; | |||||
readonly length: number; | |||||
readonly pieceLength: number; | |||||
readonly lastPieceLength: number; | |||||
readonly numPeers: number; | |||||
readonly path: string; | |||||
readonly ready: boolean; | |||||
readonly paused: boolean; | |||||
readonly done: boolean; | |||||
readonly name: string; | |||||
readonly created: Date; | |||||
readonly createdBy: string; | |||||
readonly comment: string; | |||||
readonly maxWebConns: number; | |||||
destroy(opts?: TorrentDestroyOptions, cb?: (err: Error | string) => void): void; | |||||
addPeer(peer: string | SimplePeer): boolean; | |||||
addWebSeed(url: string): void; | |||||
removePeer(peer: string | SimplePeer): void; | |||||
select(start: number, end: number, priority?: number, notify?: () => void): void; | |||||
deselect(start: number, end: number, priority: number): void; | |||||
createServer(opts?: RequestOptions): Server; | |||||
pause(): void; | |||||
resume(): void; | |||||
rescanFiles(callback?: (err: Error | string | null) => void): void; | |||||
on(event: 'infoHash' | 'metadata' | 'ready' | 'done', callback: () => void): this; | |||||
on(event: 'warning' | 'error', callback: (err: Error | string) => void): this; | |||||
on(event: 'download' | 'upload', callback: (bytes: number) => void): this; | |||||
on(event: 'wire', callback: (wire: Wire, addr?: string) => void): this; | |||||
on(event: 'noPeers', callback: (announceType: 'tracker' | 'dht') => void): this; | |||||
} | |||||
interface TorrentFile extends NodeJS.EventEmitter { | |||||
// Custom property to check if a file is selected | |||||
readonly isSelected: boolean; | |||||
readonly name: string; | |||||
readonly path: string; | |||||
readonly length: number; | |||||
readonly downloaded: number; | |||||
readonly progress: number; | |||||
select(): void; | |||||
deselect(): void; | |||||
createReadStream(opts?: { start: number, end: number, }): NodeJS.ReadableStream; | |||||
getBuffer(callback: (err: string | Error | undefined, buffer?: Buffer) => void): void; | |||||
appendTo( | |||||
rootElement: HTMLElement | string, | |||||
opts?: { autoplay?: boolean, controls?: boolean, maxBlobLength?: number }, | |||||
callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
appendTo(rootElement: HTMLElement | string, callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
renderTo( | |||||
rootElement: HTMLMediaElement | string, | |||||
opts?: { autoplay?: boolean, controls?: boolean, maxBlobLength?: number }, | |||||
callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
renderTo(rootElement: HTMLMediaElement | string, callback?: (err: Error | undefined, element: HTMLMediaElement) => void): void; | |||||
getBlob(callback: (err: string | Error | undefined, blob?: Blob) => void): void; | |||||
getBlobURL(callback: (err: string | Error | undefined, blobURL?: string) => void): void; | |||||
} | |||||
interface TorrentPiece { | |||||
readonly length: number; | |||||
readonly missing: number; | |||||
} | |||||
} | |||||
export = WebTorrent; | |||||
} | |||||
@ -0,0 +1,5 @@ | |||||
# Application key to sign stuff | |||||
APP_KEY_FILE = /run/secrets/app_key | |||||
# The webserver port | |||||
WEBSERVER_PORT = 3300 |
@ -0,0 +1,26 @@ | |||||
{ | |||||
"name": "@autoplex-service/torrent-rest", | |||||
"version": "0.0.0", | |||||
"main": "index.js", | |||||
"license": "MIT", | |||||
"scripts": { | |||||
"clean": "rimraf ./dist", | |||||
"build": "ttsc", | |||||
"start": "NODE_ENV=production node .", | |||||
"start:dev": "nodemon" | |||||
}, | |||||
"dependencies": { | |||||
"@autoplex-api/torrent": "^0.0.0", | |||||
"@autoplex/database": "^0.0.0", | |||||
"@autoplex/microservice": "^0.0.0", | |||||
"@autoplex/utils": "^0.0.0", | |||||
"@autoplex/webserver": "^0.0.0" | |||||
}, | |||||
"devDependencies": { | |||||
"@types/node": "^15.0.1", | |||||
"nodemon": "^2.0.7", | |||||
"rimraf": "^3.0.2", | |||||
"ts-node": "^9.1.1", | |||||
"typescript": "^4.2.4" | |||||
} | |||||
} |
@ -0,0 +1,19 @@ | |||||
import { Microservice } from "@autoplex/microservice"; | |||||
import * as services from "./services"; | |||||
export default class Application extends Microservice | |||||
{ | |||||
/** | |||||
* The app key to sign stuff | |||||
*/ | |||||
public readonly APP_KEY: string; | |||||
/** | |||||
* Create a new application instance | |||||
*/ | |||||
constructor(appKey: string) { | |||||
super(); | |||||
this.APP_KEY = appKey; | |||||
this.installServices(Object.values(services)); | |||||
} | |||||
} |
@ -0,0 +1,11 @@ | |||||
import Application from "./Application"; | |||||
import { env, secretSync } from "@autoplex/utils"; | |||||
// Load the API key | |||||
const API_KEY = secretSync(env("APP_KEY_FILE")); | |||||
// Create a new application instance | |||||
let app = new Application(API_KEY); | |||||
// Start the application | |||||
app.exec().then(process.exit); |
@ -0,0 +1,10 @@ | |||||
import { IpcClient } from "@autoplex-api/torrent"; | |||||
import Application from "../Application"; | |||||
export default class TorrentIpc extends IpcClient<Application> | |||||
{ | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "Torrent Client"; | |||||
} |
@ -0,0 +1,27 @@ | |||||
import { WebServerService } from "@autoplex/webserver"; | |||||
import { env } from "@autoplex/utils"; | |||||
import Application from "../../Application"; | |||||
import * as routes from "./routes"; | |||||
export default class WebServer extends WebServerService<Application> | |||||
{ | |||||
/** | |||||
* The service name | |||||
*/ | |||||
public readonly NAME = "Web Server"; | |||||
/** | |||||
* The port to serve on | |||||
*/ | |||||
public readonly PORT = parseInt(env("WEBSERVER_PORT")); | |||||
/** | |||||
* The app key to sign stuff | |||||
*/ | |||||
protected readonly APP_KEY = this.app.APP_KEY; | |||||
/** | |||||
* Register the webserver routes | |||||
*/ | |||||
protected ROUTES = Object.values(routes); | |||||
} |
@ -0,0 +1,91 @@ | |||||
import { MiddlewareMethod, RouteRegisterFactory } from "@autoplex/webserver"; | |||||
import Application from "../../../Application"; | |||||
import TorrentIpc from "../../TorrentIpc"; | |||||
export default function register(factory: RouteRegisterFactory<MiddlewareMethod<void>, Application>, | |||||
app: Application) | |||||
{ | |||||
/** | |||||
* Fetch the torrent client instance | |||||
*/ | |||||
const ipc = app.service<TorrentIpc>("Torrent Client"); | |||||
/** | |||||
* Register API prefix | |||||
*/ | |||||
factory.prefix("/api/torrent", [], (factory, app) => { | |||||
/** | |||||
* Get the torrent list | |||||
*/ | |||||
factory.get("/list", async (request, reply) => { | |||||
let torrentList = await ipc.list(); | |||||
reply.send({ result: torrentList, status: "Success" }); | |||||
}); | |||||
/** | |||||
* Fetch the details of a torrent | |||||
*/ | |||||
factory.get("/details/:infoHash", async (request, reply) => { | |||||
let infoHash: string = (<any>request.params)["infoHash"]; | |||||
if (infoHash === undefined) { | |||||
reply.status(400); | |||||
reply.send({ status: "Bad request" }); | |||||
return; | |||||
} | |||||
try { | |||||
let details = await ipc.details(infoHash); | |||||
reply.send({ result: details, status: "Success" }); | |||||
} catch(e) { | |||||
reply.status(404); | |||||
reply.send({ status: "Not found" }); | |||||
} | |||||
}); | |||||
/** | |||||
* Add a torrent to the client | |||||
*/ | |||||
factory.post("/add", async (request, reply) => { | |||||
let result: string[] = []; | |||||
if (request.isMultipart()) { | |||||
let files = request.files(); | |||||
for await (let file of files) { | |||||
let torrentFile = await file.toBuffer(); | |||||
let infoHash = await ipc.add(torrentFile); | |||||
result.push(infoHash); | |||||
} | |||||
} else { | |||||
let links = (<any>request.body)?.link ?? null; | |||||
if (links === null) { | |||||
reply.status(400); | |||||
reply.send({ status: "Bad request" }); | |||||
return; | |||||
} | |||||
for (let link of (Array.isArray(links) ? links : [links])) { | |||||
let infoHash = await ipc.add(link); | |||||
result.push(infoHash); | |||||
} | |||||
} | |||||
reply.send({ result: result, status: "Success" }); | |||||
}); | |||||
}); | |||||
/** | |||||
* Remove a torrent from the client | |||||
*/ | |||||
factory.delete("/remove/:infoHash", async (request, reply) => { | |||||
let infoHash: string = (<any>request.params)["infoHash"]; | |||||
if (infoHash === undefined) { | |||||
reply.status(400); | |||||
reply.send({ status: "Bad request" }); | |||||
return; | |||||
} | |||||
try { | |||||
await ipc.remove(infoHash); | |||||
reply.send({ status: "Success" }); | |||||
} catch(e) { | |||||
reply.status(404); | |||||
reply.send({ status: "Not found" }); | |||||
} | |||||
}); | |||||
} |
@ -0,0 +1,5 @@ | |||||
import api from "./api"; | |||||
export { | |||||
api | |||||
} |
@ -0,0 +1,7 @@ | |||||
import TorrentIpc from "./TorrentIpc"; | |||||
import WebServer from "./WebServer/WebServer"; | |||||
export { | |||||
TorrentIpc, | |||||
WebServer | |||||
} |
@ -0,0 +1,898 @@ | |||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | |||||
# yarn lockfile v1 | |||||
"@sindresorhus/is@^0.14.0": | |||||
version "0.14.0" | |||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" | |||||
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== | |||||
"@szmarczak/http-timer@^1.1.2": | |||||
version "1.1.2" | |||||
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" | |||||
integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== | |||||
dependencies: | |||||
defer-to-connect "^1.0.1" | |||||
"@types/node@^15.0.1": | |||||
version "15.0.1" | |||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" | |||||
integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== | |||||
abbrev@1: | |||||
version "1.1.1" | |||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" | |||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== | |||||
ansi-align@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" | |||||
integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== | |||||
dependencies: | |||||
string-width "^3.0.0" | |||||
ansi-regex@^4.1.0: | |||||
version "4.1.0" | |||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" | |||||
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== | |||||
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-styles@^4.1.0: | |||||
version "4.3.0" | |||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" | |||||
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== | |||||
dependencies: | |||||
color-convert "^2.0.1" | |||||
anymatch@~3.1.1: | |||||
version "3.1.2" | |||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" | |||||
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== | |||||
dependencies: | |||||
normalize-path "^3.0.0" | |||||
picomatch "^2.0.4" | |||||
arg@^4.1.0: | |||||
version "4.1.3" | |||||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" | |||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== | |||||
balanced-match@^1.0.0: | |||||
version "1.0.2" | |||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" | |||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== | |||||
binary-extensions@^2.0.0: | |||||
version "2.2.0" | |||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" | |||||
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== | |||||
boxen@^4.2.0: | |||||
version "4.2.0" | |||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" | |||||
integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== | |||||
dependencies: | |||||
ansi-align "^3.0.0" | |||||
camelcase "^5.3.1" | |||||
chalk "^3.0.0" | |||||
cli-boxes "^2.2.0" | |||||
string-width "^4.1.0" | |||||
term-size "^2.1.0" | |||||
type-fest "^0.8.1" | |||||
widest-line "^3.1.0" | |||||
brace-expansion@^1.1.7: | |||||
version "1.1.11" | |||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" | |||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== | |||||
dependencies: | |||||
balanced-match "^1.0.0" | |||||
concat-map "0.0.1" | |||||
braces@~3.0.2: | |||||
version "3.0.2" | |||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" | |||||
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== | |||||
dependencies: | |||||
fill-range "^7.0.1" | |||||
buffer-from@^1.0.0: | |||||
version "1.1.1" | |||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" | |||||
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== | |||||
cacheable-request@^6.0.0: | |||||
version "6.1.0" | |||||
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" | |||||
integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== | |||||
dependencies: | |||||
clone-response "^1.0.2" | |||||
get-stream "^5.1.0" | |||||
http-cache-semantics "^4.0.0" | |||||
keyv "^3.0.0" | |||||
lowercase-keys "^2.0.0" | |||||
normalize-url "^4.1.0" | |||||
responselike "^1.0.2" | |||||
camelcase@^5.3.1: | |||||
version "5.3.1" | |||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" | |||||
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== | |||||
chalk@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" | |||||
integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== | |||||
dependencies: | |||||
ansi-styles "^4.1.0" | |||||
supports-color "^7.1.0" | |||||
chokidar@^3.2.2: | |||||
version "3.5.1" | |||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" | |||||
integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== | |||||
dependencies: | |||||
anymatch "~3.1.1" | |||||
braces "~3.0.2" | |||||
glob-parent "~5.1.0" | |||||
is-binary-path "~2.1.0" | |||||
is-glob "~4.0.1" | |||||
normalize-path "~3.0.0" | |||||
readdirp "~3.5.0" | |||||
optionalDependencies: | |||||
fsevents "~2.3.1" | |||||
ci-info@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" | |||||
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== | |||||
cli-boxes@^2.2.0: | |||||
version "2.2.1" | |||||
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" | |||||
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== | |||||
clone-response@^1.0.2: | |||||
version "1.0.2" | |||||
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" | |||||
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= | |||||
dependencies: | |||||
mimic-response "^1.0.0" | |||||
color-convert@^2.0.1: | |||||
version "2.0.1" | |||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" | |||||
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== | |||||
dependencies: | |||||
color-name "~1.1.4" | |||||
color-name@~1.1.4: | |||||
version "1.1.4" | |||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" | |||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== | |||||
concat-map@0.0.1: | |||||
version "0.0.1" | |||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | |||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= | |||||
configstore@^5.0.1: | |||||
version "5.0.1" | |||||
resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" | |||||
integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== | |||||
dependencies: | |||||
dot-prop "^5.2.0" | |||||
graceful-fs "^4.1.2" | |||||
make-dir "^3.0.0" | |||||
unique-string "^2.0.0" | |||||
write-file-atomic "^3.0.0" | |||||
xdg-basedir "^4.0.0" | |||||
create-require@^1.1.0: | |||||
version "1.1.1" | |||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" | |||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== | |||||
crypto-random-string@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" | |||||
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== | |||||
debug@^2.2.0: | |||||
version "2.6.9" | |||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" | |||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== | |||||
dependencies: | |||||
ms "2.0.0" | |||||
debug@^3.2.6: | |||||
version "3.2.7" | |||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" | |||||
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== | |||||
dependencies: | |||||
ms "^2.1.1" | |||||
decompress-response@^3.3.0: | |||||
version "3.3.0" | |||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" | |||||
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= | |||||
dependencies: | |||||
mimic-response "^1.0.0" | |||||
deep-extend@^0.6.0: | |||||
version "0.6.0" | |||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" | |||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== | |||||
defer-to-connect@^1.0.1: | |||||
version "1.1.3" | |||||
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" | |||||
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== | |||||
diff@^4.0.1: | |||||
version "4.0.2" | |||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" | |||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== | |||||
dot-prop@^5.2.0: | |||||
version "5.3.0" | |||||
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" | |||||
integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== | |||||
dependencies: | |||||
is-obj "^2.0.0" | |||||
duplexer3@^0.1.4: | |||||
version "0.1.4" | |||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" | |||||
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= | |||||
emoji-regex@^7.0.1: | |||||
version "7.0.3" | |||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" | |||||
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== | |||||
emoji-regex@^8.0.0: | |||||
version "8.0.0" | |||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" | |||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== | |||||
end-of-stream@^1.1.0: | |||||
version "1.4.4" | |||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" | |||||
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== | |||||
dependencies: | |||||
once "^1.4.0" | |||||
escape-goat@^2.0.0: | |||||
version "2.1.1" | |||||
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" | |||||
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== | |||||
fill-range@^7.0.1: | |||||
version "7.0.1" | |||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" | |||||
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== | |||||
dependencies: | |||||
to-regex-range "^5.0.1" | |||||
fs.realpath@^1.0.0: | |||||
version "1.0.0" | |||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | |||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= | |||||
fsevents@~2.3.1: | |||||
version "2.3.2" | |||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" | |||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== | |||||
get-stream@^4.1.0: | |||||
version "4.1.0" | |||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" | |||||
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== | |||||
dependencies: | |||||
pump "^3.0.0" | |||||
get-stream@^5.1.0: | |||||
version "5.2.0" | |||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" | |||||
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== | |||||
dependencies: | |||||
pump "^3.0.0" | |||||
glob-parent@~5.1.0: | |||||
version "5.1.2" | |||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" | |||||
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== | |||||
dependencies: | |||||
is-glob "^4.0.1" | |||||
glob@^7.1.3: | |||||
version "7.1.6" | |||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" | |||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== | |||||
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-dirs@^2.0.1: | |||||
version "2.1.0" | |||||
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" | |||||
integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== | |||||
dependencies: | |||||
ini "1.3.7" | |||||
got@^9.6.0: | |||||
version "9.6.0" | |||||
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" | |||||
integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== | |||||
dependencies: | |||||
"@sindresorhus/is" "^0.14.0" | |||||
"@szmarczak/http-timer" "^1.1.2" | |||||
cacheable-request "^6.0.0" | |||||
decompress-response "^3.3.0" | |||||
duplexer3 "^0.1.4" | |||||
get-stream "^4.1.0" | |||||
lowercase-keys "^1.0.1" | |||||
mimic-response "^1.0.1" | |||||
p-cancelable "^1.0.0" | |||||
to-readable-stream "^1.0.0" | |||||
url-parse-lax "^3.0.0" | |||||
graceful-fs@^4.1.2: | |||||
version "4.2.6" | |||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" | |||||
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== | |||||
has-flag@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" | |||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= | |||||
has-flag@^4.0.0: | |||||
version "4.0.0" | |||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" | |||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== | |||||
has-yarn@^2.1.0: | |||||
version "2.1.0" | |||||
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" | |||||
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== | |||||
http-cache-semantics@^4.0.0: | |||||
version "4.1.0" | |||||
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" | |||||
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== | |||||
ignore-by-default@^1.0.1: | |||||
version "1.0.1" | |||||
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" | |||||
integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= | |||||
import-lazy@^2.1.0: | |||||
version "2.1.0" | |||||
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" | |||||
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= | |||||
imurmurhash@^0.1.4: | |||||
version "0.1.4" | |||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" | |||||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= | |||||
inflight@^1.0.4: | |||||
version "1.0.6" | |||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" | |||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= | |||||
dependencies: | |||||
once "^1.3.0" | |||||
wrappy "1" | |||||
inherits@2: | |||||
version "2.0.4" | |||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" | |||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== | |||||
ini@1.3.7: | |||||
version "1.3.7" | |||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" | |||||
integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== | |||||
ini@~1.3.0: | |||||
version "1.3.8" | |||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" | |||||
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== | |||||
is-binary-path@~2.1.0: | |||||
version "2.1.0" | |||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" | |||||
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== | |||||
dependencies: | |||||
binary-extensions "^2.0.0" | |||||
is-ci@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" | |||||
integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== | |||||
dependencies: | |||||
ci-info "^2.0.0" | |||||
is-extglob@^2.1.1: | |||||
version "2.1.1" | |||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" | |||||
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= | |||||
is-fullwidth-code-point@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" | |||||
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= | |||||
is-fullwidth-code-point@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" | |||||
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== | |||||
is-glob@^4.0.1, is-glob@~4.0.1: | |||||
version "4.0.1" | |||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" | |||||
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== | |||||
dependencies: | |||||
is-extglob "^2.1.1" | |||||
is-installed-globally@^0.3.1: | |||||
version "0.3.2" | |||||
resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" | |||||
integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== | |||||
dependencies: | |||||
global-dirs "^2.0.1" | |||||
is-path-inside "^3.0.1" | |||||
is-npm@^4.0.0: | |||||
version "4.0.0" | |||||
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" | |||||
integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== | |||||
is-number@^7.0.0: | |||||
version "7.0.0" | |||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" | |||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== | |||||
is-obj@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" | |||||
integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== | |||||
is-path-inside@^3.0.1: | |||||
version "3.0.3" | |||||
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" | |||||
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== | |||||
is-typedarray@^1.0.0: | |||||
version "1.0.0" | |||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" | |||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= | |||||
is-yarn-global@^0.3.0: | |||||
version "0.3.0" | |||||
resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" | |||||
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== | |||||
json-buffer@3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" | |||||
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= | |||||
keyv@^3.0.0: | |||||
version "3.1.0" | |||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" | |||||
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== | |||||
dependencies: | |||||
json-buffer "3.0.0" | |||||
latest-version@^5.0.0: | |||||
version "5.1.0" | |||||
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" | |||||
integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== | |||||
dependencies: | |||||
package-json "^6.3.0" | |||||
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: | |||||
version "1.0.1" | |||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" | |||||
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== | |||||
lowercase-keys@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" | |||||
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== | |||||
make-dir@^3.0.0: | |||||
version "3.1.0" | |||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" | |||||
integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== | |||||
dependencies: | |||||
semver "^6.0.0" | |||||
make-error@^1.1.1: | |||||
version "1.3.6" | |||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" | |||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== | |||||
mimic-response@^1.0.0, mimic-response@^1.0.1: | |||||
version "1.0.1" | |||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" | |||||
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== | |||||
minimatch@^3.0.4: | |||||
version "3.0.4" | |||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" | |||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== | |||||
dependencies: | |||||
brace-expansion "^1.1.7" | |||||
minimist@^1.2.0: | |||||
version "1.2.5" | |||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" | |||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== | |||||
ms@2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" | |||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= | |||||
ms@^2.1.1: | |||||
version "2.1.3" | |||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" | |||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== | |||||
nodemon@^2.0.7: | |||||
version "2.0.7" | |||||
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.7.tgz#6f030a0a0ebe3ea1ba2a38f71bf9bab4841ced32" | |||||
integrity sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA== | |||||
dependencies: | |||||
chokidar "^3.2.2" | |||||
debug "^3.2.6" | |||||
ignore-by-default "^1.0.1" | |||||
minimatch "^3.0.4" | |||||
pstree.remy "^1.1.7" | |||||
semver "^5.7.1" | |||||
supports-color "^5.5.0" | |||||
touch "^3.1.0" | |||||
undefsafe "^2.0.3" | |||||
update-notifier "^4.1.0" | |||||
nopt@~1.0.10: | |||||
version "1.0.10" | |||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" | |||||
integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= | |||||
dependencies: | |||||
abbrev "1" | |||||
normalize-path@^3.0.0, normalize-path@~3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" | |||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== | |||||
normalize-url@^4.1.0: | |||||
version "4.5.0" | |||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" | |||||
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== | |||||
once@^1.3.0, once@^1.3.1, once@^1.4.0: | |||||
version "1.4.0" | |||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" | |||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= | |||||
dependencies: | |||||
wrappy "1" | |||||
p-cancelable@^1.0.0: | |||||
version "1.1.0" | |||||
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" | |||||
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== | |||||
package-json@^6.3.0: | |||||
version "6.5.0" | |||||
resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" | |||||
integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== | |||||
dependencies: | |||||
got "^9.6.0" | |||||
registry-auth-token "^4.0.0" | |||||
registry-url "^5.0.0" | |||||
semver "^6.2.0" | |||||
path-is-absolute@^1.0.0: | |||||
version "1.0.1" | |||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" | |||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= | |||||
picomatch@^2.0.4, picomatch@^2.2.1: | |||||
version "2.2.3" | |||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" | |||||
integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== | |||||
prepend-http@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" | |||||
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= | |||||
pstree.remy@^1.1.7: | |||||
version "1.1.8" | |||||
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" | |||||
integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== | |||||
pump@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" | |||||
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== | |||||
dependencies: | |||||
end-of-stream "^1.1.0" | |||||
once "^1.3.1" | |||||
pupa@^2.0.1: | |||||
version "2.1.1" | |||||
resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" | |||||
integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== | |||||
dependencies: | |||||
escape-goat "^2.0.0" | |||||
rc@^1.2.8: | |||||
version "1.2.8" | |||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" | |||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== | |||||
dependencies: | |||||
deep-extend "^0.6.0" | |||||
ini "~1.3.0" | |||||
minimist "^1.2.0" | |||||
strip-json-comments "~2.0.1" | |||||
readdirp@~3.5.0: | |||||
version "3.5.0" | |||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" | |||||
integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== | |||||
dependencies: | |||||
picomatch "^2.2.1" | |||||
registry-auth-token@^4.0.0: | |||||
version "4.2.1" | |||||
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" | |||||
integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== | |||||
dependencies: | |||||
rc "^1.2.8" | |||||
registry-url@^5.0.0: | |||||
version "5.1.0" | |||||
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" | |||||
integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== | |||||
dependencies: | |||||
rc "^1.2.8" | |||||
responselike@^1.0.2: | |||||
version "1.0.2" | |||||
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" | |||||
integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= | |||||
dependencies: | |||||
lowercase-keys "^1.0.0" | |||||
rimraf@^3.0.2: | |||||
version "3.0.2" | |||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" | |||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== | |||||
dependencies: | |||||
glob "^7.1.3" | |||||
semver-diff@^3.1.1: | |||||
version "3.1.1" | |||||
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" | |||||
integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== | |||||
dependencies: | |||||
semver "^6.3.0" | |||||
semver@^5.7.1: | |||||
version "5.7.1" | |||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" | |||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== | |||||
semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: | |||||
version "6.3.0" | |||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" | |||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== | |||||
signal-exit@^3.0.2: | |||||
version "3.0.3" | |||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" | |||||
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== | |||||
source-map-support@^0.5.17: | |||||
version "0.5.19" | |||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" | |||||
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== | |||||
dependencies: | |||||
buffer-from "^1.0.0" | |||||
source-map "^0.6.0" | |||||
source-map@^0.6.0: | |||||
version "0.6.1" | |||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" | |||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== | |||||
string-width@^3.0.0: | |||||
version "3.1.0" | |||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" | |||||
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== | |||||
dependencies: | |||||
emoji-regex "^7.0.1" | |||||
is-fullwidth-code-point "^2.0.0" | |||||
strip-ansi "^5.1.0" | |||||
string-width@^4.0.0, string-width@^4.1.0: | |||||
version "4.2.2" | |||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" | |||||
integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== | |||||
dependencies: | |||||
emoji-regex "^8.0.0" | |||||
is-fullwidth-code-point "^3.0.0" | |||||
strip-ansi "^6.0.0" | |||||
strip-ansi@^5.1.0: | |||||
version "5.2.0" | |||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" | |||||
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== | |||||
dependencies: | |||||
ansi-regex "^4.1.0" | |||||
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== | |||||
dependencies: | |||||
ansi-regex "^5.0.0" | |||||
strip-json-comments@~2.0.1: | |||||
version "2.0.1" | |||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" | |||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= | |||||
supports-color@^5.5.0: | |||||
version "5.5.0" | |||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" | |||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== | |||||
dependencies: | |||||
has-flag "^3.0.0" | |||||
supports-color@^7.1.0: | |||||
version "7.2.0" | |||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" | |||||
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== | |||||
dependencies: | |||||
has-flag "^4.0.0" | |||||
term-size@^2.1.0: | |||||
version "2.2.1" | |||||
resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" | |||||
integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== | |||||
to-readable-stream@^1.0.0: | |||||
version "1.0.0" | |||||
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" | |||||
integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== | |||||
to-regex-range@^5.0.1: | |||||
version "5.0.1" | |||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" | |||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== | |||||
dependencies: | |||||
is-number "^7.0.0" | |||||
touch@^3.1.0: | |||||
version "3.1.0" | |||||
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" | |||||
integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== | |||||
dependencies: | |||||
nopt "~1.0.10" | |||||
ts-node@^9.1.1: | |||||
version "9.1.1" | |||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" | |||||
integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== | |||||
dependencies: | |||||
arg "^4.1.0" | |||||
create-require "^1.1.0" | |||||
diff "^4.0.1" | |||||
make-error "^1.1.1" | |||||
source-map-support "^0.5.17" | |||||
yn "3.1.1" | |||||
type-fest@^0.8.1: | |||||
version "0.8.1" | |||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" | |||||
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== | |||||
typedarray-to-buffer@^3.1.5: | |||||
version "3.1.5" | |||||
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" | |||||
integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== | |||||
dependencies: | |||||
is-typedarray "^1.0.0" | |||||
typescript@^4.2.4: | |||||
version "4.2.4" | |||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" | |||||
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== | |||||
undefsafe@^2.0.3: | |||||
version "2.0.3" | |||||
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" | |||||
integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== | |||||
dependencies: | |||||
debug "^2.2.0" | |||||
unique-string@^2.0.0: | |||||
version "2.0.0" | |||||
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" | |||||
integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== | |||||
dependencies: | |||||
crypto-random-string "^2.0.0" | |||||
update-notifier@^4.1.0: | |||||
version "4.1.3" | |||||
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" | |||||
integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== | |||||
dependencies: | |||||
boxen "^4.2.0" | |||||
chalk "^3.0.0" | |||||
configstore "^5.0.1" | |||||
has-yarn "^2.1.0" | |||||
import-lazy "^2.1.0" | |||||
is-ci "^2.0.0" | |||||
is-installed-globally "^0.3.1" | |||||
is-npm "^4.0.0" | |||||
is-yarn-global "^0.3.0" | |||||
latest-version "^5.0.0" | |||||
pupa "^2.0.1" | |||||
semver-diff "^3.1.1" | |||||
xdg-basedir "^4.0.0" | |||||
url-parse-lax@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" | |||||
integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= | |||||
dependencies: | |||||
prepend-http "^2.0.0" | |||||
widest-line@^3.1.0: | |||||
version "3.1.0" | |||||
resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" | |||||
integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== | |||||
dependencies: | |||||
string-width "^4.0.0" | |||||
wrappy@1: | |||||
version "1.0.2" | |||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" | |||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= | |||||
write-file-atomic@^3.0.0: | |||||
version "3.0.3" | |||||
resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" | |||||
integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== | |||||
dependencies: | |||||
imurmurhash "^0.1.4" | |||||
is-typedarray "^1.0.0" | |||||
signal-exit "^3.0.2" | |||||
typedarray-to-buffer "^3.1.5" | |||||
xdg-basedir@^4.0.0: | |||||
version "4.0.0" | |||||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" | |||||
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== | |||||
yn@3.1.1: | |||||
version "3.1.1" | |||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" | |||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== |