@lordbex/thelounge 4.4.4-blowfish → 4.5.0-blowfish-pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/defaults/config.js +31 -2
- package/dist/package.json +93 -91
- package/dist/server/client.js +188 -194
- package/dist/server/clientManager.js +65 -63
- package/dist/server/command-line/index.js +44 -43
- package/dist/server/command-line/install.js +37 -70
- package/dist/server/command-line/outdated.js +12 -17
- package/dist/server/command-line/start.js +25 -26
- package/dist/server/command-line/storage.js +26 -31
- package/dist/server/command-line/uninstall.js +16 -23
- package/dist/server/command-line/upgrade.js +20 -26
- package/dist/server/command-line/users/add.js +33 -40
- package/dist/server/command-line/users/edit.js +18 -24
- package/dist/server/command-line/users/index.js +12 -16
- package/dist/server/command-line/users/list.js +11 -39
- package/dist/server/command-line/users/remove.js +16 -22
- package/dist/server/command-line/users/reset.js +34 -35
- package/dist/server/command-line/utils.js +231 -87
- package/dist/server/config.js +61 -52
- package/dist/server/helper.js +29 -28
- package/dist/server/identification.js +39 -34
- package/dist/server/index.js +1 -3
- package/dist/server/log.js +19 -16
- package/dist/server/models/chan.js +36 -33
- package/dist/server/models/msg.js +15 -19
- package/dist/server/models/network.js +88 -86
- package/dist/server/models/prefix.js +4 -7
- package/dist/server/models/user.js +5 -10
- package/dist/server/path-helper.js +8 -0
- package/dist/server/plugins/auth/ldap.js +177 -112
- package/dist/server/plugins/auth/local.js +10 -15
- package/dist/server/plugins/auth.js +6 -35
- package/dist/server/plugins/changelog.js +30 -27
- package/dist/server/plugins/clientCertificate.js +33 -37
- package/dist/server/plugins/dev-server.js +15 -21
- package/dist/server/plugins/inputs/action.js +9 -14
- package/dist/server/plugins/inputs/away.js +1 -3
- package/dist/server/plugins/inputs/ban.js +9 -14
- package/dist/server/plugins/inputs/blow.js +9 -14
- package/dist/server/plugins/inputs/connect.js +5 -10
- package/dist/server/plugins/inputs/ctcp.js +7 -12
- package/dist/server/plugins/inputs/disconnect.js +1 -3
- package/dist/server/plugins/inputs/ignore.js +23 -29
- package/dist/server/plugins/inputs/ignorelist.js +12 -18
- package/dist/server/plugins/inputs/index.js +8 -34
- package/dist/server/plugins/inputs/invite.js +7 -12
- package/dist/server/plugins/inputs/kick.js +7 -12
- package/dist/server/plugins/inputs/kill.js +1 -3
- package/dist/server/plugins/inputs/list.js +1 -3
- package/dist/server/plugins/inputs/mode.js +10 -15
- package/dist/server/plugins/inputs/msg.js +13 -18
- package/dist/server/plugins/inputs/mute.js +9 -15
- package/dist/server/plugins/inputs/nick.js +9 -14
- package/dist/server/plugins/inputs/notice.js +5 -7
- package/dist/server/plugins/inputs/part.js +11 -16
- package/dist/server/plugins/inputs/quit.js +7 -13
- package/dist/server/plugins/inputs/rainbow.js +55 -0
- package/dist/server/plugins/inputs/raw.js +1 -3
- package/dist/server/plugins/inputs/rejoin.js +7 -12
- package/dist/server/plugins/inputs/topic.js +7 -12
- package/dist/server/plugins/inputs/whois.js +1 -3
- package/dist/server/plugins/irc-events/away.js +14 -20
- package/dist/server/plugins/irc-events/cap.js +16 -22
- package/dist/server/plugins/irc-events/chghost.js +14 -13
- package/dist/server/plugins/irc-events/connection.js +61 -63
- package/dist/server/plugins/irc-events/ctcp.js +22 -28
- package/dist/server/plugins/irc-events/error.js +20 -26
- package/dist/server/plugins/irc-events/help.js +7 -13
- package/dist/server/plugins/irc-events/info.js +7 -13
- package/dist/server/plugins/irc-events/invite.js +7 -13
- package/dist/server/plugins/irc-events/join.js +30 -27
- package/dist/server/plugins/irc-events/kick.js +21 -17
- package/dist/server/plugins/irc-events/link.js +75 -96
- package/dist/server/plugins/irc-events/list.js +23 -26
- package/dist/server/plugins/irc-events/message.js +46 -52
- package/dist/server/plugins/irc-events/mode.js +66 -63
- package/dist/server/plugins/irc-events/modelist.js +29 -35
- package/dist/server/plugins/irc-events/motd.js +10 -16
- package/dist/server/plugins/irc-events/names.js +3 -6
- package/dist/server/plugins/irc-events/nick.js +26 -23
- package/dist/server/plugins/irc-events/part.js +19 -15
- package/dist/server/plugins/irc-events/quit.js +17 -14
- package/dist/server/plugins/irc-events/sasl.js +9 -15
- package/dist/server/plugins/irc-events/spgroups.js +38 -0
- package/dist/server/plugins/irc-events/spjoin.js +52 -0
- package/dist/server/plugins/irc-events/topic.js +12 -18
- package/dist/server/plugins/irc-events/unhandled.js +12 -12
- package/dist/server/plugins/irc-events/welcome.js +7 -13
- package/dist/server/plugins/irc-events/whois.js +20 -24
- package/dist/server/plugins/massEventAggregator.js +214 -0
- package/dist/server/plugins/messageStorage/sqlite.js +322 -141
- package/dist/server/plugins/messageStorage/text.js +21 -26
- package/dist/server/plugins/packages/index.js +105 -74
- package/dist/server/plugins/packages/publicClient.js +7 -16
- package/dist/server/plugins/packages/themes.js +11 -16
- package/dist/server/plugins/storage.js +28 -33
- package/dist/server/plugins/sts.js +12 -17
- package/dist/server/plugins/uploader.js +40 -43
- package/dist/server/plugins/webpush.js +23 -51
- package/dist/server/server.js +318 -271
- package/dist/server/storageCleaner.js +29 -37
- package/dist/server/utils/fish.js +7 -14
- package/dist/shared/irc.js +3 -6
- package/dist/shared/linkify.js +7 -14
- package/dist/shared/types/chan.js +6 -9
- package/dist/shared/types/changelog.js +1 -2
- package/dist/shared/types/config.js +1 -2
- package/dist/shared/types/mention.js +1 -2
- package/dist/shared/types/msg.js +3 -5
- package/dist/shared/types/network.js +1 -2
- package/dist/shared/types/storage.js +1 -2
- package/dist/shared/types/user.js +1 -2
- package/index.js +14 -10
- package/package.json +93 -91
- package/public/css/style.css +9 -6
- package/public/css/style.css.map +1 -1
- package/public/fonts/font-awesome/fa-brands-400.ttf +0 -0
- package/public/fonts/font-awesome/fa-brands-400.woff2 +0 -0
- package/public/fonts/font-awesome/fa-duotone-900.ttf +0 -0
- package/public/fonts/font-awesome/fa-duotone-900.woff2 +0 -0
- package/public/fonts/font-awesome/fa-light-300.ttf +0 -0
- package/public/fonts/font-awesome/fa-light-300.woff2 +0 -0
- package/public/fonts/font-awesome/fa-regular-400.ttf +0 -0
- package/public/fonts/font-awesome/fa-regular-400.woff2 +0 -0
- package/public/fonts/font-awesome/fa-solid-900.ttf +0 -0
- package/public/fonts/font-awesome/fa-solid-900.woff2 +0 -0
- package/public/fonts/font-awesome/fa-thin-100.ttf +0 -0
- package/public/fonts/font-awesome/fa-thin-100.woff2 +0 -0
- package/public/fonts/font-awesome/fa-v4compatibility.ttf +0 -0
- package/public/fonts/font-awesome/fa-v4compatibility.woff2 +0 -0
- package/public/js/bundle.js +1 -1
- package/public/js/bundle.js.map +1 -1
- package/public/js/bundle.vendor.js +1 -1
- package/public/js/bundle.vendor.js.LICENSE.txt +24 -6
- package/public/js/bundle.vendor.js.map +1 -1
- package/public/service-worker.js +1 -1
- package/public/themes/default.css +1 -1
- package/public/themes/morning.css +1 -1
- package/dist/webpack.config.js +0 -224
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
1
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import filenamify from "filenamify";
|
|
5
|
+
import Config from "../../config.js";
|
|
6
|
+
import { MessageType } from "../../../shared/types/msg.js";
|
|
12
7
|
class TextFileMessageStorage {
|
|
13
8
|
isEnabled;
|
|
14
9
|
username;
|
|
@@ -28,9 +23,9 @@ class TextFileMessageStorage {
|
|
|
28
23
|
if (!this.isEnabled) {
|
|
29
24
|
return;
|
|
30
25
|
}
|
|
31
|
-
const logPath =
|
|
26
|
+
const logPath = path.join(Config.getUserLogsPath(), this.username, TextFileMessageStorage.getNetworkFolderName(network));
|
|
32
27
|
try {
|
|
33
|
-
await
|
|
28
|
+
await fs.mkdir(logPath, { recursive: true });
|
|
34
29
|
}
|
|
35
30
|
catch (e) {
|
|
36
31
|
throw new Error(`Unable to create logs directory: ${e}`);
|
|
@@ -38,47 +33,47 @@ class TextFileMessageStorage {
|
|
|
38
33
|
let line = `[${msg.time.toISOString()}] `;
|
|
39
34
|
// message types from src/models/msg.js
|
|
40
35
|
switch (msg.type) {
|
|
41
|
-
case
|
|
36
|
+
case MessageType.ACTION:
|
|
42
37
|
// [2014-01-01 00:00:00] * @Arnold is eating cookies
|
|
43
38
|
line += `* ${msg.from.mode}${msg.from.nick} ${msg.text}`;
|
|
44
39
|
break;
|
|
45
|
-
case
|
|
40
|
+
case MessageType.JOIN:
|
|
46
41
|
// [2014-01-01 00:00:00] *** Arnold (~arnold@foo.bar) joined
|
|
47
42
|
line += `*** ${msg.from.nick} (${msg.hostmask}) joined`;
|
|
48
43
|
break;
|
|
49
|
-
case
|
|
44
|
+
case MessageType.KICK:
|
|
50
45
|
// [2014-01-01 00:00:00] *** Arnold was kicked by Bernie (Don't steal my cookies!)
|
|
51
46
|
line += `*** ${msg.target.nick} was kicked by ${msg.from.nick} (${msg.text})`;
|
|
52
47
|
break;
|
|
53
|
-
case
|
|
48
|
+
case MessageType.MESSAGE:
|
|
54
49
|
// [2014-01-01 00:00:00] <@Arnold> Put that cookie down.. Now!!
|
|
55
50
|
line += `<${msg.from.mode}${msg.from.nick}> ${msg.text}`;
|
|
56
51
|
break;
|
|
57
|
-
case
|
|
52
|
+
case MessageType.MODE:
|
|
58
53
|
// [2014-01-01 00:00:00] *** Arnold set mode +o Bernie
|
|
59
54
|
line += `*** ${msg.from.nick} set mode ${msg.text}`;
|
|
60
55
|
break;
|
|
61
|
-
case
|
|
56
|
+
case MessageType.NICK:
|
|
62
57
|
// [2014-01-01 00:00:00] *** Arnold changed nick to Bernie
|
|
63
58
|
line += `*** ${msg.from.nick} changed nick to ${msg.new_nick}`;
|
|
64
59
|
break;
|
|
65
|
-
case
|
|
60
|
+
case MessageType.NOTICE:
|
|
66
61
|
// [2014-01-01 00:00:00] -Arnold- pssst, I have cookies!
|
|
67
62
|
line += `-${msg.from.nick}- ${msg.text}`;
|
|
68
63
|
break;
|
|
69
|
-
case
|
|
64
|
+
case MessageType.PART:
|
|
70
65
|
// [2014-01-01 00:00:00] *** Arnold (~arnold@foo.bar) left (Bye all!)
|
|
71
66
|
line += `*** ${msg.from.nick} (${msg.hostmask}) left (${msg.text})`;
|
|
72
67
|
break;
|
|
73
|
-
case
|
|
68
|
+
case MessageType.QUIT:
|
|
74
69
|
// [2014-01-01 00:00:00] *** Arnold (~arnold@foo.bar) quit (Connection reset by peer)
|
|
75
70
|
line += `*** ${msg.from.nick} (${msg.hostmask}) quit (${msg.text})`;
|
|
76
71
|
break;
|
|
77
|
-
case
|
|
72
|
+
case MessageType.CHGHOST:
|
|
78
73
|
// [2014-01-01 00:00:00] *** Arnold changed host to: new@fancy.host
|
|
79
74
|
line += `*** ${msg.from.nick} changed host to '${msg.new_ident}@${msg.new_host}'`;
|
|
80
75
|
break;
|
|
81
|
-
case
|
|
76
|
+
case MessageType.TOPIC:
|
|
82
77
|
// [2014-01-01 00:00:00] *** Arnold changed topic to: welcome everyone!
|
|
83
78
|
line += `*** ${msg.from.nick} changed topic to '${msg.text}'`;
|
|
84
79
|
break;
|
|
@@ -88,7 +83,7 @@ class TextFileMessageStorage {
|
|
|
88
83
|
}
|
|
89
84
|
line += "\n";
|
|
90
85
|
try {
|
|
91
|
-
await
|
|
86
|
+
await fs.appendFile(path.join(logPath, TextFileMessageStorage.getChannelFileName(channel)), line);
|
|
92
87
|
}
|
|
93
88
|
catch (e) {
|
|
94
89
|
throw new Error(`Failed to write user log: ${e}`);
|
|
@@ -116,9 +111,9 @@ class TextFileMessageStorage {
|
|
|
116
111
|
return `${cleanFilename(channel.name)}.log`;
|
|
117
112
|
}
|
|
118
113
|
}
|
|
119
|
-
|
|
114
|
+
export default TextFileMessageStorage;
|
|
120
115
|
function cleanFilename(name) {
|
|
121
|
-
name = (
|
|
116
|
+
name = filenamify(name, { replacement: "_" });
|
|
122
117
|
name = name.toLowerCase();
|
|
123
118
|
return name;
|
|
124
119
|
}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const themes_1 = __importDefault(require("./themes"));
|
|
14
|
-
const inputs_1 = __importDefault(require("../inputs"));
|
|
15
|
-
const fs_1 = __importDefault(require("fs"));
|
|
16
|
-
const utils_1 = __importDefault(require("../../command-line/utils"));
|
|
1
|
+
import _ from "lodash";
|
|
2
|
+
import log from "../../log.js";
|
|
3
|
+
import colors from "chalk";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import semver from "semver";
|
|
6
|
+
import Helper from "../../helper.js";
|
|
7
|
+
import Config from "../../config.js";
|
|
8
|
+
import themes from "./themes.js";
|
|
9
|
+
import inputs from "../inputs/index.js";
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import Utils from "../../command-line/utils.js";
|
|
12
|
+
import { pathToFileURL } from "url";
|
|
17
13
|
const packageMap = new Map();
|
|
18
14
|
const stylesheets = [];
|
|
19
15
|
const files = [];
|
|
@@ -22,12 +18,15 @@ const cache = {
|
|
|
22
18
|
outdated: undefined,
|
|
23
19
|
};
|
|
24
20
|
let experimentalWarningPrinted = false;
|
|
25
|
-
|
|
21
|
+
let packageWatcher = null;
|
|
22
|
+
export default {
|
|
26
23
|
getFiles,
|
|
27
24
|
getStylesheets,
|
|
28
25
|
getPackage,
|
|
29
26
|
loadPackages,
|
|
30
27
|
outdated,
|
|
28
|
+
stopWatching,
|
|
29
|
+
clearPackages,
|
|
31
30
|
};
|
|
32
31
|
// TODO: verify binds worked. Used to be 'this' instead of 'packageApis'
|
|
33
32
|
const packageApis = function (packageInfo) {
|
|
@@ -39,18 +38,18 @@ const packageApis = function (packageInfo) {
|
|
|
39
38
|
add: addFile.bind(packageApis, packageInfo.packageName),
|
|
40
39
|
},
|
|
41
40
|
Commands: {
|
|
42
|
-
add:
|
|
41
|
+
add: inputs.addPluginCommand.bind(packageApis, packageInfo),
|
|
43
42
|
runAsUser: (command, targetId, client) => client.inputLine({ target: targetId, text: command }),
|
|
44
43
|
},
|
|
45
44
|
Config: {
|
|
46
|
-
getConfig: () =>
|
|
45
|
+
getConfig: () => Config.values,
|
|
47
46
|
getPersistentStorageDir: getPersistentStorageDir.bind(packageApis, packageInfo.packageName),
|
|
48
47
|
},
|
|
49
48
|
Logger: {
|
|
50
|
-
error: (...args) =>
|
|
51
|
-
warn: (...args) =>
|
|
52
|
-
info: (...args) =>
|
|
53
|
-
debug: (...args) =>
|
|
49
|
+
error: (...args) => log.error(`[${packageInfo.packageName}]`, ...args),
|
|
50
|
+
warn: (...args) => log.warn(`[${packageInfo.packageName}]`, ...args),
|
|
51
|
+
info: (...args) => log.info(`[${packageInfo.packageName}]`, ...args),
|
|
52
|
+
debug: (...args) => log.debug(`[${packageInfo.packageName}]`, ...args),
|
|
54
53
|
},
|
|
55
54
|
};
|
|
56
55
|
};
|
|
@@ -69,43 +68,82 @@ function getFiles() {
|
|
|
69
68
|
function getPackage(name) {
|
|
70
69
|
return packageMap.get(name);
|
|
71
70
|
}
|
|
71
|
+
function clearPackages() {
|
|
72
|
+
packageMap.clear();
|
|
73
|
+
stylesheets.length = 0;
|
|
74
|
+
files.length = 0;
|
|
75
|
+
experimentalWarningPrinted = false;
|
|
76
|
+
}
|
|
72
77
|
function getEnabledPackages(packageJson) {
|
|
73
78
|
try {
|
|
74
|
-
const json = JSON.parse(
|
|
79
|
+
const json = JSON.parse(fs.readFileSync(packageJson, "utf-8"));
|
|
75
80
|
return Object.keys(json.dependencies);
|
|
76
81
|
}
|
|
77
82
|
catch (e) {
|
|
78
|
-
|
|
83
|
+
log.error(`Failed to read packages/package.json: ${colors.red(e)}`);
|
|
79
84
|
}
|
|
80
85
|
return [];
|
|
81
86
|
}
|
|
82
87
|
function getPersistentStorageDir(packageName) {
|
|
83
|
-
const dir =
|
|
84
|
-
|
|
88
|
+
const dir = path.join(Config.getPackagesPath(), packageName);
|
|
89
|
+
fs.mkdirSync(dir, { recursive: true }); // we don't care if it already exists or not
|
|
85
90
|
return dir;
|
|
86
91
|
}
|
|
87
|
-
function loadPackage(packageName) {
|
|
92
|
+
async function loadPackage(packageName) {
|
|
88
93
|
let packageInfo;
|
|
89
94
|
// TODO: type
|
|
90
95
|
let packageFile;
|
|
91
96
|
try {
|
|
92
|
-
const packagePath =
|
|
93
|
-
packageInfo = JSON.parse(
|
|
97
|
+
const packagePath = Config.getPackageModulePath(packageName);
|
|
98
|
+
packageInfo = JSON.parse(fs.readFileSync(path.join(packagePath, "package.json"), "utf-8"));
|
|
94
99
|
if (!packageInfo.thelounge) {
|
|
95
|
-
throw "'thelounge' is not present in package.json";
|
|
100
|
+
throw new Error("'thelounge' is not present in package.json");
|
|
96
101
|
}
|
|
97
102
|
if (packageInfo.thelounge.supports &&
|
|
98
|
-
!
|
|
103
|
+
!semver.satisfies(Helper.getVersionNumber(), packageInfo.thelounge.supports, {
|
|
99
104
|
includePrerelease: true, // our pre-releases should respect the semver guarantees
|
|
100
105
|
})) {
|
|
101
|
-
throw `v${packageInfo.version} does not support this version of The Lounge. Supports: ${packageInfo.thelounge.supports}
|
|
106
|
+
throw new Error(`v${packageInfo.version} does not support this version of The Lounge. Supports: ${packageInfo.thelounge.supports}`);
|
|
107
|
+
}
|
|
108
|
+
// ESM requires importing a file, not a directory
|
|
109
|
+
// Determine the entry point from package.json
|
|
110
|
+
let entryPoint = "index.js";
|
|
111
|
+
if (typeof packageInfo.exports === "string") {
|
|
112
|
+
entryPoint = packageInfo.exports;
|
|
113
|
+
}
|
|
114
|
+
else if (packageInfo.exports && typeof packageInfo.exports === "object") {
|
|
115
|
+
// Handle exports map like { ".": "./index.js" } or { "import": "...", "require": "..." }
|
|
116
|
+
const exportsObj = packageInfo.exports;
|
|
117
|
+
if (typeof exportsObj["."] === "string") {
|
|
118
|
+
entryPoint = exportsObj["."];
|
|
119
|
+
}
|
|
120
|
+
else if (typeof exportsObj.import === "string") {
|
|
121
|
+
entryPoint = exportsObj.import;
|
|
122
|
+
}
|
|
123
|
+
else if (typeof exportsObj.require === "string") {
|
|
124
|
+
entryPoint = exportsObj.require;
|
|
125
|
+
}
|
|
126
|
+
else if (exportsObj["."] && typeof exportsObj["."] === "object") {
|
|
127
|
+
const dotExports = exportsObj["."];
|
|
128
|
+
entryPoint =
|
|
129
|
+
dotExports.import || dotExports.require || dotExports.default || "index.js";
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (packageInfo.main) {
|
|
133
|
+
entryPoint = packageInfo.main;
|
|
102
134
|
}
|
|
103
|
-
|
|
135
|
+
const isJSONImport = entryPoint.endsWith(".json");
|
|
136
|
+
const fullEntryPath = pathToFileURL(path.join(packagePath, entryPoint)).href;
|
|
137
|
+
const imported = isJSONImport
|
|
138
|
+
? await import(fullEntryPath, { with: { type: "json" } })
|
|
139
|
+
: await import(fullEntryPath);
|
|
140
|
+
// Handle both ESM (direct exports) and CommonJS (wrapped in .default) modules
|
|
141
|
+
packageFile = imported.default || imported;
|
|
104
142
|
}
|
|
105
143
|
catch (e) {
|
|
106
|
-
|
|
144
|
+
log.error(`Package ${colors.bold(packageName)} could not be loaded: ${colors.red(e)}`);
|
|
107
145
|
if (e instanceof Error) {
|
|
108
|
-
|
|
146
|
+
log.debug(e.stack ? e.stack : e.message);
|
|
109
147
|
}
|
|
110
148
|
return;
|
|
111
149
|
}
|
|
@@ -117,8 +155,8 @@ function loadPackage(packageName) {
|
|
|
117
155
|
};
|
|
118
156
|
packageMap.set(packageName, packageFile);
|
|
119
157
|
if (packageInfo.type === "theme") {
|
|
120
|
-
//
|
|
121
|
-
|
|
158
|
+
// PackageInfo includes theme-specific fields when type === "theme"
|
|
159
|
+
themes.addTheme(packageName, packageInfo);
|
|
122
160
|
if (packageInfo.files) {
|
|
123
161
|
packageInfo.files.forEach((file) => addFile(packageName, file));
|
|
124
162
|
}
|
|
@@ -126,68 +164,61 @@ function loadPackage(packageName) {
|
|
|
126
164
|
if (packageFile.onServerStart) {
|
|
127
165
|
packageFile.onServerStart(packageApis(packageInfo));
|
|
128
166
|
}
|
|
129
|
-
|
|
167
|
+
log.info(`Package ${colors.bold(packageName)} ${colors.green("v" + version)} loaded`);
|
|
130
168
|
if (packageInfo.type !== "theme" && !experimentalWarningPrinted) {
|
|
131
169
|
experimentalWarningPrinted = true;
|
|
132
|
-
|
|
170
|
+
log.info("There are packages using the experimental plugin API. " +
|
|
133
171
|
"Be aware that this API is not yet stable and may change in future The Lounge releases.");
|
|
134
172
|
}
|
|
135
173
|
}
|
|
136
|
-
function loadPackages() {
|
|
137
|
-
const packageJson =
|
|
174
|
+
async function loadPackages() {
|
|
175
|
+
const packageJson = path.join(Config.getPackagesPath(), "package.json");
|
|
138
176
|
const packages = getEnabledPackages(packageJson);
|
|
139
|
-
packages.
|
|
177
|
+
await Promise.all(packages.map((pkg) => loadPackage(pkg)));
|
|
140
178
|
watchPackages(packageJson);
|
|
141
179
|
}
|
|
142
180
|
function watchPackages(packageJson) {
|
|
143
|
-
|
|
181
|
+
packageWatcher = fs.watch(packageJson, {
|
|
144
182
|
persistent: false,
|
|
145
|
-
},
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
183
|
+
}, _.debounce(() => {
|
|
184
|
+
void (async () => {
|
|
185
|
+
const updated = getEnabledPackages(packageJson);
|
|
186
|
+
for (const packageName of updated) {
|
|
187
|
+
if (packageMap.has(packageName)) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
await loadPackage(packageName);
|
|
150
191
|
}
|
|
151
|
-
|
|
152
|
-
}
|
|
192
|
+
})();
|
|
153
193
|
}, 1000, { maxWait: 10000 }));
|
|
154
194
|
}
|
|
195
|
+
function stopWatching() {
|
|
196
|
+
if (packageWatcher) {
|
|
197
|
+
packageWatcher.close();
|
|
198
|
+
packageWatcher = null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
155
201
|
async function outdated(cacheTimeout = TIME_TO_LIVE) {
|
|
156
202
|
if (cache.outdated !== undefined) {
|
|
157
203
|
return cache.outdated;
|
|
158
204
|
}
|
|
159
205
|
// Get paths to the location of packages directory
|
|
160
|
-
const packagesPath =
|
|
161
|
-
const packagesConfig =
|
|
162
|
-
const packagesList = JSON.parse(
|
|
163
|
-
const argsList = [
|
|
164
|
-
"outdated",
|
|
165
|
-
"--latest",
|
|
166
|
-
"--json",
|
|
167
|
-
"--production",
|
|
168
|
-
"--ignore-scripts",
|
|
169
|
-
"--non-interactive",
|
|
170
|
-
"--cwd",
|
|
171
|
-
packagesPath,
|
|
172
|
-
];
|
|
206
|
+
const packagesPath = Config.getPackagesPath();
|
|
207
|
+
const packagesConfig = path.join(packagesPath, "package.json");
|
|
208
|
+
const packagesList = JSON.parse(fs.readFileSync(packagesConfig, "utf-8")).dependencies;
|
|
173
209
|
// Check if the configuration file exists
|
|
174
210
|
if (!Object.entries(packagesList).length) {
|
|
175
211
|
// CLI calls outdated with zero TTL, so we can print the warning there
|
|
176
212
|
if (!cacheTimeout) {
|
|
177
|
-
|
|
213
|
+
log.warn("There are no packages installed.");
|
|
178
214
|
}
|
|
179
215
|
return false;
|
|
180
216
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
// If we get an error from calling outdated and the code isn't 0, then there are no outdated packages
|
|
187
|
-
// TODO: was (...argsList), verify this works
|
|
188
|
-
await utils_1.default.executeYarnCommand(command, ...params)
|
|
217
|
+
// npm outdated returns exit code 1 when packages are outdated, 0 when all up to date
|
|
218
|
+
// executeYarnCommand handles this mapping
|
|
219
|
+
await Utils.executeYarnCommand("outdated")
|
|
189
220
|
.then(() => updateOutdated(false))
|
|
190
|
-
.catch((
|
|
221
|
+
.catch(() => updateOutdated(true));
|
|
191
222
|
if (cacheTimeout > 0) {
|
|
192
223
|
setTimeout(() => {
|
|
193
224
|
delete cache.outdated;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const msg_1 = __importDefault(require("../../models/msg"));
|
|
7
|
-
const msg_2 = require("../../../shared/types/msg");
|
|
8
|
-
class PublicClient {
|
|
1
|
+
import Msg from "../../models/msg.js";
|
|
2
|
+
import { MessageType } from "../../../shared/types/msg.js";
|
|
3
|
+
export default class PublicClient {
|
|
9
4
|
client;
|
|
10
5
|
packageInfo;
|
|
11
6
|
constructor(client, packageInfo) {
|
|
@@ -33,11 +28,8 @@ class PublicClient {
|
|
|
33
28
|
* @param {String} event - Name of the event, must be something the browser will recognise
|
|
34
29
|
* @param {Object} data - Body of the event, can be anything, but will need to be properly interpreted by the client
|
|
35
30
|
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// Plus it is completely insane to let a plugin inject arbitrary events like that
|
|
39
|
-
sendToBrowser(event, data) {
|
|
40
|
-
this.client.emit(event, data);
|
|
31
|
+
sendToBrowser(event, ...args) {
|
|
32
|
+
this.client.emit(event, ...args);
|
|
41
33
|
}
|
|
42
34
|
/**
|
|
43
35
|
*
|
|
@@ -53,8 +45,8 @@ class PublicClient {
|
|
|
53
45
|
* @param {Chan} chan the channel to send the message to
|
|
54
46
|
*/
|
|
55
47
|
sendMessage(text, chan) {
|
|
56
|
-
chan.pushMessage(this.client, new
|
|
57
|
-
type:
|
|
48
|
+
chan.pushMessage(this.client, new Msg({
|
|
49
|
+
type: MessageType.PLUGIN,
|
|
58
50
|
text: text,
|
|
59
51
|
from: {
|
|
60
52
|
nick: this.packageInfo.name || this.packageInfo.packageName,
|
|
@@ -63,4 +55,3 @@ class PublicClient {
|
|
|
63
55
|
}));
|
|
64
56
|
}
|
|
65
57
|
}
|
|
66
|
-
exports.default = PublicClient;
|
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const fs_1 = __importDefault(require("fs"));
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
9
|
-
const config_1 = __importDefault(require("../../config"));
|
|
10
|
-
const utils_1 = __importDefault(require("../../command-line/utils"));
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import Config from "../../config.js";
|
|
5
|
+
import Utils from "../../command-line/utils.js";
|
|
11
6
|
const themes = new Map();
|
|
12
|
-
|
|
7
|
+
export default {
|
|
13
8
|
addTheme,
|
|
14
9
|
getAll,
|
|
15
10
|
getByName,
|
|
16
11
|
loadLocalThemes,
|
|
17
12
|
};
|
|
18
13
|
function loadLocalThemes() {
|
|
19
|
-
const builtInThemes =
|
|
14
|
+
const builtInThemes = fs.readdirSync(Utils.getFileFromRelativeToRoot("public", "themes"));
|
|
20
15
|
builtInThemes
|
|
21
16
|
.filter((theme) => theme.endsWith(".css"))
|
|
22
17
|
.map(makeLocalThemeObject)
|
|
@@ -31,9 +26,9 @@ function addTheme(packageName, packageObject) {
|
|
|
31
26
|
function getAll() {
|
|
32
27
|
const filteredThemes = [];
|
|
33
28
|
for (const theme of themes.values()) {
|
|
34
|
-
filteredThemes.push(
|
|
29
|
+
filteredThemes.push(_.pick(theme, ["displayName", "name", "themeColor"]));
|
|
35
30
|
}
|
|
36
|
-
return
|
|
31
|
+
return _.sortBy(filteredThemes, "displayName");
|
|
37
32
|
}
|
|
38
33
|
function getByName(name) {
|
|
39
34
|
return themes.get(name);
|
|
@@ -51,10 +46,10 @@ function makePackageThemeObject(moduleName, module) {
|
|
|
51
46
|
return;
|
|
52
47
|
}
|
|
53
48
|
const themeColor = /^#[0-9A-F]{6}$/i.test(module.themeColor) ? module.themeColor : null;
|
|
54
|
-
const modulePath =
|
|
49
|
+
const modulePath = Config.getPackageModulePath(moduleName);
|
|
55
50
|
return {
|
|
56
51
|
displayName: module.name || moduleName,
|
|
57
|
-
filename:
|
|
52
|
+
filename: path.join(modulePath, module.css),
|
|
58
53
|
name: encodeURIComponent(moduleName),
|
|
59
54
|
themeColor: themeColor,
|
|
60
55
|
};
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const log_1 = __importDefault(require("../log"));
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
-
const config_1 = __importDefault(require("../config"));
|
|
1
|
+
import log from "../log.js";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import crypto from "crypto";
|
|
5
|
+
import Config from "../config.js";
|
|
11
6
|
class Storage {
|
|
12
7
|
references;
|
|
13
8
|
constructor() {
|
|
@@ -17,55 +12,55 @@ class Storage {
|
|
|
17
12
|
// Ensures that a directory is empty.
|
|
18
13
|
// Deletes directory contents if the directory is not empty.
|
|
19
14
|
// If the directory does not exist, it is created.
|
|
20
|
-
const dir =
|
|
15
|
+
const dir = Config.getStoragePath();
|
|
21
16
|
let items;
|
|
22
17
|
try {
|
|
23
|
-
items =
|
|
18
|
+
items = fs.readdirSync(dir);
|
|
24
19
|
}
|
|
25
|
-
catch
|
|
26
|
-
|
|
20
|
+
catch {
|
|
21
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
27
22
|
return;
|
|
28
23
|
}
|
|
29
24
|
// TODO: Use `fs.rmdirSync(dir, {recursive: true});` when it's stable (node 13+)
|
|
30
|
-
items.forEach((item) => deleteFolder(
|
|
25
|
+
items.forEach((item) => deleteFolder(path.join(dir, item)));
|
|
31
26
|
}
|
|
32
27
|
dereference(url) {
|
|
33
28
|
const references = (this.references.get(url) || 0) - 1;
|
|
34
29
|
if (references < 0) {
|
|
35
|
-
return
|
|
30
|
+
return log.warn("Tried to dereference a file that has no references", url);
|
|
36
31
|
}
|
|
37
32
|
if (references > 0) {
|
|
38
33
|
return this.references.set(url, references);
|
|
39
34
|
}
|
|
40
35
|
this.references.delete(url);
|
|
41
36
|
// Drop "storage/" from url and join it with full storage path
|
|
42
|
-
const filePath =
|
|
43
|
-
|
|
37
|
+
const filePath = path.join(Config.getStoragePath(), url.substring(8));
|
|
38
|
+
fs.unlink(filePath, (err) => {
|
|
44
39
|
if (err) {
|
|
45
|
-
|
|
40
|
+
log.error("Failed to delete stored file", err.message);
|
|
46
41
|
}
|
|
47
42
|
});
|
|
48
43
|
}
|
|
49
44
|
store(data, extension, callback) {
|
|
50
|
-
const hash =
|
|
45
|
+
const hash = crypto.createHash("sha256").update(data).digest("hex");
|
|
51
46
|
const a = hash.substring(0, 2);
|
|
52
47
|
const b = hash.substring(2, 4);
|
|
53
|
-
const folder =
|
|
54
|
-
const filePath =
|
|
48
|
+
const folder = path.join(Config.getStoragePath(), a, b);
|
|
49
|
+
const filePath = path.join(folder, `${hash.substring(4)}.${extension}`);
|
|
55
50
|
const url = `storage/${a}/${b}/${hash.substring(4)}.${extension}`;
|
|
56
51
|
this.references.set(url, 1 + (this.references.get(url) || 0));
|
|
57
52
|
// If file with this name already exists, we don't need to write it again
|
|
58
|
-
if (
|
|
53
|
+
if (fs.existsSync(filePath)) {
|
|
59
54
|
return callback(url);
|
|
60
55
|
}
|
|
61
|
-
|
|
56
|
+
fs.mkdir(folder, { recursive: true }, (mkdirErr) => {
|
|
62
57
|
if (mkdirErr) {
|
|
63
|
-
|
|
58
|
+
log.error("Failed to create storage folder", mkdirErr.message);
|
|
64
59
|
return callback("");
|
|
65
60
|
}
|
|
66
|
-
|
|
61
|
+
fs.writeFile(filePath, data, (err) => {
|
|
67
62
|
if (err) {
|
|
68
|
-
|
|
63
|
+
log.error("Failed to store a file", err.message);
|
|
69
64
|
return callback("");
|
|
70
65
|
}
|
|
71
66
|
callback(url);
|
|
@@ -73,16 +68,16 @@ class Storage {
|
|
|
73
68
|
});
|
|
74
69
|
}
|
|
75
70
|
}
|
|
76
|
-
|
|
71
|
+
export default new Storage();
|
|
77
72
|
function deleteFolder(dir) {
|
|
78
|
-
|
|
79
|
-
item =
|
|
80
|
-
if (
|
|
73
|
+
fs.readdirSync(dir).forEach((item) => {
|
|
74
|
+
item = path.join(dir, item);
|
|
75
|
+
if (fs.lstatSync(item).isDirectory()) {
|
|
81
76
|
deleteFolder(item);
|
|
82
77
|
}
|
|
83
78
|
else {
|
|
84
|
-
|
|
79
|
+
fs.unlinkSync(item);
|
|
85
80
|
}
|
|
86
81
|
});
|
|
87
|
-
|
|
82
|
+
fs.rmdirSync(dir);
|
|
88
83
|
}
|