omegga 1.2.8 → 1.3.0
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 +20 -1
- package/dist/brickadia/config.js +26 -90
- package/dist/brickadia/config.js.map +1 -1
- package/dist/brickadia/server.js +294 -293
- package/dist/brickadia/server.js.map +1 -1
- package/dist/cli/auth.js +149 -177
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/config.js +64 -66
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.js +14 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/installer.js +37 -43
- package/dist/cli/installer.js.map +1 -1
- package/dist/cli/plugin.js +651 -682
- package/dist/cli/plugin.js.map +1 -1
- package/dist/cli/terminal.js +811 -733
- package/dist/cli/terminal.js.map +1 -1
- package/dist/config/formats/format_js.js +6 -6
- package/dist/config/formats/format_js.js.map +1 -1
- package/dist/config/formats/format_yml.js +7 -10
- package/dist/config/formats/format_yml.js.map +1 -1
- package/dist/config/index.js +46 -68
- package/dist/config/index.js.map +1 -1
- package/dist/config/reader.js +16 -27
- package/dist/config/reader.js.map +1 -1
- package/dist/config/validator.js +23 -25
- package/dist/config/validator.js.map +1 -1
- package/dist/config/writer.js +11 -21
- package/dist/config/writer.js.map +1 -1
- package/dist/index.js +18 -64
- package/dist/index.js.map +1 -1
- package/dist/info/default_commands.json.js +39 -0
- package/dist/info/default_commands.json.js.map +1 -0
- package/dist/logger.js +61 -60
- package/dist/logger.js.map +1 -1
- package/dist/main.js +424 -471
- package/dist/main.js.map +1 -1
- package/dist/omegga/auth.js +101 -148
- package/dist/omegga/auth.js.map +1 -1
- package/dist/omegga/commandInjector.js +261 -251
- package/dist/omegga/commandInjector.js.map +1 -1
- package/dist/omegga/index.js +14 -52
- package/dist/omegga/index.js.map +1 -1
- package/dist/omegga/logWrangler.js +224 -275
- package/dist/omegga/logWrangler.js.map +1 -1
- package/dist/omegga/matchers/auth.js +36 -50
- package/dist/omegga/matchers/auth.js.map +1 -1
- package/dist/omegga/matchers/chat.js +49 -71
- package/dist/omegga/matchers/chat.js.map +1 -1
- package/dist/omegga/matchers/command.js +25 -36
- package/dist/omegga/matchers/command.js.map +1 -1
- package/dist/omegga/matchers/exit.js +15 -18
- package/dist/omegga/matchers/exit.js.map +1 -1
- package/dist/omegga/matchers/index.js +26 -40
- package/dist/omegga/matchers/index.js.map +1 -1
- package/dist/omegga/matchers/init.js +20 -23
- package/dist/omegga/matchers/init.js.map +1 -1
- package/dist/omegga/matchers/interact.js +58 -64
- package/dist/omegga/matchers/interact.js.map +1 -1
- package/dist/omegga/matchers/join.js +74 -95
- package/dist/omegga/matchers/join.js.map +1 -1
- package/dist/omegga/matchers/leave.js +43 -56
- package/dist/omegga/matchers/leave.js.map +1 -1
- package/dist/omegga/matchers/mapChange.js +26 -35
- package/dist/omegga/matchers/mapChange.js.map +1 -1
- package/dist/omegga/matchers/minigameJoin.js +24 -31
- package/dist/omegga/matchers/minigameJoin.js.map +1 -1
- package/dist/omegga/matchers/version.js +42 -49
- package/dist/omegga/matchers/version.js.map +1 -1
- package/dist/omegga/player.js +527 -527
- package/dist/omegga/player.js.map +1 -1
- package/dist/omegga/plugin/interface.js +91 -98
- package/dist/omegga/plugin/interface.js.map +1 -1
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.js +524 -429
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js +282 -294
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_safe.js +365 -393
- package/dist/omegga/plugin/plugin_node_safe.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_unsafe.js +119 -179
- package/dist/omegga/plugin/plugin_node_unsafe.js.map +1 -1
- package/dist/omegga/plugin.js +402 -347
- package/dist/omegga/plugin.js.map +1 -1
- package/dist/omegga/server.js +742 -774
- package/dist/omegga/server.js.map +1 -1
- package/dist/omegga/wrapper.js +64 -91
- package/dist/omegga/wrapper.js.map +1 -1
- package/dist/plugin.js +11 -31
- package/dist/plugin.js.map +1 -1
- package/dist/softconfig.js +121 -100
- package/dist/softconfig.js.map +1 -1
- package/dist/updater/steam.js +97 -112
- package/dist/updater/steam.js.map +1 -1
- package/dist/util/brdb.js +496 -528
- package/dist/util/brdb.js.map +1 -1
- package/dist/util/brick/checkBounds.js +11 -15
- package/dist/util/brick/checkBounds.js.map +1 -1
- package/dist/util/brick/constants.js +723 -174
- package/dist/util/brick/constants.js.map +1 -1
- package/dist/util/brick/displayName.js +204 -211
- package/dist/util/brick/displayName.js.map +1 -1
- package/dist/util/brick/getBounds.js +29 -41
- package/dist/util/brick/getBounds.js.map +1 -1
- package/dist/util/brick/getBrickSize.js +6 -7
- package/dist/util/brick/getBrickSize.js.map +1 -1
- package/dist/util/brick/getScaleAxis.js +24 -30
- package/dist/util/brick/getScaleAxis.js.map +1 -1
- package/dist/util/brick/index.js +8 -29
- package/dist/util/brick/index.js.map +1 -1
- package/dist/util/brick/rotate.js +29 -34
- package/dist/util/brick/rotate.js.map +1 -1
- package/dist/util/brick/setOwnership.js +13 -19
- package/dist/util/brick/setOwnership.js.map +1 -1
- package/dist/util/chat.js +53 -44
- package/dist/util/chat.js.map +1 -1
- package/dist/util/color.js +112 -124
- package/dist/util/color.js.map +1 -1
- package/dist/util/file.js +54 -98
- package/dist/util/file.js.map +1 -1
- package/dist/util/index.js +84 -106
- package/dist/util/index.js.map +1 -1
- package/dist/util/map.js +18 -20
- package/dist/util/map.js.map +1 -1
- package/dist/util/pattern.js +6 -9
- package/dist/util/pattern.js.map +1 -1
- package/dist/util/time.js +31 -34
- package/dist/util/time.js.map +1 -1
- package/dist/util/uuid.js +10 -8
- package/dist/util/uuid.js.map +1 -1
- package/dist/util/wsl.js +19 -25
- package/dist/util/wsl.js.map +1 -1
- package/dist/version.js +7 -9
- package/dist/version.js.map +1 -1
- package/dist/webserver/backend/api.js +784 -874
- package/dist/webserver/backend/api.js.map +1 -1
- package/dist/webserver/backend/calendar.js +14 -17
- package/dist/webserver/backend/calendar.js.map +1 -1
- package/dist/webserver/backend/database.js +563 -613
- package/dist/webserver/backend/database.js.map +1 -1
- package/dist/webserver/backend/index.js +153 -191
- package/dist/webserver/backend/index.js.map +1 -1
- package/dist/webserver/backend/metrics.js +219 -248
- package/dist/webserver/backend/metrics.js.map +1 -1
- package/dist/webserver/backend/util.js +47 -68
- package/dist/webserver/backend/util.js.map +1 -1
- package/dist/worker.js +322 -0
- package/dist/worker.js.map +1 -0
- package/package.json +14 -10
- package/templates/safe-ts/omegga.d.ts +2 -2
- package/vite.backend.config.mts +46 -0
- package/vite.frontend.config.mts +58 -0
- package/vitest.backend.config.mts +7 -0
- package/dist/brickadia/config.d.ts +0 -3
- package/dist/brickadia/presets.d.ts +0 -65
- package/dist/brickadia/presets.js +0 -3
- package/dist/brickadia/presets.js.map +0 -1
- package/dist/brickadia/server.d.ts +0 -36
- package/dist/brickadia/types.d.ts +0 -45
- package/dist/brickadia/types.js +0 -3
- package/dist/brickadia/types.js.map +0 -1
- package/dist/cli/auth.d.ts +0 -26
- package/dist/cli/config.d.ts +0 -10
- package/dist/cli/index.d.ts +0 -30
- package/dist/cli/installer.d.ts +0 -1
- package/dist/cli/plugin.d.ts +0 -22
- package/dist/cli/terminal.d.ts +0 -25
- package/dist/config/authorizer.d.ts +0 -2
- package/dist/config/authorizer.js +0 -38
- package/dist/config/authorizer.js.map +0 -1
- package/dist/config/formats/format_js.d.ts +0 -3
- package/dist/config/formats/format_yml.d.ts +0 -3
- package/dist/config/index.d.ts +0 -18
- package/dist/config/reader.d.ts +0 -3
- package/dist/config/types.d.ts +0 -50
- package/dist/config/types.js +0 -3
- package/dist/config/types.js.map +0 -1
- package/dist/config/validator.d.ts +0 -6
- package/dist/config/writer.d.ts +0 -3
- package/dist/index.d.ts +0 -22
- package/dist/info/default_commands.json +0 -29
- package/dist/logger.d.ts +0 -41
- package/dist/main.d.ts +0 -1
- package/dist/omegga/auth.d.ts +0 -9
- package/dist/omegga/commandInjector.d.ts +0 -35
- package/dist/omegga/index.d.ts +0 -7
- package/dist/omegga/logWrangler.d.ts +0 -32
- package/dist/omegga/matchers/auth.d.ts +0 -10
- package/dist/omegga/matchers/chat.d.ts +0 -10
- package/dist/omegga/matchers/command.d.ts +0 -7
- package/dist/omegga/matchers/exit.d.ts +0 -3
- package/dist/omegga/matchers/index.d.ts +0 -3
- package/dist/omegga/matchers/init.d.ts +0 -3
- package/dist/omegga/matchers/interact.d.ts +0 -4
- package/dist/omegga/matchers/join.d.ts +0 -4
- package/dist/omegga/matchers/leave.d.ts +0 -4
- package/dist/omegga/matchers/mapChange.d.ts +0 -3
- package/dist/omegga/matchers/minigameJoin.d.ts +0 -9
- package/dist/omegga/matchers/types.d.ts +0 -5
- package/dist/omegga/matchers/types.js +0 -3
- package/dist/omegga/matchers/types.js.map +0 -1
- package/dist/omegga/matchers/version.d.ts +0 -3
- package/dist/omegga/player.d.ts +0 -81
- package/dist/omegga/plugin/interface.d.ts +0 -30
- package/dist/omegga/plugin/plugin_jsonrpc_stdio.d.ts +0 -23
- package/dist/omegga/plugin/plugin_node_safe/proxyOmegga.d.ts +0 -145
- package/dist/omegga/plugin/plugin_node_safe/worker.d.ts +0 -1
- package/dist/omegga/plugin/plugin_node_safe/worker.js +0 -367
- package/dist/omegga/plugin/plugin_node_safe/worker.js.map +0 -1
- package/dist/omegga/plugin/plugin_node_safe.d.ts +0 -23
- package/dist/omegga/plugin/plugin_node_unsafe.d.ts +0 -13
- package/dist/omegga/plugin.d.ts +0 -63
- package/dist/omegga/server.d.ts +0 -166
- package/dist/omegga/types.d.ts +0 -49
- package/dist/omegga/types.js +0 -3
- package/dist/omegga/types.js.map +0 -1
- package/dist/omegga/wrapper.d.ts +0 -32
- package/dist/plugin.d.ts +0 -916
- package/dist/softconfig.d.ts +0 -67
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/updater/index.d.ts +0 -1
- package/dist/updater/index.js +0 -10
- package/dist/updater/index.js.map +0 -1
- package/dist/updater/steam.d.ts +0 -52
- package/dist/util/brdb.d.ts +0 -31
- package/dist/util/brick/checkBounds.d.ts +0 -8
- package/dist/util/brick/constants.d.ts +0 -18
- package/dist/util/brick/displayName.d.ts +0 -7
- package/dist/util/brick/getBounds.d.ts +0 -5
- package/dist/util/brick/getBrickSize.d.ts +0 -3
- package/dist/util/brick/getScaleAxis.d.ts +0 -3
- package/dist/util/brick/index.d.ts +0 -14
- package/dist/util/brick/rotate.d.ts +0 -16
- package/dist/util/brick/setOwnership.d.ts +0 -12
- package/dist/util/chat.d.ts +0 -23
- package/dist/util/color.d.ts +0 -13
- package/dist/util/file.d.ts +0 -5
- package/dist/util/index.d.ts +0 -183
- package/dist/util/map.d.ts +0 -6
- package/dist/util/pattern.d.ts +0 -1
- package/dist/util/time.d.ts +0 -39
- package/dist/util/uuid.d.ts +0 -3
- package/dist/util/wsl.d.ts +0 -2
- package/dist/version.d.ts +0 -2
- package/dist/webserver/backend/api.d.ts +0 -115
- package/dist/webserver/backend/calendar.d.ts +0 -5
- package/dist/webserver/backend/database.d.ts +0 -150
- package/dist/webserver/backend/index.d.ts +0 -30
- package/dist/webserver/backend/metrics.d.ts +0 -3
- package/dist/webserver/backend/types.d.ts +0 -114
- package/dist/webserver/backend/types.js +0 -3
- package/dist/webserver/backend/types.js.map +0 -1
- package/dist/webserver/backend/util.d.ts +0 -2
- package/dist/webserver/index.d.ts +0 -2
- package/dist/webserver/index.js +0 -9
- package/dist/webserver/index.js.map +0 -1
package/dist/omegga/plugin.js
CHANGED
|
@@ -1,371 +1,426 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const path_1 = __importDefault(require("path"));
|
|
12
|
-
const plugin_jsonrpc_stdio_1 = __importDefault(require("./plugin/plugin_jsonrpc_stdio"));
|
|
13
|
-
const plugin_node_safe_1 = __importDefault(require("./plugin/plugin_node_safe"));
|
|
14
|
-
const plugin_node_unsafe_1 = __importDefault(require("./plugin/plugin_node_unsafe"));
|
|
15
|
-
// key-value storage for a plugin
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const logger = require("../logger.js");
|
|
4
|
+
const softconfig = require("../softconfig.js");
|
|
5
|
+
const Datastore = require("nedb-promises");
|
|
6
|
+
const fs = require("node:fs");
|
|
7
|
+
const path = require("node:path");
|
|
8
|
+
const plugin_jsonrpc_stdio = require("./plugin/plugin_jsonrpc_stdio.js");
|
|
9
|
+
const plugin_node_safe = require("./plugin/plugin_node_safe.js");
|
|
10
|
+
const plugin_node_unsafe = require("./plugin/plugin_node_unsafe.js");
|
|
16
11
|
class PluginStorage {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
constructor(store, plugin) {
|
|
13
|
+
this.store = store;
|
|
14
|
+
this.plugin = plugin;
|
|
15
|
+
this.name = plugin.getName();
|
|
16
|
+
}
|
|
17
|
+
// get the initial config values
|
|
18
|
+
getDefaultConfig() {
|
|
19
|
+
const doc = this.plugin.getDocumentation();
|
|
20
|
+
if (!doc) return {};
|
|
21
|
+
if (!doc.config) return {};
|
|
22
|
+
const config = {};
|
|
23
|
+
for (const k in doc.config) {
|
|
24
|
+
config[k] = doc.config[k].default;
|
|
21
25
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
// set the config field for this plugin
|
|
29
|
+
async setConfig(value) {
|
|
30
|
+
await this.store.update(
|
|
31
|
+
{ type: "config", plugin: this.name },
|
|
32
|
+
{
|
|
33
|
+
$set: { value }
|
|
34
|
+
},
|
|
35
|
+
{ upsert: true }
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
// get the config for this plugin
|
|
39
|
+
async getConfig() {
|
|
40
|
+
const config = await this.store.findOne({
|
|
41
|
+
type: "config",
|
|
42
|
+
plugin: this.name
|
|
43
|
+
});
|
|
44
|
+
if (!config) return null;
|
|
45
|
+
return config.value;
|
|
46
|
+
}
|
|
47
|
+
/** Wipes the configs for the plugin. */
|
|
48
|
+
async wipeConfig() {
|
|
49
|
+
await this.store.remove(
|
|
50
|
+
{ type: "config", plugin: this.name },
|
|
51
|
+
{ multi: true }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
/** Initializes the configs for the plugin into the database and sets default configs. */
|
|
55
|
+
async init() {
|
|
56
|
+
const defaultConf = this.getDefaultConfig();
|
|
57
|
+
const config = await this.getConfig();
|
|
58
|
+
await this.setConfig({
|
|
59
|
+
// use default config
|
|
60
|
+
...defaultConf,
|
|
61
|
+
// override with actual config values
|
|
62
|
+
...config ? config : {}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
// get a stored object
|
|
66
|
+
async get(key) {
|
|
67
|
+
if (typeof key !== "string" || key.length === 0) return;
|
|
68
|
+
const obj = await this.store.findOne({
|
|
69
|
+
type: "store",
|
|
70
|
+
plugin: this.name,
|
|
71
|
+
key
|
|
72
|
+
});
|
|
73
|
+
if (!obj) return null;
|
|
74
|
+
return obj.value;
|
|
75
|
+
}
|
|
76
|
+
// delete a stored object
|
|
77
|
+
async delete(key) {
|
|
78
|
+
if (typeof key !== "string" || key.length === 0) return;
|
|
79
|
+
await this.store.remove({ type: "store", plugin: this.name, key }, {});
|
|
80
|
+
}
|
|
81
|
+
// clear all stored values
|
|
82
|
+
async wipe() {
|
|
83
|
+
await this.store.remove(
|
|
84
|
+
{ type: "store", plugin: this.name },
|
|
85
|
+
{ multi: true }
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
// count number of objects in store
|
|
89
|
+
async count() {
|
|
90
|
+
return await this.store.count({ type: "store", plugin: this.name });
|
|
91
|
+
}
|
|
92
|
+
// get keys of all objects in store
|
|
93
|
+
async keys() {
|
|
94
|
+
const objects = await this.store.find({
|
|
95
|
+
type: "store",
|
|
96
|
+
plugin: this.name
|
|
97
|
+
});
|
|
98
|
+
return objects.map((o) => o.key);
|
|
99
|
+
}
|
|
100
|
+
// set a stored value
|
|
101
|
+
async set(key, value) {
|
|
102
|
+
if (typeof key !== "string" || key.length === 0) return;
|
|
103
|
+
await this.store.update(
|
|
104
|
+
{ type: "store", plugin: this.name, key },
|
|
105
|
+
{ $set: { value } },
|
|
106
|
+
{ upsert: true }
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
class PluginLoader {
|
|
111
|
+
constructor(workDir, omegga) {
|
|
112
|
+
this.path = path.join(workDir, softconfig.default.PLUGIN_PATH);
|
|
113
|
+
this.omegga = omegga;
|
|
114
|
+
this.store = Datastore.create({
|
|
115
|
+
filename: path.join(workDir, softconfig.default.DATA_PATH, softconfig.default.PLUGIN_STORE),
|
|
116
|
+
autoload: true
|
|
117
|
+
});
|
|
118
|
+
this.store.persistence.setAutocompactionInterval(1e3 * 60 * 5);
|
|
119
|
+
this.plugins = [];
|
|
120
|
+
logger.default.verbose("Loading plugin formats");
|
|
121
|
+
this.formats = [plugin_jsonrpc_stdio.default, plugin_node_safe.default, plugin_node_unsafe.default];
|
|
122
|
+
logger.default.verbose("Found plugin formats:", this.formats);
|
|
123
|
+
if (omegga) {
|
|
124
|
+
omegga.on("chatcmd:help", this.showHelp.bind(this));
|
|
125
|
+
omegga.on("cmd:plugins", this.showHelp.bind(this));
|
|
56
126
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
127
|
+
}
|
|
128
|
+
// determine if this command is a command on the plugin
|
|
129
|
+
isCommand(cmd) {
|
|
130
|
+
return cmd === "plugins" || this.plugins.some((p) => p.isCommand(cmd));
|
|
131
|
+
}
|
|
132
|
+
// unload and load all installed plugins
|
|
133
|
+
async reload() {
|
|
134
|
+
let ok = true;
|
|
135
|
+
logger.default.verbose("Reloading plugins");
|
|
136
|
+
for (const p of this.plugins) {
|
|
137
|
+
try {
|
|
138
|
+
if (p.isLoaded()) await p.unload();
|
|
139
|
+
if (!p.isLoaded()) {
|
|
140
|
+
if (p.isEnabled()) {
|
|
141
|
+
logger.default.verbose(
|
|
142
|
+
"Loading plugin",
|
|
143
|
+
p.constructor.getFormat(),
|
|
144
|
+
p.getName().underline
|
|
145
|
+
);
|
|
146
|
+
ok = await p.load() || ok;
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
logger.default.errorp(
|
|
150
|
+
"Did not successfully unload plugin",
|
|
151
|
+
p.getName().brightRed.underline
|
|
152
|
+
);
|
|
153
|
+
ok = false;
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
logger.default.errorp(
|
|
157
|
+
"Error loading plugin",
|
|
158
|
+
p.getName().brightRed.underline,
|
|
159
|
+
err
|
|
160
|
+
);
|
|
161
|
+
ok = false;
|
|
162
|
+
}
|
|
68
163
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
164
|
+
logger.default.verbose("Finished reloading plugins");
|
|
165
|
+
return ok;
|
|
166
|
+
}
|
|
167
|
+
// stop all plugins from running
|
|
168
|
+
async unload() {
|
|
169
|
+
logger.default.verbose("Unloading plugins");
|
|
170
|
+
let ok = true;
|
|
171
|
+
for (const p of this.plugins) {
|
|
172
|
+
try {
|
|
173
|
+
if (p.isLoaded()) {
|
|
174
|
+
if (!await p.unload()) {
|
|
175
|
+
logger.default.errorp(
|
|
176
|
+
"Could not unloading plugin",
|
|
177
|
+
p.getName().brightRed.underline
|
|
178
|
+
);
|
|
179
|
+
ok = false;
|
|
180
|
+
continue;
|
|
181
|
+
} else {
|
|
182
|
+
logger.default.verbose("Unloaded", p.getName().underline);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} catch (e) {
|
|
186
|
+
logger.default.errorp(
|
|
187
|
+
"Error unloading plugin",
|
|
188
|
+
p.getName().brightRed.underline
|
|
189
|
+
);
|
|
190
|
+
ok = false;
|
|
191
|
+
}
|
|
81
192
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
193
|
+
return ok;
|
|
194
|
+
}
|
|
195
|
+
/** Scans a plugin at the specified directory and create a Plugin object. */
|
|
196
|
+
async scanPlugin(dir) {
|
|
197
|
+
logger.default.verbose("Scanning plugin", dir.underline);
|
|
198
|
+
if (!fs.existsSync(dir)) {
|
|
199
|
+
logger.default.errorp("Plugin directory does not exist", dir.brightRed.underline);
|
|
200
|
+
return;
|
|
87
201
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
202
|
+
if (!fs.statSync(dir).isDirectory()) {
|
|
203
|
+
logger.default.errorp("Plugin must be a directory", dir.brightRed.underline);
|
|
204
|
+
return;
|
|
91
205
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
206
|
+
const PluginFormat = this.formats.find((f) => f.canLoad(dir));
|
|
207
|
+
if (!PluginFormat) {
|
|
208
|
+
logger.default.errorp("Missing plugin format for", dir);
|
|
209
|
+
return;
|
|
95
210
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
211
|
+
try {
|
|
212
|
+
const plugin = PluginFormat && new PluginFormat(dir, this.omegga);
|
|
213
|
+
if (!plugin.getDocumentation()) {
|
|
214
|
+
logger.default.errorp("Missing/invalid plugin documentation for", dir);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const storage = new PluginStorage(this.store, plugin);
|
|
218
|
+
await storage.init();
|
|
219
|
+
plugin.setStorage(storage);
|
|
220
|
+
return plugin;
|
|
221
|
+
} catch (e) {
|
|
222
|
+
logger.default.errorp(
|
|
223
|
+
"Error loading plugin",
|
|
224
|
+
dir.brightRed.underline,
|
|
225
|
+
PluginFormat,
|
|
226
|
+
e
|
|
227
|
+
);
|
|
103
228
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
await this.store.update({ type: 'store', plugin: this.name, key }, { $set: { value } }, { upsert: true });
|
|
229
|
+
}
|
|
230
|
+
static calculateLoadOrder(unsortedPlugins) {
|
|
231
|
+
if (!unsortedPlugins.length) {
|
|
232
|
+
return [];
|
|
109
233
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
234
|
+
const depGraph = unsortedPlugins.reduce((graph, plugin) => {
|
|
235
|
+
const name = plugin.getName();
|
|
236
|
+
const {
|
|
237
|
+
dependencies = {},
|
|
238
|
+
loadAfter = [],
|
|
239
|
+
loadBefore = []
|
|
240
|
+
} = plugin.pluginConfig ?? {};
|
|
241
|
+
graph[name] ??= {};
|
|
242
|
+
graph[name].plugin ??= plugin;
|
|
243
|
+
graph[name].behind ??= [];
|
|
244
|
+
graph[name].inDegree ??= 0;
|
|
245
|
+
for (const depName of [...loadAfter, ...Object.keys(dependencies)]) {
|
|
246
|
+
graph[name].behind.push(depName);
|
|
247
|
+
graph[depName] ??= {};
|
|
248
|
+
graph[depName].inDegree ??= 0;
|
|
249
|
+
graph[depName].inDegree++;
|
|
250
|
+
}
|
|
251
|
+
for (const depName of [...loadBefore]) {
|
|
252
|
+
graph[depName] ??= {};
|
|
253
|
+
graph[depName].behind ??= [];
|
|
254
|
+
graph[depName].behind.push(name);
|
|
255
|
+
graph[name].inDegree++;
|
|
256
|
+
}
|
|
257
|
+
return graph;
|
|
258
|
+
}, {});
|
|
259
|
+
let zeros = Object.entries(depGraph).reduce(
|
|
260
|
+
(arr, [name, { inDegree }]) => {
|
|
261
|
+
if (inDegree === 0) {
|
|
262
|
+
arr.push(name);
|
|
134
263
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
for (const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// load the plugin if it successfully unloaded
|
|
150
|
-
if (!p.isLoaded()) {
|
|
151
|
-
// only load it if it is enabled
|
|
152
|
-
if (p.isEnabled()) {
|
|
153
|
-
logger_1.default.verbose('Loading plugin', p.constructor.getFormat(), p.getName().underline);
|
|
154
|
-
ok = (await p.load()) || ok;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
logger_1.default.errorp('Did not successfully unload plugin', p.getName().brightRed.underline);
|
|
159
|
-
ok = false;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
catch (err) {
|
|
163
|
-
logger_1.default.errorp('Error loading plugin', p.getName().brightRed.underline, err);
|
|
164
|
-
ok = false;
|
|
165
|
-
}
|
|
264
|
+
return arr;
|
|
265
|
+
},
|
|
266
|
+
[]
|
|
267
|
+
);
|
|
268
|
+
const result = [];
|
|
269
|
+
while (zeros.length) {
|
|
270
|
+
result.unshift([...zeros]);
|
|
271
|
+
const nextZero = [];
|
|
272
|
+
for (const node of zeros) {
|
|
273
|
+
for (const neighbor of depGraph[node].behind) {
|
|
274
|
+
depGraph[neighbor].inDegree--;
|
|
275
|
+
if (depGraph[neighbor].inDegree === 0) {
|
|
276
|
+
nextZero.push(neighbor);
|
|
277
|
+
}
|
|
166
278
|
}
|
|
167
|
-
|
|
168
|
-
|
|
279
|
+
}
|
|
280
|
+
zeros = nextZero;
|
|
169
281
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
for (const p of this.plugins) {
|
|
176
|
-
try {
|
|
177
|
-
// unload the plugin if it's loaded
|
|
178
|
-
if (p.isLoaded()) {
|
|
179
|
-
if (!(await p.unload())) {
|
|
180
|
-
logger_1.default.errorp('Could not unloading plugin', p.getName().brightRed.underline);
|
|
181
|
-
ok = false;
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
logger_1.default.verbose('Unloaded', p.getName().underline);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
catch (e) {
|
|
190
|
-
logger_1.default.errorp('Error unloading plugin', p.getName().brightRed.underline);
|
|
191
|
-
ok = false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return ok;
|
|
282
|
+
if (Object.values(depGraph).some(({ inDegree }) => inDegree > 0)) {
|
|
283
|
+
logger.default.verbose(
|
|
284
|
+
"Cyclic or missing dependencies detected in plugins. Could not resolve load order."
|
|
285
|
+
);
|
|
286
|
+
return [];
|
|
195
287
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// create the plugin format
|
|
216
|
-
const plugin = PluginFormat && new PluginFormat(dir, this.omegga);
|
|
217
|
-
if (!plugin.getDocumentation()) {
|
|
218
|
-
logger_1.default.errorp('Missing/invalid plugin documentation for', dir);
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
// create its storage
|
|
222
|
-
const storage = new PluginStorage(this.store, plugin);
|
|
223
|
-
await storage.init();
|
|
224
|
-
// load the storage in
|
|
225
|
-
plugin.setStorage(storage);
|
|
226
|
-
// if there is a plugin format, create the plugin instance (but don't load yet)
|
|
227
|
-
return plugin;
|
|
228
|
-
}
|
|
229
|
-
catch (e) {
|
|
230
|
-
// if a plugin format fails to load, prevent omegga from dying
|
|
231
|
-
logger_1.default.errorp('Error loading plugin', dir.brightRed.underline, PluginFormat, e);
|
|
232
|
-
}
|
|
288
|
+
return result.map(
|
|
289
|
+
(interchangeablePlugins) => interchangeablePlugins.map((name) => depGraph[name].plugin).sort((a, b) => a.getName().localeCompare(b.getName()))
|
|
290
|
+
).flat().sort((a, b) => {
|
|
291
|
+
const A = a.pluginConfig?.loadPriority;
|
|
292
|
+
const B = b.pluginConfig?.loadPriority;
|
|
293
|
+
const aU = A == null;
|
|
294
|
+
const bU = B == null;
|
|
295
|
+
if (aU && bU) return 0;
|
|
296
|
+
if (aU) return B <= 0 ? 1 : -1;
|
|
297
|
+
if (bU) return A <= 0 ? -1 : 1;
|
|
298
|
+
return A - B;
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/** Scans plugin directory for plugins and builds their documentation. */
|
|
302
|
+
async scan() {
|
|
303
|
+
logger.default.verbose("Scanning plugin directory");
|
|
304
|
+
if (!fs.existsSync(this.path)) {
|
|
305
|
+
logger.default.verbose("Plugin directory is missing");
|
|
306
|
+
return false;
|
|
233
307
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
// plugin directory doesn't exist
|
|
238
|
-
if (!fs_1.default.existsSync(this.path)) {
|
|
239
|
-
logger_1.default.verbose('Plugin directory is missing');
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
// make sure there are no plugins running
|
|
243
|
-
if (this.plugins.some(p => p.isLoaded())) {
|
|
244
|
-
logger_1.default.errorp('Cannot re-scan plugins while a plugin is loaded');
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
// find all directories in the plugin path
|
|
248
|
-
this.plugins = (await Promise.all(fs_1.default
|
|
249
|
-
.readdirSync(this.path)
|
|
250
|
-
.map(dir => path_1.default.join(this.path, dir)) // convert from local paths
|
|
251
|
-
.map(async (dir) => this.scanPlugin(dir))))
|
|
252
|
-
// remove plugins without formats
|
|
253
|
-
.filter(p => p);
|
|
254
|
-
logger_1.default.verbose('Finished scanning plugin directory');
|
|
255
|
-
logger_1.default.verbose(`Found ${this.plugins.length} plugins`, this.plugins.map(p => p.getName()));
|
|
256
|
-
this.buildDocumentation();
|
|
257
|
-
return true;
|
|
308
|
+
if (this.plugins.some((p) => p.isLoaded())) {
|
|
309
|
+
logger.default.errorp("Cannot re-scan plugins while a plugin is loaded");
|
|
310
|
+
return false;
|
|
258
311
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
312
|
+
const unsortedPlugins = (await Promise.all(
|
|
313
|
+
fs.readdirSync(this.path).map((dir) => path.join(this.path, dir)).map(async (dir) => this.scanPlugin(dir))
|
|
314
|
+
)).filter((p) => p);
|
|
315
|
+
this.plugins = PluginLoader.calculateLoadOrder(unsortedPlugins);
|
|
316
|
+
logger.default.verbose("Finished scanning plugin directory");
|
|
317
|
+
logger.default.verbose(
|
|
318
|
+
`Found ${this.plugins.length} plugins.Loading in this order: `,
|
|
319
|
+
this.plugins.map((p) => p.getName())
|
|
320
|
+
);
|
|
321
|
+
this.buildDocumentation();
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
// show helptext
|
|
325
|
+
showHelp(player, ...args) {
|
|
326
|
+
const send = (msg) => this.omegga.whisper(player, msg);
|
|
327
|
+
const commands = this.commands ?? {};
|
|
328
|
+
const docs = this.documentation ?? {};
|
|
329
|
+
const splitHelper = (objs) => {
|
|
330
|
+
const lines = [];
|
|
331
|
+
while (objs.length > 0) {
|
|
332
|
+
const [item] = objs.splice(0, 1);
|
|
333
|
+
if (!lines.length || lines[lines.length - 1].length + item.length > 150)
|
|
334
|
+
lines.push(item);
|
|
335
|
+
else lines[lines.length - 1] += ", " + item;
|
|
336
|
+
}
|
|
337
|
+
return lines;
|
|
338
|
+
};
|
|
339
|
+
if (!args.length) {
|
|
340
|
+
send(
|
|
341
|
+
'"Use <code>/plugins plugin</>, <code>/plugins !command</>, <code>/plugins /command</> for more information"'
|
|
342
|
+
);
|
|
343
|
+
const plugins = Object.keys(docs).map(
|
|
344
|
+
(d) => `<color=\\"${docs[d]._plugin.isLoaded() ? "aaffaa" : "aaaaaa"}\\">${d}</>`
|
|
345
|
+
);
|
|
346
|
+
if (!plugins.length) {
|
|
347
|
+
send('"<b>No Installed Plugins</>"');
|
|
348
|
+
} else {
|
|
349
|
+
const lines = splitHelper(plugins);
|
|
350
|
+
send(`"<b>Installed Plugins</>: ${lines[0]}"`);
|
|
351
|
+
for (let i = 1; i < lines.length; i++) send(`"${lines[i]}"`);
|
|
352
|
+
}
|
|
353
|
+
} else if (args.length > 0) {
|
|
354
|
+
const target = args.join(" ").toLowerCase();
|
|
355
|
+
if (target in docs) {
|
|
356
|
+
const doc = docs[target];
|
|
357
|
+
const desc = doc.description || "no description";
|
|
358
|
+
const color = doc._plugin.isLoaded() ? "aaffaa" : "aaaaaa";
|
|
359
|
+
send(
|
|
360
|
+
`"<b>Plugin</> <code><color=\\"${color}\\">${doc.name}</></>: ${desc}"`
|
|
361
|
+
);
|
|
362
|
+
if (doc.author)
|
|
363
|
+
send(`"<b>Author</>: <color=\\"c4d7f5\\"><b>${doc.author}</></>"`);
|
|
364
|
+
if (doc.commands && doc.commands.length > 0) {
|
|
365
|
+
const lines = splitHelper(
|
|
366
|
+
doc.commands.map((c) => `<code>${c.name}</>`)
|
|
367
|
+
);
|
|
368
|
+
send(`"<b>Commands</>: ${lines[0]}"`);
|
|
369
|
+
for (let i = 1; i < lines.length; i++) send(`"${lines[i]}"`);
|
|
292
370
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const cmd = commands[target];
|
|
313
|
-
const desc = cmd.description || 'no description';
|
|
314
|
-
const example = cmd.example || 'no example';
|
|
315
|
-
const color = cmd._plugin.isLoaded() ? 'aaffaa' : 'aaaaaa';
|
|
316
|
-
send(`"<b>Command</> <code><color=\\"${color}\\">${cmd.name}</></>: ${desc}"`);
|
|
317
|
-
send(`"<b>Example</>: <code>${example}</>"`);
|
|
318
|
-
if (cmd.args && cmd.args.length > 0) {
|
|
319
|
-
send('"<b>Arguments</>:"');
|
|
320
|
-
for (const arg of cmd.args) {
|
|
321
|
-
const desc = arg.description || 'no description';
|
|
322
|
-
send(`"- <code>${arg.name}</>${arg.required ? ' (required)' : ''}: ${desc}"`);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
send('"<b>Arguments</>: None"');
|
|
327
|
-
}
|
|
328
|
-
// user takes the helptext literally
|
|
329
|
-
}
|
|
330
|
-
else if (args[0] === '!command' ||
|
|
331
|
-
args[0] === '/command' ||
|
|
332
|
-
args[0] === 'plugin') {
|
|
333
|
-
send('"Use <code>/plugins [name of plugin]</> or <code>/plugins [name of !command or /command]</> for more help for the respective plugin or command"');
|
|
334
|
-
// argument is not found
|
|
335
|
-
}
|
|
336
|
-
else {
|
|
337
|
-
send('"Could not find that command or plugin"');
|
|
338
|
-
}
|
|
339
|
-
// too many arguments
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
send('"Use <code>/plugins</> to list plugins and <code>/plugins plugin</> or <code>!help !command or /command</> for more information"');
|
|
371
|
+
} else if (target in commands) {
|
|
372
|
+
const cmd = commands[target];
|
|
373
|
+
const desc = cmd.description || "no description";
|
|
374
|
+
const example = cmd.example || "no example";
|
|
375
|
+
const color = cmd._plugin.isLoaded() ? "aaffaa" : "aaaaaa";
|
|
376
|
+
send(
|
|
377
|
+
`"<b>Command</> <code><color=\\"${color}\\">${cmd.name}</></>: ${desc}"`
|
|
378
|
+
);
|
|
379
|
+
send(`"<b>Example</>: <code>${example}</>"`);
|
|
380
|
+
if (cmd.args && cmd.args.length > 0) {
|
|
381
|
+
send('"<b>Arguments</>:"');
|
|
382
|
+
for (const arg of cmd.args) {
|
|
383
|
+
const desc2 = arg.description || "no description";
|
|
384
|
+
send(
|
|
385
|
+
`"- <code>${arg.name}</>${arg.required ? " (required)" : ""}: ${desc2}"`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
send('"<b>Arguments</>: None"');
|
|
343
390
|
}
|
|
391
|
+
} else if (args[0] === "!command" || args[0] === "/command" || args[0] === "plugin") {
|
|
392
|
+
send(
|
|
393
|
+
'"Use <code>/plugins [name of plugin]</> or <code>/plugins [name of !command or /command]</> for more help for the respective plugin or command"'
|
|
394
|
+
);
|
|
395
|
+
} else {
|
|
396
|
+
send('"Could not find that command or plugin"');
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
send(
|
|
400
|
+
'"Use <code>/plugins</> to list plugins and <code>/plugins plugin</> or <code>!help !command or /command</> for more information"'
|
|
401
|
+
);
|
|
344
402
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (doc.commands) {
|
|
362
|
-
for (const cmd of doc.commands) {
|
|
363
|
-
this.commands[cmd.name.toLowerCase()] = cmd;
|
|
364
|
-
cmd._plugin = plugin;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
403
|
+
}
|
|
404
|
+
// generate documentation from loaded plugins
|
|
405
|
+
buildDocumentation() {
|
|
406
|
+
this.documentation = {};
|
|
407
|
+
this.commands = {};
|
|
408
|
+
for (const plugin of this.plugins) {
|
|
409
|
+
const doc = JSON.parse(JSON.stringify(plugin.getDocumentation()));
|
|
410
|
+
if (!doc) continue;
|
|
411
|
+
const name = plugin.getName();
|
|
412
|
+
if (!name) continue;
|
|
413
|
+
this.documentation[name.toLowerCase()] = doc;
|
|
414
|
+
doc._plugin = plugin;
|
|
415
|
+
if (doc.commands) {
|
|
416
|
+
for (const cmd of doc.commands) {
|
|
417
|
+
this.commands[cmd.name.toLowerCase()] = cmd;
|
|
418
|
+
cmd._plugin = plugin;
|
|
367
419
|
}
|
|
420
|
+
}
|
|
368
421
|
}
|
|
422
|
+
}
|
|
369
423
|
}
|
|
370
424
|
exports.PluginLoader = PluginLoader;
|
|
371
|
-
|
|
425
|
+
exports.PluginStorage = PluginStorage;
|
|
426
|
+
//# sourceMappingURL=plugin.js.map
|