Getting the client to run (#12)
* Clean up workbench and integrate initialization data * Uncomment Electron fill * Run server & client together * Clean up Electron fill & patch * Bind fs methods This makes them usable with the promise form: `promisify(access)(...)`. * Add space between tag and title to browser logger * Add typescript dep to server and default __dirname for path * Serve web files from server * Adjust some dev options * Rework workbench a bit to use a class and catch unexpected errors * No mkdirs for now, fix util fill, use bash with exec * More fills, make general client abstract * More fills * Fix cp.exec * Fix require calls in fs fill being aliased * Create data and storage dir * Implement fs.watch Using exec for now. * Implement storage database fill * Fix os export and homedir * Add comment to use navigator.sendBeacon * Fix fs callbacks (some args are optional) * Make sure data directory exists when passing it back * Update patch * Target es5 * More fills * Add APIs required for bootstrap-fork to function (#15) * Add bootstrap-fork execution * Add createConnection * Bundle bootstrap-fork into cli * Remove .node directory created from spdlog * Fix npm start * Remove unnecessary comment * Add webpack-hot-middleware if CLI env is not set * Add restarting to shared process * Fix starting with yarn
This commit is contained in:
1
packages/server/.gitignore
vendored
1
packages/server/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
out
|
||||
cli*
|
||||
build
|
||||
|
||||
# This file is generated when the binary is created.
|
||||
# We want to use the parent tsconfig so we can ignore it.
|
||||
|
@ -4,10 +4,12 @@
|
||||
"bin": "./out/cli.js",
|
||||
"files": [],
|
||||
"scripts": {
|
||||
"start": "ts-node -r tsconfig-paths/register src/cli.ts",
|
||||
"build:webpack": "rm -rf ./out && ../../node_modules/.bin/webpack --config ./webpack.config.js",
|
||||
"start": "NODE_ENV=development ts-node -r tsconfig-paths/register src/cli.ts",
|
||||
"build:webpack": "rm -rf ./out && export CLI=true && ../../node_modules/.bin/webpack --config ./webpack.config.js",
|
||||
"build:nexe": "node scripts/nexe.js",
|
||||
"build": "npm run build:webpack && npm run build:nexe"
|
||||
"build:bootstrap-fork": "cd ../vscode && npm run build:bootstrap-fork; cp ./bin/bootstrap-fork.js ../server/build/bootstrap-fork.js",
|
||||
"build:default-extensions": "cd ../../lib/vscode && npx gulp vscode-linux-arm && cd ../.. && cp -r ./lib/VSCode-linux-arm/resources/app/extensions/* ./packages/server/build/extensions/",
|
||||
"build": "npm run build:bootstrap-fork && npm run build:webpack && npm run build:nexe"
|
||||
},
|
||||
"dependencies": {
|
||||
"@oclif/config": "^1.10.4",
|
||||
@ -16,6 +18,7 @@
|
||||
"express": "^4.16.4",
|
||||
"nexe": "^2.0.0-rc.34",
|
||||
"node-pty": "^0.8.0",
|
||||
"spdlog": "^0.7.2",
|
||||
"ws": "^6.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -23,6 +26,7 @@
|
||||
"@types/ws": "^6.0.1",
|
||||
"string-replace-webpack-plugin": "^0.1.3",
|
||||
"ts-node": "^7.0.1",
|
||||
"tsconfig-paths": "^3.7.0"
|
||||
"tsconfig-paths": "^3.7.0",
|
||||
"typescript": "^3.2.2"
|
||||
}
|
||||
}
|
||||
|
@ -28,14 +28,22 @@ nexe.compile({
|
||||
additionalFiles: [
|
||||
'./node_modules/node-pty/build/Release/pty',
|
||||
],
|
||||
}
|
||||
},
|
||||
"spdlog": {
|
||||
additionalFiles: [
|
||||
'spdlog.node',
|
||||
],
|
||||
},
|
||||
},
|
||||
targets: ["linux"],
|
||||
/**
|
||||
* 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")],
|
||||
resources: [
|
||||
path.join(__dirname, "../package.json"),
|
||||
path.join(__dirname, "../build/**"),
|
||||
],
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { SharedProcessInitMessage } from "@coder/protocol/src/proto";
|
||||
import { Command, flags } from "@oclif/command";
|
||||
import { logger, field } from "@coder/logger";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import { createApp } from './server';
|
||||
import { requireModule } from "./vscode/bootstrapFork";
|
||||
import { createApp } from "./server";
|
||||
import { SharedProcess } from './vscode/sharedProcess';
|
||||
|
||||
export class Entry extends Command {
|
||||
|
||||
@ -17,23 +20,65 @@ export class Entry extends Command {
|
||||
open: flags.boolean({ char: "o", description: "Open in browser on startup" }),
|
||||
port: flags.integer({ char: "p", default: 8080, description: "Port to bind on" }),
|
||||
version: flags.version({ char: "v" }),
|
||||
|
||||
// Dev flags
|
||||
"bootstrap-fork": flags.string({ hidden: true }),
|
||||
};
|
||||
public static args = [{
|
||||
name: "workdir",
|
||||
description: "Specify working dir",
|
||||
default: () => process.cwd(),
|
||||
default: (): string => process.cwd(),
|
||||
}];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
try {
|
||||
/**
|
||||
* Suuuper janky
|
||||
* Comes from - https://github.com/nexe/nexe/issues/524
|
||||
* Seems to cleanup by removing this path immediately
|
||||
* If any native module is added its assumed this pathname
|
||||
* will change.
|
||||
*/
|
||||
require("spdlog");
|
||||
const nodePath = path.join(process.cwd(), "e91a410b");
|
||||
fs.unlinkSync(path.join(nodePath, "spdlog.node"));
|
||||
fs.rmdirSync(nodePath);
|
||||
} catch (ex) {
|
||||
logger.warn("Failed to remove extracted dependency.", field("dependency", "spdlog"), field("error", ex.message));
|
||||
}
|
||||
|
||||
const { args, flags } = this.parse(Entry);
|
||||
|
||||
const dataDir = flags["data-dir"] || path.join(os.homedir(), `.vscode-online`);
|
||||
if (flags["bootstrap-fork"]) {
|
||||
const modulePath = flags["bootstrap-fork"];
|
||||
if (!modulePath) {
|
||||
logger.error("No module path specified to fork!");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
requireModule(modulePath);
|
||||
return;
|
||||
}
|
||||
|
||||
const dataDir = flags["data-dir"] || path.join(os.homedir(), ".vscode-online");
|
||||
const workingDir = args["workdir"];
|
||||
|
||||
logger.info("\u001B[1mvscode-remote v1.0.0");
|
||||
// TODO: fill in appropriate doc url
|
||||
logger.info("Additional documentation: https://coder.com/docs");
|
||||
logger.info("Initializing", field("data-dir", dataDir), field("working-dir", workingDir));
|
||||
const sharedProcess = new SharedProcess(dataDir);
|
||||
logger.info("Starting shared process...", field("socket", sharedProcess.socketPath));
|
||||
sharedProcess.onWillRestart(() => {
|
||||
logger.info("Restarting shared process...");
|
||||
|
||||
sharedProcess.ready.then(() => {
|
||||
logger.info("Shared process has restarted!");
|
||||
});
|
||||
});
|
||||
sharedProcess.ready.then(() => {
|
||||
logger.info("Shared process has started up!");
|
||||
});
|
||||
|
||||
const app = createApp((app) => {
|
||||
app.use((req, res, next) => {
|
||||
@ -43,17 +88,33 @@ export class Entry extends Command {
|
||||
|
||||
next();
|
||||
});
|
||||
if (process.env.CLI === "false" || !process.env.CLI) {
|
||||
const webpackConfig = require(path.join(__dirname, "..", "..", "web", "webpack.dev.config.js"));
|
||||
const compiler = require("webpack")(webpackConfig);
|
||||
app.use(require("webpack-dev-middleware")(compiler, {
|
||||
logger,
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
stats: webpackConfig.stats,
|
||||
}));
|
||||
app.use(require("webpack-hot-middleware")(compiler));
|
||||
}
|
||||
}, {
|
||||
dataDirectory: dataDir,
|
||||
workingDirectory: workingDir,
|
||||
});
|
||||
dataDirectory: dataDir,
|
||||
workingDirectory: workingDir,
|
||||
});
|
||||
|
||||
logger.info("Starting webserver...", field("host", flags.host), field("port", flags.port))
|
||||
logger.info("Starting webserver...", field("host", flags.host), field("port", flags.port));
|
||||
app.server.listen(flags.port, flags.host);
|
||||
let clientId = 1;
|
||||
app.wss.on("connection", (ws, req) => {
|
||||
const id = clientId++;
|
||||
logger.info(`WebSocket opened \u001B[0m${req.url}`, field("client", id), field("ip", req.socket.remoteAddress));
|
||||
const spm = (<any>req).sharedProcessInit as SharedProcessInitMessage;
|
||||
if (!spm) {
|
||||
logger.warn("Received a socket without init data. Not sure how this happened.");
|
||||
|
||||
return;
|
||||
}
|
||||
logger.info(`WebSocket opened \u001B[0m${req.url}`, field("client", id), field("ip", req.socket.remoteAddress), field("window_id", spm.getWindowId()), field("log_directory", spm.getLogDirectory()));
|
||||
|
||||
ws.on("close", (code) => {
|
||||
logger.info(`WebSocket closed \u001B[0m${req.url}`, field("client", id), field("code", code));
|
||||
@ -73,9 +134,10 @@ export class Entry extends Command {
|
||||
logger.info(`http://localhost:${flags.port}/`);
|
||||
logger.info(" ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Entry.run(undefined, {
|
||||
root: process.env.BUILD_DIR as string,
|
||||
root: process.env.BUILD_DIR as string || __dirname,
|
||||
//@ts-ignore
|
||||
}).catch(require("@oclif/errors/handle"));
|
||||
|
70
packages/server/src/ipc.ts
Normal file
70
packages/server/src/ipc.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { EventEmitter } from "events";
|
||||
import { ChildProcess } from "child_process";
|
||||
|
||||
export interface IpcMessage {
|
||||
readonly event: string;
|
||||
readonly args: any[];
|
||||
}
|
||||
|
||||
export class StdioIpcHandler extends EventEmitter {
|
||||
|
||||
private isListening: boolean = false;
|
||||
|
||||
public constructor(
|
||||
private readonly childProcess?: ChildProcess,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public on(event: string, cb: (...args: any[]) => void): this {
|
||||
this.listen();
|
||||
return super.on(event, cb);
|
||||
}
|
||||
|
||||
public once(event: string, cb: (...args: any[]) => void): this {
|
||||
this.listen();
|
||||
return super.once(event, cb);
|
||||
}
|
||||
|
||||
public addListener(event: string, cb: (...args: any[]) => void): this {
|
||||
this.listen();
|
||||
return super.addListener(event, cb);
|
||||
}
|
||||
|
||||
public send(event: string, ...args: any[]): void {
|
||||
const msg: IpcMessage = {
|
||||
event,
|
||||
args,
|
||||
};
|
||||
const d = JSON.stringify(msg);
|
||||
if (this.childProcess) {
|
||||
this.childProcess.stdin.write(d + "\n");
|
||||
} else {
|
||||
process.stdout.write(d);
|
||||
}
|
||||
}
|
||||
|
||||
private listen(): void {
|
||||
if (this.isListening) {
|
||||
return;
|
||||
}
|
||||
const onData = (data: any) => {
|
||||
try {
|
||||
const d = JSON.parse(data.toString()) as IpcMessage;
|
||||
this.emit(d.event, ...d.args);
|
||||
} catch (ex) {
|
||||
if (!this.childProcess) {
|
||||
process.stderr.write(`Failed to parse incoming data: ${ex.message}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (this.childProcess) {
|
||||
this.childProcess.stdout.resume();
|
||||
this.childProcess.stdout.on("data", onData);
|
||||
} else {
|
||||
process.stdin.resume();
|
||||
process.stdin.on("data", onData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -3,34 +3,67 @@ import { Server, ServerOptions } from "@coder/protocol/src/node/server";
|
||||
import * as express from "express";
|
||||
import * as http from "http";
|
||||
import * as ws from "ws";
|
||||
import * as url from "url";
|
||||
import { ClientMessage, SharedProcessInitMessage } from '@coder/protocol/src/proto';
|
||||
|
||||
export const createApp = (registerMiddleware?: (app: express.Application) => void, options?: ServerOptions): {
|
||||
readonly express: express.Application;
|
||||
readonly server: http.Server;
|
||||
readonly wss: ws.Server;
|
||||
} => {
|
||||
} => {
|
||||
const app = express();
|
||||
if (registerMiddleware) {
|
||||
registerMiddleware(app);
|
||||
}
|
||||
const server = http.createServer(app);
|
||||
const wss = new ws.Server({ server });
|
||||
|
||||
wss.on("connection", (ws: WebSocket) => {
|
||||
|
||||
wss.shouldHandle = (req): boolean => {
|
||||
if (typeof req.url === "undefined") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parsedUrl = url.parse(req.url, true);
|
||||
const sharedProcessInit = parsedUrl.query["shared_process_init"];
|
||||
if (typeof sharedProcessInit === "undefined" || Array.isArray(sharedProcessInit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const msg = ClientMessage.deserializeBinary(Buffer.from(sharedProcessInit, "base64"));
|
||||
if (!msg.hasSharedProcessInit()) {
|
||||
return false;
|
||||
}
|
||||
const spm = msg.getSharedProcessInit()!;
|
||||
(<any>req).sharedProcessInit = spm;
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
wss.on("connection", (ws: WebSocket, req) => {
|
||||
const spm = (<any>req).sharedProcessInit as SharedProcessInitMessage;
|
||||
if (!spm) {
|
||||
ws.close();
|
||||
return;
|
||||
}
|
||||
|
||||
const connection: ReadWriteConnection = {
|
||||
onMessage: (cb) => {
|
||||
onMessage: (cb): void => {
|
||||
ws.addEventListener("message", (event) => cb(event.data));
|
||||
},
|
||||
close: () => ws.close(),
|
||||
send: (data) => ws.send(data),
|
||||
onClose: (cb) => ws.addEventListener("close", () => cb()),
|
||||
close: (): void => ws.close(),
|
||||
send: (data): void => ws.send(data),
|
||||
onClose: (cb): void => ws.addEventListener("close", () => cb()),
|
||||
};
|
||||
|
||||
|
||||
const server = new Server(connection, options);
|
||||
});
|
||||
|
||||
/**
|
||||
* We should static-serve the `web` package at this point
|
||||
* We should static-serve the `web` package at this point.
|
||||
*/
|
||||
app.get("/", (req, res, next) => {
|
||||
res.write("Example! :)");
|
||||
|
29
packages/server/src/vscode/bootstrapFork.ts
Normal file
29
packages/server/src/vscode/bootstrapFork.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import * as cp from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
declare var __non_webpack_require__: typeof require;
|
||||
|
||||
export const requireModule = (modulePath: string): void => {
|
||||
process.env.AMD_ENTRYPOINT = modulePath;
|
||||
process.env.VSCODE_ALLOW_IO = "true";
|
||||
const content = fs.readFileSync(path.join(process.env.BUILD_DIR as string || path.join(__dirname, "../.."), "./build/bootstrap-fork.js"));
|
||||
eval(content.toString());
|
||||
};
|
||||
|
||||
/**
|
||||
* Uses the internal bootstrap-fork.js to load a module
|
||||
* @example
|
||||
* const cp = forkModule("vs/code/electron-browser/sharedProcess/sharedProcessMain");
|
||||
* cp.stdout.on("data", (data) => console.log(data.toString("utf8")));
|
||||
* cp.stderr.on("data", (data) => console.log(data.toString("utf8")));
|
||||
* @param modulePath
|
||||
*/
|
||||
export const forkModule = (modulePath: string): cp.ChildProcess => {
|
||||
const args = ["--bootstrap-fork", modulePath];
|
||||
if (process.env.CLI === "true") {
|
||||
return cp.spawn(process.execPath, args);
|
||||
} else {
|
||||
return cp.spawn("npm", ["start", "--scripts-prepend-node-path", "--", ...args]);
|
||||
}
|
||||
};
|
106
packages/server/src/vscode/sharedProcess.ts
Normal file
106
packages/server/src/vscode/sharedProcess.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { ChildProcess } from "child_process";
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
import { forkModule } from "./bootstrapFork";
|
||||
import { StdioIpcHandler } from "../ipc";
|
||||
import { logger, field } from "@coder/logger/src";
|
||||
import { ParsedArgs } from "vs/platform/environment/common/environment";
|
||||
import { LogLevel } from "vs/platform/log/common/log";
|
||||
import { Emitter, Event } from '@coder/events/src';
|
||||
|
||||
export class SharedProcess {
|
||||
public readonly socketPath: string = path.join(os.tmpdir(), `.vscode-online${Math.random().toString()}`);
|
||||
private _ready: Promise<void> | undefined;
|
||||
private activeProcess: ChildProcess | undefined;
|
||||
private ipcHandler: StdioIpcHandler | undefined;
|
||||
private readonly willRestartEmitter: Emitter<void>;
|
||||
|
||||
public constructor(
|
||||
private readonly userDataDir: string,
|
||||
) {
|
||||
this.willRestartEmitter = new Emitter();
|
||||
|
||||
this.restart();
|
||||
}
|
||||
|
||||
public get onWillRestart(): Event<void> {
|
||||
return this.willRestartEmitter.event;
|
||||
}
|
||||
|
||||
public get ready(): Promise<void> {
|
||||
return this._ready!;
|
||||
}
|
||||
|
||||
public restart(): void {
|
||||
if (this.activeProcess) {
|
||||
this.willRestartEmitter.emit();
|
||||
}
|
||||
|
||||
if (this.activeProcess && !this.activeProcess.killed) {
|
||||
this.activeProcess.kill();
|
||||
}
|
||||
|
||||
let resolve: () => void;
|
||||
let reject: (err: Error) => void;
|
||||
|
||||
const extensionsDir = path.join(this.userDataDir, "extensions");
|
||||
const mkdir = (dir: string): void => {
|
||||
try {
|
||||
fs.mkdirSync(dir);
|
||||
} catch (ex) {
|
||||
if (ex.code !== "EEXIST") {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
};
|
||||
mkdir(this.userDataDir);
|
||||
mkdir(extensionsDir);
|
||||
|
||||
this._ready = new Promise<void>((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
|
||||
let resolved: boolean = false;
|
||||
this.activeProcess = forkModule("vs/code/electron-browser/sharedProcess/sharedProcessMain");
|
||||
this.activeProcess.on("exit", () => {
|
||||
this.restart();
|
||||
});
|
||||
this.ipcHandler = new StdioIpcHandler(this.activeProcess);
|
||||
this.ipcHandler.once("handshake:hello", () => {
|
||||
const data: {
|
||||
sharedIPCHandle: string;
|
||||
args: ParsedArgs;
|
||||
logLevel: LogLevel;
|
||||
} = {
|
||||
args: {
|
||||
"builtin-extensions-dir": path.join(process.env.BUILD_DIR || path.join(__dirname, "../.."), "build/extensions"),
|
||||
"user-data-dir": this.userDataDir,
|
||||
"extensions-dir": extensionsDir,
|
||||
} as any,
|
||||
logLevel: 0,
|
||||
sharedIPCHandle: this.socketPath,
|
||||
};
|
||||
this.ipcHandler!.send("handshake:hey there", "", data);
|
||||
});
|
||||
this.ipcHandler.once("handshake:im ready", () => {
|
||||
resolved = true;
|
||||
resolve();
|
||||
});
|
||||
this.activeProcess.stderr.on("data", (data) => {
|
||||
if (!resolved) {
|
||||
reject(data.toString());
|
||||
} else {
|
||||
logger.named("SHRD PROC").debug("stderr", field("message", data.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.ipcHandler) {
|
||||
this.ipcHandler.send("handshake:goodbye");
|
||||
}
|
||||
this.ipcHandler = undefined;
|
||||
}
|
||||
}
|
@ -2,9 +2,10 @@ const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
const merge = require("webpack-merge");
|
||||
const StringReplacePlugin = require("string-replace-webpack-plugin");
|
||||
const HappyPack = require("happypack");
|
||||
|
||||
module.exports = merge({
|
||||
devtool: 'none',
|
||||
devtool: "none",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@ -35,14 +36,15 @@ module.exports = merge({
|
||||
__dirname: false,
|
||||
setImmediate: false
|
||||
},
|
||||
externals: ["node-pty"],
|
||||
externals: ["node-pty", "spdlog"],
|
||||
entry: "./packages/server/src/cli.ts",
|
||||
target: "node",
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.BUILD_DIR": `"${__dirname}"`,
|
||||
"process.env.CLI": `"${process.env.CLI ? "true" : "false"}"`,
|
||||
}),
|
||||
],
|
||||
}, require("../../scripts/webpack.general.config"), {
|
||||
}, require("../../scripts/webpack.general.config")(), {
|
||||
mode: "development",
|
||||
});
|
||||
|
@ -418,6 +418,11 @@ binary-extensions@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14"
|
||||
integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==
|
||||
|
||||
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@^1.0.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
|
||||
@ -1386,9 +1391,9 @@ fs.realpath@^1.0.0:
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
fsevents@^1.0.0:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
|
||||
integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==
|
||||
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"
|
||||
@ -2152,9 +2157,9 @@ map-visit@^1.0.0:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
math-random@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.3.tgz#5843d8307f8d2fd83de240701eeb2dc7bc77a104"
|
||||
integrity sha512-hULdrPg17lCyaJOrDwS4RSGQcc/MFyv1aujidohCsBq2zotkhIns8mMDQ7B8VnKG23xcpa+haU5MLDNyNzCesQ==
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"
|
||||
integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
|
||||
|
||||
media-typer@0.3.0:
|
||||
version "0.3.0"
|
||||
@ -2313,7 +2318,7 @@ nan@2.10.0:
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
|
||||
integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==
|
||||
|
||||
nan@^2.9.2:
|
||||
nan@^2.8.0, 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==
|
||||
@ -3169,6 +3174,15 @@ source-map@~0.1.38:
|
||||
dependencies:
|
||||
amdefine ">=0.0.4"
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
@ -3464,6 +3478,11 @@ typescript@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"
|
||||
|
Reference in New Issue
Block a user