Add file uploading support
Co-Authored-By: Max Leiter <hello@maxleiter.com> Co-Authored-By: Jérémie Astori <astorije@users.noreply.github.com>
This commit is contained in:
parent
7c12883dc1
commit
ce212e001c
@ -242,6 +242,7 @@ kbd {
|
||||
#settings .extra-experimental,
|
||||
#settings .extra-help,
|
||||
#settings #play::before,
|
||||
#form #upload::before,
|
||||
#form #submit::before,
|
||||
#chat .away .from::before,
|
||||
#chat .back .from::before,
|
||||
@ -315,6 +316,7 @@ kbd {
|
||||
#footer .settings::before { content: "\f013"; /* http://fontawesome.io/icon/cog/ */ }
|
||||
#footer .help::before { content: "\f059"; /* http://fontawesome.io/icon/question/ */ }
|
||||
|
||||
#form #upload::before { content: "\f0c6"; /* https://fontawesome.com/icons/paperclip?style=solid */ }
|
||||
#form #submit::before { content: "\f1d8"; /* http://fontawesome.io/icon/paper-plane/ */ }
|
||||
|
||||
#chat .away .from::before,
|
||||
@ -1930,6 +1932,12 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
content: "\f00c"; /* http://fontawesome.io/icon/check/ */
|
||||
}
|
||||
|
||||
#upload-progressbar {
|
||||
background: blue;
|
||||
width: 0%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
#form {
|
||||
flex: 0 0 auto;
|
||||
border: 0;
|
||||
@ -1957,6 +1965,7 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
|
||||
#connection-error.shown {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#form #nick {
|
||||
@ -1991,6 +2000,11 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
#form #upload-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#form #upload,
|
||||
#form #submit {
|
||||
color: #607992;
|
||||
font-size: 14px;
|
||||
@ -2519,8 +2533,9 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* Image viewer */
|
||||
/* Image viewer and drag-and-drop overlay */
|
||||
|
||||
#upload-overlay,
|
||||
#image-viewer,
|
||||
#image-viewer .close-btn {
|
||||
/* Vertically and horizontally center stuff */
|
||||
@ -2530,6 +2545,7 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#upload-overlay,
|
||||
#image-viewer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@ -2548,6 +2564,11 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#upload-overlay.is-dragover {
|
||||
visibility: visible;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
#image-viewer .close-btn,
|
||||
#image-viewer .previous-image-btn,
|
||||
#image-viewer .next-image-btn {
|
||||
|
@ -84,9 +84,14 @@
|
||||
<div id="chat-container" class="window">
|
||||
<div id="chat"></div>
|
||||
<div id="connection-error"></div>
|
||||
<span id="upload-progressbar"></span>
|
||||
<form id="form" method="post" action="">
|
||||
<span id="nick"></span>
|
||||
<textarea id="input" class="mousetrap"></textarea>
|
||||
<span id="upload-tooltip" class="tooltipped tooltipped-w tooltipped-no-touch" aria-label="Upload File">
|
||||
<input id="upload-input" type="file" multiple></button>
|
||||
<button id="upload" type="button" aria-label="Upload file"></button>
|
||||
</span>
|
||||
<span id="submit-tooltip" class="tooltipped tooltipped-w tooltipped-no-touch" aria-label="Send message">
|
||||
<button id="submit" type="submit" aria-label="Send message"></button>
|
||||
</span>
|
||||
@ -102,6 +107,7 @@
|
||||
|
||||
<div id="context-menu-container"></div>
|
||||
<div id="image-viewer"></div>
|
||||
<div id="upload-overlay"></div>
|
||||
|
||||
<script src="js/bundle.vendor.js"></script>
|
||||
<script src="js/bundle.js"></script>
|
||||
|
@ -7,6 +7,7 @@ const options = require("../options");
|
||||
const webpush = require("../webpush");
|
||||
const connect = $("#connect");
|
||||
const utils = require("../utils");
|
||||
const upload = require("../upload");
|
||||
|
||||
window.addEventListener("beforeinstallprompt", (installPromptEvent) => {
|
||||
$("#webapp-install-button")
|
||||
@ -23,6 +24,12 @@ window.addEventListener("beforeinstallprompt", (installPromptEvent) => {
|
||||
});
|
||||
|
||||
socket.on("configuration", function(data) {
|
||||
if (data.fileUpload) {
|
||||
$("#upload").show();
|
||||
} else {
|
||||
$("#upload").hide();
|
||||
}
|
||||
|
||||
if (options.initialized) {
|
||||
// Likely a reconnect, request sync for possibly missed settings.
|
||||
socket.emit("setting:get");
|
||||
@ -44,6 +51,11 @@ socket.on("configuration", function(data) {
|
||||
pop.play();
|
||||
});
|
||||
|
||||
if (data.fileUpload) {
|
||||
upload.initialize();
|
||||
upload.setMaxFileSize(data.fileUploadMaxFileSize);
|
||||
}
|
||||
|
||||
utils.togglePasswordField("#change-password .reveal-password");
|
||||
|
||||
options.initialize();
|
||||
|
@ -15,6 +15,7 @@ require("./part");
|
||||
require("./quit");
|
||||
require("./sync_sort");
|
||||
require("./topic");
|
||||
require("./uploads");
|
||||
require("./users");
|
||||
require("./sign_out");
|
||||
require("./sessions_list");
|
||||
|
10
client/js/socket-events/uploads.js
Normal file
10
client/js/socket-events/uploads.js
Normal file
@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
const socket = require("../socket");
|
||||
const wrapCursor = require("undate").wrapCursor;
|
||||
|
||||
socket.on("upload:success", (url) => {
|
||||
const fullURL = new URL(url, location);
|
||||
const textbox = document.getElementById("input");
|
||||
wrapCursor(textbox, fullURL, " ");
|
||||
});
|
@ -11,6 +11,10 @@ const socket = io({
|
||||
reconnection: !$(document.body).hasClass("public"),
|
||||
});
|
||||
|
||||
$("#connection-error").on("click", function() {
|
||||
$(this).removeClass("shown");
|
||||
});
|
||||
|
||||
socket.on("disconnect", handleDisconnect);
|
||||
socket.on("connect_error", handleDisconnect);
|
||||
socket.on("error", handleDisconnect);
|
||||
@ -42,6 +46,7 @@ function handleDisconnect(data) {
|
||||
$("#loading-page-message, #connection-error").text(`Waiting to reconnect… (${message})`).addClass("shown");
|
||||
$(".show-more button, #input").prop("disabled", true);
|
||||
$("#submit").hide();
|
||||
$("#upload").hide();
|
||||
|
||||
// If the server shuts down, socket.io skips reconnection
|
||||
// and we have to manually call connect to start the process
|
||||
|
54
client/js/upload.js
Normal file
54
client/js/upload.js
Normal file
@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
|
||||
const $ = require("jquery");
|
||||
const socket = require("./socket");
|
||||
const SocketIOFileUpload = require("socketio-file-upload/client");
|
||||
const instance = new SocketIOFileUpload(socket);
|
||||
|
||||
function initialize() {
|
||||
instance.listenOnInput(document.getElementById("upload-input"));
|
||||
instance.listenOnDrop(document);
|
||||
|
||||
$("#upload").on("click", () => {
|
||||
$("#upload-input").trigger("click");
|
||||
});
|
||||
|
||||
instance.addEventListener("complete", () => {
|
||||
// Reset progressbar
|
||||
$("#upload-progressbar").width(0);
|
||||
});
|
||||
|
||||
instance.addEventListener("progress", (event) => {
|
||||
const percent = `${((event.bytesLoaded / event.file.size) * 100)}%`;
|
||||
$("#upload-progressbar").width(percent);
|
||||
});
|
||||
|
||||
instance.addEventListener("error", (event) => {
|
||||
// Reset progressbar
|
||||
$("#upload-progressbar").width(0);
|
||||
$("#connection-error").addClass("shown").text(event.message);
|
||||
});
|
||||
|
||||
const $form = $(document);
|
||||
const $overlay = $("#upload-overlay");
|
||||
|
||||
$form.on("dragover", () => {
|
||||
$overlay.addClass("is-dragover");
|
||||
return false;
|
||||
});
|
||||
|
||||
$form.on("dragend dragleave drop", () => {
|
||||
$overlay.removeClass("is-dragover");
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in the `configuration` socket event.
|
||||
* Makes it so the user can be notified if a file is too large without waiting for the upload to finish server-side.
|
||||
**/
|
||||
function setMaxFileSize(kb) {
|
||||
instance.maxFileSize = kb;
|
||||
}
|
||||
|
||||
module.exports = {initialize, setMaxFileSize};
|
@ -139,6 +139,27 @@ module.exports = {
|
||||
// This value is set to `2048` kilobytes by default.
|
||||
prefetchMaxImageSize: 2048,
|
||||
|
||||
// ### `fileUpload`
|
||||
//
|
||||
// Allow uploading files to the server hosting The Lounge.
|
||||
//
|
||||
// Files are stored in the `${THELOUNGE_HOME}/uploads` folder, do not expire,
|
||||
// and are not removed by The Lounge. This may cause issues depending on your
|
||||
// hardware, for example in terms of disk usage.
|
||||
//
|
||||
// The available keys for the `fileUpload` object are:
|
||||
//
|
||||
// - `enable`: When set to `true`, files can be uploaded on the client with a
|
||||
// drag-and-drop or using the upload dialog.
|
||||
// - `maxFileSize`: When file upload is enabled, users sending files above
|
||||
// this limit will be prompted an error message in their browser. A value of
|
||||
// `-1` disables the file size limit and allows files of any size. **Use at
|
||||
// your own risk.** This value is set to `10240` kilobytes by default.
|
||||
fileUpload: {
|
||||
enable: true,
|
||||
maxFileSize: 10240,
|
||||
},
|
||||
|
||||
// ### `transports`
|
||||
//
|
||||
// Set `socket.io` transports.
|
||||
|
@ -44,9 +44,11 @@
|
||||
"cheerio": "0.22.0",
|
||||
"commander": "2.17.1",
|
||||
"express": "4.16.3",
|
||||
"file-type": "9.0.0",
|
||||
"filenamify": "2.1.0",
|
||||
"fs-extra": "7.0.0",
|
||||
"irc-framework": "3.1.0",
|
||||
"is-utf8": "0.2.1",
|
||||
"linkify-it": "2.0.3",
|
||||
"lodash": "4.17.10",
|
||||
"mime-types": "2.1.20",
|
||||
@ -54,9 +56,11 @@
|
||||
"package-json": "5.0.0",
|
||||
"primer-tooltips": "1.5.7",
|
||||
"read": "1.0.7",
|
||||
"read-chunk": "3.0.0",
|
||||
"request": "2.88.0",
|
||||
"semver": "5.5.1",
|
||||
"socket.io": "2.1.1",
|
||||
"socketio-file-upload": "0.6.2",
|
||||
"thelounge-ldapjs-non-maintained-fork": "1.0.2",
|
||||
"tlds": "1.203.1",
|
||||
"ua-parser-js": "0.7.18",
|
||||
|
@ -15,6 +15,7 @@ let configPath;
|
||||
let usersPath;
|
||||
let storagePath;
|
||||
let packagesPath;
|
||||
let fileUploadPath;
|
||||
let userLogsPath;
|
||||
|
||||
const Helper = {
|
||||
@ -25,6 +26,7 @@ const Helper = {
|
||||
getPackageModulePath,
|
||||
getStoragePath,
|
||||
getConfigPath,
|
||||
getFileUploadPath,
|
||||
getUsersPath,
|
||||
getUserConfigPath,
|
||||
getUserLogsPath,
|
||||
@ -92,6 +94,7 @@ function setHome(newPath) {
|
||||
configPath = path.join(homePath, "config.js");
|
||||
usersPath = path.join(homePath, "users");
|
||||
storagePath = path.join(homePath, "storage");
|
||||
fileUploadPath = path.join(homePath, "uploads");
|
||||
packagesPath = path.join(homePath, "packages");
|
||||
userLogsPath = path.join(homePath, "logs");
|
||||
|
||||
@ -142,6 +145,10 @@ function getConfigPath() {
|
||||
return configPath;
|
||||
}
|
||||
|
||||
function getFileUploadPath() {
|
||||
return fileUploadPath;
|
||||
}
|
||||
|
||||
function getUsersPath() {
|
||||
return usersPath;
|
||||
}
|
||||
|
152
src/plugins/uploader.js
Normal file
152
src/plugins/uploader.js
Normal file
@ -0,0 +1,152 @@
|
||||
"use strict";
|
||||
|
||||
const SocketIOFileUploadServer = require("socketio-file-upload/server");
|
||||
const Helper = require("../helper");
|
||||
const path = require("path");
|
||||
const fsextra = require("fs-extra");
|
||||
const fs = require("fs");
|
||||
const fileType = require("file-type");
|
||||
const readChunk = require("read-chunk");
|
||||
const crypto = require("crypto");
|
||||
const isUtf8 = require("is-utf8");
|
||||
const log = require("../log");
|
||||
|
||||
const whitelist = [
|
||||
"application/ogg",
|
||||
"audio/midi",
|
||||
"audio/mpeg",
|
||||
"audio/ogg",
|
||||
"audio/x-wav",
|
||||
"image/bmp",
|
||||
"image/gif",
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/webp",
|
||||
"text/plain",
|
||||
"video/mp4",
|
||||
"video/ogg",
|
||||
"video/webm",
|
||||
];
|
||||
|
||||
class Uploader {
|
||||
constructor(client, socket) {
|
||||
const uploader = new SocketIOFileUploadServer();
|
||||
const folder = path.join(Helper.getFileUploadPath(), ".tmp");
|
||||
|
||||
fsextra.ensureDir(folder, (err) => {
|
||||
if (err) {
|
||||
log.err(`Error ensuring ${folder} exists for uploads.`);
|
||||
} else {
|
||||
uploader.dir = folder;
|
||||
}
|
||||
});
|
||||
|
||||
uploader.on("complete", (data) => {
|
||||
handleSaving(data).then((randomName) => {
|
||||
const randomFileName = randomName;
|
||||
const slug = data.file.base;
|
||||
const url = `uploads/${randomFileName}/${slug}`;
|
||||
client.emit("upload:success", url);
|
||||
});
|
||||
});
|
||||
|
||||
uploader.on("error", (data) => {
|
||||
log.error(`Error uploading ${data.error.name}`);
|
||||
log.error(data.error);
|
||||
});
|
||||
|
||||
// maxFileSize is in bytes, but config option is passed in as KB
|
||||
uploader.maxFileSize = Uploader.getMaxFileSize();
|
||||
uploader.listen(socket);
|
||||
|
||||
// Returns Promise
|
||||
function handleSaving(data) {
|
||||
const tempPath = path.join(Helper.getFileUploadPath(), ".tmp", data.file.name);
|
||||
let randomName, destPath;
|
||||
|
||||
// If file conflicts
|
||||
do {
|
||||
randomName = crypto.randomBytes(8).toString("hex");
|
||||
destPath = path.join(Helper.getFileUploadPath(), randomName.substring(0, 2), randomName);
|
||||
} while (fs.stat(destPath, (err) => (err ? true : false)));
|
||||
|
||||
return fsextra.move(tempPath, destPath)
|
||||
.then(() => randomName).catch(() => {
|
||||
log.warn(`Unable to move file ${tempPath} to ${destPath}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static isValidType(mimeType) {
|
||||
return whitelist.includes(mimeType);
|
||||
}
|
||||
|
||||
static router(express) {
|
||||
express.get("/uploads/:name/:slug*?", (req, res) => {
|
||||
const name = req.params.name;
|
||||
|
||||
const nameRegex = /^[0-9a-f]{16}$/;
|
||||
|
||||
if (!nameRegex.test(name)) {
|
||||
return res.status(404).send("Not found");
|
||||
}
|
||||
|
||||
const folder = name.substring(0, 2);
|
||||
const uploadPath = Helper.getFileUploadPath();
|
||||
const filePath = path.join(uploadPath, folder, name);
|
||||
const type = Uploader.getFileType(filePath);
|
||||
const mimeType = type || "application/octet-stream";
|
||||
const contentDisposition = Uploader.isValidType(type) ? "inline" : "attachment";
|
||||
|
||||
// doesn't exist
|
||||
if (type === undefined) {
|
||||
return res.status(404).send("Not found");
|
||||
}
|
||||
|
||||
res.setHeader("Content-Disposition", contentDisposition);
|
||||
res.setHeader("Cache-Control", "max-age=86400");
|
||||
res.contentType(mimeType);
|
||||
|
||||
return res.sendFile(filePath);
|
||||
});
|
||||
}
|
||||
|
||||
static getMaxFileSize() {
|
||||
const configOption = Helper.config.fileUpload.maxFileSize;
|
||||
|
||||
if (configOption === -1) { // no file size limit
|
||||
return null;
|
||||
}
|
||||
|
||||
return configOption * 1024;
|
||||
}
|
||||
|
||||
static getFileType(filePath) {
|
||||
let buffer;
|
||||
let type;
|
||||
|
||||
try {
|
||||
buffer = readChunk.sync(filePath, 0, 4100);
|
||||
} catch (e) {
|
||||
if (e.code === "ENOENT") { // doesn't exist
|
||||
return;
|
||||
}
|
||||
|
||||
log.warn(`Failed to read ${filePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// returns {ext, mime} if found, null if not.
|
||||
const file = fileType(buffer);
|
||||
|
||||
if (file) {
|
||||
type = file.mime;
|
||||
} else if (isUtf8(buffer)) {
|
||||
type = "text/plain";
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Uploader;
|
@ -10,6 +10,7 @@ const fs = require("fs");
|
||||
const path = require("path");
|
||||
const io = require("socket.io");
|
||||
const dns = require("dns");
|
||||
const Uploader = require("./plugins/uploader");
|
||||
const Helper = require("./helper");
|
||||
const colors = require("chalk");
|
||||
const net = require("net");
|
||||
@ -51,9 +52,13 @@ module.exports = function() {
|
||||
.use(express.static(path.join(__dirname, "..", "public"), staticOptions))
|
||||
.use("/storage/", express.static(Helper.getStoragePath(), staticOptions));
|
||||
|
||||
if (Helper.config.fileUpload.enable) {
|
||||
Uploader.router(app);
|
||||
}
|
||||
|
||||
// This route serves *installed themes only*. Local themes are served directly
|
||||
// from the `public/themes/` folder as static assets, without entering this
|
||||
// handler. Remember this is you make changes to this function, serving of
|
||||
// handler. Remember this if you make changes to this function, serving of
|
||||
// local themes will not get those changes.
|
||||
app.get("/themes/:theme.css", (req, res) => {
|
||||
const themeName = req.params.theme;
|
||||
@ -284,6 +289,10 @@ function initializeClient(socket, client, token, lastMessage) {
|
||||
|
||||
client.clientAttach(socket.id, token);
|
||||
|
||||
if (Helper.config.fileUpload.enable) {
|
||||
new Uploader(client, socket);
|
||||
}
|
||||
|
||||
socket.on("disconnect", function() {
|
||||
client.clientDetach(socket.id);
|
||||
});
|
||||
@ -583,6 +592,7 @@ function getClientConfiguration(network) {
|
||||
"prefetch",
|
||||
]);
|
||||
|
||||
config.fileUpload = Helper.config.fileUpload.enable;
|
||||
config.ldapEnabled = Helper.config.ldap.enable;
|
||||
|
||||
if (config.displayNetwork) {
|
||||
@ -607,6 +617,10 @@ function getClientConfiguration(network) {
|
||||
config.defaults.nick = Helper.getDefaultNick();
|
||||
}
|
||||
|
||||
if (Uploader) {
|
||||
config.fileUploadMaxFileSize = Uploader.getMaxFileSize();
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
97
yarn.lock
97
yarn.lock
@ -1528,12 +1528,12 @@ caniuse-api@^1.5.2:
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
|
||||
version "1.0.30000882"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000882.tgz#d9d50e5189be253ffb31d347cd7f3c615b602f7f"
|
||||
version "1.0.30000883"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000883.tgz#976f22d6a9be119b342d5ce6c7ee98fc6e0bc94a"
|
||||
|
||||
caniuse-lite@^1.0.30000878:
|
||||
version "1.0.30000882"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000882.tgz#0d5066847a11a5af0e50ffce6c062ef0665f68ea"
|
||||
version "1.0.30000883"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000883.tgz#597c1eabfb379bd9fbeaa778632762eb574706ac"
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
@ -1571,7 +1571,7 @@ chalk@2.4.1, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.
|
||||
|
||||
chalk@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
dependencies:
|
||||
ansi-styles "^2.2.1"
|
||||
escape-string-regexp "^1.0.2"
|
||||
@ -1595,9 +1595,9 @@ character-reference-invalid@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz#21e421ad3d84055952dab4a43a04e73cd425d3ed"
|
||||
|
||||
chardet@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029"
|
||||
chardet@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
||||
|
||||
check-error@^1.0.1:
|
||||
version "1.0.2"
|
||||
@ -2309,8 +2309,8 @@ detect-libc@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
|
||||
detect-node@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127"
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
|
||||
|
||||
diff@3.5.0, diff@^3.5.0:
|
||||
version "3.5.0"
|
||||
@ -2434,8 +2434,8 @@ ee-first@1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
|
||||
electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.61:
|
||||
version "1.3.61"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.61.tgz#a8ac295b28d0f03d85e37326fd16b6b6b17a1795"
|
||||
version "1.3.62"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.62.tgz#2e8e2dc070c800ec8ce23ff9dfcceb585d6f9ed8"
|
||||
|
||||
elliptic@^6.0.0:
|
||||
version "6.4.1"
|
||||
@ -2667,7 +2667,7 @@ etag@~1.8.1:
|
||||
|
||||
event-stream@~3.3.0:
|
||||
version "3.3.4"
|
||||
resolved "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
|
||||
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
|
||||
dependencies:
|
||||
duplexer "~0.1.1"
|
||||
from "~0"
|
||||
@ -2809,11 +2809,11 @@ extend@^3.0.0, extend@~3.0.2:
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
|
||||
external-editor@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.1.tgz#fc9638c4d7cde4f0bb82b12307a1a23912c492e3"
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27"
|
||||
dependencies:
|
||||
chardet "^0.5.0"
|
||||
iconv-lite "^0.4.22"
|
||||
chardet "^0.7.0"
|
||||
iconv-lite "^0.4.24"
|
||||
tmp "^0.0.33"
|
||||
|
||||
extglob@^0.3.1:
|
||||
@ -2903,6 +2903,10 @@ file-entry-cache@^2.0.0:
|
||||
flat-cache "^1.2.1"
|
||||
object-assign "^4.0.1"
|
||||
|
||||
file-type@9.0.0:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18"
|
||||
|
||||
filename-regex@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
|
||||
@ -3249,7 +3253,7 @@ globjoin@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
|
||||
|
||||
gonzales-pe@4.2.3:
|
||||
gonzales-pe@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.3.tgz#41091703625433285e0aee3aa47829fc1fbeb6f2"
|
||||
dependencies:
|
||||
@ -3552,7 +3556,7 @@ iconv-lite@0.4.19:
|
||||
version "0.4.19"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
|
||||
|
||||
iconv-lite@^0.4.11, iconv-lite@^0.4.22, iconv-lite@^0.4.4:
|
||||
iconv-lite@^0.4.11, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
dependencies:
|
||||
@ -3980,6 +3984,10 @@ is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
|
||||
is-utf8@0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||
|
||||
is-whitespace-character@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz#ede53b4c6f6fb3874533751ec9280d01928d03ed"
|
||||
@ -4759,7 +4767,7 @@ mixin-deep@^1.2.0:
|
||||
|
||||
mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
@ -5744,11 +5752,11 @@ postcss-safe-parser@^4.0.0:
|
||||
postcss "^7.0.0"
|
||||
|
||||
postcss-sass@^0.3.0:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.3.2.tgz#17f3074cecb28128b156f1a4407c6ad075d7e00c"
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.3.3.tgz#bec188ac285d21ac8feba194c2f327fdda31e671"
|
||||
dependencies:
|
||||
gonzales-pe "4.2.3"
|
||||
postcss "6.0.22"
|
||||
gonzales-pe "^4.2.3"
|
||||
postcss "^7.0.1"
|
||||
|
||||
postcss-scss@^2.0.0:
|
||||
version "2.0.0"
|
||||
@ -5809,14 +5817,6 @@ postcss-zindex@^2.0.1:
|
||||
postcss "^5.0.4"
|
||||
uniqs "^2.0.0"
|
||||
|
||||
postcss@6.0.22:
|
||||
version "6.0.22"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.22.tgz#e23b78314905c3b90cbd61702121e7a78848f2a3"
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
source-map "^0.6.1"
|
||||
supports-color "^5.4.0"
|
||||
|
||||
postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16:
|
||||
version "5.2.18"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
|
||||
@ -5834,7 +5834,7 @@ postcss@^6.0.1, postcss@^6.0.23, postcss@^6.0.8:
|
||||
source-map "^0.6.1"
|
||||
supports-color "^5.4.0"
|
||||
|
||||
postcss@^7.0.0, postcss@^7.0.2:
|
||||
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2:
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.2.tgz#7b5a109de356804e27f95a960bef0e4d5bc9bb18"
|
||||
dependencies:
|
||||
@ -6044,6 +6044,13 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
read-chunk@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-3.0.0.tgz#086cd198406104355626afacd2d21084afc367ec"
|
||||
dependencies:
|
||||
pify "^4.0.0"
|
||||
with-open-file "^0.1.3"
|
||||
|
||||
read-pkg-up@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
|
||||
@ -6407,8 +6414,8 @@ runes@^0.4.3:
|
||||
resolved "https://registry.yarnpkg.com/runes/-/runes-0.4.3.tgz#32f7738844bc767b65cc68171528e3373c7bb355"
|
||||
|
||||
rxjs@^6.1.0:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9"
|
||||
version "6.3.1"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.1.tgz#878a1a8c64b8a5da11dcf74b5033fe944cdafb84"
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
@ -6683,6 +6690,10 @@ socket.io@2.1.1:
|
||||
socket.io-client "2.1.1"
|
||||
socket.io-parser "~3.2.0"
|
||||
|
||||
socketio-file-upload@0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/socketio-file-upload/-/socketio-file-upload-0.6.2.tgz#0e13c5e2b2a6798f0754d2bdcf2b404f8707e192"
|
||||
|
||||
sockjs-client@1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.5.tgz#1bb7c0f7222c40f42adf14f4442cbd1269771a83"
|
||||
@ -7342,8 +7353,8 @@ uglify-es@^3.3.4:
|
||||
source-map "~0.6.1"
|
||||
|
||||
uglify-js@3.4.x:
|
||||
version "3.4.8"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.8.tgz#d590777b208258b54131b1ae45bc9d3f68033a3e"
|
||||
version "3.4.9"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
|
||||
dependencies:
|
||||
commander "~2.17.1"
|
||||
source-map "~0.6.1"
|
||||
@ -7742,8 +7753,8 @@ webpack-log@^2.0.0:
|
||||
uuid "^3.3.2"
|
||||
|
||||
webpack-sources@^1.0.1, webpack-sources@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.2.0.tgz#18181e0d013fce096faf6f8e6d41eeffffdceac2"
|
||||
dependencies:
|
||||
source-list-map "^2.0.0"
|
||||
source-map "~0.6.1"
|
||||
@ -7817,6 +7828,14 @@ window-size@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
|
||||
|
||||
with-open-file@^0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/with-open-file/-/with-open-file-0.1.3.tgz#9d8ed7a993cd15c55b3f7b815930a94c430885a1"
|
||||
dependencies:
|
||||
p-finally "^1.0.0"
|
||||
p-try "^2.0.0"
|
||||
pify "^3.0.0"
|
||||
|
||||
wordwrap@0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
|
||||
|
Loading…
Reference in New Issue
Block a user