Featureful (#31)

* Fix loading within the CLI

* Remove app

* Remove promise handle

* Add initial travis file

* Add libxkbfile dependency

* Add libxkbfile-dev

* Add build script

* Fix malformed bash statement

* Remove yarn from script

* Improve build script

* Extract upx before usage

* Only run upx if on linux

* Ensure resource directory exists

* Pack runnable binary

* Export binary with platform

* Improve build process

* Install upx before running install script

* Update typescript version before running nexe

* Add os.release() function for multi-platform support

* Update travis.yml to improve deployment

* Add on CI

* Update to v1.31.0

* Add libsecret

* Update build target

* Skip cleanup

* Fix built-in extensions

* Add basics for apps

* Create custom DNS server

* Fix forking within CLI. Fixes TS language features

* Fix filename resolve

* Fix default extensions path

* Add custom dialog

* Store workspace path

* Remove outfiles

* Cleanup

* Always authed outside of CLI

* Use location.host for client

* Remove useless app interface

* Remove debug file for building wordlist

* Use chromes tcp host

* Update patch

* Build browser app before packaging

* Replace all css containing file:// URLs, fix webviews

* Fix save

* Fix mkdir
This commit is contained in:
Kyle Carberry 2019-02-21 11:55:42 -06:00 committed by Asher
parent bdd24081ab
commit 85d2225e0c
84 changed files with 5204 additions and 264 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
lib
node_modules
dist
out

23
.travis.yml Normal file
View File

@ -0,0 +1,23 @@
language: node_js
node_js:
- 8.9.3
matrix:
include:
- os: linux
dist: ubuntu
- os: osx
- os: windows
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libxkbfile-dev libsecret-1-dev;
fi
script:
- scripts/build.sh
deploy:
provider: releases
skip_cleanup: true
api_key:
secure: T/yqCIeqLifteriv8D3CnehNFzSBP309GZqeUfyx8Q+xSQEttA9Enxl+Qw9GkdedYTN4J56iucHIac6CwcvKSKIXqk80CeSEW0BNxZs5wIgv4rRMMy/GAX0NBWKNOkoGlH8M6VyQcM7eY2iGAn1EX755PHalk6rWwfsauRANOQyb2DXQBan5C0YUnogq2qcW1xkIwlXH7l0Ekbtego0f6QPv0rSyOcL1LKm6xk0Aq+xLNKJkT6TSL6xYpkPlZLjnql09Nspkqs6NehWlft2n09bHqAtjNnWw9OYCvxp8mdHeTE5uShuEqYPzdYU5LVFoE7wElI8uqS66noaA18ytZYGw2IrY6GZcn+wtR6WyM2+YXl2HclL1/Fs6Vn8+zwq2IBZchBNv3KJSn1dxiqLlD/s6YQyni17x/9FhtFoNUvsbY5zSC1xrnNQBQWFg0TRnoC9rPR+7hQtT1+5+CvRxpvcNWnPuA22919PFE79ejJulPmsnyF+YLs9c6APJgOpOO1f6fKt5Mcb02dubPqGcQ9NbqUUNTl4IUvEtjG0LnFAgEGerxAcsdnUTxzBVf0LJLlhRKW1BigUTbRwfUJL1DN0mWg9cg7fL5VqrogvNq3uRguxOsYr+bcHDbimQSAY3No3fAkTTqQSJh56Dx57/Un18KxuOTiRB9de1RtiudsI=
file: packages/server/cli-$TRAVIS_OS_NAME
on:
repo: codercom/vscode-online
all_branches: true

195
build/tasks.ts Normal file
View File

@ -0,0 +1,195 @@
import { register, run } from "@coder/runner";
import * as fs from "fs";
import * as fse from "fs-extra";
import * as path from "path";
import * as zlib from "zlib";
const libPath = path.join(__dirname, "../lib");
const vscodePath = path.join(libPath, "vscode");
const pkgsPath = path.join(__dirname, "../packages");
const defaultExtensionsPath = path.join(libPath, "VSCode-linux-x64/resources/app/extensions");
const buildServerBinary = register("build:server:binary", async (runner) => {
await ensureInstalled();
await copyForDefaultExtensions();
await Promise.all([
buildBootstrapFork(),
buildWeb(),
buildDefaultExtensions(),
buildServerBundle(),
buildAppBrowser(),
]);
await buildServerBinaryPackage();
});
const buildServerBinaryPackage = register("build:server:binary:package", async (runner) => {
const cliPath = path.join(pkgsPath, "server");
runner.cwd = cliPath;
if (!fs.existsSync(path.join(cliPath, "out"))) {
throw new Error("Cannot build binary without web bundle built");
}
await buildServerBinaryCopy();
const resp = await runner.execute("npm", ["run", "build:nexe"]);
if (resp.exitCode !== 0) {
throw new Error(`Failed to package binary: ${resp.stderr}`);
}
});
const buildServerBinaryCopy = register("build:server:binary:copy", async (runner) => {
const cliPath = path.join(pkgsPath, "server");
const cliBuildPath = path.join(cliPath, "build");
fse.removeSync(cliBuildPath);
fse.mkdirpSync(path.join(cliBuildPath, "extensions"));
const bootstrapForkPath = path.join(pkgsPath, "vscode", "bin", "bootstrap-fork.js");
const webOutputPath = path.join(pkgsPath, "web", "out");
const browserAppOutputPath = path.join(pkgsPath, "app", "browser", "out");
const nodePtyModule = path.join(pkgsPath, "protocol", "node_modules", "node-pty", "build", "Release", "pty.node");
if (!fs.existsSync(nodePtyModule)) {
throw new Error("Could not find pty.node. Ensure all packages have been installed");
}
if (!fs.existsSync(webOutputPath)) {
throw new Error("Web bundle must be built");
}
if (!fs.existsSync(defaultExtensionsPath)) {
throw new Error("Default extensions must be built");
}
if (!fs.existsSync(bootstrapForkPath)) {
throw new Error("Bootstrap fork must exist");
}
fse.copySync(defaultExtensionsPath, path.join(cliBuildPath, "extensions"));
fs.writeFileSync(path.join(cliBuildPath, "bootstrap-fork.js.gz"), zlib.gzipSync(fs.readFileSync(bootstrapForkPath)));
const cpDir = (dir: string, subdir: "auth" | "unauth", rootPath: string): void => {
const stat = fs.statSync(dir);
if (stat.isDirectory()) {
const paths = fs.readdirSync(dir);
paths.forEach((p) => cpDir(path.join(dir, p), subdir, rootPath));
} else if (stat.isFile()) {
const newPath = path.join(cliBuildPath, "web", subdir, path.relative(rootPath, dir));
fse.mkdirpSync(path.dirname(newPath));
fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir)));
} else {
// Nothing
}
};
cpDir(webOutputPath, "auth", webOutputPath);
cpDir(browserAppOutputPath, "unauth", browserAppOutputPath);
fse.mkdirpSync(path.join(cliBuildPath, "modules"));
fse.copySync(nodePtyModule, path.join(cliBuildPath, "modules", "pty.node"));
});
const buildServerBundle = register("build:server:bundle", async (runner) => {
const cliPath = path.join(pkgsPath, "server");
runner.cwd = cliPath;
await runner.execute("npm", ["run", "build:webpack"]);
});
const buildBootstrapFork = register("build:bootstrap-fork", async (runner) => {
await ensureInstalled();
await ensurePatched();
const vscodePkgPath = path.join(pkgsPath, "vscode");
runner.cwd = vscodePkgPath;
await runner.execute("npm", ["run", "build:bootstrap-fork"]);
});
const buildAppBrowser = register("build:app:browser", async (runner) => {
await ensureInstalled();
const appPath = path.join(pkgsPath, "app/browser");
runner.cwd = appPath;
fse.removeSync(path.join(appPath, "out"));
await runner.execute("npm", ["run", "build"]);
});
const buildWeb = register("build:web", async (runner) => {
await ensureInstalled();
await ensurePatched();
const webPath = path.join(pkgsPath, "web");
runner.cwd = webPath;
fse.removeSync(path.join(webPath, "out"));
await runner.execute("npm", ["run", "build"]);
});
const extDirPath = path.join("lib", "vscode-default-extensions");
const copyForDefaultExtensions = register("build:copy-vscode", async (runner) => {
if (!fs.existsSync(defaultExtensionsPath)) {
await ensureClean();
fse.removeSync(extDirPath);
fse.copySync(vscodePath, extDirPath);
}
});
const buildDefaultExtensions = register("build:default-extensions", async (runner) => {
if (!fs.existsSync(defaultExtensionsPath)) {
await copyForDefaultExtensions();
runner.cwd = extDirPath;
const resp = await runner.execute("npx", ["gulp", "vscode-linux-x64"]);
if (resp.exitCode !== 0) {
throw new Error(`Failed to build default extensions: ${resp.stderr}`);
}
}
});
const ensureInstalled = register("vscode:install", async (runner) => {
await ensureCloned();
runner.cwd = vscodePath;
const install = await runner.execute("yarn", []);
if (install.exitCode !== 0) {
throw new Error(`Failed to install vscode dependencies: ${install.stderr}`);
}
});
const ensureCloned = register("vscode:clone", async (runner) => {
if (fs.existsSync(vscodePath)) {
await ensureClean();
} else {
fs.mkdirSync(libPath);
runner.cwd = libPath;
const clone = await runner.execute("git", ["clone", "https://github.com/microsoft/vscode"]);
if (clone.exitCode !== 0) {
throw new Error(`Failed to clone: ${clone.exitCode}`);
}
}
runner.cwd = vscodePath;
const checkout = await runner.execute("git", ["checkout", "tags/1.31.0"]);
if (checkout.exitCode !== 0) {
throw new Error(`Failed to checkout: ${checkout.stderr}`);
}
});
const ensureClean = register("vscode:clean", async (runner) => {
runner.cwd = vscodePath;
const status = await runner.execute("git", ["status", "--porcelain"]);
if (status.stdout.trim() !== "") {
const clean = await runner.execute("git", ["clean", "-f", "-d", "-X"]);
if (clean.exitCode !== 0) {
throw new Error(`Failed to clean git repository: ${clean.stderr}`);
}
const removeUnstaged = await runner.execute("git", ["checkout", "--", "."]);
if (removeUnstaged.exitCode !== 0) {
throw new Error(`Failed to remove unstaged files: ${removeUnstaged.stderr}`);
}
}
});
const ensurePatched = register("vscode:patch", async (runner) => {
if (!fs.existsSync(vscodePath)) {
throw new Error("vscode must be cloned to patch");
}
await ensureClean();
runner.cwd = vscodePath;
const patchPath = path.join(__dirname, "../scripts/vscode.patch");
const apply = await runner.execute("git", ["apply", "--unidiff-zero", patchPath]);
if (apply.exitCode !== 0) {
throw new Error(`Failed to apply patches: ${apply.stderr}`);
}
});
run();

View File

@ -6,21 +6,21 @@
"description": "Run VS Code remotely.",
"scripts": {
"build:rules": "cd ./rules && tsc -p .",
"vscode:clone": "mkdir -p ./lib && test -d ./lib/vscode || git clone https://github.com/Microsoft/vscode/ ./lib/vscode",
"vscode:install": "cd ./lib/vscode && git checkout tags/1.30.1 && yarn",
"vscode": "npm-run-all vscode:*",
"packages:install": "cd ./packages && yarn",
"postinstall": "npm-run-all --parallel vscode packages:install build:rules",
"start": "cd ./packages/server && yarn start",
"postinstall": "npm-run-all --parallel packages:install build:rules",
"start": "cd ./packages/server && yarn start",
"task": "ts-node -r tsconfig-paths/register build/tasks.ts",
"test": "cd ./packages && yarn test"
},
"devDependencies": {
"@types/fs-extra": "^5.0.4",
"@types/node": "^10.12.18",
"@types/trash": "^4.3.1",
"crypto-browserify": "^3.12.0",
"css-loader": "^2.1.0",
"file-loader": "^3.0.1",
"fork-ts-checker-webpack-plugin": "^0.5.2",
"fs-extra": "^7.0.1",
"happypack": "^5.0.1",
"html-webpack-plugin": "^3.2.0",
"http-browserify": "^1.7.0",
@ -35,6 +35,7 @@
"style-loader": "^0.23.1",
"ts-loader": "^5.3.3",
"ts-node": "^7.0.1",
"tsconfig-paths": "^3.8.0",
"tslint": "^5.12.1",
"typescript": "^3.2.2",
"typescript-tslint-plugin": "^0.2.1",

View File

@ -0,0 +1,10 @@
{
"name": "@coder/app",
"scripts": {
"start": "../../../node_modules/.bin/webpack-dev-server --config ./webpack.config.js",
"build": "../../../node_modules/.bin/webpack --config ./webpack.config.js"
},
"dependencies": {
"material-components-web": "^0.44.0"
}
}

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
<title>Coder</title>
</head>
<body>
<div class="login">
<div class="back">
<- Back </div> <h4 class="title">AWS Cloud</h4>
<h2 class="subtitle">
Enter server password
</h2>
<div class="mdc-text-field">
<input type="password" id="password" class="mdc-text-field__input" required>
<label class="mdc-floating-label" for="password">Password</label>
<div class="mdc-line-ripple"></div>
</div>
<div class="mdc-text-field-helper-line">
<div class="mdc-text-field-helper-text">helper text</div>
</div>
<div class="mdc-form-field">
<div class="mdc-checkbox">
<input type="checkbox" class="mdc-checkbox__native-control" id="remember" />
<div class="mdc-checkbox__background">
<svg class="mdc-checkbox__checkmark" viewBox="0 0 24 24">
<path class="mdc-checkbox__checkmark-path" fill="none" d="M1.73,12.91 8.1,19.28 22.79,4.59" />
</svg>
<div class="mdc-checkbox__mixedmark"></div>
</div>
</div>
<label for="remember">Remember Me</label>
</div>
<button id="submit" class="mdc-button mdc-button--unelevated">
<span class="mdc-button__label">Enter IDE</span>
</button>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,108 @@
@import url("https://use.typekit.net/vzk7ygg.css");
html, body {
background-color: #FFFFFF;
min-height: 100%;
}
body {
font-family: 'aktiv-grotesk';
display: flex;
align-items: center;
justify-content: center;
height: calc(100vh - 20px);
margin: 0;
padding: 10px;
--mdc-theme-primary: #AAADA1;
--mdc-theme-secondary: #AAADA1;
&.in-app {
.back {
pointer-events: all;
opacity: 1;
}
}
}
.login {
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
max-width: 328px;
width: 100%;
padding: 40px;
border-radius: 5px;
position: relative;
color: #575962;
.title {
margin-bottom: 0px;
font-size: 12px;
font-weight: 500;
letter-spacing: 1.5px;
line-height: 15px;
margin-bottom: 5px;
margin-top: 0px;
text-align: center;
text-transform: uppercase;
}
.subtitle {
text-align: center;
margin: 0;
font-size: 19px;
font-weight: bold;
line-height: 25px;
margin-bottom: 45px;
}
.mdc-text-field {
width: 100%;
background: none !important;
&::before {
background: none !important;
}
}
.mdc-form-field {
text-align: left;
font-size: 12px;
color: #797E84;
margin-top: 16px;
}
.mdc-button {
border-radius: 24px;
padding-left: 75px;
padding-right: 75px;
padding-top: 15px;
padding-bottom: 15px;
height: 48px;
margin: 0 auto;
display: block;
box-shadow: 0 12px 17px 2px rgba(171,173,163,0.14), 0 5px 22px 4px rgba(171,173,163,0.12), 0 7px 8px -4px rgba(171,173,163,0.2);
margin-top: 40px;
}
}
.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label {
color: var(--mdc-theme-primary);
}
.mdc-floating-label--float-above {
transform: translateY(-70%) scale(0.75);
}
.mdc-text-field:not(.mdc-text-field--disabled):not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mdc-text-field__input, .mdc-text-field:not(.mdc-text-field--disabled):not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mdc-text-field__input:hover {
border-bottom-color: #EBEDF2;
}
.back {
position: absolute;
top: -50px;
left: -50px;
font-weight: bold;
opacity: 0;
pointer-events: none;
// transition: 500ms opacity ease;
}

View File

@ -0,0 +1,30 @@
//@ts-ignore
import { MDCTextField } from "@material/textfield";
//@ts-ignore
import { MDCCheckbox } from "@material/checkbox";
import "material-components-web/dist/material-components-web.css";
import "./app.scss";
document.querySelectorAll(".mdc-text-field").forEach((d) => window["t"] = new MDCTextField(d));
document.querySelectorAll(".mdc-checkbox").forEach((d) => new MDCCheckbox(d));
window.addEventListener("message", (event) => {
if (event.data === "app") {
document.body.classList.add("in-app");
const back = document.querySelector(".back")!;
back.addEventListener("click", () => {
(event.source as Window).postMessage("back", event.origin);
});
}
});
const password = document.getElementById("password") as HTMLInputElement;
const submit = document.getElementById("submit") as HTMLButtonElement;
if (!submit) {
throw new Error("No submit button found");
}
submit.addEventListener("click", () => {
document.cookie = `password=${password.value}`;
location.reload();
});

View File

@ -0,0 +1,24 @@
const path = require("path");
const webpack = require("webpack");
const merge = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const prod = process.env.NODE_ENV === "production";
module.exports = merge(require(path.join(__dirname, "../../../scripts", "webpack.general.config.js"))(), {
devtool: prod ? "source-map" : "cheap-module-eval-source-map",
mode: prod ? "production" : "development",
output: {
path: path.join(__dirname, "out"),
},
entry: [
"webpack-hot-middleware/client?reload=true&quiet=true",
"./packages/app/browser/src/app.ts"
],
plugins: [
new HtmlWebpackPlugin({
template: "packages/app/browser/src/app.html",
}),
new webpack.HotModuleReplacementPlugin(),
// new BundleAnalyzerPlugin(),
]
});

View File

@ -0,0 +1,518 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@material/animation@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.41.0.tgz#315b45b32e1aeebee8a4cf555b8ad52076d09ddd"
integrity sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==
"@material/auto-init@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-0.41.0.tgz#8a59bb0b83e0f51ead9508074f9a29b2b6a20eec"
integrity sha512-jp6L8MpYu7DudgDfA8iTyD9BwQrYPEDsIJGbqzN9vcCBl5FoBatkB8pcFXKr+1mRBk7T1Qmf6+H5nDtxyXjHEQ==
"@material/base@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/base/-/base-0.41.0.tgz#badadce711b4c25b1eb889a5e7581e32cd07c421"
integrity sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==
"@material/button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/button/-/button-0.44.0.tgz#f01dcbea88bdc314e7640b76e5558101c8b4d69d"
integrity sha512-T8u8s8rlB49D9/5Nh5b0XsKRgSq3X0yWGo71MgaTnCnwxt8oZ6PxW/cH6Nn3Xp0NCr3mlSVQs08BviUfAmtlsg==
dependencies:
"@material/elevation" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/card@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/card/-/card-0.44.0.tgz#e62050e3e77f525173a015119200055cd7b71bf0"
integrity sha512-fUixXuh133bVp5c1gPIHreL5jwMJEeVIQf0E4xdxhkA+i4ku8fIAvIW62EuCmfJsXicv4q8NG3Ip6pCY+NW3ZA==
dependencies:
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/checkbox@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.0.tgz#5d0eee1db006db9f0fb700bf1c20408292305cf7"
integrity sha512-IzucxG+NuPNyByGmHg/cuYJ5ooMKouuj994PZXZyqb7owfrjjtXm7wjav66cvCowbVbcoa1owQMGBi18C9f4TQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/chips@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/chips/-/chips-0.44.0.tgz#bf553a5bf5db7320978402ac92069c9688b84d5a"
integrity sha512-+qrme6sGwYmX/ixHAo3Z1M7lorsxRyKexn1l+BSBX5PBc2f4w5Ml1eYYYcyVGfLX9LXmefRk0G6dUXXPyCE00g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/checkbox" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/dialog@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-0.44.0.tgz#388f93f9f225824c75cbe9da8c464a52d79972e8"
integrity sha512-V6ButfknOMKOscL0Y39yLjamxvrIuyugobjf5s44ZeJc+9jUSkC7M3zP+T7rh358NcX+JSPP8iCGmUn/+LXpMQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/dom@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/dom/-/dom-0.41.0.tgz#6756865f97bad4c91ee75e69d769d7cdc25398ae"
integrity sha512-wOJrMwjPddYXpQFZAIaCLWI3TO/6KU1lxESTBzunni8A4FHQVWhokml5Xt85GqZwmPFeIF2s+D0wfbWyrGBuKQ==
"@material/drawer@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-0.44.0.tgz#74b3ddfb741bffc72331c7a73cf62716fd3f0ab3"
integrity sha512-AYwFe0jgqqSmJd1bny8JJTA2SScF86Wfbk99lXXEwd/acS8IbnnuH6zfAg6MyJX12FDb8dE8Z/Ok1IwLiVa9sQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/list" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/elevation@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-0.44.0.tgz#ca16a67188ce9810dc2fa3d7a39073e72df4b754"
integrity sha512-edNou34yFCSMb6XXe/6Y7AEh8DigWAhBUyIeMiMBD4k1km2xYCJbcnl8FBPJFteOrca97KoJComRlJPB6EurRQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/fab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/fab/-/fab-0.44.0.tgz#0bcbbdfb6f24c53d59e08c9c0d400d2616dea184"
integrity sha512-1CEP4NlXDYioJ/YpSjh/MlIygtoC7CaHqIbucxX1O5WRPmS7K1uPt+o7netbLErAmcJdV/JrI/tqh9kKuX2x/Q==
dependencies:
"@material/animation" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/feature-targeting@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.0.tgz#52cc73f0c8a83159de0357aebe74f15f9856fb4c"
integrity sha512-ShuC2TOLfjFpYUCQFtvkqDJhM6HTaucSx5HkRbOvOG+VlpzDx6pAqRUmdVaq2p7tHoQf2vwPMlSVm3gOjWt4VQ==
"@material/floating-label@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.0.tgz#8694cd49f6905641b67a9e7a112b820d028f09c7"
integrity sha512-k4npGNxyMtnjgJZNjU5VvqqaUqlbzlbVAhepT8PxYTpj+4Skg6PjHwieTCDCgsbqHvFcQX+WfUrSZXY7wFV7cw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/form-field@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-0.44.0.tgz#b7518e885c0e953a2a5fe0140af927c30e066f4e"
integrity sha512-SK+V34dzoBCQ/CHn5nBp8BAh21Vj9p1pcok+/WpYBTeg4EphTYP2nUQLMNEN92l6zjgAYf+g9Ocj3t26HNHWqA==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/grid-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/grid-list/-/grid-list-0.44.0.tgz#bd31d992ab1a910731e4a47c11fe91d44e3bc02b"
integrity sha512-NxLL0A48K1O14ZZymFIyf6HDbF33+NgXYXqP2yosTC3Jw4iwmUcJTpFTmSw1U/m1xT4zEpeKEGJ4vjVUWpS9Mg==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/icon-button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-0.44.0.tgz#febbcfd27d91eca8096ae042b9c07ed0f65345e9"
integrity sha512-n6L7RaRyEci6eGsuBTSEG+t9ATHAHaMlf9zuTWorEnIXY4DAmGO7ggBjw4+1XIOjhpLeIjyJdcvUK6Yz/UVM6Q==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/icon-toggle@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-toggle/-/icon-toggle-0.44.0.tgz#b9de32f194b5aa9721ca799d59be0f477a5c5305"
integrity sha512-8T1b4iK61/q/3U0iIjEDJ9do5viCQ45IbrQqa8EYCZ1KDU/Q8z5N+bvOzQK8XnTL51BdDRMgP9lfQZh6nszmkA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/image-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/image-list/-/image-list-0.44.0.tgz#a27996962044ac8c9ce6cb509f63746f08ed2e98"
integrity sha512-kI9aKJdc1Bd02l8nRTGG1wy/lNkECScfnBmCiLQ3XjAFtRYd2eWO0Z/AVvUG3egsIZnZBxqFGGsf5Htm9E/HiQ==
dependencies:
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/layout-grid@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-0.41.0.tgz#2e7d3be76313e0684d573b10c2c6a88b3230d251"
integrity sha512-Sa5RNoTGgfIojqJ9E94p7/k11V6q/tGk7HwKi4AQNAPjxield0zcl3G/SbsSb8YSHoK+D+7OXDN+n11x6EqF7g==
"@material/line-ripple@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-0.43.0.tgz#6cb530bab53f055f3583646a21ad20c1703f3a83"
integrity sha512-sXZYW4Em5uLEnAuVsQCO+sVHsTg7J2TOTJ0+akwZFMmd2tmNicjarQdlGIE9iU7Wjm51NOoLAu6Mz+8kLg90bQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/linear-progress@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-0.43.0.tgz#4821424aa24c78de256e74a91d5be3df55c534d9"
integrity sha512-bqkDcob+xp1mFkyBsOkoaLgrtapmz7jznGoI3nmkqyk75EB2XQcn1H8Vr6cnp/jkF4nbKu0GdVJO3VXUFmGmrQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/list/-/list-0.44.0.tgz#cf1910e15b66759334b8618d1110fbcc72c3d326"
integrity sha512-35gkN1+XZaau9d9ngyN2x14bzkj/ajZCDm7mbWibDQy272A16j6KuFLQFA8RUQV04OgL4YPVxY87dpCn/p+uTg==
dependencies:
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/menu-surface@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu-surface/-/menu-surface-0.44.0.tgz#902c081df42859b925a5b4502791b3febf48f1ae"
integrity sha512-s49kvIlQ4H5wvMD4yeHMMqnamPod06IUagMK6Ry0oTpUANSnyeNXxa3HkScl7DMJiS8IJeV21fSLAzlZYP2PDQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/menu@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu/-/menu-0.44.0.tgz#776ec8a04406266a0a0a13eb140b1fd691e442cb"
integrity sha512-92XvAcv9rBW1jQ3UvwJ8zk9hbSRe/FqSuFdZ9fNPE348dCY2pbcdQfnUJTe3ycAN/I1c5frkrhx8F0II+nfbNQ==
dependencies:
"@material/base" "^0.41.0"
"@material/list" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/notched-outline@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.0.tgz#d5a2e1d649921575a7cd2e88ee4581e4a1809573"
integrity sha512-c3nqOqUQAmW3h4zBbZVbMRdf4nNTYm0tVwXIAwmcCs5nvAthEHnzHwwFddNP7/9Wju6LZ0uqWn6xlyKly0uipw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/radio@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/radio/-/radio-0.44.0.tgz#f4cacdfabc7d765aa000cb34c5a37966f6d4fd6d"
integrity sha512-ar7uhlfHuSwM9JUUjpv7pLDLE0p436cCMxNTpmMjWabfvo3pMWlExvk72Oj81tBgfxY/uASLB3oj4neudXu9JQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/ripple@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.0.tgz#98920ff8ec4bf5714c97df3d190f02f8a5b476cc"
integrity sha512-MlaW4nUDgzS0JOBfsUawXyTOilr0jn+xvTVn6PEaGh2rmhNA54AhixXvdsVUWE9lfmHAsZV0AJHz2z7nunNhbQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/feature-targeting" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/rtl@^0.42.0":
version "0.42.0"
resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-0.42.0.tgz#1836e78186c2d8b996f6fbf97adab203535335bc"
integrity sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==
"@material/select@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/select/-/select-0.44.0.tgz#8041b4fe6247d013b0f12685fbdf50aa9ff57b35"
integrity sha512-tw3/QIBLuRCT+5IXx4IPiJk7FzeGeR65JEizdRUItH8yzoIiQLs/b2i3KtHM2YBXHgeUcEBF2AOqPX2opdYhug==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/selection-control@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.0.tgz#63d5c65a47a9f54f5a0316b5ecdb5e5f35108609"
integrity sha512-HgCAPnMVMEj4X4ILkFSifqtZ3Tcc5HkU+Lfk9g0807sCaN/qBKWkYKLH2WJUbW8uk+MXK7DgP1khtS5zzanJWA==
dependencies:
"@material/ripple" "^0.44.0"
"@material/shape@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.43.0.tgz#b877acfd8be8abc9ddcf6601eb60dd0588292415"
integrity sha512-KGnoQV4G2OQbMe5Lr5Xbk8XNlO93Qi/juxXtd2wrAfiaPmktD8ug0CwdVDOPBOmj9a0gX3Ofi9XWcoU+tLEVjg==
"@material/slider@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/slider/-/slider-0.44.0.tgz#2055df894eb725e541cde50a544719c07934755b"
integrity sha512-Lnn2fdUesXX4O0UpJzveEuOj+og+dXCwhal73u3l3NXEdc/eRgYxwWdF3ww4MmCZ786EwUmjb4vIc9olN4DO3A==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/snackbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-0.44.0.tgz#d98672b849f5f295e4fac2d474a9c80f11945518"
integrity sha512-KhCrmJm8Zu/ZZPuRCGfMKsZ0vudINlNgTjlOau0kQ/UgR1xBUvLOE8NjyXZr0RQz5obyW7xpyIWIpscn0IUeyw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/icon-button" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/switch@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/switch/-/switch-0.44.0.tgz#f2cbb447437b12eb3bc7f0ec8318dbd3b4f0afce"
integrity sha512-EadCg6lHUF260R2Q/l++vXIITqacvbXlobSoewA5ib6y9BU2g7l13wL1W8xAVJNUMgFa/PyN+EKT3oCql7jZLg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/tab-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-bar/-/tab-bar-0.44.0.tgz#b17d791bd557b1d84892fef1a1d8b8d6fef7c6d6"
integrity sha512-kCrt05d61YXyY43SNc0dPGuqysbcLr/KRDBvzpXgE4gv2jCCVhhjAH10KPlx8pthp/UtvrYJHb34acAKEGzdHA==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-scroller" "^0.44.0"
"@material/tab-indicator@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/tab-indicator/-/tab-indicator-0.43.0.tgz#37fd05513ba55ae218d9068c986c2676096fd6eb"
integrity sha512-RMNMQpWYghWpM6d0ayfuHEPzTiebKG0bMthViiD6tly8PubmOT8mShNhPm8ihybhDPUOLSz+7V4QNE5wikLEYg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/tab-scroller@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-scroller/-/tab-scroller-0.44.0.tgz#82d092ed45d2ee9d82038bed318e6ff6bdc36dad"
integrity sha512-Ufd3NWBN11kY2oA7bGmTYWGP1uz2mq0tfDM0JOiqoLMgD7y3Z18kmxnpq2qkg1vi4kvix28hBYGGMfLlq9rGDA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/tab" "^0.44.0"
"@material/tab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab/-/tab-0.44.0.tgz#254b92cff99015f0bd59a86d08d3f1c4744d0742"
integrity sha512-czrbGjtKkmUS3iYBX523xT5GOkjP0h+0x9fTnw+heFNpw5dCn6cZvlj3D9ayZU+ZH93x68TFhFVBuLU5f0EBXw==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/tab-indicator" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/textfield@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.0.tgz#277b33948ddff33f7f643323895e5a683f013601"
integrity sha512-IMBwMcE82eVU+Wifpu0t84tozvBPLCeqQELDtZNYujKg3RxaultzJLwIyGKPMZ9R4yPEpV2vgXPGKE+2/AWt0g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/theme@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.43.0.tgz#6d9fa113c82e841817882172c152d60d2d203ca6"
integrity sha512-/zndZL6EihI18v2mYd4O8xvOBAAXmLeHyHVK28LozSAaJ9okQgD25wq5Ktk95oMTmPIC+rH66KcK6371ivNk8g==
"@material/toolbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/toolbar/-/toolbar-0.44.0.tgz#6689aecdeccc78b7a890a3abbe8b68a2c6339307"
integrity sha512-YgLlOFQ5VzFLQBpXYSMviEbYox0fia+sasHuYPUhTAtas1ExVt9EEiIolDSVvhv2PruTReKKefxSbXAqGlOHog==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/top-app-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/top-app-bar/-/top-app-bar-0.44.0.tgz#2495c7f9567568fb961ccced24f479c4806a72af"
integrity sha512-tf0yXQJARYs8UPaH8oo3LnsSHEiur7Zm8Fc3hv3F0gNRRaZYBjwsMQMVbZZaWoQCWskMALyntBg+Fo18zdgDxw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/typography@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.0.tgz#cf61dce2ee89bfa084d86e1b0f270a585bf9dfaf"
integrity sha512-m4SjA9OjZRDKowN3cPzEa8e2GlTlEn3ZmW/Fy9eRNSp83iY+8a0xl6kCaF80v5qAVwVcpfEFyEHWxMJtkBw2uA==
focus-trap@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-4.0.2.tgz#4ee2b96547c9ea0e4252a2d4b2cca68944194663"
integrity sha512-HtLjfAK7Hp2qbBtLS6wEznID1mPT+48ZnP2nkHzgjpL4kroYHg0CdqJ5cTXk+UO5znAxF5fRUkhdyfgrhh8Lzw==
dependencies:
tabbable "^3.1.2"
xtend "^4.0.1"
material-components-web@^0.44.0:
version "0.44.0"
resolved "https://registry.yarnpkg.com/material-components-web/-/material-components-web-0.44.0.tgz#ff782e8d7bdd8212d3c6022a731258d0d42da531"
integrity sha512-BSRLf58SMVhAvlDhJDlcgYuvzeMwbMHKTJ7oIB8LaM24ZpXBxP9XCYJpKheMtiVLrgllCGDlJ/47OIDReHQXdQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/auto-init" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/card" "^0.44.0"
"@material/checkbox" "^0.44.0"
"@material/chips" "^0.44.0"
"@material/dialog" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/drawer" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/fab" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/floating-label" "^0.44.0"
"@material/form-field" "^0.44.0"
"@material/grid-list" "^0.44.0"
"@material/icon-button" "^0.44.0"
"@material/icon-toggle" "^0.44.0"
"@material/image-list" "^0.44.0"
"@material/layout-grid" "^0.41.0"
"@material/line-ripple" "^0.43.0"
"@material/linear-progress" "^0.43.0"
"@material/list" "^0.44.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/radio" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/select" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/slider" "^0.44.0"
"@material/snackbar" "^0.44.0"
"@material/switch" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-bar" "^0.44.0"
"@material/tab-indicator" "^0.43.0"
"@material/tab-scroller" "^0.44.0"
"@material/textfield" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/toolbar" "^0.44.0"
"@material/top-app-bar" "^0.44.0"
"@material/typography" "^0.44.0"
tabbable@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
xtend@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

View File

@ -0,0 +1,42 @@
{
"manifest_version": 2,
"name": "Coder",
"version": "1",
"icons": {
"128": "icon_128.png"
},
"permissions": [
"storage",
"webview",
"http://*/*",
"https://*/*"
],
"app": {
"background": {
"scripts": [
"out/background.js"
]
},
"content": {
"scripts": [
"out/content.js"
]
}
},
"commands": {
"toggle-feature-foo": {
"suggested_key": {
"default": "Ctrl+W"
},
"description": "Toggle feature foo",
"global": true
}
},
"sockets": {
"tcpServer": {
"listen": [
""
]
}
}
}

View File

@ -0,0 +1,9 @@
{
"name": "@coder/chrome-app",
"dependencies": {
"@types/chrome": "^0.0.79"
},
"scripts": {
"build": "../../../node_modules/.bin/webpack --config ./webpack.config.js"
}
}

View File

@ -0,0 +1,13 @@
/// <reference path="../node_modules/@types/chrome/index.d.ts" />
// tslint:disable-next-line:no-any
const chromeApp = (<any>chrome).app;
chromeApp.runtime.onLaunched.addListener(() => {
chromeApp.window.create("src/index.html", {
outerBounds: {
width: 400,
height: 500,
},
});
});

View File

@ -0,0 +1,92 @@
//@ts-ignore
import { TcpHost, TcpServer, TcpConnection } from "@coder/app/common/src/app";
import { Event, Emitter } from "@coder/events/src";
export const tcpHost: TcpHost = {
listen(host: string, port: number): Promise<TcpServer> {
const socketApi: {
readonly tcpServer: {
create(props: {}, cb: (createInfo: { readonly socketId: number }) => void): void;
listen(socketId: number, address: string, port: number, callback: (result: number) => void): void;
disconnect(socketId: number, callback: () => void): void;
readonly onAccept: {
addListener(callback: (info: { readonly socketId: number; readonly clientSocketId: number }) => void): void;
};
};
readonly tcp: {
readonly onReceive: {
addListener(callback: (info: { readonly socketId: number; readonly data: ArrayBuffer; }) => void): void;
};
close(socketId: number, callback?: () => void): void;
send(socketId: number, data: ArrayBuffer, callback?: () => void): void;
setPaused(socketId: number, value: boolean): void;
};
// tslint:disable-next-line:no-any
} = (<any>chrome).sockets;
return new Promise((resolve, reject): void => {
socketApi.tcpServer.create({}, (createInfo) => {
const serverSocketId = createInfo.socketId;
socketApi.tcpServer.listen(serverSocketId, host, port, (result) => {
if (result < 0) {
return reject("Failed to listen: " + chrome.runtime.lastError);
}
const connectionEmitter = new Emitter<TcpConnection>();
socketApi.tcpServer.onAccept.addListener((info) => {
if (info.socketId !== serverSocketId) {
return;
}
const dataEmitter = new Emitter<ArrayBuffer>();
socketApi.tcp.onReceive.addListener((recvInfo) => {
if (recvInfo.socketId !== info.clientSocketId) {
return;
}
dataEmitter.emit(recvInfo.data);
});
socketApi.tcp.setPaused(info.clientSocketId, false);
connectionEmitter.emit({
send: (data): Promise<void> => {
return new Promise<void>((res): void => {
socketApi.tcp.send(info.clientSocketId, data, () => {
res();
});
});
},
close: (): Promise<void> => {
return new Promise((res): void => {
socketApi.tcp.close(info.clientSocketId, () => {
res();
});
});
},
get onData(): Event<ArrayBuffer> {
return dataEmitter.event;
},
});
});
resolve({
get onConnection(): Event<TcpConnection> {
return connectionEmitter.event;
},
close: (): Promise<void> => {
return new Promise((res): void => {
socketApi.tcpServer.disconnect(serverSocketId, () => {
res();
});
});
},
});
});
});
});
},
};

View File

@ -0,0 +1,33 @@
import { create } from "@coder/app/common/src/app";
import { tcpHost } from "./chome";
create({
storage: {
get: <T>(key: string): Promise<T | undefined> => {
return new Promise<T | undefined>((resolve, reject): void => {
try {
chrome.storage.sync.get(key, (items) => {
resolve(items[key]);
});
} catch (ex) {
reject(ex);
}
});
},
set: <T>(key: string, value: T): Promise<void> => {
return new Promise<void>((resolve, reject): void => {
try {
chrome.storage.sync.set({
[key]: value,
}, () => {
resolve();
});
} catch (ex) {
reject(ex);
}
});
},
},
tcp: tcpHost,
node: document.getElementById("main") as HTMLDivElement,
});

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="style-src 'self' https://use.typekit.net; font-src 'self' https://use.typekit.net;">
<link rel="stylesheet" type="text/css" href="/out/main.css">
</head>
<body>
<div id="main"></div>
<script src="/out/content.js"></script>
</body>
</html>

View File

@ -0,0 +1,37 @@
const path = require("path");
const webpack = require("webpack");
const merge = require("webpack-merge");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const HtmlWebpackPlugin = require("html-webpack-plugin");
const prod = process.env.NODE_ENV === "production";
module.exports = [
merge(require(path.join(__dirname, "../../../scripts", "webpack.general.config.js"))(), {
devtool: "none",
mode: "development",
target: "web",
output: {
path: path.join(__dirname, "out"),
filename: "background.js",
},
entry: [
"./packages/app/chrome/src/background.ts"
],
plugins: [
]
}),
merge(require(path.join(__dirname, "../../../scripts", "webpack.general.config.js"))(), {
devtool: "none",
mode: "development",
target: "web",
output: {
path: path.join(__dirname, "out"),
filename: "content.js",
},
entry: [
"./packages/app/chrome/src/content.ts"
],
plugins: [
]
}),
];

View File

@ -0,0 +1,22 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/chrome@^0.0.79":
version "0.0.79"
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.79.tgz#1c83b35bd9b21b6204fb56e4816a1ea65dc013e5"
integrity sha512-4+Xducpig6lpwVX65Hk8KSZwRoURHXMDbd38SDNcV8TBaw4xyJki39fjB1io2h7ip+BsyFvgTm9OxR5qneLPiA==
dependencies:
"@types/filesystem" "*"
"@types/filesystem@*":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.29.tgz#ee3748eb5be140dcf980c3bd35f11aec5f7a3748"
integrity sha512-85/1KfRedmfPGsbK8YzeaQUyV1FQAvMPMTuWFQ5EkLd2w7szhNO96bk3Rh/SKmOfd9co2rCLf0Voy4o7ECBOvw==
dependencies:
"@types/filewriter" "*"
"@types/filewriter@*":
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
integrity sha1-wFTor02d11205jq8dviFFocU1LM=

View File

@ -0,0 +1,13 @@
{
"name": "@coder/app-common",
"main": "src/app.ts",
"dependencies": {
"material-components-web": "^0.44.0",
"react": "^16.8.1",
"react-dom": "^16.8.1"
},
"devDependencies": {
"@types/react": "^16.8.2",
"@types/react-dom": "^16.8.0"
}
}

View File

@ -0,0 +1,279 @@
@font-face {
font-family: 'aktiv-grotesk';
font-weight: 400;
// src: url("fonts/AktivGroteskRegular.ttf"); /* IE9 Compat Modes */
src: url("fonts/AktivGroteskRegular.woff2") format("woff2"), url("fonts/AktivGroteskRegular.woff") format("woff"); /* Pretty Modern Browsers */
}
@font-face {
font-family: 'aktiv-grotesk';
font-weight: 500;
src: url("fonts/AktivGroteskMedium.woff2") format("woff2"), url("fonts/AktivGroteskMedium.woff") format("woff"); /* Pretty Modern Browsers */
// src: url("fonts/AktivGroteskMedium.ttf");
}
@font-face {
font-family: 'aktiv-grotesk';
font-weight: 700;
src: url("fonts/AktivGroteskBold.woff2") format("woff2"), url("fonts/AktivGroteskBold.woff") format("woff"); /* Pretty Modern Browsers */
// src: url("fonts/AktivGroteskBold.ttf") format("ttf"); /* IE9 Compat Modes */
}
body, button, input {
font-family: 'aktiv-grotesk',sans-serif !important;
}
body {
margin: 0;
background-color: #F6F8FB;
--mdc-theme-primary: #2A2E37;
}
webview {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
opacity: 0;
pointer-events: none;
transition: 150ms opacity ease;
&.active {
opacity: 1;
pointer-events: all;
}
}
.logo-fill {
fill: #2A2E37;
}
.main {
& > .header {
width: 100%;
height: 71px;
border-bottom: 1px solid rgba(117, 122, 131, 0.1);
display: flex;
margin-bottom: 60px;
.logo {
max-height: fit-content;
width: 145px;
}
.shrinker {
max-width: 1145px;
width: 100%;
margin: 0 auto;
display: flex;
}
}
.content {
max-width: 960px;
width: 100%;
padding-bottom: 100px;
margin: 0 auto;
}
}
.servers {
color: #2B343B;
& > .header {
display: flex;
flex-direction: row;
align-items: center;
padding-bottom: 21px;
h3 {
font-size: 24px;
font-weight: 500;
letter-spacing: 0.35px;
line-height: 33px;
margin: 0;
margin-left: 30px;
}
.add-server {
margin-left: auto;
border-radius: 24px;
font-weight: bold;
font-size: 14px;
letter-spacing: 1.25px;
}
.refresh {
margin-left: 16px;
margin-right: 15px;
cursor: pointer;
svg {
@keyframes rotate {
100% { transform: rotate(360deg); }
}
&.refreshing {
animation: rotate 1s linear infinite;
}
}
}
}
& > .grid {
display: grid;
grid-template-columns: 1fr 1.6fr 1.3fr 1.1fr 0.6fr 0.4fr;
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
border-radius: 0 0 5px 5px;
.mdc-linear-progress {
grid-column-start: 1;
grid-column-end: 7;
// height: 0;
position: relative;
--mdc-theme-primary: rgb(107, 109, 102);
height: 5px;
&:after {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: #2A2E37;
transition: 500ms opacity ease;
content: " ";
}
&.loading {
&:after {
opacity: 0;
}
}
}
.title, .value {
padding-top: 14px;
padding-bottom: 14px;
}
.title {
background-color: var(--mdc-theme-primary);
font-size: 10px;
color: #9D9FA4;
font-weight: bold;
letter-spacing: 2px;
line-height: 12px;
text-transform: uppercase;
// padding-top: 15px;
// padding-bottom: 10px;
&:first-child {
padding-left: 30px;
border-radius: 10px 0 0 0;
}
&:nth-child(6) {
padding-right: 30px;
border-radius: 0 10px 0 0;
}
&.servername {
color: white;
}
}
.value {
border-top: 1px solid #EBEBF2;
font-size: 14px;
letter-spacing: 0.2px;
display: flex;
align-items: center;
color: #717680;
background-color: white;
&.dark {
background-color: #F6F8FB;
}
&.servername {
.logo {
height: 25px;
}
}
&.strong {
font-weight: 600;
color: #2B343B;
font-size: 14px;
letter-spacing: 0.6px;
}
&.status {
padding-left: 36px;
span {
margin-left: 7px;
line-height: 0px;
}
}
&.buttons {
button {
margin-left: auto;
border-radius: 24px;
border: 1px solid #CFD1D7;
font-size: 14px;
font-weight: bold;
letter-spacing: 1.25px;
line-height: 16px;
padding-left: 18px;
padding-right: 18px;
}
}
&.icons {
padding-left: 16px;
}
&:last-child {
border-bottom-right-radius: 5px;
}
&:nth-last-child(6) {
border-bottom-left-radius: 5px;
}
}
}
}
.flex-row {
display: flex;
flex-direction: row;
}
.floater {
box-shadow: 0 8px 80px 10px rgba(69, 65, 78, 0.08);
border-radius: 10px;
padding: 3em;
min-width: 300px;
width: 100%;
& > h1 {
font-size: 3.5em;
margin-top: 0px;
// margin-bottom: 0px;
}
}
.mdc-ripple-upgraded--unbounded {
padding: 2px;
padding-top: 5px;
cursor: pointer;
}

View File

@ -0,0 +1,33 @@
//@ts-ignore
import { MDCTextField } from "@material/textfield";
import { TcpHost } from "./connection";
import { StorageProvider } from "./storage";
import "material-components-web/dist/material-components-web.css";
import "./app.scss";
import "./tooltip.scss";
import * as React from "react";
import { render } from "react-dom";
import { Main } from "./containers";
export * from "./connection";
export interface App {
readonly tcp: TcpHost;
readonly storage: StorageProvider;
readonly node: HTMLElement;
}
export interface RegisteredServer {
readonly host: "coder" | "self";
readonly hostname: string;
readonly name: string;
}
export const create = async (app: App): Promise<void> => {
let servers = await app.storage.get<RegisteredServer[]>("servers");
if (!servers) {
servers = [];
}
render(<Main />, app.node);
};

View File

@ -0,0 +1,17 @@
import { Event } from "@coder/events";
import { TunnelCloseEvent } from "@coder/tunnel/src/client";
export interface TcpHost {
listen(host: string, port: number): Promise<TcpServer>;
}
export interface TcpServer {
readonly onConnection: Event<TcpConnection>;
close(): Promise<void>;
}
export interface TcpConnection {
readonly onData: Event<ArrayBuffer>;
send(data: ArrayBuffer): Promise<void>;
close(): Promise<void>;
}

View File

@ -0,0 +1,573 @@
//@ts-ignore
import { MDCRipple } from "@material/ripple";
//@ts-ignore
import { MDCTextField } from "@material/textfield";
//@ts-ignore
import { MDCLinearProgress } from "@material/linear-progress";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { RegisteredServer } from "./app";
// tslint:disable-next-line:no-any
declare var WebSettings: any;
interface AuthedUser {
readonly username: string;
}
export class Main extends React.Component<void, {
readonly view: "servers" | "add-server";
readonly loading: boolean;
}> {
private webview: HTMLWebViewElement | undefined;
public constructor(props: void) {
super(props);
this.state = {
view: "servers",
loading: false,
};
}
public componentDidMount(): void {
window.addEventListener("message", (event) => {
if (event.data === "back") {
if (this.webview) {
this.webview.classList.remove("active");
}
}
if (event.data === "loaded") {
if (this.webview) {
// this.setState({ loading: false });
// this.webview.classList.add("active");
}
}
});
if (this.webview) {
this.webview.addEventListener("error", (event) => {
console.error(event);
});
this.webview.addEventListener("loadstart", (event) => {
this.setState({ loading: true });
});
this.webview.addEventListener("loadstop", (event) => {
this.setState({ loading: false });
this.webview!.classList.add("active");
// tslint:disable-next-line:no-any
const cw = (this.webview as any).contentWindow as Window;
cw.postMessage("app", "*");
});
}
}
public render(): JSX.Element {
return (
<div className="main">
<div className="header">
<div className="shrinker">
<Logo />
</div>
</div>
<div className="content">
{((): JSX.Element => {
switch (this.state.view) {
case "servers":
return (
<Servers servers={[
{
host: "coder",
hostname: "--",
name: "Coder",
},
{
host: "self",
hostname: "http://localhost:8080",
name: "Kyle's Magic Server",
},
]}
user={{
username: "Kyle",
}}
onSelect={(server): void => {
if (this.webview) {
this.webview.setAttribute("src", server.hostname);
}
}}
onAddServer={() => this.setState({ view: "add-server" })}
loading={this.state.loading}
/>
);
case "add-server":
return (
<div>Add server</div>
);
}
})()}
</div>
<webview ref={(wv: HTMLWebViewElement): HTMLWebViewElement => this.webview = wv}></webview>
</div>
);
}
}
export class AddServer extends React.Component {
public render(): JSX.Element {
return (
<div className="add-server">
<h3>Add Server</h3>
<p>Something about what you can do once you add your own server. A link to setup guides for this would be great as well.</p>
<Input label="Address" id="address" />
<br></br>
</div>
);
}
}
export class Servers extends React.Component<{
readonly user?: AuthedUser;
readonly servers: ReadonlyArray<RegisteredServer>;
readonly onSelect: (server: RegisteredServer) => void;
readonly onAddServer: () => void;
readonly loading: boolean;
}, {
readonly refreshing: boolean;
}> {
// tslint:disable-next-line:no-any
public constructor(props: any) {
super(props);
this.state = {
refreshing: false,
};
}
public render(): JSX.Element {
return (
<div className="servers">
<div className="header">
<h3>Servers</h3>
<Button onClick={(): void => this.props.onAddServer()} className="add-server" type="unelevated">Add Server</Button>
<Ripple>
<div className="refresh">
<svg onClick={(): void => this.doRefresh()} className={this.state.refreshing ? "refreshing" : ""} width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g>
<g transform="translate(4.000000, 4.000000)" fill="#2A2E37">
<path d="M8,3 C9.179,3 10.311,3.423 11.205,4.17 L8.883,6.492 L15.094,7.031 L14.555,0.82 L12.625,2.75 C11.353,1.632 9.71,1 8,1 C4.567,1 1.664,3.454 1.097,6.834 L3.07,7.165 C3.474,4.752 5.548,3 8,3 Z" id="Path"></path>
<path d="M8,13 C6.821,13 5.689,12.577 4.795,11.83 L7.117,9.508 L0.906,8.969 L1.445,15.18 L3.375,13.25 C4.647,14.368 6.29,15 8,15 C11.433,15 14.336,12.546 14.903,9.166 L12.93,8.835 C12.526,11.248 10.452,13 8,13 Z" id="Path"></path>
</g>
<rect id="Rectangle" fillRule="nonzero" x="0" y="0" width="24" height="24"></rect>
</g>
</g>
</svg>
</div>
</Ripple>
</div>
<div className="grid">
<div className="title status">
Status
</div>
<div className="title servername">
Server Name
</div>
<div className="title hostname">
Hostname
</div>
<div className="title details">
Details
</div>
<div className="title">
{/* Used for continue/launch buttons */}
</div>
<div className="title">
{/* Used for logout and delete buttons */}
</div>
<div role="progressbar" className={`mdc-linear-progress mdc-linear-progress--indeterminate ${this.props.loading ? "loading" : ""}`} ref={(d) => {
if (d) new MDCLinearProgress(d)}}>
<div className="mdc-linear-progress__buffering-dots"></div>
<div className="mdc-linear-progress__buffer"></div>
<div className="mdc-linear-progress__bar mdc-linear-progress__primary-bar">
<span className="mdc-linear-progress__bar-inner"></span>
</div>
<div className="mdc-linear-progress__bar mdc-linear-progress__secondary-bar">
<span className="mdc-linear-progress__bar-inner"></span>
</div>
</div>
{this.props.servers.map((server, i) => {
return (
<Server key={server.hostname + i} user={this.props.user} server={server} onSelect={(): void => this.props.onSelect(server)} />
);
})}
</div>
</div>
);
}
private doRefresh(): void {
if (this.state.refreshing) {
return;
}
this.setState({
refreshing: true,
}, () => {
setTimeout(() => {
this.setState({
refreshing: false,
});
}, 1500);
});
}
}
interface ServerProps {
readonly user?: AuthedUser;
readonly server: RegisteredServer;
readonly onSelect: () => void;
}
export class Server extends React.Component<ServerProps, {
readonly user?: AuthedUser;
readonly status: "Online" | "Offline" | "Checking";
readonly version: string;
}> {
// tslint:disable-next-line:no-any
public constructor(props: ServerProps) {
super(props);
this.state = {
status: props.server.host === "coder" ? "Online" : "Checking",
version: "",
};
}
public componentWillMount(): void {
if (this.props.server.host !== "self") {
return;
}
const xhr = new XMLHttpRequest();
xhr.open("GET", this.props.server.hostname);
xhr.addEventListener("error", (err) => {
this.setState({
status: "Offline",
});
});
xhr.addEventListener("loadend", () => {
if (xhr.status === 200) {
this.setState({
status: "Online",
version: "v1.31.0",
});
} else {
this.setState({
status: "Offline",
});
}
});
xhr.send();
}
public render(): JSX.Element {
return (
<>
<div className={`status value ${this.extraClasses}`}>
{((): JSX.Element => {
switch (this.state.status) {
case "Offline":
return (
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard-Copy-3" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<circle id="Oval" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" cx="8" cy="8" r="7.25"></circle>
<path d="M5.15444712,5.15444712 L10.8455529,10.8455529" id="Path-4" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero"></path>
<path d="M5.15444712,5.15444712 L10.8455529,10.8455529" id="Path-4" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" transform="translate(8.000000, 8.000000) scale(-1, 1) translate(-8.000000, -8.000000) "></path>
</g>
</svg>
);
case "Online":
return (
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard-Copy-4" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="checkmark-copy-21" fillRule="nonzero">
<circle id="Oval" fill="#2B343B" cx="8" cy="8" r="8"></circle>
<polyline id="Path-2" stroke="#FFFFFF" strokeWidth="1.5" points="3.46296296 8.62222222 6.05555556 11.1111111 12.537037 4.88888889"></polyline>
</g>
</g>
</svg>
);
case "Checking":
return (
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard-Copy-5" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<circle id="Oval" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" cx="8" cy="8" r="7.25"></circle>
<polyline id="Path" stroke="#2B343B" strokeWidth="1.5" points="7.90558664 4.63916767 7.90558664 8.63916767 11.9055866 8.63916767"></polyline>
</g>
</svg>
);
default:
throw new Error("unsupported status");
}
})()}
<span>
{this.state.status}
</span>
</div>
<div className={`servername value strong ${this.extraClasses}`}>
{this.props.server.host === "coder" ? (
<Logo />
) : this.props.server.name}
</div>
<div className={`hostname value ${this.extraClasses}`}>
{this.props.server.hostname}
</div>
<div className={`details value ${this.extraClasses}`}>
{this.props.server.host === "coder" && this.props.user ? `Logged in as ${this.props.user.username}` : this.state.version}
</div>
<div className={`buttons value ${this.extraClasses}`}>
<Button onClick={(): void => this.props.onSelect()} className="add-server" type="outlined">{this.props.server.host === "coder" ? "Continue" : "Launch"}</Button>
</div>
<div className={`icons value ${this.extraClasses}`}>
<Ripple>
<div>
{this.props.server.host === "coder" ? (
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="log-out-copy-2" transform="translate(4.000000, 4.000000)" fill="#2A2E37">
<polygon id="Path" points="4 4 0 8 4 12 4 9 10 9 10 7 4 7"></polygon>
<path d="M15,16 L6,16 C5.4,16 5,15.6 5,15 L5,12 L7,12 L7,14 L14,14 L14,2 L7,2 L7,4 L5,4 L5,1 C5,0.4 5.4,0 6,0 L15,0 C15.6,0 16,0.4 16,1 L16,15 C16,15.6 15.6,16 15,16 Z" id="Path"></path>
</g>
</g>
</svg>
) : (
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="bin" transform="translate(4.000000, 4.000000)" fill="#2B343B">
<rect id="Rectangle" x="5" y="7" width="2" height="6"></rect>
<rect id="Rectangle" x="9" y="7" width="2" height="6"></rect>
<path d="M12,1 C12,0.4 11.6,0 11,0 L5,0 C4.4,0 4,0.4 4,1 L4,3 L0,3 L0,5 L1,5 L1,15 C1,15.6 1.4,16 2,16 L14,16 C14.6,16 15,15.6 15,15 L15,5 L16,5 L16,3 L12,3 L12,1 Z M6,2 L10,2 L10,3 L6,3 L6,2 Z M13,5 L13,14 L3,14 L3,5 L13,5 Z" id="Shape" fillRule="nonzero"></path>
</g>
</g>
</svg>
)}
</div>
</Ripple>
</div>
</>
);
}
private get extraClasses(): string {
return this.props.server.host === "coder" ? "dark" : "";
}
}
export class Input extends React.Component<{
readonly label: string;
readonly id: string;
readonly type?: string;
}> {
private wrapper: HTMLDivElement | undefined;
public componentDidMount(): void {
if (this.wrapper) {
const textInput = new MDCTextField(this.wrapper);
}
}
public render(): JSX.Element {
return (
<div className="mdc-text-field mdc-text-field--outlined" ref={(i: HTMLDivElement): HTMLDivElement => this.wrapper = i}>
<input type={this.props.type || "text"} id={this.props.id} className="mdc-text-field__input" spellCheck={false}></input>
<div className="mdc-notched-outline">
<div className="mdc-notched-outline__leading"></div>
<div className="mdc-notched-outline__notch">
<label htmlFor={this.props.id} className="mdc-floating-label">{this.props.label}</label>
</div>
<div className="mdc-notched-outline__trailing"></div>
</div>
</div>
);
}
}
export class Button extends React.Component<{
readonly type: "outlined" | "unelevated";
readonly className?: string;
readonly onClick?: () => void;
}> {
private button: HTMLButtonElement | undefined;
public componentDidMount(): void {
if (this.button) {
const b = new MDCRipple(this.button);
}
}
public render(): JSX.Element {
return (
<button onClick={() => this.props.onClick ? this.props.onClick() : undefined} className={`mdc-button mdc-button--${this.props.type} ${this.props.className || ""}`} ref={(b: HTMLButtonElement): HTMLButtonElement => this.button = b}>
<span className="mdc-button__label">{this.props.children}</span>
</button>
);
}
}
export class Tooltip extends React.Component<{
readonly message: string;
}> {
public componentDidMount(): void {
Object.keys(this.refs).forEach((ref) => {
const el = this.refs[ref];
if (el) {
const element = ReactDOM.findDOMNode(el);
if (element) {
const te = document.createElement("div");
te.className = "md-tooltip-content";
te.innerHTML = this.props.message;
element.appendChild(te);
(element as HTMLElement).classList.add("md-tooltip");
}
}
});
}
public render(): JSX.Element {
return (
<>
{React.Children.map(this.props.children, (element, idx) => {
return React.cloneElement(element as any, { ref: idx });
})}
</>
);
}
}
export class Ripple extends React.Component<{
readonly className?: string;
}> {
public componentDidMount(): void {
Object.keys(this.refs).forEach((ref) => {
const el = this.refs[ref];
if (el) {
const element = ReactDOM.findDOMNode(el);
if (element) {
(element as HTMLElement).classList.add("mdc-ripple-surface");
(element as HTMLElement).setAttribute("data-mdc-ripple-is-unbounded", "");
const r = new MDCRipple(element);
}
}
});
}
public render(): JSX.Element {
return (
<>
{React.Children.map(this.props.children, (element, idx) => {
return React.cloneElement(element as any, { ref: idx });
})}
</>
);
}
}
export class Logo extends React.Component {
public render(): JSX.Element {
return (
<svg className="logo" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 471 117"
style={{enableBackground: "new 0 0 471 117"} as any} xmlSpace="preserve">
<g>
<g>
<path className="logo-fill" d="M217,75.6c5.9,0,10.7-2.3,14.5-7l7.7,7.9c-6.1,6.9-13.3,10.3-21.6,10.3s-15.1-2.6-20.5-7.9
C191.7,73.7,189,67,189,59s2.7-14.7,8.2-20s12.2-8,20.1-8c8.8,0,16.2,3.4,22.2,10.1l-7.5,8.5c-3.8-4.7-8.5-7.1-14.2-7.1
c-4.5,0-8.4,1.5-11.6,4.4c-3.2,3-4.8,6.9-4.8,11.9s1.5,9,4.5,12.1C209,74.1,212.6,75.6,217,75.6z M284.1,46.7
c-3.1-3.4-6.9-5.1-11.4-5.1s-8.3,1.7-11.4,5.1s-4.6,7.5-4.6,12.3s1.5,8.9,4.6,12.3s6.9,5,11.4,5s8.3-1.7,11.4-5
c3.1-3.4,4.6-7.5,4.6-12.3S287.2,50.1,284.1,46.7z M272.7,86.8c-8,0-14.7-2.7-20.1-8s-8.2-11.9-8.2-19.9c0-7.9,2.7-14.5,8.2-19.9
c5.4-5.3,12.2-8,20.1-8c8,0,14.7,2.7,20.1,8s8.2,11.9,8.2,19.9c0,7.9-2.7,14.5-8.2,19.9C287.4,84.1,280.7,86.8,272.7,86.8z
M352.3,39.4c5.1,4.7,7.7,11.2,7.7,19.6s-2.5,15-7.5,19.9s-12.7,7.3-22.9,7.3h-18.4V32.3h19C339.8,32.4,347.2,34.7,352.3,39.4z
M343.5,71.5c3-2.8,4.4-6.8,4.4-12.1s-1.5-9.4-4.4-12.2c-3-2.9-7.5-4.3-13.6-4.3h-6.7v32.8h7.6C336.3,75.6,340.5,74.2,343.5,71.5z
M409.3,32.4v10.7h-26.8v11.1h24.1v10.3h-24.1v11.2h27.7v10.6h-39.7V32.4H409.3L409.3,32.4z M464.6,50.3c0,8.6-3.4,14.2-10.3,16.7
l13.6,19.3h-14.8l-11.9-17.2h-8.3v17.2h-12V32.4h20.4c8.4,0,14.4,1.4,17.9,4.2C462.8,39.4,464.6,44,464.6,50.3z M450.1,56.7
c1.5-1.3,2.2-3.5,2.2-6.4s-0.8-4.9-2.3-6s-4.2-1.6-8.1-1.6h-9v16h8.8C445.8,58.7,448.6,58,450.1,56.7z"/>
</g>
<g>
<path className="logo-fill" d="M164.8,50.9c-3.3,0-5.5-1.9-5.5-5.8V22.7c0-14.3-6-22.2-21.5-22.2h-7.2v15.1h2.2c6.1,0,9,3.3,9,9.2v19.8
c0,8.6,2.6,12.1,8.3,13.9c-5.7,1.7-8.3,5.3-8.3,13.9c0,4.9,0,9.8,0,14.7c0,4.1,0,8.1-1.1,12.2c-1.1,3.8-2.9,7.4-5.4,10.5
c-1.4,1.8-3,3.3-4.8,4.7v2h7.2c15.5,0,21.5-7.9,21.5-22.2V71.9c0-4,2.1-5.8,5.5-5.8h4.1V51h-4V50.9L164.8,50.9z"/>
<path className="logo-fill" d="M115.8,23.3H93.6c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h22.3c0.5,0,0.9,0.4,0.9,0.9v1.7
C116.8,22.9,116.3,23.3,115.8,23.3z"/>
<path className="logo-fill" d="M119.6,44.9h-16.2c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h16.2c0.5,0,0.9,0.4,0.9,0.9V44
C120.5,44.4,120.1,44.9,119.6,44.9z"/>
<path className="logo-fill" d="M126,34.1H93.6c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h32.3c0.5,0,0.9,0.4,0.9,0.9v1.7
C126.8,33.6,126.5,34.1,126,34.1z"/>
<g>
<path className="logo-fill" d="M67.9,28.2c2.2,0,4.4,0.2,6.5,0.7v-4.1c0-5.8,3-9.2,9-9.2h2.2V0.5h-7.2c-15.5,0-21.5,7.9-21.5,22.2v7.4
C60.4,28.9,64.1,28.2,67.9,28.2z"/>
</g>
<path className="logo-fill" d="M132.8,82.6c-1.6-12.7-11.4-23.3-24-25.7c-3.5-0.7-7-0.8-10.4-0.2c-0.1,0-0.1-0.1-0.2-0.1
c-5.5-11.5-17.3-19.1-30.1-19.1S43.6,44.9,38,56.4c-0.1,0-0.1,0.1-0.2,0.1c-3.6-0.4-7.2-0.2-10.8,0.7c-12.4,3-21.8,13.4-23.5,26
c-0.2,1.3-0.3,2.6-0.3,3.8c0,3.8,2.6,7.3,6.4,7.8c4.7,0.7,8.8-2.9,8.7-7.5c0-0.7,0-1.5,0.1-2.2c0.8-6.4,5.7-11.8,12.1-13.3
c2-0.5,4-0.6,5.9-0.3c6.1,0.8,12.1-2.3,14.7-7.7c1.9-4,4.9-7.5,8.9-9.4c4.4-2.1,9.4-2.4,14-0.8c4.8,1.7,8.4,5.3,10.6,9.8
c2.3,4.4,3.4,7.5,8.3,8.1c2,0.3,7.6,0.2,9.7,0.1c4.1,0,8.2,1.4,11.1,4.3c1.9,2,3.3,4.5,3.9,7.3c0.9,4.5-0.2,9-2.9,12.4
c-1.9,2.4-4.5,4.2-7.4,5c-1.4,0.4-2.8,0.5-4.2,0.5c-0.8,0-1.9,0-3.2,0c-4,0-12.5,0-18.9,0c-4.4,0-7.9-3.5-7.9-7.9V78.4V63.9
c0-1.2-1-2.2-2.2-2.2h-3.1c-6.1,0.1-11,6.9-11,14.1s0,26.3,0,26.3c0,7.8,6.3,14.1,14.1,14.1c0,0,34.7-0.1,35.2-0.1
c8-0.8,15.4-4.9,20.4-11.2C131.5,98.8,133.8,90.8,132.8,82.6z"/>
</g>
</g>
</svg>
);
}
}
// const $ = <K extends keyof HTMLElementTagNameMap>(tagName: K, className?: string, content?: string): HTMLElementTagNameMap[K] => {
// const el = document.createElement(tagName);
// if (className) {
// el.className = className;
// }
// if (content) {
// el.innerText = content;
// }
// return el;
// };
// const createInput = (id: string, labelName: string, type: string = "text"): HTMLDivElement => {
// // <div class="mdc-text-field mdc-text-field--outlined">
// // <input type="password" id="password" class="mdc-text-field__input">
// // <!-- <label class="mdc-floating-label" for="name">Name</label>
// // <div class="mdc-line-ripple"></div> -->
// // <div class="mdc-notched-outline">
// // <div class="mdc-notched-outline__leading"></div>
// // <div class="mdc-notched-outline__notch">
// // <label for="password" class="mdc-floating-label">Password</label>
// // </div>
// // <div class="mdc-notched-outline__trailing"></div>
// // </div>
// const wrapper = $("div", "mdc-text-field mdc-text-field--outlined");
// const input = $("input", "mdc-text-field__input");
// input.type = type;
// input.id = id;
// wrapper.appendChild(input);
// const notchedOutline = $("div", "mdc-notched-outline");
// notchedOutline.appendChild($("div", "mdc-notched-outline__leading"));
// const notch = $("div", "mdc-notched-outline__notch");
// const label = $("label", "mdc-floating-label", labelName);
// label.setAttribute("for", id);
// notch.appendChild(label);
// notchedOutline.appendChild(notch);
// wrapper.appendChild(notchedOutline);
// wrapper.appendChild($("div", "mdc-notched-outline__trailing"));
// const field = new MDCTextField(wrapper);
// return wrapper;
// };
// export const createCoderLogin = (parentNode: HTMLElement): void => {
// parentNode.appendChild($("h1", "header", "Login with Coder"));
// parentNode.appendChild(createInput("username", "Username"));
// parentNode.appendChild($("br"));
// parentNode.appendChild($("br"));
// parentNode.appendChild(createInput("password", "Password", "password"));
// };

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
export interface StorageProvider {
set<T>(key: string, value: T): Promise<void>;
get<T>(key: string): Promise<T | undefined>;
}

View File

@ -0,0 +1,24 @@
.md-tooltip {
position: relative;
}
.md-tooltip-content {
position: absolute;
bottom: -35px;
left: 50%;
padding: 7px;
transform: translateX(-50%) scale(0);
transition: transform 0.15s cubic-bezier(0, 0, 0.2, 1);
transform-origin: top;
background: rgba(67, 67, 67, 0.97);
color: white;
letter-spacing: 0.3px;
border-radius: 3px;
font-size: 12px;
font-weight: 500;
z-index: 2;
}
.md-tooltip:hover .md-tooltip-content {
transform: translateX(-50%) scale(1);
}

View File

@ -0,0 +1,601 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@material/animation@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.41.0.tgz#315b45b32e1aeebee8a4cf555b8ad52076d09ddd"
integrity sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==
"@material/auto-init@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-0.41.0.tgz#8a59bb0b83e0f51ead9508074f9a29b2b6a20eec"
integrity sha512-jp6L8MpYu7DudgDfA8iTyD9BwQrYPEDsIJGbqzN9vcCBl5FoBatkB8pcFXKr+1mRBk7T1Qmf6+H5nDtxyXjHEQ==
"@material/base@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/base/-/base-0.41.0.tgz#badadce711b4c25b1eb889a5e7581e32cd07c421"
integrity sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==
"@material/button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/button/-/button-0.44.0.tgz#f01dcbea88bdc314e7640b76e5558101c8b4d69d"
integrity sha512-T8u8s8rlB49D9/5Nh5b0XsKRgSq3X0yWGo71MgaTnCnwxt8oZ6PxW/cH6Nn3Xp0NCr3mlSVQs08BviUfAmtlsg==
dependencies:
"@material/elevation" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/card@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/card/-/card-0.44.0.tgz#e62050e3e77f525173a015119200055cd7b71bf0"
integrity sha512-fUixXuh133bVp5c1gPIHreL5jwMJEeVIQf0E4xdxhkA+i4ku8fIAvIW62EuCmfJsXicv4q8NG3Ip6pCY+NW3ZA==
dependencies:
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/checkbox@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.0.tgz#5d0eee1db006db9f0fb700bf1c20408292305cf7"
integrity sha512-IzucxG+NuPNyByGmHg/cuYJ5ooMKouuj994PZXZyqb7owfrjjtXm7wjav66cvCowbVbcoa1owQMGBi18C9f4TQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/chips@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/chips/-/chips-0.44.0.tgz#bf553a5bf5db7320978402ac92069c9688b84d5a"
integrity sha512-+qrme6sGwYmX/ixHAo3Z1M7lorsxRyKexn1l+BSBX5PBc2f4w5Ml1eYYYcyVGfLX9LXmefRk0G6dUXXPyCE00g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/checkbox" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/dialog@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-0.44.0.tgz#388f93f9f225824c75cbe9da8c464a52d79972e8"
integrity sha512-V6ButfknOMKOscL0Y39yLjamxvrIuyugobjf5s44ZeJc+9jUSkC7M3zP+T7rh358NcX+JSPP8iCGmUn/+LXpMQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/dom@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/dom/-/dom-0.41.0.tgz#6756865f97bad4c91ee75e69d769d7cdc25398ae"
integrity sha512-wOJrMwjPddYXpQFZAIaCLWI3TO/6KU1lxESTBzunni8A4FHQVWhokml5Xt85GqZwmPFeIF2s+D0wfbWyrGBuKQ==
"@material/drawer@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-0.44.0.tgz#74b3ddfb741bffc72331c7a73cf62716fd3f0ab3"
integrity sha512-AYwFe0jgqqSmJd1bny8JJTA2SScF86Wfbk99lXXEwd/acS8IbnnuH6zfAg6MyJX12FDb8dE8Z/Ok1IwLiVa9sQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/list" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/elevation@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-0.44.0.tgz#ca16a67188ce9810dc2fa3d7a39073e72df4b754"
integrity sha512-edNou34yFCSMb6XXe/6Y7AEh8DigWAhBUyIeMiMBD4k1km2xYCJbcnl8FBPJFteOrca97KoJComRlJPB6EurRQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/fab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/fab/-/fab-0.44.0.tgz#0bcbbdfb6f24c53d59e08c9c0d400d2616dea184"
integrity sha512-1CEP4NlXDYioJ/YpSjh/MlIygtoC7CaHqIbucxX1O5WRPmS7K1uPt+o7netbLErAmcJdV/JrI/tqh9kKuX2x/Q==
dependencies:
"@material/animation" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/feature-targeting@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.0.tgz#52cc73f0c8a83159de0357aebe74f15f9856fb4c"
integrity sha512-ShuC2TOLfjFpYUCQFtvkqDJhM6HTaucSx5HkRbOvOG+VlpzDx6pAqRUmdVaq2p7tHoQf2vwPMlSVm3gOjWt4VQ==
"@material/floating-label@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.0.tgz#8694cd49f6905641b67a9e7a112b820d028f09c7"
integrity sha512-k4npGNxyMtnjgJZNjU5VvqqaUqlbzlbVAhepT8PxYTpj+4Skg6PjHwieTCDCgsbqHvFcQX+WfUrSZXY7wFV7cw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/form-field@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-0.44.0.tgz#b7518e885c0e953a2a5fe0140af927c30e066f4e"
integrity sha512-SK+V34dzoBCQ/CHn5nBp8BAh21Vj9p1pcok+/WpYBTeg4EphTYP2nUQLMNEN92l6zjgAYf+g9Ocj3t26HNHWqA==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/grid-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/grid-list/-/grid-list-0.44.0.tgz#bd31d992ab1a910731e4a47c11fe91d44e3bc02b"
integrity sha512-NxLL0A48K1O14ZZymFIyf6HDbF33+NgXYXqP2yosTC3Jw4iwmUcJTpFTmSw1U/m1xT4zEpeKEGJ4vjVUWpS9Mg==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/icon-button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-0.44.0.tgz#febbcfd27d91eca8096ae042b9c07ed0f65345e9"
integrity sha512-n6L7RaRyEci6eGsuBTSEG+t9ATHAHaMlf9zuTWorEnIXY4DAmGO7ggBjw4+1XIOjhpLeIjyJdcvUK6Yz/UVM6Q==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/icon-toggle@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-toggle/-/icon-toggle-0.44.0.tgz#b9de32f194b5aa9721ca799d59be0f477a5c5305"
integrity sha512-8T1b4iK61/q/3U0iIjEDJ9do5viCQ45IbrQqa8EYCZ1KDU/Q8z5N+bvOzQK8XnTL51BdDRMgP9lfQZh6nszmkA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/image-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/image-list/-/image-list-0.44.0.tgz#a27996962044ac8c9ce6cb509f63746f08ed2e98"
integrity sha512-kI9aKJdc1Bd02l8nRTGG1wy/lNkECScfnBmCiLQ3XjAFtRYd2eWO0Z/AVvUG3egsIZnZBxqFGGsf5Htm9E/HiQ==
dependencies:
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/layout-grid@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-0.41.0.tgz#2e7d3be76313e0684d573b10c2c6a88b3230d251"
integrity sha512-Sa5RNoTGgfIojqJ9E94p7/k11V6q/tGk7HwKi4AQNAPjxield0zcl3G/SbsSb8YSHoK+D+7OXDN+n11x6EqF7g==
"@material/line-ripple@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-0.43.0.tgz#6cb530bab53f055f3583646a21ad20c1703f3a83"
integrity sha512-sXZYW4Em5uLEnAuVsQCO+sVHsTg7J2TOTJ0+akwZFMmd2tmNicjarQdlGIE9iU7Wjm51NOoLAu6Mz+8kLg90bQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/linear-progress@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-0.43.0.tgz#4821424aa24c78de256e74a91d5be3df55c534d9"
integrity sha512-bqkDcob+xp1mFkyBsOkoaLgrtapmz7jznGoI3nmkqyk75EB2XQcn1H8Vr6cnp/jkF4nbKu0GdVJO3VXUFmGmrQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/list/-/list-0.44.0.tgz#cf1910e15b66759334b8618d1110fbcc72c3d326"
integrity sha512-35gkN1+XZaau9d9ngyN2x14bzkj/ajZCDm7mbWibDQy272A16j6KuFLQFA8RUQV04OgL4YPVxY87dpCn/p+uTg==
dependencies:
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/menu-surface@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu-surface/-/menu-surface-0.44.0.tgz#902c081df42859b925a5b4502791b3febf48f1ae"
integrity sha512-s49kvIlQ4H5wvMD4yeHMMqnamPod06IUagMK6Ry0oTpUANSnyeNXxa3HkScl7DMJiS8IJeV21fSLAzlZYP2PDQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/menu@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu/-/menu-0.44.0.tgz#776ec8a04406266a0a0a13eb140b1fd691e442cb"
integrity sha512-92XvAcv9rBW1jQ3UvwJ8zk9hbSRe/FqSuFdZ9fNPE348dCY2pbcdQfnUJTe3ycAN/I1c5frkrhx8F0II+nfbNQ==
dependencies:
"@material/base" "^0.41.0"
"@material/list" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/notched-outline@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.0.tgz#d5a2e1d649921575a7cd2e88ee4581e4a1809573"
integrity sha512-c3nqOqUQAmW3h4zBbZVbMRdf4nNTYm0tVwXIAwmcCs5nvAthEHnzHwwFddNP7/9Wju6LZ0uqWn6xlyKly0uipw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/radio@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/radio/-/radio-0.44.0.tgz#f4cacdfabc7d765aa000cb34c5a37966f6d4fd6d"
integrity sha512-ar7uhlfHuSwM9JUUjpv7pLDLE0p436cCMxNTpmMjWabfvo3pMWlExvk72Oj81tBgfxY/uASLB3oj4neudXu9JQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/ripple@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.0.tgz#98920ff8ec4bf5714c97df3d190f02f8a5b476cc"
integrity sha512-MlaW4nUDgzS0JOBfsUawXyTOilr0jn+xvTVn6PEaGh2rmhNA54AhixXvdsVUWE9lfmHAsZV0AJHz2z7nunNhbQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/feature-targeting" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/rtl@^0.42.0":
version "0.42.0"
resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-0.42.0.tgz#1836e78186c2d8b996f6fbf97adab203535335bc"
integrity sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==
"@material/select@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/select/-/select-0.44.0.tgz#8041b4fe6247d013b0f12685fbdf50aa9ff57b35"
integrity sha512-tw3/QIBLuRCT+5IXx4IPiJk7FzeGeR65JEizdRUItH8yzoIiQLs/b2i3KtHM2YBXHgeUcEBF2AOqPX2opdYhug==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/selection-control@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.0.tgz#63d5c65a47a9f54f5a0316b5ecdb5e5f35108609"
integrity sha512-HgCAPnMVMEj4X4ILkFSifqtZ3Tcc5HkU+Lfk9g0807sCaN/qBKWkYKLH2WJUbW8uk+MXK7DgP1khtS5zzanJWA==
dependencies:
"@material/ripple" "^0.44.0"
"@material/shape@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.43.0.tgz#b877acfd8be8abc9ddcf6601eb60dd0588292415"
integrity sha512-KGnoQV4G2OQbMe5Lr5Xbk8XNlO93Qi/juxXtd2wrAfiaPmktD8ug0CwdVDOPBOmj9a0gX3Ofi9XWcoU+tLEVjg==
"@material/slider@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/slider/-/slider-0.44.0.tgz#2055df894eb725e541cde50a544719c07934755b"
integrity sha512-Lnn2fdUesXX4O0UpJzveEuOj+og+dXCwhal73u3l3NXEdc/eRgYxwWdF3ww4MmCZ786EwUmjb4vIc9olN4DO3A==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/snackbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-0.44.0.tgz#d98672b849f5f295e4fac2d474a9c80f11945518"
integrity sha512-KhCrmJm8Zu/ZZPuRCGfMKsZ0vudINlNgTjlOau0kQ/UgR1xBUvLOE8NjyXZr0RQz5obyW7xpyIWIpscn0IUeyw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/icon-button" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/switch@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/switch/-/switch-0.44.0.tgz#f2cbb447437b12eb3bc7f0ec8318dbd3b4f0afce"
integrity sha512-EadCg6lHUF260R2Q/l++vXIITqacvbXlobSoewA5ib6y9BU2g7l13wL1W8xAVJNUMgFa/PyN+EKT3oCql7jZLg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/tab-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-bar/-/tab-bar-0.44.0.tgz#b17d791bd557b1d84892fef1a1d8b8d6fef7c6d6"
integrity sha512-kCrt05d61YXyY43SNc0dPGuqysbcLr/KRDBvzpXgE4gv2jCCVhhjAH10KPlx8pthp/UtvrYJHb34acAKEGzdHA==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-scroller" "^0.44.0"
"@material/tab-indicator@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/tab-indicator/-/tab-indicator-0.43.0.tgz#37fd05513ba55ae218d9068c986c2676096fd6eb"
integrity sha512-RMNMQpWYghWpM6d0ayfuHEPzTiebKG0bMthViiD6tly8PubmOT8mShNhPm8ihybhDPUOLSz+7V4QNE5wikLEYg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/tab-scroller@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-scroller/-/tab-scroller-0.44.0.tgz#82d092ed45d2ee9d82038bed318e6ff6bdc36dad"
integrity sha512-Ufd3NWBN11kY2oA7bGmTYWGP1uz2mq0tfDM0JOiqoLMgD7y3Z18kmxnpq2qkg1vi4kvix28hBYGGMfLlq9rGDA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/tab" "^0.44.0"
"@material/tab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab/-/tab-0.44.0.tgz#254b92cff99015f0bd59a86d08d3f1c4744d0742"
integrity sha512-czrbGjtKkmUS3iYBX523xT5GOkjP0h+0x9fTnw+heFNpw5dCn6cZvlj3D9ayZU+ZH93x68TFhFVBuLU5f0EBXw==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/tab-indicator" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/textfield@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.0.tgz#277b33948ddff33f7f643323895e5a683f013601"
integrity sha512-IMBwMcE82eVU+Wifpu0t84tozvBPLCeqQELDtZNYujKg3RxaultzJLwIyGKPMZ9R4yPEpV2vgXPGKE+2/AWt0g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/theme@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.43.0.tgz#6d9fa113c82e841817882172c152d60d2d203ca6"
integrity sha512-/zndZL6EihI18v2mYd4O8xvOBAAXmLeHyHVK28LozSAaJ9okQgD25wq5Ktk95oMTmPIC+rH66KcK6371ivNk8g==
"@material/toolbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/toolbar/-/toolbar-0.44.0.tgz#6689aecdeccc78b7a890a3abbe8b68a2c6339307"
integrity sha512-YgLlOFQ5VzFLQBpXYSMviEbYox0fia+sasHuYPUhTAtas1ExVt9EEiIolDSVvhv2PruTReKKefxSbXAqGlOHog==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/top-app-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/top-app-bar/-/top-app-bar-0.44.0.tgz#2495c7f9567568fb961ccced24f479c4806a72af"
integrity sha512-tf0yXQJARYs8UPaH8oo3LnsSHEiur7Zm8Fc3hv3F0gNRRaZYBjwsMQMVbZZaWoQCWskMALyntBg+Fo18zdgDxw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/typography@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.0.tgz#cf61dce2ee89bfa084d86e1b0f270a585bf9dfaf"
integrity sha512-m4SjA9OjZRDKowN3cPzEa8e2GlTlEn3ZmW/Fy9eRNSp83iY+8a0xl6kCaF80v5qAVwVcpfEFyEHWxMJtkBw2uA==
"@types/prop-types@*":
version "15.5.8"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce"
integrity sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==
"@types/react-dom@^16.8.0":
version "16.8.0"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.0.tgz#c565f43f9d2ec911f9e0b8f3b74e25e67879aa3f"
integrity sha512-Jp4ufcEEjVJEB0OHq2MCZcE1u3KYUKO6WnSuiU/tZeYeiZxUoQavfa/TZeiIT+1XoN6l0lQVNM30VINZFDeolQ==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^16.8.2":
version "16.8.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.2.tgz#3b7a7f7ea89d1c7d68b00849fb5de839011c077b"
integrity sha512-6mcKsqlqkN9xADrwiUz2gm9Wg4iGnlVGciwBRYFQSMWG6MQjhOZ/AVnxn+6v8nslFgfYTV8fNdE6XwKu6va5PA==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
csstype@^2.2.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.2.tgz#3043d5e065454579afc7478a18de41909c8a2f01"
integrity sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==
focus-trap@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-4.0.2.tgz#4ee2b96547c9ea0e4252a2d4b2cca68944194663"
integrity sha512-HtLjfAK7Hp2qbBtLS6wEznID1mPT+48ZnP2nkHzgjpL4kroYHg0CdqJ5cTXk+UO5znAxF5fRUkhdyfgrhh8Lzw==
dependencies:
tabbable "^3.1.2"
xtend "^4.0.1"
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
material-components-web@^0.44.0:
version "0.44.0"
resolved "https://registry.yarnpkg.com/material-components-web/-/material-components-web-0.44.0.tgz#ff782e8d7bdd8212d3c6022a731258d0d42da531"
integrity sha512-BSRLf58SMVhAvlDhJDlcgYuvzeMwbMHKTJ7oIB8LaM24ZpXBxP9XCYJpKheMtiVLrgllCGDlJ/47OIDReHQXdQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/auto-init" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/card" "^0.44.0"
"@material/checkbox" "^0.44.0"
"@material/chips" "^0.44.0"
"@material/dialog" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/drawer" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/fab" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/floating-label" "^0.44.0"
"@material/form-field" "^0.44.0"
"@material/grid-list" "^0.44.0"
"@material/icon-button" "^0.44.0"
"@material/icon-toggle" "^0.44.0"
"@material/image-list" "^0.44.0"
"@material/layout-grid" "^0.41.0"
"@material/line-ripple" "^0.43.0"
"@material/linear-progress" "^0.43.0"
"@material/list" "^0.44.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/radio" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/select" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/slider" "^0.44.0"
"@material/snackbar" "^0.44.0"
"@material/switch" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-bar" "^0.44.0"
"@material/tab-indicator" "^0.43.0"
"@material/tab-scroller" "^0.44.0"
"@material/textfield" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/toolbar" "^0.44.0"
"@material/top-app-bar" "^0.44.0"
"@material/typography" "^0.44.0"
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
prop-types@^15.6.2:
version "15.7.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.1.tgz#2fa61e0a699d428b40320127733ee2931f05d9d1"
integrity sha512-f8Lku2z9kERjOCcnDOPm68EBJAO2K00Q5mSgPAUE/gJuBgsYLbVy6owSrtcHj90zt8PvW+z0qaIIgsIhHOa1Qw==
dependencies:
object-assign "^4.1.1"
react-is "^16.8.1"
react-dom@^16.8.1:
version "16.8.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.1.tgz#ec860f98853d09d39bafd3a6f1e12389d283dbb4"
integrity sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.13.1"
react-is@^16.8.1:
version "16.8.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.1.tgz#a80141e246eb894824fb4f2901c0c50ef31d4cdb"
integrity sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA==
react@^16.8.1:
version "16.8.1"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.1.tgz#ae11831f6cb2a05d58603a976afc8a558e852c4a"
integrity sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.13.1"
scheduler@^0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.1.tgz#1a217df1bfaabaf4f1b92a9127d5d732d85a9591"
integrity sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
tabbable@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
xtend@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=

View File

@ -0,0 +1,18 @@
# This file specifies files that are *not* uploaded to Google Cloud Platform
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore
src
# Node.js dependencies:
node_modules/

8
packages/dns/Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM node
COPY out/main.js /main.js
COPY package.json /package.json
RUN yarn
ENV NODE_ENV production
CMD ["node", "/main.js"]

5
packages/dns/app.yaml Normal file
View File

@ -0,0 +1,5 @@
runtime: nodejs10
service: cdrdns
network:
forwarded_ports:
- 53/udp

14
packages/dns/package.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "@coder/dns",
"main": "out/main.js",
"scripts": {
"build": "../../node_modules/.bin/webpack --config ./webpack.config.js"
},
"dependencies": {
"node-named": "^0.0.1"
},
"devDependencies": {
"ip-address": "^5.8.9",
"@types/ip-address": "^5.8.2"
}
}

109
packages/dns/src/dns.ts Normal file
View File

@ -0,0 +1,109 @@
import { field, logger } from "@coder/logger";
import * as http from "http";
//@ts-ignore
import * as named from "node-named";
import * as ip from "ip-address";
import { words, wordKeys } from "./words";
import * as dgram from "dgram";
const oldCreate = dgram.createSocket;
// tslint:disable-next-line:no-any
(<any>dgram).createSocket = (_: any, callback: any): dgram.Socket => {
return oldCreate("udp4", callback);
};
interface DnsQuery {
name(): string;
// tslint:disable-next-line:no-any
addAnswer(domain: string, target: any, ttl: number): void;
}
const dnsServer: {
listen(port: number, host: string, callback: () => void): void;
on(event: "query", callback: (query: DnsQuery) => void): void;
send(query: DnsQuery): void;
} = named.createServer();
const isDev = process.env.NODE_ENV !== "production";
const dnsPort = isDev ? 9999 : 53;
dnsServer.listen(dnsPort, "0.0.0.0", () => {
logger.info("DNS server started", field("port", dnsPort));
});
dnsServer.on("query", (query) => {
const domain = query.name();
const reqParts = domain.split(".");
if (reqParts.length < 2) {
dnsServer.send(query);
logger.info("Invalid request", field("request", domain));
return;
}
const allWords = reqParts.shift()!;
if (allWords.length > 16) {
dnsServer.send(query);
logger.info("Invalid request", field("request", domain));
return;
}
const wordParts = allWords.split(/(?=[A-Z])/);
const ipParts: string[] = [];
// Should be left with HowAreYouNow
for (let i = 0; i < wordParts.length; i++) {
const part = wordParts[i];
if (part.length > 4) {
dnsServer.send(query);
logger.info("Words too long", field("request", domain));
return;
}
const ipPart = words[part.toLowerCase()];
if (typeof ipPart === "undefined") {
dnsServer.send(query);
logger.info("Word not found in index", field("part", part), field("request", domain));
return;
}
ipParts.push(ipPart.toString());
}
const address = new ip.Address4(ipParts.join("."));
if (address.isValid()) {
logger.info("Responded with valid address query", field("address", address.address), field("request", domain));
query.addAnswer(domain, new named.ARecord(address.address), 99999);
} else {
logger.warn("Received invalid request", field("request", domain));
}
dnsServer.send(query);
});
const httpServer = http.createServer((request, response) => {
const remoteAddr = request.connection.remoteAddress;
if (!remoteAddr) {
response.writeHead(422);
response.end();
return;
}
const hostHeader = request.headers.host;
if (!hostHeader) {
response.writeHead(422);
response.end();
return;
}
const host = remoteAddr.split(".").map(p => wordKeys[Number.parseInt(p, 10)]).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join("");
logger.info("Resolved host", field("remote-addr", remoteAddr), field("host", host));
response.writeHead(200);
response.write(`${host}.${hostHeader}`);
response.end();
});
const httpPort = isDev ? 3000 : 80;
httpServer.listen(httpPort, "0.0.0.0", () => {
logger.info("HTTP server started", field("port", httpPort));
});

260
packages/dns/src/words.ts Normal file
View File

@ -0,0 +1,260 @@
export const words: { readonly [key: string]: number } = {
term: 0,
salt: 1,
barn: 2,
corn: 3,
went: 4,
feel: 5,
rest: 6,
will: 7,
pale: 8,
cave: 9,
dirt: 10,
time: 11,
in: 12,
pie: 13,
star: 14,
iron: 15,
door: 16,
tone: 17,
want: 18,
task: 19,
zoo: 20,
nor: 21,
fall: 22,
tell: 23,
noon: 24,
new: 25,
per: 26,
end: 27,
arm: 28,
been: 29,
wolf: 30,
port: 31,
beat: 32,
pour: 33,
far: 34,
may: 35,
tie: 36,
moon: 37,
duck: 38,
us: 39,
led: 40,
met: 41,
bank: 42,
day: 43,
due: 44,
both: 45,
pet: 46,
gate: 47,
pain: 48,
rock: 49,
fill: 50,
open: 51,
thus: 52,
mark: 53,
our: 54,
loud: 55,
wife: 56,
say: 57,
flag: 58,
as: 59,
ride: 60,
once: 61,
sun: 62,
duty: 63,
pure: 64,
made: 65,
gulf: 66,
pig: 67,
fish: 68,
name: 69,
army: 70,
have: 71,
ill: 72,
meal: 73,
ago: 74,
late: 75,
view: 76,
atom: 77,
pen: 78,
mud: 79,
tail: 80,
sink: 81,
cow: 82,
rear: 83,
fur: 84,
go: 85,
suit: 86,
come: 87,
fear: 88,
also: 89,
sail: 90,
row: 91,
lay: 92,
noun: 93,
hat: 94,
am: 95,
mail: 96,
keep: 97,
drop: 98,
than: 99,
weak: 100,
by: 101,
who: 102,
fire: 103,
good: 104,
sick: 105,
care: 106,
pink: 107,
lady: 108,
war: 109,
sets: 110,
swam: 111,
well: 112,
shoe: 113,
bent: 114,
fuel: 115,
wet: 116,
fog: 117,
land: 118,
lead: 119,
tax: 120,
deal: 121,
verb: 122,
take: 123,
save: 124,
gift: 125,
had: 126,
gold: 127,
slow: 128,
drew: 129,
lamp: 130,
roof: 131,
hung: 132,
wild: 133,
able: 134,
girl: 135,
warn: 136,
were: 137,
know: 138,
camp: 139,
milk: 140,
neck: 141,
aid: 142,
fair: 143,
bell: 144,
dig: 145,
hope: 146,
wood: 147,
away: 148,
cook: 149,
just: 150,
form: 151,
food: 152,
hall: 153,
mind: 154,
for: 155,
card: 156,
half: 157,
sat: 158,
now: 159,
team: 160,
rush: 161,
face: 162,
wire: 163,
such: 164,
tool: 165,
make: 166,
fat: 167,
hold: 168,
inch: 169,
bill: 170,
mean: 171,
tide: 172,
burn: 173,
talk: 174,
tape: 175,
hard: 176,
mine: 177,
on: 178,
year: 179,
rich: 180,
sum: 181,
yes: 182,
baby: 183,
wide: 184,
how: 185,
clay: 186,
car: 187,
here: 188,
cent: 189,
bowl: 190,
post: 191,
said: 192,
see: 193,
raw: 194,
foot: 195,
life: 196,
bar: 197,
from: 198,
path: 199,
meat: 200,
show: 201,
sent: 202,
wait: 203,
mice: 204,
ten: 205,
pot: 206,
nice: 207,
idea: 208,
or: 209,
onto: 210,
rose: 211,
your: 212,
this: 213,
cat: 214,
bet: 215,
took: 216,
hang: 217,
very: 218,
bend: 219,
mix: 220,
base: 221,
jack: 222,
her: 223,
leg: 224,
own: 225,
book: 226,
love: 227,
dawn: 228,
deer: 229,
hit: 230,
rain: 231,
gas: 232,
eat: 233,
tube: 234,
case: 235,
pipe: 236,
get: 237,
joy: 238,
ever: 239,
nest: 240,
home: 241,
egg: 242,
pack: 243,
hand: 244,
cold: 245,
hot: 246,
frog: 247,
peep: 248,
seed: 249,
rawr: 250,
top: 251,
meow: 252,
bark: 253,
eel: 254,
swap: 255,
};
export const wordKeys = Object.keys(words);

View File

@ -0,0 +1,18 @@
const path = require("path");
const merge = require("webpack-merge");
module.exports = merge(require(path.join(__dirname, "../../scripts", "webpack.general.config.js"))(), {
devtool: "none",
mode: "production",
target: "node",
externals: {
"node-named": "commonjs node-named",
},
output: {
path: path.join(__dirname, "out"),
filename: "main.js",
},
entry: [
"./packages/dns/src/dns.ts"
],
});

88
packages/dns/yarn.lock Normal file
View File

@ -0,0 +1,88 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/ip-address@^5.8.2":
version "5.8.2"
resolved "https://registry.yarnpkg.com/@types/ip-address/-/ip-address-5.8.2.tgz#5e413c477f78b3a264745eac937538a6e6e0c1f6"
integrity sha512-LFlDGRjJDnahfPyNCZGXvlaevSmZTi/zDxjTdXeTs8TQ9pQkNZKbCWaJXW29a3bGPRsASqeO+jGgZlaTUi9jTw==
dependencies:
"@types/jsbn" "*"
"@types/jsbn@*":
version "1.2.29"
resolved "https://registry.yarnpkg.com/@types/jsbn/-/jsbn-1.2.29.tgz#28229bc0262c704a1506c3ed69a7d7e115bd7832"
integrity sha512-2dVz9LTEGWVj9Ov9zaDnpvqHFV+W4bXtU0EUEGAzWfdRNO3dlUuosdHpENI6/oQW+Kejn0hAjk6P/czs9h/hvg==
bunyan@0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-0.7.0.tgz#921065e70c936fe302a740e2c5605775beea2f42"
integrity sha1-khBl5wyTb+MCp0DixWBXdb7qL0I=
"coffee-script@>= 1.1.1":
version "1.12.7"
resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53"
integrity sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==
ip-address@^5.8.9:
version "5.8.9"
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-5.8.9.tgz#6379277c23fc5adb20511e4d23ec2c1bde105dfd"
integrity sha512-7ay355oMN34iXhET1BmCJVsHjOTSItEEIIpOs38qUC23AIhOy+xIPnkrTuEFjeLMrTJ7m8KMXWgWfy/2Vn9sDw==
dependencies:
jsbn "1.1.0"
lodash.find "^4.6.0"
lodash.max "^4.0.1"
lodash.merge "^4.6.0"
lodash.padstart "^4.6.1"
lodash.repeat "^4.1.0"
sprintf-js "1.1.0"
ipaddr.js@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-0.1.1.tgz#28c6a7c116a021c555544f906ab1ad540b1d635a"
integrity sha1-KManwRagIcVVVE+QarGtVAsdY1o=
dependencies:
coffee-script ">= 1.1.1"
jsbn@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
integrity sha1-sBMHyym2GKHtJux56RH4A8TaAEA=
lodash.find@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=
lodash.max@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.max/-/lodash.max-4.0.1.tgz#8735566c618b35a9f760520b487ae79658af136a"
integrity sha1-hzVWbGGLNan3YFILSHrnllivE2o=
lodash.merge@^4.6.0:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
lodash.padstart@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b"
integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=
lodash.repeat@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.repeat/-/lodash.repeat-4.1.0.tgz#fc7de8131d8c8ac07e4b49f74ffe829d1f2bec44"
integrity sha1-/H3oEx2MisB+S0n3T/6CnR8r7EQ=
node-named@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/node-named/-/node-named-0.0.1.tgz#3607b434cf237ab99440f5ff6d19c05e3a93e217"
integrity sha1-Nge0NM8jermUQPX/bRnAXjqT4hc=
dependencies:
bunyan "0.7.0"
ipaddr.js "0.1.1"
sprintf-js@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.0.tgz#cffcaf702daf65ea39bb4e0fa2b299cec1a1be46"
integrity sha1-z/yvcC2vZeo5u04PorKZzsGhvkY=

View File

@ -32,6 +32,13 @@ export abstract class IdeClient {
logger.info("Loading IDE");
this.loadTime = time(2500);
let appWindow: Window | undefined;
window.addEventListener("message", (event) => {
if (event.data === "app") {
appWindow = event.source as Window;
}
});
this.sharedProcessData = new Promise((resolve): void => {
client.onSharedProcessActive(resolve);
});
@ -48,6 +55,9 @@ export abstract class IdeClient {
this.initialize().then(() => {
logger.info("Load completed", field("duration", this.loadTime));
if (appWindow) {
appWindow.postMessage("loaded", "*");
}
}).catch((error) => {
logger.error(error.message);
logger.warn("Load completed with errors", field("duration", this.loadTime));

View File

@ -92,7 +92,7 @@ class WebsocketConnection implements ReadWriteConnection {
private async openSocket(): Promise<WebSocket> {
this.dispose();
const socket = new WebSocket(
`${location.protocol === "https" ? "wss" : "ws"}://${location.host}`,
`${location.protocol === "https:" ? "wss" : "ws"}://${location.host}`,
);
socket.binaryType = "arraybuffer";
this.activeSocket = socket;

View File

@ -19,15 +19,59 @@ if (typeof document === "undefined") {
(global as any).document = {} as any;
}
const oldCreateElement: <K extends keyof HTMLElementTagNameMap>(
tagName: K, options?: ElementCreationOptions,
) => HTMLElementTagNameMap[K] = document.createElement;
const oldCreateElement = document.createElement;
const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K] => {
const createElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K] => {
return oldCreateElement.call(document, tagName);
// tslint:disable-next-line:no-any
return oldCreateElement.call(document, tagName as any);
};
if (tagName === "style") {
const style = createElement("style");
// tslint:disable-next-line:no-any
const getPropertyDescriptor = (object: any, id: string): PropertyDescriptor | undefined => {
let op = Object.getPrototypeOf(object);
while (!Object.getOwnPropertyDescriptor(op, id)) {
op = Object.getPrototypeOf(op);
}
return Object.getOwnPropertyDescriptor(op, id);
};
const oldInnerHtml = getPropertyDescriptor(style, "innerHTML");
if (!oldInnerHtml) {
throw new Error("Failed to find innerHTML property");
}
Object.defineProperty(style, "innerHTML", {
get: (): string => {
return oldInnerHtml!.get!.call(style);
},
set: (value: string): void => {
value = value.replace(/file:\/\//g, "/resource");
oldInnerHtml!.set!.call(style, value);
},
});
let overridden = false;
const oldSheet = getPropertyDescriptor(style, "sheet");
Object.defineProperty(style, "sheet", {
// tslint:disable-next-line:no-any
get: (): any => {
const sheet = oldSheet!.get!.call(style);
if (sheet && !overridden) {
const oldInsertRule = sheet.insertRule;
sheet.insertRule = (rule: string, index?: number): void => {
rule = rule.replace(/file:\/\//g, "/resource");
oldInsertRule.call(sheet, rule, index);
};
overridden = true;
}
return sheet;
},
});
return style;
}
if (tagName === "webview") {
const view = createElement("iframe") as HTMLIFrameElement;
view.style.border = "0px";
@ -56,8 +100,19 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
view.contentDocument.body.parentElement!.style.overflow = "hidden";
const script = createElement("script");
script.src = url;
script.addEventListener("load", () => {
view.contentDocument!.dispatchEvent(new Event("DOMContentLoaded", {
bubbles: true,
cancelable: true,
}));
// const e = new CustomEvent("ipc-message");
// (e as any).channel = "webview-ready"; // tslint:disable-line no-any
// (e as any).args = [frameID]; // tslint:disable-line no-any
// view.dispatchEvent(e);
});
view.contentDocument.head.appendChild(script);
}
};
},
});
@ -65,8 +120,8 @@ const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HT
(view as any).send = (channel: string, ...args: any[]): void => { // tslint:disable-line no-any
if (args[0] && typeof args[0] === "object" && args[0].contents) {
// TODO
// args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m) => `"${getFetchUrl(m)}"`);
// args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m) => `"${getFetchUrl(m)}"`);
args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m1) => `"/resource${m1}"`);
args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m, m1) => `"/resource${m1}"`);
}
if (view.contentWindow) {
view.contentWindow.postMessage({

View File

@ -118,6 +118,7 @@ class 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));
@ -157,6 +158,10 @@ class FS {
ae.emit("close");
}
public destroy(): void {
ae.emit("destroy");
}
}) as fs.WriteStream;
}

View File

@ -32,6 +32,10 @@ class OS {
this._tmpdir = data.tmpDirectory;
}
public release(): string {
return "Unknown";
}
public platform(): NodeJS.Platform {
if (navigator.appVersion.indexOf("Win") != -1) {
return "win32";

View File

@ -0,0 +1,4 @@
{
"name": "@coder/runner",
"main": "src/index.ts"
}

View File

@ -0,0 +1 @@
export * from "./runner";

View File

@ -0,0 +1,114 @@
import * as cp from "child_process";
import { logger, Logger, field, time } from "@coder/logger";
export interface CommandResult {
readonly exitCode: number;
readonly stdout: string;
readonly stderr: string;
}
const execute = (command: string, args: string[] = [], options: cp.SpawnOptions, logger: Logger): Promise<CommandResult> => {
let resolve: (result: CommandResult) => void;
const prom = new Promise<CommandResult>(res => resolve = res);
const stdout: string[] = [];
const stderr: string[] = [];
const complete = (exitCode: number): void => {
resolve({
stderr: stderr.join(""),
stdout: stdout.join(""),
exitCode,
});
};
logger.info(`Executing '${command} ${JSON.stringify(args)}'`, field("options", options));
const proc = cp.spawn(command, args.length > 0 ? args : [], options);
proc.on("close", (code) => {
complete(code);
});
proc.on("exit", (code) => {
complete(code!);
});
proc.stdout.on("data", (d) => {
stdout.push(d.toString());
logger.debug("stdio", field("stdout", d.toString()));
});
proc.stderr.on("data", (d) => {
stderr.push(d.toString());
logger.debug("stdio", field("stderr", d.toString()));
});
return prom;
};
export type TaskFunction = (runner: Runner) => void | Promise<void>;
export interface Runner {
cwd: string;
execute(command: string, args?: string[], env?: object): Promise<CommandResult>;
}
export interface Task {
readonly name: string;
readonly func: TaskFunction;
}
const tasks = new Map<string, Task>();
const activated = new Map<string, Promise<void>>();
export const register = (name: string, func: TaskFunction): () => void | Promise<void> => {
if (tasks.has(name)) {
throw new Error(`Task "${name}" already registered`);
}
tasks.set(name, {
name,
func,
});
return (): void | Promise<void> => {
return run(name);
};
};
export const run = (name: string = process.argv[2]): void | Promise<void> => {
const task = tasks.get(name);
if (!task) {
logger.error("Task not found.", field("name", name), field("available", Array.from(tasks.keys())));
return process.exit(1);
}
if (activated.has(name)) {
return activated.get(name);
}
let cwd: string = process.cwd();
const log = logger.named(name);
const timer = time(Number.MAX_SAFE_INTEGER);
log.info("Starting...");
const prom = task.func({
set cwd(path: string) {
cwd = path;
},
execute(command: string, args: string[] = [], env?: object): Promise<CommandResult> {
return execute(command, args, {
cwd,
env: env as NodeJS.ProcessEnv,
}, log);
},
});
if (prom) {
activated.set(name, prom);
prom.then(() => {
log.info("Completed!", field("time", timer));
}).catch((ex) => {
activated.delete(name);
log.error(`Failed: ${ex.message}`);
log.error(`Stack: ${ex.stack}`);
return process.exit(1);
});
}
return prom;
};

View File

@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1

16
packages/server/README.md Normal file
View File

@ -0,0 +1,16 @@
# server
## Endpoints
### `/tunnel/<port>`
Tunnels a TCP connection over WebSockets. Implemented for proxying connections from a remote machine locally.
### `/ports`
Watches for open ports. Implemented for tunneling ports on the remote server.
### `/resource/<url>`
Reads files on GET.
Writes files on POST.

View File

@ -18,9 +18,12 @@
"@oclif/plugin-help": "^2.1.4",
"express": "^4.16.4",
"express-static-gzip": "^1.1.3",
"httpolyglot": "^0.1.2",
"mime-types": "^2.1.21",
"nexe": "^2.0.0-rc.34",
"segfault-handler": "^1.0.1",
"node-netstat": "^1.6.0",
"pem": "^1.14.1",
"promise.prototype.finally": "^3.1.0",
"spdlog": "^0.7.2",
"ws": "^6.1.2",
"xhr2": "^0.1.4"
@ -29,6 +32,7 @@
"@types/express": "^4.16.0",
"@types/fs-extra": "^5.0.4",
"@types/mime-types": "^2.1.0",
"@types/pem": "^1.9.4",
"@types/ws": "^6.0.1",
"fs-extra": "^7.0.1",
"string-replace-webpack-plugin": "^0.1.3",

View File

@ -3,57 +3,12 @@ const fse = require("fs-extra");
const os = require("os");
const path = require("path");
const nexe = require("nexe");
const zlib = require("zlib");
const nexeRoot = path.join(os.homedir(), ".nexe");
if (!fs.existsSync(nexeRoot)) {
throw new Error("run nexe manually on a binary to initialize it");
}
const listed = fs.readdirSync(nexeRoot);
listed.forEach((list) => {
if (list.startsWith("linux")) {
const stat = fs.statSync(path.join(nexeRoot, list));
if (stat.isFile()) {
if (stat.size > 20000000) {
throw new Error("must use upx to shrink node binary in ~/.nexe/" + list);
}
}
}
});
const tmpDir = path.join(__dirname, "../build");
if (fs.existsSync(tmpDir)) {
console.log("Removing old build dir...");
fse.removeSync(tmpDir);
}
console.log("Copying build files...");
fse.copySync(path.join(__dirname, "../resources"), tmpDir, {
recursive: true,
});
const modDir = path.join(tmpDir, "modules");
fs.mkdirSync(modDir);
fse.copySync(path.join(__dirname, "../../protocol/node_modules/node-pty/build/Release/pty.node"), path.join(modDir, "pty.node"));
const zipper = (p) => {
const stat = fs.statSync(p);
if (!stat.isDirectory()) {
fs.writeFileSync(p + ".gz", zlib.gzipSync(fs.readFileSync(p)));
fse.removeSync(p);
return;
}
const files = fs.readdirSync(p);
files.forEach((f) => zipper(path.join(p, f)));
};
zipper(path.join(tmpDir, "web"));
zipper(path.join(tmpDir, "bootstrap-fork.js"));
nexe.compile({
debugBundle: true,
input: path.join(__dirname, "../out/cli.js"),
output: 'cli',
targets: ["linux"],
output: `cli-${process.env.TRAVIS_OS_NAME || os.platform()}`,
targets: [os.platform()],
native: {
spdlog: {
additionalFiles: [

View File

@ -6,7 +6,7 @@ import * as os from "os";
import * as path from "path";
import * as WebSocket from "ws";
import { createApp } from "./server";
import { requireModule } from "./vscode/bootstrapFork";
import { requireModule, requireFork } from "./vscode/bootstrapFork";
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
import { setup as setupNativeModules } from "./modules";
import { fillFs } from "./fill";
@ -26,6 +26,8 @@ export class Entry extends Command {
// Dev flags
"bootstrap-fork": flags.string({ hidden: true }),
"fork": flags.string({ hidden: true }),
env: flags.string({ hidden: true }),
args: flags.string({ hidden: true }),
};
@ -76,6 +78,12 @@ export class Entry extends Command {
return requireModule(modulePath, builtInExtensionsDir);
}
if (flags["fork"]) {
const modulePath = flags["fork"];
return requireFork(modulePath, JSON.parse(flags.args!), builtInExtensionsDir);
}
const dataDir = flags["data-dir"] || path.join(os.homedir(), ".vscode-remote");
const workingDir = args["workdir"];
@ -92,6 +100,38 @@ export class Entry extends Command {
const logDir = path.join(dataDir, "logs", new Date().toISOString().replace(/[-:.TZ]/g, ""));
process.env.VSCODE_LOGS = logDir;
const certPath = flags.cert;
const certKeyPath = flags["cert-key"];
if (certPath && !certKeyPath) {
logger.error("'--cert-key' flag is required when specifying a certificate!");
process.exit(1);
}
if (!certPath && certKeyPath) {
logger.error("'--cert' flag is required when specifying certificate key!");
process.exit(1);
}
let certData: Buffer | undefined;
let certKeyData: Buffer | undefined;
if (typeof certPath !== "undefined" && typeof certKeyPath !== "undefined") {
try {
certData = fs.readFileSync(certPath);
} catch (ex) {
logger.error(`Failed to read certificate: ${ex.message}`);
process.exit(1);
}
try {
certKeyData = fs.readFileSync(certKeyPath);
} catch (ex) {
logger.error(`Failed to read certificate key: ${ex.message}`);
process.exit(1);
}
}
logger.info("\u001B[1mvscode-remote v1.0.0");
// TODO: fill in appropriate doc url
logger.info("Additional documentation: https://coder.com/docs");
@ -111,7 +151,9 @@ export class Entry extends Command {
}
});
const app = createApp((app) => {
const password = "023450wf0951";
const hasCustomHttps = certData && certKeyData;
const app = await createApp((app) => {
app.use((req, res, next) => {
res.on("finish", () => {
logger.trace(`\u001B[1m${req.method} ${res.statusCode} \u001B[0m${req.url}`, field("host", req.hostname), field("ip", req.ip));
@ -132,10 +174,13 @@ export class Entry extends Command {
app.use(require("webpack-hot-middleware")(compiler));
}
}, {
builtInExtensionsDirectory: builtInExtensionsDir,
dataDirectory: dataDir,
workingDirectory: workingDir,
});
builtInExtensionsDirectory: builtInExtensionsDir,
dataDirectory: dataDir,
workingDirectory: workingDir,
}, password, hasCustomHttps ? {
key: certKeyData,
cert: certData,
} : undefined);
logger.info("Starting webserver...", field("host", flags.host), field("port", flags.port));
app.server.listen(flags.port, flags.host);
@ -161,7 +206,7 @@ export class Entry extends Command {
}
logger.info(" ");
logger.info("Password:\u001B[1m 023450wf09");
logger.info(`Password:\u001B[1m ${password}`);
logger.info(" ");
logger.info("Started (click the link below to open):");
logger.info(`http://localhost:${flags.port}/`);

View File

@ -49,7 +49,11 @@ export const fillFs = (): void => {
}
};
if (customPromisify) {
(<any>fs[propertyName])[util.promisify.custom] = customPromisify;
(<any>fs[propertyName])[util.promisify.custom] = (...args: any[]) => {
return customPromisify(...args).catch((ex) => {
throw ex;
});
};
}
};
@ -113,13 +117,6 @@ export const fillFs = (): void => {
const fileDesc = fds.get(fd)!;
/**
* `readFile` is filled within nexe, but `read` is not
* https://github.com/nexe/nexe/blob/master/src/fs/patch.ts#L199
* We can simulate a real _read_ by reading the entire file.
* Efficiency can be improved here by storing the entire file in memory
* until it has been closed.
*/
return fs.readFile(fileDesc.path, (err, rb) => {
if (err) {
return callOld();

View File

@ -35,8 +35,10 @@ export const setup = (dataDirectory: string): void => {
*/
unpackModule("pty");
const nodePtyUtils = require("../../protocol/node_modules/node-pty/lib/utils") as typeof import("../../protocol/node_modules/node-pty/src/utils");
nodePtyUtils.loadNative = (modName: string) => {
// tslint:disable-next-line:no-any
nodePtyUtils.loadNative = (modName: string): any => {
return __non_webpack_require__(path.join(dataDirectory, "modules", modName + ".node"));
};
// tslint:disable-next-line:no-unused-expression
require("../../protocol/node_modules/node-pty/lib/index") as typeof import("../../protocol/node_modules/node-pty/src/index");
};

View File

@ -0,0 +1,105 @@
//@ts-ignore
import * as netstat from "node-netstat";
import { Event, Emitter } from "@coder/events";
export interface PortScanner {
readonly ports: ReadonlyArray<number>;
readonly onAdded: Event<ReadonlyArray<number>>;
readonly onRemoved: Event<ReadonlyArray<number>>;
dispose(): void;
}
/**
* Creates a disposable port scanner.
* Will scan local ports and emit events when ports are added or removed.
* Currently only scans TCP ports.
*/
export const createPortScanner = (scanInterval: number = 250): PortScanner => {
const ports = new Map<number, number>();
const addEmitter = new Emitter<number[]>();
const removeEmitter = new Emitter<number[]>();
const scan = (onCompleted: (err?: Error) => void): void => {
const scanTime = Date.now();
const added: number[] = [];
netstat({
done: (err: Error): void => {
const removed: number[] = [];
ports.forEach((value, key) => {
if (value !== scanTime) {
// Remove port
removed.push(key);
ports.delete(key);
}
});
if (removed.length > 0) {
removeEmitter.emit(removed);
}
if (added.length > 0) {
addEmitter.emit(added);
}
onCompleted(err);
},
filter: {
state: "LISTEN",
},
}, (data: {
readonly protocol: string;
readonly local: {
readonly port: number;
readonly address: string;
};
}) => {
// https://en.wikipedia.org/wiki/Registered_port
if (data.local.port <= 1023 || data.local.port >= 49151) {
return;
}
// Only forward TCP ports
if (!data.protocol.startsWith("tcp")) {
return;
}
if (!ports.has(data.local.port)) {
added.push(data.local.port);
}
ports.set(data.local.port, scanTime);
});
};
let lastTimeout: NodeJS.Timer | undefined;
let disposed: boolean = false;
const doInterval = (): void => {
scan(() => {
if (disposed) {
return;
}
lastTimeout = setTimeout(doInterval, scanInterval);
});
};
doInterval();
return {
get ports(): number[] {
return Array.from(ports.keys());
},
get onAdded(): Event<number[]> {
return addEmitter.event;
},
get onRemoved(): Event<number[]> {
return removeEmitter.event;
},
dispose(): void {
if (typeof lastTimeout !== "undefined") {
clearTimeout(lastTimeout);
}
disposed = true;
},
};
};

View File

@ -1,4 +1,4 @@
import { logger } from "@coder/logger";
import { logger, field } from "@coder/logger";
import { ReadWriteConnection } from "@coder/protocol";
import { Server, ServerOptions } from "@coder/protocol/src/node/server";
import * as express from "express";
@ -6,30 +6,116 @@ import * as express from "express";
import * as expressStaticGzip from "express-static-gzip";
import * as fs from "fs";
import * as http from "http";
//@ts-ignore
import * as httpolyglot from "httpolyglot";
import * as https from "https";
import * as mime from "mime-types";
import * as net from "net";
import * as path from "path";
import * as pem from "pem";
import * as util from "util";
import * as ws from "ws";
import { isCli, buildDir } from "./constants";
import { TunnelCloseCode } from "@coder/tunnel/src/common";
import { handle as handleTunnel } from "@coder/tunnel/src/server";
import { createPortScanner } from "./portScanner";
import { buildDir, isCli } from "./constants";
export const createApp = (registerMiddleware?: (app: express.Application) => void, options?: ServerOptions): {
export const createApp = async (registerMiddleware?: (app: express.Application) => void, options?: ServerOptions, password?: string, httpsOptions?: https.ServerOptions): Promise<{
readonly express: express.Application;
readonly server: http.Server;
readonly wss: ws.Server;
} => {
}> => {
const parseCookies = (req: http.IncomingMessage): { [key: string]: string } => {
const cookies: { [key: string]: string } = {};
const rc = req.headers.cookie;
if (rc) {
rc.split(";").forEach((cook) => {
const parts = cook.split("=");
cookies[parts.shift()!.trim()] = decodeURI(parts.join("="));
});
}
return cookies;
};
const isAuthed = (req: http.IncomingMessage): boolean => {
try {
if (!password || !isCli) {
return true;
}
// Try/catch placed here just in case
const cookies = parseCookies(req);
if (cookies.password && cookies.password === password) {
return true;
}
} catch (ex) {
logger.error("Failed to parse cookies", field("error", ex));
}
return false;
};
const isEncrypted = (socket: net.Socket): boolean => {
// tslint:disable-next-line:no-any
return (socket as any).encrypted;
};
const app = express();
if (registerMiddleware) {
registerMiddleware(app);
}
const server = http.createServer(app);
const certs = await new Promise<pem.CertificateCreationResult>((res, rej): void => {
pem.createCertificate({
selfSigned: true,
}, (err, result) => {
if (err) {
rej(err);
return;
}
res(result);
});
});
const server = httpolyglot.createServer({
key: certs.serviceKey,
cert: certs.certificate,
}, app) as http.Server;
const wss = new ws.Server({ server });
wss.shouldHandle = (req): boolean => {
// Should handle auth here
return true;
return isAuthed(req);
};
wss.on("connection", (ws) => {
const portScanner = createPortScanner();
wss.on("connection", (ws, req) => {
if (req.url && req.url.startsWith("/tunnel")) {
try {
const rawPort = req.url.split("/").pop();
const port = Number.parseInt(rawPort!, 10);
handleTunnel(ws, port);
} catch (ex) {
ws.close(TunnelCloseCode.Error, ex.toString());
}
return;
}
if (req.url && req.url.startsWith("/ports")) {
const onAdded = portScanner.onAdded((added) => ws.send(JSON.stringify({ added })));
const onRemoved = portScanner.onRemoved((removed) => ws.send(JSON.stringify({ removed })));
ws.on("close", () => {
onAdded.dispose();
onRemoved.dispose();
});
return ws.send(JSON.stringify({ ports: portScanner.ports }));
}
const connection: ReadWriteConnection = {
onMessage: (cb): void => {
ws.addEventListener("message", (event) => cb(event.data));
@ -52,11 +138,17 @@ export const createApp = (registerMiddleware?: (app: express.Application) => voi
});
const baseDir = buildDir || path.join(__dirname, "..");
if (isCli) {
app.use(expressStaticGzip(path.join(baseDir, "build/web")));
} else {
app.use(express.static(path.join(baseDir, "resources/web")));
}
const authStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/auth"));
const unauthStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/unauth"));
app.use((req, res, next) => {
if (isAuthed(req)) {
// We can serve the actual VSCode bin
authStaticFunc(req, res, next);
} else {
// Serve only the unauthed version
unauthStaticFunc(req, res, next);
}
});
app.get("/resource/:url(*)", async (req, res) => {
try {
const fullPath = `/${req.params.url}`;
@ -91,6 +183,28 @@ export const createApp = (registerMiddleware?: (app: express.Application) => voi
res.end();
}
});
app.post("/resource/:url(*)", async (req, res) => {
try {
const fullPath = `/${req.params.url}`;
const data: string[] = [];
req.setEncoding("utf8");
req.on("data", (chunk) => {
data.push(chunk);
});
req.on("end", () => {
const body = data.join("");
fs.writeFileSync(fullPath, body);
logger.debug("Wrote resource", field("path", fullPath), field("content-length", body.length));
res.status(200);
res.end();
});
} catch (ex) {
res.write(ex.toString());
res.status(500);
res.end();
}
});
return {
express: app,

View File

@ -5,37 +5,104 @@ import * as zlib from "zlib";
import * as vm from "vm";
import { isCli } from "../constants";
let ipcMsgBuffer: Buffer[] | undefined = [];
let ipcMsgListener = process.send ? (d: Buffer): number => ipcMsgBuffer!.push(d) : undefined;
if (ipcMsgListener) {
process.on("message", ipcMsgListener);
}
/**
* Requires a module from the filesystem.
*
* Will load from the CLI if file is included inside of the default extensions dir
*/
// tslint:disable-next-line:no-any
const requireFilesystemModule = (id: string, builtInExtensionsDir: string): any => {
const mod = require("module") as typeof import("module");
const customMod = new mod.Module(id);
customMod.filename = id;
// tslint:disable-next-line:no-any
customMod.paths = [(<any>mod)._nodeModulePaths(path.dirname(id)), path.join(__dirname, "../../../../lib/vscode/node_modules")];
if (id.startsWith(builtInExtensionsDir)) {
customMod.loaded = true;
const fileName = id.endsWith(".js") ? id : `${id}.js`;
const req = vm.runInThisContext(mod.wrap(fs.readFileSync(fileName).toString()), {
displayErrors: true,
filename: id + fileName,
});
req(customMod.exports, customMod.require.bind(customMod), customMod, fileName, path.dirname(id));
return customMod.exports;
}
return customMod.require(id);
};
/**
* Called from forking a module
*/
export const requireFork = (modulePath: string, args: string[], builtInExtensionsDir: string): void => {
const Module = require("module") as typeof import("module");
const oldRequire = Module.prototype.require;
// tslint:disable-next-line:no-any
Module.prototype.require = (id: string): any => {
if (id === "typescript") {
return require("typescript");
}
return oldRequire(id);
};
if (!process.send) {
throw new Error("No IPC messaging initialized");
}
process.argv = ["", "", ...args];
requireFilesystemModule(modulePath, builtInExtensionsDir);
if (ipcMsgBuffer && ipcMsgListener) {
process.removeListener("message", ipcMsgListener);
// tslint:disable-next-line:no-any
ipcMsgBuffer.forEach((i) => process.emit("message" as any, i as any));
ipcMsgBuffer = undefined;
ipcMsgListener = undefined;
}
};
export const requireModule = (modulePath: string, builtInExtensionsDir: string): void => {
process.env.AMD_ENTRYPOINT = modulePath;
const xml = require("xhr2");
xml.XMLHttpRequest.prototype._restrictedHeaders["user-agent"] = false;
// tslint:disable-next-line no-any this makes installing extensions work.
(global as any).XMLHttpRequest = xml.XMLHttpRequest;
const mod = require("module") as typeof import("module");
const promiseFinally = require("promise.prototype.finally") as { shim: () => void };
promiseFinally.shim();
/**
* Used for loading extensions. Using __non_webpack_require__ didn't work
* as it was not resolving to the FS.
*/
(global as any).nativeNodeRequire = (id: string): any => {// tslint:disable-line no-any
const customMod = new mod.Module(id);
customMod.filename = id;
// tslint:disable-next-line no-any
customMod.paths = (mod as any)._nodeModulePaths(path.dirname(id));
if (id.startsWith(builtInExtensionsDir)) {
customMod.loaded = true;
const req = vm.runInThisContext(mod.wrap(fs.readFileSync(id + ".js").toString()), {
displayErrors: true,
filename: id + ".js",
});
req(customMod.exports, customMod.require.bind(customMod), customMod, __filename, path.dirname(id));
return customMod.exports;
}
return customMod.require(id);
// tslint:disable-next-line:no-any
(global as any).nativeNodeRequire = (id: string): any => {
return requireFilesystemModule(id, builtInExtensionsDir);
};
if (isCli) {
/**
* Needed for properly forking external modules within the CLI
*/
// tslint:disable-next-line:no-any
(<any>cp).fork = (modulePath: string, args: ReadonlyArray<string> = [], options?: cp.ForkOptions): cp.ChildProcess => {
return cp.spawn(process.execPath, ["--fork", modulePath, "--args", JSON.stringify(args)], {
...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));
@ -43,7 +110,7 @@ export const requireModule = (modulePath: string, builtInExtensionsDir: string):
if (isCli) {
content = zlib.gunzipSync(readFile("bootstrap-fork.js.gz"));
} else {
content = readFile("../resources/bootstrap-fork.js");
content = readFile("../../vscode/bin/bootstrap-fork.js");
}
eval(content.toString());
};
@ -71,7 +138,7 @@ export const forkModule = (modulePath: string, args: string[], options: cp.ForkO
stdio: [null, null, null, "ipc"],
};
if (isCli) {
proc = cp.execFile(process.execPath, forkArgs, forkOptions);
proc = cp.spawn(process.execPath, forkArgs, options);
} else {
proc = cp.spawn(process.execPath, ["--require", "ts-node/register", "--require", "tsconfig-paths/register", process.argv[1], ...forkArgs], forkOptions);
}

View File

@ -129,6 +129,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/pem@^1.9.4":
version "1.9.4"
resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.4.tgz#9ef9302dc5f0352503e193003b208cddef4ffa45"
integrity sha512-cLRUgpedqF4lnQxDsjbRCgHRPHaJvnsHC+LEBTKnChddoPYJYQMq/LjSsEDwvRteeJV8MGt7Ea9jYCBVufrcNg==
dependencies:
"@types/node" "*"
"@types/range-parser@*":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
@ -430,13 +437,6 @@ 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.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.4.0.tgz#909efa49f2ebe07ecd3cb136778f665052040127"
integrity sha512-7znEVX22Djn+nYjxCWKDne0RRloa9XfYa84yk3s+HkE3LpDYZmhArYr9O9huBoHY3/oXispx5LorIX7Sl2CgSQ==
dependencies:
file-uri-to-path "1.0.0"
bindings@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5"
@ -624,6 +624,11 @@ chardet@^0.4.0:
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"
@ -800,6 +805,11 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
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"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
css-loader@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.9.1.tgz#2e1aa00ce7e30ef2c6a7a4b300a080a7c979e0dc"
@ -915,6 +925,13 @@ deepmerge@^2.0.1:
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
define-properties@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
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"
@ -1019,6 +1036,32 @@ end-of-stream@^1.0.0:
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"
integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==
dependencies:
es-to-primitive "^1.2.0"
function-bind "^1.1.1"
has "^1.0.3"
is-callable "^1.1.4"
is-regex "^1.0.4"
object-keys "^1.0.12"
es-to-primitive@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==
dependencies:
is-callable "^1.1.4"
is-date-object "^1.0.1"
is-symbol "^1.0.2"
es6-promisify@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6"
integrity sha512-J3ZkwbEnnO+fGAKrjVpeUAnZshAdfZvbhQpqfIH9kSAspReRC4nJnu8ewm55b4y9ElyeuhCTzJD0XiH8Tsbhlw==
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -1279,11 +1322,6 @@ file-type@^6.1.0:
resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919"
integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@ -1429,6 +1467,11 @@ fsevents@^1.0.0:
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.6.0"
resolved "https://registry.yarnpkg.com/fuse-box/-/fuse-box-3.6.0.tgz#a4adf41a60855c7b0a0775b3095b6b0c2d35b011"
@ -1645,6 +1688,11 @@ has-symbol-support-x@^1.4.1:
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"
@ -1688,6 +1736,13 @@ has-values@^1.0.0:
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"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
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"
@ -1712,6 +1767,11 @@ http-signature@~1.2.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"
integrity sha1-5NNH/omEpi9GfUBg31J/GFH2mXs=
iconv-lite@0.4.23:
version "0.4.23"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
@ -1815,11 +1875,16 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
is-buffer@^1.1.5:
is-buffer@^1.1.5, 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==
is-callable@^1.1.4:
version "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"
@ -1834,6 +1899,11 @@ is-data-descriptor@^1.0.0:
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"
@ -1956,6 +2026,13 @@ is-promise@^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"
integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
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"
@ -1966,6 +2043,13 @@ is-stream@^1.0.0, is-stream@^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"
integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
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"
@ -1976,11 +2060,21 @@ is-windows@^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"
@ -2192,6 +2286,15 @@ math-random@^1.0.1:
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"
integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
dependencies:
charenc "~0.0.1"
crypt "~0.0.1"
is-buffer "~1.1.1"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -2344,7 +2447,7 @@ mute-stream@0.0.7:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
nan@^2.0.9, nan@^2.8.0, 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==
@ -2406,6 +2509,13 @@ nexe@^2.0.0-rc.34:
uglify-es "^3.3.9"
uglify-js "3.0.28"
node-netstat@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/node-netstat/-/node-netstat-1.6.0.tgz#38c36b5f966b00ffaa2ed6f6321e6ad4487d8c89"
integrity sha512-KPDopkvPllhcILoHMWYUxvOO5c+VcPB38LxlOFPiZhZ/hJTMH/GXGCs6nvxu4d6unwsbEfgzJ4pPye3CFv9yTg==
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"
@ -2501,6 +2611,11 @@ object-copy@^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"
@ -2576,7 +2691,7 @@ os-homedir@^1.0.0:
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.2:
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
@ -2660,6 +2775,16 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
pem@^1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.1.tgz#8ff3c5884bfcba7bbdfea5b67a7fa24b4ca3bb86"
integrity sha512-WY3IzMoh+Gwp4xJTT2MqIOaVzNqU7jHqj7k0pOnLIkNSnOpjhy3PHr9mXGi+C5tRC2z1EX5lvzEbd9BtHumHLQ==
dependencies:
es6-promisify "^6.0.0"
md5 "^2.2.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"
@ -2744,6 +2869,15 @@ process-nextick-args@~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"
integrity sha512-7p/K2f6dI+dM8yjRQEGrTQs5hTQixUAdOGpMEA3+pVxpX5oHKRSKAXyLw9Q9HUWDTdwtoo39dSHGQtN90HcEwQ==
dependencies:
define-properties "^1.1.2"
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"
@ -3022,14 +3156,6 @@ seek-bzip@^1.0.5:
dependencies:
commander "~2.8.1"
segfault-handler@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/segfault-handler/-/segfault-handler-1.0.1.tgz#9466d8f77d8826cfbdfa811124ece02983fd6ad2"
integrity sha512-3koBV3F0IPxTYacnoL7WoFlaMndXsXj62tiVbbW9Kzp3K+F9Y6GWW5XmKSv7j+7nf2M+qjNzc4W1iZoa8vocjw==
dependencies:
bindings "^1.2.1"
nan "^2.0.9"
semver@^5.3.0, semver@^5.6.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
@ -3668,6 +3794,13 @@ watch@^1.0.1:
exec-sh "^0.2.0"
minimist "^1.2.0"
which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
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"

View File

@ -0,0 +1,4 @@
{
"name": "@coder/tunnel",
"main": "src/tunnel.ts"
}

View File

@ -0,0 +1,48 @@
import { Event, Emitter } from "@coder/events";
import { TunnelCloseCode } from "./common";
export interface TunnelCloseEvent {
readonly code: TunnelCloseCode;
readonly reason: string;
}
export interface ClientConnection {
readonly onData: Event<ArrayBuffer>;
readonly onClose: Event<TunnelCloseEvent>;
send(data: ArrayBuffer): void;
}
export const forward = (connectionUrl: string): Promise<ClientConnection> => {
return new Promise((resolve, reject): void => {
const socket = new WebSocket(connectionUrl);
const closeEmitter = new Emitter<TunnelCloseEvent>();
const dataEmitter = new Emitter<ArrayBuffer>();
const connection: ClientConnection = {
get onClose(): Event<TunnelCloseEvent> {
return closeEmitter.event;
},
get onData(): Event<ArrayBuffer> {
return dataEmitter.event;
},
send(data: ArrayBuffer): void {
socket.send(data);
},
};
socket.binaryType = "arraybuffer";
socket.addEventListener("message", (event) => {
dataEmitter.emit(event.data);
});
socket.addEventListener("error", (event) => {
reject("uncertain");
});
socket.addEventListener("open", () => {
resolve(connection);
});
socket.addEventListener("close", (event) => {
closeEmitter.emit({
code: event.code,
reason: event.reason,
});
});
});
};

View File

@ -0,0 +1,5 @@
export enum TunnelCloseCode {
Normal = 1000,
Error = 4000,
ConnectionRefused = 4001,
}

View File

@ -0,0 +1,53 @@
import * as net from "net";
import { TunnelCloseCode } from "./common";
export interface WS {
addEventListener(event: "message", cb: (event: {
// tslint:disable-next-line:no-any
readonly data: any;
}) => void): void;
addEventListener(event: "close", cb: () => void): void;
binaryType: string;
close(code: number, reason?: string): void;
// tslint:disable-next-line:no-any
send(data: any): void;
}
export const handle = async (socket: WS, port: number): Promise<void> => {
const hosts = [
"127.0.0.1",
"::", // localhost
];
let localSocket: net.Socket | undefined;
for (let i = 0; i < hosts.length; i++) {
if (localSocket) {
break;
}
localSocket = await new Promise((resolve, reject): void => {
const socket = net.connect({
host: hosts[i],
port,
}, () => {
// Connected
resolve(socket);
});
socket.on("error", (err: Error & { readonly code: string }) => {
if (err.code === "ECONNREFUSED") {
resolve(undefined);
}
});
});
}
if (!localSocket) {
socket.close(TunnelCloseCode.ConnectionRefused);
return;
}
socket.binaryType = "arraybuffer";
socket.addEventListener("message", (event) => localSocket!.write(Buffer.from(event.data)));
socket.addEventListener("close", () => localSocket!.end());
localSocket.on("data", (data) => socket.send(data));
localSocket.on("error", (err) => socket.close(TunnelCloseCode.Error, err.toString()));
localSocket.on("close", () => socket.close(TunnelCloseCode.Normal));
};

View File

@ -2,6 +2,7 @@ import * as paths from "./fill/paths";
import "./fill/platform";
import "./fill/storageDatabase";
import "./fill/windowsService";
import "./fill/workspacesService";
import "./fill/environmentService";
import "./fill/vscodeTextmate";
import "./fill/codeEditor";
@ -17,13 +18,14 @@ import { LogLevel } from "vs/platform/log/common/log";
import { URI } from "vs/base/common/uri";
import { INotificationService } from "vs/platform/notification/common/notification";
import { IProgressService2, ProgressLocation } from "vs/platform/progress/common/progress";
import { ExplorerItem, Model } from "vs/workbench/parts/files/common/explorerModel";
import { ExplorerItem, ExplorerModel } from "vs/workbench/parts/files/common/explorerModel";
import { DragMouseEvent } from "vs/base/browser/mouseEvent";
import { IEditorService, IResourceEditor } from "vs/workbench/services/editor/common/editorService";
import { IEditorGroup } from "vs/workbench/services/group/common/editorGroupsService";
import { IWindowsService } from "vs/platform/windows/common/windows";
import { IWindowsService, IWindowConfiguration } from "vs/platform/windows/common/windows";
import { ServiceCollection } from "vs/platform/instantiation/common/serviceCollection";
import { RawContextKey, IContextKeyService } from "vs/platform/contextkey/common/contextkey";
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
export class Client extends IdeClient {
private readonly windowId = parseInt(new Date().toISOString().replace(/[-:.TZ]/g, ""), 10);
@ -39,7 +41,7 @@ export class Client extends IdeClient {
return this._builtInExtensionsDirectory;
}
public async handleExternalDrop(target: ExplorerItem | Model, originalEvent: DragMouseEvent): Promise<void> {
public async handleExternalDrop(target: ExplorerItem | ExplorerModel, originalEvent: DragMouseEvent): Promise<void> {
await this.upload.uploadDropped(
originalEvent.browserEvent as DragEvent,
(target instanceof ExplorerItem ? target : target.roots[0]).resource,
@ -93,6 +95,25 @@ export class Client extends IdeClient {
return new PasteAction();
}
public set workspace(ws: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | undefined) {
if (typeof ws === "undefined") {
window.localStorage.removeItem("workspace");
} else {
window.localStorage.setItem("workspace", JSON.stringify(ws));
}
location.reload();
}
public get workspace(): undefined | IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier {
const ws = window.localStorage.getItem("workspace");
try {
return JSON.parse(ws!);
} catch (ex) {
return undefined;
}
}
public get serviceCollection(): ServiceCollection {
if (!this._serviceCollection) {
throw new Error("Trying to access service collection before it has been set");
@ -162,8 +183,9 @@ export class Client extends IdeClient {
this._builtInExtensionsDirectory = data.builtInExtensionsDirectory;
process.env.SHELL = data.shell;
const { startup } = require("./startup");
await startup({
const workspace = this.workspace || URI.file(data.workingDirectory);
const { startup } = require("./startup") as typeof import("vs/workbench/electron-browser/main");
const config: IWindowConfiguration = {
machineId: "1",
windowId: this.windowId,
logLevel: LogLevel.Info,
@ -174,9 +196,13 @@ export class Client extends IdeClient {
nodeCachedDataDir: data.tmpDirectory,
perfEntries: [],
_: [],
folderUri: URI.file(data.workingDirectory),
});
};
if ((workspace as IWorkspaceIdentifier).configPath) {
config.workspace = workspace as IWorkspaceIdentifier;
} else {
config.folderUri = workspace as URI;
}
await startup(config);
const contextKeys = this.serviceCollection.get(IContextKeyService) as IContextKeyService;
const bounded = this.clipboardContextKey.bindTo(contextKeys);
this.clipboard.onPermissionChange((enabled) => {

View File

@ -0,0 +1,146 @@
.dialog {
--primary: #2A2E37;
--border: black;
--faded: #a0a1a5;
--header-background: #161616;
--header-foreground: white;
--list-active-selection-background: rgb(0, 120, 160);
--list-active-selection-foreground: white;
--list-hover-background: rgb(36, 39, 46);
font-family: inherit;
box-shadow: 0 18px 80px 10px rgba(0, 0, 0, 0.1);
background-color: var(--primary);
display: flex;
flex-direction: column;
user-select: none;
overflow: hidden;
border-radius: 5px;
.monaco-tl-twistie {
display: none;
}
.title {
background-color: var(--header-background);
color: var(--header-foreground);
padding: 1px;
font-size: 11px;
font-weight: normal;
text-transform: uppercase;
white-space: nowrap;
padding-left: 10px;
}
.nav {
display: flex;
flex-direction: row;
padding: 4px;
padding-top: 8px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
min-height: 32px;
}
.path {
display: flex;
flex-direction: row;
.path-part {
padding: 5px;
border-radius: 3px;
font-size: 1.2em;
cursor: pointer;
&:not(:first-child) {
margin-left: 5px;
}
&.active {
font-weight: bold;
color: var(--list-active-selection-foreground);
}
}
}
.file-area {
flex: 1;
display: flex;
flex-direction: column;
.dialog-grid {
display: grid;
grid-template-columns: 2fr 0.2fr 0.8fr;
}
.headings {
padding: 8px;
font-size: 12px;
}
.dialog-entry {
cursor: pointer;
font-size: 1.2em;
padding: 0px;
padding-left: 8px;
padding-right: 8px;
.dialog-entry-info {
display: flex;
flex-direction: row;
}
.dialog-entry-icon {
width: 16px;
height: 19px;
display: inline-block;
margin-right: 5px;
margin-bottom: -3px;
}
&:hover {
background-color: var(--list-hover-background);
}
&.active {
background-color: var(--list-active-selection-background);
color: var(--list-active-selection-foreground);
}
}
}
.buttons {
display: flex;
flex-direction: row;
padding: 10px;
position: relative;
background: var(--primary);
border-top: 1px solid var(--border);
button:first-child {
margin-left: auto;
margin-right: 10px;
}
button {
background: transparent;
outline: none;
border: 0;
color: var(--faded);
padding: 10px;
padding-left: 18px;
padding-right: 18px;
transition: 150ms background ease, 150ms color ease;
cursor: pointer;
border-radius: 5px;
&:hover {
background: var(--titlebar);
color: white;
}
}
}
}
.monaco-shell .monaco-tree.focused.no-focused-item:focus:before, .monaco-shell .monaco-list:not(.element-focused):focus:before {
display: none;
}

View File

@ -0,0 +1,471 @@
import { Emitter, Event } from "@coder/events";
import { client as ideClient } from "@coder/ide/src/fill/client";
import { client } from "@coder/vscode/src/client";
import * as fs from "fs";
import * as path from "path";
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";
import { ITreeElement, ITreeNode, ITreeRenderer, TreeFilterResult, TreeVisibility } from "vs/base/browser/ui/tree/tree";
import { KeyCode } from "vs/base/common/keyCodes";
import { URI } from "vs/base/common/uri";
import { getIconClasses } from "vs/editor/common/services/getIconClasses";
import { IModelService } from "vs/editor/common/services/modelService";
import { IModeService } from "vs/editor/common/services/modeService";
import { FileKind } from "vs/platform/files/common/files";
import "./dialog.scss";
import { IThemeService } from "vs/platform/theme/common/themeService";
declare var __non_webpack_require__: typeof require;
export enum DialogType {
NewFolder,
Save,
Open,
}
export interface CommonDialogOptions {
readonly title?: string;
readonly defaultPath?: string;
readonly buttonLabel?: string;
}
export interface OpenDialogOptions extends CommonDialogOptions {
readonly properties: {
readonly openFile: true;
readonly openDirectory?: boolean;
readonly showHiddenFiles?: boolean;
} | {
readonly openDirectory: true;
readonly showHiddenFiles?: boolean;
readonly openFile?: boolean;
};
}
export interface SaveDialogOptions extends CommonDialogOptions {
readonly type: DialogType.Save;
readonly nameFieldLabel?: string;
}
export type DialogOptions = OpenDialogOptions | SaveDialogOptions;
export const showOpenDialog = (options: OpenDialogOptions): Promise<string> => {
return new Promise<string>((resolve, reject): void => {
const dialog = new Dialog(DialogType.Open, options);
dialog.onSelect((e) => {
dialog.dispose();
resolve(e);
});
dialog.onError((e) => {
dialog.dispose();
reject(e);
});
});
};
interface DialogEntry {
readonly fullPath: string;
readonly name: string;
readonly isDirectory: boolean;
readonly size: number;
readonly lastModified: string;
}
class Dialog {
private _path: string | undefined;
private static readonly UpperDirId = "..";
private readonly filesNode: HTMLElement;
private readonly pathNode: HTMLElement;
private readonly entryList: ObjectTree<DialogEntry, string>;
private readonly background: HTMLElement;
private readonly root: HTMLElement;
private readonly selectEmitter: Emitter<string>;
private readonly errorEmitter: Emitter<Error>;
public constructor(
private readonly type: DialogType,
private readonly options: DialogOptions,
) {
this.selectEmitter = new Emitter();
this.errorEmitter = new Emitter();
this.background = document.createElement("div");
this.background.style.position = "absolute";
this.background.style.top = "0";
this.background.style.left = "0";
this.background.style.bottom = "0";
this.background.style.right = "0";
this.background.style.zIndex = "5";
this.background.style.display = "flex";
this.background.style.alignItems = "center";
this.background.style.justifyContent = "center";
this.background.style.background = "rgba(0, 0, 0, 0.25)";
this.root = document.createElement("div");
this.root.style.width = "850px";
this.root.style.height = "600px";
this.background.appendChild(this.root);
document.body.appendChild(this.background);
this.root.classList.add("dialog");
const setProperty = (vari: string, id: string): void => {
const getColor = (id: string): string | undefined => {
const ts = client.serviceCollection.get<IThemeService>(IThemeService) as IThemeService;
const c = ts.getTheme().getColor(id);
if (!c) {
return;
}
return c.toString();
};
const c = getColor(id);
if (c) {
this.root.style.setProperty(vari, c);
}
};
setProperty("--primary", "sideBar.background");
setProperty("--list-active-selection-background", "list.activeSelectionBackground");
setProperty("--list-active-selection-foreground", "list.activeSelectionForeground");
setProperty("--list-hover-background", "list.hoverBackground");
setProperty("--header-background", "sideBarSectionHeader.background");
setProperty("--header-foreground", "sideBarSectionHeader.foreground");
setProperty("--border", "panel.border");
this.background.addEventListener("contextmenu", (event) => {
event.preventDefault();
});
const titleNode = document.createElement("div");
titleNode.classList.add("title");
let title: string | undefined;
switch (this.type) {
// case DialogType.NewFolder:
// title = "New Folder";
// break;
case DialogType.Open:
title = "Open File";
break;
case DialogType.Save:
title = "Save File";
break;
default:
throw new Error("Uncased type");
}
titleNode.innerText = options.title || title;
this.root.appendChild(titleNode);
const navItems = document.createElement("div");
navItems.classList.add("nav");
this.pathNode = document.createElement("div");
this.pathNode.classList.add("path");
navItems.appendChild(this.pathNode);
this.root.appendChild(navItems);
const fileAreaNode = document.createElement("div");
fileAreaNode.classList.add("file-area");
fileAreaNode.classList.add("show-file-icons");
const headingsNode = document.createElement("div");
headingsNode.className = "headings dialog-grid";
["Name", "Size", "Last Modified"].forEach(e => {
const header = document.createElement("div");
header.innerText = e;
headingsNode.appendChild(header);
});
this.filesNode = document.createElement("div");
this.filesNode.className = "files-list";
fileAreaNode.appendChild(headingsNode);
this.entryList = new ObjectTree<DialogEntry, string>(this.filesNode, {
getHeight: (entry: DialogEntry): number => {
return 20;
},
getTemplateId: (entry: DialogEntry): string => {
return "dialog-entry";
},
}, [new DialogEntryRenderer()], {
openController: {
shouldOpen: (event): boolean => {
return true;
},
},
keyboardNavigationLabelProvider: {
getKeyboardNavigationLabel: (element): string => {
return element.name;
},
mightProducePrintableCharacter: (event): boolean => {
if (event.ctrlKey || event.metaKey) {
// ignore ctrl/cmd-combination but not shift/alt-combinatios
return false;
}
// weak check for certain ranges. this is properly implemented in a subclass
// with access to the KeyboardMapperFactory.
if ((event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z)
|| (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9)
|| event.keyCode === KeyCode.US_DOT || event.keyCode === KeyCode.US_SLASH || event.keyCode === KeyCode.US_MINUS) {
return true;
}
return false;
},
},
automaticKeyboardNavigation: true,
enableKeyboardNavigation: true,
multipleSelectionSupport: false,
openOnSingleClick: false,
filter: {
filter: (): TreeFilterResult<string> => {
// tslint:disable-next-line:no-any
(<any>this.entryList)._options.simpleKeyboardNavigation = true;
// tslint:disable-next-line:no-any
const pat = (<any>this.entryList).typeFilterController.filter._pattern;
return {
data: pat,
visibility: TreeVisibility.Visible,
};
},
},
filterOnType: true,
});
// tslint:disable-next-line:no-any
(<any>this.entryList).focusNavigationFilter = (node: ITreeNode<DialogEntry, string>): boolean => {
if (node.filterData) {
return node.element.name.toLowerCase().startsWith(node.filterData.toLowerCase()!);
}
return false;
};
this.entryList.onDidOpen((event) => {
const element = event.elements[0]!;
if (!element) {
const fv = this.filterValue;
if (fv === Dialog.UpperDirId) {
this.path = path.dirname(this._path!);
}
if (fv.startsWith("/")) {
fs.stat(fv, (err, stats) => {
if (err) {
return;
}
if (stats.isDirectory()) {
this.path = fv;
}
});
}
return;
}
if (element.isDirectory) {
this.path = element.fullPath;
} else {
// Open
this.selectEmitter.emit(element.fullPath);
}
});
fileAreaNode.appendChild(this.entryList.getHTMLElement());
this.root.appendChild(fileAreaNode);
const buttonsNode = document.createElement("div");
buttonsNode.className = "buttons";
const cancelBtn = document.createElement("button");
cancelBtn.innerText = "Cancel";
cancelBtn.addEventListener("click", () => {
this.errorEmitter.emit(new Error("Cancelled"));
});
buttonsNode.appendChild(cancelBtn);
const confirmBtn = document.createElement("button");
confirmBtn.innerText = "Confirm";
confirmBtn.addEventListener("click", () => {
if (this._path) {
this.selectEmitter.emit(this._path);
}
});
buttonsNode.appendChild(confirmBtn);
this.root.appendChild(buttonsNode);
this.entryList.layout();
this.path = options.defaultPath || "/";
}
public get onSelect(): Event<string> {
return this.selectEmitter.event;
}
public get onError(): Event<Error> {
return this.errorEmitter.event;
}
public dispose(): void {
this.selectEmitter.dispose();
this.errorEmitter.dispose();
this.entryList.dispose();
this.background.remove();
}
private buildPath(): void {
while (this.pathNode.lastChild) {
this.pathNode.removeChild(this.pathNode.lastChild);
}
if (!this._path) {
throw new Error("cannot build path node without valid path");
}
const pathParts = ["", ...this._path.split("/").filter((p) => p.length > 0)];
for (let i = 0; i < pathParts.length; i++) {
const pathPartNode = document.createElement("div");
pathPartNode.classList.add("path-part");
pathPartNode.innerText = pathParts[i].length > 0 ? pathParts[i] : "/";
if (i === pathParts.length - 1) {
pathPartNode.classList.add("active");
}
pathPartNode.addEventListener("click", () => {
this.path = "/" + pathParts.slice(0, i + 1).join("/");
});
this.pathNode.appendChild(pathPartNode);
}
}
private set path(directory: string) {
const ts = Date.now();
this.list(directory).then((value) => {
this._path = directory;
this.buildPath();
while (this.filesNode.lastChild) {
this.filesNode.removeChild(this.filesNode.lastChild);
}
const items = value.filter((v) => {
if (v.name.startsWith(".")) {
const props = (this.options as OpenDialogOptions).properties;
if (props && props.showHiddenFiles) {
return true;
}
return false;
}
return true;
});
this.entryList.setChildren(null, items.map((i: DialogEntry): ITreeElement<DialogEntry> => ({ element: i })));
this.entryList.domFocus();
this.entryList.setFocus([null]);
// Clears the input on refresh
// tslint:disable-next-line:no-any
(<any>this.entryList).typeFilterController.onInput("");
}).catch((ex) => {
this.errorEmitter.emit(ex);
});
}
private get filterValue(): string {
// tslint:disable-next-line:no-any
return (<any>this.entryList).typeFilterController.filter._pattern;
}
private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> {
return ideClient.evaluate((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");
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);
}
}
interface DialogEntryData {
icon: HTMLElement;
size: HTMLElement;
lastModified: HTMLElement;
label: HighlightedLabel;
}
class DialogEntryRenderer implements ITreeRenderer<DialogEntry, string, DialogEntryData> {
public get templateId(): string {
return "dialog-entry";
}
public renderTemplate(container: HTMLElement): DialogEntryData {
addClass(container, "dialog-entry");
addClass(container, "dialog-grid");
const wrapper = append(container, $(".dialog-entry-info"));
const icon: HTMLElement = append(wrapper, $("div"));
const name = append(wrapper, $(".dialog-entry-name"));
const label = new HighlightedLabel(name, false);
append(container, wrapper);
const size = append(container, $(".dialog-entry-size"));
const mtime = append(container, $(".dialog-entry-mtime"));
return {
icon,
size,
lastModified: mtime,
label,
};
}
public renderElement(node: ITreeNode<DialogEntry, string>, index: number, templateData: DialogEntryData): void {
templateData.icon.className = "dialog-entry-icon monaco-icon-label";
const classes = getIconClasses(
client.serviceCollection.get<IModelService>(IModelService) as IModelService,
client.serviceCollection.get<IModeService>(IModeService) as IModeService,
URI.file(node.element.name),
node.element.isDirectory ? FileKind.FOLDER : FileKind.FILE,
);
templateData.icon.hidden = classes.length === 0;
classes.forEach((c) => {
try {
templateData.icon.classList.add(c);
} catch (ex) {
// Nothin needed. Sometimes bad classes are given
}
});
templateData.label.set(node.element.name, typeof node.filterData === "string" && node.element.name.toLowerCase().startsWith(node.filterData.toLowerCase()) ? [{
start: 0,
end: node.filterData.length,
}] : []);
templateData.size.innerText = node.element.size.toString();
templateData.lastModified.innerText = node.element.lastModified;
}
public disposeTemplate(templateData: DialogEntryData): void {
// throw new Error("Method not implemented.");
}
}

View File

@ -1,7 +1,7 @@
import { logger } from "@coder/logger";
import { IDisposable } from "vs/base/common/lifecycle";
import * as actions from "vs/platform/actions/common/actions";
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions";
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions/developerActions";
// Intercept appending menu items so we can skip items that won't work.
const originalAppend = actions.MenuRegistry.appendMenuItem.bind(actions.MenuRegistry);

View File

@ -1,4 +1,4 @@
import { readFile, writeFile } from "fs";
import { readFile, writeFile, mkdir } from "fs";
import * as path from "path";
import { promisify } from "util";
import { IDisposable } from "@coder/disposable";
@ -7,6 +7,8 @@ import * as workspaceStorage from "vs/base/node/storage";
import * as globalStorage from "vs/platform/storage/node/storageIpc";
import * as paths from "./paths";
import { logger, field } from "@coder/logger";
import { client } from "@coder/vscode/src/client";
import { IStorageService, WillSaveStateReason } from "vs/platform/storage/common/storage";
class StorageDatabase implements workspaceStorage.IStorageDatabase {
public readonly onDidChangeItemsExternal = Event.None;
@ -20,11 +22,9 @@ class StorageDatabase implements workspaceStorage.IStorageDatabase {
if (!navigator.sendBeacon) {
throw new Error("cannot save state");
}
// TODO: Need to use navigator.sendBeacon instead of the web socket, or we
// need to save when there is a change. Should we save as a sqlite3
// database instead of JSON? Could send to the server the way the global
// storage works. Or maybe fill `vscode-sqlite3` to do that.
this.save();
this.triggerFlush(WillSaveStateReason.SHUTDOWN);
navigator.sendBeacon(`/resource${this.path}`, this.content);
});
}
@ -58,7 +58,7 @@ class StorageDatabase implements workspaceStorage.IStorageDatabase {
request.delete.forEach(key => this.items.delete(key));
}
return Promise.resolve();
return this.save();
}
public close(): Promise<void> {
@ -69,13 +69,38 @@ class StorageDatabase implements workspaceStorage.IStorageDatabase {
return Promise.resolve("ok");
}
private save(): Promise<void> {
private async save(): Promise<void> {
try {
await promisify(mkdir)(path.dirname(this.path));
} catch (ex) {}
return promisify(writeFile)(this.path, this.content);
}
private triggerFlush(reason: WillSaveStateReason = WillSaveStateReason.NONE): boolean {
// tslint:disable-next-line:no-any
const storageService = client.serviceCollection.get<IStorageService>(IStorageService) as any;
if (reason === WillSaveStateReason.SHUTDOWN && storageService.close) {
storageService.close();
return true;
}
if (storageService._onWillSaveState) {
storageService._onWillSaveState.fire({ reason });
return true;
}
return false;
}
private get content(): string {
const json: { [key: string]: string } = {};
this.items.forEach((value, key) => {
json[key] = value;
});
return promisify(writeFile)(this.path, JSON.stringify(json));
return JSON.stringify(json);
}
}

View File

@ -1,13 +1,14 @@
import * as electron from "electron";
import { Emitter } from "@coder/events";
import * as windowsIpc from "vs/platform/windows/node/windowsIpc";
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions } from "vs/platform/windows/common/windows";
import { IWindowsService, INativeOpenDialogOptions, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IMessageBoxResult, IDevToolsOptions, IEnterWorkspaceResult, CrashReporterStartOptions, INewWindowOptions, IOpenFileRequest, IAddFoldersRequest } from "vs/platform/windows/common/windows";
import { ParsedArgs } from "vs/platform/environment/common/environment";
import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
import { URI } from "vs/base/common/uri";
import { IRecentlyOpened } from "vs/platform/history/common/history";
import { ISerializableCommandAction } from "vs/platform/actions/common/actions";
import { client } from "../client";
import { showOpenDialog } from "../dialog";
/**
* Instead of going to the shared process, we'll directly run these methods on
@ -34,20 +35,70 @@ class WindowsService implements IWindowsService {
private readonly window = new electron.BrowserWindow();
// Dialogs
public pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
throw new Error("not implemented");
public async pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
showOpenDialog({
...(_options.dialogOptions || {}),
properties: {
openFile: true,
openDirectory: true,
},
}).then((path) => {
// tslint:disable-next-line:no-any
(<any>electron.ipcMain).send("vscode:openFiles", {
filesToOpen: [{
fileUri: URI.file(path),
}],
} as IOpenFileRequest);
}).catch((ex) => {
//
});
}
public pickFileAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
throw new Error("not implemented");
public async pickFileAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
showOpenDialog({
...(_options.dialogOptions || {}),
properties: {
openFile: true,
},
}).then((path) => {
// tslint:disable-next-line:no-any
(<any>electron.ipcMain).send("vscode:openFiles", {
filesToOpen: [{
fileUri: URI.file(path),
}],
} as IOpenFileRequest);
}).catch((ex) => {
//
});
}
public pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
throw new Error("not implemented");
public async pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
showOpenDialog({
...(_options.dialogOptions || {}),
properties: {
openDirectory: true,
},
}).then((path) => {
client.workspace = URI.file(path);
}).catch((ex) => {
//
});
}
public pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
throw new Error("not implemented");
public async pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise<void> {
showOpenDialog({
...(_options.dialogOptions || {}),
properties: {
openDirectory: true,
},
}).then((path) => {
// tslint:disable-next-line:no-any
(<any>electron.ipcMain).send("vscode:addFolders", {
foldersToAdd: [URI.file(path)],
} as IAddFoldersRequest);
}).catch((ex) => {
//
});
}
public showMessageBox(windowId: number, options: MessageBoxOptions): Promise<IMessageBoxResult> {
@ -70,10 +121,14 @@ class WindowsService implements IWindowsService {
}
public showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<string[]> {
return new Promise((resolve): void => {
electron.dialog.showOpenDialog(this.getWindowById(windowId), options, (filePaths, _bookmarks) => {
resolve(filePaths);
});
return showOpenDialog({
...(options || {}),
properties: {
openDirectory: true,
openFile: true,
},
}).then((path) => {
return [path];
});
}
@ -93,8 +148,17 @@ class WindowsService implements IWindowsService {
throw new Error("not implemented");
}
public enterWorkspace(_windowId: number, _path: string): Promise<IEnterWorkspaceResult> {
throw new Error("not implemented");
public enterWorkspace(_windowId: number, _path: URI): Promise<IEnterWorkspaceResult> {
if (_path.path.endsWith(".json")) {
client.workspace = {
id: "Untitled",
configPath: _path.path,
};
} else {
client.workspace = _path;
}
return undefined!;
}
public createAndEnterWorkspace(_windowId: number, _folders?: IWorkspaceFolderCreationData[], _path?: string): Promise<IEnterWorkspaceResult> {
@ -251,8 +315,8 @@ class WindowsService implements IWindowsService {
return Promise.resolve(1);
}
public openExternal(_url: string): Promise<boolean> {
throw new Error("not implemented");
public async openExternal(_url: string): Promise<boolean> {
return typeof window.open(_url, "_blank") !== "undefined";
}
public startCrashReporter(_config: CrashReporterStartOptions): Promise<void> {

View File

@ -4,7 +4,7 @@ import { Registry } from "vs/platform/registry/common/platform";
import { IWorkbenchActionRegistry, Extensions } from "vs/workbench/common/actions";
import { SyncActionDescriptor } from "vs/platform/actions/common/actions";
import { ContextKeyExpr } from "vs/platform/contextkey/common/contextkey";
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions";
import { ToggleDevToolsAction } from "vs/workbench/electron-browser/actions/developerActions";
import { TerminalPasteAction } from "vs/workbench/parts/terminal/electron-browser/terminalActions";
import { KEYBINDING_CONTEXT_TERMINAL_FOCUS } from "vs/workbench/parts/terminal/common/terminal";
import { KeyCode, KeyMod } from "vs/base/common/keyCodes";

View File

@ -0,0 +1,40 @@
import { URI } from "vs/base/common/uri";
import { IEnvironmentService } from "vs/platform/environment/common/environment";
import { ILogService } from "vs/platform/log/common/log";
import { IWorkspaceFolderCreationData, IWorkspaceIdentifier, IWorkspacesService } from "vs/platform/workspaces/common/workspaces";
import { WorkspacesMainService } from "vs/platform/workspaces/electron-main/workspacesMainService";
import * as workspacesIpc from "vs/platform/workspaces/node/workspacesIpc";
import { client } from "../client";
/**
* Instead of going to the shared process, we'll directly run these methods on
* the client. This setup means we can only control the current window.
*/
class WorkspacesService implements IWorkspacesService {
// tslint:disable-next-line:no-any
public _serviceBrand: any;
public createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[] | undefined): Promise<IWorkspaceIdentifier> {
const mainService = new WorkspacesMainService(
client.serviceCollection.get<IEnvironmentService>(IEnvironmentService) as IEnvironmentService,
client.serviceCollection.get<ILogService>(ILogService) as ILogService,
);
// lib/vscode/src/vs/platform/workspaces/node/workspacesIpc.ts
const rawFolders: IWorkspaceFolderCreationData[] = folders!;
if (Array.isArray(rawFolders)) {
folders = rawFolders.map(rawFolder => {
return {
uri: URI.revive(rawFolder.uri), // convert raw URI back to real URI
name: rawFolder.name!,
} as IWorkspaceFolderCreationData;
});
}
return mainService.createUntitledWorkspace(folders);
}
}
const target = workspacesIpc as typeof workspacesIpc;
// @ts-ignore TODO: don't ignore it.
target.WorkspacesChannelClient = WorkspacesService;

View File

@ -5,144 +5,176 @@
import "vs/loader";
// Base
import "vs/base/common/strings";
import "vs/base/common/errors";
//#region --- workbench/editor core
// Configuration
import "vs/workbench/services/configuration/common/configurationExtensionPoint";
// Editor
import "vs/editor/editor.all";
// Platform
import "vs/platform/widget/browser/contextScopedHistoryWidget";
import "vs/platform/label/electron-browser/label.contribution";
import "vs/workbench/api/electron-browser/extensionHost.contribution";
// Menus/Actions
import "vs/workbench/services/actions/electron-browser/menusExtensionPoint";
import "vs/workbench/electron-browser/shell.contribution";
import "vs/workbench/browser/workbench.contribution";
// Views
import "vs/workbench/api/browser/viewsContainersExtensionPoint";
import { startup } from "vs/workbench/electron-browser/main";
//#endregion
//#region --- workbench actions
import "vs/workbench/browser/actions/layoutActions";
import "vs/workbench/browser/actions/listCommands";
import "vs/workbench/browser/actions/navigationActions";
import "vs/workbench/browser/parts/quickopen/quickOpenActions";
import "vs/workbench/browser/parts/quickinput/quickInputActions";
//#endregion
//#region --- API Extension Points
import "vs/workbench/api/common/menusExtensionPoint";
import "vs/workbench/api/common/configurationExtensionPoint";
import "vs/workbench/api/browser/viewsExtensionPoint";
//#endregion
//#region --- workbench services
import "vs/workbench/services/bulkEdit/electron-browser/bulkEditService";
//#endregion
//#region --- workbench parts
// Localizations
import "vs/workbench/parts/localizations/electron-browser/localizations.contribution";
// Workbench
import "vs/workbench/browser/actions/toggleActivityBarVisibility";
import "vs/workbench/browser/actions/toggleStatusbarVisibility";
import "vs/workbench/browser/actions/toggleSidebarVisibility";
import "vs/workbench/browser/actions/toggleSidebarPosition";
import "vs/workbench/browser/actions/toggleEditorLayout";
import "vs/workbench/browser/actions/toggleZenMode";
import "vs/workbench/browser/actions/toggleCenteredLayout";
import "vs/workbench/browser/actions/toggleTabsVisibility";
// Preferences
import "vs/workbench/parts/preferences/electron-browser/preferences.contribution";
import "vs/workbench/parts/preferences/browser/keybindingsEditorContribution";
// Logs
import "vs/workbench/parts/logs/electron-browser/logs.contribution";
import "vs/workbench/browser/parts/quickopen/quickopen.contribution";
// Quick Open Handlers
import "vs/workbench/parts/quickopen/browser/quickopen.contribution";
import "vs/workbench/browser/parts/editor/editorPicker";
import "vs/workbench/browser/parts/quickinput/quickInput.contribution";
// Explorer
import "vs/workbench/parts/files/electron-browser/explorerViewlet";
import "vs/workbench/parts/files/electron-browser/fileActions.contribution";
import "vs/workbench/parts/files/electron-browser/files.contribution";
// Backup
import "vs/workbench/parts/backup/common/backup.contribution";
// Stats
import "vs/workbench/parts/stats/node/stats.contribution";
// Rapid Render Splash
import "vs/workbench/parts/splash/electron-browser/partsSplash.contribution";
// Search
import "vs/workbench/parts/search/electron-browser/search.contribution";
import "vs/workbench/parts/search/browser/searchView";
import "vs/workbench/parts/search/browser/openAnythingHandler";
// SCM
import "vs/workbench/parts/scm/electron-browser/scm.contribution";
import "vs/workbench/parts/scm/electron-browser/scmViewlet";
// Debug
import "vs/workbench/parts/debug/electron-browser/debug.contribution";
// import "vs/workbench/parts/debug/browser/debugQuickOpen";
// import "vs/workbench/parts/debug/electron-browser/repl";
// import "vs/workbench/parts/debug/browser/debugViewlet";
import "vs/workbench/parts/debug/browser/debugQuickOpen";
import "vs/workbench/parts/debug/electron-browser/repl";
import "vs/workbench/parts/debug/browser/debugViewlet";
// Markers
import "vs/workbench/parts/markers/electron-browser/markers.contribution";
// Comments
import "vs/workbench/parts/comments/electron-browser/comments.contribution";
// HTML Preview
import "vs/workbench/parts/html/electron-browser/html.contribution";
// URL Support
import "vs/workbench/parts/url/electron-browser/url.contribution";
// Webview
import "vs/workbench/parts/webview/electron-browser/webview.contribution";
import "vs/workbench/parts/welcome/walkThrough/electron-browser/walkThrough.contribution";
// Extensions Management
import "vs/workbench/parts/extensions/electron-browser/extensions.contribution";
import "vs/workbench/parts/extensions/browser/extensionsQuickOpen";
import "vs/workbench/parts/extensions/electron-browser/extensionsViewlet";
import "vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution";
// Output Panel
import "vs/workbench/parts/output/electron-browser/output.contribution";
import "vs/workbench/parts/output/browser/outputPanel";
// Terminal
import "vs/workbench/parts/terminal/electron-browser/terminal.contribution";
import "vs/workbench/parts/terminal/browser/terminalQuickOpen";
import "vs/workbench/parts/terminal/electron-browser/terminalPanel";
import "vs/workbench/electron-browser/workbench";
// import "vs/workbench/parts/relauncher/electron-browser/relauncher.contribution";
// Relauncher
import "vs/workbench/parts/relauncher/electron-browser/relauncher.contribution";
// Tasks
import "vs/workbench/parts/tasks/electron-browser/task.contribution";
// Emmet
import "vs/workbench/parts/emmet/browser/emmet.browser.contribution";
import "vs/workbench/parts/emmet/electron-browser/emmet.contribution";
import "vs/workbench/parts/codeEditor/codeEditor.contribution";
// CodeEditor Contributions
import "vs/workbench/parts/codeEditor/electron-browser/codeEditor.contribution";
// Execution
import "vs/workbench/parts/execution/electron-browser/execution.contribution";
// Snippets
import "vs/workbench/parts/snippets/electron-browser/snippets.contribution";
import "vs/workbench/parts/snippets/electron-browser/snippetsService";
import "vs/workbench/parts/snippets/electron-browser/insertSnippet";
import "vs/workbench/parts/snippets/electron-browser/configureSnippets";
import "vs/workbench/parts/snippets/electron-browser/tabCompletion";
import "vs/workbench/parts/themes/electron-browser/themes.contribution";
// import "vs/workbench/parts/feedback/electron-browser/feedback.contribution";
import "vs/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.contribution";
// Send a Smile
import "vs/workbench/parts/feedback/electron-browser/feedback.contribution";
// Update
import "vs/workbench/parts/update/electron-browser/update.contribution";
// import "vs/workbench/parts/surveys/electron-browser/nps.contribution";
// import "vs/workbench/parts/surveys/electron-browser/languageSurveys.contribution";
// Surveys
import "vs/workbench/parts/surveys/electron-browser/nps.contribution";
import "vs/workbench/parts/surveys/electron-browser/languageSurveys.contribution";
// Performance
import "vs/workbench/parts/performance/electron-browser/performance.contribution";
// import "vs/workbench/parts/cli/electron-browser/cli.contribution";
// CLI
import "vs/workbench/parts/cli/electron-browser/cli.contribution";
import "vs/workbench/api/electron-browser/extensionHost.contribution";
import "vs/workbench/electron-browser/main.contribution";
import { startup } from "vs/workbench/electron-browser/main";
// import "vs/workbench/parts/themes/test/electron-browser/themes.test.contribution";
// Themes Support
import "vs/workbench/parts/themes/electron-browser/themes.contribution";
import "vs/workbench/parts/themes/test/electron-browser/themes.test.contribution";
// Watermark
import "vs/workbench/parts/watermark/electron-browser/watermark";
// Welcome
import "vs/workbench/parts/welcome/walkThrough/electron-browser/walkThrough.contribution";
import "vs/workbench/parts/welcome/gettingStarted/electron-browser/gettingStarted.contribution";
import "vs/workbench/parts/welcome/overlay/browser/welcomeOverlay";
import "vs/workbench/parts/welcome/page/electron-browser/welcomePage.contribution";
// Outline
import "vs/workbench/parts/outline/electron-browser/outline.contribution";
import "vs/workbench/services/bulkEdit/electron-browser/bulkEditService";
// Experiments
import "vs/workbench/parts/experiments/electron-browser/experiments.contribution";
//#endregion
import { URI } from "vs/base/common/uri";
export {

4
scripts/build.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -e
yarn task build:server:binary

View File

@ -1,8 +1,8 @@
diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
index 457818a975..ad45ffe58a 100644
index a342222d04..c731e82591 100644
--- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
+++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
@@ -196,0 +197,2 @@ async function handshake(configuration: ISharedProcessConfiguration): Promise<vo
@@ -195,0 +196,2 @@ async function handshake(configuration: ISharedProcessConfiguration): Promise<vo
+
+startup({ machineId: "1" });
diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts
@ -38,10 +38,10 @@ index 5e43f1b39e..a008d3ac7e 100644
+ }
+ }
diff --git a/src/vs/loader.js b/src/vs/loader.js
index 2bf7fe37d7..81cc668f12 100644
index 4eddcab3a0..5d80768406 100644
--- a/src/vs/loader.js
+++ b/src/vs/loader.js
@@ -670,4 +670,4 @@ var AMDLoader;
@@ -671,4 +671,4 @@ var AMDLoader;
- this._fs = nodeRequire('fs');
- this._vm = nodeRequire('vm');
- this._path = nodeRequire('path');
@ -50,7 +50,7 @@ index 2bf7fe37d7..81cc668f12 100644
+ this._vm = require('vm');
+ this._path = require('path');
+ this._crypto = require('crypto');
@@ -733,0 +734,7 @@ var AMDLoader;
@@ -736,0 +737,7 @@ var AMDLoader;
+ const context = require.context("../", true, /.*/);
+ if (scriptSrc.indexOf("file:///") !== -1) {
+ const vsSrc = scriptSrc.split("file:///")[1].split(".js")[0];
@ -58,11 +58,11 @@ index 2bf7fe37d7..81cc668f12 100644
+ scriptSrc = `node|./${vsSrc}`;
+ }
+ }
@@ -738 +745 @@ var AMDLoader;
@@ -741 +748 @@ var AMDLoader;
- moduleExports_1 = nodeRequire(pieces[1]);
+ moduleExports_1 = context(pieces[1]);
diff --git a/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts b/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts
index e3efb95b75..163bc4c994 100644
index 6c52cbc937..09adbe7f51 100644
--- a/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts
+++ b/src/vs/workbench/api/electron-browser/mainThreadHeapService.ts
@@ -57,0 +58,3 @@ export class HeapService implements IHeapService {
@ -70,24 +70,24 @@ index e3efb95b75..163bc4c994 100644
+ return Promise.resolve(obj);
+
diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts
index 7841dcdaa2..f5665f0db3 100644
index 1f4a1e100b..1bf605a064 100644
--- a/src/vs/workbench/api/node/extHostExtensionService.ts
+++ b/src/vs/workbench/api/node/extHostExtensionService.ts
@@ -654 +654 @@ function loadCommonJSModule<T>(logService: ILogService, modulePath: string, acti
@@ -719 +719 @@ function loadCommonJSModule<T>(logService: ILogService, modulePath: string, acti
- r = require.__$__nodeRequire<T>(modulePath);
+ r = (global as any).nativeNodeRequire(modulePath);
diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts
index 38bf337a61..a6ee664a20 100644
index e73acff052..bd65fcbd6c 100644
--- a/src/vs/workbench/browser/dnd.ts
+++ b/src/vs/workbench/browser/dnd.ts
@@ -171 +171 @@ export class ResourcesDropHandler {
- return;
+ return (require('vs/../../../../packages/vscode') as typeof import ('vs/../../../../packages/vscode')).client.handleDrop(event, resolveTargetGroup, afterDrop, targetIndex);
diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts
index a43d63aa51..438d0a8245 100644
index 1e6333c731..0a7bdeeb9b 100644
--- a/src/vs/workbench/electron-browser/main.ts
+++ b/src/vs/workbench/electron-browser/main.ts
@@ -150,7 +150,7 @@ function openWorkbench(configuration: IWindowConfiguration): Promise<void> {
@@ -147,7 +147,7 @@ function openWorkbench(configuration: IWindowConfiguration): Promise<void> {
- (<any>self).require.config({
- onError: err => {
- if (err.errorCode === 'load') {
@ -103,27 +103,23 @@ index a43d63aa51..438d0a8245 100644
+ // }
+ // });
diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts
index ea348f3a04..ada0003fea 100644
index c0aff6bd4b..4f3b1e3984 100644
--- a/src/vs/workbench/electron-browser/window.ts
+++ b/src/vs/workbench/electron-browser/window.ts
@@ -48 +48 @@ const TextInputActions: IAction[] = [
- new Action('editor.action.clipboardPasteAction', nls.localize('paste', "Paste"), null, true, () => document.execCommand('paste') && Promise.resolve(true)),
@@ -49 +49 @@ const TextInputActions: IAction[] = [
- new Action('editor.action.clipboardPasteAction', nls.localize('paste', "Paste"), undefined, true, () => Promise.resolve(document.execCommand('paste'))),
+ (require('vs/../../../../packages/vscode') as typeof import ('vs/../../../../packages/vscode')).client.pasteAction,
@@ -263 +263 @@ export class ElectronWindow extends Themable {
- (<any>window).open = function (url: string, target: string, features: string, replace: boolean): any {
+ (<any>window).openInvalid = function (url: string, target: string, features: string, replace: boolean): any {
diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts
index 35bc4a82b3..45e96001b6 100644
index d82db96296..c9bd4e0325 100644
--- a/src/vs/workbench/electron-browser/workbench.ts
+++ b/src/vs/workbench/electron-browser/workbench.ts
@@ -250,0 +251 @@ export class Workbench extends Disposable implements IPartService {
@@ -272,0 +273 @@ export class Workbench extends Disposable implements IPartService {
+ (require('vs/../../../../packages/vscode') as typeof import ('vs/../../../../packages/vscode')).client.serviceCollection = serviceCollection;
diff --git a/src/vs/workbench/node/extensionHostProcess.ts b/src/vs/workbench/node/extensionHostProcess.ts
index 8d182d18d9..69d51e1aea 100644
--- a/src/vs/workbench/node/extensionHostProcess.ts
+++ b/src/vs/workbench/node/extensionHostProcess.ts
@@ -132 +132 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
- process.kill(initData.parentPid, 0); // throws an exception if the main process doesn't exist anymore.
+ // process.kill(initData.parentPid, 0); // throws an exception if the main process doesn't exist anymore.
diff --git a/src/vs/workbench/parts/debug/node/debugAdapter.ts b/src/vs/workbench/parts/debug/node/debugAdapter.ts
index 2d798bf2df..9ccadacb3a 100644
index 81954344b9..2bdce9603e 100644
--- a/src/vs/workbench/parts/debug/node/debugAdapter.ts
+++ b/src/vs/workbench/parts/debug/node/debugAdapter.ts
@@ -315 +315 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter {
@ -133,11 +129,11 @@ index 2d798bf2df..9ccadacb3a 100644
- if (!fs.existsSync(this.adapterExecutable.command)) {
+ if (!(await require("util").promisify(fs.exists)(this.adapterExecutable.command))) {
diff --git a/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts
index e600fb2f78..1e0dc9a220 100644
index e66f74f034..aca6f509b0 100644
--- a/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts
+++ b/src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts
@@ -934,0 +935 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop {
+ return (require('vs/../../../../packages/vscode') as typeof import ('vs/../../../../packages/vscode')).client.handleExternalDrop(target, originalEvent);
@@ -586,0 +587 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
+ return (require('vs/../../../../packages/vscode') as typeof import ('vs/../../../../packages/vscode')).client.handleExternalDrop(target, originalEvent as any);
diff --git a/src/vs/workbench/parts/logs/electron-browser/logs.contribution.ts b/src/vs/workbench/parts/logs/electron-browser/logs.contribution.ts
index 4015c9cd5d..bebdb25f6c 100644
--- a/src/vs/workbench/parts/logs/electron-browser/logs.contribution.ts
@ -147,14 +143,62 @@ index 4015c9cd5d..bebdb25f6c 100644
+ // This channel only seems to be used when loading the app and we skip all of that, so it is never actually created or written to.
+ // outputChannelRegistry.registerChannel({ id: Constants.mainLogChannelId, label: nls.localize('mainLog', "Main"), file: URI.file(join(environmentService.logsPath, `main.log`)), log: true });
diff --git a/src/vs/workbench/parts/output/common/outputLinkProvider.ts b/src/vs/workbench/parts/output/common/outputLinkProvider.ts
index 63437034c9..acd82c8375 100644
index 6d9451401a..510f5131ce 100644
--- a/src/vs/workbench/parts/output/common/outputLinkProvider.ts
+++ b/src/vs/workbench/parts/output/common/outputLinkProvider.ts
@@ -77,0 +78,2 @@ export class OutputLinkProvider {
+ // TODO@coder: get this working.
+
+ return Promise.resolve([]);
diff --git a/src/vs/workbench/parts/webview/electron-browser/webview-pre.js b/src/vs/workbench/parts/webview/electron-browser/webview-pre.js
index 29593dc6b6..dd3d25098d 100644
--- a/src/vs/workbench/parts/webview/electron-browser/webview-pre.js
+++ b/src/vs/workbench/parts/webview/electron-browser/webview-pre.js
@@ -10 +10,19 @@
- const ipcRenderer = require('electron').ipcRenderer;
+ const ipcRenderer = {
+ on: (channel, callback) => {
+ window.addEventListener("message", (event) => {
+ if (event.data.channel === channel) {
+ callback(event.data.channel, ...event.data.data);
+ }
+ });
+ },
+ sendToHost: (channel, ...args) => {
+ window.parent.postMessage({
+ channel,
+ data: args,
+ id: document.body.id,
+ }, "*");
+ },
+ };
+ const process = {
+ pid: undefined,
+ };
@@ -22,7 +40,7 @@
- require('electron').webFrame.registerURLSchemeAsPrivileged('vscode-resource', {
- secure: true,
- bypassCSP: false,
- allowServiceWorkers: false,
- supportFetchAPI: true,
- corsEnabled: true
- });
+ // require('electron').webFrame.registerURLSchemeAsPrivileged('vscode-resource', {
+ // secure: true,
+ // bypassCSP: false,
+ // allowServiceWorkers: false,
+ // supportFetchAPI: true,
+ // corsEnabled: true
+ // });
diff --git a/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts b/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts
index 5d9110300f..ecdc40b0eb 100644
--- a/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts
+++ b/src/vs/workbench/parts/webview/electron-browser/webviewElement.ts
@@ -261,0 +262,3 @@ export class WebviewElement extends Disposable {
+ Object.defineProperty(this._options, 'useSameOriginForRoot', {
+ value: true,
+ });
diff --git a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts
index 7b4e8721ac..96d612f940 100644
index 147f05b246..fa89583203 100644
--- a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts
+++ b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts
@@ -31,6 +31,6 @@ export class WalkThroughContentProvider implements ITextModelContentProvider, IW
@ -193,15 +237,22 @@ index 7b4e8721ac..96d612f940 100644
- this.modelService.updateModel(codeEditorModel, content.value);
+ this.modelService.updateModel(codeEditorModel, content);
diff --git a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts
index 4cb7a231f3..78c87d13f6 100644
index 29cbfd65c4..1091dc3c8a 100644
--- a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts
+++ b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts
@@ -33,0 +34 @@ function getSystemExtensionsRoot(): string {
+ return (require('vs/../../../../packages/vscode') as typeof import ('vs/../../../../packages/vscode')).client.builtInExtensionsDirectory;
diff --git a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts
index 5b4136989f..25ccc0fe9e 100644
--- a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts
+++ b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts
@@ -181 +181 @@ function _processIconThemeDocument(id: string, iconThemeDocumentLocation: URI, i
- return resources.joinPath(iconThemeDocumentLocationDirname, path);
+ return "/resource" + resources.joinPath(iconThemeDocumentLocationDirname, path).path;
diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts
index 5f2935618c..af5498d7ac 100644
--- a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts
+++ b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts
@@ -132 +132 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
- process.kill(initData.parentPid, 0); // throws an exception if the main process doesn't exist anymore.
+ // process.kill(initData.parentPid, 0); // throws an exception if the main process doesn't exist anymore.
diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts
index 1ad274696d..f52d1e0d2e 100644
--- a/src/vs/workbench/workbench.main.ts
+++ b/src/vs/workbench/workbench.main.ts
@@ -25 +25 @@ import 'vs/workbench/browser/actions/navigationActions';
-import 'vs/workbench/browser/parts/quickopen/quickopenActions';
+import 'vs/workbench/browser/parts/quickopen/quickOpenActions';

View File

@ -33,7 +33,7 @@ module.exports = (options = {}) => ({
}],
},
}, {
test: /\.(js)/,
test: /\.(js|css)/,
exclude: /test/,
}, {
test: /\.(txt|d\.ts|test.ts|perf.data.js|jxs|scpt|exe|sh|less)$/,
@ -61,7 +61,7 @@ module.exports = (options = {}) => ({
// pages or iframes so we don't need to include it here. Also excluding
// markdown.css because even though it uses the file-loader as shown above
// in the string replace, it's still making its way into the main CSS.
exclude: /test|code\/electron-browser\/.+\.css$|markdown.css$/,
exclude: /test|code\/electron-browser\/.+\.css$/,
test: /\.s?css$/,
// This is required otherwise it'll fail to resolve CSS in common.
include: root,
@ -73,7 +73,7 @@ module.exports = (options = {}) => ({
loader: "sass-loader",
}],
}, {
test: /\.(svg|png|ttf|woff|eot)$/,
test: /\.(svg|png|ttf|woff|eot|woff2)$/,
use: [{
loader: "file-loader",
options: {

View File

@ -4,6 +4,7 @@
"module": "commonjs",
"baseUrl": ".",
"rootDir": ".",
"jsx": "react",
"outDir": "dist",
"declaration": true,
"sourceMap": true,

View File

@ -14,6 +14,23 @@
dependencies:
execa "^0.2.2"
"@types/fs-extra@^5.0.4":
version "5.0.5"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.5.tgz#080d90a792f3fa2c5559eb44bd8ef840aae9104b"
integrity sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==
dependencies:
"@types/node" "*"
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@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/node@^10.12.18":
version "10.12.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
@ -1231,6 +1248,11 @@ deep-extend@^0.6.0:
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
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==
default-gateway@^2.6.0:
version "2.7.2"
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f"
@ -1943,6 +1965,15 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
fs-extra@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
dependencies:
graceful-fs "^4.1.2"
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"
@ -2835,6 +2866,13 @@ jsonfile@^2.1.0:
optionalDependencies:
graceful-fs "^4.1.6"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
@ -5178,6 +5216,17 @@ ts-node@^7.0.1:
source-map-support "^0.5.6"
yn "^2.0.0"
tsconfig-paths@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.8.0.tgz#4e34202d5b41958f269cf56b01ed95b853d59f72"
integrity sha512-zZEYFo4sjORK8W58ENkRn9s+HmQFkkwydDG7My5s/fnfr2YYCaiyXe/HBUcIgU8epEKOXwiahOO+KZYjiXlWyQ==
dependencies:
"@types/json5" "^0.0.29"
deepmerge "^2.0.1"
json5 "^1.0.1"
minimist "^1.2.0"
strip-bom "^3.0.0"
tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
@ -5298,6 +5347,11 @@ unique-slug@^2.0.0:
dependencies:
imurmurhash "^0.1.4"
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"