@ -0,0 +1,5 @@ | |||
DB_HOST = database | |||
DB_PORT = 3306 | |||
DB_USER = root | |||
DB_PASSWORD_FILE = /run/secrets/mysql_root_password | |||
DB_DATABASE = autoplex_torrent |
@ -0,0 +1,3 @@ | |||
# Autoplex Torrent Client | |||
The torrent client for Autoplex. |
@ -0,0 +1,6 @@ | |||
{ | |||
"watch": ["src"], | |||
"ext": "ts,json", | |||
"ignore": ["src/**/*.spec.ts"], | |||
"exec": "node --inspect=0.0.0.0:9229 -r ts-node/register src/index.ts" | |||
} |
@ -0,0 +1,7 @@ | |||
{ | |||
"cli": { | |||
"entitiesDir": "src/database/entities", | |||
"migrationsDir": "src/database/migrations", | |||
"subscribersDir": "src/database/subscribers" | |||
} | |||
} |
@ -0,0 +1,44 @@ | |||
{ | |||
"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-api/torrent": "^0.0.0", | |||
"@autoplex/ipc": "^0.0.0", | |||
"@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" | |||
} | |||
} |
@ -0,0 +1,26 @@ | |||
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) | |||
} | |||
@ -0,0 +1,29 @@ | |||
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 | |||
} |
@ -0,0 +1,73 @@ | |||
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(','); | |||
} | |||
} |
@ -0,0 +1,5 @@ | |||
import Torrent from "./Torrent"; | |||
export default [ | |||
Torrent | |||
]; |
@ -0,0 +1,18 @@ | |||
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"] | |||
}); | |||
} |
@ -0,0 +1,11 @@ | |||
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); |
@ -0,0 +1,36 @@ | |||
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(); | |||
} | |||
} |
@ -0,0 +1,114 @@ | |||
import assert from "assert"; | |||
import WebTorrent from "webtorrent-hybrid"; | |||
import TorrentClient from "./TorrentClient"; | |||
import { IpcServerService } from "@autoplex/ipc"; | |||
import { SOCKET_PATH } from "@autoplex-api/torrent"; | |||
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 = 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); | |||
} | |||
} |
@ -0,0 +1,298 @@ | |||
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; |
@ -0,0 +1,9 @@ | |||
import Database from "./Database"; | |||
import IpcInterface from "./IpcInterface"; | |||
import TorrentClient from "./TorrentClient"; | |||
export { | |||
Database, | |||
IpcInterface, | |||
TorrentClient | |||
} |
@ -0,0 +1,31 @@ | |||
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; | |||
} |
@ -0,0 +1,350 @@ | |||
/// <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; | |||
} | |||
@ -0,0 +1,38 @@ | |||
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; |
@ -0,0 +1,232 @@ | |||
// 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,71 @@ | |||
{ | |||
"compilerOptions": { | |||
/* Visit https://aka.ms/tsconfig.json to read more about this file */ | |||
/* Basic Options */ | |||
// "incremental": true, /* Enable incremental compilation */ | |||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ | |||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ | |||
// "lib": [], /* Specify library files to be included in the compilation. */ | |||
// "allowJs": true, /* Allow javascript files to be compiled. */ | |||
// "checkJs": true, /* Report errors in .js files. */ | |||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ | |||
// "declaration": true, /* Generates corresponding '.d.ts' file. */ | |||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ | |||
"sourceMap": true, /* Generates corresponding '.map' file. */ | |||
// "outFile": "./", /* Concatenate and emit output to single file. */ | |||
"outDir": "./dist", /* Redirect output structure to the directory. */ | |||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ | |||
// "composite": true, /* Enable project compilation */ | |||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ | |||
// "removeComments": true, /* Do not emit comments to output. */ | |||
// "noEmit": true, /* Do not emit outputs. */ | |||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ | |||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ | |||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ | |||
/* Strict Type-Checking Options */ | |||
"strict": true, /* Enable all strict type-checking options. */ | |||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ | |||
// "strictNullChecks": true, /* Enable strict null checks. */ | |||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ | |||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ | |||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ | |||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ | |||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ | |||
/* Additional Checks */ | |||
// "noUnusedLocals": true, /* Report errors on unused locals. */ | |||
// "noUnusedParameters": true, /* Report errors on unused parameters. */ | |||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ | |||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ | |||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ | |||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ | |||
/* Module Resolution Options */ | |||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ | |||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ | |||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ | |||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ | |||
"typeRoots": ["./src/typings"], /* List of folders to include type definitions from. */ | |||
// "types": [], /* Type declaration files to be included in compilation. */ | |||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ | |||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | |||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ | |||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ | |||
/* Source Map Options */ | |||
"sourceRoot": "./src", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ | |||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ | |||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ | |||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ | |||
/* Experimental Options */ | |||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ | |||
"emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ | |||
/* Advanced Options */ | |||
"skipLibCheck": true, /* Skip type checking of declaration files. */ | |||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ | |||
} | |||
} |