From dc2253e71862fbd557c2b6d29fa0db73b580be5f Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 26 Mar 2019 13:01:25 -0500 Subject: [PATCH] Refactor evaluations (#285) * Replace evaluations with proxies and messages * Return proxies synchronously Otherwise events can be lost. * Ensure events cannot be missed * Refactor remaining fills * Use more up-to-date version of util For callbackify. * Wait for dispose to come back before removing This prevents issues with the "done" event not always being the last event fired. For example a socket might close and then end, but only if the caller called end. * Remove old node-pty tests * Fix emitting events twice on duplex streams * Preserve environment when spawning processes * Throw a better error if the proxy doesn't exist * Remove rimraf dependency from ide * Update net.Server.listening * Use exit event instead of killed Doesn't look like killed is even a thing. * Add response timeout to server * Fix trash * Require node-pty & spdlog after they get unpackaged This fixes an error when running in the binary. * Fix errors in down emitter preventing reconnecting * Fix disposing proxies when nothing listens to "error" event * Refactor event tests to use jest.fn() * Reject proxy call when disconnected Otherwise it'll wait for the timeout which is a waste of time since we already know the connection is dead. * Use nbin for binary packaging * Remove additional module requires * Attempt to remove require for local bootstrap-fork * Externalize fsevents --- build/tasks.ts | 40 +- package.json | 2 + packages/events/src/events.ts | 84 +- packages/events/test/events.test.ts | 122 + packages/ide-api/api.d.ts | 28 +- packages/ide/package.json | 7 +- packages/ide/src/fill/child_process.ts | 195 +- packages/ide/src/fill/client.ts | 7 +- packages/ide/src/fill/electron.ts | 8 +- packages/ide/src/fill/fs.ts | 763 +---- packages/ide/src/fill/net.ts | 258 +- packages/ide/src/fill/trash.ts | 4 + packages/ide/yarn.lock | 110 - packages/package.json | 5 +- packages/protocol/package.json | 3 +- packages/protocol/src/browser/client.ts | 535 +++- .../src/browser/modules/child_process.ts | 126 + packages/protocol/src/browser/modules/fs.ts | 316 ++ .../protocol/src/browser/modules/index.ts | 6 + packages/protocol/src/browser/modules/net.ts | 280 ++ .../protocol/src/browser/modules/node-pty.ts | 45 + .../protocol/src/browser/modules/spdlog.ts | 32 + .../protocol/src/browser/modules/stream.ts | 233 ++ .../protocol/src/browser/modules/trash.ts | 10 + packages/protocol/src/common/connection.ts | 2 + packages/protocol/src/common/helpers.ts | 422 --- packages/protocol/src/common/proxy.ts | 83 + packages/protocol/src/common/util.ts | 348 +- packages/protocol/src/index.ts | 2 +- packages/protocol/src/node/evaluate.ts | 157 - .../src/node/modules/child_process.ts | 103 + packages/protocol/src/node/modules/fs.ts | 250 ++ packages/protocol/src/node/modules/index.ts | 6 + packages/protocol/src/node/modules/net.ts | 90 + .../protocol/src/node/modules/node-pty.ts | 75 + packages/protocol/src/node/modules/spdlog.ts | 46 + packages/protocol/src/node/modules/stream.ts | 107 + packages/protocol/src/node/modules/trash.ts | 7 + packages/protocol/src/node/server.ts | 333 +- packages/protocol/src/proto/client.proto | 18 +- packages/protocol/src/proto/client_pb.d.ts | 78 +- packages/protocol/src/proto/client_pb.js | 354 +-- packages/protocol/src/proto/node.proto | 86 +- packages/protocol/src/proto/node_pb.d.ts | 314 +- packages/protocol/src/proto/node_pb.js | 1929 +++++++++-- .../test/child_process.test.ts | 32 +- packages/protocol/test/evaluate.test.ts | 84 - packages/{ide => protocol}/test/forker.js | 0 packages/{ide => protocol}/test/fs.test.ts | 193 +- packages/protocol/test/helpers.ts | 59 +- packages/{ide => protocol}/test/net.test.ts | 58 +- .../test/node-pty.test.ts | 52 +- packages/protocol/test/spdlog.test.ts | 35 + packages/protocol/test/trash.test.ts | 26 + packages/protocol/yarn.lock | 39 +- packages/server/package.json | 4 +- packages/server/scripts/nbin.ts | 21 + packages/server/scripts/nexe.js | 31 - packages/server/src/cli.ts | 9 +- packages/server/src/fill.ts | 195 -- packages/server/src/server.ts | 27 +- packages/server/src/vscode/bootstrapFork.ts | 34 +- packages/server/webpack.config.js | 7 +- packages/server/yarn.lock | 2817 +---------------- packages/vscode/package.json | 1 - packages/vscode/src/dialog.ts | 49 +- packages/vscode/src/fill/node-pty.ts | 94 +- packages/vscode/src/fill/spdlog.ts | 63 +- packages/vscode/src/workbench.ts | 2 + packages/vscode/yarn.lock | 28 +- packages/web/webpack.config.js | 2 +- scripts/test-setup.js | 20 + scripts/vscode.patch | 23 +- tsconfig.json | 4 + yarn.lock | 9 +- 75 files changed, 5866 insertions(+), 6181 deletions(-) create mode 100644 packages/events/test/events.test.ts create mode 100644 packages/ide/src/fill/trash.ts create mode 100644 packages/protocol/src/browser/modules/child_process.ts create mode 100644 packages/protocol/src/browser/modules/fs.ts create mode 100644 packages/protocol/src/browser/modules/index.ts create mode 100644 packages/protocol/src/browser/modules/net.ts create mode 100644 packages/protocol/src/browser/modules/node-pty.ts create mode 100644 packages/protocol/src/browser/modules/spdlog.ts create mode 100644 packages/protocol/src/browser/modules/stream.ts create mode 100644 packages/protocol/src/browser/modules/trash.ts delete mode 100644 packages/protocol/src/common/helpers.ts create mode 100644 packages/protocol/src/common/proxy.ts delete mode 100644 packages/protocol/src/node/evaluate.ts create mode 100644 packages/protocol/src/node/modules/child_process.ts create mode 100644 packages/protocol/src/node/modules/fs.ts create mode 100644 packages/protocol/src/node/modules/index.ts create mode 100644 packages/protocol/src/node/modules/net.ts create mode 100644 packages/protocol/src/node/modules/node-pty.ts create mode 100644 packages/protocol/src/node/modules/spdlog.ts create mode 100644 packages/protocol/src/node/modules/stream.ts create mode 100644 packages/protocol/src/node/modules/trash.ts rename packages/{ide => protocol}/test/child_process.test.ts (72%) delete mode 100644 packages/protocol/test/evaluate.test.ts rename packages/{ide => protocol}/test/forker.js (100%) rename packages/{ide => protocol}/test/fs.test.ts (74%) rename packages/{ide => protocol}/test/net.test.ts (74%) rename packages/{vscode => protocol}/test/node-pty.test.ts (69%) create mode 100644 packages/protocol/test/spdlog.test.ts create mode 100644 packages/protocol/test/trash.test.ts create mode 100644 packages/server/scripts/nbin.ts delete mode 100644 packages/server/scripts/nexe.js delete mode 100644 packages/server/src/fill.ts diff --git a/build/tasks.ts b/build/tasks.ts index 4c10b1fb..f526d6b8 100644 --- a/build/tasks.ts +++ b/build/tasks.ts @@ -33,50 +33,12 @@ const buildServerBinaryPackage = register("build:server:binary:package", async ( throw new Error("Cannot build binary without server bundle built"); } await buildServerBinaryCopy(); - await dependencyNexeBinary(); - const resp = await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build:nexe"]); + const resp = await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build:binary"]); if (resp.exitCode !== 0) { throw new Error(`Failed to package binary: ${resp.stderr}`); } }); -const dependencyNexeBinary = register("dependency:nexe", async (runner) => { - if (os.platform() === "linux" && process.env.COMPRESS === "true") { - // Download the nexe binary so we can compress it before nexe runs. If we - // don't want compression we don't need to do anything since nexe will take - // care of getting the binary. - const nexeDir = path.join(os.homedir(), ".nexe"); - const targetBinaryName = `${os.platform()}-${os.arch()}-${process.version.substr(1)}`; - const targetBinaryPath = path.join(nexeDir, targetBinaryName); - if (!fs.existsSync(targetBinaryPath)) { - fse.mkdirpSync(nexeDir); - runner.cwd = nexeDir; - await runner.execute("wget", [`https://github.com/nexe/nexe/releases/download/v3.0.0-beta.15/${targetBinaryName}`]); - await runner.execute("chmod", ["+x", targetBinaryPath]); - } - // Compress with upx if it doesn't already look compressed. - if (fs.statSync(targetBinaryPath).size >= 20000000) { - // It needs to be executable for upx to work, which it might not be if - // nexe downloaded it. - fs.chmodSync(targetBinaryPath, "755"); - const upxFolder = path.join(os.tmpdir(), "upx"); - const upxBinary = path.join(upxFolder, "upx"); - if (!fs.existsSync(upxBinary)) { - fse.mkdirpSync(upxFolder); - runner.cwd = upxFolder; - const upxExtract = await runner.execute("bash", ["-c", "curl -L https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz | tar xJ --strip-components=1"]); - if (upxExtract.exitCode !== 0) { - throw new Error(`Failed to extract upx: ${upxExtract.stderr}`); - } - } - if (!fs.existsSync(upxBinary)) { - throw new Error("Not sure how, but the UPX binary does not exist"); - } - await runner.execute(upxBinary, [targetBinaryPath]); - } - } -}); - const buildServerBinaryCopy = register("build:server:binary:copy", async (runner) => { const cliPath = path.join(pkgsPath, "server"); const cliBuildPath = path.join(cliPath, "build"); diff --git a/package.json b/package.json index 4eca724e..0c3ba275 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,12 @@ "ts-loader": "^5.3.3", "ts-node": "^7.0.1", "tsconfig-paths": "^3.8.0", + "tslib": "^1.9.3", "tslint": "^5.12.1", "typescript": "^3.2.2", "typescript-tslint-plugin": "^0.2.1", "uglifyjs-webpack-plugin": "^2.1.1", + "util": "^0.11.1", "webpack": "^4.28.4", "webpack-bundle-analyzer": "^3.0.3", "webpack-cli": "^3.2.1", diff --git a/packages/events/src/events.ts b/packages/events/src/events.ts index c1ac796c..0befa8f6 100644 --- a/packages/events/src/events.ts +++ b/packages/events/src/events.ts @@ -1,28 +1,51 @@ import { IDisposable } from "@coder/disposable"; export interface Event { - (listener: (e: T) => void): IDisposable; + (listener: (value: T) => void): IDisposable; + (id: number | string, listener: (value: T) => void): IDisposable; } /** - * Emitter typecasts for a single event type. + * Emitter typecasts for a single event type. You can optionally use IDs, but + * using undefined with IDs will not work. If you emit without an ID, *all* + * listeners regardless of their ID (or lack thereof) will receive the event. + * Similarly, if you listen without an ID you will get *all* events for any or + * no ID. */ export class Emitter { - private listeners = void>>[]; + private listeners = void>>[]; + private readonly idListeners = new Map void>>(); public get event(): Event { - return (cb: (e: T) => void): IDisposable => { - if (this.listeners) { - this.listeners.push(cb); + return (id: number | string | ((value: T) => void), cb?: (value: T) => void): IDisposable => { + if (typeof id !== "function") { + if (this.idListeners.has(id)) { + this.idListeners.get(id)!.push(cb!); + } else { + this.idListeners.set(id, [cb!]); + } + + return { + dispose: (): void => { + if (this.idListeners.has(id)) { + const cbs = this.idListeners.get(id)!; + const i = cbs.indexOf(cb!); + if (i !== -1) { + cbs.splice(i, 1); + } + } + }, + }; } + cb = id; + this.listeners.push(cb); + return { dispose: (): void => { - if (this.listeners) { - const i = this.listeners.indexOf(cb); - if (i !== -1) { - this.listeners.splice(i, 1); - } + const i = this.listeners.indexOf(cb!); + if (i !== -1) { + this.listeners.splice(i, 1); } }, }; @@ -32,16 +55,45 @@ export class Emitter { /** * Emit an event with a value. */ - public emit(value: T): void { - if (this.listeners) { - this.listeners.forEach((t) => t(value)); + public emit(value: T): void; + public emit(id: number | string, value: T): void; + public emit(id: number | string | T, value?: T): void { + if ((typeof id === "number" || typeof id === "string") && typeof value !== "undefined") { + if (this.idListeners.has(id)) { + this.idListeners.get(id)!.forEach((cb) => cb(value!)); + } + this.listeners.forEach((cb) => cb(value!)); + } else { + this.idListeners.forEach((cbs) => cbs.forEach((cb) => cb((id as T)!))); + this.listeners.forEach((cb) => cb((id as T)!)); } } /** * Dispose the current events. */ - public dispose(): void { - this.listeners = []; + public dispose(): void; + public dispose(id: number | string): void; + public dispose(id?: number | string): void { + if (typeof id !== "undefined") { + this.idListeners.delete(id); + } else { + this.listeners = []; + this.idListeners.clear(); + } + } + + public get counts(): { [key: string]: number } { + const counts = <{ [key: string]: number }>{}; + if (this.listeners.length > 0) { + counts["n/a"] = this.listeners.length; + } + this.idListeners.forEach((cbs, id) => { + if (cbs.length > 0) { + counts[`${id}`] = cbs.length; + } + }); + + return counts; } } diff --git a/packages/events/test/events.test.ts b/packages/events/test/events.test.ts new file mode 100644 index 00000000..1c92327a --- /dev/null +++ b/packages/events/test/events.test.ts @@ -0,0 +1,122 @@ +import { Emitter } from "../src/events"; + +describe("Event", () => { + const emitter = new Emitter(); + + it("should listen to global event", () => { + const fn = jest.fn(); + const d = emitter.event(fn); + emitter.emit(10); + expect(fn).toHaveBeenCalledWith(10); + d.dispose(); + }); + + it("should listen to id event", () => { + const fn = jest.fn(); + const d = emitter.event(0, fn); + emitter.emit(0, 5); + expect(fn).toHaveBeenCalledWith(5); + d.dispose(); + }); + + it("should listen to string id event", () => { + const fn = jest.fn(); + const d = emitter.event("string", fn); + emitter.emit("string", 55); + expect(fn).toHaveBeenCalledWith(55); + d.dispose(); + }); + + it("should not listen wrong id event", () => { + const fn = jest.fn(); + const d = emitter.event(1, fn); + emitter.emit(0, 5); + emitter.emit(1, 6); + expect(fn).toHaveBeenCalledWith(6); + expect(fn).toHaveBeenCalledTimes(1); + d.dispose(); + }); + + it("should listen to id event globally", () => { + const fn = jest.fn(); + const d = emitter.event(fn); + emitter.emit(1, 11); + expect(fn).toHaveBeenCalledWith(11); + d.dispose(); + }); + + it("should listen to global event", () => { + const fn = jest.fn(); + const d = emitter.event(3, fn); + emitter.emit(14); + expect(fn).toHaveBeenCalledWith(14); + d.dispose(); + }); + + it("should listen to id event multiple times", () => { + const fn = jest.fn(); + const disposers = [ + emitter.event(934, fn), + emitter.event(934, fn), + emitter.event(934, fn), + emitter.event(934, fn), + ]; + emitter.emit(934, 324); + expect(fn).toHaveBeenCalledTimes(4); + expect(fn).toHaveBeenCalledWith(324); + disposers.forEach((d) => d.dispose()); + }); + + it("should dispose individually", () => { + const fn = jest.fn(); + const d = emitter.event(fn); + + const fn2 = jest.fn(); + const d2 = emitter.event(1, fn2); + + d.dispose(); + + emitter.emit(12); + emitter.emit(1, 12); + + expect(fn).not.toBeCalled(); + expect(fn2).toBeCalledTimes(2); + + d2.dispose(); + + emitter.emit(12); + emitter.emit(1, 12); + + expect(fn).not.toBeCalled(); + expect(fn2).toBeCalledTimes(2); + }); + + it("should dispose by id", () => { + const fn = jest.fn(); + emitter.event(fn); + + const fn2 = jest.fn(); + emitter.event(1, fn2); + + emitter.dispose(1); + + emitter.emit(12); + emitter.emit(1, 12); + + expect(fn).toBeCalledTimes(2); + expect(fn2).not.toBeCalled(); + }); + + it("should dispose all", () => { + const fn = jest.fn(); + emitter.event(fn); + emitter.event(1, fn); + + emitter.dispose(); + + emitter.emit(12); + emitter.emit(1, 12); + + expect(fn).not.toBeCalled(); + }); +}); diff --git a/packages/ide-api/api.d.ts b/packages/ide-api/api.d.ts index 3faeafc8..0a7b64fe 100644 --- a/packages/ide-api/api.d.ts +++ b/packages/ide-api/api.d.ts @@ -1,3 +1,5 @@ +// tslint:disable no-any + export interface EvalHelper { } interface ActiveEvalEmitter { removeAllListeners(event?: string): void; @@ -106,7 +108,7 @@ interface IMenuItem { command: ICommandAction; alt?: ICommandAction; // when?: ContextKeyExpr; - group?: 'navigation' | string; + group?: "navigation" | string; order?: number; } @@ -135,23 +137,7 @@ interface ICommandRegistry { } declare namespace ide { - export const client: { - run(func: (helper: ActiveEvalEmitter) => Disposer): ActiveEvalEmitter; - run(func: (helper: ActiveEvalEmitter, a1: T1) => Disposer, a1: T1): ActiveEvalEmitter; - run(func: (helper: ActiveEvalEmitter, a1: T1, a2: T2) => Disposer, a1: T1, a2: T2): ActiveEvalEmitter; - run(func: (helper: ActiveEvalEmitter, a1: T1, a2: T2, a3: T3) => Disposer, a1: T1, a2: T2, a3: T3): ActiveEvalEmitter; - run(func: (helper: ActiveEvalEmitter, a1: T1, a2: T2, a3: T3, a4: T4) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4): ActiveEvalEmitter; - run(func: (helper: ActiveEvalEmitter, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): ActiveEvalEmitter; - run(func: (helper: ActiveEvalEmitter, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): ActiveEvalEmitter; - - evaluate(func: (helper: EvalHelper) => R | Promise): Promise; - evaluate(func: (helper: EvalHelper, a1: T1) => R | Promise, a1: T1): Promise; - evaluate(func: (helper: EvalHelper, a1: T1, a2: T2) => R | Promise, a1: T1, a2: T2): Promise; - evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3) => R | Promise, a1: T1, a2: T2, a3: T3): Promise; - evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4) => R | Promise, a1: T1, a2: T2, a3: T3, a4: T4): Promise; - evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => R | Promise, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): Promise; - evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => R | Promise, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): Promise; - }; + export const client: {}; export const workbench: { readonly statusbarService: IStatusbarService; @@ -177,8 +163,8 @@ declare namespace ide { Ignore = 0, Info = 1, Warning = 2, - Error = 3 - } + Error = 3, + } export enum StatusbarAlignment { LEFT = 0, @@ -229,7 +215,7 @@ declare namespace ide { declare global { interface Window { ide?: typeof ide; - + addEventListener(event: "ide-ready", callback: (ide: CustomEvent & { readonly ide: typeof ide }) => void): void; } } diff --git a/packages/ide/package.json b/packages/ide/package.json index f229782c..ac53ecb0 100644 --- a/packages/ide/package.json +++ b/packages/ide/package.json @@ -1,10 +1,5 @@ { "name": "@coder/ide", "description": "Browser-based IDE client abstraction.", - "main": "src/index.ts", - "dependencies": {}, - "devDependencies": { - "@types/rimraf": "^2.0.2", - "rimraf": "^2.6.3" - } + "main": "src/index.ts" } diff --git a/packages/ide/src/fill/child_process.ts b/packages/ide/src/fill/child_process.ts index 92a2a7e0..afcfe7a0 100644 --- a/packages/ide/src/fill/child_process.ts +++ b/packages/ide/src/fill/child_process.ts @@ -1,195 +1,4 @@ -import * as cp from "child_process"; -import * as net from "net"; -import * as stream from "stream"; -import { CallbackEmitter, ActiveEvalReadable, ActiveEvalWritable } from "@coder/protocol"; +import { Module } from "@coder/protocol"; import { client } from "./client"; -import { promisify } from "util"; -declare var __non_webpack_require__: typeof require; - -class ChildProcess extends CallbackEmitter implements cp.ChildProcess { - private _connected: boolean = false; - private _killed: boolean = false; - private _pid = -1; - public readonly stdin: stream.Writable; - public readonly stdout: stream.Readable; - public readonly stderr: stream.Readable; - // We need the explicit type otherwise TypeScript thinks it is (Writable | Readable)[]. - public readonly stdio: [stream.Writable, stream.Readable, stream.Readable] = [this.stdin, this.stdout, this.stderr]; - - // tslint:disable no-any - public constructor(method: "exec", command: string, options?: { encoding?: string | null } & cp.ExecOptions | null, callback?: (...args: any[]) => void); - public constructor(method: "fork", modulePath: string, options?: cp.ForkOptions, args?: string[]); - public constructor(method: "spawn", command: string, options?: cp.SpawnOptions, args?: string[]); - public constructor(method: "exec" | "spawn" | "fork", command: string, options: object = {}, callback?: string[] | ((...args: any[]) => void)) { - // tslint:enable no-any - super(); - - let args: string[] = []; - if (Array.isArray(callback)) { - args = callback; - callback = undefined; - } - - this.ae = client.run((ae, command, method, args, options, callbackId) => { - const cp = __non_webpack_require__("child_process") as typeof import("child_process"); - - ae.preserveEnv(options); - - let childProcess: cp.ChildProcess; - switch (method) { - case "exec": - childProcess = cp.exec(command, options, ae.maybeCallback(callbackId)); - break; - case "spawn": - childProcess = cp.spawn(command, args, options); - break; - case "fork": - childProcess = ae.fork(command, args, options); - break; - default: - throw new Error(`invalid method ${method}`); - } - - ae.on("disconnect", () => childProcess.disconnect()); - ae.on("kill", (signal: string) => childProcess.kill(signal)); - ae.on("ref", () => childProcess.ref()); - ae.on("send", (message: string, callbackId: number) => childProcess.send(message, ae.maybeCallback(callbackId))); - ae.on("unref", () => childProcess.unref()); - - ae.emit("pid", childProcess.pid); - childProcess.on("close", (code, signal) => ae.emit("close", code, signal)); - childProcess.on("disconnect", () => ae.emit("disconnect")); - childProcess.on("error", (error) => ae.emit("error", error)); - childProcess.on("exit", (code, signal) => ae.emit("exit", code, signal)); - childProcess.on("message", (message) => ae.emit("message", message)); - - if (childProcess.stdin) { - const stdinAe = ae.createUnique("stdin"); - stdinAe.bindWritable(childProcess.stdin); - } - if (childProcess.stdout) { - const stdoutAe = ae.createUnique("stdout"); - stdoutAe.bindReadable(childProcess.stdout); - } - if (childProcess.stderr) { - const stderrAe = ae.createUnique("stderr"); - stderrAe.bindReadable(childProcess.stderr); - } - - return { - onDidDispose: (cb): cp.ChildProcess => childProcess.on("close", cb), - dispose: (): void => { - childProcess.kill(); - setTimeout(() => childProcess.kill("SIGKILL"), 5000); // Double tap. - }, - }; - }, command, method, args, options, this.storeCallback(callback)); - - this.ae.on("pid", (pid) => { - this._pid = pid; - this._connected = true; - }); - - this.stdin = new ActiveEvalWritable(this.ae.createUnique("stdin")); - this.stdout = new ActiveEvalReadable(this.ae.createUnique("stdout")); - this.stderr = new ActiveEvalReadable(this.ae.createUnique("stderr")); - - this.ae.on("close", (code, signal) => this.emit("close", code, signal)); - this.ae.on("disconnect", () => this.emit("disconnect")); - this.ae.on("error", (error) => this.emit("error", error)); - this.ae.on("exit", (code, signal) => { - this._connected = false; - this._killed = true; - this.emit("exit", code, signal); - }); - this.ae.on("message", (message) => this.emit("message", message)); - } - - public get pid(): number { return this._pid; } - public get connected(): boolean { return this._connected; } - public get killed(): boolean { return this._killed; } - - public kill(): void { this.ae.emit("kill"); } - public disconnect(): void { this.ae.emit("disconnect"); } - public ref(): void { this.ae.emit("ref"); } - public unref(): void { this.ae.emit("unref"); } - - public send( - message: any, // tslint:disable-line no-any to match spec - sendHandle?: net.Socket | net.Server | ((error: Error) => void), - options?: cp.MessageOptions | ((error: Error) => void), - callback?: (error: Error) => void): boolean { - if (typeof sendHandle === "function") { - callback = sendHandle; - sendHandle = undefined; - } else if (typeof options === "function") { - callback = options; - options = undefined; - } - if (sendHandle || options) { - throw new Error("sendHandle and options are not supported"); - } - this.ae.emit("send", message, this.storeCallback(callback)); - - // Unfortunately this will always have to be true since we can't retrieve - // the actual response synchronously. - return true; - } -} - -class CP { - public readonly ChildProcess = ChildProcess; - - public exec = ( - command: string, - options?: { encoding?: string | null } & cp.ExecOptions | null | ((error: cp.ExecException | null, stdout: string, stderr: string) => void) | ((error: cp.ExecException | null, stdout: Buffer, stderr: Buffer) => void), - callback?: ((error: cp.ExecException | null, stdout: string, stderr: string) => void) | ((error: cp.ExecException | null, stdout: Buffer, stderr: Buffer) => void), - ): cp.ChildProcess => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - - return new ChildProcess("exec", command, options, callback); - } - - public fork = (modulePath: string, args?: string[] | cp.ForkOptions, options?: cp.ForkOptions): cp.ChildProcess => { - if (args && !Array.isArray(args)) { - options = args; - args = undefined; - } - - return new ChildProcess("fork", modulePath, options, args); - } - - public spawn = (command: string, args?: string[] | cp.SpawnOptions, options?: cp.SpawnOptions): cp.ChildProcess => { - if (args && !Array.isArray(args)) { - options = args; - args = undefined; - } - - return new ChildProcess("spawn", command, options, args); - } -} - -const fillCp = new CP(); -// Methods that don't follow the standard callback pattern (an error followed -// by a single result) need to provide a custom promisify function. -Object.defineProperty(fillCp.exec, promisify.custom, { - value: ( - command: string, - options?: { encoding?: string | null } & cp.ExecOptions | null, - ): Promise<{ stdout: string | Buffer, stderr: string | Buffer }> => { - return new Promise((resolve, reject): void => { - fillCp.exec(command, options, (error: cp.ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => { - if (error) { - reject(error); - } else { - resolve({ stdout, stderr }); - } - }); - }); - }, -}); -export = fillCp; +export = client.modules[Module.ChildProcess]; diff --git a/packages/ide/src/fill/client.ts b/packages/ide/src/fill/client.ts index 18fc8322..acace202 100644 --- a/packages/ide/src/fill/client.ts +++ b/packages/ide/src/fill/client.ts @@ -61,7 +61,12 @@ class WebsocketConnection implements ReadWriteConnection { socket.addEventListener("close", (event) => { if (this.isUp) { this.isUp = false; - this.downEmitter.emit(undefined); + try { + this.downEmitter.emit(undefined); + } catch (error) { + // Don't let errors here prevent restarting. + logger.error(error.message); + } } logger.warn( "Web socket closed", diff --git a/packages/ide/src/fill/electron.ts b/packages/ide/src/fill/electron.ts index 65e70546..af2b7928 100644 --- a/packages/ide/src/fill/electron.ts +++ b/packages/ide/src/fill/electron.ts @@ -1,12 +1,10 @@ /// import { EventEmitter } from "events"; import * as fs from "fs"; +import * as trash from "trash"; import { logger, field } from "@coder/logger"; import { IKey, Dialog as DialogBox } from "./dialog"; import { clipboard } from "./clipboard"; -import { client } from "./client"; - -declare var __non_webpack_require__: typeof require; // tslint:disable-next-line no-any (global as any).getOpenUrls = (): string[] => { @@ -184,9 +182,7 @@ class Clipboard { class Shell { public async moveItemToTrash(path: string): Promise { - await client.evaluate((helper, path) => { - return helper.modules.trash(path); - }, path); + await trash(path); } } diff --git a/packages/ide/src/fill/fs.ts b/packages/ide/src/fill/fs.ts index 07f2788c..93097963 100644 --- a/packages/ide/src/fill/fs.ts +++ b/packages/ide/src/fill/fs.ts @@ -1,763 +1,4 @@ -import { EventEmitter } from "events"; -import * as fs from "fs"; -import * as stream from "stream"; -import { Client, IEncodingOptions, IEncodingOptionsCallback } from "@coder/protocol"; +import { Module } from "@coder/protocol"; import { client } from "./client"; -import { promisify } from "util"; -declare var __non_webpack_require__: typeof require; -declare var _Buffer: typeof Buffer; - -/** - * Implements the native fs module - * Doesn't use `implements typeof import("fs")` to remove need for __promisify__ impls - * - * TODO: For now we can't use async in the evaluate calls because they get - * transpiled to TypeScript's helpers. tslib is included but we also need to set - * _this somehow which the __awaiter helper uses. - */ -class FS { - public constructor( - private readonly client: Client, - ) { } - - public access = (path: fs.PathLike, mode: number | undefined | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof mode === "function") { - callback = mode; - mode = undefined; - } - this.client.evaluate((_helper, path, mode) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.access)(path, mode); - }, path, mode).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - // tslint:disable-next-line no-any - public appendFile = (file: fs.PathLike | number, data: any, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - this.client.evaluate((_helper, path, data, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.appendFile)(path, data, options); - }, file, data, options).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - public chmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, path, mode) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.chmod)(path, mode); - }, path, mode).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public chown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, path, uid, gid) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.chown)(path, uid, gid); - }, path, uid, gid).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public close = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, fd) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.close)(fd); - }, fd).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public copyFile = (src: fs.PathLike, dest: fs.PathLike, flags: number | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof flags === "function") { - callback = flags; - } - this.client.evaluate((_helper, src, dest, flags) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.copyFile)(src, dest, flags); - }, src, dest, typeof flags !== "function" ? flags : undefined).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - // tslint:disable-next-line no-any - public createWriteStream = (path: fs.PathLike, options?: any): fs.WriteStream => { - const ae = this.client.run((ae, path, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const str = fs.createWriteStream(path, options); - ae.on("write", (d: string) => str.write(_Buffer.from(d, "utf8"))); - ae.on("close", () => str.close()); - ae.on("destroy", () => str.destroy()); - str.on("close", () => ae.emit("close")); - str.on("open", (fd) => ae.emit("open", fd)); - str.on("error", (err) => ae.emit(err)); - - return { - onDidDispose: (cb): fs.WriteStream => str.on("close", cb), - dispose: (): void => str.close(), - }; - }, path, options); - - return new (class WriteStream extends stream.Writable implements fs.WriteStream { - - private _bytesWritten: number = 0; - - public constructor() { - super({ - write: (data, encoding, cb): void => { - this._bytesWritten += data.length; - ae.emit("write", Buffer.from(data, encoding), encoding); - cb(); - }, - }); - - ae.on("open", (fd: number) => this.emit("open", fd)); - ae.on("close", () => this.emit("close")); - } - - public get bytesWritten(): number { - return this._bytesWritten; - } - - public get path(): string | Buffer { - return ""; - } - - public close(): void { - ae.emit("close"); - } - - public destroy(): void { - ae.emit("destroy"); - } - - }) as fs.WriteStream; - } - - public exists = (path: fs.PathLike, callback: (exists: boolean) => void): void => { - this.client.evaluate((_helper, path) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.exists)(path); - }, path).then((r) => { - callback(r); - }).catch(() => { - callback(false); - }); - } - - public fchmod = (fd: number, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, fd, mode) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.fchmod)(fd, mode); - }, fd, mode).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public fchown = (fd: number, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, fd, uid, gid) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.fchown)(fd, uid, gid); - }, fd, uid, gid).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public fdatasync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, fd) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.fdatasync)(fd); - }, fd).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public fstat = (fd: number, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => { - this.client.evaluate((_helper, fd) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - const tslib = __non_webpack_require__("tslib") as typeof import("tslib"); - - return util.promisify(fs.fstat)(fd).then((stats) => { - return tslib.__assign(stats, { - _isBlockDevice: stats.isBlockDevice ? stats.isBlockDevice() : false, - _isCharacterDevice: stats.isCharacterDevice ? stats.isCharacterDevice() : false, - _isDirectory: stats.isDirectory(), - _isFIFO: stats.isFIFO ? stats.isFIFO() : false, - _isFile: stats.isFile(), - _isSocket: stats.isSocket ? stats.isSocket() : false, - _isSymbolicLink: stats.isSymbolicLink ? stats.isSymbolicLink() : false, - }); - }); - }, fd).then((stats) => { - callback(undefined!, new Stats(stats)); - }).catch((ex) => { - callback(ex, undefined!); - }); - } - - public fsync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, fd) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.fsync)(fd); - }, fd).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public ftruncate = (fd: number, len: number | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof len === "function") { - callback = len; - len = undefined; - } - this.client.evaluate((_helper, fd, len) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.ftruncate)(fd, len); - }, fd, len).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - public futimes = (fd: number, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, fd, atime, mtime) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.futimes)(fd, atime, mtime); - }, fd, atime, mtime).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public lchmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, path, mode) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.lchmod)(path, mode); - }, path, mode).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public lchown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, path, uid, gid) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.lchown)(path, uid, gid); - }, path, uid, gid).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public link = (existingPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, existingPath, newPath) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.link)(existingPath, newPath); - }, existingPath, newPath).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public lstat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => { - this.client.evaluate((_helper, path) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - const tslib = __non_webpack_require__("tslib") as typeof import("tslib"); - - return util.promisify(fs.lstat)(path).then((stats) => { - return tslib.__assign(stats, { - _isBlockDevice: stats.isBlockDevice ? stats.isBlockDevice() : false, - _isCharacterDevice: stats.isCharacterDevice ? stats.isCharacterDevice() : false, - _isDirectory: stats.isDirectory(), - _isFIFO: stats.isFIFO ? stats.isFIFO() : false, - _isFile: stats.isFile(), - _isSocket: stats.isSocket ? stats.isSocket() : false, - _isSymbolicLink: stats.isSymbolicLink ? stats.isSymbolicLink() : false, - }); - }); - }, path).then((stats) => { - callback(undefined!, new Stats(stats)); - }).catch((ex) => { - callback(ex, undefined!); - }); - } - - public mkdir = (path: fs.PathLike, mode: number | string | fs.MakeDirectoryOptions | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof mode === "function") { - callback = mode; - mode = undefined; - } - this.client.evaluate((_helper, path, mode) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.mkdir)(path, mode); - }, path, mode).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - public mkdtemp = (prefix: string, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, folder: string | Buffer) => void): void => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - this.client.evaluate((_helper, prefix, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.mkdtemp)(prefix, options); - }, prefix, options).then((folder) => { - callback!(undefined!, folder); - }).catch((ex) => { - callback!(ex, undefined!); - }); - } - - public open = (path: fs.PathLike, flags: string | number, mode: string | number | undefined | null | ((err: NodeJS.ErrnoException, fd: number) => void), callback?: (err: NodeJS.ErrnoException, fd: number) => void): void => { - if (typeof mode === "function") { - callback = mode; - mode = undefined; - } - this.client.evaluate((_helper, path, flags, mode) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.open)(path, flags, mode); - }, path, flags, mode).then((fd) => { - callback!(undefined!, fd); - }).catch((ex) => { - callback!(ex, undefined!); - }); - } - - public read = (fd: number, buffer: TBuffer, offset: number, length: number, position: number | null, callback: (err: NodeJS.ErrnoException, bytesRead: number, buffer: TBuffer) => void): void => { - this.client.evaluate((_helper, fd, length, position) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - const buffer = new _Buffer(length); - - return util.promisify(fs.read)(fd, buffer, 0, length, position).then((resp) => { - return { - bytesRead: resp.bytesRead, - content: resp.bytesRead < buffer.length ? buffer.slice(0, resp.bytesRead) : buffer, - }; - }); - }, fd, length, position).then((resp) => { - buffer.set(resp.content, offset); - callback(undefined!, resp.bytesRead, resp.content as TBuffer); - }).catch((ex) => { - callback(ex, undefined!, undefined!); - }); - } - - public readFile = (path: fs.PathLike | number, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, data: string | Buffer) => void): void => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - this.client.evaluate((_helper, path, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.readFile)(path, options).then((value) => value.toString()); - }, path, options).then((buffer) => { - callback!(undefined!, buffer); - }).catch((ex) => { - callback!(ex, undefined!); - }); - } - - public readdir = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, files: Buffer[] | fs.Dirent[] | string[]) => void): void => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - // TODO: options can also take `withFileTypes` but the types aren't working. - this.client.evaluate((_helper, path, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.readdir)(path, options); - }, path, options).then((files) => { - callback!(undefined!, files); - }).catch((ex) => { - callback!(ex, undefined!); - }); - } - - public readlink = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, linkString: string | Buffer) => void): void => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - this.client.evaluate((_helper, path, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.readlink)(path, options); - }, path, options).then((linkString) => { - callback!(undefined!, linkString); - }).catch((ex) => { - callback!(ex, undefined!); - }); - } - - public realpath = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, resolvedPath: string | Buffer) => void): void => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - this.client.evaluate((_helper, path, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.realpath)(path, options); - }, path, options).then((resolvedPath) => { - callback!(undefined!, resolvedPath); - }).catch((ex) => { - callback!(ex, undefined!); - }); - } - - public rename = (oldPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, oldPath, newPath) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.rename)(oldPath, newPath); - }, oldPath, newPath).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public rmdir = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, path) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.rmdir)(path); - }, path).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public stat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => { - this.client.evaluate((_helper, path) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - const tslib = __non_webpack_require__("tslib") as typeof import("tslib"); - - return util.promisify(fs.stat)(path).then((stats) => { - return tslib.__assign(stats, { - /** - * We need to check if functions exist because nexe's implemented FS - * lib doesnt implement fs.stats properly - */ - _isBlockDevice: stats.isBlockDevice ? stats.isBlockDevice() : false, - _isCharacterDevice: stats.isCharacterDevice ? stats.isCharacterDevice() : false, - _isDirectory: stats.isDirectory(), - _isFIFO: stats.isFIFO ? stats.isFIFO() : false, - _isFile: stats.isFile(), - _isSocket: stats.isSocket ? stats.isSocket() : false, - _isSymbolicLink: stats.isSymbolicLink ? stats.isSymbolicLink() : false, - }); - }); - }, path).then((stats) => { - callback(undefined!, new Stats(stats)); - }).catch((ex) => { - callback(ex, undefined!); - }); - } - - public symlink = (target: fs.PathLike, path: fs.PathLike, type: fs.symlink.Type | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof type === "function") { - callback = type; - type = undefined; - } - this.client.evaluate((_helper, target, path, type) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.symlink)(target, path, type); - }, target, path, type).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - public truncate = (path: fs.PathLike, len: number | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof len === "function") { - callback = len; - len = undefined; - } - this.client.evaluate((_helper, path, len) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.truncate)(path, len); - }, path, len).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - public unlink = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, path) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.unlink)(path); - }, path).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public utimes = (path: fs.PathLike, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => { - this.client.evaluate((_helper, path, atime, mtime) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.utimes)(path, atime, mtime); - }, path, atime, mtime).then(() => { - callback(undefined!); - }).catch((ex) => { - callback(ex); - }); - } - - public write = (fd: number, buffer: TBuffer, offset: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: TBuffer) => void), length: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: TBuffer) => void), position: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: TBuffer) => void), callback?: (err: NodeJS.ErrnoException, written: number, buffer: TBuffer) => void): void => { - if (typeof offset === "function") { - callback = offset; - offset = undefined; - } - if (typeof length === "function") { - callback = length; - length = undefined; - } - if (typeof position === "function") { - callback = position; - position = undefined; - } - this.client.evaluate((_helper, fd, buffer, offset, length, position) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.write)(fd, _Buffer.from(buffer, "utf8"), offset, length, position).then((resp) => { - return { - bytesWritten: resp.bytesWritten, - content: resp.buffer.toString("utf8"), - }; - }); - }, fd, buffer.toString(), offset, length, position).then((r) => { - callback!(undefined!, r.bytesWritten, Buffer.from(r.content, "utf8") as TBuffer); - }).catch((ex) => { - callback!(ex, undefined!, undefined!); - }); - } - - // tslint:disable-next-line no-any - public writeFile = (path: fs.PathLike | number, data: any, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException) => void): void => { - if (typeof options === "function") { - callback = options; - options = undefined; - } - this.client.evaluate((_helper, path, data, options) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - - return util.promisify(fs.writeFile)(path, data, options); - }, path, data, options).then(() => { - callback!(undefined!); - }).catch((ex) => { - callback!(ex); - }); - } - - public watch = (filename: fs.PathLike, options?: IEncodingOptions | ((event: string, filename: string | Buffer) => void), listener?: ((event: string, filename: string | Buffer) => void)): fs.FSWatcher => { - if (typeof options === "function") { - listener = options; - options = undefined; - } - - const ae = this.client.run((ae, filename, hasListener, options) => { - const fs = __non_webpack_require__("fs") as typeof import ("fs"); - // tslint:disable-next-line no-any - const watcher = fs.watch(filename, options as any, hasListener ? (event, filename): void => { - ae.emit("listener", event, filename); - } : undefined); - watcher.on("change", (event, filename) => ae.emit("change", event, filename)); - watcher.on("error", (error) => ae.emit("error", error)); - ae.on("close", () => watcher.close()); - - return { - onDidDispose: (cb): void => ae.on("close", cb), - dispose: (): void => watcher.close(), - }; - }, filename.toString(), !!listener, options); - - return new class Watcher extends EventEmitter implements fs.FSWatcher { - public constructor() { - super(); - ae.on("change", (event: string, filename: string) => this.emit("change", event, filename)); - ae.on("error", (error: Error) => this.emit("error", error)); - ae.on("listener", (event: string, filename: string) => listener && listener(event, filename)); - } - - public close(): void { - ae.emit("close"); - } - }; - } -} - -interface IStats { - dev: number; - ino: number; - mode: number; - nlink: number; - uid: number; - gid: number; - rdev: number; - size: number; - blksize: number; - blocks: number; - atimeMs: number; - mtimeMs: number; - ctimeMs: number; - birthtimeMs: number; - atime: Date | string; - mtime: Date | string; - ctime: Date | string; - birthtime: Date | string; - _isFile: boolean; - _isDirectory: boolean; - _isBlockDevice: boolean; - _isCharacterDevice: boolean; - _isSymbolicLink: boolean; - _isFIFO: boolean; - _isSocket: boolean; -} - -class Stats implements fs.Stats { - public readonly atime: Date; - public readonly mtime: Date; - public readonly ctime: Date; - public readonly birthtime: Date; - - public constructor(private readonly stats: IStats) { - this.atime = new Date(stats.atime); - this.mtime = new Date(stats.mtime); - this.ctime = new Date(stats.ctime); - this.birthtime = new Date(stats.birthtime); - } - - public get dev(): number { return this.stats.dev; } - public get ino(): number { return this.stats.ino; } - public get mode(): number { return this.stats.mode; } - public get nlink(): number { return this.stats.nlink; } - public get uid(): number { return this.stats.uid; } - public get gid(): number { return this.stats.gid; } - public get rdev(): number { return this.stats.rdev; } - public get size(): number { return this.stats.size; } - public get blksize(): number { return this.stats.blksize; } - public get blocks(): number { return this.stats.blocks; } - public get atimeMs(): number { return this.stats.atimeMs; } - public get mtimeMs(): number { return this.stats.mtimeMs; } - public get ctimeMs(): number { return this.stats.ctimeMs; } - public get birthtimeMs(): number { return this.stats.birthtimeMs; } - public isFile(): boolean { return this.stats._isFile; } - public isDirectory(): boolean { return this.stats._isDirectory; } - public isBlockDevice(): boolean { return this.stats._isBlockDevice; } - public isCharacterDevice(): boolean { return this.stats._isCharacterDevice; } - public isSymbolicLink(): boolean { return this.stats._isSymbolicLink; } - public isFIFO(): boolean { return this.stats._isFIFO; } - public isSocket(): boolean { return this.stats._isSocket; } - - public toObject(): object { - return JSON.parse(JSON.stringify(this)); - } -} - -const fillFs = new FS(client); -// Methods that don't follow the standard callback pattern (an error followed -// by a single result) need to provide a custom promisify function. -Object.defineProperty(fillFs.exists, promisify.custom, { - value: (path: fs.PathLike): Promise => new Promise((resolve): void => fillFs.exists(path, resolve)), -}); -export = fillFs; +export = client.modules[Module.Fs]; diff --git a/packages/ide/src/fill/net.ts b/packages/ide/src/fill/net.ts index cd44deef..4eb9a4b0 100644 --- a/packages/ide/src/fill/net.ts +++ b/packages/ide/src/fill/net.ts @@ -1,258 +1,4 @@ -import * as net from "net"; -import { CallbackEmitter, ActiveEvalDuplex, ActiveEvalHelper } from "@coder/protocol"; +import { Module } from "@coder/protocol"; import { client } from "./client"; -declare var __non_webpack_require__: typeof require; - -class Socket extends ActiveEvalDuplex implements net.Socket { - private _connecting: boolean = false; - private _destroyed: boolean = false; - - public constructor(options?: net.SocketConstructorOpts, ae?: ActiveEvalHelper) { - super(ae || client.run((ae, options) => { - const net = __non_webpack_require__("net") as typeof import("net"); - - return ae.bindSocket(new net.Socket(options)); - }, options)); - - this.ae.on("connect", () => { - this._connecting = false; - this.emit("connect"); - }); - this.ae.on("error", () => { - this._connecting = false; - this._destroyed = true; - }); - this.ae.on("lookup", (error, address, family, host) => this.emit("lookup", error, address, family, host)); - this.ae.on("timeout", () => this.emit("timeout")); - } - - public connect(options: net.SocketConnectOpts | number | string, host?: string | Function, connectionListener?: Function): this { - // This is to get around type issues with socket.connect as well as extract - // the function wherever it might be. - switch (typeof options) { - case "string": options = { path: options }; break; - case "number": options = { port: options }; break; - } - switch (typeof host) { - case "function": connectionListener = host; break; - case "string": (options as net.TcpSocketConnectOpts).host = host; break; - } - - this._connecting = true; - this.ae.emit("connect", options, this.storeCallback(connectionListener)); - - return this; - } - - // tslint:disable-next-line no-any - public write(data: any, encoding?: string | Function, fd?: string | Function): boolean { - let callback: Function | undefined; - if (typeof encoding === "function") { - callback = encoding; - encoding = undefined; - } - if (typeof fd === "function") { - callback = fd; - fd = undefined; - } - this.ae.emit("write", data, encoding, fd, this.storeCallback(callback)); - - return true; // Always true since we can't get this synchronously. - } - - public get connecting(): boolean { return this._connecting; } - public get destroyed(): boolean { return this._destroyed; } - - public get bufferSize(): number { throw new Error("not implemented"); } - public get bytesRead(): number { throw new Error("not implemented"); } - public get bytesWritten(): number { throw new Error("not implemented"); } - public get localAddress(): string { throw new Error("not implemented"); } - public get localPort(): number { throw new Error("not implemented"); } - public address(): net.AddressInfo | string { throw new Error("not implemented"); } - - public setTimeout(timeout: number, callback?: Function): this { return this.emitReturnThis("setTimeout", timeout, this.storeCallback(callback)); } - public setNoDelay(noDelay?: boolean): this { return this.emitReturnThis("setNoDelay", noDelay); } - public setKeepAlive(enable?: boolean, initialDelay?: number): this { return this.emitReturnThis("setKeepAlive", enable, initialDelay); } - public unref(): void { this.ae.emit("unref"); } - public ref(): void { this.ae.emit("ref"); } -} - -class Server extends CallbackEmitter implements net.Server { - private readonly sockets = new Map(); - private _listening: boolean = false; - - public constructor(options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean } | ((socket: Socket) => void), connectionListener?: (socket: Socket) => void) { - super(); - - if (typeof options === "function") { - connectionListener = options; - options = undefined; - } - - this.ae = client.run((ae, options, callbackId) => { - const net = __non_webpack_require__("net") as typeof import("net"); - - let connectionId = 0; - const sockets = new Map(); - const storeSocket = (socket: net.Socket): number => { - const socketId = connectionId++; - sockets.set(socketId, socket); - const socketAe = ae.createUnique(socketId); - const disposer = socketAe.bindSocket(socket); - socket.on("close", () => { - disposer.dispose(); - sockets.delete(socketId); - }); - - return socketId; - }; - - const callback = ae.maybeCallback(callbackId); - let server = new net.Server(options, typeof callback !== "undefined" ? (socket): void => { - callback(storeSocket(socket)); - } : undefined); - - server.on("close", () => ae.emit("close")); - server.on("connection", (socket) => ae.emit("connection", storeSocket(socket))); - server.on("error", (error) => ae.emit("error", error)); - server.on("listening", () => ae.emit("listening")); - - ae.on("close", (callbackId: number) => server.close(ae.maybeCallback(callbackId))); - ae.on("listen", (handle?: net.ListenOptions | number | string) => server.listen(handle)); - ae.on("ref", () => server.ref()); - ae.on("unref", () => server.unref()); - - return { - onDidDispose: (cb): net.Server => server.on("close", cb), - dispose: (): void => { - server.removeAllListeners(); - server.close(); - sockets.forEach((socket) => { - socket.removeAllListeners(); - socket.end(); - socket.destroy(); - socket.unref(); - }); - sockets.clear(); - }, - }; - }, options || {}, this.storeCallback(connectionListener)); - - this.ae.on("close", () => { - this._listening = false; - this.emit("close"); - }); - - this.ae.on("connection", (socketId) => { - const socketAe = this.ae.createUnique(socketId); - const socket = new Socket(undefined, socketAe); - this.sockets.set(socketId, socket); - socket.on("close", () => this.sockets.delete(socketId)); - if (connectionListener) { - connectionListener(socket); - } - this.emit("connection", socket); - }); - - this.ae.on("error", (error) => { - this._listening = false; - this.emit("error", error); - }); - - this.ae.on("listening", () => { - this._listening = true; - this.emit("listening"); - }); - } - - public listen(handle?: net.ListenOptions | number | string, hostname?: string | number | Function, backlog?: number | Function, listeningListener?: Function): this { - if (typeof handle === "undefined") { - throw new Error("no handle"); - } - - switch (typeof handle) { - case "number": handle = { port: handle }; break; - case "string": handle = { path: handle }; break; - } - switch (typeof hostname) { - case "function": listeningListener = hostname; break; - case "string": handle.host = hostname; break; - case "number": handle.backlog = hostname; break; - } - switch (typeof backlog) { - case "function": listeningListener = backlog; break; - case "number": handle.backlog = backlog; break; - } - - if (listeningListener) { - this.ae.on("listening", () => { - listeningListener!(); - }); - } - - this.ae.emit("listen", handle); - - return this; - } - - public close(callback?: Function): this { - // close() doesn't fire the close event until all connections are also - // closed, but it does prevent new connections. - this._listening = false; - this.ae.emit("close", this.storeCallback(callback)); - - return this; - } - - public get connections(): number { return this.sockets.size; } - public get listening(): boolean { return this._listening; } - - public get maxConnections(): number { throw new Error("not implemented"); } - public address(): net.AddressInfo | string { throw new Error("not implemented"); } - - public ref(): this { return this.emitReturnThis("ref"); } - public unref(): this { return this.emitReturnThis("unref"); } - public getConnections(cb: (error: Error | null, count: number) => void): void { cb(null, this.sockets.size); } - - // tslint:disable-next-line no-any - private emitReturnThis(event: string, ...args: any[]): this { - this.ae.emit(event, ...args); - - return this; - } -} - -type NodeNet = typeof net; - -/** - * Implementation of net for the browser. - */ -class Net implements NodeNet { - // @ts-ignore this is because Socket is missing things from the Stream - // namespace but I'm unsure how best to provide them (finished, - // finished.__promisify__, pipeline, and some others) or if it even matters. - public readonly Socket = Socket; - public readonly Server = Server; - - public createConnection(target: string | number | net.NetConnectOpts, host?: string | Function, callback?: Function): net.Socket { - const socket = new Socket(); - socket.connect(target, host, callback); - - return socket; - } - - public createServer( - options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean } | ((socket: net.Socket) => void), - connectionListener?: (socket: net.Socket) => void, - ): net.Server { - return new Server(options, connectionListener); - } - - public connect(): net.Socket { throw new Error("not implemented"); } - public isIP(_input: string): number { throw new Error("not implemented"); } - public isIPv4(_input: string): boolean { throw new Error("not implemented"); } - public isIPv6(_input: string): boolean { throw new Error("not implemented"); } -} - -export = new Net(); +export = client.modules[Module.Net]; diff --git a/packages/ide/src/fill/trash.ts b/packages/ide/src/fill/trash.ts new file mode 100644 index 00000000..249dab5d --- /dev/null +++ b/packages/ide/src/fill/trash.ts @@ -0,0 +1,4 @@ +import { Module } from "@coder/protocol"; +import { client } from "./client"; + +export = client.modules[Module.Trash].trash; diff --git a/packages/ide/yarn.lock b/packages/ide/yarn.lock index 56f12cc0..fb57ccd1 100644 --- a/packages/ide/yarn.lock +++ b/packages/ide/yarn.lock @@ -2,113 +2,3 @@ # yarn lockfile v1 -"@types/events@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - -"@types/glob@*": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" - integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== - dependencies: - "@types/events" "*" - "@types/minimatch" "*" - "@types/node" "*" - -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/node@*": - version "11.9.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.4.tgz#ceb0048a546db453f6248f2d1d95e937a6f00a14" - integrity sha512-Zl8dGvAcEmadgs1tmSPcvwzO1YRsz38bVJQvH1RvRqSR9/5n61Q1ktcDL0ht3FXWR+ZpVmXVwN1LuH4Ax23NsA== - -"@types/rimraf@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e" - integrity sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ== - dependencies: - "@types/glob" "*" - "@types/node" "*" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -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" - -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= - -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= - -glob@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - 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" - -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.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -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" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -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= - -rimraf@^2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/packages/package.json b/packages/package.json index 12e48d0b..59a8725e 100644 --- a/packages/package.json +++ b/packages/package.json @@ -33,7 +33,8 @@ "@coder/(.*)/test": "/$1/test", "@coder/(.*)": "/$1/src", "vs/(.*)": "/../lib/vscode/src/vs/$1", - "vszip": "/../lib/vscode/src/vs/base/node/zip.ts" + "vszip": "/../lib/vscode/src/vs/base/node/zip.ts", + "^node-pty": "node-pty-prebuilt" }, "transform": { "^.+\\.tsx?$": "ts-jest" @@ -44,4 +45,4 @@ ], "testRegex": ".*\\.test\\.tsx?" } -} \ No newline at end of file +} diff --git a/packages/protocol/package.json b/packages/protocol/package.json index 48749123..5b3876f4 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -7,12 +7,13 @@ "node-pty-prebuilt": "^0.7.6", "spdlog": "^0.7.2", "trash": "^4.3.0", - "tslib": "^1.9.3", "ws": "^6.1.2" }, "devDependencies": { "@types/google-protobuf": "^3.2.7", + "@types/rimraf": "^2.0.2", "@types/text-encoding": "^0.0.35", + "rimraf": "^2.6.3", "text-encoding": "^0.7.0", "ts-protoc-gen": "^0.8.0" } diff --git a/packages/protocol/src/browser/client.ts b/packages/protocol/src/browser/client.ts index 9323df11..470c862a 100644 --- a/packages/protocol/src/browser/client.ts +++ b/packages/protocol/src/browser/client.ts @@ -1,19 +1,32 @@ -import { EventEmitter } from "events"; +import { PathLike } from "fs"; +import { ExecException, ExecOptions } from "child_process"; +import { promisify } from "util"; import { Emitter } from "@coder/events"; import { logger, field } from "@coder/logger"; -import { Ping, NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, ClientMessage, WorkingInitMessage, EvalEventMessage } from "../proto"; -import { ReadWriteConnection, InitData, OperatingSystem, SharedProcessData } from "../common/connection"; -import { ActiveEvalHelper, EvalHelper, Disposer, ServerActiveEvalHelper } from "../common/helpers"; -import { stringify, parse } from "../common/util"; +import { ReadWriteConnection, InitData, SharedProcessData } from "../common/connection"; +import { Module, ServerProxy } from "../common/proxy"; +import { stringify, parse, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util"; +import { Ping, ServerMessage, ClientMessage, MethodMessage, NamedProxyMessage, NumberedProxyMessage, SuccessMessage, FailMessage, EventMessage, CallbackMessage } from "../proto"; +import { FsModule, ChildProcessModule, NetModule, NodePtyModule, SpdlogModule, TrashModule } from "./modules"; + +// tslint:disable no-any + +interface ProxyData { + promise: Promise; + instance: any; + callbacks: Map void>; +} /** - * Client accepts an arbitrary connection intended to communicate with the Server. + * Client accepts a connection to communicate with the server. */ export class Client { - private evalId = 0; - private readonly evalDoneEmitter = new Emitter(); - private readonly evalFailedEmitter = new Emitter(); - private readonly evalEventEmitter = new Emitter(); + private messageId = 0; + private callbackId = 0; + private readonly proxies = new Map(); + private readonly successEmitter = new Emitter(); + private readonly failEmitter = new Emitter(); + private readonly eventEmitter = new Emitter<{ event: string; args: any[]; }>(); private _initData: InitData | undefined; private readonly initDataEmitter = new Emitter(); @@ -22,37 +35,123 @@ export class Client { private readonly sharedProcessActiveEmitter = new Emitter(); public readonly onSharedProcessActive = this.sharedProcessActiveEmitter.event; + private disconnected: boolean = false; + // The socket timeout is 60s, so we need to send a ping periodically to // prevent it from closing. private pingTimeout: NodeJS.Timer | number | undefined; private readonly pingTimeoutDelay = 30000; + private readonly responseTimeout = 10000; + + public readonly modules: { + [Module.ChildProcess]: ChildProcessModule, + [Module.Fs]: FsModule, + [Module.Net]: NetModule, + [Module.NodePty]: NodePtyModule, + [Module.Spdlog]: SpdlogModule, + [Module.Trash]: TrashModule, + }; + /** * @param connection Established connection to the server */ - public constructor( - private readonly connection: ReadWriteConnection, - ) { - connection.onMessage((data) => { + public constructor(private readonly connection: ReadWriteConnection) { + connection.onMessage(async (data) => { let message: ServerMessage | undefined; try { message = ServerMessage.deserializeBinary(data); - this.handleMessage(message); + await this.handleMessage(message); } catch (error) { logger.error( "Failed to handle server message", - field("id", message && message.hasEvalEvent() ? message.getEvalEvent()!.getId() : undefined), + field("id", message && this.getMessageId(message)), field("length", data.byteLength), field("error", error.message), ); } }); - connection.onClose(() => { - clearTimeout(this.pingTimeout as any); // tslint:disable-line no-any - this.pingTimeout = undefined; + this.createProxy(Module.ChildProcess); + this.createProxy(Module.Fs); + this.createProxy(Module.Net); + this.createProxy(Module.NodePty); + this.createProxy(Module.Spdlog); + this.createProxy(Module.Trash); + + this.modules = { + [Module.ChildProcess]: new ChildProcessModule(this.getProxy(Module.ChildProcess).instance), + [Module.Fs]: new FsModule(this.getProxy(Module.Fs).instance), + [Module.Net]: new NetModule(this.getProxy(Module.Net).instance), + [Module.NodePty]: new NodePtyModule(this.getProxy(Module.NodePty).instance), + [Module.Spdlog]: new SpdlogModule(this.getProxy(Module.Spdlog).instance), + [Module.Trash]: new TrashModule(this.getProxy(Module.Trash).instance), + }; + + // Methods that don't follow the standard callback pattern (an error + // followed by a single result) need to provide a custom promisify function. + Object.defineProperty(this.modules[Module.Fs].exists, promisify.custom, { + value: (path: PathLike): Promise => { + return new Promise((resolve): void => this.modules[Module.Fs].exists(path, resolve)); + }, }); + Object.defineProperty(this.modules[Module.ChildProcess].exec, promisify.custom, { + value: ( + command: string, + options?: { encoding?: string | null } & ExecOptions | null, + ): Promise<{ stdout: string | Buffer, stderr: string | Buffer }> => { + return new Promise((resolve, reject): void => { + this.modules[Module.ChildProcess].exec(command, options, (error: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => { + if (error) { + reject(error); + } else { + resolve({ stdout, stderr }); + } + }); + }); + }, + }); + + /** + * If the connection is interrupted, the calls will neither succeed nor fail + * nor exit so we need to send a failure on all of them as well as trigger + * events so things like child processes can clean up and possibly restart. + */ + const handleDisconnect = (): void => { + this.disconnected = true; + logger.trace(() => [ + "disconnected from server", + field("proxies", this.proxies.size), + field("callbacks", Array.from(this.proxies.values()).reduce((count, p) => count + p.callbacks.size, 0)), + field("success listeners", this.successEmitter.counts), + field("fail listeners", this.failEmitter.counts), + field("event listeners", this.eventEmitter.counts), + ]); + + const message = new FailMessage(); + const error = new Error("disconnected"); + message.setResponse(stringify(error)); + this.failEmitter.emit(message); + + this.eventEmitter.emit({ event: "exit", args: [1] }); + this.eventEmitter.emit({ event: "close", args: [] }); + try { + this.eventEmitter.emit({ event: "error", args: [error] }); + } catch (error) { + // If nothing is listening, EventEmitter will throw an error. + } + this.eventEmitter.emit({ event: "done", args: [true] }); + }; + + connection.onDown(() => handleDisconnect()); + connection.onClose(() => { + clearTimeout(this.pingTimeout as any); + this.pingTimeout = undefined; + handleDisconnect(); + }); + connection.onUp(() => this.disconnected = false); + this.initDataPromise = new Promise((resolve): void => { this.initDataEmitter.event(resolve); }); @@ -60,6 +159,9 @@ export class Client { this.startPinging(); } + /** + * Close the connection. + */ public dispose(): void { this.connection.close(); } @@ -68,158 +170,109 @@ export class Client { return this.initDataPromise; } - public run(func: (helper: ServerActiveEvalHelper) => Disposer): ActiveEvalHelper; - public run(func: (helper: ServerActiveEvalHelper, a1: T1) => Disposer, a1: T1): ActiveEvalHelper; - public run(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2) => Disposer, a1: T1, a2: T2): ActiveEvalHelper; - public run(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3) => Disposer, a1: T1, a2: T2, a3: T3): ActiveEvalHelper; - public run(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3, a4: T4) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4): ActiveEvalHelper; - public run(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): ActiveEvalHelper; - public run(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): ActiveEvalHelper; /** - * Run a function on the server and provide an event emitter which allows - * listening and emitting to the emitter provided to that function. The - * function should return a disposer for cleaning up when the client - * disconnects and for notifying when disposal has happened outside manual - * activation. + * Make a remote call for a proxy's method using proto. */ - public run(func: (helper: ServerActiveEvalHelper, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => Disposer, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): ActiveEvalHelper { - const doEval = this.doEvaluate(func, a1, a2, a3, a4, a5, a6, true); + private remoteCall(proxyId: number | Module, method: string, args: any[]): Promise { + if (this.disconnected) { + return Promise.reject(new Error("disconnected")); + } - // This takes server events and emits them to the client's emitter. - const eventEmitter = new EventEmitter(); - const d1 = this.evalEventEmitter.event((msg) => { - if (msg.getId() === doEval.id) { - eventEmitter.emit(msg.getEvent(), ...msg.getArgsList().map(parse)); - } - }); + const message = new MethodMessage(); + const id = this.messageId++; + let proxyMessage: NamedProxyMessage | NumberedProxyMessage; + if (typeof proxyId === "string") { + proxyMessage = new NamedProxyMessage(); + proxyMessage.setModule(moduleToProto(proxyId)); + message.setNamedProxy(proxyMessage); + } else { + proxyMessage = new NumberedProxyMessage(); + proxyMessage.setProxyId(proxyId); + message.setNumberedProxy(proxyMessage); + } + proxyMessage.setId(id); + proxyMessage.setMethod(method); - doEval.completed.then(() => { - d1.dispose(); - }).catch((ex) => { - d1.dispose(); - // This error event is only received by the client. - eventEmitter.emit("error", ex); - }); + const storeCallback = (cb: (...args: any[]) => void): number => { + const callbackId = this.callbackId++; + logger.trace(() => [ + "storing callback", + field("proxyId", proxyId), + field("callbackId", callbackId), + ]); - return new ActiveEvalHelper({ - // This takes client events and emits them to the server's emitter and - // listens to events received from the server (via the event hook above). - // tslint:disable no-any - on: (event: string, cb: (...args: any[]) => void): EventEmitter => eventEmitter.on(event, cb), - emit: (event: string, ...args: any[]): void => { - const eventsMsg = new EvalEventMessage(); - eventsMsg.setId(doEval.id); - eventsMsg.setEvent(event); - eventsMsg.setArgsList(args.map((a) => stringify(a))); - const clientMsg = new ClientMessage(); - clientMsg.setEvalEvent(eventsMsg); - this.connection.send(clientMsg.serializeBinary()); - }, - removeAllListeners: (event: string): EventEmitter => eventEmitter.removeAllListeners(event), - // tslint:enable no-any - }); - } + this.getProxy(proxyId).callbacks.set(callbackId, cb); - public evaluate(func: (helper: EvalHelper) => R | Promise): Promise; - public evaluate(func: (helper: EvalHelper, a1: T1) => R | Promise, a1: T1): Promise; - public evaluate(func: (helper: EvalHelper, a1: T1, a2: T2) => R | Promise, a1: T1, a2: T2): Promise; - public evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3) => R | Promise, a1: T1, a2: T2, a3: T3): Promise; - public evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4) => R | Promise, a1: T1, a2: T2, a3: T3, a4: T4): Promise; - public evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => R | Promise, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): Promise; - public evaluate(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => R | Promise, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): Promise; - /** - * Evaluates a function on the server. - * To pass variables, ensure they are serializable and passed through the included function. - * @example - * const returned = await this.client.evaluate((helper, value) => { - * return value; - * }, "hi"); - * console.log(returned); - * // output: "hi" - * @param func Function to evaluate - * @returns Promise rejected or resolved from the evaluated function - */ - public evaluate(func: (helper: EvalHelper, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => R | Promise, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): Promise { - return this.doEvaluate(func, a1, a2, a3, a4, a5, a6, false).completed; - } + return callbackId; + }; - // tslint:disable-next-line no-any - private doEvaluate(func: (...args: any[]) => void | Promise | R | Promise, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6, active: boolean = false): { - readonly completed: Promise; - readonly id: number; - } { - const newEval = new NewEvalMessage(); - const id = this.evalId++; - newEval.setId(id); - newEval.setActive(active); - newEval.setArgsList([a1, a2, a3, a4, a5, a6].map((a) => stringify(a))); - newEval.setFunction(func.toString()); + const stringifiedArgs = args.map((a) => stringify(a, storeCallback)); + logger.trace(() => [ + "sending", + field("id", id), + field("proxyId", proxyId), + field("method", method), + field("args", stringifiedArgs), + ]); - const clientMsg = new ClientMessage(); - clientMsg.setNewEval(newEval); - this.connection.send(clientMsg.serializeBinary()); + proxyMessage.setArgsList(stringifiedArgs); - const completed = new Promise((resolve, reject): void => { + const clientMessage = new ClientMessage(); + clientMessage.setMethod(message); + this.connection.send(clientMessage.serializeBinary()); + + // The server will send back a fail or success message when the method + // has completed, so we listen for that based on the message's unique ID. + const promise = new Promise((resolve, reject): void => { const dispose = (): void => { d1.dispose(); d2.dispose(); + clearTimeout(timeout as any); }; - const d1 = this.evalDoneEmitter.event((doneMsg) => { - if (doneMsg.getId() === id) { - dispose(); - resolve(parse(doneMsg.getResponse())); - } + const timeout = setTimeout(() => { + dispose(); + reject(new Error("timed out")); + }, this.responseTimeout); + + const d1 = this.successEmitter.event(id, (message) => { + dispose(); + resolve(this.parse(message.getResponse())); }); - const d2 = this.evalFailedEmitter.event((failedMsg) => { - if (failedMsg.getId() === id) { - dispose(); - reject(parse(failedMsg.getResponse())); - } + const d2 = this.failEmitter.event(id, (message) => { + dispose(); + reject(parse(message.getResponse())); }); }); - return { completed, id }; + return promise; } /** - * Handles a message from the server. All incoming server messages should be - * routed through here. + * Handle all messages from the server. */ - private handleMessage(message: ServerMessage): void { + private async handleMessage(message: ServerMessage): Promise { if (message.hasInit()) { const init = message.getInit()!; - let opSys: OperatingSystem; - switch (init.getOperatingSystem()) { - case WorkingInitMessage.OperatingSystem.WINDOWS: - opSys = OperatingSystem.Windows; - break; - case WorkingInitMessage.OperatingSystem.LINUX: - opSys = OperatingSystem.Linux; - break; - case WorkingInitMessage.OperatingSystem.MAC: - opSys = OperatingSystem.Mac; - break; - default: - throw new Error(`unsupported operating system ${init.getOperatingSystem()}`); - } this._initData = { dataDirectory: init.getDataDirectory(), homeDirectory: init.getHomeDirectory(), tmpDirectory: init.getTmpDirectory(), workingDirectory: init.getWorkingDirectory(), - os: opSys, + os: protoToOperatingSystem(init.getOperatingSystem()), shell: init.getShell(), builtInExtensionsDirectory: init.getBuiltinExtensionsDir(), }; this.initDataEmitter.emit(this._initData); - } else if (message.hasEvalDone()) { - this.evalDoneEmitter.emit(message.getEvalDone()!); - } else if (message.hasEvalFailed()) { - this.evalFailedEmitter.emit(message.getEvalFailed()!); - } else if (message.hasEvalEvent()) { - this.evalEventEmitter.emit(message.getEvalEvent()!); + } else if (message.hasSuccess()) { + this.emitSuccess(message.getSuccess()!); + } else if (message.hasFail()) { + this.emitFail(message.getFail()!); + } else if (message.hasEvent()) { + await this.emitEvent(message.getEvent()!); + } else if (message.hasCallback()) { + await this.runCallback(message.getCallback()!); } else if (message.hasSharedProcessActive()) { const sharedProcessActiveMessage = message.getSharedProcessActive()!; this.sharedProcessActiveEmitter.emit({ @@ -227,13 +280,85 @@ export class Client { logPath: sharedProcessActiveMessage.getLogPath(), }); } else if (message.hasPong()) { - // Nothing to do since we run the pings on a timer, in case either message - // is dropped which would break the ping cycle. + // Nothing to do since pings are on a timer rather than waiting for the + // next pong in case a message from either the client or server is dropped + // which would break the ping cycle. } else { throw new Error("unknown message type"); } } + private emitSuccess(message: SuccessMessage): void { + logger.trace(() => [ + "received resolve", + field("id", message.getId()), + ]); + + this.successEmitter.emit(message.getId(), message); + } + + private emitFail(message: FailMessage): void { + logger.trace(() => [ + "received reject", + field("id", message.getId()), + ]); + + this.failEmitter.emit(message.getId(), message); + } + + /** + * Emit an event received from the server. We could send requests for "on" to + * the server and serialize functions using IDs, but doing it that way makes + * it possible to miss events depending on whether the server receives the + * request before it emits. Instead, emit all events from the server so all + * events are always caught on the client. + */ + private async emitEvent(message: EventMessage): Promise { + const eventMessage = message.getNamedEvent()! || message.getNumberedEvent()!; + const proxyId = message.getNamedEvent() + ? protoToModule(message.getNamedEvent()!.getModule()) + : message.getNumberedEvent()!.getProxyId(); + const event = eventMessage.getEvent(); + await this.ensureResolved(proxyId); + logger.trace(() => [ + "received event", + field("proxyId", proxyId), + field("event", event), + field("args", eventMessage.getArgsList()), + ]); + + const args = eventMessage.getArgsList().map((a) => this.parse(a)); + this.eventEmitter.emit(proxyId, { event, args }); + } + + /** + * Run a callback as requested by the server. Since we don't know when + * callbacks get garbage collected we dispose them only when the proxy + * disposes. That means they should only be used if they run for the lifetime + * of the proxy (like child_process.exec), otherwise we'll leak. They should + * also only be used when passed together with the method. If they are sent + * afterward, they may never be called due to timing issues. + */ + private async runCallback(message: CallbackMessage): Promise { + const callbackMessage = message.getNamedCallback()! || message.getNumberedCallback()!; + const proxyId = message.getNamedCallback() + ? protoToModule(message.getNamedCallback()!.getModule()) + : message.getNumberedCallback()!.getProxyId(); + const callbackId = callbackMessage.getCallbackId(); + await this.ensureResolved(proxyId); + logger.trace(() => [ + "running callback", + field("proxyId", proxyId), + field("callbackId", callbackId), + field("args", callbackMessage.getArgsList()), + ]); + const args = callbackMessage.getArgsList().map((a) => this.parse(a)); + this.getProxy(proxyId).callbacks.get(callbackId)!(...args); + } + + /** + * Start the ping loop. Does nothing if already pinging. + */ private startPinging = (): void => { if (typeof this.pingTimeout !== "undefined") { return; @@ -250,4 +375,136 @@ export class Client { schedulePing(); } + + /** + * Return the message's ID if it has one or a string identifier. For logging + * errors with an ID to make the error more useful. + */ + private getMessageId(message: ServerMessage): number | string | undefined { + if (message.hasInit()) { + return "init"; + } else if (message.hasSuccess()) { + return message.getSuccess()!.getId(); + } else if (message.hasFail()) { + return message.getFail()!.getId(); + } else if (message.hasEvent()) { + const eventMessage = message.getEvent()!.getNamedEvent()! + || message.getEvent()!.getNumberedEvent()!; + + return `event: ${eventMessage.getEvent()}`; + } else if (message.hasCallback()) { + const callbackMessage = message.getCallback()!.getNamedCallback()! + || message.getCallback()!.getNumberedCallback()!; + + return `callback: ${callbackMessage.getCallbackId()}`; + } else if (message.hasSharedProcessActive()) { + return "shared"; + } else if (message.hasPong()) { + return "pong"; + } + } + + /** + * Return a proxy that makes remote calls. + */ + private createProxy(proxyId: number | Module, promise: Promise = Promise.resolve()): T { + logger.trace(() => [ + "creating proxy", + field("proxyId", proxyId), + ]); + + const instance = new Proxy({ + proxyId, + onDone: (cb: (...args: any[]) => void): void => { + this.eventEmitter.event(proxyId, (event) => { + if (event.event === "done") { + cb(...event.args); + } + }); + }, + onEvent: (cb: (event: string, ...args: any[]) => void): void => { + this.eventEmitter.event(proxyId, (event) => { + cb(event.event, ...event.args); + }); + }, + }, { + get: (target: any, name: string): any => { + // When resolving a promise with a proxy, it will check for "then". + if (name === "then") { + return; + } + + if (typeof target[name] === "undefined") { + target[name] = (...args: any[]): Promise | ServerProxy => { + return this.remoteCall(proxyId, name, args); + }; + } + + return target[name]; + }, + }); + + this.proxies.set(proxyId, { + promise, + instance, + callbacks: new Map(), + }); + + instance.onDone((disconnected: boolean) => { + const log = (): void => { + logger.trace(() => [ + typeof proxyId === "number" ? "disposed proxy" : "disposed proxy callbacks", + field("proxyId", proxyId), + field("disconnected", disconnected), + field("callbacks", Array.from(this.proxies.values()).reduce((count, proxy) => count + proxy.callbacks.size, 0)), + field("success listeners", this.successEmitter.counts), + field("fail listeners", this.failEmitter.counts), + field("event listeners", this.eventEmitter.counts), + ]); + }; + + // Uniquely identified items (top-level module proxies) can continue to + // be used so we don't need to delete them. + if (typeof proxyId === "number") { + const dispose = (): void => { + this.proxies.delete(proxyId); + this.eventEmitter.dispose(proxyId); + log(); + }; + if (!disconnected) { + instance.dispose().then(dispose).catch(dispose); + } else { + dispose(); + } + } else { + // The callbacks will still be unusable though. + this.getProxy(proxyId).callbacks.clear(); + log(); + } + }); + + return instance; + } + + /** + * We aren't guaranteed the promise will call all the `then` callbacks + * synchronously once it resolves, so the event message can come in and fire + * before a caller has been able to attach an event. Waiting for the promise + * ensures it runs after everything else. + */ + private async ensureResolved(proxyId: number | Module): Promise { + await this.getProxy(proxyId).promise; + } + + private parse(value?: string, promise?: Promise): any { + return parse(value, undefined, (id) => this.createProxy(id, promise)); + } + + private getProxy(proxyId: number | Module): ProxyData { + if (!this.proxies.has(proxyId)) { + throw new Error(`proxy ${proxyId} disposed too early`); + } + + return this.proxies.get(proxyId)!; + } } diff --git a/packages/protocol/src/browser/modules/child_process.ts b/packages/protocol/src/browser/modules/child_process.ts new file mode 100644 index 00000000..de13e171 --- /dev/null +++ b/packages/protocol/src/browser/modules/child_process.ts @@ -0,0 +1,126 @@ +import * as cp from "child_process"; +import * as net from "net"; +import * as stream from "stream"; +import { callbackify } from "util"; +import { ClientProxy } from "../../common/proxy"; +import { ChildProcessModuleProxy, ChildProcessProxy, ChildProcessProxies } from "../../node/modules/child_process"; +import { Readable, Writable } from "./stream"; + +export class ChildProcess extends ClientProxy implements cp.ChildProcess { + public readonly stdin: stream.Writable; + public readonly stdout: stream.Readable; + public readonly stderr: stream.Readable; + public readonly stdio: [stream.Writable, stream.Readable, stream.Readable]; + + private _connected: boolean = false; + private _killed: boolean = false; + private _pid = -1; + + public constructor(proxyPromises: Promise) { + super(proxyPromises.then((p) => p.childProcess)); + this.stdin = new Writable(proxyPromises.then((p) => p.stdin!)); + this.stdout = new Readable(proxyPromises.then((p) => p.stdout!)); + this.stderr = new Readable(proxyPromises.then((p) => p.stderr!)); + this.stdio = [this.stdin, this.stdout, this.stderr]; + + this.proxy.getPid().then((pid) => { + this._pid = pid; + this._connected = true; + }); + this.on("disconnect", () => this._connected = false); + this.on("exit", () => { + this._connected = false; + this._killed = true; + }); + } + + public get pid(): number { + return this._pid; + } + + public get connected(): boolean { + return this._connected; + } + + public get killed(): boolean { + return this._killed; + } + + public kill(): void { + this._killed = true; + this.proxy.kill(); + } + + public disconnect(): void { + this.proxy.disconnect(); + } + + public ref(): void { + this.proxy.ref(); + } + + public unref(): void { + this.proxy.unref(); + } + + public send( + message: any, // tslint:disable-line no-any + sendHandle?: net.Socket | net.Server | ((error: Error) => void), + options?: cp.MessageOptions | ((error: Error) => void), + callback?: (error: Error) => void): boolean { + if (typeof sendHandle === "function") { + callback = sendHandle; + sendHandle = undefined; + } else if (typeof options === "function") { + callback = options; + options = undefined; + } + if (sendHandle || options) { + throw new Error("sendHandle and options are not supported"); + } + + callbackify(this.proxy.send)(message, (error) => { + if (callback) { + callback(error); + } + }); + + return true; // Always true since we can't get this synchronously. + } +} + +export class ChildProcessModule { + public constructor(private readonly proxy: ChildProcessModuleProxy) {} + + public exec = ( + command: string, + options?: { encoding?: string | null } & cp.ExecOptions | null + | ((error: cp.ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void), + callback?: ((error: cp.ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void), + ): cp.ChildProcess => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + + return new ChildProcess(this.proxy.exec(command, options, callback)); + } + + public fork = (modulePath: string, args?: string[] | cp.ForkOptions, options?: cp.ForkOptions): cp.ChildProcess => { + if (!Array.isArray(args)) { + options = args; + args = undefined; + } + + return new ChildProcess(this.proxy.fork(modulePath, args, options)); + } + + public spawn = (command: string, args?: string[] | cp.SpawnOptions, options?: cp.SpawnOptions): cp.ChildProcess => { + if (!Array.isArray(args)) { + options = args; + args = undefined; + } + + return new ChildProcess(this.proxy.spawn(command, args, options)); + } +} diff --git a/packages/protocol/src/browser/modules/fs.ts b/packages/protocol/src/browser/modules/fs.ts new file mode 100644 index 00000000..c8b793af --- /dev/null +++ b/packages/protocol/src/browser/modules/fs.ts @@ -0,0 +1,316 @@ +import * as fs from "fs"; +import { callbackify } from "util"; +import { ClientProxy } from "../../common/proxy"; +import { IEncodingOptions, IEncodingOptionsCallback } from "../../common/util"; +import { FsModuleProxy, Stats as IStats, WatcherProxy, WriteStreamProxy } from "../../node/modules/fs"; +import { Writable } from "./stream"; + +// tslint:disable no-any + +class Watcher extends ClientProxy implements fs.FSWatcher { + public close(): void { + this.proxy.close(); + } +} + +class WriteStream extends Writable implements fs.WriteStream { + public get bytesWritten(): number { + throw new Error("not implemented"); + } + + public get path(): string | Buffer { + throw new Error("not implemented"); + } + + public close(): void { + this.proxy.close(); + } +} + +export class FsModule { + public constructor(private readonly proxy: FsModuleProxy) {} + + public access = (path: fs.PathLike, mode: number | undefined | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof mode === "function") { + callback = mode; + mode = undefined; + } + callbackify(this.proxy.access)(path, mode, callback!); + } + + public appendFile = (path: fs.PathLike | number, data: any, options?: fs.WriteFileOptions | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + callbackify(this.proxy.appendFile)(path, data, options, callback!); + } + + public chmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.chmod)(path, mode, callback!); + } + + public chown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.chown)(path, uid, gid, callback!); + } + + public close = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.close)(fd, callback!); + } + + public copyFile = (src: fs.PathLike, dest: fs.PathLike, flags: number | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof flags === "function") { + callback = flags; + } + callbackify(this.proxy.copyFile)( + src, dest, typeof flags !== "function" ? flags : undefined, callback!, + ); + } + + public createWriteStream = (path: fs.PathLike, options?: any): fs.WriteStream => { + return new WriteStream(this.proxy.createWriteStream(path, options)); + } + + public exists = (path: fs.PathLike, callback: (exists: boolean) => void): void => { + callbackify(this.proxy.exists)(path, (exists) => { + callback!(exists as any); + }); + } + + public fchmod = (fd: number, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.fchmod)(fd, mode, callback!); + } + + public fchown = (fd: number, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.fchown)(fd, uid, gid, callback!); + } + + public fdatasync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.fdatasync)(fd, callback!); + } + + public fstat = (fd: number, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => { + callbackify(this.proxy.fstat)(fd, (error, stats) => { + callback(error, stats && new Stats(stats)); + }); + } + + public fsync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.fsync)(fd, callback!); + } + + public ftruncate = (fd: number, len: number | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof len === "function") { + callback = len; + len = undefined; + } + callbackify(this.proxy.ftruncate)(fd, len, callback!); + } + + public futimes = (fd: number, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.futimes)(fd, atime, mtime, callback!); + } + + public lchmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.lchmod)(path, mode, callback!); + } + + public lchown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.lchown)(path, uid, gid, callback!); + } + + public link = (existingPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.link)(existingPath, newPath, callback!); + } + + public lstat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => { + callbackify(this.proxy.lstat)(path, (error, stats) => { + callback(error, stats && new Stats(stats)); + }); + } + + public mkdir = (path: fs.PathLike, mode: number | string | fs.MakeDirectoryOptions | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof mode === "function") { + callback = mode; + mode = undefined; + } + callbackify(this.proxy.mkdir)(path, mode, callback!); + } + + public mkdtemp = (prefix: string, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, folder: string | Buffer) => void): void => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + callbackify(this.proxy.mkdtemp)(prefix, options, callback!); + } + + public open = (path: fs.PathLike, flags: string | number, mode: string | number | undefined | null | ((err: NodeJS.ErrnoException, fd: number) => void), callback?: (err: NodeJS.ErrnoException, fd: number) => void): void => { + if (typeof mode === "function") { + callback = mode; + mode = undefined; + } + callbackify(this.proxy.open)(path, flags, mode, callback!); + } + + public read = (fd: number, buffer: Buffer, offset: number, length: number, position: number | null, callback: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void => { + this.proxy.read(fd, length, position).then((response) => { + buffer.set(response.buffer, offset); + callback(undefined!, response.bytesRead, response.buffer); + }).catch((error) => { + callback(error, undefined!, undefined!); + }); + } + + public readFile = (path: fs.PathLike | number, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, data: string | Buffer) => void): void => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + callbackify(this.proxy.readFile)(path, options, callback!); + } + + public readdir = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, files: Buffer[] | fs.Dirent[] | string[]) => void): void => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + callbackify(this.proxy.readdir)(path, options, callback!); + } + + public readlink = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, linkString: string | Buffer) => void): void => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + callbackify(this.proxy.readlink)(path, options, callback!); + } + + public realpath = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, resolvedPath: string | Buffer) => void): void => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + callbackify(this.proxy.realpath)(path, options, callback!); + } + + public rename = (oldPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.rename)(oldPath, newPath, callback!); + } + + public rmdir = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.rmdir)(path, callback!); + } + + public stat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => { + callbackify(this.proxy.stat)(path, (error, stats) => { + callback(error, stats && new Stats(stats)); + }); + } + + public symlink = (target: fs.PathLike, path: fs.PathLike, type: fs.symlink.Type | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof type === "function") { + callback = type; + type = undefined; + } + callbackify(this.proxy.symlink)(target, path, type, callback!); + } + + public truncate = (path: fs.PathLike, len: number | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof len === "function") { + callback = len; + len = undefined; + } + callbackify(this.proxy.truncate)(path, len, callback!); + } + + public unlink = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.unlink)(path, callback!); + } + + public utimes = (path: fs.PathLike, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => { + callbackify(this.proxy.utimes)(path, atime, mtime, callback!); + } + + public write = (fd: number, buffer: Buffer, offset: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void), length: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void), position: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void), callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void => { + if (typeof offset === "function") { + callback = offset; + offset = undefined; + } + if (typeof length === "function") { + callback = length; + length = undefined; + } + if (typeof position === "function") { + callback = position; + position = undefined; + } + this.proxy.write(fd, buffer, offset, length, position).then((r) => { + callback!(undefined!, r.bytesWritten, r.buffer); + }).catch((error) => { + callback!(error, undefined!, undefined!); + }); + } + + public writeFile = (path: fs.PathLike | number, data: any, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException) => void): void => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + callbackify(this.proxy.writeFile)(path, data, options, callback!); + } + + public watch = (filename: fs.PathLike, options?: IEncodingOptions | ((event: string, filename: string | Buffer) => void), listener?: ((event: string, filename: string | Buffer) => void)): fs.FSWatcher => { + if (typeof options === "function") { + listener = options; + options = undefined; + } + + const watcher = new Watcher(this.proxy.watch(filename, options)); + if (listener) { + watcher.on("change", listener); + } + + return watcher; + } +} + +class Stats implements fs.Stats { + public readonly atime: Date; + public readonly mtime: Date; + public readonly ctime: Date; + public readonly birthtime: Date; + + public constructor(private readonly stats: IStats) { + this.atime = new Date(stats.atime); + this.mtime = new Date(stats.mtime); + this.ctime = new Date(stats.ctime); + this.birthtime = new Date(stats.birthtime); + } + + public get dev(): number { return this.stats.dev; } + public get ino(): number { return this.stats.ino; } + public get mode(): number { return this.stats.mode; } + public get nlink(): number { return this.stats.nlink; } + public get uid(): number { return this.stats.uid; } + public get gid(): number { return this.stats.gid; } + public get rdev(): number { return this.stats.rdev; } + public get size(): number { return this.stats.size; } + public get blksize(): number { return this.stats.blksize; } + public get blocks(): number { return this.stats.blocks; } + public get atimeMs(): number { return this.stats.atimeMs; } + public get mtimeMs(): number { return this.stats.mtimeMs; } + public get ctimeMs(): number { return this.stats.ctimeMs; } + public get birthtimeMs(): number { return this.stats.birthtimeMs; } + public isFile(): boolean { return this.stats._isFile; } + public isDirectory(): boolean { return this.stats._isDirectory; } + public isBlockDevice(): boolean { return this.stats._isBlockDevice; } + public isCharacterDevice(): boolean { return this.stats._isCharacterDevice; } + public isSymbolicLink(): boolean { return this.stats._isSymbolicLink; } + public isFIFO(): boolean { return this.stats._isFIFO; } + public isSocket(): boolean { return this.stats._isSocket; } + + public toObject(): object { + return JSON.parse(JSON.stringify(this)); + } +} diff --git a/packages/protocol/src/browser/modules/index.ts b/packages/protocol/src/browser/modules/index.ts new file mode 100644 index 00000000..590d037d --- /dev/null +++ b/packages/protocol/src/browser/modules/index.ts @@ -0,0 +1,6 @@ +export * from "./child_process"; +export * from "./fs"; +export * from "./net"; +export * from "./node-pty"; +export * from "./spdlog"; +export * from "./trash"; diff --git a/packages/protocol/src/browser/modules/net.ts b/packages/protocol/src/browser/modules/net.ts new file mode 100644 index 00000000..723bb1b1 --- /dev/null +++ b/packages/protocol/src/browser/modules/net.ts @@ -0,0 +1,280 @@ +import * as net from "net"; +import { callbackify } from "util"; +import { ClientProxy } from "../../common/proxy"; +import { NetModuleProxy, NetServerProxy, NetSocketProxy } from "../../node/modules/net"; +import { Duplex } from "./stream"; + +export class Socket extends Duplex implements net.Socket { + private _connecting: boolean = false; + private _destroyed: boolean = false; + + public constructor(proxyPromise: Promise | NetSocketProxy, connecting?: boolean) { + super(proxyPromise); + if (connecting) { + this._connecting = connecting; + } + this.on("close", () => { + this._destroyed = true; + this._connecting = false; + }); + this.on("connect", () => this._connecting = false); + } + + public connect(options: number | string | net.SocketConnectOpts, host?: string | Function, callback?: Function): this { + if (typeof host === "function") { + callback = host; + host = undefined; + } + this._connecting = true; + if (callback) { + this.on("connect", callback as () => void); + } + this.proxy.connect(options, host); + + return this; + } + + // tslint:disable-next-line no-any + public end(data?: any, encoding?: string | Function, callback?: Function): void { + if (typeof encoding === "function") { + callback = encoding; + encoding = undefined; + } + + callbackify(this.proxy.end)(data, encoding, () => { + if (callback) { + callback(); + } + }); + } + + // tslint:disable-next-line no-any + public write(data: any, encoding?: string | Function, fd?: string | Function): boolean { + let callback: undefined | Function; + if (typeof encoding === "function") { + callback = encoding; + encoding = undefined; + } + if (typeof fd === "function") { + callback = fd; + fd = undefined; + } + if (typeof fd !== "undefined") { + throw new Error("fd argument not supported"); + } + + callbackify(this.proxy.write)(data, encoding, () => { + if (callback) { + callback(); + } + }); + + return true; // Always true since we can't get this synchronously. + } + + public get connecting(): boolean { + return this._connecting; + } + + public get destroyed(): boolean { + return this._destroyed; + } + + public get bufferSize(): number { + throw new Error("not implemented"); + } + + public get bytesRead(): number { + throw new Error("not implemented"); + } + + public get bytesWritten(): number { + throw new Error("not implemented"); + } + + public get localAddress(): string { + throw new Error("not implemented"); + } + + public get localPort(): number { + throw new Error("not implemented"); + } + + public address(): net.AddressInfo | string { + throw new Error("not implemented"); + } + + public setTimeout(): this { + throw new Error("not implemented"); + } + + public setNoDelay(): this { + throw new Error("not implemented"); + } + + public setKeepAlive(): this { + throw new Error("not implemented"); + } + + public unref(): void { + this.proxy.unref(); + } + + public ref(): void { + this.proxy.ref(); + } +} + +export class Server extends ClientProxy implements net.Server { + private readonly sockets = new Map(); + private _listening: boolean = false; + + public constructor(proxyPromise: Promise | NetServerProxy) { + super(proxyPromise); + + this.proxy.onConnection((socketProxy) => { + this.emit("connection", new Socket(socketProxy)); + }); + + this.on("listening", () => this._listening = true); + this.on("error", () => this._listening = false); + this.on("close", () => this._listening = false); + } + + public listen(handle?: net.ListenOptions | number | string, hostname?: string | number | Function, backlog?: number | Function, callback?: Function): this { + if (typeof hostname === "function") { + callback = hostname; + hostname = undefined; + } + if (typeof backlog === "function") { + callback = backlog; + backlog = undefined; + } + if (callback) { + this.on("listening", callback as () => void); + } + + this.proxy.listen(handle, hostname, backlog); + + return this; + } + + public get connections(): number { + return this.sockets.size; + } + + public get listening(): boolean { + return this._listening; + } + + public get maxConnections(): number { + throw new Error("not implemented"); + } + + public address(): net.AddressInfo | string { + throw new Error("not implemented"); + } + + public close(callback?: () => void): this { + this._listening = false; + if (callback) { + this.on("close", callback); + } + this.proxy.close(); + + return this; + } + + public ref(): this { + this.proxy.ref(); + + return this; + } + + public unref(): this { + this.proxy.unref(); + + return this; + } + + public getConnections(cb: (error: Error | null, count: number) => void): void { + cb(null, this.sockets.size); + } +} + +type NodeNet = typeof net; + +export class NetModule implements NodeNet { + public readonly Socket: typeof net.Socket; + public readonly Server: typeof net.Server; + + public constructor(private readonly proxy: NetModuleProxy) { + // @ts-ignore this is because Socket is missing things from the Stream + // namespace but I'm unsure how best to provide them (finished, + // finished.__promisify__, pipeline, and some others) or if it even matters. + this.Socket = class extends Socket { + public constructor(options?: net.SocketConstructorOpts) { + super(proxy.createSocket(options)); + } + }; + + this.Server = class extends Server { + public constructor(options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean } | ((socket: Socket) => void), listener?: (socket: Socket) => void) { + super(proxy.createServer(typeof options !== "function" ? options : undefined)); + if (typeof options === "function") { + listener = options; + } + if (listener) { + this.on("connection", listener); + } + } + }; + } + + public createConnection = (target: string | number | net.NetConnectOpts, host?: string | Function, callback?: Function): net.Socket => { + if (typeof host === "function") { + callback = host; + host = undefined; + } + + const socket = new Socket(this.proxy.createConnection(target, host), true); + if (callback) { + socket.on("connect", callback as () => void); + } + + return socket; + } + + public createServer = ( + options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean } | ((socket: net.Socket) => void), + callback?: (socket: net.Socket) => void, + ): net.Server => { + if (typeof options === "function") { + callback = options; + options = undefined; + } + + const server = new Server(this.proxy.createServer(options)); + if (callback) { + server.on("connection", callback); + } + + return server; + } + + public connect = (): net.Socket => { + throw new Error("not implemented"); + } + + public isIP = (_input: string): number => { + throw new Error("not implemented"); + } + + public isIPv4 = (_input: string): boolean => { + throw new Error("not implemented"); + } + + public isIPv6 = (_input: string): boolean => { + throw new Error("not implemented"); + } +} diff --git a/packages/protocol/src/browser/modules/node-pty.ts b/packages/protocol/src/browser/modules/node-pty.ts new file mode 100644 index 00000000..7c96859f --- /dev/null +++ b/packages/protocol/src/browser/modules/node-pty.ts @@ -0,0 +1,45 @@ +import * as pty from "node-pty"; +import { ClientProxy } from "../../common/proxy"; +import { NodePtyModuleProxy, NodePtyProcessProxy } from "../../node/modules/node-pty"; + +export class NodePtyProcess extends ClientProxy implements pty.IPty { + private _pid = -1; + private _process = ""; + + public constructor(proxyPromise: Promise) { + super(proxyPromise); + this.proxy.getPid().then((pid) => this._pid = pid); + this.proxy.getProcess().then((process) => this._process = process); + this.on("process", (process) => this._process = process); + } + + public get pid(): number { + return this._pid; + } + + public get process(): string { + return this._process; + } + + public resize(columns: number, rows: number): void { + this.proxy.resize(columns, rows); + } + + public write(data: string): void { + this.proxy.write(data); + } + + public kill(signal?: string): void { + this.proxy.kill(signal); + } +} + +type NodePty = typeof pty; + +export class NodePtyModule implements NodePty { + public constructor(private readonly proxy: NodePtyModuleProxy) {} + + public spawn = (file: string, args: string[] | string, options: pty.IPtyForkOptions): pty.IPty => { + return new NodePtyProcess(this.proxy.spawn(file, args, options)); + } +} diff --git a/packages/protocol/src/browser/modules/spdlog.ts b/packages/protocol/src/browser/modules/spdlog.ts new file mode 100644 index 00000000..9d10fbab --- /dev/null +++ b/packages/protocol/src/browser/modules/spdlog.ts @@ -0,0 +1,32 @@ +import * as spdlog from "spdlog"; +import { ClientProxy } from "../../common/proxy"; +import { RotatingLoggerProxy, SpdlogModuleProxy } from "../../node/modules/spdlog"; + +class RotatingLogger extends ClientProxy implements spdlog.RotatingLogger { + public async trace (message: string): Promise { this.proxy.trace(message); } + public async debug (message: string): Promise { this.proxy.debug(message); } + public async info (message: string): Promise { this.proxy.info(message); } + public async warn (message: string): Promise { this.proxy.warn(message); } + public async error (message: string): Promise { this.proxy.error(message); } + public async critical (message: string): Promise { this.proxy.critical(message); } + public async setLevel (level: number): Promise { this.proxy.setLevel(level); } + public async clearFormatters (): Promise { this.proxy.clearFormatters(); } + public async flush (): Promise { this.proxy.flush(); } + public async drop (): Promise { this.proxy.drop(); } +} + +export class SpdlogModule { + public readonly RotatingLogger: typeof spdlog.RotatingLogger; + + public constructor(private readonly proxy: SpdlogModuleProxy) { + this.RotatingLogger = class extends RotatingLogger { + public constructor(name: string, filename: string, filesize: number, filecount: number) { + super(proxy.createLogger(name, filename, filesize, filecount)); + } + }; + } + + public setAsyncMode = (bufferSize: number, flushInterval: number): void => { + this.proxy.setAsyncMode(bufferSize, flushInterval); + } +} diff --git a/packages/protocol/src/browser/modules/stream.ts b/packages/protocol/src/browser/modules/stream.ts new file mode 100644 index 00000000..f5db4644 --- /dev/null +++ b/packages/protocol/src/browser/modules/stream.ts @@ -0,0 +1,233 @@ +import * as stream from "stream"; +import { callbackify } from "util"; +import { ClientProxy } from "../../common/proxy"; +import { DuplexProxy, IReadableProxy, WritableProxy } from "../../node/modules/stream"; + +export class Writable extends ClientProxy implements stream.Writable { + public get writable(): boolean { + throw new Error("not implemented"); + } + + public get writableHighWaterMark(): number { + throw new Error("not implemented"); + } + + public get writableLength(): number { + throw new Error("not implemented"); + } + + public _write(): void { + throw new Error("not implemented"); + } + + public _destroy(): void { + throw new Error("not implemented"); + } + + public _final(): void { + throw new Error("not implemented"); + } + + public pipe(): T { + throw new Error("not implemented"); + } + + public cork(): void { + throw new Error("not implemented"); + } + + public uncork(): void { + throw new Error("not implemented"); + } + + public destroy(): void { + this.proxy.destroy(); + } + + public setDefaultEncoding(encoding: string): this { + this.proxy.setDefaultEncoding(encoding); + + return this; + } + + // tslint:disable-next-line no-any + public write(chunk: any, encoding?: string | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean { + if (typeof encoding === "function") { + callback = encoding; + encoding = undefined; + } + callbackify(this.proxy.write)(chunk, encoding, (error) => { + if (callback) { + callback(error); + } + }); + + return true; // Always true since we can't get this synchronously. + } + + // tslint:disable-next-line no-any + public end(data?: any | (() => void), encoding?: string | (() => void), callback?: (() => void)): void { + if (typeof data === "function") { + callback = data; + data = undefined; + } + if (typeof encoding === "function") { + callback = encoding; + encoding = undefined; + } + callbackify(this.proxy.end)(data, encoding, () => { + if (callback) { + callback(); + } + }); + } +} + +export class Readable extends ClientProxy implements stream.Readable { + public get readable(): boolean { + throw new Error("not implemented"); + } + + public get readableHighWaterMark(): number { + throw new Error("not implemented"); + } + + public get readableLength(): number { + throw new Error("not implemented"); + } + + public _read(): void { + throw new Error("not implemented"); + } + + public read(): void { + throw new Error("not implemented"); + } + + public _destroy(): void { + throw new Error("not implemented"); + } + + public unpipe(): this { + throw new Error("not implemented"); + } + + public pause(): this { + throw new Error("not implemented"); + } + + public resume(): this { + throw new Error("not implemented"); + } + + public isPaused(): boolean { + throw new Error("not implemented"); + } + + public wrap(): this { + throw new Error("not implemented"); + } + + public push(): boolean { + throw new Error("not implemented"); + } + + public unshift(): void { + throw new Error("not implemented"); + } + + public pipe(): T { + throw new Error("not implemented"); + } + + // tslint:disable-next-line no-any + public [Symbol.asyncIterator](): AsyncIterableIterator { + throw new Error("not implemented"); + } + + public destroy(): void { + this.proxy.destroy(); + } + + public setEncoding(encoding: string): this { + this.proxy.setEncoding(encoding); + + return this; + } +} + +export class Duplex extends Writable implements stream.Duplex, stream.Readable { + private readonly _readable: Readable; + + public constructor(proxyPromise: Promise | T) { + super(proxyPromise); + this._readable = new Readable(proxyPromise, false); + } + + public get readable(): boolean { + return this._readable.readable; + } + + public get readableHighWaterMark(): number { + return this._readable.readableHighWaterMark; + } + + public get readableLength(): number { + return this._readable.readableLength; + } + + public _read(): void { + this._readable._read(); + } + + public read(): void { + this._readable.read(); + } + + public unpipe(): this { + this._readable.unpipe(); + + return this; + } + + public pause(): this { + this._readable.unpipe(); + + return this; + } + + public resume(): this { + this._readable.resume(); + + return this; + } + + public isPaused(): boolean { + return this._readable.isPaused(); + } + + public wrap(): this { + this._readable.wrap(); + + return this; + } + + public push(): boolean { + return this._readable.push(); + } + + public unshift(): void { + this._readable.unshift(); + } + + // tslint:disable-next-line no-any + public [Symbol.asyncIterator](): AsyncIterableIterator { + return this._readable[Symbol.asyncIterator](); + } + + public setEncoding(encoding: string): this { + this.proxy.setEncoding(encoding); + + return this; + } +} diff --git a/packages/protocol/src/browser/modules/trash.ts b/packages/protocol/src/browser/modules/trash.ts new file mode 100644 index 00000000..d555126d --- /dev/null +++ b/packages/protocol/src/browser/modules/trash.ts @@ -0,0 +1,10 @@ +import * as trash from "trash"; +import { TrashModuleProxy } from "../../node/modules/trash"; + +export class TrashModule { + public constructor(private readonly proxy: TrashModuleProxy) {} + + public trash = (path: string, options?: trash.Options): Promise => { + return this.proxy.trash(path, options); + } +} diff --git a/packages/protocol/src/common/connection.ts b/packages/protocol/src/common/connection.ts index 06e255dc..0c53817a 100644 --- a/packages/protocol/src/common/connection.ts +++ b/packages/protocol/src/common/connection.ts @@ -5,6 +5,8 @@ export interface SendableConnection { export interface ReadWriteConnection extends SendableConnection { onMessage(cb: (data: Uint8Array | Buffer) => void): void; onClose(cb: () => void): void; + onDown(cb: () => void): void; + onUp(cb: () => void): void; close(): void; } diff --git a/packages/protocol/src/common/helpers.ts b/packages/protocol/src/common/helpers.ts deleted file mode 100644 index ebcb3b10..00000000 --- a/packages/protocol/src/common/helpers.ts +++ /dev/null @@ -1,422 +0,0 @@ -/// -/// -import { ChildProcess, SpawnOptions, ForkOptions } from "child_process"; -import { EventEmitter } from "events"; -import { Socket } from "net"; -import { Duplex, Readable, Writable } from "stream"; -import { IDisposable } from "@coder/disposable"; -import { logger } from "@coder/logger"; - -// tslint:disable no-any - -export type ForkProvider = (modulePath: string, args: string[], options: ForkOptions) => ChildProcess; - -export interface Disposer extends IDisposable { - onDidDispose: (cb: () => void) => void; -} - -interface ActiveEvalEmitter { - removeAllListeners(event?: string): void; - emit(event: string, ...args: any[]): void; - on(event: string, cb: (...args: any[]) => void): void; -} - -/** - * For any non-external modules that are not built in, we need to require and - * access them server-side. A require on the client-side won't work since that - * code won't exist on the server (and bloat the client with an unused import), - * and we can't manually import on the server-side and then call - * `__webpack_require__` on the client-side because Webpack stores modules by - * their paths which would require us to hard-code the path. - */ -export interface Modules { - pty: typeof import("node-pty"); - spdlog: typeof import("spdlog"); - trash: typeof import("trash"); -} - -/** - * Helper class for server-side evaluations. - */ -export class EvalHelper { - public constructor(public modules: Modules) {} - - /** - * Some spawn code tries to preserve the env (the debug adapter for instance) - * but the env is mostly blank (since we're in the browser), so we'll just - * always preserve the main process.env here, otherwise it won't have access - * to PATH, etc. - * TODO: An alternative solution would be to send the env to the browser? - */ - public preserveEnv(options: SpawnOptions | ForkOptions): void { - if (options && options.env) { - options.env = { ...process.env, ...options.env }; - } - } -} - -/** - * Helper class for client-side active evaluations. - */ -export class ActiveEvalHelper implements ActiveEvalEmitter { - public constructor(private readonly emitter: ActiveEvalEmitter) {} - - public removeAllListeners(event?: string): void { - this.emitter.removeAllListeners(event); - } - - public emit(event: string, ...args: any[]): void { - this.emitter.emit(event, ...args); - } - - public on(event: string, cb: (...args: any[]) => void): void { - this.emitter.on(event, cb); - } - - /** - * Create a new helper to make unique events for an item. - */ - public createUnique(id: number | "stdout" | "stderr" | "stdin"): ActiveEvalHelper { - return new ActiveEvalHelper(this.createUniqueEmitter(id)); - } - - /** - * Wrap the evaluation emitter to make unique events for an item to prevent - * conflicts when it shares that emitter with other items. - */ - protected createUniqueEmitter(id: number | "stdout" | "stderr" | "stdin"): ActiveEvalEmitter { - let events = []; - - return { - removeAllListeners: (event?: string): void => { - if (!event) { - events.forEach((e) => this.removeAllListeners(e)); - events = []; - } else { - const index = events.indexOf(event); - if (index !== -1) { - events.splice(index, 1); - this.removeAllListeners(`${event}:${id}`); - } - } - }, - emit: (event: string, ...args: any[]): void => { - this.emit(`${event}:${id}`, ...args); - }, - on: (event: string, cb: (...args: any[]) => void): void => { - if (!events.includes(event)) { - events.push(event); - } - this.on(`${event}:${id}`, cb); - }, - }; - } -} - -/** - * Helper class for server-side active evaluations. - */ -export class ServerActiveEvalHelper extends ActiveEvalHelper implements EvalHelper { - private readonly evalHelper: EvalHelper; - - public constructor(public modules: Modules, emitter: ActiveEvalEmitter, public readonly fork: ForkProvider) { - super(emitter); - this.evalHelper = new EvalHelper(modules); - } - - public preserveEnv(options: SpawnOptions | ForkOptions): void { - this.evalHelper.preserveEnv(options); - } - - /** - * If there is a callback ID, return a function that emits the callback event - * on the active evaluation with that ID and all arguments passed to it. - * Otherwise, return undefined. - */ - public maybeCallback(callbackId?: number): ((...args: any[]) => void) | undefined { - return typeof callbackId !== "undefined" ? (...args: any[]): void => { - this.emit("callback", callbackId, ...args); - } : undefined; - } - - /** - * Bind a socket to an active evaluation and returns a disposer. - */ - public bindSocket(socket: Socket): Disposer { - socket.on("connect", () => this.emit("connect")); - socket.on("lookup", (error, address, family, host) => this.emit("lookup", error, address, family, host)); - socket.on("timeout", () => this.emit("timeout")); - - this.on("connect", (options, callbackId) => socket.connect(options, this.maybeCallback(callbackId))); - this.on("ref", () => socket.ref()); - this.on("setKeepAlive", (enable, initialDelay) => socket.setKeepAlive(enable, initialDelay)); - this.on("setNoDelay", (noDelay) => socket.setNoDelay(noDelay)); - this.on("setTimeout", (timeout, callbackId) => socket.setTimeout(timeout, this.maybeCallback(callbackId))); - this.on("unref", () => socket.unref()); - - this.bindReadable(socket); - this.bindWritable(socket); - - return { - onDidDispose: (cb): Socket => socket.on("close", cb), - dispose: (): void => { - socket.removeAllListeners(); - socket.end(); - socket.destroy(); - socket.unref(); - }, - }; - } - - /** - * Bind a writable stream to the active evaluation. - */ - public bindWritable(writable: Writable | Duplex): void { - if (!((writable as Readable).read)) { // To avoid binding twice. - writable.on("close", () => this.emit("close")); - writable.on("error", (error) => this.emit("error", error)); - - this.on("destroy", () => writable.destroy()); - } - - writable.on("drain", () => this.emit("drain")); - writable.on("finish", () => this.emit("finish")); - writable.on("pipe", () => this.emit("pipe")); - writable.on("unpipe", () => this.emit("unpipe")); - - this.on("cork", () => writable.cork()); - this.on("end", (chunk, encoding, callbackId) => writable.end(chunk, encoding, this.maybeCallback(callbackId))); - this.on("setDefaultEncoding", (encoding) => writable.setDefaultEncoding(encoding)); - this.on("uncork", () => writable.uncork()); - // Sockets can pass an fd instead of a callback but streams cannot. - this.on("write", (chunk, encoding, fd, callbackId) => writable.write(chunk, encoding, this.maybeCallback(callbackId) || fd)); - } - - /** - * Bind a readable stream to the active evaluation. - */ - public bindReadable(readable: Readable): void { - // Streams don't have an argument on close but sockets do. - readable.on("close", (...args: any[]) => this.emit("close", ...args)); - readable.on("data", (data) => this.emit("data", data)); - readable.on("end", () => this.emit("end")); - readable.on("error", (error) => this.emit("error", error)); - readable.on("readable", () => this.emit("readable")); - - this.on("destroy", () => readable.destroy()); - this.on("pause", () => readable.pause()); - this.on("push", (chunk, encoding) => readable.push(chunk, encoding)); - this.on("resume", () => readable.resume()); - this.on("setEncoding", (encoding) => readable.setEncoding(encoding)); - this.on("unshift", (chunk) => readable.unshift(chunk)); - } - - public createUnique(id: number | "stdout" | "stderr" | "stdin"): ServerActiveEvalHelper { - return new ServerActiveEvalHelper(this.modules, this.createUniqueEmitter(id), this.fork); - } -} - -/** - * An event emitter that can store callbacks with IDs in a map so we can pass - * them back and forth through an active evaluation using those IDs. - */ -export class CallbackEmitter extends EventEmitter { - private _ae: ActiveEvalHelper | undefined; - private callbackId = 0; - private readonly callbacks = new Map(); - - public constructor(ae?: ActiveEvalHelper) { - super(); - if (ae) { - this.ae = ae; - } - } - - protected get ae(): ActiveEvalHelper { - if (!this._ae) { - throw new Error("trying to access active evaluation before it has been set"); - } - - return this._ae; - } - - protected set ae(ae: ActiveEvalHelper) { - if (this._ae) { - throw new Error("cannot override active evaluation"); - } - this._ae = ae; - this.ae.on("callback", (callbackId, ...args: any[]) => this.runCallback(callbackId, ...args)); - } - - /** - * Store the callback and return and ID referencing its location in the map. - */ - protected storeCallback(callback?: Function): number | undefined { - if (!callback) { - return undefined; - } - - const callbackId = this.callbackId++; - this.callbacks.set(callbackId, callback); - - return callbackId; - } - - /** - * Call the function with the specified ID and delete it from the map. - * If the ID is undefined or doesn't exist, nothing happens. - */ - private runCallback(callbackId?: number, ...args: any[]): void { - const callback = typeof callbackId !== "undefined" && this.callbacks.get(callbackId); - if (callback && typeof callbackId !== "undefined") { - this.callbacks.delete(callbackId); - callback(...args); - } - } -} - -/** - * A writable stream over an active evaluation. - */ -export class ActiveEvalWritable extends CallbackEmitter implements Writable { - public constructor(ae: ActiveEvalHelper) { - super(ae); - // Streams don't have an argument on close but sockets do. - this.ae.on("close", (...args: any[]) => this.emit("close", ...args)); - this.ae.on("drain", () => this.emit("drain")); - this.ae.on("error", (error) => this.emit("error", error)); - this.ae.on("finish", () => this.emit("finish")); - this.ae.on("pipe", () => logger.warn("pipe is not supported")); - this.ae.on("unpipe", () => logger.warn("unpipe is not supported")); - } - - public get writable(): boolean { throw new Error("not implemented"); } - public get writableHighWaterMark(): number { throw new Error("not implemented"); } - public get writableLength(): number { throw new Error("not implemented"); } - public _write(): void { throw new Error("not implemented"); } - public _destroy(): void { throw new Error("not implemented"); } - public _final(): void { throw new Error("not implemented"); } - public pipe(): T { throw new Error("not implemented"); } - - public cork(): void { this.ae.emit("cork"); } - public destroy(): void { this.ae.emit("destroy"); } - public setDefaultEncoding(encoding: string): this { - this.ae.emit("setDefaultEncoding", encoding); - - return this; - } - public uncork(): void { this.ae.emit("uncork"); } - - public write(chunk: any, encoding?: string | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean { - if (typeof encoding === "function") { - callback = encoding; - encoding = undefined; - } - - // Sockets can pass an fd instead of a callback but streams cannot.. - this.ae.emit("write", chunk, encoding, undefined, this.storeCallback(callback)); - - // Always true since we can't get this synchronously. - return true; - } - - public end(data?: any, encoding?: string | Function, callback?: Function): void { - if (typeof encoding === "function") { - callback = encoding; - encoding = undefined; - } - this.ae.emit("end", data, encoding, this.storeCallback(callback)); - } -} - -/** - * A readable stream over an active evaluation. - */ -export class ActiveEvalReadable extends CallbackEmitter implements Readable { - public constructor(ae: ActiveEvalHelper) { - super(ae); - this.ae.on("close", () => this.emit("close")); - this.ae.on("data", (data) => this.emit("data", data)); - this.ae.on("end", () => this.emit("end")); - this.ae.on("error", (error) => this.emit("error", error)); - this.ae.on("readable", () => this.emit("readable")); - } - - public get readable(): boolean { throw new Error("not implemented"); } - public get readableHighWaterMark(): number { throw new Error("not implemented"); } - public get readableLength(): number { throw new Error("not implemented"); } - public _read(): void { throw new Error("not implemented"); } - public read(): any { throw new Error("not implemented"); } - public isPaused(): boolean { throw new Error("not implemented"); } - public pipe(): T { throw new Error("not implemented"); } - public unpipe(): this { throw new Error("not implemented"); } - public unshift(): this { throw new Error("not implemented"); } - public wrap(): this { throw new Error("not implemented"); } - public push(): boolean { throw new Error("not implemented"); } - public _destroy(): void { throw new Error("not implemented"); } - public [Symbol.asyncIterator](): AsyncIterableIterator { throw new Error("not implemented"); } - - public destroy(): void { this.ae.emit("destroy"); } - public pause(): this { return this.emitReturnThis("pause"); } - public resume(): this { return this.emitReturnThis("resume"); } - public setEncoding(encoding?: string): this { return this.emitReturnThis("setEncoding", encoding); } - - // tslint:disable-next-line no-any - protected emitReturnThis(event: string, ...args: any[]): this { - this.ae.emit(event, ...args); - - return this; - } -} - -/** - * An duplex stream over an active evaluation. - */ -export class ActiveEvalDuplex extends ActiveEvalReadable implements Duplex { - // Some unfortunate duplication here since we can't have multiple extends. - public constructor(ae: ActiveEvalHelper) { - super(ae); - this.ae.on("drain", () => this.emit("drain")); - this.ae.on("finish", () => this.emit("finish")); - this.ae.on("pipe", () => logger.warn("pipe is not supported")); - this.ae.on("unpipe", () => logger.warn("unpipe is not supported")); - } - - public get writable(): boolean { throw new Error("not implemented"); } - public get writableHighWaterMark(): number { throw new Error("not implemented"); } - public get writableLength(): number { throw new Error("not implemented"); } - public _write(): void { throw new Error("not implemented"); } - public _destroy(): void { throw new Error("not implemented"); } - public _final(): void { throw new Error("not implemented"); } - public pipe(): T { throw new Error("not implemented"); } - - public cork(): void { this.ae.emit("cork"); } - public destroy(): void { this.ae.emit("destroy"); } - public setDefaultEncoding(encoding: string): this { - this.ae.emit("setDefaultEncoding", encoding); - - return this; - } - public uncork(): void { this.ae.emit("uncork"); } - - public write(chunk: any, encoding?: string | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean { - if (typeof encoding === "function") { - callback = encoding; - encoding = undefined; - } - - // Sockets can pass an fd instead of a callback but streams cannot.. - this.ae.emit("write", chunk, encoding, undefined, this.storeCallback(callback)); - - // Always true since we can't get this synchronously. - return true; - } - - public end(data?: any, encoding?: string | Function, callback?: Function): void { - if (typeof encoding === "function") { - callback = encoding; - encoding = undefined; - } - this.ae.emit("end", data, encoding, this.storeCallback(callback)); - } -} diff --git a/packages/protocol/src/common/proxy.ts b/packages/protocol/src/common/proxy.ts new file mode 100644 index 00000000..dd0feda2 --- /dev/null +++ b/packages/protocol/src/common/proxy.ts @@ -0,0 +1,83 @@ +import { EventEmitter } from "events"; +import { isPromise } from "./util"; + +// tslint:disable no-any + +/** + * Allow using a proxy like it's returned synchronously. This only works because + * all proxy methods return promises. + */ +const unpromisify = (proxyPromise: Promise): T => { + return new Proxy({}, { + get: (target: any, name: string): any => { + if (typeof target[name] === "undefined") { + target[name] = async (...args: any[]): Promise => { + const proxy = await proxyPromise; + + return proxy ? (proxy as any)[name](...args) : undefined; + }; + } + + return target[name]; + }, + }); +}; + +/** + * Client-side emitter that just forwards proxy events to its own emitter. + * It also turns a promisified proxy into a non-promisified proxy so we don't + * need a bunch of `then` calls everywhere. + */ +export abstract class ClientProxy extends EventEmitter { + protected readonly proxy: T; + + /** + * You can specify not to bind events in order to avoid emitting twice for + * duplex streams. + */ + public constructor(proxyPromise: Promise | T, bindEvents: boolean = true) { + super(); + this.proxy = isPromise(proxyPromise) ? unpromisify(proxyPromise) : proxyPromise; + if (bindEvents) { + this.proxy.onEvent((event, ...args): void => { + this.emit(event, ...args); + }); + } + } +} + +/** + * Proxy to the actual instance on the server. Every method must only accept + * serializable arguments and must return promises with serializable values. If + * a proxy itself has proxies on creation (like how ChildProcess has stdin), + * then it should return all of those at once, otherwise you will miss events + * from those child proxies and fail to dispose them properly. + */ +export interface ServerProxy { + dispose(): Promise; + + /** + * This is used instead of an event to force it to be implemented since there + * would be no guarantee the implementation would remember to emit the event. + */ + onDone(cb: () => void): Promise; + + /** + * Listen to all possible events. On the client, this is to reduce boilerplate + * that would just be a bunch of error-prone forwarding of each individual + * event from the proxy to its own emitter. It also fixes a timing issue + * because we just always send all events from the server, so we never miss + * any due to listening too late. + */ + // tslint:disable-next-line no-any + onEvent(cb: (event: string, ...args: any[]) => void): Promise; +} + +export enum Module { + Fs = "fs", + ChildProcess = "child_process", + Net = "net", + Spdlog = "spdlog", + NodePty = "node-pty", + Trash = "trash", +} diff --git a/packages/protocol/src/common/util.ts b/packages/protocol/src/common/util.ts index 45ff225a..f1ba5e5d 100644 --- a/packages/protocol/src/common/util.ts +++ b/packages/protocol/src/common/util.ts @@ -1,3 +1,9 @@ +import { Module as ProtoModule, WorkingInitMessage } from "../proto"; +import { OperatingSystem } from "../common/connection"; +import { Module, ServerProxy } from "./proxy"; + +// tslint:disable no-any + /** * Return true if we're in a browser environment (including web workers). */ @@ -14,86 +20,294 @@ export const escapePath = (path: string): string => { }; export type IEncodingOptions = { - encoding?: string | null; + encoding?: BufferEncoding | null; flag?: string; mode?: string; persistent?: boolean; recursive?: boolean; -} | string | undefined | null; +} | BufferEncoding | undefined | null; -// tslint:disable-next-line no-any export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoException, ...args: any[]) => void); -/** - * Stringify an event argument. isError is because although methods like - * `fs.stat` are supposed to throw Error objects, they currently throw regular - * objects when running tests through Jest. - */ -export const stringify = (arg: any, isError?: boolean): string => { // tslint:disable-line no-any - if (arg instanceof Error || isError) { - // Errors don't stringify at all. They just become "{}". - return JSON.stringify({ - type: "Error", - data: { - message: arg.message, - stack: arg.stack, - code: (arg as NodeJS.ErrnoException).code, - }, - }); - } else if (arg instanceof Uint8Array) { - // With stringify, these get turned into objects with each index becoming a - // key for some reason. Then trying to do something like write that data - // results in [object Object] being written. Stringify them like a Buffer - // instead. - return JSON.stringify({ - type: "Buffer", - data: Array.from(arg), - }); - } +interface StringifiedError { + type: "error"; + data: { + message: string; + stack?: string; + code?: string; + }; +} - return JSON.stringify(arg); +interface StringifiedBuffer { + type: "buffer"; + data: number[]; +} + +interface StringifiedObject { + type: "object"; + data: { [key: string]: StringifiedValue }; +} + +interface StringifiedArray { + type: "array"; + data: StringifiedValue[]; +} + +interface StringifiedProxy { + type: "proxy"; + data: { + id: number; + }; +} + +interface StringifiedFunction { + type: "function"; + data: { + id: number; + }; +} + +interface StringifiedUndefined { + type: "undefined"; +} + +type StringifiedValue = StringifiedFunction | StringifiedProxy + | StringifiedUndefined | StringifiedObject | StringifiedArray + | StringifiedBuffer | StringifiedError | number | string | boolean | null; + +const isPrimitive = (value: any): value is number | string | boolean | null => { + return typeof value === "number" + || typeof value === "string" + || typeof value === "boolean" + || value === null; }; -/** - * Parse an event argument. - */ -export const parse = (arg: string): any => { // tslint:disable-line no-any - const convert = (value: any): any => { // tslint:disable-line no-any - if (value && value.data && value.type) { - switch (value.type) { - // JSON.stringify turns a Buffer into an object but JSON.parse doesn't - // turn it back, it just remains an object. - case "Buffer": - if (Array.isArray(value.data)) { - return Buffer.from(value); - } - break; - // Errors apparently can't be stringified, so we do something similar to - // what happens to buffers and stringify them as regular objects. - case "Error": - if (value.data.message) { - const error = new Error(value.data.message); - // TODO: Can we set the stack? Doing so seems to make it into an - // "invalid object". - if (typeof value.data.code !== "undefined") { - (error as NodeJS.ErrnoException).code = value.data.code; - } - // tslint:disable-next-line no-any - (error as any).originalStack = value.data.stack; - return error; - } - break; +/** + * Stringify an argument or a return value. + * If sending a function is possible, provide `storeFunction`. + * If sending a proxy is possible, provide `storeProxy`. + */ +export const stringify = ( + value: any, + storeFunction?: (fn: () => void) => number, + storeProxy?: (proxy: ServerProxy) => number, +): string => { + const convert = (currentValue: any): StringifiedValue => { + // Errors don't stringify at all. They just become "{}". + // For some reason when running in Jest errors aren't instances of Error, + // so also check against the values. + if (currentValue instanceof Error + || (currentValue && typeof currentValue.message !== "undefined" + && typeof currentValue.stack !== "undefined")) { + return { + type: "error", + data: { + message: currentValue.message, + stack: currentValue.stack, + code: (currentValue as NodeJS.ErrnoException).code, + }, + }; + } + + // With stringify, Uint8Array gets turned into objects with each index + // becoming a key for some reason. Then trying to do something like write + // that data results in [object Object] being written. Stringify them like + // a Buffer instead. Also handle Buffer so it doesn't get caught by the + // object check and to get the same type. + if (currentValue instanceof Uint8Array || currentValue instanceof Buffer) { + return { + type: "buffer", + data: Array.from(currentValue), + }; + } + + if (Array.isArray(currentValue)) { + return { + type: "array", + data: currentValue.map((a) => convert(a)), + }; + } + + if (isProxy(currentValue)) { + if (!storeProxy) { + throw new Error("no way to serialize proxy"); + } + + return { + type: "proxy", + data: { + id: storeProxy(currentValue), + }, + }; + } + + if (currentValue !== null && typeof currentValue === "object") { + const converted: { [key: string]: StringifiedValue } = {}; + Object.keys(currentValue).forEach((key) => { + converted[key] = convert(currentValue[key]); + }); + + return { + type: "object", + data: converted, + }; + } + + // `undefined` can't be stringified. + if (typeof currentValue === "undefined") { + return { + type: "undefined", + }; + } + + if (typeof currentValue === "function") { + if (!storeFunction) { + throw new Error("no way to serialize function"); + } + + return { + type: "function", + data: { + id: storeFunction(currentValue), + }, + }; + } + + if (!isPrimitive(currentValue)) { + throw new Error(`cannot stringify ${typeof currentValue}`); + } + + return currentValue; + }; + + return JSON.stringify(convert(value)); +}; + +/** + * Parse an argument. + * If running a remote callback is supported, provide `runCallback`. + * If using a remote proxy is supported, provide `createProxy`. + */ +export const parse = ( + value?: string, + runCallback?: (id: number, args: any[]) => void, + createProxy?: (id: number) => ServerProxy, +): any => { + const convert = (currentValue: StringifiedValue): any => { + if (currentValue && !isPrimitive(currentValue)) { + // Would prefer a switch but the types don't seem to work. + if (currentValue.type === "buffer") { + return Buffer.from(currentValue.data); + } + + if (currentValue.type === "error") { + const error = new Error(currentValue.data.message); + if (typeof currentValue.data.code !== "undefined") { + (error as NodeJS.ErrnoException).code = currentValue.data.code; + } + (error as any).originalStack = currentValue.data.stack; + + return error; + } + + if (currentValue.type === "object") { + const converted: { [key: string]: any } = {}; + Object.keys(currentValue.data).forEach((key) => { + converted[key] = convert(currentValue.data[key]); + }); + + return converted; + } + + if (currentValue.type === "array") { + return currentValue.data.map(convert); + } + + if (currentValue.type === "undefined") { + return undefined; + } + + if (currentValue.type === "function") { + if (!runCallback) { + throw new Error("no way to run remote callback"); + } + + return (...args: any[]): void => { + return runCallback(currentValue.data.id, args); + }; + } + + if (currentValue.type === "proxy") { + if (!createProxy) { + throw new Error("no way to create proxy"); + } + + return createProxy(currentValue.data.id); } } - if (value && typeof value === "object") { - Object.keys(value).forEach((key) => { - value[key] = convert(value[key]); - }); - } - - return value; + return currentValue; }; - return arg ? convert(JSON.parse(arg)) : arg; + return value && convert(JSON.parse(value)); +}; + +export const protoToModule = (protoModule: ProtoModule): Module => { + switch (protoModule) { + case ProtoModule.CHILDPROCESS: return Module.ChildProcess; + case ProtoModule.FS: return Module.Fs; + case ProtoModule.NET: return Module.Net; + case ProtoModule.NODEPTY: return Module.NodePty; + case ProtoModule.SPDLOG: return Module.Spdlog; + case ProtoModule.TRASH: return Module.Trash; + default: throw new Error(`invalid module ${protoModule}`); + } +}; + +export const moduleToProto = (moduleName: Module): ProtoModule => { + switch (moduleName) { + case Module.ChildProcess: return ProtoModule.CHILDPROCESS; + case Module.Fs: return ProtoModule.FS; + case Module.Net: return ProtoModule.NET; + case Module.NodePty: return ProtoModule.NODEPTY; + case Module.Spdlog: return ProtoModule.SPDLOG; + case Module.Trash: return ProtoModule.TRASH; + default: throw new Error(`invalid module "${moduleName}"`); + } +}; + +export const protoToOperatingSystem = (protoOp: WorkingInitMessage.OperatingSystem): OperatingSystem => { + switch (protoOp) { + case WorkingInitMessage.OperatingSystem.WINDOWS: return OperatingSystem.Windows; + case WorkingInitMessage.OperatingSystem.LINUX: return OperatingSystem.Linux; + case WorkingInitMessage.OperatingSystem.MAC: return OperatingSystem.Mac; + default: throw new Error(`unsupported operating system ${protoOp}`); + } +}; + +export const platformToProto = (platform: NodeJS.Platform): WorkingInitMessage.OperatingSystem => { + switch (platform) { + case "win32": return WorkingInitMessage.OperatingSystem.WINDOWS; + case "linux": return WorkingInitMessage.OperatingSystem.LINUX; + case "darwin": return WorkingInitMessage.OperatingSystem.MAC; + default: throw new Error(`unrecognized platform "${platform}"`); + } +}; + +export const isProxy = (value: any): value is ServerProxy => { + return value && typeof value === "object" && typeof value.onEvent === "function"; +}; + +export const isPromise = (value: any): value is Promise => { + return typeof value.then === "function" && typeof value.catch === "function"; +}; + +/** + * When spawning VS Code tries to preserve the environment but since it's in + * the browser, it doesn't work. + */ +export const preserveEnv = (options?: { env?: NodeJS.ProcessEnv } | null): void => { + if (options && options.env) { + options.env = { ...process.env, ...options.env }; + } }; diff --git a/packages/protocol/src/index.ts b/packages/protocol/src/index.ts index 6d293bd2..b118df39 100644 --- a/packages/protocol/src/index.ts +++ b/packages/protocol/src/index.ts @@ -1,4 +1,4 @@ export * from "./browser/client"; export * from "./common/connection"; -export * from "./common/helpers"; +export * from "./common/proxy"; export * from "./common/util"; diff --git a/packages/protocol/src/node/evaluate.ts b/packages/protocol/src/node/evaluate.ts deleted file mode 100644 index 5a7f70d3..00000000 --- a/packages/protocol/src/node/evaluate.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { fork as cpFork } from "child_process"; -import { EventEmitter } from "events"; -import * as vm from "vm"; -import { logger, field } from "@coder/logger"; -import { NewEvalMessage, EvalFailedMessage, EvalDoneMessage, ServerMessage, EvalEventMessage } from "../proto"; -import { SendableConnection } from "../common/connection"; -import { ServerActiveEvalHelper, EvalHelper, ForkProvider, Modules } from "../common/helpers"; -import { stringify, parse } from "../common/util"; - -export interface ActiveEvaluation { - onEvent(msg: EvalEventMessage): void; - dispose(): void; -} - -declare var __non_webpack_require__: typeof require; -export const evaluate = (connection: SendableConnection, message: NewEvalMessage, onDispose: () => void, fork?: ForkProvider): ActiveEvaluation | void => { - /** - * Send the response and call onDispose. - */ - // tslint:disable-next-line no-any - const sendResp = (resp: any): void => { - logger.trace(() => [ - "resolve", - field("id", message.getId()), - field("response", stringify(resp)), - ]); - - const evalDone = new EvalDoneMessage(); - evalDone.setId(message.getId()); - evalDone.setResponse(stringify(resp)); - - const serverMsg = new ServerMessage(); - serverMsg.setEvalDone(evalDone); - connection.send(serverMsg.serializeBinary()); - - onDispose(); - }; - - /** - * Send an exception and call onDispose. - */ - const sendException = (error: Error): void => { - logger.trace(() => [ - "reject", - field("id", message.getId()), - field("response", stringify(error, true)), - ]); - - const evalFailed = new EvalFailedMessage(); - evalFailed.setId(message.getId()); - evalFailed.setResponse(stringify(error, true)); - - const serverMsg = new ServerMessage(); - serverMsg.setEvalFailed(evalFailed); - connection.send(serverMsg.serializeBinary()); - - onDispose(); - }; - - const modules: Modules = { - spdlog: require("spdlog"), - pty: require("node-pty-prebuilt"), - trash: require("trash"), - }; - - let eventEmitter = message.getActive() ? new EventEmitter(): undefined; - const sandbox = { - helper: eventEmitter ? new ServerActiveEvalHelper(modules, { - removeAllListeners: (event?: string): void => { - eventEmitter!.removeAllListeners(event); - }, - // tslint:disable no-any - on: (event: string, cb: (...args: any[]) => void): void => { - eventEmitter!.on(event, (...args: any[]) => { - logger.trace(() => [ - `${event}`, - field("id", message.getId()), - field("args", args.map((a) => stringify(a))), - ]); - cb(...args); - }); - }, - emit: (event: string, ...args: any[]): void => { - logger.trace(() => [ - `emit ${event}`, - field("id", message.getId()), - field("args", args.map((a) => stringify(a))), - ]); - const eventMsg = new EvalEventMessage(); - eventMsg.setEvent(event); - eventMsg.setArgsList(args.map((a) => stringify(a))); - eventMsg.setId(message.getId()); - const serverMsg = new ServerMessage(); - serverMsg.setEvalEvent(eventMsg); - connection.send(serverMsg.serializeBinary()); - }, - // tslint:enable no-any - }, fork || cpFork) : new EvalHelper(modules), - _Buffer: Buffer, - // When the client is ran from Webpack, it will replace - // __non_webpack_require__ with require, which we then need to provide to - // the sandbox. Since the server might also be using Webpack, we need to set - // it to the non-Webpack version when that's the case. Then we need to also - // provide __non_webpack_require__ for when the client doesn't run through - // Webpack meaning it doesn't get replaced with require (Jest for example). - require: typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require, - __non_webpack_require__: typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require, - setTimeout, - setInterval, - clearTimeout, - process: { - env: process.env, - }, - args: message.getArgsList().map(parse), - }; - - let value: any; // tslint:disable-line no-any - try { - const code = `(${message.getFunction()})(helper, ...args);`; - value = vm.runInNewContext(code, sandbox, { - // If the code takes longer than this to return, it is killed and throws. - timeout: message.getTimeout() || 15000, - }); - } catch (ex) { - sendException(ex); - } - - // An evaluation completes when the value it returns resolves. An active - // evaluation completes when it is disposed. Active evaluations are required - // to return disposers so we can know both when it has ended (so we can clean - // up on our end) and how to force end it (for example when the client - // disconnects). - // tslint:disable-next-line no-any - const promise = !eventEmitter ? value as Promise : new Promise((resolve): void => { - value.onDidDispose(resolve); - }); - if (promise && promise.then) { - promise.then(sendResp).catch(sendException); - } else { - sendResp(value); - } - - return eventEmitter ? { - onEvent: (eventMsg: EvalEventMessage): void => { - eventEmitter!.emit(eventMsg.getEvent(), ...eventMsg.getArgsList().map(parse)); - }, - dispose: (): void => { - if (eventEmitter) { - if (value && value.dispose) { - value.dispose(); - } - eventEmitter.removeAllListeners(); - eventEmitter = undefined; - } - }, - } : undefined; -}; diff --git a/packages/protocol/src/node/modules/child_process.ts b/packages/protocol/src/node/modules/child_process.ts new file mode 100644 index 00000000..fbf45200 --- /dev/null +++ b/packages/protocol/src/node/modules/child_process.ts @@ -0,0 +1,103 @@ +import * as cp from "child_process"; +import { ServerProxy } from "../../common/proxy"; +import { preserveEnv } from "../../common/util"; +import { WritableProxy, ReadableProxy } from "./stream"; + +export type ForkProvider = (modulePath: string, args?: string[], options?: cp.ForkOptions) => cp.ChildProcess; + +export class ChildProcessProxy implements ServerProxy { + public constructor(private readonly process: cp.ChildProcess) {} + + public async kill(signal?: string): Promise { + this.process.kill(signal); + } + + public async disconnect(): Promise { + this.process.disconnect(); + } + + public async ref(): Promise { + this.process.ref(); + } + + public async unref(): Promise { + this.process.unref(); + } + + // tslint:disable-next-line no-any + public async send(message: any): Promise { + return new Promise((resolve, reject) => { + this.process.send(message, (error) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); + } + + public async getPid(): Promise { + return this.process.pid; + } + + public async onDone(cb: () => void): Promise { + this.process.on("close", cb); + } + + public async dispose(): Promise { + this.kill(); + setTimeout(() => this.kill("SIGKILL"), 5000); // Double tap. + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + this.process.on("close", (code, signal) => cb("close", code, signal)); + this.process.on("disconnect", () => cb("disconnect")); + this.process.on("error", (error) => cb("error", error)); + this.process.on("exit", (exitCode, signal) => cb("exit", exitCode, signal)); + this.process.on("message", (message) => cb("message", message)); + } +} + +export interface ChildProcessProxies { + childProcess: ChildProcessProxy; + stdin?: WritableProxy; + stdout?: ReadableProxy; + stderr?: ReadableProxy; +} + +export class ChildProcessModuleProxy { + public constructor(private readonly forkProvider?: ForkProvider) {} + + public async exec( + command: string, + options?: { encoding?: string | null } & cp.ExecOptions | null, + callback?: ((error: cp.ExecException | null, stdin: string | Buffer, stdout: string | Buffer) => void), + ): Promise { + preserveEnv(options); + + return this.returnProxies(cp.exec(command, options, callback)); + } + + public async fork(modulePath: string, args?: string[], options?: cp.ForkOptions): Promise { + preserveEnv(options); + + return this.returnProxies((this.forkProvider || cp.fork)(modulePath, args, options)); + } + + public async spawn(command: string, args?: string[], options?: cp.SpawnOptions): Promise { + preserveEnv(options); + + return this.returnProxies(cp.spawn(command, args, options)); + } + + private returnProxies(process: cp.ChildProcess): ChildProcessProxies { + return { + childProcess: new ChildProcessProxy(process), + stdin: process.stdin && new WritableProxy(process.stdin), + stdout: process.stdout && new ReadableProxy(process.stdout), + stderr: process.stderr && new ReadableProxy(process.stderr), + }; + } +} diff --git a/packages/protocol/src/node/modules/fs.ts b/packages/protocol/src/node/modules/fs.ts new file mode 100644 index 00000000..c2e164a2 --- /dev/null +++ b/packages/protocol/src/node/modules/fs.ts @@ -0,0 +1,250 @@ +import * as fs from "fs"; +import { promisify } from "util"; +import { ServerProxy } from "../../common/proxy"; +import { IEncodingOptions } from "../../common/util"; +import { WritableProxy } from "./stream"; + +/** + * A serializable version of fs.Stats. + */ +export interface Stats { + dev: number; + ino: number; + mode: number; + nlink: number; + uid: number; + gid: number; + rdev: number; + size: number; + blksize: number; + blocks: number; + atimeMs: number; + mtimeMs: number; + ctimeMs: number; + birthtimeMs: number; + atime: Date | string; + mtime: Date | string; + ctime: Date | string; + birthtime: Date | string; + _isFile: boolean; + _isDirectory: boolean; + _isBlockDevice: boolean; + _isCharacterDevice: boolean; + _isSymbolicLink: boolean; + _isFIFO: boolean; + _isSocket: boolean; +} + +export class WriteStreamProxy extends WritableProxy { + public async close(): Promise { + this.stream.close(); + } + + public async dispose(): Promise { + super.dispose(); + this.stream.close(); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + super.onEvent(cb); + this.stream.on("open", (fd) => cb("open", fd)); + } +} + +export class WatcherProxy implements ServerProxy { + public constructor(private readonly watcher: fs.FSWatcher) {} + + public async close(): Promise { + this.watcher.close(); + } + + public async dispose(): Promise { + this.watcher.close(); + this.watcher.removeAllListeners(); + } + + public async onDone(cb: () => void): Promise { + this.watcher.on("close", cb); + this.watcher.on("error", cb); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + this.watcher.on("change", (event, filename) => cb("change", event, filename)); + this.watcher.on("close", () => cb("close")); + this.watcher.on("error", (error) => cb("error", error)); + } +} + +export class FsModuleProxy { + public access(path: fs.PathLike, mode?: number): Promise { + return promisify(fs.access)(path, mode); + } + + // tslint:disable-next-line no-any + public appendFile(file: fs.PathLike | number, data: any, options?: fs.WriteFileOptions): Promise { + return promisify(fs.appendFile)(file, data, options); + } + + public chmod(path: fs.PathLike, mode: string | number): Promise { + return promisify(fs.chmod)(path, mode); + } + + public chown(path: fs.PathLike, uid: number, gid: number): Promise { + return promisify(fs.chown)(path, uid, gid); + } + + public close(fd: number): Promise { + return promisify(fs.close)(fd); + } + + public copyFile(src: fs.PathLike, dest: fs.PathLike, flags?: number): Promise { + return promisify(fs.copyFile)(src, dest, flags); + } + + // tslint:disable-next-line no-any + public async createWriteStream(path: fs.PathLike, options?: any): Promise { + return new WriteStreamProxy(fs.createWriteStream(path, options)); + } + + public exists(path: fs.PathLike): Promise { + return promisify(fs.exists)(path); + } + + public fchmod(fd: number, mode: string | number): Promise { + return promisify(fs.fchmod)(fd, mode); + } + + public fchown(fd: number, uid: number, gid: number): Promise { + return promisify(fs.fchown)(fd, uid, gid); + } + + public fdatasync(fd: number): Promise { + return promisify(fs.fdatasync)(fd); + } + + public async fstat(fd: number): Promise { + return this.makeStatsSerializable(await promisify(fs.fstat)(fd)); + } + + public fsync(fd: number): Promise { + return promisify(fs.fsync)(fd); + } + + public ftruncate(fd: number, len?: number | null): Promise { + return promisify(fs.ftruncate)(fd, len); + } + + public futimes(fd: number, atime: string | number | Date, mtime: string | number | Date): Promise { + return promisify(fs.futimes)(fd, atime, mtime); + } + + public lchmod(path: fs.PathLike, mode: string | number): Promise { + return promisify(fs.lchmod)(path, mode); + } + + public lchown(path: fs.PathLike, uid: number, gid: number): Promise { + return promisify(fs.lchown)(path, uid, gid); + } + + public link(existingPath: fs.PathLike, newPath: fs.PathLike): Promise { + return promisify(fs.link)(existingPath, newPath); + } + + public async lstat(path: fs.PathLike): Promise { + return this.makeStatsSerializable(await promisify(fs.lstat)(path)); + } + + public mkdir(path: fs.PathLike, mode: number | string | fs.MakeDirectoryOptions | undefined | null): Promise { + return promisify(fs.mkdir)(path, mode); + } + + public mkdtemp(prefix: string, options: IEncodingOptions): Promise { + return promisify(fs.mkdtemp)(prefix, options); + } + + public open(path: fs.PathLike, flags: string | number, mode: string | number | undefined | null): Promise { + return promisify(fs.open)(path, flags, mode); + } + + public read(fd: number, length: number, position: number | null): Promise<{ bytesRead: number, buffer: Buffer }> { + const buffer = new Buffer(length); + + return promisify(fs.read)(fd, buffer, 0, length, position); + } + + public readFile(path: fs.PathLike | number, options: IEncodingOptions): Promise { + return promisify(fs.readFile)(path, options); + } + + public readdir(path: fs.PathLike, options: IEncodingOptions): Promise { + return promisify(fs.readdir)(path, options); + } + + public readlink(path: fs.PathLike, options: IEncodingOptions): Promise { + return promisify(fs.readlink)(path, options); + } + + public realpath(path: fs.PathLike, options: IEncodingOptions): Promise { + return promisify(fs.realpath)(path, options); + } + + public rename(oldPath: fs.PathLike, newPath: fs.PathLike): Promise { + return promisify(fs.rename)(oldPath, newPath); + } + + public rmdir(path: fs.PathLike): Promise { + return promisify(fs.rmdir)(path); + } + + public async stat(path: fs.PathLike): Promise { + return this.makeStatsSerializable(await promisify(fs.stat)(path)); + } + + public symlink(target: fs.PathLike, path: fs.PathLike, type?: fs.symlink.Type | null): Promise { + return promisify(fs.symlink)(target, path, type); + } + + public truncate(path: fs.PathLike, len?: number | null): Promise { + return promisify(fs.truncate)(path, len); + } + + public unlink(path: fs.PathLike): Promise { + return promisify(fs.unlink)(path); + } + + public utimes(path: fs.PathLike, atime: string | number | Date, mtime: string | number | Date): Promise { + return promisify(fs.utimes)(path, atime, mtime); + } + + public async write(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): Promise<{ bytesWritten: number, buffer: Buffer }> { + return promisify(fs.write)(fd, buffer, offset, length, position); + } + + // tslint:disable-next-line no-any + public writeFile (path: fs.PathLike | number, data: any, options: IEncodingOptions): Promise { + return promisify(fs.writeFile)(path, data, options); + } + + public async watch(filename: fs.PathLike, options?: IEncodingOptions): Promise { + return new WatcherProxy(fs.watch(filename, options)); + } + + private makeStatsSerializable(stats: fs.Stats): Stats { + return { + ...stats, + /** + * We need to check if functions exist because nexe's implemented FS + * lib doesnt implement fs.stats properly. + */ + _isBlockDevice: stats.isBlockDevice ? stats.isBlockDevice() : false, + _isCharacterDevice: stats.isCharacterDevice ? stats.isCharacterDevice() : false, + _isDirectory: stats.isDirectory(), + _isFIFO: stats.isFIFO ? stats.isFIFO() : false, + _isFile: stats.isFile(), + _isSocket: stats.isSocket ? stats.isSocket() : false, + _isSymbolicLink: stats.isSymbolicLink ? stats.isSymbolicLink() : false, + }; + } +} diff --git a/packages/protocol/src/node/modules/index.ts b/packages/protocol/src/node/modules/index.ts new file mode 100644 index 00000000..590d037d --- /dev/null +++ b/packages/protocol/src/node/modules/index.ts @@ -0,0 +1,6 @@ +export * from "./child_process"; +export * from "./fs"; +export * from "./net"; +export * from "./node-pty"; +export * from "./spdlog"; +export * from "./trash"; diff --git a/packages/protocol/src/node/modules/net.ts b/packages/protocol/src/node/modules/net.ts new file mode 100644 index 00000000..5e5133c4 --- /dev/null +++ b/packages/protocol/src/node/modules/net.ts @@ -0,0 +1,90 @@ +import * as net from "net"; +import { ServerProxy } from "../../common/proxy"; +import { DuplexProxy } from "./stream"; + +export class NetSocketProxy extends DuplexProxy { + public async connect(options: number | string | net.SocketConnectOpts, host?: string): Promise { + this.stream.connect(options as any, host as any); // tslint:disable-line no-any this works fine + } + + public async unref(): Promise { + this.stream.unref(); + } + + public async ref(): Promise { + this.stream.ref(); + } + + public async dispose(): Promise { + this.stream.removeAllListeners(); + this.stream.end(); + this.stream.destroy(); + this.stream.unref(); + } + + public async onDone(cb: () => void): Promise { + this.stream.on("close", cb); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + super.onEvent(cb); + this.stream.on("connect", () => cb("connect")); + this.stream.on("lookup", (error, address, family, host) => cb("lookup", error, address, family, host)); + this.stream.on("timeout", () => cb("timeout")); + } +} + +export class NetServerProxy implements ServerProxy { + public constructor(private readonly server: net.Server) {} + + public async listen(handle?: net.ListenOptions | number | string, hostname?: string | number, backlog?: number): Promise { + this.server.listen(handle, hostname as any, backlog as any); // tslint:disable-line no-any this is fine + } + + public async ref(): Promise { + this.server.ref(); + } + + public async unref(): Promise { + this.server.unref(); + } + + public async close(): Promise { + this.server.close(); + } + + public async onConnection(cb: (proxy: NetSocketProxy) => void): Promise { + this.server.on("connection", (socket) => cb(new NetSocketProxy(socket))); + } + + public async dispose(): Promise { + this.server.close(); + this.server.removeAllListeners(); + } + + public async onDone(cb: () => void): Promise { + this.server.on("close", cb); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + this.server.on("close", () => cb("close")); + this.server.on("error", (error) => cb("error", error)); + this.server.on("listening", () => cb("listening")); + } +} + +export class NetModuleProxy { + public async createSocket(options?: net.SocketConstructorOpts): Promise { + return new NetSocketProxy(new net.Socket(options)); + } + + public async createConnection(target: string | number | net.NetConnectOpts, host?: string): Promise { + return new NetSocketProxy(net.createConnection(target as any, host)); // tslint:disable-line no-any defeat stubborness + } + + public async createServer(options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean }): Promise { + return new NetServerProxy(net.createServer(options)); + } +} diff --git a/packages/protocol/src/node/modules/node-pty.ts b/packages/protocol/src/node/modules/node-pty.ts new file mode 100644 index 00000000..191c64f1 --- /dev/null +++ b/packages/protocol/src/node/modules/node-pty.ts @@ -0,0 +1,75 @@ +/// +import { EventEmitter } from "events"; +import * as pty from "node-pty"; +import { ServerProxy } from "../../common/proxy"; +import { preserveEnv } from "../../common/util"; + +/** + * Server-side IPty proxy. + */ +export class NodePtyProcessProxy implements ServerProxy { + private readonly emitter = new EventEmitter(); + + public constructor(private readonly process: pty.IPty) { + let name = process.process; + setTimeout(() => { // Need to wait for the caller to listen to the event. + this.emitter.emit("process", name); + }, 1); + const timer = setInterval(() => { + if (process.process !== name) { + name = process.process; + this.emitter.emit("process", name); + } + }, 200); + + this.onDone(() => clearInterval(timer)); + } + + public async getPid(): Promise { + return this.process.pid; + } + + public async getProcess(): Promise { + return this.process.process; + } + + public async kill(signal?: string): Promise { + this.process.kill(signal); + } + + public async resize(columns: number, rows: number): Promise { + this.process.resize(columns, rows); + } + + public async write(data: string): Promise { + this.process.write(data); + } + + public async onDone(cb: () => void): Promise { + this.process.on("exit", cb); + } + + public async dispose(): Promise { + this.kill(); + setTimeout(() => this.kill("SIGKILL"), 5000); // Double tap. + this.emitter.removeAllListeners(); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + this.emitter.on("process", (process) => cb("process", process)); + this.process.on("data", (data) => cb("data", data)); + this.process.on("exit", (exitCode, signal) => cb("exit", exitCode, signal)); + } +} + +/** + * Server-side node-pty proxy. + */ +export class NodePtyModuleProxy { + public async spawn(file: string, args: string[] | string, options: pty.IPtyForkOptions): Promise { + preserveEnv(options); + + return new NodePtyProcessProxy(require("node-pty").spawn(file, args, options)); + } +} diff --git a/packages/protocol/src/node/modules/spdlog.ts b/packages/protocol/src/node/modules/spdlog.ts new file mode 100644 index 00000000..b84771cd --- /dev/null +++ b/packages/protocol/src/node/modules/spdlog.ts @@ -0,0 +1,46 @@ +/// +import { EventEmitter } from "events"; +import * as spdlog from "spdlog"; +import { ServerProxy } from "../../common/proxy"; + +export class RotatingLoggerProxy implements ServerProxy { + private readonly emitter = new EventEmitter(); + + public constructor(private readonly logger: spdlog.RotatingLogger) {} + + public async trace (message: string): Promise { this.logger.trace(message); } + public async debug (message: string): Promise { this.logger.debug(message); } + public async info (message: string): Promise { this.logger.info(message); } + public async warn (message: string): Promise { this.logger.warn(message); } + public async error (message: string): Promise { this.logger.error(message); } + public async critical (message: string): Promise { this.logger.critical(message); } + public async setLevel (level: number): Promise { this.logger.setLevel(level); } + public async clearFormatters (): Promise { this.logger.clearFormatters(); } + public async flush (): Promise { this.logger.flush(); } + public async drop (): Promise { this.logger.drop(); } + + public async onDone(cb: () => void): Promise { + this.emitter.on("dispose", cb); + } + + public async dispose(): Promise { + this.flush(); + this.emitter.emit("dispose"); + this.emitter.removeAllListeners(); + } + + // tslint:disable-next-line no-any + public async onEvent(_cb: (event: string, ...args: any[]) => void): Promise { + // No events. + } +} + +export class SpdlogModuleProxy { + public async createLogger(name: string, filePath: string, fileSize: number, fileCount: number): Promise { + return new RotatingLoggerProxy(new (require("spdlog") as typeof import("spdlog")).RotatingLogger(name, filePath, fileSize, fileCount)); + } + + public async setAsyncMode(bufferSize: number, flushInterval: number): Promise { + require("spdlog").setAsyncMode(bufferSize, flushInterval); + } +} diff --git a/packages/protocol/src/node/modules/stream.ts b/packages/protocol/src/node/modules/stream.ts new file mode 100644 index 00000000..0114547b --- /dev/null +++ b/packages/protocol/src/node/modules/stream.ts @@ -0,0 +1,107 @@ +import * as stream from "stream"; +import { ServerProxy } from "../../common/proxy"; + +export class WritableProxy implements ServerProxy { + public constructor(protected readonly stream: T) {} + + public async destroy(): Promise { + this.stream.destroy(); + } + + // tslint:disable-next-line no-any + public async end(data?: any, encoding?: string): Promise { + return new Promise((resolve): void => { + this.stream.end(data, encoding, () => { + resolve(); + }); + }); + } + + public async setDefaultEncoding(encoding: string): Promise { + this.stream.setDefaultEncoding(encoding); + } + + // tslint:disable-next-line no-any + public async write(data: any, encoding?: string): Promise { + return new Promise((resolve, reject): void => { + this.stream.write(data, encoding, (error) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); + } + + public async dispose(): Promise { + this.stream.end(); + this.stream.removeAllListeners(); + } + + public async onDone(cb: () => void): Promise { + this.stream.on("close", cb); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + // Sockets have an extra argument on "close". + // tslint:disable-next-line no-any + this.stream.on("close", (...args: any[]) => cb("close", ...args)); + this.stream.on("drain", () => cb("drain")); + this.stream.on("error", (error) => cb("error", error)); + this.stream.on("finish", () => cb("finish")); + } +} + +/** + * This noise is because we can't do multiple extends and we also can't seem to + * do `extends WritableProxy implement ReadableProxy` (for `DuplexProxy`). + */ +export interface IReadableProxy extends ServerProxy { + destroy(): Promise; + setEncoding(encoding: string): Promise; + dispose(): Promise; + onDone(cb: () => void): Promise; +} + +export class ReadableProxy implements IReadableProxy { + public constructor(protected readonly stream: T) {} + + public async destroy(): Promise { + this.stream.destroy(); + } + + public async setEncoding(encoding: string): Promise { + this.stream.setEncoding(encoding); + } + + public async dispose(): Promise { + this.stream.destroy(); + } + + public async onDone(cb: () => void): Promise { + this.stream.on("close", cb); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + this.stream.on("close", () => cb("close")); + this.stream.on("data", (chunk) => cb("data", chunk)); + this.stream.on("end", () => cb("end")); + this.stream.on("error", (error) => cb("error", error)); + } +} + +export class DuplexProxy extends WritableProxy implements IReadableProxy { + public async setEncoding(encoding: string): Promise { + this.stream.setEncoding(encoding); + } + + // tslint:disable-next-line no-any + public async onEvent(cb: (event: string, ...args: any[]) => void): Promise { + super.onEvent(cb); + this.stream.on("data", (chunk) => cb("data", chunk)); + this.stream.on("end", () => cb("end")); + } +} diff --git a/packages/protocol/src/node/modules/trash.ts b/packages/protocol/src/node/modules/trash.ts new file mode 100644 index 00000000..6f6bedc9 --- /dev/null +++ b/packages/protocol/src/node/modules/trash.ts @@ -0,0 +1,7 @@ +import * as trash from "trash"; + +export class TrashModuleProxy { + public async trash(path: string, options?: trash.Options): Promise { + return trash(path, options); + } +} diff --git a/packages/protocol/src/node/server.ts b/packages/protocol/src/node/server.ts index 0afebbaf..238e8876 100644 --- a/packages/protocol/src/node/server.ts +++ b/packages/protocol/src/node/server.ts @@ -1,10 +1,13 @@ import { mkdirp } from "fs-extra"; import * as os from "os"; -import { logger, field } from "@coder/logger"; -import { Pong, ClientMessage, WorkingInitMessage, ServerMessage } from "../proto"; -import { evaluate, ActiveEvaluation } from "./evaluate"; -import { ForkProvider } from "../common/helpers"; +import { field, logger} from "@coder/logger"; import { ReadWriteConnection } from "../common/connection"; +import { Module, ServerProxy } from "../common/proxy"; +import { isPromise, isProxy, moduleToProto, parse, platformToProto, protoToModule, stringify } from "../common/util"; +import { CallbackMessage, ClientMessage, EventMessage, FailMessage, MethodMessage, NamedCallbackMessage, NamedEventMessage, NumberedCallbackMessage, NumberedEventMessage, Pong, ServerMessage, SuccessMessage, WorkingInitMessage } from "../proto"; +import { ChildProcessModuleProxy, ForkProvider, FsModuleProxy, NetModuleProxy, NodePtyModuleProxy, SpdlogModuleProxy, TrashModuleProxy } from "./modules"; + +// tslint:disable no-any export interface ServerOptions { readonly workingDirectory: string; @@ -14,27 +17,59 @@ export interface ServerOptions { readonly fork?: ForkProvider; } +interface ProxyData { + disposeTimeout?: number | NodeJS.Timer; + instance: any; +} + export class Server { - private readonly evals = new Map(); + private proxyId = 0; + private readonly proxies = new Map(); + private disconnected: boolean = false; + private responseTimeout = 10000; public constructor( private readonly connection: ReadWriteConnection, private readonly options?: ServerOptions, ) { - connection.onMessage((data) => { + connection.onMessage(async (data) => { try { - this.handleMessage(ClientMessage.deserializeBinary(data)); + await this.handleMessage(ClientMessage.deserializeBinary(data)); } catch (ex) { - logger.error("Failed to handle client message", field("length", data.byteLength), field("exception", { - message: ex.message, - stack: ex.stack, - })); + logger.error( + "Failed to handle client message", + field("length", data.byteLength), + field("exception", { + message: ex.message, + stack: ex.stack, + }), + ); } }); + connection.onClose(() => { - this.evals.forEach((e) => e.dispose()); + this.disconnected = true; + + logger.trace(() => [ + "disconnected from client", + field("proxies", this.proxies.size), + ]); + + this.proxies.forEach((proxy, proxyId) => { + if (isProxy(proxy.instance)) { + proxy.instance.dispose(); + } + this.removeProxy(proxyId); + }); }); + this.storeProxy(new ChildProcessModuleProxy(this.options ? this.options.fork : undefined), Module.ChildProcess); + this.storeProxy(new FsModuleProxy(), Module.Fs); + this.storeProxy(new NetModuleProxy(), Module.Net); + this.storeProxy(new NodePtyModuleProxy(), Module.NodePty); + this.storeProxy(new SpdlogModuleProxy(), Module.Spdlog); + this.storeProxy(new TrashModuleProxy(), Module.Trash); + if (!this.options) { logger.warn("No server options provided. InitMessage will not be sent."); @@ -55,53 +90,19 @@ export class Server { initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory); initMsg.setHomeDirectory(os.homedir()); initMsg.setTmpDirectory(os.tmpdir()); - const platform = os.platform(); - let operatingSystem: WorkingInitMessage.OperatingSystem; - switch (platform) { - case "win32": - operatingSystem = WorkingInitMessage.OperatingSystem.WINDOWS; - break; - case "linux": - operatingSystem = WorkingInitMessage.OperatingSystem.LINUX; - break; - case "darwin": - operatingSystem = WorkingInitMessage.OperatingSystem.MAC; - break; - default: - throw new Error(`unrecognized platform "${platform}"`); - } - initMsg.setOperatingSystem(operatingSystem); + initMsg.setOperatingSystem(platformToProto(os.platform())); initMsg.setShell(os.userInfo().shell || global.process.env.SHELL); const srvMsg = new ServerMessage(); srvMsg.setInit(initMsg); connection.send(srvMsg.serializeBinary()); } - private handleMessage(message: ClientMessage): void { - if (message.hasNewEval()) { - const evalMessage = message.getNewEval()!; - logger.trace(() => [ - "EvalMessage", - field("id", evalMessage.getId()), - field("args", evalMessage.getArgsList()), - field("function", evalMessage.getFunction()), - ]); - const resp = evaluate(this.connection, evalMessage, () => { - this.evals.delete(evalMessage.getId()); - logger.trace(() => [ - `dispose ${evalMessage.getId()}, ${this.evals.size} left`, - ]); - }, this.options ? this.options.fork : undefined); - if (resp) { - this.evals.set(evalMessage.getId(), resp); - } - } else if (message.hasEvalEvent()) { - const evalEventMessage = message.getEvalEvent()!; - const e = this.evals.get(evalEventMessage.getId()); - if (!e) { - return; - } - e.onEvent(evalEventMessage); + /** + * Handle all messages from the client. + */ + private async handleMessage(message: ClientMessage): Promise { + if (message.hasMethod()) { + await this.runMethod(message.getMethod()!); } else if (message.hasPing()) { logger.trace("ping"); const srvMsg = new ServerMessage(); @@ -111,4 +112,230 @@ export class Server { throw new Error("unknown message type"); } } + + /** + * Run a method on a proxy. + */ + private async runMethod(message: MethodMessage): Promise { + const proxyMessage = message.getNamedProxy()! || message.getNumberedProxy()!; + const id = proxyMessage.getId(); + const proxyId = message.hasNamedProxy() + ? protoToModule(message.getNamedProxy()!.getModule()) + : message.getNumberedProxy()!.getProxyId(); + const method = proxyMessage.getMethod(); + const args = proxyMessage.getArgsList().map((a) => parse( + a, + (id, args) => this.sendCallback(proxyId, id, args), + )); + + logger.trace(() => [ + "received", + field("id", id), + field("proxyId", proxyId), + field("method", method), + field("args", proxyMessage.getArgsList()), + ]); + + let response: any; + try { + const proxy = this.getProxy(proxyId); + if (typeof proxy.instance[method] !== "function") { + throw new Error(`"${method}" is not a function`); + } + + response = proxy.instance[method](...args); + + // We wait for the client to call "dispose" instead of doing it onDone to + // ensure all the messages it sent get processed before we get rid of it. + if (method === "dispose") { + this.removeProxy(proxyId); + } + + // Proxies must always return promises. + if (!isPromise(response)) { + throw new Error('"${method}" must return a promise'); + } + } catch (error) { + logger.error( + error.message, + field("type", typeof response), + field("proxyId", proxyId), + ); + this.sendException(id, error); + } + + try { + this.sendResponse(id, await response); + } catch (error) { + this.sendException(id, error); + } + } + + /** + * Send a callback to the client. + */ + private sendCallback(proxyId: number | Module, callbackId: number, args: any[]): void { + const stringifiedArgs = args.map((a) => this.stringify(a)); + logger.trace(() => [ + "sending callback", + field("proxyId", proxyId), + field("callbackId", callbackId), + field("args", stringifiedArgs), + ]); + + const message = new CallbackMessage(); + let callbackMessage: NamedCallbackMessage | NumberedCallbackMessage; + if (typeof proxyId === "string") { + callbackMessage = new NamedCallbackMessage(); + callbackMessage.setModule(moduleToProto(proxyId)); + message.setNamedCallback(callbackMessage); + } else { + callbackMessage = new NumberedCallbackMessage(); + callbackMessage.setProxyId(proxyId); + message.setNumberedCallback(callbackMessage); + } + callbackMessage.setCallbackId(callbackId); + callbackMessage.setArgsList(stringifiedArgs); + + const serverMessage = new ServerMessage(); + serverMessage.setCallback(message); + this.connection.send(serverMessage.serializeBinary()); + } + + /** + * Store a proxy and bind events to send them back to the client. + */ + private storeProxy(instance: ServerProxy): number; + private storeProxy(instance: any, moduleProxyId: Module): Module; + private storeProxy(instance: ServerProxy | any, moduleProxyId?: Module): number | Module { + // In case we disposed while waiting for a function to return. + if (this.disconnected) { + if (isProxy(instance)) { + instance.dispose(); + } + + throw new Error("disposed"); + } + + const proxyId = moduleProxyId || this.proxyId++; + logger.trace(() => [ + "storing proxy", + field("proxyId", proxyId), + ]); + + this.proxies.set(proxyId, { instance }); + + if (isProxy(instance)) { + instance.onEvent((event, ...args) => this.sendEvent(proxyId, event, ...args)); + instance.onDone(() => { + // It might have finished because we disposed it due to a disconnect. + if (!this.disconnected) { + this.sendEvent(proxyId, "done"); + this.getProxy(proxyId).disposeTimeout = setTimeout(() => { + instance.dispose(); + this.removeProxy(proxyId); + }, this.responseTimeout); + } + }); + } + + return proxyId; + } + + /** + * Send an event to the client. + */ + private sendEvent(proxyId: number | Module, event: string, ...args: any[]): void { + const stringifiedArgs = args.map((a) => this.stringify(a)); + logger.trace(() => [ + "sending event", + field("proxyId", proxyId), + field("event", event), + field("args", stringifiedArgs), + ]); + + const message = new EventMessage(); + let eventMessage: NamedEventMessage | NumberedEventMessage; + if (typeof proxyId === "string") { + eventMessage = new NamedEventMessage(); + eventMessage.setModule(moduleToProto(proxyId)); + message.setNamedEvent(eventMessage); + } else { + eventMessage = new NumberedEventMessage(); + eventMessage.setProxyId(proxyId); + message.setNumberedEvent(eventMessage); + } + eventMessage.setEvent(event); + eventMessage.setArgsList(stringifiedArgs); + + const serverMessage = new ServerMessage(); + serverMessage.setEvent(message); + this.connection.send(serverMessage.serializeBinary()); + } + + /** + * Send a response back to the client. + */ + private sendResponse(id: number, response: any): void { + const stringifiedResponse = this.stringify(response); + logger.trace(() => [ + "sending resolve", + field("id", id), + field("response", stringifiedResponse), + ]); + + const successMessage = new SuccessMessage(); + successMessage.setId(id); + successMessage.setResponse(stringifiedResponse); + + const serverMessage = new ServerMessage(); + serverMessage.setSuccess(successMessage); + this.connection.send(serverMessage.serializeBinary()); + } + + /** + * Send an exception back to the client. + */ + private sendException(id: number, error: Error): void { + const stringifiedError = stringify(error); + logger.trace(() => [ + "sending reject", + field("id", id) , + field("response", stringifiedError), + ]); + + const failedMessage = new FailMessage(); + failedMessage.setId(id); + failedMessage.setResponse(stringifiedError); + + const serverMessage = new ServerMessage(); + serverMessage.setFail(failedMessage); + this.connection.send(serverMessage.serializeBinary()); + } + + /** + * Call after disposing a proxy. + */ + private removeProxy(proxyId: number | Module): void { + clearTimeout(this.getProxy(proxyId).disposeTimeout as any); + this.proxies.delete(proxyId); + + logger.trace(() => [ + "disposed and removed proxy", + field("proxyId", proxyId), + field("proxies", this.proxies.size), + ]); + } + + private stringify(value: any): string { + return stringify(value, undefined, (p) => this.storeProxy(p)); + } + + private getProxy(proxyId: number | Module): ProxyData { + if (!this.proxies.has(proxyId)) { + throw new Error(`proxy ${proxyId} disposed too early`); + } + + return this.proxies.get(proxyId)!; + } } diff --git a/packages/protocol/src/proto/client.proto b/packages/protocol/src/proto/client.proto index a29839ab..931dbdf6 100644 --- a/packages/protocol/src/proto/client.proto +++ b/packages/protocol/src/proto/client.proto @@ -2,29 +2,29 @@ syntax = "proto3"; import "node.proto"; import "vscode.proto"; +// Messages that the client can send to the server. message ClientMessage { oneof msg { // node.proto - NewEvalMessage new_eval = 11; - EvalEventMessage eval_event = 12; - - Ping ping = 13; + MethodMessage method = 20; + Ping ping = 21; } } +// Messages that the server can send to the client. message ServerMessage { oneof msg { // node.proto - EvalFailedMessage eval_failed = 13; - EvalDoneMessage eval_done = 14; - EvalEventMessage eval_event = 15; + FailMessage fail = 13; + SuccessMessage success = 14; + EventMessage event = 19; + CallbackMessage callback = 22; + Pong pong = 18; WorkingInitMessage init = 16; // vscode.proto SharedProcessActiveMessage shared_process_active = 17; - - Pong pong = 18; } } diff --git a/packages/protocol/src/proto/client_pb.d.ts b/packages/protocol/src/proto/client_pb.d.ts index ce223fff..9cf8e46a 100644 --- a/packages/protocol/src/proto/client_pb.d.ts +++ b/packages/protocol/src/proto/client_pb.d.ts @@ -6,15 +6,10 @@ import * as node_pb from "./node_pb"; import * as vscode_pb from "./vscode_pb"; export class ClientMessage extends jspb.Message { - hasNewEval(): boolean; - clearNewEval(): void; - getNewEval(): node_pb.NewEvalMessage | undefined; - setNewEval(value?: node_pb.NewEvalMessage): void; - - hasEvalEvent(): boolean; - clearEvalEvent(): void; - getEvalEvent(): node_pb.EvalEventMessage | undefined; - setEvalEvent(value?: node_pb.EvalEventMessage): void; + hasMethod(): boolean; + clearMethod(): void; + getMethod(): node_pb.MethodMessage | undefined; + setMethod(value?: node_pb.MethodMessage): void; hasPing(): boolean; clearPing(): void; @@ -34,34 +29,42 @@ export class ClientMessage extends jspb.Message { export namespace ClientMessage { export type AsObject = { - newEval?: node_pb.NewEvalMessage.AsObject, - evalEvent?: node_pb.EvalEventMessage.AsObject, + method?: node_pb.MethodMessage.AsObject, ping?: node_pb.Ping.AsObject, } export enum MsgCase { MSG_NOT_SET = 0, - NEW_EVAL = 11, - EVAL_EVENT = 12, - PING = 13, + METHOD = 20, + PING = 21, } } export class ServerMessage extends jspb.Message { - hasEvalFailed(): boolean; - clearEvalFailed(): void; - getEvalFailed(): node_pb.EvalFailedMessage | undefined; - setEvalFailed(value?: node_pb.EvalFailedMessage): void; + hasFail(): boolean; + clearFail(): void; + getFail(): node_pb.FailMessage | undefined; + setFail(value?: node_pb.FailMessage): void; - hasEvalDone(): boolean; - clearEvalDone(): void; - getEvalDone(): node_pb.EvalDoneMessage | undefined; - setEvalDone(value?: node_pb.EvalDoneMessage): void; + hasSuccess(): boolean; + clearSuccess(): void; + getSuccess(): node_pb.SuccessMessage | undefined; + setSuccess(value?: node_pb.SuccessMessage): void; - hasEvalEvent(): boolean; - clearEvalEvent(): void; - getEvalEvent(): node_pb.EvalEventMessage | undefined; - setEvalEvent(value?: node_pb.EvalEventMessage): void; + hasEvent(): boolean; + clearEvent(): void; + getEvent(): node_pb.EventMessage | undefined; + setEvent(value?: node_pb.EventMessage): void; + + hasCallback(): boolean; + clearCallback(): void; + getCallback(): node_pb.CallbackMessage | undefined; + setCallback(value?: node_pb.CallbackMessage): void; + + hasPong(): boolean; + clearPong(): void; + getPong(): node_pb.Pong | undefined; + setPong(value?: node_pb.Pong): void; hasInit(): boolean; clearInit(): void; @@ -73,11 +76,6 @@ export class ServerMessage extends jspb.Message { getSharedProcessActive(): vscode_pb.SharedProcessActiveMessage | undefined; setSharedProcessActive(value?: vscode_pb.SharedProcessActiveMessage): void; - hasPong(): boolean; - clearPong(): void; - getPong(): node_pb.Pong | undefined; - setPong(value?: node_pb.Pong): void; - getMsgCase(): ServerMessage.MsgCase; serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): ServerMessage.AsObject; @@ -91,22 +89,24 @@ export class ServerMessage extends jspb.Message { export namespace ServerMessage { export type AsObject = { - evalFailed?: node_pb.EvalFailedMessage.AsObject, - evalDone?: node_pb.EvalDoneMessage.AsObject, - evalEvent?: node_pb.EvalEventMessage.AsObject, + fail?: node_pb.FailMessage.AsObject, + success?: node_pb.SuccessMessage.AsObject, + event?: node_pb.EventMessage.AsObject, + callback?: node_pb.CallbackMessage.AsObject, + pong?: node_pb.Pong.AsObject, init?: WorkingInitMessage.AsObject, sharedProcessActive?: vscode_pb.SharedProcessActiveMessage.AsObject, - pong?: node_pb.Pong.AsObject, } export enum MsgCase { MSG_NOT_SET = 0, - EVAL_FAILED = 13, - EVAL_DONE = 14, - EVAL_EVENT = 15, + FAIL = 13, + SUCCESS = 14, + EVENT = 19, + CALLBACK = 22, + PONG = 18, INIT = 16, SHARED_PROCESS_ACTIVE = 17, - PONG = 18, } } diff --git a/packages/protocol/src/proto/client_pb.js b/packages/protocol/src/proto/client_pb.js index 2d451abd..516dcc9f 100644 --- a/packages/protocol/src/proto/client_pb.js +++ b/packages/protocol/src/proto/client_pb.js @@ -43,16 +43,15 @@ if (goog.DEBUG && !COMPILED) { * @private {!Array>} * @const */ -proto.ClientMessage.oneofGroups_ = [[11,12,13]]; +proto.ClientMessage.oneofGroups_ = [[20,21]]; /** * @enum {number} */ proto.ClientMessage.MsgCase = { MSG_NOT_SET: 0, - NEW_EVAL: 11, - EVAL_EVENT: 12, - PING: 13 + METHOD: 20, + PING: 21 }; /** @@ -91,8 +90,7 @@ proto.ClientMessage.prototype.toObject = function(opt_includeInstance) { */ proto.ClientMessage.toObject = function(includeInstance, msg) { var f, obj = { - newEval: (f = msg.getNewEval()) && node_pb.NewEvalMessage.toObject(includeInstance, f), - evalEvent: (f = msg.getEvalEvent()) && node_pb.EvalEventMessage.toObject(includeInstance, f), + method: (f = msg.getMethod()) && node_pb.MethodMessage.toObject(includeInstance, f), ping: (f = msg.getPing()) && node_pb.Ping.toObject(includeInstance, f) }; @@ -130,17 +128,12 @@ proto.ClientMessage.deserializeBinaryFromReader = function(msg, reader) { } var field = reader.getFieldNumber(); switch (field) { - case 11: - var value = new node_pb.NewEvalMessage; - reader.readMessage(value,node_pb.NewEvalMessage.deserializeBinaryFromReader); - msg.setNewEval(value); + case 20: + var value = new node_pb.MethodMessage; + reader.readMessage(value,node_pb.MethodMessage.deserializeBinaryFromReader); + msg.setMethod(value); break; - case 12: - var value = new node_pb.EvalEventMessage; - reader.readMessage(value,node_pb.EvalEventMessage.deserializeBinaryFromReader); - msg.setEvalEvent(value); - break; - case 13: + case 21: var value = new node_pb.Ping; reader.readMessage(value,node_pb.Ping.deserializeBinaryFromReader); msg.setPing(value); @@ -174,26 +167,18 @@ proto.ClientMessage.prototype.serializeBinary = function() { */ proto.ClientMessage.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getNewEval(); + f = message.getMethod(); if (f != null) { writer.writeMessage( - 11, + 20, f, - node_pb.NewEvalMessage.serializeBinaryToWriter - ); - } - f = message.getEvalEvent(); - if (f != null) { - writer.writeMessage( - 12, - f, - node_pb.EvalEventMessage.serializeBinaryToWriter + node_pb.MethodMessage.serializeBinaryToWriter ); } f = message.getPing(); if (f != null) { writer.writeMessage( - 13, + 21, f, node_pb.Ping.serializeBinaryToWriter ); @@ -202,23 +187,23 @@ proto.ClientMessage.serializeBinaryToWriter = function(message, writer) { /** - * optional NewEvalMessage new_eval = 11; - * @return {?proto.NewEvalMessage} + * optional MethodMessage method = 20; + * @return {?proto.MethodMessage} */ -proto.ClientMessage.prototype.getNewEval = function() { - return /** @type{?proto.NewEvalMessage} */ ( - jspb.Message.getWrapperField(this, node_pb.NewEvalMessage, 11)); +proto.ClientMessage.prototype.getMethod = function() { + return /** @type{?proto.MethodMessage} */ ( + jspb.Message.getWrapperField(this, node_pb.MethodMessage, 20)); }; -/** @param {?proto.NewEvalMessage|undefined} value */ -proto.ClientMessage.prototype.setNewEval = function(value) { - jspb.Message.setOneofWrapperField(this, 11, proto.ClientMessage.oneofGroups_[0], value); +/** @param {?proto.MethodMessage|undefined} value */ +proto.ClientMessage.prototype.setMethod = function(value) { + jspb.Message.setOneofWrapperField(this, 20, proto.ClientMessage.oneofGroups_[0], value); }; -proto.ClientMessage.prototype.clearNewEval = function() { - this.setNewEval(undefined); +proto.ClientMessage.prototype.clearMethod = function() { + this.setMethod(undefined); }; @@ -226,54 +211,24 @@ proto.ClientMessage.prototype.clearNewEval = function() { * Returns whether this field is set. * @return {!boolean} */ -proto.ClientMessage.prototype.hasNewEval = function() { - return jspb.Message.getField(this, 11) != null; +proto.ClientMessage.prototype.hasMethod = function() { + return jspb.Message.getField(this, 20) != null; }; /** - * optional EvalEventMessage eval_event = 12; - * @return {?proto.EvalEventMessage} - */ -proto.ClientMessage.prototype.getEvalEvent = function() { - return /** @type{?proto.EvalEventMessage} */ ( - jspb.Message.getWrapperField(this, node_pb.EvalEventMessage, 12)); -}; - - -/** @param {?proto.EvalEventMessage|undefined} value */ -proto.ClientMessage.prototype.setEvalEvent = function(value) { - jspb.Message.setOneofWrapperField(this, 12, proto.ClientMessage.oneofGroups_[0], value); -}; - - -proto.ClientMessage.prototype.clearEvalEvent = function() { - this.setEvalEvent(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {!boolean} - */ -proto.ClientMessage.prototype.hasEvalEvent = function() { - return jspb.Message.getField(this, 12) != null; -}; - - -/** - * optional Ping ping = 13; + * optional Ping ping = 21; * @return {?proto.Ping} */ proto.ClientMessage.prototype.getPing = function() { return /** @type{?proto.Ping} */ ( - jspb.Message.getWrapperField(this, node_pb.Ping, 13)); + jspb.Message.getWrapperField(this, node_pb.Ping, 21)); }; /** @param {?proto.Ping|undefined} value */ proto.ClientMessage.prototype.setPing = function(value) { - jspb.Message.setOneofWrapperField(this, 13, proto.ClientMessage.oneofGroups_[0], value); + jspb.Message.setOneofWrapperField(this, 21, proto.ClientMessage.oneofGroups_[0], value); }; @@ -287,7 +242,7 @@ proto.ClientMessage.prototype.clearPing = function() { * @return {!boolean} */ proto.ClientMessage.prototype.hasPing = function() { - return jspb.Message.getField(this, 13) != null; + return jspb.Message.getField(this, 21) != null; }; @@ -317,19 +272,20 @@ if (goog.DEBUG && !COMPILED) { * @private {!Array>} * @const */ -proto.ServerMessage.oneofGroups_ = [[13,14,15,16,17,18]]; +proto.ServerMessage.oneofGroups_ = [[13,14,19,22,18,16,17]]; /** * @enum {number} */ proto.ServerMessage.MsgCase = { MSG_NOT_SET: 0, - EVAL_FAILED: 13, - EVAL_DONE: 14, - EVAL_EVENT: 15, + FAIL: 13, + SUCCESS: 14, + EVENT: 19, + CALLBACK: 22, + PONG: 18, INIT: 16, - SHARED_PROCESS_ACTIVE: 17, - PONG: 18 + SHARED_PROCESS_ACTIVE: 17 }; /** @@ -368,12 +324,13 @@ proto.ServerMessage.prototype.toObject = function(opt_includeInstance) { */ proto.ServerMessage.toObject = function(includeInstance, msg) { var f, obj = { - evalFailed: (f = msg.getEvalFailed()) && node_pb.EvalFailedMessage.toObject(includeInstance, f), - evalDone: (f = msg.getEvalDone()) && node_pb.EvalDoneMessage.toObject(includeInstance, f), - evalEvent: (f = msg.getEvalEvent()) && node_pb.EvalEventMessage.toObject(includeInstance, f), + fail: (f = msg.getFail()) && node_pb.FailMessage.toObject(includeInstance, f), + success: (f = msg.getSuccess()) && node_pb.SuccessMessage.toObject(includeInstance, f), + event: (f = msg.getEvent()) && node_pb.EventMessage.toObject(includeInstance, f), + callback: (f = msg.getCallback()) && node_pb.CallbackMessage.toObject(includeInstance, f), + pong: (f = msg.getPong()) && node_pb.Pong.toObject(includeInstance, f), init: (f = msg.getInit()) && proto.WorkingInitMessage.toObject(includeInstance, f), - sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActiveMessage.toObject(includeInstance, f), - pong: (f = msg.getPong()) && node_pb.Pong.toObject(includeInstance, f) + sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActiveMessage.toObject(includeInstance, f) }; if (includeInstance) { @@ -411,19 +368,29 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) { var field = reader.getFieldNumber(); switch (field) { case 13: - var value = new node_pb.EvalFailedMessage; - reader.readMessage(value,node_pb.EvalFailedMessage.deserializeBinaryFromReader); - msg.setEvalFailed(value); + var value = new node_pb.FailMessage; + reader.readMessage(value,node_pb.FailMessage.deserializeBinaryFromReader); + msg.setFail(value); break; case 14: - var value = new node_pb.EvalDoneMessage; - reader.readMessage(value,node_pb.EvalDoneMessage.deserializeBinaryFromReader); - msg.setEvalDone(value); + var value = new node_pb.SuccessMessage; + reader.readMessage(value,node_pb.SuccessMessage.deserializeBinaryFromReader); + msg.setSuccess(value); break; - case 15: - var value = new node_pb.EvalEventMessage; - reader.readMessage(value,node_pb.EvalEventMessage.deserializeBinaryFromReader); - msg.setEvalEvent(value); + case 19: + var value = new node_pb.EventMessage; + reader.readMessage(value,node_pb.EventMessage.deserializeBinaryFromReader); + msg.setEvent(value); + break; + case 22: + var value = new node_pb.CallbackMessage; + reader.readMessage(value,node_pb.CallbackMessage.deserializeBinaryFromReader); + msg.setCallback(value); + break; + case 18: + var value = new node_pb.Pong; + reader.readMessage(value,node_pb.Pong.deserializeBinaryFromReader); + msg.setPong(value); break; case 16: var value = new proto.WorkingInitMessage; @@ -435,11 +402,6 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) { reader.readMessage(value,vscode_pb.SharedProcessActiveMessage.deserializeBinaryFromReader); msg.setSharedProcessActive(value); break; - case 18: - var value = new node_pb.Pong; - reader.readMessage(value,node_pb.Pong.deserializeBinaryFromReader); - msg.setPong(value); - break; default: reader.skipField(); break; @@ -469,28 +431,44 @@ proto.ServerMessage.prototype.serializeBinary = function() { */ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getEvalFailed(); + f = message.getFail(); if (f != null) { writer.writeMessage( 13, f, - node_pb.EvalFailedMessage.serializeBinaryToWriter + node_pb.FailMessage.serializeBinaryToWriter ); } - f = message.getEvalDone(); + f = message.getSuccess(); if (f != null) { writer.writeMessage( 14, f, - node_pb.EvalDoneMessage.serializeBinaryToWriter + node_pb.SuccessMessage.serializeBinaryToWriter ); } - f = message.getEvalEvent(); + f = message.getEvent(); if (f != null) { writer.writeMessage( - 15, + 19, f, - node_pb.EvalEventMessage.serializeBinaryToWriter + node_pb.EventMessage.serializeBinaryToWriter + ); + } + f = message.getCallback(); + if (f != null) { + writer.writeMessage( + 22, + f, + node_pb.CallbackMessage.serializeBinaryToWriter + ); + } + f = message.getPong(); + if (f != null) { + writer.writeMessage( + 18, + f, + node_pb.Pong.serializeBinaryToWriter ); } f = message.getInit(); @@ -509,35 +487,27 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) { vscode_pb.SharedProcessActiveMessage.serializeBinaryToWriter ); } - f = message.getPong(); - if (f != null) { - writer.writeMessage( - 18, - f, - node_pb.Pong.serializeBinaryToWriter - ); - } }; /** - * optional EvalFailedMessage eval_failed = 13; - * @return {?proto.EvalFailedMessage} + * optional FailMessage fail = 13; + * @return {?proto.FailMessage} */ -proto.ServerMessage.prototype.getEvalFailed = function() { - return /** @type{?proto.EvalFailedMessage} */ ( - jspb.Message.getWrapperField(this, node_pb.EvalFailedMessage, 13)); +proto.ServerMessage.prototype.getFail = function() { + return /** @type{?proto.FailMessage} */ ( + jspb.Message.getWrapperField(this, node_pb.FailMessage, 13)); }; -/** @param {?proto.EvalFailedMessage|undefined} value */ -proto.ServerMessage.prototype.setEvalFailed = function(value) { +/** @param {?proto.FailMessage|undefined} value */ +proto.ServerMessage.prototype.setFail = function(value) { jspb.Message.setOneofWrapperField(this, 13, proto.ServerMessage.oneofGroups_[0], value); }; -proto.ServerMessage.prototype.clearEvalFailed = function() { - this.setEvalFailed(undefined); +proto.ServerMessage.prototype.clearFail = function() { + this.setFail(undefined); }; @@ -545,29 +515,29 @@ proto.ServerMessage.prototype.clearEvalFailed = function() { * Returns whether this field is set. * @return {!boolean} */ -proto.ServerMessage.prototype.hasEvalFailed = function() { +proto.ServerMessage.prototype.hasFail = function() { return jspb.Message.getField(this, 13) != null; }; /** - * optional EvalDoneMessage eval_done = 14; - * @return {?proto.EvalDoneMessage} + * optional SuccessMessage success = 14; + * @return {?proto.SuccessMessage} */ -proto.ServerMessage.prototype.getEvalDone = function() { - return /** @type{?proto.EvalDoneMessage} */ ( - jspb.Message.getWrapperField(this, node_pb.EvalDoneMessage, 14)); +proto.ServerMessage.prototype.getSuccess = function() { + return /** @type{?proto.SuccessMessage} */ ( + jspb.Message.getWrapperField(this, node_pb.SuccessMessage, 14)); }; -/** @param {?proto.EvalDoneMessage|undefined} value */ -proto.ServerMessage.prototype.setEvalDone = function(value) { +/** @param {?proto.SuccessMessage|undefined} value */ +proto.ServerMessage.prototype.setSuccess = function(value) { jspb.Message.setOneofWrapperField(this, 14, proto.ServerMessage.oneofGroups_[0], value); }; -proto.ServerMessage.prototype.clearEvalDone = function() { - this.setEvalDone(undefined); +proto.ServerMessage.prototype.clearSuccess = function() { + this.setSuccess(undefined); }; @@ -575,29 +545,29 @@ proto.ServerMessage.prototype.clearEvalDone = function() { * Returns whether this field is set. * @return {!boolean} */ -proto.ServerMessage.prototype.hasEvalDone = function() { +proto.ServerMessage.prototype.hasSuccess = function() { return jspb.Message.getField(this, 14) != null; }; /** - * optional EvalEventMessage eval_event = 15; - * @return {?proto.EvalEventMessage} + * optional EventMessage event = 19; + * @return {?proto.EventMessage} */ -proto.ServerMessage.prototype.getEvalEvent = function() { - return /** @type{?proto.EvalEventMessage} */ ( - jspb.Message.getWrapperField(this, node_pb.EvalEventMessage, 15)); +proto.ServerMessage.prototype.getEvent = function() { + return /** @type{?proto.EventMessage} */ ( + jspb.Message.getWrapperField(this, node_pb.EventMessage, 19)); }; -/** @param {?proto.EvalEventMessage|undefined} value */ -proto.ServerMessage.prototype.setEvalEvent = function(value) { - jspb.Message.setOneofWrapperField(this, 15, proto.ServerMessage.oneofGroups_[0], value); +/** @param {?proto.EventMessage|undefined} value */ +proto.ServerMessage.prototype.setEvent = function(value) { + jspb.Message.setOneofWrapperField(this, 19, proto.ServerMessage.oneofGroups_[0], value); }; -proto.ServerMessage.prototype.clearEvalEvent = function() { - this.setEvalEvent(undefined); +proto.ServerMessage.prototype.clearEvent = function() { + this.setEvent(undefined); }; @@ -605,8 +575,68 @@ proto.ServerMessage.prototype.clearEvalEvent = function() { * Returns whether this field is set. * @return {!boolean} */ -proto.ServerMessage.prototype.hasEvalEvent = function() { - return jspb.Message.getField(this, 15) != null; +proto.ServerMessage.prototype.hasEvent = function() { + return jspb.Message.getField(this, 19) != null; +}; + + +/** + * optional CallbackMessage callback = 22; + * @return {?proto.CallbackMessage} + */ +proto.ServerMessage.prototype.getCallback = function() { + return /** @type{?proto.CallbackMessage} */ ( + jspb.Message.getWrapperField(this, node_pb.CallbackMessage, 22)); +}; + + +/** @param {?proto.CallbackMessage|undefined} value */ +proto.ServerMessage.prototype.setCallback = function(value) { + jspb.Message.setOneofWrapperField(this, 22, proto.ServerMessage.oneofGroups_[0], value); +}; + + +proto.ServerMessage.prototype.clearCallback = function() { + this.setCallback(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.ServerMessage.prototype.hasCallback = function() { + return jspb.Message.getField(this, 22) != null; +}; + + +/** + * optional Pong pong = 18; + * @return {?proto.Pong} + */ +proto.ServerMessage.prototype.getPong = function() { + return /** @type{?proto.Pong} */ ( + jspb.Message.getWrapperField(this, node_pb.Pong, 18)); +}; + + +/** @param {?proto.Pong|undefined} value */ +proto.ServerMessage.prototype.setPong = function(value) { + jspb.Message.setOneofWrapperField(this, 18, proto.ServerMessage.oneofGroups_[0], value); +}; + + +proto.ServerMessage.prototype.clearPong = function() { + this.setPong(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.ServerMessage.prototype.hasPong = function() { + return jspb.Message.getField(this, 18) != null; }; @@ -670,36 +700,6 @@ proto.ServerMessage.prototype.hasSharedProcessActive = function() { }; -/** - * optional Pong pong = 18; - * @return {?proto.Pong} - */ -proto.ServerMessage.prototype.getPong = function() { - return /** @type{?proto.Pong} */ ( - jspb.Message.getWrapperField(this, node_pb.Pong, 18)); -}; - - -/** @param {?proto.Pong|undefined} value */ -proto.ServerMessage.prototype.setPong = function(value) { - jspb.Message.setOneofWrapperField(this, 18, proto.ServerMessage.oneofGroups_[0], value); -}; - - -proto.ServerMessage.prototype.clearPong = function() { - this.setPong(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {!boolean} - */ -proto.ServerMessage.prototype.hasPong = function() { - return jspb.Message.getField(this, 18) != null; -}; - - /** * Generated by JsPbCodeGenerator. diff --git a/packages/protocol/src/proto/node.proto b/packages/protocol/src/proto/node.proto index e0610761..889e7741 100644 --- a/packages/protocol/src/proto/node.proto +++ b/packages/protocol/src/proto/node.proto @@ -1,28 +1,90 @@ syntax = "proto3"; -message NewEvalMessage { - uint64 id = 1; - string function = 2; - repeated string args = 3; - // Timeout in ms - uint32 timeout = 4; - // Create active eval message. - // Allows for dynamic communication for an eval - bool active = 5; +enum Module { + ChildProcess = 0; + Fs = 1; + Net = 2; + NodePty = 3; + Spdlog = 4; + Trash = 5; } -message EvalEventMessage { +// A proxy identified by a unique name like "fs". +message NamedProxyMessage { uint64 id = 1; + Module module = 2; + string method = 3; + repeated string args = 4; +} + +// A general proxy identified by an ID like WriteStream. +message NumberedProxyMessage { + uint64 id = 1; + uint64 proxy_id = 2; + string method = 3; + repeated string args = 4; +} + +// Call a remote method. +message MethodMessage { + oneof msg { + NamedProxyMessage named_proxy = 1; + NumberedProxyMessage numbered_proxy = 2; + } +} + +// Call a remote callback. +message CallbackMessage { + oneof msg { + NamedCallbackMessage named_callback = 1; + NumberedCallbackMessage numbered_callback = 2; + } +} + +// A remote callback for uniquely named proxy. +message NamedCallbackMessage { + Module module = 1; + uint64 callback_id = 2; + repeated string args = 3; +} + +// A remote callback for a numbered proxy. +message NumberedCallbackMessage { + uint64 proxy_id = 1; + uint64 callback_id = 2; + repeated string args = 3; +} + +// Emit an event. +message EventMessage { + oneof msg { + NamedEventMessage named_event = 1; + NumberedEventMessage numbered_event = 2; + } +} + +// Emit an event on a uniquely named proxy. +message NamedEventMessage { + Module module = 1; string event = 2; repeated string args = 3; } -message EvalFailedMessage { +// Emit an event on a numbered proxy. +message NumberedEventMessage { + uint64 proxy_id = 1; + string event = 2; + repeated string args = 3; +} + +// Remote method failed. +message FailMessage { uint64 id = 1; string response = 2; } -message EvalDoneMessage { +// Remote method succeeded. +message SuccessMessage { uint64 id = 1; string response = 2; } diff --git a/packages/protocol/src/proto/node_pb.d.ts b/packages/protocol/src/proto/node_pb.d.ts index 7a1a8744..ded41450 100644 --- a/packages/protocol/src/proto/node_pb.d.ts +++ b/packages/protocol/src/proto/node_pb.d.ts @@ -3,48 +3,243 @@ import * as jspb from "google-protobuf"; -export class NewEvalMessage extends jspb.Message { +export class NamedProxyMessage extends jspb.Message { getId(): number; setId(value: number): void; - getFunction(): string; - setFunction(value: string): void; + getModule(): Module; + setModule(value: Module): void; + + getMethod(): string; + setMethod(value: string): void; clearArgsList(): void; getArgsList(): Array; setArgsList(value: Array): void; addArgs(value: string, index?: number): string; - getTimeout(): number; - setTimeout(value: number): void; - - getActive(): boolean; - setActive(value: boolean): void; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): NewEvalMessage.AsObject; - static toObject(includeInstance: boolean, msg: NewEvalMessage): NewEvalMessage.AsObject; + toObject(includeInstance?: boolean): NamedProxyMessage.AsObject; + static toObject(includeInstance: boolean, msg: NamedProxyMessage): NamedProxyMessage.AsObject; static extensions: {[key: number]: jspb.ExtensionFieldInfo}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: NewEvalMessage, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): NewEvalMessage; - static deserializeBinaryFromReader(message: NewEvalMessage, reader: jspb.BinaryReader): NewEvalMessage; + static serializeBinaryToWriter(message: NamedProxyMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NamedProxyMessage; + static deserializeBinaryFromReader(message: NamedProxyMessage, reader: jspb.BinaryReader): NamedProxyMessage; } -export namespace NewEvalMessage { +export namespace NamedProxyMessage { export type AsObject = { id: number, - pb_function: string, + module: Module, + method: string, argsList: Array, - timeout: number, - active: boolean, } } -export class EvalEventMessage extends jspb.Message { +export class NumberedProxyMessage extends jspb.Message { getId(): number; setId(value: number): void; + getProxyId(): number; + setProxyId(value: number): void; + + getMethod(): string; + setMethod(value: string): void; + + clearArgsList(): void; + getArgsList(): Array; + setArgsList(value: Array): void; + addArgs(value: string, index?: number): string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NumberedProxyMessage.AsObject; + static toObject(includeInstance: boolean, msg: NumberedProxyMessage): NumberedProxyMessage.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NumberedProxyMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NumberedProxyMessage; + static deserializeBinaryFromReader(message: NumberedProxyMessage, reader: jspb.BinaryReader): NumberedProxyMessage; +} + +export namespace NumberedProxyMessage { + export type AsObject = { + id: number, + proxyId: number, + method: string, + argsList: Array, + } +} + +export class MethodMessage extends jspb.Message { + hasNamedProxy(): boolean; + clearNamedProxy(): void; + getNamedProxy(): NamedProxyMessage | undefined; + setNamedProxy(value?: NamedProxyMessage): void; + + hasNumberedProxy(): boolean; + clearNumberedProxy(): void; + getNumberedProxy(): NumberedProxyMessage | undefined; + setNumberedProxy(value?: NumberedProxyMessage): void; + + getMsgCase(): MethodMessage.MsgCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): MethodMessage.AsObject; + static toObject(includeInstance: boolean, msg: MethodMessage): MethodMessage.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: MethodMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): MethodMessage; + static deserializeBinaryFromReader(message: MethodMessage, reader: jspb.BinaryReader): MethodMessage; +} + +export namespace MethodMessage { + export type AsObject = { + namedProxy?: NamedProxyMessage.AsObject, + numberedProxy?: NumberedProxyMessage.AsObject, + } + + export enum MsgCase { + MSG_NOT_SET = 0, + NAMED_PROXY = 1, + NUMBERED_PROXY = 2, + } +} + +export class CallbackMessage extends jspb.Message { + hasNamedCallback(): boolean; + clearNamedCallback(): void; + getNamedCallback(): NamedCallbackMessage | undefined; + setNamedCallback(value?: NamedCallbackMessage): void; + + hasNumberedCallback(): boolean; + clearNumberedCallback(): void; + getNumberedCallback(): NumberedCallbackMessage | undefined; + setNumberedCallback(value?: NumberedCallbackMessage): void; + + getMsgCase(): CallbackMessage.MsgCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): CallbackMessage.AsObject; + static toObject(includeInstance: boolean, msg: CallbackMessage): CallbackMessage.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: CallbackMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): CallbackMessage; + static deserializeBinaryFromReader(message: CallbackMessage, reader: jspb.BinaryReader): CallbackMessage; +} + +export namespace CallbackMessage { + export type AsObject = { + namedCallback?: NamedCallbackMessage.AsObject, + numberedCallback?: NumberedCallbackMessage.AsObject, + } + + export enum MsgCase { + MSG_NOT_SET = 0, + NAMED_CALLBACK = 1, + NUMBERED_CALLBACK = 2, + } +} + +export class NamedCallbackMessage extends jspb.Message { + getModule(): Module; + setModule(value: Module): void; + + getCallbackId(): number; + setCallbackId(value: number): void; + + clearArgsList(): void; + getArgsList(): Array; + setArgsList(value: Array): void; + addArgs(value: string, index?: number): string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NamedCallbackMessage.AsObject; + static toObject(includeInstance: boolean, msg: NamedCallbackMessage): NamedCallbackMessage.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NamedCallbackMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NamedCallbackMessage; + static deserializeBinaryFromReader(message: NamedCallbackMessage, reader: jspb.BinaryReader): NamedCallbackMessage; +} + +export namespace NamedCallbackMessage { + export type AsObject = { + module: Module, + callbackId: number, + argsList: Array, + } +} + +export class NumberedCallbackMessage extends jspb.Message { + getProxyId(): number; + setProxyId(value: number): void; + + getCallbackId(): number; + setCallbackId(value: number): void; + + clearArgsList(): void; + getArgsList(): Array; + setArgsList(value: Array): void; + addArgs(value: string, index?: number): string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NumberedCallbackMessage.AsObject; + static toObject(includeInstance: boolean, msg: NumberedCallbackMessage): NumberedCallbackMessage.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NumberedCallbackMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NumberedCallbackMessage; + static deserializeBinaryFromReader(message: NumberedCallbackMessage, reader: jspb.BinaryReader): NumberedCallbackMessage; +} + +export namespace NumberedCallbackMessage { + export type AsObject = { + proxyId: number, + callbackId: number, + argsList: Array, + } +} + +export class EventMessage extends jspb.Message { + hasNamedEvent(): boolean; + clearNamedEvent(): void; + getNamedEvent(): NamedEventMessage | undefined; + setNamedEvent(value?: NamedEventMessage): void; + + hasNumberedEvent(): boolean; + clearNumberedEvent(): void; + getNumberedEvent(): NumberedEventMessage | undefined; + setNumberedEvent(value?: NumberedEventMessage): void; + + getMsgCase(): EventMessage.MsgCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): EventMessage.AsObject; + static toObject(includeInstance: boolean, msg: EventMessage): EventMessage.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: EventMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): EventMessage; + static deserializeBinaryFromReader(message: EventMessage, reader: jspb.BinaryReader): EventMessage; +} + +export namespace EventMessage { + export type AsObject = { + namedEvent?: NamedEventMessage.AsObject, + numberedEvent?: NumberedEventMessage.AsObject, + } + + export enum MsgCase { + MSG_NOT_SET = 0, + NAMED_EVENT = 1, + NUMBERED_EVENT = 2, + } +} + +export class NamedEventMessage extends jspb.Message { + getModule(): Module; + setModule(value: Module): void; + getEvent(): string; setEvent(value: string): void; @@ -54,24 +249,54 @@ export class EvalEventMessage extends jspb.Message { addArgs(value: string, index?: number): string; serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): EvalEventMessage.AsObject; - static toObject(includeInstance: boolean, msg: EvalEventMessage): EvalEventMessage.AsObject; + toObject(includeInstance?: boolean): NamedEventMessage.AsObject; + static toObject(includeInstance: boolean, msg: NamedEventMessage): NamedEventMessage.AsObject; static extensions: {[key: number]: jspb.ExtensionFieldInfo}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: EvalEventMessage, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): EvalEventMessage; - static deserializeBinaryFromReader(message: EvalEventMessage, reader: jspb.BinaryReader): EvalEventMessage; + static serializeBinaryToWriter(message: NamedEventMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NamedEventMessage; + static deserializeBinaryFromReader(message: NamedEventMessage, reader: jspb.BinaryReader): NamedEventMessage; } -export namespace EvalEventMessage { +export namespace NamedEventMessage { export type AsObject = { - id: number, + module: Module, event: string, argsList: Array, } } -export class EvalFailedMessage extends jspb.Message { +export class NumberedEventMessage extends jspb.Message { + getProxyId(): number; + setProxyId(value: number): void; + + getEvent(): string; + setEvent(value: string): void; + + clearArgsList(): void; + getArgsList(): Array; + setArgsList(value: Array): void; + addArgs(value: string, index?: number): string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NumberedEventMessage.AsObject; + static toObject(includeInstance: boolean, msg: NumberedEventMessage): NumberedEventMessage.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NumberedEventMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NumberedEventMessage; + static deserializeBinaryFromReader(message: NumberedEventMessage, reader: jspb.BinaryReader): NumberedEventMessage; +} + +export namespace NumberedEventMessage { + export type AsObject = { + proxyId: number, + event: string, + argsList: Array, + } +} + +export class FailMessage extends jspb.Message { getId(): number; setId(value: number): void; @@ -79,23 +304,23 @@ export class EvalFailedMessage extends jspb.Message { setResponse(value: string): void; serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): EvalFailedMessage.AsObject; - static toObject(includeInstance: boolean, msg: EvalFailedMessage): EvalFailedMessage.AsObject; + toObject(includeInstance?: boolean): FailMessage.AsObject; + static toObject(includeInstance: boolean, msg: FailMessage): FailMessage.AsObject; static extensions: {[key: number]: jspb.ExtensionFieldInfo}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: EvalFailedMessage, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): EvalFailedMessage; - static deserializeBinaryFromReader(message: EvalFailedMessage, reader: jspb.BinaryReader): EvalFailedMessage; + static serializeBinaryToWriter(message: FailMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): FailMessage; + static deserializeBinaryFromReader(message: FailMessage, reader: jspb.BinaryReader): FailMessage; } -export namespace EvalFailedMessage { +export namespace FailMessage { export type AsObject = { id: number, response: string, } } -export class EvalDoneMessage extends jspb.Message { +export class SuccessMessage extends jspb.Message { getId(): number; setId(value: number): void; @@ -103,16 +328,16 @@ export class EvalDoneMessage extends jspb.Message { setResponse(value: string): void; serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): EvalDoneMessage.AsObject; - static toObject(includeInstance: boolean, msg: EvalDoneMessage): EvalDoneMessage.AsObject; + toObject(includeInstance?: boolean): SuccessMessage.AsObject; + static toObject(includeInstance: boolean, msg: SuccessMessage): SuccessMessage.AsObject; static extensions: {[key: number]: jspb.ExtensionFieldInfo}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: EvalDoneMessage, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): EvalDoneMessage; - static deserializeBinaryFromReader(message: EvalDoneMessage, reader: jspb.BinaryReader): EvalDoneMessage; + static serializeBinaryToWriter(message: SuccessMessage, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): SuccessMessage; + static deserializeBinaryFromReader(message: SuccessMessage, reader: jspb.BinaryReader): SuccessMessage; } -export namespace EvalDoneMessage { +export namespace SuccessMessage { export type AsObject = { id: number, response: string, @@ -151,3 +376,12 @@ export namespace Pong { } } +export enum Module { + CHILDPROCESS = 0, + FS = 1, + NET = 2, + NODEPTY = 3, + SPDLOG = 4, + TRASH = 5, +} + diff --git a/packages/protocol/src/proto/node_pb.js b/packages/protocol/src/proto/node_pb.js index 62585b06..a0423f9c 100644 --- a/packages/protocol/src/proto/node_pb.js +++ b/packages/protocol/src/proto/node_pb.js @@ -11,12 +11,20 @@ var jspb = require('google-protobuf'); var goog = jspb; var global = Function('return this')(); -goog.exportSymbol('proto.EvalDoneMessage', null, global); -goog.exportSymbol('proto.EvalEventMessage', null, global); -goog.exportSymbol('proto.EvalFailedMessage', null, global); -goog.exportSymbol('proto.NewEvalMessage', null, global); +goog.exportSymbol('proto.CallbackMessage', null, global); +goog.exportSymbol('proto.EventMessage', null, global); +goog.exportSymbol('proto.FailMessage', null, global); +goog.exportSymbol('proto.MethodMessage', null, global); +goog.exportSymbol('proto.Module', null, global); +goog.exportSymbol('proto.NamedCallbackMessage', null, global); +goog.exportSymbol('proto.NamedEventMessage', null, global); +goog.exportSymbol('proto.NamedProxyMessage', null, global); +goog.exportSymbol('proto.NumberedCallbackMessage', null, global); +goog.exportSymbol('proto.NumberedEventMessage', null, global); +goog.exportSymbol('proto.NumberedProxyMessage', null, global); goog.exportSymbol('proto.Ping', null, global); goog.exportSymbol('proto.Pong', null, global); +goog.exportSymbol('proto.SuccessMessage', null, global); /** * Generated by JsPbCodeGenerator. @@ -28,19 +36,19 @@ goog.exportSymbol('proto.Pong', null, global); * @extends {jspb.Message} * @constructor */ -proto.NewEvalMessage = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.NewEvalMessage.repeatedFields_, null); +proto.NamedProxyMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.NamedProxyMessage.repeatedFields_, null); }; -goog.inherits(proto.NewEvalMessage, jspb.Message); +goog.inherits(proto.NamedProxyMessage, jspb.Message); if (goog.DEBUG && !COMPILED) { - proto.NewEvalMessage.displayName = 'proto.NewEvalMessage'; + proto.NamedProxyMessage.displayName = 'proto.NamedProxyMessage'; } /** * List of repeated fields within this message type. * @private {!Array} * @const */ -proto.NewEvalMessage.repeatedFields_ = [3]; +proto.NamedProxyMessage.repeatedFields_ = [4]; @@ -55,8 +63,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * for transitional soy proto support: http://goto/soy-param-migration * @return {!Object} */ -proto.NewEvalMessage.prototype.toObject = function(opt_includeInstance) { - return proto.NewEvalMessage.toObject(opt_includeInstance, this); +proto.NamedProxyMessage.prototype.toObject = function(opt_includeInstance) { + return proto.NamedProxyMessage.toObject(opt_includeInstance, this); }; @@ -65,17 +73,16 @@ proto.NewEvalMessage.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Whether to include the JSPB * instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.NewEvalMessage} msg The msg instance to transform. + * @param {!proto.NamedProxyMessage} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.NewEvalMessage.toObject = function(includeInstance, msg) { +proto.NamedProxyMessage.toObject = function(includeInstance, msg) { var f, obj = { id: jspb.Message.getFieldWithDefault(msg, 1, 0), - pb_function: jspb.Message.getFieldWithDefault(msg, 2, ""), - argsList: jspb.Message.getRepeatedField(msg, 3), - timeout: jspb.Message.getFieldWithDefault(msg, 4, 0), - active: jspb.Message.getFieldWithDefault(msg, 5, false) + module: jspb.Message.getFieldWithDefault(msg, 2, 0), + method: jspb.Message.getFieldWithDefault(msg, 3, ""), + argsList: jspb.Message.getRepeatedField(msg, 4) }; if (includeInstance) { @@ -89,23 +96,23 @@ proto.NewEvalMessage.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.NewEvalMessage} + * @return {!proto.NamedProxyMessage} */ -proto.NewEvalMessage.deserializeBinary = function(bytes) { +proto.NamedProxyMessage.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.NewEvalMessage; - return proto.NewEvalMessage.deserializeBinaryFromReader(msg, reader); + var msg = new proto.NamedProxyMessage; + return proto.NamedProxyMessage.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.NewEvalMessage} msg The message object to deserialize into. + * @param {!proto.NamedProxyMessage} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.NewEvalMessage} + * @return {!proto.NamedProxyMessage} */ -proto.NewEvalMessage.deserializeBinaryFromReader = function(msg, reader) { +proto.NamedProxyMessage.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -117,20 +124,16 @@ proto.NewEvalMessage.deserializeBinaryFromReader = function(msg, reader) { msg.setId(value); break; case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setFunction(value); + var value = /** @type {!proto.Module} */ (reader.readEnum()); + msg.setModule(value); break; case 3: var value = /** @type {string} */ (reader.readString()); - msg.addArgs(value); + msg.setMethod(value); break; case 4: - var value = /** @type {number} */ (reader.readUint32()); - msg.setTimeout(value); - break; - case 5: - var value = /** @type {boolean} */ (reader.readBool()); - msg.setActive(value); + var value = /** @type {string} */ (reader.readString()); + msg.addArgs(value); break; default: reader.skipField(); @@ -145,9 +148,9 @@ proto.NewEvalMessage.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.NewEvalMessage.prototype.serializeBinary = function() { +proto.NamedProxyMessage.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.NewEvalMessage.serializeBinaryToWriter(this, writer); + proto.NamedProxyMessage.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -155,11 +158,11 @@ proto.NewEvalMessage.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.NewEvalMessage} message + * @param {!proto.NamedProxyMessage} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.NewEvalMessage.serializeBinaryToWriter = function(message, writer) { +proto.NamedProxyMessage.serializeBinaryToWriter = function(message, writer) { var f = undefined; f = message.getId(); if (f !== 0) { @@ -168,34 +171,27 @@ proto.NewEvalMessage.serializeBinaryToWriter = function(message, writer) { f ); } - f = message.getFunction(); + f = message.getModule(); + if (f !== 0.0) { + writer.writeEnum( + 2, + f + ); + } + f = message.getMethod(); if (f.length > 0) { writer.writeString( - 2, + 3, f ); } f = message.getArgsList(); if (f.length > 0) { writer.writeRepeatedString( - 3, - f - ); - } - f = message.getTimeout(); - if (f !== 0) { - writer.writeUint32( 4, f ); } - f = message.getActive(); - if (f) { - writer.writeBool( - 5, - f - ); - } }; @@ -203,44 +199,59 @@ proto.NewEvalMessage.serializeBinaryToWriter = function(message, writer) { * optional uint64 id = 1; * @return {number} */ -proto.NewEvalMessage.prototype.getId = function() { +proto.NamedProxyMessage.prototype.getId = function() { return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); }; /** @param {number} value */ -proto.NewEvalMessage.prototype.setId = function(value) { +proto.NamedProxyMessage.prototype.setId = function(value) { jspb.Message.setProto3IntField(this, 1, value); }; /** - * optional string function = 2; - * @return {string} + * optional Module module = 2; + * @return {!proto.Module} */ -proto.NewEvalMessage.prototype.getFunction = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +proto.NamedProxyMessage.prototype.getModule = function() { + return /** @type {!proto.Module} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); }; -/** @param {string} value */ -proto.NewEvalMessage.prototype.setFunction = function(value) { - jspb.Message.setProto3StringField(this, 2, value); +/** @param {!proto.Module} value */ +proto.NamedProxyMessage.prototype.setModule = function(value) { + jspb.Message.setProto3EnumField(this, 2, value); }; /** - * repeated string args = 3; + * optional string method = 3; + * @return {string} + */ +proto.NamedProxyMessage.prototype.getMethod = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** @param {string} value */ +proto.NamedProxyMessage.prototype.setMethod = function(value) { + jspb.Message.setProto3StringField(this, 3, value); +}; + + +/** + * repeated string args = 4; * @return {!Array} */ -proto.NewEvalMessage.prototype.getArgsList = function() { - return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); +proto.NamedProxyMessage.prototype.getArgsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 4)); }; /** @param {!Array} value */ -proto.NewEvalMessage.prototype.setArgsList = function(value) { - jspb.Message.setField(this, 3, value || []); +proto.NamedProxyMessage.prototype.setArgsList = function(value) { + jspb.Message.setField(this, 4, value || []); }; @@ -248,48 +259,16 @@ proto.NewEvalMessage.prototype.setArgsList = function(value) { * @param {!string} value * @param {number=} opt_index */ -proto.NewEvalMessage.prototype.addArgs = function(value, opt_index) { - jspb.Message.addToRepeatedField(this, 3, value, opt_index); +proto.NamedProxyMessage.prototype.addArgs = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 4, value, opt_index); }; -proto.NewEvalMessage.prototype.clearArgsList = function() { +proto.NamedProxyMessage.prototype.clearArgsList = function() { this.setArgsList([]); }; -/** - * optional uint32 timeout = 4; - * @return {number} - */ -proto.NewEvalMessage.prototype.getTimeout = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); -}; - - -/** @param {number} value */ -proto.NewEvalMessage.prototype.setTimeout = function(value) { - jspb.Message.setProto3IntField(this, 4, value); -}; - - -/** - * optional bool active = 5; - * Note that Boolean fields may be set to 0/1 when serialized from a Java server. - * You should avoid comparisons like {@code val === true/false} in those cases. - * @return {boolean} - */ -proto.NewEvalMessage.prototype.getActive = function() { - return /** @type {boolean} */ (jspb.Message.getFieldWithDefault(this, 5, false)); -}; - - -/** @param {boolean} value */ -proto.NewEvalMessage.prototype.setActive = function(value) { - jspb.Message.setProto3BooleanField(this, 5, value); -}; - - /** * Generated by JsPbCodeGenerator. @@ -301,19 +280,19 @@ proto.NewEvalMessage.prototype.setActive = function(value) { * @extends {jspb.Message} * @constructor */ -proto.EvalEventMessage = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.EvalEventMessage.repeatedFields_, null); +proto.NumberedProxyMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.NumberedProxyMessage.repeatedFields_, null); }; -goog.inherits(proto.EvalEventMessage, jspb.Message); +goog.inherits(proto.NumberedProxyMessage, jspb.Message); if (goog.DEBUG && !COMPILED) { - proto.EvalEventMessage.displayName = 'proto.EvalEventMessage'; + proto.NumberedProxyMessage.displayName = 'proto.NumberedProxyMessage'; } /** * List of repeated fields within this message type. * @private {!Array} * @const */ -proto.EvalEventMessage.repeatedFields_ = [3]; +proto.NumberedProxyMessage.repeatedFields_ = [4]; @@ -328,8 +307,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * for transitional soy proto support: http://goto/soy-param-migration * @return {!Object} */ -proto.EvalEventMessage.prototype.toObject = function(opt_includeInstance) { - return proto.EvalEventMessage.toObject(opt_includeInstance, this); +proto.NumberedProxyMessage.prototype.toObject = function(opt_includeInstance) { + return proto.NumberedProxyMessage.toObject(opt_includeInstance, this); }; @@ -338,13 +317,1378 @@ proto.EvalEventMessage.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Whether to include the JSPB * instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.EvalEventMessage} msg The msg instance to transform. + * @param {!proto.NumberedProxyMessage} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.EvalEventMessage.toObject = function(includeInstance, msg) { +proto.NumberedProxyMessage.toObject = function(includeInstance, msg) { var f, obj = { id: jspb.Message.getFieldWithDefault(msg, 1, 0), + proxyId: jspb.Message.getFieldWithDefault(msg, 2, 0), + method: jspb.Message.getFieldWithDefault(msg, 3, ""), + argsList: jspb.Message.getRepeatedField(msg, 4) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.NumberedProxyMessage} + */ +proto.NumberedProxyMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.NumberedProxyMessage; + return proto.NumberedProxyMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.NumberedProxyMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.NumberedProxyMessage} + */ +proto.NumberedProxyMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint64()); + msg.setId(value); + break; + case 2: + var value = /** @type {number} */ (reader.readUint64()); + msg.setProxyId(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.setMethod(value); + break; + case 4: + var value = /** @type {string} */ (reader.readString()); + msg.addArgs(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.NumberedProxyMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.NumberedProxyMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.NumberedProxyMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NumberedProxyMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getId(); + if (f !== 0) { + writer.writeUint64( + 1, + f + ); + } + f = message.getProxyId(); + if (f !== 0) { + writer.writeUint64( + 2, + f + ); + } + f = message.getMethod(); + if (f.length > 0) { + writer.writeString( + 3, + f + ); + } + f = message.getArgsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 4, + f + ); + } +}; + + +/** + * optional uint64 id = 1; + * @return {number} + */ +proto.NumberedProxyMessage.prototype.getId = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.NumberedProxyMessage.prototype.setId = function(value) { + jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional uint64 proxy_id = 2; + * @return {number} + */ +proto.NumberedProxyMessage.prototype.getProxyId = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.NumberedProxyMessage.prototype.setProxyId = function(value) { + jspb.Message.setProto3IntField(this, 2, value); +}; + + +/** + * optional string method = 3; + * @return {string} + */ +proto.NumberedProxyMessage.prototype.getMethod = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** @param {string} value */ +proto.NumberedProxyMessage.prototype.setMethod = function(value) { + jspb.Message.setProto3StringField(this, 3, value); +}; + + +/** + * repeated string args = 4; + * @return {!Array} + */ +proto.NumberedProxyMessage.prototype.getArgsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 4)); +}; + + +/** @param {!Array} value */ +proto.NumberedProxyMessage.prototype.setArgsList = function(value) { + jspb.Message.setField(this, 4, value || []); +}; + + +/** + * @param {!string} value + * @param {number=} opt_index + */ +proto.NumberedProxyMessage.prototype.addArgs = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 4, value, opt_index); +}; + + +proto.NumberedProxyMessage.prototype.clearArgsList = function() { + this.setArgsList([]); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.MethodMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.MethodMessage.oneofGroups_); +}; +goog.inherits(proto.MethodMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.MethodMessage.displayName = 'proto.MethodMessage'; +} +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.MethodMessage.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.MethodMessage.MsgCase = { + MSG_NOT_SET: 0, + NAMED_PROXY: 1, + NUMBERED_PROXY: 2 +}; + +/** + * @return {proto.MethodMessage.MsgCase} + */ +proto.MethodMessage.prototype.getMsgCase = function() { + return /** @type {proto.MethodMessage.MsgCase} */(jspb.Message.computeOneofCase(this, proto.MethodMessage.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.MethodMessage.prototype.toObject = function(opt_includeInstance) { + return proto.MethodMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.MethodMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.MethodMessage.toObject = function(includeInstance, msg) { + var f, obj = { + namedProxy: (f = msg.getNamedProxy()) && proto.NamedProxyMessage.toObject(includeInstance, f), + numberedProxy: (f = msg.getNumberedProxy()) && proto.NumberedProxyMessage.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.MethodMessage} + */ +proto.MethodMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.MethodMessage; + return proto.MethodMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.MethodMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.MethodMessage} + */ +proto.MethodMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.NamedProxyMessage; + reader.readMessage(value,proto.NamedProxyMessage.deserializeBinaryFromReader); + msg.setNamedProxy(value); + break; + case 2: + var value = new proto.NumberedProxyMessage; + reader.readMessage(value,proto.NumberedProxyMessage.deserializeBinaryFromReader); + msg.setNumberedProxy(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.MethodMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.MethodMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.MethodMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.MethodMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNamedProxy(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.NamedProxyMessage.serializeBinaryToWriter + ); + } + f = message.getNumberedProxy(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.NumberedProxyMessage.serializeBinaryToWriter + ); + } +}; + + +/** + * optional NamedProxyMessage named_proxy = 1; + * @return {?proto.NamedProxyMessage} + */ +proto.MethodMessage.prototype.getNamedProxy = function() { + return /** @type{?proto.NamedProxyMessage} */ ( + jspb.Message.getWrapperField(this, proto.NamedProxyMessage, 1)); +}; + + +/** @param {?proto.NamedProxyMessage|undefined} value */ +proto.MethodMessage.prototype.setNamedProxy = function(value) { + jspb.Message.setOneofWrapperField(this, 1, proto.MethodMessage.oneofGroups_[0], value); +}; + + +proto.MethodMessage.prototype.clearNamedProxy = function() { + this.setNamedProxy(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.MethodMessage.prototype.hasNamedProxy = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional NumberedProxyMessage numbered_proxy = 2; + * @return {?proto.NumberedProxyMessage} + */ +proto.MethodMessage.prototype.getNumberedProxy = function() { + return /** @type{?proto.NumberedProxyMessage} */ ( + jspb.Message.getWrapperField(this, proto.NumberedProxyMessage, 2)); +}; + + +/** @param {?proto.NumberedProxyMessage|undefined} value */ +proto.MethodMessage.prototype.setNumberedProxy = function(value) { + jspb.Message.setOneofWrapperField(this, 2, proto.MethodMessage.oneofGroups_[0], value); +}; + + +proto.MethodMessage.prototype.clearNumberedProxy = function() { + this.setNumberedProxy(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.MethodMessage.prototype.hasNumberedProxy = function() { + return jspb.Message.getField(this, 2) != null; +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.CallbackMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.CallbackMessage.oneofGroups_); +}; +goog.inherits(proto.CallbackMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.CallbackMessage.displayName = 'proto.CallbackMessage'; +} +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.CallbackMessage.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.CallbackMessage.MsgCase = { + MSG_NOT_SET: 0, + NAMED_CALLBACK: 1, + NUMBERED_CALLBACK: 2 +}; + +/** + * @return {proto.CallbackMessage.MsgCase} + */ +proto.CallbackMessage.prototype.getMsgCase = function() { + return /** @type {proto.CallbackMessage.MsgCase} */(jspb.Message.computeOneofCase(this, proto.CallbackMessage.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.CallbackMessage.prototype.toObject = function(opt_includeInstance) { + return proto.CallbackMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.CallbackMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.CallbackMessage.toObject = function(includeInstance, msg) { + var f, obj = { + namedCallback: (f = msg.getNamedCallback()) && proto.NamedCallbackMessage.toObject(includeInstance, f), + numberedCallback: (f = msg.getNumberedCallback()) && proto.NumberedCallbackMessage.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.CallbackMessage} + */ +proto.CallbackMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.CallbackMessage; + return proto.CallbackMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.CallbackMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.CallbackMessage} + */ +proto.CallbackMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.NamedCallbackMessage; + reader.readMessage(value,proto.NamedCallbackMessage.deserializeBinaryFromReader); + msg.setNamedCallback(value); + break; + case 2: + var value = new proto.NumberedCallbackMessage; + reader.readMessage(value,proto.NumberedCallbackMessage.deserializeBinaryFromReader); + msg.setNumberedCallback(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.CallbackMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.CallbackMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.CallbackMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.CallbackMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNamedCallback(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.NamedCallbackMessage.serializeBinaryToWriter + ); + } + f = message.getNumberedCallback(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.NumberedCallbackMessage.serializeBinaryToWriter + ); + } +}; + + +/** + * optional NamedCallbackMessage named_callback = 1; + * @return {?proto.NamedCallbackMessage} + */ +proto.CallbackMessage.prototype.getNamedCallback = function() { + return /** @type{?proto.NamedCallbackMessage} */ ( + jspb.Message.getWrapperField(this, proto.NamedCallbackMessage, 1)); +}; + + +/** @param {?proto.NamedCallbackMessage|undefined} value */ +proto.CallbackMessage.prototype.setNamedCallback = function(value) { + jspb.Message.setOneofWrapperField(this, 1, proto.CallbackMessage.oneofGroups_[0], value); +}; + + +proto.CallbackMessage.prototype.clearNamedCallback = function() { + this.setNamedCallback(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.CallbackMessage.prototype.hasNamedCallback = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional NumberedCallbackMessage numbered_callback = 2; + * @return {?proto.NumberedCallbackMessage} + */ +proto.CallbackMessage.prototype.getNumberedCallback = function() { + return /** @type{?proto.NumberedCallbackMessage} */ ( + jspb.Message.getWrapperField(this, proto.NumberedCallbackMessage, 2)); +}; + + +/** @param {?proto.NumberedCallbackMessage|undefined} value */ +proto.CallbackMessage.prototype.setNumberedCallback = function(value) { + jspb.Message.setOneofWrapperField(this, 2, proto.CallbackMessage.oneofGroups_[0], value); +}; + + +proto.CallbackMessage.prototype.clearNumberedCallback = function() { + this.setNumberedCallback(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.CallbackMessage.prototype.hasNumberedCallback = function() { + return jspb.Message.getField(this, 2) != null; +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.NamedCallbackMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.NamedCallbackMessage.repeatedFields_, null); +}; +goog.inherits(proto.NamedCallbackMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.NamedCallbackMessage.displayName = 'proto.NamedCallbackMessage'; +} +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.NamedCallbackMessage.repeatedFields_ = [3]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.NamedCallbackMessage.prototype.toObject = function(opt_includeInstance) { + return proto.NamedCallbackMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.NamedCallbackMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NamedCallbackMessage.toObject = function(includeInstance, msg) { + var f, obj = { + module: jspb.Message.getFieldWithDefault(msg, 1, 0), + callbackId: jspb.Message.getFieldWithDefault(msg, 2, 0), + argsList: jspb.Message.getRepeatedField(msg, 3) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.NamedCallbackMessage} + */ +proto.NamedCallbackMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.NamedCallbackMessage; + return proto.NamedCallbackMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.NamedCallbackMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.NamedCallbackMessage} + */ +proto.NamedCallbackMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!proto.Module} */ (reader.readEnum()); + msg.setModule(value); + break; + case 2: + var value = /** @type {number} */ (reader.readUint64()); + msg.setCallbackId(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.addArgs(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.NamedCallbackMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.NamedCallbackMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.NamedCallbackMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NamedCallbackMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getModule(); + if (f !== 0.0) { + writer.writeEnum( + 1, + f + ); + } + f = message.getCallbackId(); + if (f !== 0) { + writer.writeUint64( + 2, + f + ); + } + f = message.getArgsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 3, + f + ); + } +}; + + +/** + * optional Module module = 1; + * @return {!proto.Module} + */ +proto.NamedCallbackMessage.prototype.getModule = function() { + return /** @type {!proto.Module} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** @param {!proto.Module} value */ +proto.NamedCallbackMessage.prototype.setModule = function(value) { + jspb.Message.setProto3EnumField(this, 1, value); +}; + + +/** + * optional uint64 callback_id = 2; + * @return {number} + */ +proto.NamedCallbackMessage.prototype.getCallbackId = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.NamedCallbackMessage.prototype.setCallbackId = function(value) { + jspb.Message.setProto3IntField(this, 2, value); +}; + + +/** + * repeated string args = 3; + * @return {!Array} + */ +proto.NamedCallbackMessage.prototype.getArgsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); +}; + + +/** @param {!Array} value */ +proto.NamedCallbackMessage.prototype.setArgsList = function(value) { + jspb.Message.setField(this, 3, value || []); +}; + + +/** + * @param {!string} value + * @param {number=} opt_index + */ +proto.NamedCallbackMessage.prototype.addArgs = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 3, value, opt_index); +}; + + +proto.NamedCallbackMessage.prototype.clearArgsList = function() { + this.setArgsList([]); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.NumberedCallbackMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.NumberedCallbackMessage.repeatedFields_, null); +}; +goog.inherits(proto.NumberedCallbackMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.NumberedCallbackMessage.displayName = 'proto.NumberedCallbackMessage'; +} +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.NumberedCallbackMessage.repeatedFields_ = [3]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.NumberedCallbackMessage.prototype.toObject = function(opt_includeInstance) { + return proto.NumberedCallbackMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.NumberedCallbackMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NumberedCallbackMessage.toObject = function(includeInstance, msg) { + var f, obj = { + proxyId: jspb.Message.getFieldWithDefault(msg, 1, 0), + callbackId: jspb.Message.getFieldWithDefault(msg, 2, 0), + argsList: jspb.Message.getRepeatedField(msg, 3) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.NumberedCallbackMessage} + */ +proto.NumberedCallbackMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.NumberedCallbackMessage; + return proto.NumberedCallbackMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.NumberedCallbackMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.NumberedCallbackMessage} + */ +proto.NumberedCallbackMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint64()); + msg.setProxyId(value); + break; + case 2: + var value = /** @type {number} */ (reader.readUint64()); + msg.setCallbackId(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.addArgs(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.NumberedCallbackMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.NumberedCallbackMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.NumberedCallbackMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NumberedCallbackMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProxyId(); + if (f !== 0) { + writer.writeUint64( + 1, + f + ); + } + f = message.getCallbackId(); + if (f !== 0) { + writer.writeUint64( + 2, + f + ); + } + f = message.getArgsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 3, + f + ); + } +}; + + +/** + * optional uint64 proxy_id = 1; + * @return {number} + */ +proto.NumberedCallbackMessage.prototype.getProxyId = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.NumberedCallbackMessage.prototype.setProxyId = function(value) { + jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional uint64 callback_id = 2; + * @return {number} + */ +proto.NumberedCallbackMessage.prototype.getCallbackId = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.NumberedCallbackMessage.prototype.setCallbackId = function(value) { + jspb.Message.setProto3IntField(this, 2, value); +}; + + +/** + * repeated string args = 3; + * @return {!Array} + */ +proto.NumberedCallbackMessage.prototype.getArgsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); +}; + + +/** @param {!Array} value */ +proto.NumberedCallbackMessage.prototype.setArgsList = function(value) { + jspb.Message.setField(this, 3, value || []); +}; + + +/** + * @param {!string} value + * @param {number=} opt_index + */ +proto.NumberedCallbackMessage.prototype.addArgs = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 3, value, opt_index); +}; + + +proto.NumberedCallbackMessage.prototype.clearArgsList = function() { + this.setArgsList([]); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.EventMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.EventMessage.oneofGroups_); +}; +goog.inherits(proto.EventMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.EventMessage.displayName = 'proto.EventMessage'; +} +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.EventMessage.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.EventMessage.MsgCase = { + MSG_NOT_SET: 0, + NAMED_EVENT: 1, + NUMBERED_EVENT: 2 +}; + +/** + * @return {proto.EventMessage.MsgCase} + */ +proto.EventMessage.prototype.getMsgCase = function() { + return /** @type {proto.EventMessage.MsgCase} */(jspb.Message.computeOneofCase(this, proto.EventMessage.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.EventMessage.prototype.toObject = function(opt_includeInstance) { + return proto.EventMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.EventMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.EventMessage.toObject = function(includeInstance, msg) { + var f, obj = { + namedEvent: (f = msg.getNamedEvent()) && proto.NamedEventMessage.toObject(includeInstance, f), + numberedEvent: (f = msg.getNumberedEvent()) && proto.NumberedEventMessage.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.EventMessage} + */ +proto.EventMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.EventMessage; + return proto.EventMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.EventMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.EventMessage} + */ +proto.EventMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.NamedEventMessage; + reader.readMessage(value,proto.NamedEventMessage.deserializeBinaryFromReader); + msg.setNamedEvent(value); + break; + case 2: + var value = new proto.NumberedEventMessage; + reader.readMessage(value,proto.NumberedEventMessage.deserializeBinaryFromReader); + msg.setNumberedEvent(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.EventMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.EventMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.EventMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.EventMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNamedEvent(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.NamedEventMessage.serializeBinaryToWriter + ); + } + f = message.getNumberedEvent(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.NumberedEventMessage.serializeBinaryToWriter + ); + } +}; + + +/** + * optional NamedEventMessage named_event = 1; + * @return {?proto.NamedEventMessage} + */ +proto.EventMessage.prototype.getNamedEvent = function() { + return /** @type{?proto.NamedEventMessage} */ ( + jspb.Message.getWrapperField(this, proto.NamedEventMessage, 1)); +}; + + +/** @param {?proto.NamedEventMessage|undefined} value */ +proto.EventMessage.prototype.setNamedEvent = function(value) { + jspb.Message.setOneofWrapperField(this, 1, proto.EventMessage.oneofGroups_[0], value); +}; + + +proto.EventMessage.prototype.clearNamedEvent = function() { + this.setNamedEvent(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.EventMessage.prototype.hasNamedEvent = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional NumberedEventMessage numbered_event = 2; + * @return {?proto.NumberedEventMessage} + */ +proto.EventMessage.prototype.getNumberedEvent = function() { + return /** @type{?proto.NumberedEventMessage} */ ( + jspb.Message.getWrapperField(this, proto.NumberedEventMessage, 2)); +}; + + +/** @param {?proto.NumberedEventMessage|undefined} value */ +proto.EventMessage.prototype.setNumberedEvent = function(value) { + jspb.Message.setOneofWrapperField(this, 2, proto.EventMessage.oneofGroups_[0], value); +}; + + +proto.EventMessage.prototype.clearNumberedEvent = function() { + this.setNumberedEvent(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {!boolean} + */ +proto.EventMessage.prototype.hasNumberedEvent = function() { + return jspb.Message.getField(this, 2) != null; +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.NamedEventMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.NamedEventMessage.repeatedFields_, null); +}; +goog.inherits(proto.NamedEventMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.NamedEventMessage.displayName = 'proto.NamedEventMessage'; +} +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.NamedEventMessage.repeatedFields_ = [3]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.NamedEventMessage.prototype.toObject = function(opt_includeInstance) { + return proto.NamedEventMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.NamedEventMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NamedEventMessage.toObject = function(includeInstance, msg) { + var f, obj = { + module: jspb.Message.getFieldWithDefault(msg, 1, 0), event: jspb.Message.getFieldWithDefault(msg, 2, ""), argsList: jspb.Message.getRepeatedField(msg, 3) }; @@ -360,23 +1704,23 @@ proto.EvalEventMessage.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.EvalEventMessage} + * @return {!proto.NamedEventMessage} */ -proto.EvalEventMessage.deserializeBinary = function(bytes) { +proto.NamedEventMessage.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.EvalEventMessage; - return proto.EvalEventMessage.deserializeBinaryFromReader(msg, reader); + var msg = new proto.NamedEventMessage; + return proto.NamedEventMessage.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.EvalEventMessage} msg The message object to deserialize into. + * @param {!proto.NamedEventMessage} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.EvalEventMessage} + * @return {!proto.NamedEventMessage} */ -proto.EvalEventMessage.deserializeBinaryFromReader = function(msg, reader) { +proto.NamedEventMessage.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -384,8 +1728,8 @@ proto.EvalEventMessage.deserializeBinaryFromReader = function(msg, reader) { var field = reader.getFieldNumber(); switch (field) { case 1: - var value = /** @type {number} */ (reader.readUint64()); - msg.setId(value); + var value = /** @type {!proto.Module} */ (reader.readEnum()); + msg.setModule(value); break; case 2: var value = /** @type {string} */ (reader.readString()); @@ -408,9 +1752,9 @@ proto.EvalEventMessage.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.EvalEventMessage.prototype.serializeBinary = function() { +proto.NamedEventMessage.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.EvalEventMessage.serializeBinaryToWriter(this, writer); + proto.NamedEventMessage.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -418,13 +1762,230 @@ proto.EvalEventMessage.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.EvalEventMessage} message + * @param {!proto.NamedEventMessage} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.EvalEventMessage.serializeBinaryToWriter = function(message, writer) { +proto.NamedEventMessage.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getId(); + f = message.getModule(); + if (f !== 0.0) { + writer.writeEnum( + 1, + f + ); + } + f = message.getEvent(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getArgsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 3, + f + ); + } +}; + + +/** + * optional Module module = 1; + * @return {!proto.Module} + */ +proto.NamedEventMessage.prototype.getModule = function() { + return /** @type {!proto.Module} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** @param {!proto.Module} value */ +proto.NamedEventMessage.prototype.setModule = function(value) { + jspb.Message.setProto3EnumField(this, 1, value); +}; + + +/** + * optional string event = 2; + * @return {string} + */ +proto.NamedEventMessage.prototype.getEvent = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** @param {string} value */ +proto.NamedEventMessage.prototype.setEvent = function(value) { + jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * repeated string args = 3; + * @return {!Array} + */ +proto.NamedEventMessage.prototype.getArgsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); +}; + + +/** @param {!Array} value */ +proto.NamedEventMessage.prototype.setArgsList = function(value) { + jspb.Message.setField(this, 3, value || []); +}; + + +/** + * @param {!string} value + * @param {number=} opt_index + */ +proto.NamedEventMessage.prototype.addArgs = function(value, opt_index) { + jspb.Message.addToRepeatedField(this, 3, value, opt_index); +}; + + +proto.NamedEventMessage.prototype.clearArgsList = function() { + this.setArgsList([]); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.NumberedEventMessage = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.NumberedEventMessage.repeatedFields_, null); +}; +goog.inherits(proto.NumberedEventMessage, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.NumberedEventMessage.displayName = 'proto.NumberedEventMessage'; +} +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.NumberedEventMessage.repeatedFields_ = [3]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.NumberedEventMessage.prototype.toObject = function(opt_includeInstance) { + return proto.NumberedEventMessage.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.NumberedEventMessage} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NumberedEventMessage.toObject = function(includeInstance, msg) { + var f, obj = { + proxyId: jspb.Message.getFieldWithDefault(msg, 1, 0), + event: jspb.Message.getFieldWithDefault(msg, 2, ""), + argsList: jspb.Message.getRepeatedField(msg, 3) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.NumberedEventMessage} + */ +proto.NumberedEventMessage.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.NumberedEventMessage; + return proto.NumberedEventMessage.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.NumberedEventMessage} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.NumberedEventMessage} + */ +proto.NumberedEventMessage.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint64()); + msg.setProxyId(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setEvent(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.addArgs(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.NumberedEventMessage.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.NumberedEventMessage.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.NumberedEventMessage} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.NumberedEventMessage.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProxyId(); if (f !== 0) { writer.writeUint64( 1, @@ -449,16 +2010,16 @@ proto.EvalEventMessage.serializeBinaryToWriter = function(message, writer) { /** - * optional uint64 id = 1; + * optional uint64 proxy_id = 1; * @return {number} */ -proto.EvalEventMessage.prototype.getId = function() { +proto.NumberedEventMessage.prototype.getProxyId = function() { return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); }; /** @param {number} value */ -proto.EvalEventMessage.prototype.setId = function(value) { +proto.NumberedEventMessage.prototype.setProxyId = function(value) { jspb.Message.setProto3IntField(this, 1, value); }; @@ -467,13 +2028,13 @@ proto.EvalEventMessage.prototype.setId = function(value) { * optional string event = 2; * @return {string} */ -proto.EvalEventMessage.prototype.getEvent = function() { +proto.NumberedEventMessage.prototype.getEvent = function() { return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); }; /** @param {string} value */ -proto.EvalEventMessage.prototype.setEvent = function(value) { +proto.NumberedEventMessage.prototype.setEvent = function(value) { jspb.Message.setProto3StringField(this, 2, value); }; @@ -482,13 +2043,13 @@ proto.EvalEventMessage.prototype.setEvent = function(value) { * repeated string args = 3; * @return {!Array} */ -proto.EvalEventMessage.prototype.getArgsList = function() { +proto.NumberedEventMessage.prototype.getArgsList = function() { return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); }; /** @param {!Array} value */ -proto.EvalEventMessage.prototype.setArgsList = function(value) { +proto.NumberedEventMessage.prototype.setArgsList = function(value) { jspb.Message.setField(this, 3, value || []); }; @@ -497,12 +2058,12 @@ proto.EvalEventMessage.prototype.setArgsList = function(value) { * @param {!string} value * @param {number=} opt_index */ -proto.EvalEventMessage.prototype.addArgs = function(value, opt_index) { +proto.NumberedEventMessage.prototype.addArgs = function(value, opt_index) { jspb.Message.addToRepeatedField(this, 3, value, opt_index); }; -proto.EvalEventMessage.prototype.clearArgsList = function() { +proto.NumberedEventMessage.prototype.clearArgsList = function() { this.setArgsList([]); }; @@ -518,12 +2079,12 @@ proto.EvalEventMessage.prototype.clearArgsList = function() { * @extends {jspb.Message} * @constructor */ -proto.EvalFailedMessage = function(opt_data) { +proto.FailMessage = function(opt_data) { jspb.Message.initialize(this, opt_data, 0, -1, null, null); }; -goog.inherits(proto.EvalFailedMessage, jspb.Message); +goog.inherits(proto.FailMessage, jspb.Message); if (goog.DEBUG && !COMPILED) { - proto.EvalFailedMessage.displayName = 'proto.EvalFailedMessage'; + proto.FailMessage.displayName = 'proto.FailMessage'; } @@ -538,8 +2099,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * for transitional soy proto support: http://goto/soy-param-migration * @return {!Object} */ -proto.EvalFailedMessage.prototype.toObject = function(opt_includeInstance) { - return proto.EvalFailedMessage.toObject(opt_includeInstance, this); +proto.FailMessage.prototype.toObject = function(opt_includeInstance) { + return proto.FailMessage.toObject(opt_includeInstance, this); }; @@ -548,11 +2109,11 @@ proto.EvalFailedMessage.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Whether to include the JSPB * instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.EvalFailedMessage} msg The msg instance to transform. + * @param {!proto.FailMessage} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.EvalFailedMessage.toObject = function(includeInstance, msg) { +proto.FailMessage.toObject = function(includeInstance, msg) { var f, obj = { id: jspb.Message.getFieldWithDefault(msg, 1, 0), response: jspb.Message.getFieldWithDefault(msg, 2, "") @@ -569,23 +2130,23 @@ proto.EvalFailedMessage.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.EvalFailedMessage} + * @return {!proto.FailMessage} */ -proto.EvalFailedMessage.deserializeBinary = function(bytes) { +proto.FailMessage.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.EvalFailedMessage; - return proto.EvalFailedMessage.deserializeBinaryFromReader(msg, reader); + var msg = new proto.FailMessage; + return proto.FailMessage.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.EvalFailedMessage} msg The message object to deserialize into. + * @param {!proto.FailMessage} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.EvalFailedMessage} + * @return {!proto.FailMessage} */ -proto.EvalFailedMessage.deserializeBinaryFromReader = function(msg, reader) { +proto.FailMessage.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -613,9 +2174,9 @@ proto.EvalFailedMessage.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.EvalFailedMessage.prototype.serializeBinary = function() { +proto.FailMessage.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.EvalFailedMessage.serializeBinaryToWriter(this, writer); + proto.FailMessage.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -623,11 +2184,11 @@ proto.EvalFailedMessage.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.EvalFailedMessage} message + * @param {!proto.FailMessage} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.EvalFailedMessage.serializeBinaryToWriter = function(message, writer) { +proto.FailMessage.serializeBinaryToWriter = function(message, writer) { var f = undefined; f = message.getId(); if (f !== 0) { @@ -650,13 +2211,13 @@ proto.EvalFailedMessage.serializeBinaryToWriter = function(message, writer) { * optional uint64 id = 1; * @return {number} */ -proto.EvalFailedMessage.prototype.getId = function() { +proto.FailMessage.prototype.getId = function() { return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); }; /** @param {number} value */ -proto.EvalFailedMessage.prototype.setId = function(value) { +proto.FailMessage.prototype.setId = function(value) { jspb.Message.setProto3IntField(this, 1, value); }; @@ -665,13 +2226,13 @@ proto.EvalFailedMessage.prototype.setId = function(value) { * optional string response = 2; * @return {string} */ -proto.EvalFailedMessage.prototype.getResponse = function() { +proto.FailMessage.prototype.getResponse = function() { return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); }; /** @param {string} value */ -proto.EvalFailedMessage.prototype.setResponse = function(value) { +proto.FailMessage.prototype.setResponse = function(value) { jspb.Message.setProto3StringField(this, 2, value); }; @@ -687,12 +2248,12 @@ proto.EvalFailedMessage.prototype.setResponse = function(value) { * @extends {jspb.Message} * @constructor */ -proto.EvalDoneMessage = function(opt_data) { +proto.SuccessMessage = function(opt_data) { jspb.Message.initialize(this, opt_data, 0, -1, null, null); }; -goog.inherits(proto.EvalDoneMessage, jspb.Message); +goog.inherits(proto.SuccessMessage, jspb.Message); if (goog.DEBUG && !COMPILED) { - proto.EvalDoneMessage.displayName = 'proto.EvalDoneMessage'; + proto.SuccessMessage.displayName = 'proto.SuccessMessage'; } @@ -707,8 +2268,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * for transitional soy proto support: http://goto/soy-param-migration * @return {!Object} */ -proto.EvalDoneMessage.prototype.toObject = function(opt_includeInstance) { - return proto.EvalDoneMessage.toObject(opt_includeInstance, this); +proto.SuccessMessage.prototype.toObject = function(opt_includeInstance) { + return proto.SuccessMessage.toObject(opt_includeInstance, this); }; @@ -717,11 +2278,11 @@ proto.EvalDoneMessage.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Whether to include the JSPB * instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.EvalDoneMessage} msg The msg instance to transform. + * @param {!proto.SuccessMessage} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.EvalDoneMessage.toObject = function(includeInstance, msg) { +proto.SuccessMessage.toObject = function(includeInstance, msg) { var f, obj = { id: jspb.Message.getFieldWithDefault(msg, 1, 0), response: jspb.Message.getFieldWithDefault(msg, 2, "") @@ -738,23 +2299,23 @@ proto.EvalDoneMessage.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.EvalDoneMessage} + * @return {!proto.SuccessMessage} */ -proto.EvalDoneMessage.deserializeBinary = function(bytes) { +proto.SuccessMessage.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.EvalDoneMessage; - return proto.EvalDoneMessage.deserializeBinaryFromReader(msg, reader); + var msg = new proto.SuccessMessage; + return proto.SuccessMessage.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.EvalDoneMessage} msg The message object to deserialize into. + * @param {!proto.SuccessMessage} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.EvalDoneMessage} + * @return {!proto.SuccessMessage} */ -proto.EvalDoneMessage.deserializeBinaryFromReader = function(msg, reader) { +proto.SuccessMessage.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -782,9 +2343,9 @@ proto.EvalDoneMessage.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.EvalDoneMessage.prototype.serializeBinary = function() { +proto.SuccessMessage.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.EvalDoneMessage.serializeBinaryToWriter(this, writer); + proto.SuccessMessage.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -792,11 +2353,11 @@ proto.EvalDoneMessage.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.EvalDoneMessage} message + * @param {!proto.SuccessMessage} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.EvalDoneMessage.serializeBinaryToWriter = function(message, writer) { +proto.SuccessMessage.serializeBinaryToWriter = function(message, writer) { var f = undefined; f = message.getId(); if (f !== 0) { @@ -819,13 +2380,13 @@ proto.EvalDoneMessage.serializeBinaryToWriter = function(message, writer) { * optional uint64 id = 1; * @return {number} */ -proto.EvalDoneMessage.prototype.getId = function() { +proto.SuccessMessage.prototype.getId = function() { return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); }; /** @param {number} value */ -proto.EvalDoneMessage.prototype.setId = function(value) { +proto.SuccessMessage.prototype.setId = function(value) { jspb.Message.setProto3IntField(this, 1, value); }; @@ -834,13 +2395,13 @@ proto.EvalDoneMessage.prototype.setId = function(value) { * optional string response = 2; * @return {string} */ -proto.EvalDoneMessage.prototype.getResponse = function() { +proto.SuccessMessage.prototype.getResponse = function() { return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); }; /** @param {string} value */ -proto.EvalDoneMessage.prototype.setResponse = function(value) { +proto.SuccessMessage.prototype.setResponse = function(value) { jspb.Message.setProto3StringField(this, 2, value); }; @@ -1077,4 +2638,16 @@ proto.Pong.serializeBinaryToWriter = function(message, writer) { }; +/** + * @enum {number} + */ +proto.Module = { + CHILDPROCESS: 0, + FS: 1, + NET: 2, + NODEPTY: 3, + SPDLOG: 4, + TRASH: 5 +}; + goog.object.extend(exports, proto); diff --git a/packages/ide/test/child_process.test.ts b/packages/protocol/test/child_process.test.ts similarity index 72% rename from packages/ide/test/child_process.test.ts rename to packages/protocol/test/child_process.test.ts index 57ce9998..46298abd 100644 --- a/packages/ide/test/child_process.test.ts +++ b/packages/protocol/test/child_process.test.ts @@ -3,12 +3,12 @@ import * as path from "path"; import { Readable } from "stream"; import * as util from "util"; import { createClient } from "@coder/protocol/test"; - -const client = createClient(); -jest.mock("../src/fill/client", () => ({ client })); -const cp = require("../src/fill/child_process") as typeof import("child_process"); +import { Module } from "../src/common/proxy"; describe("child_process", () => { + const client = createClient(); + const cp = client.modules[Module.ChildProcess]; + const getStdout = async (proc: ChildProcess): Promise => { return new Promise((r): Readable => proc.stdout.on("data", r)) .then((s) => s.toString()); @@ -71,4 +71,28 @@ describe("child_process", () => { await new Promise((r): ChildProcess => proc.on("exit", r)); }); }); + + it("should dispose", (done) => { + setTimeout(() => { + client.dispose(); + done(); + }, 100); + }); + + it("should disconnect", async () => { + const client = createClient(); + const cp = client.modules[Module.ChildProcess]; + const proc = cp.fork(path.join(__dirname, "forker.js")); + const fn = jest.fn(); + proc.on("error", fn); + + proc.send({ bananas: true }); + await expect(new Promise((r): ChildProcess => proc.on("message", r))) + .resolves.toMatchObject({ + bananas: true, + }); + + client.dispose(); + expect(fn).toHaveBeenCalledWith(new Error("disconnected")); + }); }); diff --git a/packages/protocol/test/evaluate.test.ts b/packages/protocol/test/evaluate.test.ts deleted file mode 100644 index 00f00106..00000000 --- a/packages/protocol/test/evaluate.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { createClient } from "./helpers"; - -describe("Evaluate", () => { - const client = createClient(); - - it("should transfer string", async () => { - const value = await client.evaluate(() => { - return "hi"; - }); - - expect(value).toEqual("hi"); - }, 100); - - it("should compute from string", async () => { - const start = "ban\%\$\"``a,,,,asdasd"; - const value = await client.evaluate((_helper, a) => { - return a; - }, start); - - expect(value).toEqual(start); - }, 100); - - it("should compute from object", async () => { - const value = await client.evaluate((_helper, arg) => { - return arg.bananas * 2; - }, { bananas: 1 }); - - expect(value).toEqual(2); - }, 100); - - it("should transfer object", async () => { - const value = await client.evaluate(() => { - return { alpha: "beta" }; - }); - - expect(value.alpha).toEqual("beta"); - }, 100); - - it("should require", async () => { - const value = await client.evaluate(() => { - const fs = require("fs") as typeof import("fs"); - - return Object.keys(fs).filter((f) => f === "readFileSync"); - }); - - expect(value[0]).toEqual("readFileSync"); - }, 100); - - it("should resolve with promise", async () => { - const value = await client.evaluate(async () => { - await new Promise((r): number => setTimeout(r, 100)); - - return "donkey"; - }); - - expect(value).toEqual("donkey"); - }, 250); - - it("should do active process", (done) => { - const runner = client.run((ae) => { - ae.on("first", () => { - ae.emit("first:response"); - ae.on("second", () => ae.emit("second:response")); - }); - - const disposeCallbacks = void>>[]; - const dispose = (): void => { - disposeCallbacks.forEach((cb) => cb()); - ae.emit("disposed"); - }; - - return { - onDidDispose: (cb: () => void): number => disposeCallbacks.push(cb), - dispose, - }; - }); - - runner.emit("first"); - runner.on("first:response", () => runner.emit("second")); - runner.on("second:response", () => client.dispose()); - - runner.on("disposed", () => done()); - }); -}); diff --git a/packages/ide/test/forker.js b/packages/protocol/test/forker.js similarity index 100% rename from packages/ide/test/forker.js rename to packages/protocol/test/forker.js diff --git a/packages/ide/test/fs.test.ts b/packages/protocol/test/fs.test.ts similarity index 74% rename from packages/ide/test/fs.test.ts rename to packages/protocol/test/fs.test.ts index a4eb1bdf..f009ef4b 100644 --- a/packages/ide/test/fs.test.ts +++ b/packages/protocol/test/fs.test.ts @@ -1,53 +1,34 @@ import * as nativeFs from "fs"; -import * as os from "os"; import * as path from "path"; import * as util from "util"; -import * as rimraf from "rimraf"; -import { createClient } from "@coder/protocol/test"; - -const client = createClient(); -jest.mock("../src/fill/client", () => ({ client })); -const fs = require("../src/fill/fs") as typeof import("fs"); +import { Module } from "../src/common/proxy"; +import { createClient, Helper } from "./helpers"; describe("fs", () => { - let i = 0; - const coderDir = path.join(os.tmpdir(), "coder", "fs"); - const testFile = path.join(__dirname, "fs.test.ts"); - const tmpFile = (): string => path.join(coderDir, `${i++}`); - const createTmpFile = async (): Promise => { - const tf = tmpFile(); - await util.promisify(nativeFs.writeFile)(tf, ""); - - return tf; - }; + const client = createClient(); + // tslint:disable-next-line no-any + const fs = client.modules[Module.Fs] as any as typeof import("fs"); + const helper = new Helper("fs"); beforeAll(async () => { - try { - await util.promisify(nativeFs.mkdir)(path.dirname(coderDir)); - } catch (error) { - if (error.code !== "EEXIST" && error.code !== "EISDIR") { - throw error; - } - } - await util.promisify(rimraf)(coderDir); - await util.promisify(nativeFs.mkdir)(coderDir); + await helper.prepare(); }); describe("access", () => { it("should access existing file", async () => { - await expect(util.promisify(fs.access)(testFile)) + await expect(util.promisify(fs.access)(__filename)) .resolves.toBeUndefined(); }); it("should fail to access nonexistent file", async () => { - await expect(util.promisify(fs.access)(tmpFile())) + await expect(util.promisify(fs.access)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("append", () => { it("should append to existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.appendFile)(file, "howdy")) .resolves.toBeUndefined(); expect(await util.promisify(nativeFs.readFile)(file, "utf8")) @@ -55,7 +36,7 @@ describe("fs", () => { }); it("should create then append to nonexistent file", async () => { - const file = tmpFile(); + const file = helper.tmpFile(); await expect(util.promisify(fs.appendFile)(file, "howdy")) .resolves.toBeUndefined(); expect(await util.promisify(nativeFs.readFile)(file, "utf8")) @@ -63,7 +44,7 @@ describe("fs", () => { }); it("should fail to append to file in nonexistent directory", async () => { - const file = path.join(tmpFile(), "nope"); + const file = path.join(helper.tmpFile(), "nope"); await expect(util.promisify(fs.appendFile)(file, "howdy")) .rejects.toThrow("ENOENT"); expect(await util.promisify(nativeFs.exists)(file)) @@ -73,33 +54,33 @@ describe("fs", () => { describe("chmod", () => { it("should chmod existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.chmod)(file, "755")) .resolves.toBeUndefined(); }); it("should fail to chmod nonexistent file", async () => { - await expect(util.promisify(fs.chmod)(tmpFile(), "755")) + await expect(util.promisify(fs.chmod)(helper.tmpFile(), "755")) .rejects.toThrow("ENOENT"); }); }); describe("chown", () => { it("should chown existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.chown)(file, 1, 1)) .resolves.toBeUndefined(); }); it("should fail to chown nonexistent file", async () => { - await expect(util.promisify(fs.chown)(tmpFile(), 1, 1)) + await expect(util.promisify(fs.chown)(helper.tmpFile(), 1, 1)) .rejects.toThrow("ENOENT"); }); }); describe("close", () => { it("should close opened file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "r"); await expect(util.promisify(fs.close)(fd)) .resolves.toBeUndefined(); @@ -113,8 +94,8 @@ describe("fs", () => { describe("copyFile", () => { it("should copy existing file", async () => { - const source = await createTmpFile(); - const destination = tmpFile(); + const source = await helper.createTmpFile(); + const destination = helper.tmpFile(); await expect(util.promisify(fs.copyFile)(source, destination)) .resolves.toBeUndefined(); await expect(util.promisify(fs.exists)(destination)) @@ -122,44 +103,47 @@ describe("fs", () => { }); it("should fail to copy nonexistent file", async () => { - await expect(util.promisify(fs.copyFile)(tmpFile(), tmpFile())) + await expect(util.promisify(fs.copyFile)(helper.tmpFile(), helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("createWriteStream", () => { it("should write to file", async () => { - const file = tmpFile(); + const file = helper.tmpFile(); const content = "howdy\nhow\nr\nu"; const stream = fs.createWriteStream(file); stream.on("open", (fd) => { expect(fd).toBeDefined(); stream.write(content); stream.close(); + stream.end(); }); - await expect(new Promise((resolve): void => { - stream.on("close", async () => { - resolve(await util.promisify(nativeFs.readFile)(file, "utf8")); - }); - })).resolves.toBe(content); + + await Promise.all([ + new Promise((resolve): nativeFs.WriteStream => stream.on("close", resolve)), + new Promise((resolve): nativeFs.WriteStream => stream.on("finish", resolve)), + ]); + + await expect(util.promisify(nativeFs.readFile)(file, "utf8")).resolves.toBe(content); }); }); describe("exists", () => { it("should output file exists", async () => { - await expect(util.promisify(fs.exists)(testFile)) + await expect(util.promisify(fs.exists)(__filename)) .resolves.toBe(true); }); it("should output file does not exist", async () => { - await expect(util.promisify(fs.exists)(tmpFile())) + await expect(util.promisify(fs.exists)(helper.tmpFile())) .resolves.toBe(false); }); }); describe("fchmod", () => { it("should fchmod existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "r"); await expect(util.promisify(fs.fchmod)(fd, "755")) .resolves.toBeUndefined(); @@ -174,7 +158,7 @@ describe("fs", () => { describe("fchown", () => { it("should fchown existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "r"); await expect(util.promisify(fs.fchown)(fd, 1, 1)) .resolves.toBeUndefined(); @@ -189,7 +173,7 @@ describe("fs", () => { describe("fdatasync", () => { it("should fdatasync existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "r"); await expect(util.promisify(fs.fdatasync)(fd)) .resolves.toBeUndefined(); @@ -204,7 +188,7 @@ describe("fs", () => { describe("fstat", () => { it("should fstat existing file", async () => { - const fd = await util.promisify(nativeFs.open)(testFile, "r"); + const fd = await util.promisify(nativeFs.open)(__filename, "r"); const stat = await util.promisify(nativeFs.fstat)(fd); await expect(util.promisify(fs.fstat)(fd)) .resolves.toMatchObject({ @@ -221,7 +205,7 @@ describe("fs", () => { describe("fsync", () => { it("should fsync existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "r"); await expect(util.promisify(fs.fsync)(fd)) .resolves.toBeUndefined(); @@ -236,7 +220,7 @@ describe("fs", () => { describe("ftruncate", () => { it("should ftruncate existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "w"); await expect(util.promisify(fs.ftruncate)(fd, 1)) .resolves.toBeUndefined(); @@ -251,7 +235,7 @@ describe("fs", () => { describe("futimes", () => { it("should futimes existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "w"); await expect(util.promisify(fs.futimes)(fd, 1, 1)) .resolves.toBeUndefined(); @@ -266,36 +250,36 @@ describe("fs", () => { describe("lchmod", () => { it("should lchmod existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.lchmod)(file, "755")) .resolves.toBeUndefined(); }); // TODO: Doesn't fail on my system? it("should fail to lchmod nonexistent file", async () => { - await expect(util.promisify(fs.lchmod)(tmpFile(), "755")) + await expect(util.promisify(fs.lchmod)(helper.tmpFile(), "755")) .resolves.toBeUndefined(); }); }); describe("lchown", () => { it("should lchown existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.lchown)(file, 1, 1)) .resolves.toBeUndefined(); }); // TODO: Doesn't fail on my system? it("should fail to lchown nonexistent file", async () => { - await expect(util.promisify(fs.lchown)(tmpFile(), 1, 1)) + await expect(util.promisify(fs.lchown)(helper.tmpFile(), 1, 1)) .resolves.toBeUndefined(); }); }); describe("link", () => { it("should link existing file", async () => { - const source = await createTmpFile(); - const destination = tmpFile(); + const source = await helper.createTmpFile(); + const destination = helper.tmpFile(); await expect(util.promisify(fs.link)(source, destination)) .resolves.toBeUndefined(); await expect(util.promisify(fs.exists)(destination)) @@ -303,29 +287,30 @@ describe("fs", () => { }); it("should fail to link nonexistent file", async () => { - await expect(util.promisify(fs.link)(tmpFile(), tmpFile())) + await expect(util.promisify(fs.link)(helper.tmpFile(), helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("lstat", () => { it("should lstat existing file", async () => { - const stat = await util.promisify(nativeFs.lstat)(testFile); - await expect(util.promisify(fs.lstat)(testFile)) + const stat = await util.promisify(nativeFs.lstat)(__filename); + await expect(util.promisify(fs.lstat)(__filename)) .resolves.toMatchObject({ size: stat.size, }); }); it("should fail to lstat non-existent file", async () => { - await expect(util.promisify(fs.lstat)(tmpFile())) + await expect(util.promisify(fs.lstat)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("mkdir", () => { - const target = tmpFile(); + let target: string; it("should create nonexistent directory", async () => { + target = helper.tmpFile(); await expect(util.promisify(fs.mkdir)(target)) .resolves.toBeUndefined(); }); @@ -338,28 +323,28 @@ describe("fs", () => { describe("mkdtemp", () => { it("should create temp dir", async () => { - await expect(util.promisify(fs.mkdtemp)(coderDir + "/")) + await expect(util.promisify(fs.mkdtemp)(helper.coderDir + "/")) .resolves.toMatch(/^\/tmp\/coder\/fs\/[a-zA-Z0-9]{6}/); }); }); describe("open", () => { it("should open existing file", async () => { - const fd = await util.promisify(fs.open)(testFile, "r"); + const fd = await util.promisify(fs.open)(__filename, "r"); expect(fd).not.toBeNaN(); await expect(util.promisify(fs.close)(fd)) .resolves.toBeUndefined(); }); it("should fail to open nonexistent file", async () => { - await expect(util.promisify(fs.open)(tmpFile(), "r")) + await expect(util.promisify(fs.open)(helper.tmpFile(), "r")) .rejects.toThrow("ENOENT"); }); }); describe("read", () => { it("should read existing file", async () => { - const fd = await util.promisify(nativeFs.open)(testFile, "r"); + const fd = await util.promisify(nativeFs.open)(__filename, "r"); const stat = await util.promisify(nativeFs.fstat)(fd); const buffer = new Buffer(stat.size); let bytesRead = 0; @@ -373,7 +358,7 @@ describe("fs", () => { bytesRead += chunkSize; } - const content = await util.promisify(nativeFs.readFile)(testFile, "utf8"); + const content = await util.promisify(nativeFs.readFile)(__filename, "utf8"); expect(buffer.toString()).toEqual(content); await util.promisify(nativeFs.close)(fd); }); @@ -386,64 +371,64 @@ describe("fs", () => { describe("readFile", () => { it("should read existing file", async () => { - const content = await util.promisify(nativeFs.readFile)(testFile, "utf8"); - await expect(util.promisify(fs.readFile)(testFile, "utf8")) + const content = await util.promisify(nativeFs.readFile)(__filename, "utf8"); + await expect(util.promisify(fs.readFile)(__filename, "utf8")) .resolves.toEqual(content); }); it("should fail to read nonexistent file", async () => { - await expect(util.promisify(fs.readFile)(tmpFile())) + await expect(util.promisify(fs.readFile)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("readdir", () => { it("should read existing directory", async () => { - const paths = await util.promisify(nativeFs.readdir)(coderDir); - await expect(util.promisify(fs.readdir)(coderDir)) + const paths = await util.promisify(nativeFs.readdir)(helper.coderDir); + await expect(util.promisify(fs.readdir)(helper.coderDir)) .resolves.toEqual(paths); }); it("should fail to read nonexistent directory", async () => { - await expect(util.promisify(fs.readdir)(tmpFile())) + await expect(util.promisify(fs.readdir)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("readlink", () => { it("should read existing link", async () => { - const source = await createTmpFile(); - const destination = tmpFile(); + const source = await helper.createTmpFile(); + const destination = helper.tmpFile(); await util.promisify(nativeFs.symlink)(source, destination); await expect(util.promisify(fs.readlink)(destination)) .resolves.toBe(source); }); it("should fail to read nonexistent link", async () => { - await expect(util.promisify(fs.readlink)(tmpFile())) + await expect(util.promisify(fs.readlink)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("realpath", () => { it("should read real path of existing file", async () => { - const source = await createTmpFile(); - const destination = tmpFile(); + const source = await helper.createTmpFile(); + const destination = helper.tmpFile(); nativeFs.symlinkSync(source, destination); await expect(util.promisify(fs.realpath)(destination)) .resolves.toBe(source); }); it("should fail to read real path of nonexistent file", async () => { - await expect(util.promisify(fs.realpath)(tmpFile())) + await expect(util.promisify(fs.realpath)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("rename", () => { it("should rename existing file", async () => { - const source = await createTmpFile(); - const destination = tmpFile(); + const source = await helper.createTmpFile(); + const destination = helper.tmpFile(); await expect(util.promisify(fs.rename)(source, destination)) .resolves.toBeUndefined(); await expect(util.promisify(nativeFs.exists)(source)) @@ -453,14 +438,14 @@ describe("fs", () => { }); it("should fail to rename nonexistent file", async () => { - await expect(util.promisify(fs.rename)(tmpFile(), tmpFile())) + await expect(util.promisify(fs.rename)(helper.tmpFile(), helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("rmdir", () => { it("should rmdir existing directory", async () => { - const dir = tmpFile(); + const dir = helper.tmpFile(); await util.promisify(nativeFs.mkdir)(dir); await expect(util.promisify(fs.rmdir)(dir)) .resolves.toBeUndefined(); @@ -469,15 +454,15 @@ describe("fs", () => { }); it("should fail to rmdir nonexistent directory", async () => { - await expect(util.promisify(fs.rmdir)(tmpFile())) + await expect(util.promisify(fs.rmdir)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("stat", () => { it("should stat existing file", async () => { - const nativeStat = await util.promisify(nativeFs.stat)(testFile); - const stat = await util.promisify(fs.stat)(testFile); + const nativeStat = await util.promisify(nativeFs.stat)(__filename); + const stat = await util.promisify(fs.stat)(__filename); expect(stat).toMatchObject({ size: nativeStat.size, }); @@ -485,7 +470,7 @@ describe("fs", () => { }); it("should stat existing folder", async () => { - const dir = tmpFile(); + const dir = helper.tmpFile(); await util.promisify(nativeFs.mkdir)(dir); const nativeStat = await util.promisify(nativeFs.stat)(dir); const stat = await util.promisify(fs.stat)(dir); @@ -496,7 +481,7 @@ describe("fs", () => { }); it("should fail to stat nonexistent file", async () => { - const error = await util.promisify(fs.stat)(tmpFile()).catch((e) => e); + const error = await util.promisify(fs.stat)(helper.tmpFile()).catch((e) => e); expect(error.message).toContain("ENOENT"); expect(error.code).toBe("ENOENT"); }); @@ -504,8 +489,8 @@ describe("fs", () => { describe("symlink", () => { it("should symlink existing file", async () => { - const source = await createTmpFile(); - const destination = tmpFile(); + const source = await helper.createTmpFile(); + const destination = helper.tmpFile(); await expect(util.promisify(fs.symlink)(source, destination)) .resolves.toBeUndefined(); expect(util.promisify(nativeFs.exists)(source)) @@ -514,14 +499,14 @@ describe("fs", () => { // TODO: Seems to be happy to do this on my system? it("should fail to symlink nonexistent file", async () => { - await expect(util.promisify(fs.symlink)(tmpFile(), tmpFile())) + await expect(util.promisify(fs.symlink)(helper.tmpFile(), helper.tmpFile())) .resolves.toBeUndefined(); }); }); describe("truncate", () => { it("should truncate existing file", async () => { - const file = tmpFile(); + const file = helper.tmpFile(); await util.promisify(nativeFs.writeFile)(file, "hiiiiii"); await expect(util.promisify(fs.truncate)(file, 2)) .resolves.toBeUndefined(); @@ -530,14 +515,14 @@ describe("fs", () => { }); it("should fail to truncate nonexistent file", async () => { - await expect(util.promisify(fs.truncate)(tmpFile(), 0)) + await expect(util.promisify(fs.truncate)(helper.tmpFile(), 0)) .rejects.toThrow("ENOENT"); }); }); describe("unlink", () => { it("should unlink existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.unlink)(file)) .resolves.toBeUndefined(); expect(util.promisify(nativeFs.exists)(file)) @@ -545,27 +530,27 @@ describe("fs", () => { }); it("should fail to unlink nonexistent file", async () => { - await expect(util.promisify(fs.unlink)(tmpFile())) + await expect(util.promisify(fs.unlink)(helper.tmpFile())) .rejects.toThrow("ENOENT"); }); }); describe("utimes", () => { it("should update times on existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.utimes)(file, 100, 100)) .resolves.toBeUndefined(); }); it("should fail to update times on nonexistent file", async () => { - await expect(util.promisify(fs.utimes)(tmpFile(), 100, 100)) + await expect(util.promisify(fs.utimes)(helper.tmpFile(), 100, 100)) .rejects.toThrow("ENOENT"); }); }); describe("write", () => { it("should write to existing file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); const fd = await util.promisify(nativeFs.open)(file, "w"); await expect(util.promisify(fs.write)(fd, Buffer.from("hi"))) .resolves.toBe(2); @@ -582,11 +567,15 @@ describe("fs", () => { describe("writeFile", () => { it("should write file", async () => { - const file = await createTmpFile(); + const file = await helper.createTmpFile(); await expect(util.promisify(fs.writeFile)(file, "howdy")) .resolves.toBeUndefined(); await expect(util.promisify(nativeFs.readFile)(file, "utf8")) .resolves.toBe("howdy"); }); }); + + it("should dispose", () => { + client.dispose(); + }); }); diff --git a/packages/protocol/test/helpers.ts b/packages/protocol/test/helpers.ts index 828cf9c5..f187dc6e 100644 --- a/packages/protocol/test/helpers.ts +++ b/packages/protocol/test/helpers.ts @@ -1,7 +1,54 @@ +import * as fs from "fs"; +import * as os from "os"; +import * as path from "path"; +import * as rimraf from "rimraf"; +import * as util from "util"; +import { IDisposable } from "@coder/disposable"; import { Emitter } from "@coder/events"; import { Client } from "../src/browser/client"; import { Server, ServerOptions } from "../src/node/server"; +// So we only make the directory once when running multiple tests. +let mkdirPromise: Promise | undefined; + +export class Helper { + private i = 0; + public coderDir: string; + private baseDir = path.join(os.tmpdir(), "coder"); + + public constructor(directoryName: string) { + if (!directoryName.trim()) { + throw new Error("no directory name"); + } + + this.coderDir = path.join(this.baseDir, directoryName); + } + + public tmpFile(): string { + return path.join(this.coderDir, `${this.i++}`); + } + + public async createTmpFile(): Promise { + const tf = this.tmpFile(); + await util.promisify(fs.writeFile)(tf, ""); + + return tf; + } + + public async prepare(): Promise { + if (!mkdirPromise) { + mkdirPromise = util.promisify(fs.mkdir)(this.baseDir).catch((error) => { + if (error.code !== "EEXIST" && error.code !== "EISDIR") { + throw error; + } + }); + } + await mkdirPromise; + await util.promisify(rimraf)(this.coderDir); + await util.promisify(fs.mkdir)(this.coderDir); + } +} + export const createClient = (serverOptions?: ServerOptions): Client => { const s2c = new Emitter(); const c2s = new Emitter(); @@ -10,19 +57,19 @@ export const createClient = (serverOptions?: ServerOptions): Client => { // tslint:disable-next-line no-unused-expression new Server({ close: (): void => closeCallbacks.forEach((cb) => cb()), + onDown: (_cb: () => void): void => undefined, + onUp: (_cb: () => void): void => undefined, onClose: (cb: () => void): number => closeCallbacks.push(cb), - onMessage: (cb): void => { - c2s.event((d) => cb(d)); - }, + onMessage: (cb): IDisposable => c2s.event((d) => cb(d)), send: (data): NodeJS.Timer => setTimeout(() => s2c.emit(data), 0), }, serverOptions); const client = new Client({ close: (): void => closeCallbacks.forEach((cb) => cb()), + onDown: (_cb: () => void): void => undefined, + onUp: (_cb: () => void): void => undefined, onClose: (cb: () => void): number => closeCallbacks.push(cb), - onMessage: (cb): void => { - s2c.event((d) => cb(d)); - }, + onMessage: (cb): IDisposable => s2c.event((d) => cb(d)), send: (data): NodeJS.Timer => setTimeout(() => c2s.emit(data), 0), }); diff --git a/packages/ide/test/net.test.ts b/packages/protocol/test/net.test.ts similarity index 74% rename from packages/ide/test/net.test.ts rename to packages/protocol/test/net.test.ts index 9922a10c..1dfd2e35 100644 --- a/packages/ide/test/net.test.ts +++ b/packages/protocol/test/net.test.ts @@ -1,34 +1,18 @@ -import * as fs from "fs"; import * as nativeNet from "net"; -import * as os from "os"; -import * as path from "path"; -import * as util from "util"; -import * as rimraf from "rimraf"; -import { createClient } from "@coder/protocol/test"; - -const client = createClient(); -jest.mock("../src/fill/client", () => ({ client })); -const net = require("../src/fill/net") as typeof import("net"); +import { Module } from "../src/common/proxy"; +import { createClient, Helper } from "./helpers"; describe("net", () => { - let i = 0; - const coderDir = path.join(os.tmpdir(), "coder", "net"); - const tmpFile = (): string => path.join(coderDir, `socket.${i++}`); + const client = createClient(); + const net = client.modules[Module.Net]; + const helper = new Helper("net"); beforeAll(async () => { - try { - await util.promisify(fs.mkdir)(path.dirname(coderDir)); - } catch (error) { - if (error.code !== "EEXIST" && error.code !== "EISDIR") { - throw error; - } - } - await util.promisify(rimraf)(coderDir); - await util.promisify(fs.mkdir)(coderDir); + await helper.prepare(); }); describe("Socket", () => { - const socketPath = tmpFile(); + const socketPath = helper.tmpFile(); let server: nativeNet.Server; beforeAll(async () => { @@ -41,6 +25,19 @@ describe("net", () => { server.close(); }); + it("should fail to connect", async () => { + const socket = new net.Socket(); + + const fn = jest.fn(); + socket.on("error", fn); + + socket.connect("/tmp/t/e/s/t/d/o/e/s/n/o/t/e/x/i/s/t"); + + await new Promise((r): nativeNet.Socket => socket.on("close", r)); + + expect(fn).toHaveBeenCalledTimes(1); + }); + it("should connect", async () => { await new Promise((resolve): void => { const socket = net.createConnection(socketPath, () => { @@ -98,7 +95,7 @@ describe("net", () => { const s = net.createServer(); s.on("listening", () => s.close()); s.on("close", () => done()); - s.listen(tmpFile()); + s.listen(helper.tmpFile()); }); it("should get connection", async () => { @@ -109,9 +106,13 @@ describe("net", () => { } }); - const socketPath = tmpFile(); + const socketPath = helper.tmpFile(); s.listen(socketPath); + await new Promise((resolve): void => { + s.on("listening", resolve); + }); + const makeConnection = async (): Promise => { net.createConnection(socketPath); await Promise.all([ @@ -134,4 +135,11 @@ describe("net", () => { await new Promise((r): nativeNet.Server => s.on("close", r)); }); }); + + it("should dispose", (done) => { + setTimeout(() => { + client.dispose(); + done(); + }, 100); + }); }); diff --git a/packages/vscode/test/node-pty.test.ts b/packages/protocol/test/node-pty.test.ts similarity index 69% rename from packages/vscode/test/node-pty.test.ts rename to packages/protocol/test/node-pty.test.ts index d8d38df9..62159b98 100644 --- a/packages/vscode/test/node-pty.test.ts +++ b/packages/protocol/test/node-pty.test.ts @@ -1,11 +1,11 @@ import { IPty } from "node-pty"; -import { createClient } from "@coder/protocol/test"; - -const client = createClient(); -jest.mock("../../ide/src/fill/client", () => ({ client })); -const pty = require("../src/fill/node-pty") as typeof import("node-pty"); +import { Module } from "../src/common/proxy"; +import { createClient } from "./helpers"; describe("node-pty", () => { + const client = createClient(); + const pty = client.modules[Module.NodePty]; + /** * Returns a function that when called returns a promise that resolves with * the next chunk of data from the process. @@ -47,12 +47,11 @@ describe("node-pty", () => { const getData = promisifyData(proc); - // First it outputs @hostname:cwd - expect((await getData()).length).toBeGreaterThan(1); - - // Then it seems to overwrite that with a shorter prompt in the format of - // [hostname@user]$ - expect((await getData())).toContain("$"); + // Wait for [hostname@user]$ + let data = ""; + while (!data.includes("$")) { + data = await getData(); + } proc.kill(); @@ -67,33 +66,34 @@ describe("node-pty", () => { // isn't affected by custom configuration. const proc = pty.spawn("/bin/bash", ["--rcfile", "/tmp/test/nope/should/not/exist"], { cols: 10, - rows: 10, + rows: 912, }); const getData = promisifyData(proc); - // We've already tested these first two bits of output; see shell test. - await getData(); - await getData(); - proc.write("tput lines\n"); - expect(await getData()).toContain("tput"); - - expect((await getData()).trim()).toContain("10"); - proc.resize(10, 50); - - // The prompt again. - await getData(); - await getData(); + let data = ""; + while (!data.includes("912")) { + data = await getData(); + } + proc.resize(10, 219); proc.write("tput lines\n"); - expect(await getData()).toContain("tput"); - expect((await getData())).toContain("50"); + while (!data.includes("219")) { + data = await getData(); + } proc.kill(); await new Promise((resolve): void => { proc.on("exit", resolve); }); }); + + it("should dispose", (done) => { + setTimeout(() => { + client.dispose(); + done(); + }, 100); + }); }); diff --git a/packages/protocol/test/spdlog.test.ts b/packages/protocol/test/spdlog.test.ts new file mode 100644 index 00000000..d698df71 --- /dev/null +++ b/packages/protocol/test/spdlog.test.ts @@ -0,0 +1,35 @@ +import * as fs from "fs"; +import * as util from "util"; +import { Module } from "../src/common/proxy"; +import { createClient, Helper } from "./helpers"; + +describe("spdlog", () => { + const client = createClient(); + const spdlog = client.modules[Module.Spdlog]; + const helper = new Helper("spdlog"); + + beforeAll(async () => { + await helper.prepare(); + }); + + it("should log to a file", async () => { + const file = await helper.createTmpFile(); + const logger = new spdlog.RotatingLogger("test logger", file, 10000, 10); + logger.trace("trace"); + logger.debug("debug"); + logger.info("info"); + logger.warn("warn"); + logger.error("error"); + logger.critical("critical"); + logger.flush(); + await new Promise((resolve): number | NodeJS.Timer => setTimeout(resolve, 1000)); + expect(await util.promisify(fs.readFile)(file, "utf8")) + .toContain("critical"); + }); + + it("should dispose", () => { + setTimeout(() => { + client.dispose(); + }, 100); + }); +}); diff --git a/packages/protocol/test/trash.test.ts b/packages/protocol/test/trash.test.ts new file mode 100644 index 00000000..f309a613 --- /dev/null +++ b/packages/protocol/test/trash.test.ts @@ -0,0 +1,26 @@ +import * as fs from "fs"; +import * as util from "util"; +import { Module } from "../src/common/proxy"; +import { createClient, Helper } from "./helpers"; + +describe("trash", () => { + const client = createClient(); + const trash = client.modules[Module.Trash]; + const helper = new Helper("trash"); + + beforeAll(async () => { + await helper.prepare(); + }); + + it("should trash a file", async () => { + const file = await helper.createTmpFile(); + await trash.trash(file); + expect(await util.promisify(fs.exists)(file)).toBeFalsy(); + }); + + it("should dispose", () => { + setTimeout(() => { + client.dispose(); + }, 100); + }); +}); diff --git a/packages/protocol/yarn.lock b/packages/protocol/yarn.lock index f5a7859d..5cecc1a0 100644 --- a/packages/protocol/yarn.lock +++ b/packages/protocol/yarn.lock @@ -14,11 +14,43 @@ dependencies: execa "^0.2.2" +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/glob@*": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + "@types/google-protobuf@^3.2.7": version "3.2.7" resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.2.7.tgz#9576ed5dd62cdb1c9f952522028a03b7cb2b69b5" integrity sha512-Pb9wl5qDEwfnJeeu6Zpn5Y+waLrKETStqLZXHMGCTbkNuBBudPy4qOGN6veamyeoUBwTm2knOVeP/FlHHhhmzA== +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +"@types/node@*": + version "11.11.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.3.tgz#7c6b0f8eaf16ae530795de2ad1b85d34bf2f5c58" + integrity sha512-wp6IOGu1lxsfnrD+5mX6qwSwWuqsdkKKxTN4aQc4wByHAKZJf9/D4KXPQ1POUjEbnCP5LMggB0OEFNY9OTsMqg== + +"@types/rimraf@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e" + integrity sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ== + dependencies: + "@types/glob" "*" + "@types/node" "*" + "@types/text-encoding@^0.0.35": version "0.0.35" resolved "https://registry.yarnpkg.com/@types/text-encoding/-/text-encoding-0.0.35.tgz#6f14474e0b232bc70c59677aadc65dcc5a99c3a9" @@ -898,7 +930,7 @@ readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" -rimraf@^2.2.8: +rimraf@^2.2.8, rimraf@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -1124,11 +1156,6 @@ ts-protoc-gen@^0.8.0: dependencies: google-protobuf "^3.6.1" -tslib@^1.9.3: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" diff --git a/packages/server/package.json b/packages/server/package.json index a231aecd..fea167c9 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -6,9 +6,10 @@ "scripts": { "start": "node --max-old-space-size=32384 --require ts-node/register --require tsconfig-paths/register src/cli.ts", "build": "rm -rf ./out && ../../node_modules/.bin/cross-env CLI=true UV_THREADPOOL_SIZE=100 node --max-old-space-size=32384 ../../node_modules/webpack/bin/webpack.js --config ./webpack.config.js", - "build:nexe": "node scripts/nexe.js" + "build:binary": "ts-node scripts/nbin.ts" }, "dependencies": { + "@coder/nbin": "^1.0.0", "@oclif/config": "^1.10.4", "@oclif/errors": "^1.2.2", "@oclif/plugin-help": "^2.1.4", @@ -32,7 +33,6 @@ "@types/safe-compare": "^1.1.0", "@types/ws": "^6.0.1", "fs-extra": "^7.0.1", - "nexe": "^2.0.0-rc.34", "opn": "^5.4.0", "string-replace-webpack-plugin": "^0.1.3", "ts-node": "^7.0.1", diff --git a/packages/server/scripts/nbin.ts b/packages/server/scripts/nbin.ts new file mode 100644 index 00000000..fabf4281 --- /dev/null +++ b/packages/server/scripts/nbin.ts @@ -0,0 +1,21 @@ +import { Binary } from "@coder/nbin"; +import * as fs from "fs"; +import * as os from "os"; +import * as path from "path"; + +const target = `${os.platform()}-${os.arch()}`; +const rootDir = path.join(__dirname, ".."); +const bin = new Binary({ + mainFile: path.join(rootDir, "out", "cli.js"), +}); +bin.writeFiles(path.join(rootDir, "build", "**")); +bin.writeFiles(path.join(rootDir, "out", "**")); +bin.build().then((binaryData) => { + const outputPath = path.join(__dirname, "..", `cli-${target}`); + fs.writeFileSync(outputPath, binaryData); + fs.chmodSync(outputPath, "755"); +}).catch((ex) => { + // tslint:disable-next-line:no-console + console.error(ex); + process.exit(1); +}); diff --git a/packages/server/scripts/nexe.js b/packages/server/scripts/nexe.js deleted file mode 100644 index 5de18bd4..00000000 --- a/packages/server/scripts/nexe.js +++ /dev/null @@ -1,31 +0,0 @@ -const fs = require("fs"); -const fse = require("fs-extra"); -const os = require("os"); -const path = require("path"); - -const nexePath = require.resolve("nexe"); -const shimPath = path.join(path.dirname(nexePath), "lib/steps/shim.js"); -let shimContent = fs.readFileSync(shimPath).toString(); -const replaceString = `global.nativeFs = { existsSync: originalExistsSync, readFile: originalReadFile, readFileSync: originalReadFileSync, createReadStream: originalCreateReadStream, readdir: originalReaddir, readdirSync: originalReaddirSync, statSync: originalStatSync, stat: originalStat, realpath: originalRealpath, realpathSync: originalRealpathSync };`; -shimContent = shimContent.replace(/compiler\.options\.resources\.length[\s\S]*wrap\("(.*\\n)"/g, (om, a) => { - return om.replace(a, `${a}${replaceString}`); -}); -fs.writeFileSync(shimPath, shimContent); - -const nexe = require("nexe"); - -const target = `${os.platform()}-${os.arch()}`; -nexe.compile({ - debugBundle: true, - input: path.join(__dirname, "../out/cli.js"), - output: `cli-${target}`, - targets: [target], - /** - * To include native extensions, do NOT install node_modules for each one. They - * are not required as each extension is built using webpack. - */ - resources: [ - path.join(__dirname, "../package.json"), - path.join(__dirname, "../build/**/*"), - ], -}); diff --git a/packages/server/src/cli.ts b/packages/server/src/cli.ts index 4e15d8ad..e2a6ea9f 100644 --- a/packages/server/src/cli.ts +++ b/packages/server/src/cli.ts @@ -9,7 +9,6 @@ import * as os from "os"; import * as path from "path"; import * as WebSocket from "ws"; import { buildDir, cacheHome, dataHome, isCli, serveStatic } from "./constants"; -import { fillFs } from "./fill"; import { setup as setupNativeModules } from "./modules"; import { createApp } from "./server"; import { forkModule, requireFork, requireModule } from "./vscode/bootstrapFork"; @@ -44,8 +43,10 @@ export class Entry extends Command { }]; public async run(): Promise { + Error.stackTraceLimit = Infinity; + if (isCli) { - fillFs(); + require("nbin").shimNativeFs("/home/kyle/node/coder/code-server/packages/server"); } const { args, flags } = this.parse(Entry); @@ -182,13 +183,13 @@ export class Entry extends Command { dataDirectory: dataDir, workingDirectory: workingDir, cacheDirectory: cacheHome, - fork: (modulePath: string, args: string[], options: ForkOptions): ChildProcess => { + fork: (modulePath: string, args?: string[], options?: ForkOptions): ChildProcess => { if (options && options.env && options.env.AMD_ENTRYPOINT) { return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir); } if (isCli) { - return spawn(process.execPath, ["--fork", modulePath, "--args", JSON.stringify(args), "--data-dir", dataDir], { + return spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), "--fork", modulePath, "--args", JSON.stringify(args), "--data-dir", dataDir], { ...options, stdio: [null, null, null, "ipc"], }); diff --git a/packages/server/src/fill.ts b/packages/server/src/fill.ts deleted file mode 100644 index e8de2727..00000000 --- a/packages/server/src/fill.ts +++ /dev/null @@ -1,195 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; -import * as util from "util"; -import { isCli, buildDir } from "./constants"; - -// tslint:disable:no-any -const nativeFs = (global).nativeFs as typeof fs || {}; -const oldAccess = fs.access; -const existsWithinBinary = (path: fs.PathLike): Promise => { - return new Promise((resolve): void => { - if (typeof path === "number") { - if (path < 0) { - return resolve(true); - } - } - oldAccess(path, fs.constants.F_OK, (err) => { - const exists = !err; - const es = fs.existsSync(path); - const res = !exists && es; - resolve(res); - }); - }); -}; - -export const fillFs = (): void => { - /** - * Refer to https://github.com/nexe/nexe/blob/master/src/fs/patch.ts - * For impls - */ - - if (!isCli) { - throw new Error("Should not fill FS when not in CLI"); - } - - interface FD { - readonly path: string; - position: number; - } - - let lastFd = Number.MIN_SAFE_INTEGER; - const fds = new Map(); - - const replaceNative = (propertyName: T, func: (callOld: () => void, ...args: any[]) => any, customPromisify?: (...args: any[]) => Promise): void => { - const oldFunc = (fs)[propertyName]; - fs[propertyName] = (...args: any[]): any => { - try { - return func(() => { - return oldFunc(...args); - }, ...args); - } catch (ex) { - return oldFunc(...args); - } - }; - if (customPromisify) { - (fs[propertyName])[util.promisify.custom] = (...args: any[]): any => { - return customPromisify(...args).catch((ex) => { - throw ex; - }); - }; - } - }; - - replaceNative("access", (callNative, path, mode, callback) => { - existsWithinBinary(path).then((exists) => { - if (!exists) { - return callNative(); - } - - return callback(); - }); - }); - - replaceNative("exists", (callOld, path, callback) => { - existsWithinBinary(path).then((exists) => { - if (exists) { - return callback(true); - } - - return callOld(); - }); - }, (path) => new Promise((res): void => fs.exists(path, res))); - - replaceNative("open", (callOld, path: fs.PathLike, flags: string | Number, mode: any, callback: any) => { - existsWithinBinary(path).then((exists) => { - if (!exists) { - return callOld(); - } - - if (typeof mode === "function") { - callback = mode; - mode = undefined; - } - - if (path === process.execPath) { - return callOld(); - } - - const fd = lastFd++; - fds.set(fd, { - path: path.toString(), - position: 0, - }); - callback(undefined, fd); - }); - }); - - replaceNative("close", (callOld, fd: number, callback) => { - if (!fds.has(fd)) { - return callOld(); - } - - fds.delete(fd); - callback(); - }); - - replaceNative("read", (callOld, fd: number, buffer: Buffer, offset: number, length: number, position: number | null, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void) => { - if (!fds.has(fd)) { - return callOld(); - } - - const fileDesc = fds.get(fd)!; - - return fs.readFile(fileDesc.path, (err, rb) => { - if (err) { - return callOld(); - } - - rb = rb.slice(position || fileDesc.position); - const sliced = rb.slice(0, length); - if (position === null) { - fileDesc.position += sliced.byteLength; - } - buffer.set(sliced, offset); - if (callback) { - callback(undefined!, sliced.byteLength, buffer); - } - }); - }, (fd: number, buffer: Buffer, offset: number, length: number, position: number | null): Promise<{ - bytesRead: number; - buffer: Buffer; - }> => { - return new Promise((res, rej): void => { - fs.read(fd, buffer, offset, length, position, (err, bytesRead, buffer) => { - if (err) { - return rej(err); - } - - res({ - bytesRead, - buffer, - }); - }); - }); - }); - - replaceNative("readdir", (callOld, directory: string, callback: (err: NodeJS.ErrnoException, paths: string[]) => void) => { - const relative = path.relative(directory, buildDir!); - if (relative.startsWith("..")) { - return callOld(); - } - - return nativeFs.readdir(directory, callback); - }); - - const fillNativeFunc = (propertyName: T): void => { - replaceNative(propertyName, (callOld, newPath, ...args) => { - if (typeof newPath !== "string") { - return callOld(); - } - - const rel = path.relative(newPath, buildDir!); - if (rel.startsWith("..")) { - return callOld(); - } - - const func = nativeFs[propertyName] as any; - - return func(newPath, ...args); - }); - }; - - const properties: Array = [ - "existsSync", - "readFile", - "readFileSync", - "createReadStream", - "readdir", - "readdirSync", - "statSync", - "stat", - "realpath", - "realpathSync", - ]; - properties.forEach((p) => fillNativeFunc(p)); -}; diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index d4f45562..ae5a9374 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -1,11 +1,13 @@ -import { mkdirp } from "fs-extra"; -import { logger, field } from "@coder/logger"; +import { field, logger } from "@coder/logger"; import { ReadWriteConnection } from "@coder/protocol"; import { Server, ServerOptions } from "@coder/protocol/src/node/server"; +import { TunnelCloseCode } from "@coder/tunnel/src/common"; +import { handle as handleTunnel } from "@coder/tunnel/src/server"; import * as express from "express"; //@ts-ignore import * as expressStaticGzip from "express-static-gzip"; import * as fs from "fs"; +import { mkdirp } from "fs-extra"; import * as http from "http"; //@ts-ignore import * as httpolyglot from "httpolyglot"; @@ -17,11 +19,9 @@ import * as path from "path"; import * as pem from "pem"; import * as util from "util"; import * as ws from "ws"; -import safeCompare = require("safe-compare"); -import { TunnelCloseCode } from "@coder/tunnel/src/common"; -import { handle as handleTunnel } from "@coder/tunnel/src/server"; -import { createPortScanner } from "./portScanner"; import { buildDir } from "./constants"; +import { createPortScanner } from "./portScanner"; +import safeCompare = require("safe-compare"); interface CreateAppOptions { registerMiddleware?: (app: express.Application) => void; @@ -180,10 +180,13 @@ export const createApp = async (options: CreateAppOptions): Promise<{ logger.error(error.message); } }, + onUp: (): void => undefined, // This can't come back up. + onDown: (cb): void => ws.addEventListener("close", () => cb()), onClose: (cb): void => ws.addEventListener("close", () => cb()), }; - const server = new Server(connection, options.serverOptions); + // tslint:disable-next-line no-unused-expression + new Server(connection, options.serverOptions); }); const baseDir = buildDir || path.join(__dirname, ".."); @@ -202,6 +205,10 @@ export const createApp = async (options: CreateAppOptions): Promise<{ unauthStaticFunc(req, res, next); } }); + // @ts-ignore + app.use((err, req, res, next) => { + next(); + }); app.get("/ping", (req, res) => { res.json({ hostname: os.hostname(), @@ -235,9 +242,11 @@ export const createApp = async (options: CreateAppOptions): Promise<{ } const content = await util.promisify(fs.readFile)(fullPath); - res.header("Content-Type", mimeType as string); + res.writeHead(200, { + "Content-Type": mimeType, + "Content-Length": content.byteLength, + }); res.write(content); - res.status(200); res.end(); } catch (ex) { res.write(ex.toString()); diff --git a/packages/server/src/vscode/bootstrapFork.ts b/packages/server/src/vscode/bootstrapFork.ts index 71ff3815..5b2349ff 100644 --- a/packages/server/src/vscode/bootstrapFork.ts +++ b/packages/server/src/vscode/bootstrapFork.ts @@ -1,9 +1,8 @@ import * as cp from "child_process"; import * as fs from "fs"; import * as path from "path"; -import * as zlib from "zlib"; import * as vm from "vm"; -import { isCli } from "../constants"; +import { buildDir, isCli } from "../constants"; let ipcMsgBuffer: Buffer[] | undefined = []; let ipcMsgListener = process.send ? (d: Buffer): number => ipcMsgBuffer!.push(d) : undefined; @@ -11,6 +10,8 @@ if (ipcMsgListener) { process.on("message", ipcMsgListener); } +declare var __non_webpack_require__: typeof require; + /** * Requires a module from the filesystem. * @@ -29,7 +30,7 @@ const requireFilesystemModule = (id: string, builtInExtensionsDir: string): any const fileName = id.endsWith(".js") ? id : `${id}.js`; const req = vm.runInThisContext(mod.wrap(fs.readFileSync(fileName).toString()), { displayErrors: true, - filename: id + fileName, + filename: fileName, }); req(customMod.exports, customMod.require.bind(customMod), customMod, fileName, path.dirname(id)); @@ -46,6 +47,14 @@ export const requireFork = (modulePath: string, args: string[], builtInExtension const Module = require("module") as typeof import("module"); const oldRequire = Module.prototype.require; // tslint:disable-next-line:no-any + const oldLoad = (Module as any)._findPath; + // @ts-ignore + (Module as any)._findPath = function (request, parent, isMain): any { + const lookupPaths = oldLoad.call(this, request, parent, isMain); + + return lookupPaths; + }; + // tslint:disable-next-line:no-any Module.prototype.require = function (id: string): any { if (id === "typescript") { return require("typescript"); @@ -96,23 +105,20 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens */ // tslint:disable-next-line:no-any (cp).fork = (modulePath: string, args: ReadonlyArray = [], options?: cp.ForkOptions): cp.ChildProcess => { - return cp.spawn(process.execPath, ["--fork", modulePath, "--args", JSON.stringify(args), "--data-dir", dataDir], { + return cp.spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), "--fork", modulePath, "--args", JSON.stringify(args), "--data-dir", dataDir], { ...options, stdio: [null, null, null, "ipc"], }); }; } - let content: Buffer | undefined; - const readFile = (name: string): Buffer => { - return fs.readFileSync(path.join(process.env.BUILD_DIR as string || path.join(__dirname, "../.."), "./build", name)); - }; + const baseDir = path.join(buildDir, "build"); if (isCli) { - content = zlib.gunzipSync(readFile("bootstrap-fork.js.gz")); + __non_webpack_require__(path.join(baseDir, "bootstrap-fork.js.gz")); } else { - content = readFile("../../vscode/out/bootstrap-fork.js"); + // We need to check `isCli` here to confuse webpack. + require(path.join(__dirname, isCli ? "" : "../../../vscode/out/bootstrap-fork.js")); } - eval(content.toString()); }; /** @@ -123,12 +129,12 @@ export const requireModule = (modulePath: string, dataDir: string, builtInExtens * cp.stderr.on("data", (data) => console.log(data.toString("utf8"))); * @param modulePath Path of the VS Code module to load. */ -export const forkModule = (modulePath: string, args: string[], options: cp.ForkOptions, dataDir?: string): cp.ChildProcess => { +export const forkModule = (modulePath: string, args?: string[], options?: cp.ForkOptions, dataDir?: string): cp.ChildProcess => { let proc: cp.ChildProcess; const forkOptions: cp.ForkOptions = { stdio: [null, null, null, "ipc"], }; - if (options.env) { + if (options && options.env) { // This prevents vscode from trying to load original-fs from electron. delete options.env.ELECTRON_RUN_AS_NODE; forkOptions.env = options.env; @@ -141,7 +147,7 @@ export const forkModule = (modulePath: string, args: string[], options: cp.ForkO forkArgs.push("--data-dir", dataDir); } if (isCli) { - proc = cp.spawn(process.execPath, forkArgs, forkOptions); + proc = cp.spawn(process.execPath, [path.join(buildDir, "out", "cli.js"), ...forkArgs], forkOptions); } else { proc = cp.spawn(process.execPath, ["--require", "ts-node/register", "--require", "tsconfig-paths/register", process.argv[1], ...forkArgs], forkOptions); } diff --git a/packages/server/webpack.config.js b/packages/server/webpack.config.js index 25141922..0b3ddb2c 100644 --- a/packages/server/webpack.config.js +++ b/packages/server/webpack.config.js @@ -13,6 +13,7 @@ module.exports = merge( path: path.join(__dirname, "out"), libraryTarget: "commonjs", }, + mode: "production", node: { console: false, global: false, @@ -27,7 +28,11 @@ module.exports = merge( "node-pty": "node-pty-prebuilt", }, }, - externals: ["tslib"], + externals: { + "tslib": "commonjs tslib", + "nbin": "commonjs nbin", + "fsevents": "fsevents", + }, entry: "./packages/server/src/cli.ts", plugins: [ new webpack.DefinePlugin({ diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index ea9514c2..d07319f8 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -2,6 +2,22 @@ # yarn lockfile v1 +"@coder/logger@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.0.3.tgz#e0e1ae5496fde5a3c6ef3d748fdfb26a55add8b8" + integrity sha512-1o5qDZX2VZUNnzgz5KfAdMnaqaX6FNeTs0dUdg73MRHfQW94tFTIryFC1xTTCuzxGDjVHOHkaUAI4uHA2bheOA== + +"@coder/nbin@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@coder/nbin/-/nbin-1.0.0.tgz#3919a9ea49200e6fed855742d34f02d40db06c79" + integrity sha512-HHgoLITnPu6riv94lOBKhJiSHdx8OhDl1MYjPb2wj7eXYh/t4swb7B4OQ7Smttp6DqWxBTOsbySxhVuJNhvqaw== + dependencies: + "@coder/logger" "^1.0.3" + fs-extra "^7.0.1" + glob "^7.1.3" + node-fetch "^2.3.0" + ora "^3.2.0" + "@oclif/command@^1.5.4": version "1.5.8" resolved "https://registry.yarnpkg.com/@oclif/command/-/command-1.5.8.tgz#cd09d4f3183123548cb25d1b12b92e41277ac3e9" @@ -59,11 +75,6 @@ widest-line "^2.0.1" wrap-ansi "^4.0.0" -"@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== - "@types/body-parser@*": version "1.17.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c" @@ -169,11 +180,6 @@ "@types/events" "*" "@types/node" "*" -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== - accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" @@ -182,51 +188,11 @@ accepts@~1.3.5: mime-types "~2.1.18" negotiator "0.6.1" -acorn-jsx@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" - integrity sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw== - dependencies: - acorn "^5.0.3" - -acorn@^5.0.3, acorn@^5.7.3: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== - -ajax-request@^1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/ajax-request/-/ajax-request-1.2.3.tgz#99fcbec1d6d2792f85fa949535332bd14f5f3790" - integrity sha1-mfy+wdbSeS+F+pSVNTMr0U9fN5A= - dependencies: - file-system "^2.1.1" - utils-extend "^1.0.7" - -ajv@^6.5.5: - version "6.9.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.2.tgz#4927adb83e7f48e5a32b45729744c71ec39c9c7b" - integrity sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" @@ -237,11 +203,6 @@ ansi-regex@^4.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -249,123 +210,16 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" - integrity sha1-DELU+xcWDVqa8eSEus4cZpIsGyE= - -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" - -app-builder@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/app-builder/-/app-builder-5.2.0.tgz#0ec0c7fa0bbeb7e526294c445e13f1236002827c" - integrity sha512-RRj/vu8WhmMM71G9BxMLRvcwpr1QUJZ9NXURGGo1v3fPiauzkQfNi31kM7irRNqR87NV+lJ/qI62iTzcAc+V0Q== - -app-root-path@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-1.4.0.tgz#6335d865c9640d0fad99004e5a79232238e92dfa" - integrity sha1-YzXYZclkDQ+tmQBOWnkjIjjpLfo= - -app-root-path@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.1.0.tgz#98bf6599327ecea199309866e8140368fd2e646a" - integrity sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo= - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= - dependencies: - arr-flatten "^1.0.1" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.0.1, arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - integrity sha1-GdOGodntxufByF04iu28xW0zYC0= - async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -376,87 +230,16 @@ async@~0.2.10: resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-img@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/base64-img/-/base64-img-1.0.4.tgz#3e22d55d6c74a24553d840d2b1bc12a7db078d35" - integrity sha1-PiLVXWx0okVT2EDSsbwSp9sHjTU= - dependencies: - ajax-request "^1.2.0" - file-system "^2.1.0" - -base64-js@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" - integrity sha1-EQHpVE9KdrG8OybUUsqW16NeeXg= - -base64-js@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== -binary-extensions@^1.0.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.0.tgz#9523e001306a32444b907423f1de2164222f6ab1" - integrity sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw== - -bl@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - body-parser@1.18.3: version "1.18.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" @@ -473,11 +256,6 @@ body-parser@1.18.3: raw-body "2.3.3" type-is "~1.6.16" -bowser@^2.0.0-beta.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.1.0.tgz#76cc094f97578ba4858fb4359445ee1317d1be6f" - integrity sha512-tP90ci4QY8PRBQjU0+iTsoO3DMNYtXCM0aVxeKhjxXF8IH9xTXUmjcTECPN+y5v0BGeRDfMcSLeohPiUZuz37g== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -486,31 +264,6 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -524,11 +277,6 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" @@ -539,85 +287,12 @@ buffer-from@^1.0.0, buffer-from@^1.1.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -buffer@^3.0.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb" - integrity sha1-pyyTb3e5a/UvX357RnGAYoVR3vs= - dependencies: - base64-js "0.0.8" - ieee754 "^1.1.4" - isarray "^1.0.0" - bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -caw@^2.0.0, caw@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95" - integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== - dependencies: - get-proxy "^2.0.0" - isurl "^1.0.0-alpha5" - tunnel-agent "^0.6.0" - url-to-options "^1.0.1" - -chain-able@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chain-able/-/chain-able-1.0.1.tgz#b48ac9bdc18f2192ec730abc66609f90aab5605f" - integrity sha1-tIrJvcGPIZLscwq8ZmCfkKq1YF8= - -chain-able@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chain-able/-/chain-able-3.0.0.tgz#dcffe8b04f3da210941a23843bc1332bb288ca9f" - integrity sha512-26MoELhta86n7gCsE2T1hGRyncZvPjFXTkB/DEp4+i/EJVSxXQNwXMDZZb2+SWcbPuow18wQtztaW7GXOel9DA== - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1: +chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -626,54 +301,11 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= - charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= -chokidar@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - -chownr@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" - integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -clean-css@^4.1.9: - version "4.2.1" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" - integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== - dependencies: - source-map "~0.6.0" - clean-stack@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.3.0.tgz#9e821501ae979986c46b1d66d2d432db2fd4ae31" @@ -686,35 +318,15 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" -cli-spinners@^1.0.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" - integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== +cli-spinners@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.0.0.tgz#4b078756fc17a8f72043fdc9f1f14bf4fa87e2df" + integrity sha512-yiEBmhaKPPeBj7wWm4GEdtPZK940p9pl3EANIrnJ3JnvWyrPjcFcsEq6qRUuQ7fzB0+Y82ld3p6B34xo95foWw== -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - -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" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= color-convert@^1.9.0: version "1.9.3" @@ -728,65 +340,16 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== - dependencies: - delayed-stream "~1.0.0" - -commander@~2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== - -commander@~2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" - integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== - -commander@~2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= - dependencies: - graceful-readlink ">= 1.0.0" - -component-emitter@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= - 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= -config-chain@^1.1.11: - version "1.1.12" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= -content-disposition@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - dependencies: - safe-buffer "5.1.2" - content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -802,16 +365,6 @@ cookie@0.3.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - crypt@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" @@ -831,14 +384,7 @@ csso@1.3.x: resolved "https://registry.yarnpkg.com/csso/-/csso-1.3.12.tgz#fc628694a2d38938aaac4996753218fd311cdb9e" integrity sha1-/GKGlKLTiTiqrEmWdTIY/TEc254= -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -852,86 +398,18 @@ debug@^4.1.0: dependencies: ms "^2.1.1" -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -decompress-response@^3.2.0, 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" - -decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - -decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - -decompress-targz@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - -decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d" - integrity sha1-eu3YVCflqS2s/lVnSnxQXpbQH50= - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.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== - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - deepmerge@^2.0.1: version "2.2.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + define-properties@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -939,38 +417,6 @@ define-properties@^1.1.2: dependencies: object-keys "^1.0.12" -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -981,46 +427,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== -download@^6.2.0: - version "6.2.5" - resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714" - integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA== - dependencies: - caw "^2.0.0" - content-disposition "^0.5.2" - decompress "^4.0.0" - ext-name "^5.0.0" - file-type "5.2.0" - filenamify "^2.0.0" - get-stream "^3.0.0" - got "^7.0.0" - make-dir "^1.0.0" - p-event "^1.0.0" - pify "^3.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= - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -1036,13 +447,6 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== - dependencies: - once "^1.4.0" - es-abstract@^1.9.0: version "1.13.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" @@ -1074,77 +478,16 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@^1.8.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.1.tgz#c485ff8d6b4cdb89e27f4a856e91f118401ca510" - integrity sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw== - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -esprima@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= - -estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -exec-sh@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== - dependencies: - merge "^1.2.0" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= - dependencies: - is-posix-bracket "^0.1.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - dependencies: - fill-range "^2.1.0" - express-static-gzip@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/express-static-gzip/-/express-static-gzip-1.1.3.tgz#345ea02637d9d5865777d6fb57ccc0884abcda65" @@ -1152,7 +495,7 @@ express-static-gzip@^1.1.3: dependencies: serve-static "^1.12.3" -express@^4.14.0, express@^4.16.4: +express@^4.16.4: version "4.16.4" resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== @@ -1188,110 +531,6 @@ express@^4.14.0, express@^4.16.4: utils-merge "1.0.1" vary "~1.1.2" -ext-list@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" - integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== - dependencies: - mime-db "^1.28.0" - -ext-name@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" - integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== - dependencies: - ext-list "^2.0.0" - sort-keys-length "^1.0.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^2.0.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= - dependencies: - is-extglob "^1.0.0" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - file-loader@^0.8.1: version "0.8.5" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.8.5.tgz#9275d031fe780f27d47f5f4af02bd43713cc151b" @@ -1299,76 +538,6 @@ file-loader@^0.8.1: dependencies: loader-utils "~0.2.5" -file-match@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/file-match/-/file-match-1.0.2.tgz#c9cad265d2c8adf3a81475b0df475859069faef7" - integrity sha1-ycrSZdLIrfOoFHWw30dYWQafrvc= - dependencies: - utils-extend "^1.0.6" - -file-system@^2.1.0, file-system@^2.1.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/file-system/-/file-system-2.2.2.tgz#7d65833e3a2347dcd956a813c677153ed3edd987" - integrity sha1-fWWDPjojR9zZVqgTxncVPtPt2Yc= - dependencies: - file-match "^1.0.1" - utils-extend "^1.0.4" - -file-type@5.2.0, file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha1-LdvqfHP/42No365J3DOMBYwritY= - -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= - -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - -filenamify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" - integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.0" - trim-repeated "^1.0.0" - -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" @@ -1382,69 +551,16 @@ finalhandler@1.1.1: statuses "~1.4.0" unpipe "~1.0.0" -fliplog@^0.3.13: - version "0.3.13" - resolved "https://registry.yarnpkg.com/fliplog/-/fliplog-0.3.13.tgz#dd0d786e821822aae272e0ddc84012596a96154c" - integrity sha512-R504CdX+mdhMYpmyrdiQ9PW6ncAyZnxyeA85fS1/P/Y9qmbMiQsqt6QzsYhq5kbqMb84PibVOcS1oz98GJl6EQ== - dependencies: - chain-able "^1.0.1" - -for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - dependencies: - for-in "^1.0.1" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -from2@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - fs-extra@^7.0.0, fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -1454,144 +570,17 @@ fs-extra@^7.0.0, fs-extra@^7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" - integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== - dependencies: - minipass "^2.2.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@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" - integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== - dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -fuse-box@^3.1.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/fuse-box/-/fuse-box-3.7.1.tgz#d32879ceee4c8bcec9bbd8fcfe5b29e7142371cd" - integrity sha512-aM7t9bUcRpNNQu9M+YjXXzx9JSJQVPWeY+8iTyv7OhvJNWHrqqEWPzbn9OfcyFa2AfPwAUyC/uzWexBbjtTvsA== - dependencies: - acorn "^5.7.3" - acorn-jsx "^4.0.1" - ansi "^0.3.1" - app-root-path "^2.0.1" - base64-img "^1.0.3" - base64-js "^1.2.0" - bowser "^2.0.0-beta.3" - chokidar "^1.6.1" - clean-css "^4.1.9" - escodegen "^1.8.1" - express "^4.14.0" - fliplog "^0.3.13" - fs-extra "^7.0.0" - fuse-concat-with-sourcemaps "^1.0.5" - getopts "^2.1.1" - glob "^7.1.1" - ieee754 "^1.1.8" - inquirer "^3.0.6" - lego-api "^1.0.7" - mustache "^2.3.0" - postcss "^6.0.1" - pretty-time "^0.2.0" - prettysize "0.0.3" - realm-utils "^1.0.9" - regexpu-core "^4.1.3" - request "^2.79.0" - shorthash "0.0.2" - source-map "^0.7.1" - sourcemap-blender "1.0.5" - stream-browserify "^2.0.1" - tslib "^1.8.0" - watch "^1.0.1" - ws "^1.1.1" - -fuse-concat-with-sourcemaps@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fuse-concat-with-sourcemaps/-/fuse-concat-with-sourcemaps-1.0.5.tgz#9c6a521f675cff5cdbb48db1ca9c181ae49a7b97" - integrity sha512-tKsRJIxn9tU3IH8JHMwFhGbObqkDKXhNKOvcM+QyflAlYb2EgOvIQe8D6WB/cocA3puldHatsp9SN5SKryasrw== - dependencies: - source-map "^0.6.1" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -get-proxy@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" - integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== - dependencies: - npm-conf "^1.1.0" - -get-stream@3.0.0, get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getopts@^2.1.1: - version "2.2.4" - resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.4.tgz#3137fe8a5fddf304904059a851bdc1c22f0f54fb" - integrity sha512-Rz7DGyomZjrenu9Jx4qmzdlvJgvrEFHXHvjK0FcZtcTC1U5FmES7OdZHUwMuSnEE6QvBvwse1JODKj7TgbSEjQ== - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= - dependencies: - is-glob "^2.0.0" - -glob@^7.0.3, glob@^7.1.1, glob@^7.1.3: +glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -1603,148 +592,21 @@ glob@^7.0.3, glob@^7.1.1, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -got@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -got@^8.0.3: - version "8.3.2" - resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" - integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.4.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - 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-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== - dependencies: - has-symbol-support-x "^1.4.1" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -1752,11 +614,6 @@ has@^1.0.1, has@^1.0.3: dependencies: function-bind "^1.1.1" -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" @@ -1767,15 +624,6 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - httpolyglot@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/httpolyglot/-/httpolyglot-0.1.2.tgz#e4d347fe8984a62f467d4060df527f1851f6997b" @@ -1788,25 +636,6 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.17, iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ieee754@^1.1.4, ieee754@^1.1.8: - version "1.1.12" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" - integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== - -ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== - dependencies: - minimatch "^3.0.4" - indent-string@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" @@ -1820,71 +649,17 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4, ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - ipaddr.js@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5, is-buffer@~1.1.1: +is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -1894,147 +669,16 @@ is-callable@^1.1.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - 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-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= - dependencies: - is-extglob "^1.0.0" - -is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= - -is-number@^2.0.2, is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - -is-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -2042,16 +686,6 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= - -is-stream@^1.0.0, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - is-symbol@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" @@ -2059,86 +693,16 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.0" -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-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -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= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - json5@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -2158,62 +722,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -keyv@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== - dependencies: - json-buffer "3.0.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - -lego-api@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/lego-api/-/lego-api-1.0.8.tgz#5e26be726c5e11d540f89e7c6b1abf8c5834bd01" - integrity sha512-pZD0mf32+RL1bUMJztRcXiNBB1gE8gd/h4MDLWdZp7vaMZyjPiYK/zNpNNGoJvmoa7D/wf9dll+5z7pDObdLFg== - dependencies: - chain-able "^3.0.0" - -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - loader-utils@^0.2.5, loader-utils@~0.2.2, loader-utils@~0.2.3, loader-utils@~0.2.5: version "0.2.17" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" @@ -2244,57 +752,18 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "~3.0.0" -lodash@^4.3.0: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - -log-symbols@^2.1.0: +log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== dependencies: chalk "^2.0.1" -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= - -lowercase-keys@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - make-error@^1.1.1: version "1.3.5" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -math-random@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" - integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== - md5@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" @@ -2314,71 +783,16 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= -merge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" - integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== - methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^2.1.5: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -micromatch@^3.1.10: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -mime-db@^1.28.0, mime-db@~1.37.0: +mime-db@~1.37.0: version "1.37.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== -mime-db@~1.38.0: - version "1.38.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" - integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.22" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" - integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== - dependencies: - mime-db "~1.38.0" - mime-types@^2.1.21, mime-types@~2.1.18: version "2.1.21" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" @@ -2396,11 +810,6 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-response@^1.0.0: - 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" @@ -2418,30 +827,7 @@ minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -minipass@^2.2.1, minipass@^2.3.4: - version "2.3.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" - integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" - integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== - dependencies: - minipass "^2.2.1" - -mixin-deep@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -2458,77 +844,15 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -mustache@^2.3.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.2.tgz#a6d4d9c3f91d13359ab889a812954f9230a3d0c5" - integrity sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ== - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -nan@^2.9.2: - version "2.12.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" - integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -nanoseconds@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/nanoseconds/-/nanoseconds-0.1.0.tgz#69ec39fcd00e77ab3a72de0a43342824cd79233a" - integrity sha1-aew5/NAOd6s6ct4KQzQoJM15Izo= - -needle@^2.2.1: - version "2.2.4" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" - integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== - dependencies: - debug "^2.1.2" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= -nexe@^2.0.0-rc.34: - version "2.0.0-rc.34" - resolved "https://registry.yarnpkg.com/nexe/-/nexe-2.0.0-rc.34.tgz#7ad082a3b11bfa2d53885e0fb6ca4d4ba0c5b0f2" - integrity sha512-BUzKZ2KnBzycbG4Ix3NpsimIGehRyRkKuZ2SpgmblDvvKR0NBF61i2Aqno3HmoBZW8uAYKjqazp81ovAAU2Rvw== - dependencies: - app-builder "^5.1.0" - caw "^2.0.1" - chalk "^1.1.3" - download "^6.2.0" - fuse-box "^3.1.0" - globby "^6.1.0" - got "^8.0.3" - minimist "^1.2.0" - mkdirp "^0.5.1" - ora "^1.2.0" - pify "^3.0.0" - rimraf "^2.6.1" - typescript "2.5.3" - uglify-es "^3.3.9" - uglify-js "3.0.28" +node-fetch@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" + integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== node-netstat@^1.6.0: version "1.6.0" @@ -2537,128 +861,16 @@ node-netstat@^1.6.0: dependencies: is-wsl "^1.1.0" -node-pre-gyp@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - -normalize-path@^2.0.0, normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - -npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== - -npm-conf@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" - integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== - dependencies: - config-chain "^1.1.11" - pify "^3.0.0" - -npm-packlist@^1.1.6: - version "1.4.1" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" - integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - object-keys@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -2666,7 +878,7 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" -once@^1.3.0, once@^1.4.0: +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -2687,112 +899,28 @@ opn@^5.4.0: dependencies: is-wsl "^1.1.0" -optionator@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= +ora@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.2.0.tgz#67e98a7e11f7f0ac95deaaaf11bb04de3d09e481" + integrity sha512-XHMZA5WieCbtg+tu0uPF8CjvwQdNzKCX6BVh3N6GFsEXH40mTk5dsw/ya1lBTUGJslcEFJFQ8cBhOgkkZXQtMA== dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - integrity sha1-7CLTEoBrtT5zF3Pnza788cZDEo8= - -ora@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-1.4.0.tgz#884458215b3a5d4097592285f93321bb7a79e2e5" - integrity sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw== - dependencies: - chalk "^2.1.0" + chalk "^2.4.2" cli-cursor "^2.1.0" - cli-spinners "^1.0.1" - log-symbols "^2.1.0" + cli-spinners "^2.0.0" + log-symbols "^2.2.0" + strip-ansi "^5.0.0" + wcwidth "^1.0.1" -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== - -p-cancelable@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" - integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== - -p-event@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-event/-/p-event-1.3.0.tgz#8e6b4f4f65c72bc5b6fe28b75eda874f96a4a085" - integrity sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU= - dependencies: - p-timeout "^1.1.1" - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= - -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= - dependencies: - p-finally "^1.0.0" - -p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== - dependencies: - p-finally "^1.0.0" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - 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" @@ -2813,90 +941,6 @@ pem@^1.14.1: os-tmpdir "^1.0.1" which "^1.3.1" -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss@^6.0.1: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - -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= - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= - -pretty-time@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-0.2.0.tgz#7a3bdec4049c620cd7c42b7f342b74d56e73d74e" - integrity sha1-ejvexAScYgzXxCt/NCt01W5z104= - dependencies: - is-number "^2.0.2" - nanoseconds "^0.1.0" - -prettysize@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/prettysize/-/prettysize-0.0.3.tgz#14afff6a645e591a4ddf1c72919c23b4146181a1" - integrity sha1-FK//amReWRpN3xxykZwjtBRhgaE= - -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== - promise.prototype.finally@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" @@ -2906,11 +950,6 @@ promise.prototype.finally@^3.1.0: es-abstract "^1.9.0" function-bind "^1.1.1" -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" @@ -2919,44 +958,11 @@ proxy-addr@~2.0.4: forwarded "~0.1.2" ipaddr.js "1.8.0" -psl@^1.1.24: - version "1.1.31" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" - integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -qs@6.5.2, qs@~6.5.2: +qs@6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -randomatic@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" - integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -2972,150 +978,6 @@ raw-body@2.3.3: iconv-lite "0.4.23" unpipe "1.0.0" -rc@^1.2.7: - 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" - -readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readdirp@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -realm-utils@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/realm-utils/-/realm-utils-1.0.9.tgz#5c76a5ff39e4816af2c133a161f4221d6628eff4" - integrity sha1-XHal/znkgWrywTOhYfQiHWYo7/Q= - dependencies: - app-root-path "^1.3.0" - mkdirp "^0.5.1" - -regenerate-unicode-properties@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" - integrity sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== - dependencies: - is-equal-shallow "^0.1.3" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexpu-core@^4.1.3: - version "4.4.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.4.0.tgz#8d43e0d1266883969720345e70c275ee0aec0d32" - integrity sha512-eDDWElbwwI3K0Lo6CqbQbA6FwgtCz4kYTarrri1okfkRLZAqstU+B3voZBCjg8Fl6iq0gXrJG6MvRgLthfvgOA== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^7.0.0" - regjsgen "^0.5.0" - regjsparser "^0.6.0" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.0.2" - -regjsgen@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" - integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== - -regjsparser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" - integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== - dependencies: - jsesc "~0.5.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.5.2, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request@^2.79.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -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" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -3124,38 +986,7 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -rimraf@^2.6.1: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" - -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= - -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -3167,31 +998,12 @@ safe-compare@^1.1.4: dependencies: buffer-alloc "^1.2.0" -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -seek-bzip@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" - integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w= - dependencies: - commander "~2.8.1" - -semver@^5.3.0, semver@^5.6.0: +semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -3225,108 +1037,16 @@ serve-static@1.13.2, serve-static@^1.12.3: parseurl "~1.3.2" send "0.16.2" -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" - -set-value@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== -shorthash@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/shorthash/-/shorthash-0.0.2.tgz#59b268eecbde59038b30da202bcfbddeb2c4a4eb" - integrity sha1-WbJo7sveWQOLMNogK8+93rLEpOs= - -signal-exit@^3.0.0, signal-exit@^3.0.2: +signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sort-keys-length@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" - integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= - dependencies: - sort-keys "^1.0.0" - -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= - dependencies: - is-plain-obj "^1.0.0" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - source-map-support@^0.5.6: version "0.5.10" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" @@ -3335,26 +1055,11 @@ source-map-support@^0.5.6: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.6, source-map@~0.5.1: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: +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== -source-map@^0.7.1, source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - source-map@~0.1.38: version "0.1.43" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" @@ -3362,43 +1067,6 @@ source-map@~0.1.38: dependencies: amdefine ">=0.0.4" -sourcemap-blender@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sourcemap-blender/-/sourcemap-blender-1.0.5.tgz#d361f3d12381c4e477178113878fdf984a91bdbc" - integrity sha512-GPhjCmDtJ8YY6zt1L6kP6WtBg6WrdWt5hw2Wmgt9rwC3yiwLo9vEuabh/YYSZ5KmFV20hVkGdkTwpXtT2E65TA== - dependencies: - source-map "^0.7.3" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -3409,19 +1077,6 @@ statuses@~1.4.0: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - string-replace-webpack-plugin@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/string-replace-webpack-plugin/-/string-replace-webpack-plugin-0.1.3.tgz#73c657e759d66cfe80ae1e0cf091aa256d0e715c" @@ -3434,16 +1089,7 @@ string-replace-webpack-plugin@^0.1.3: file-loader "^0.8.1" style-loader "^0.8.3" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.1.0, string-width@^2.1.1: +string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -3451,20 +1097,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -3484,25 +1116,6 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - -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= - -strip-outer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - style-loader@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.8.3.tgz#f4f92eb7db63768748f15065cd6700f5a1c85357" @@ -3510,106 +1123,13 @@ style-loader@^0.8.3: dependencies: loader-utils "^0.2.5" -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0, supports-color@^5.4.0: +supports-color@^5.3.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" -tar-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - -tar@^4: - version "4.4.8" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" - integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.3.4" - minizlib "^1.1.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.2" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - ts-node@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" @@ -3635,30 +1155,11 @@ tsconfig-paths@^3.7.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.8.0, tslib@^1.9.3: +tslib@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" @@ -3667,78 +1168,11 @@ type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.18" -typescript@2.5.3: - version "2.5.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.3.tgz#df3dcdc38f3beb800d4bc322646b04a3f6ca7f0d" - integrity sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w== - typescript@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== -uglify-es@^3.3.9: - version "3.3.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" - integrity sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ== - dependencies: - commander "~2.13.0" - source-map "~0.6.1" - -uglify-js@3.0.28: - version "3.0.28" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.28.tgz#96b8495f0272944787b5843a1679aa326640d5f7" - integrity sha512-0h/qGay016GG2lVav3Kz174F3T2Vjlz2v6HCt+WDQpoXfco0hWwF5gHK9yh88mUYvIC+N7Z8NT8WpjSp1yoqGA== - dependencies: - commander "~2.11.0" - source-map "~0.5.1" - -ultron@1.0.x: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= - -unbzip2-stream@^1.0.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1" - integrity sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw== - dependencies: - buffer "^3.0.1" - through "^2.3.6" - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz#9f1dc76926d6ccf452310564fd834ace059663d4" - integrity sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" - integrity sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg== - -union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^0.4.3" - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -3749,91 +1183,22 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - -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" - -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -utils-extend@^1.0.4, utils-extend@^1.0.6, utils-extend@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/utils-extend/-/utils-extend-1.0.8.tgz#ccfd7b64540f8e90ee21eec57769d0651cab8a5f" - integrity sha1-zP17ZFQPjpDuIe7Fd2nQZRyril8= - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -watch@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" - integrity sha1-NApxe952Vyb6CqB9ch4BR6VR3ww= - dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" + defaults "^1.0.3" which@^1.3.1: version "1.3.1" @@ -3842,13 +1207,6 @@ which@^1.3.1: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - widest-line@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" @@ -3856,11 +1214,6 @@ widest-line@^2.0.1: dependencies: string-width "^2.1.1" -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - wrap-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-4.0.0.tgz#b3570d7c70156159a2d42be5cc942e957f7b1131" @@ -3875,14 +1228,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@^1.1.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" - integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w== - dependencies: - options ">=0.0.5" - ultron "1.0.x" - ws@^6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.2.tgz#3cc7462e98792f0ac679424148903ded3b9c3ad8" @@ -3895,24 +1240,6 @@ xhr2@^0.1.4: resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= -xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= - -yallist@^3.0.0, yallist@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" - integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== - -yauzl@^2.4.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - yn@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" diff --git a/packages/vscode/package.json b/packages/vscode/package.json index df9c53c9..777dcdf6 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -8,7 +8,6 @@ "dependencies": { "iconv-lite": "^0.4.24", "onigasm": "^2.2.1", - "spdlog": "^0.7.2", "string-replace-loader": "^2.1.1", "tar-stream": "^2.0.1" }, diff --git a/packages/vscode/src/dialog.ts b/packages/vscode/src/dialog.ts index e7788e12..9321fac8 100644 --- a/packages/vscode/src/dialog.ts +++ b/packages/vscode/src/dialog.ts @@ -1,7 +1,7 @@ import * as fs from "fs"; import * as path from "path"; +import * as util from "util"; import { Emitter, Event } from "@coder/events"; -import { client as ideClient } from "@coder/ide/src/fill/client"; import { $, addClass, append } from "vs/base/browser/dom"; import { HighlightedLabel } from "vs/base/browser/ui/highlightedlabel/highlightedLabel"; import { ObjectTree } from "vs/base/browser/ui/tree/objectTree"; @@ -16,8 +16,6 @@ import { IThemeService } from "vs/platform/theme/common/themeService"; import { workbench } from "./workbench"; import "./dialog.scss"; -declare var __non_webpack_require__: typeof require; - export enum DialogType { NewFolder, Save, @@ -183,15 +181,15 @@ class Dialog { this.filesNode = document.createElement("div"); this.filesNode.className = "files-list"; this.entryList = new ObjectTree(this.filesNode, { - getHeight: (entry: DialogEntry): number => { + getHeight: (_entry: DialogEntry): number => { return 20; }, - getTemplateId: (entry: DialogEntry): string => { + getTemplateId: (_entry: DialogEntry): string => { return "dialog-entry"; }, }, [new DialogEntryRenderer()], { openController: { - shouldOpen: (event): boolean => { + shouldOpen: (_event): boolean => { return true; }, }, @@ -341,7 +339,6 @@ class Dialog { } private set path(directory: string) { - const ts = Date.now(); this.list(directory).then((value) => { this._path = directory; this.buildPath(); @@ -380,32 +377,16 @@ class Dialog { } private async list(directory: string): Promise> { - return ideClient.evaluate((_helper, directory) => { - const fs = __non_webpack_require__("fs") as typeof import("fs"); - const util = __non_webpack_require__("util") as typeof import("util"); - const path = __non_webpack_require__("path") as typeof import("path"); + const paths = (await util.promisify(fs.readdir)(directory)).sort(); + const stats = await Promise.all(paths.map(p => util.promisify(fs.stat)(path.join(directory, p)))); - return util.promisify(fs.readdir)(directory).then((paths) => { - paths = paths.sort(); - - return Promise.all(paths.map(p => util.promisify(fs.stat)(path.join(directory, p)))).then((stats) => { - return { - paths, - stats, - }; - }); - }).then(({ paths, stats }) => { - return stats.map((stat, index): DialogEntry => { - return { - fullPath: path.join(directory, paths[index]), - name: paths[index], - isDirectory: stat.isDirectory(), - lastModified: stat.mtime.toDateString(), - size: stat.size, - }; - }); - }); - }, directory); + return stats.map((stat, index): DialogEntry => ({ + fullPath: path.join(directory, paths[index]), + name: paths[index], + isDirectory: stat.isDirectory(), + lastModified: stat.mtime.toDateString(), + size: stat.size, + })); } } @@ -441,7 +422,7 @@ class DialogEntryRenderer implements ITreeRenderer, index: number, templateData: DialogEntryData): void { + public renderElement(node: ITreeNode, _index: number, templateData: DialogEntryData): void { templateData.icon.className = "dialog-entry-icon monaco-icon-label"; const classes = getIconClasses( workbench.serviceCollection.get(IModelService) as IModelService, @@ -465,7 +446,7 @@ class DialogEntryRenderer implements ITreeRenderer { - ae.preserveEnv(options); - - const ptyProc = ae.modules.pty.spawn(file, args, options); - - let process = ptyProc.process; - ae.emit("process", process); - ae.emit("pid", ptyProc.pid); - - const timer = setInterval(() => { - if (ptyProc.process !== process) { - process = ptyProc.process; - ae.emit("process", process); - } - }, 200); - - ptyProc.on("exit", (code, signal) => { - clearTimeout(timer); - ae.emit("exit", code, signal); - }); - - ptyProc.on("data", (data) => ae.emit("data", data)); - - ae.on("resize", (cols: number, rows: number) => ptyProc.resize(cols, rows)); - ae.on("write", (data: string) => ptyProc.write(data)); - ae.on("kill", (signal: string) => ptyProc.kill(signal)); - - return { - onDidDispose: (cb): void => ptyProc.on("exit", cb), - dispose: (): void => { - ptyProc.kill(); - setTimeout(() => ptyProc.kill("SIGKILL"), 5000); // Double tap. - }, - }; - }, file, args, options); - - this.ae.on("error", (error) => logger.error(error.message)); - - this.ae.on("pid", (pid) => this._pid = pid); - this.ae.on("process", (process) => this._process = process); - - this.ae.on("exit", (code, signal) => this.emitter.emit("exit", code, signal)); - this.ae.on("data", (data) => this.emitter.emit("data", data)); - } - - public get pid(): number { - return this._pid; - } - - public get process(): string { - return this._process; - } - - // tslint:disable-next-line no-any - public on(event: string, listener: (...args: any[]) => void): void { - this.emitter.on(event, listener); - } - - public resize(columns: number, rows: number): void { - this.ae.emit("resize", columns, rows); - } - - public write(data: string): void { - this.ae.emit("write", data); - } - - public kill(signal?: string): void { - this.ae.emit("kill", signal); - } -} - -const ptyType: typeof nodePty = { - spawn: (file: string, args: string[] | string, options: nodePty.IPtyForkOptions): nodePty.IPty => { - return new Pty(file, args, options); - }, -}; - -module.exports = ptyType; +export = client.modules[Module.NodePty]; diff --git a/packages/vscode/src/fill/spdlog.ts b/packages/vscode/src/fill/spdlog.ts index d3ec4758..3b98204d 100644 --- a/packages/vscode/src/fill/spdlog.ts +++ b/packages/vscode/src/fill/spdlog.ts @@ -1,63 +1,4 @@ -import { RotatingLogger as NodeRotatingLogger } from "spdlog"; -import { logger } from "@coder/logger"; +import { Module } from "@coder/protocol"; import { client } from "@coder/ide/src/fill/client"; -const ae = client.run((ae) => { - const loggers = new Map(); - - ae.on("new", (id: number, name: string, filePath: string, fileSize: number, fileCount: number) => { - const logger = new ae.modules.spdlog.RotatingLogger(name, filePath, fileSize, fileCount); - loggers.set(id, logger); - }); - - ae.on("clearFormatters", (id: number) => loggers.get(id)!.clearFormatters()); - ae.on("critical", (id: number, message: string) => loggers.get(id)!.critical(message)); - ae.on("debug", (id: number, message: string) => loggers.get(id)!.debug(message)); - ae.on("drop", (id: number) => loggers.get(id)!.drop()); - ae.on("errorLog", (id: number, message: string) => loggers.get(id)!.error(message)); - ae.on("flush", (id: number) => loggers.get(id)!.flush()); - ae.on("info", (id: number, message: string) => loggers.get(id)!.info(message)); - ae.on("setAsyncMode", (bufferSize: number, flushInterval: number) => ae.modules.spdlog.setAsyncMode(bufferSize, flushInterval)); - ae.on("setLevel", (id: number, level: number) => loggers.get(id)!.setLevel(level)); - ae.on("trace", (id: number, message: string) => loggers.get(id)!.trace(message)); - ae.on("warn", (id: number, message: string) => loggers.get(id)!.warn(message)); - - const disposeCallbacks = void>>[]; - - return { - onDidDispose: (cb): number => disposeCallbacks.push(cb), - dispose: (): void => { - loggers.forEach((logger) => logger.flush()); - loggers.clear(); - disposeCallbacks.forEach((cb) => cb()); - }, - }; -}); - -const spdLogger = logger.named("spdlog"); -ae.on("close", () => spdLogger.error("session closed prematurely")); -ae.on("error", (error: Error) => spdLogger.error(error.message)); - -let id = 0; -export class RotatingLogger implements NodeRotatingLogger { - private readonly id = id++; - - public constructor(name: string, filePath: string, fileSize: number, fileCount: number) { - ae.emit("new", this.id, name, filePath, fileSize, fileCount); - } - - public trace(message: string): void { ae.emit("trace", this.id, message); } - public debug(message: string): void { ae.emit("debug", this.id, message); } - public info(message: string): void { ae.emit("info", this.id, message); } - public warn(message: string): void { ae.emit("warn", this.id, message); } - public error(message: string): void { ae.emit("errorLog", this.id, message); } - public critical(message: string): void { ae.emit("critical", this.id, message); } - public setLevel(level: number): void { ae.emit("setLevel", this.id, level); } - public clearFormatters(): void { ae.emit("clearFormatters", this.id); } - public flush(): void { ae.emit("flush", this.id); } - public drop(): void { ae.emit("drop", this.id); } -} - -export const setAsyncMode = (bufferSize: number, flushInterval: number): void => { - ae.emit("setAsyncMode", bufferSize, flushInterval); -}; +export = client.modules[Module.Spdlog]; diff --git a/packages/vscode/src/workbench.ts b/packages/vscode/src/workbench.ts index 5343995c..4e023ed1 100644 --- a/packages/vscode/src/workbench.ts +++ b/packages/vscode/src/workbench.ts @@ -202,6 +202,8 @@ export class Workbench { /** * Resolves the error of the workspace identifier being invalid. */ + // tslint:disable-next-line:no-console + console.error(ex); this.workspace = undefined; location.reload(); diff --git a/packages/vscode/yarn.lock b/packages/vscode/yarn.lock index ef3efe40..635b9297 100644 --- a/packages/vscode/yarn.lock +++ b/packages/vscode/yarn.lock @@ -34,11 +34,6 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -bindings@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5" - integrity sha512-i47mqjF9UbjxJhxGf+pZ6kSxrnI3wBLlnGI2ArWJ4r0VrvDS7ZYXkprq/pLaBWYq4GM0r4zdHY+NNRqEMU7uew== - bl@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88" @@ -114,24 +109,12 @@ lru-cache@^4.1.1: pseudomap "^1.0.2" yallist "^2.1.2" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -nan@^2.10.0, nan@^2.8.0: +nan@^2.10.0: version "2.12.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== @@ -194,15 +177,6 @@ schema-utils@^0.4.5: ajv "^6.1.0" ajv-keywords "^3.1.0" -spdlog@^0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.7.2.tgz#9298753d7694b9ee9bbfd7e01ea1e4c6ace1e64d" - integrity sha512-rHfWCaWMD4NindDnql6rc6kn7Bs8JR92jhiUpCl3D6v+jYcQ6GozMLig0RliOOR8st5mU+IHLZnr15fBys5x/Q== - dependencies: - bindings "^1.3.0" - mkdirp "^0.5.1" - nan "^2.8.0" - string-replace-loader@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-replace-loader/-/string-replace-loader-2.1.1.tgz#b72e7b57b6ef04efe615aff0ad989b5c14ca63d1" diff --git a/packages/web/webpack.config.js b/packages/web/webpack.config.js index 8c0316ac..a55d5314 100644 --- a/packages/web/webpack.config.js +++ b/packages/web/webpack.config.js @@ -12,7 +12,6 @@ module.exports = merge( typescriptCompilerOptions: { "target": "es5", "lib": ["dom", "esnext"], - "importHelpers": true, }, }, ), { @@ -58,6 +57,7 @@ module.exports = merge( "fs": path.join(fills, "fs.ts"), "net": path.join(fills, "net.ts"), "util": path.join(fills, "util.ts"), + "trash": path.join(fills, "trash.ts"), "electron": path.join(fills, "electron.ts"), "native-keymap": path.join(vsFills, "native-keymap.ts"), diff --git a/scripts/test-setup.js b/scripts/test-setup.js index a571d84d..cdbef08e 100644 --- a/scripts/test-setup.js +++ b/scripts/test-setup.js @@ -1,3 +1,23 @@ +const fs = require("fs"); +const util = require("util"); + +// This isn't properly promisified in Jest. +Object.defineProperty(fs.read, util.promisify.custom, { + configurable: true, + value: (...args) => { + return new Promise((resolve, reject) => { + args.push((error, bytesRead, buffer) => { + if (error) { + reject(error); + } else { + resolve({ bytesRead, buffer }); + } + }); + fs.read(...args); + }); + }, +}); + global.requestAnimationFrame = (cb) => { setTimeout(cb, 0); }; diff --git a/scripts/vscode.patch b/scripts/vscode.patch index 3c256c4b..7b14fc7c 100644 --- a/scripts/vscode.patch +++ b/scripts/vscode.patch @@ -154,12 +154,21 @@ index 25de96d..66e732e 100644 + +startup({ machineId: "1" }); diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts -index f4a579b..7f57220 100644 +index f4a579b..aa3c6d9 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts -@@ -353 +353 @@ export class Configuration extends CommonEditorConfiguration { +@@ -10 +9,0 @@ import { Disposable } from 'vs/base/common/lifecycle'; +-import * as platform from 'vs/base/common/platform'; +@@ -17 +15,0 @@ import { IDimension } from 'vs/editor/common/editorCommon'; +-import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +@@ -18,0 +17 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib ++import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +@@ -353 +352 @@ export class Configuration extends CommonEditorConfiguration { - if (platform.isMacintosh) { + if (browser.isMacintosh) { +@@ -364 +363 @@ export class Configuration extends CommonEditorConfiguration { +- emptySelectionClipboard: browser.isWebKit || browser.isFirefox, ++ emptySelectionClipboard: false, // browser.isWebKit || browser.isFirefox, diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 1a8af35..fe56af9 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts @@ -189,11 +198,14 @@ index fa004fb..6420078 100644 - 'included': platform.isMacintosh + 'included': platform.isNative && platform.isMacintosh diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts -index 934e908..b404444 100644 +index 934e908..bd6fd88 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts -@@ -9,0 +10 @@ import * as platform from 'vs/base/common/platform'; +@@ -6 +6 @@ +-import * as nls from 'vs/nls'; +import * as browser from 'vs/base/browser/browser'; +@@ -13,0 +14 @@ import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper'; ++import * as nls from 'vs/nls'; @@ -1765 +1766 @@ export class EditorOptionsValidator { - configuredMulticursorModifier = platform.isMacintosh ? 'metaKey' : 'ctrlKey'; + configuredMulticursorModifier = browser.isMacintosh ? 'metaKey' : 'ctrlKey'; @@ -203,6 +215,9 @@ index 934e908..b404444 100644 @@ -2534 +2535 @@ export const EDITOR_FONT_DEFAULTS = { - platform.isMacintosh ? 12 : 14 + browser.isMacintosh ? 12 : 14 +@@ -2640 +2641 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = { +- selectionClipboard: true, ++ selectionClipboard: false, diff --git a/src/vs/editor/common/config/fontInfo.ts b/src/vs/editor/common/config/fontInfo.ts index 88cb52a..c4a1be9 100644 --- a/src/vs/editor/common/config/fontInfo.ts diff --git a/tsconfig.json b/tsconfig.json index a71c2bc1..307ba119 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "strict": true, "resolveJsonModule": true, "experimentalDecorators": true, + "importHelpers": true, "plugins": [ { "name": "tslint-language-service" @@ -22,6 +23,9 @@ ], "vs/*": [ "./lib/vscode/src/vs/*" + ], + "node-pty": [ + "./packages/protocol/node_modules/node-pty-prebuilt" ] } } diff --git a/yarn.lock b/yarn.lock index 0f23529b..8edb5418 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5076,7 +5076,7 @@ tsconfig-paths@^3.8.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== @@ -5284,6 +5284,13 @@ util@^0.10.3: dependencies: inherits "2.0.3" +util@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + utila@^0.4.0, utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"