omegga 1.2.9 → 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 +1 -1
- 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
|
@@ -1,407 +1,379 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return ((fs_1.default.existsSync(path_1.default.join(pluginPath, MAIN_FILE)) ||
|
|
41
|
-
fs_1.default.existsSync(path_1.default.join(pluginPath, MAIN_FILE_TS))) &&
|
|
42
|
-
fs_1.default.existsSync(path_1.default.join(pluginPath, DOC_FILE)) &&
|
|
43
|
-
fs_1.default.existsSync(path_1.default.join(pluginPath, ACCESS_FILE)));
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const logger = require("../../logger.js");
|
|
4
|
+
const EventEmitter = require("node:events");
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
const node_worker_threads = require("node:worker_threads");
|
|
8
|
+
const readline = require("readline");
|
|
9
|
+
const _interface = require("./interface.js");
|
|
10
|
+
const proxyOmegga = require("./plugin_node_safe/proxyOmegga.js");
|
|
11
|
+
const MAIN_FILE = "omegga.plugin.js";
|
|
12
|
+
const MAIN_FILE_TS = "omegga.plugin.ts";
|
|
13
|
+
const DOC_FILE = "doc.json";
|
|
14
|
+
const ACCESS_FILE = "access.json";
|
|
15
|
+
const PLUGIN_FILE = "plugin.json";
|
|
16
|
+
class NodeVmPlugin extends _interface.Plugin {
|
|
17
|
+
#worker;
|
|
18
|
+
#outInterface;
|
|
19
|
+
#errInterface;
|
|
20
|
+
// every node vm plugin requires a main file, a doc file, and an access file
|
|
21
|
+
// may evolve this so it checks the contents of the doc file later
|
|
22
|
+
static canLoad(pluginPath) {
|
|
23
|
+
return (fs.existsSync(path.join(pluginPath, MAIN_FILE)) || fs.existsSync(path.join(pluginPath, MAIN_FILE_TS))) && fs.existsSync(path.join(pluginPath, DOC_FILE)) && fs.existsSync(path.join(pluginPath, ACCESS_FILE));
|
|
24
|
+
}
|
|
25
|
+
// safe node plugins are limited
|
|
26
|
+
static getFormat() {
|
|
27
|
+
return "node_safe";
|
|
28
|
+
}
|
|
29
|
+
constructor(pluginPath, omegga) {
|
|
30
|
+
super(pluginPath, omegga);
|
|
31
|
+
this.plugin = new EventEmitter();
|
|
32
|
+
this.messageCounter = 0;
|
|
33
|
+
this.documentation = _interface.Plugin.readJSON(path.join(pluginPath, DOC_FILE));
|
|
34
|
+
this.isTypeScript = fs.existsSync(path.join(pluginPath, MAIN_FILE_TS));
|
|
35
|
+
this.pluginConfig = _interface.Plugin.readJSON(path.join(pluginPath, PLUGIN_FILE));
|
|
36
|
+
this.access = _interface.Plugin.readJSON(path.join(pluginPath, ACCESS_FILE)) || [];
|
|
37
|
+
this.commands = [];
|
|
38
|
+
if (!(this.access instanceof Array) || !this.access.every((s) => typeof s === "string")) {
|
|
39
|
+
throw new Error("access list not a string array");
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
41
|
+
const name = this.getName();
|
|
42
|
+
this.plugin.on("error", (resp, ...args) => {
|
|
43
|
+
logger.default.error(name.brightRed.underline, "!>".red, ...args);
|
|
44
|
+
this.notify(resp);
|
|
45
|
+
});
|
|
46
|
+
this.plugin.on("log", (resp, ...args) => {
|
|
47
|
+
logger.default.log(name.underline, ">>".green, ...args);
|
|
48
|
+
this.notify(resp);
|
|
49
|
+
});
|
|
50
|
+
this.plugin.on("exec", (_, cmd) => omegga.writeln(cmd));
|
|
51
|
+
this.plugin.on("store.get", async (resp, key) => {
|
|
52
|
+
try {
|
|
53
|
+
this.notify(resp, await this.storage.get(key));
|
|
54
|
+
} catch (e) {
|
|
55
|
+
logger.default.error(
|
|
56
|
+
name.brightRed.underline,
|
|
57
|
+
"!>".red,
|
|
58
|
+
"error in store.get of",
|
|
59
|
+
key,
|
|
60
|
+
e
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
this.plugin.on("store.set", async (resp, key, value) => {
|
|
65
|
+
try {
|
|
66
|
+
await this.storage.set(key, JSON.parse(value));
|
|
67
|
+
} catch (e) {
|
|
68
|
+
logger.default.error(
|
|
69
|
+
name.brightRed.underline,
|
|
70
|
+
"!>".red,
|
|
71
|
+
"error in store.set of",
|
|
72
|
+
key,
|
|
73
|
+
value,
|
|
74
|
+
e
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
this.notify(resp);
|
|
78
|
+
});
|
|
79
|
+
this.plugin.on("store.delete", async (resp, key) => {
|
|
80
|
+
try {
|
|
81
|
+
await this.storage.delete(key);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
logger.default.error(
|
|
84
|
+
name.brightRed.underline,
|
|
85
|
+
"!>".red,
|
|
86
|
+
"error in store.delete of",
|
|
87
|
+
key,
|
|
88
|
+
e
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
this.notify(resp);
|
|
92
|
+
});
|
|
93
|
+
this.plugin.on("store.wipe", async (resp) => {
|
|
94
|
+
try {
|
|
95
|
+
await this.storage.wipe();
|
|
96
|
+
} catch (e) {
|
|
97
|
+
logger.default.error(
|
|
98
|
+
name.brightRed.underline,
|
|
99
|
+
"!>".red,
|
|
100
|
+
"error in store.wipe",
|
|
101
|
+
e
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
this.notify(resp);
|
|
105
|
+
});
|
|
106
|
+
this.plugin.on("store.count", async (resp) => {
|
|
107
|
+
try {
|
|
108
|
+
this.notify(resp, await this.storage.count());
|
|
109
|
+
} catch (e) {
|
|
110
|
+
logger.default.error(
|
|
111
|
+
name.brightRed.underline,
|
|
112
|
+
"!>".red,
|
|
113
|
+
"error in store.count",
|
|
114
|
+
e
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
this.plugin.on("store.keys", async (resp) => {
|
|
119
|
+
try {
|
|
120
|
+
this.notify(resp, await this.storage.keys());
|
|
121
|
+
} catch (e) {
|
|
122
|
+
logger.default.error(
|
|
123
|
+
name.brightRed.underline,
|
|
124
|
+
"!>".red,
|
|
125
|
+
"error in store.keys",
|
|
126
|
+
e
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
this.plugin.on("getPlugin", async (resp, name2) => {
|
|
131
|
+
const plugin = this.omegga.pluginLoader.plugins.find(
|
|
132
|
+
(p) => p.getName() === name2
|
|
133
|
+
);
|
|
134
|
+
if (plugin) {
|
|
135
|
+
this.notify(resp, {
|
|
136
|
+
name: name2,
|
|
137
|
+
documentation: plugin.getDocumentation(),
|
|
138
|
+
loaded: plugin.isLoaded()
|
|
119
139
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
// determing if a command is registered
|
|
189
|
-
isCommand(cmd) {
|
|
190
|
-
return this.commands.includes(cmd);
|
|
191
|
-
}
|
|
192
|
-
// require the plugin into the system, run the init func
|
|
193
|
-
async load() {
|
|
194
|
-
var _a;
|
|
195
|
-
// can't load the plugin if it's already loaded
|
|
196
|
-
if (typeof __classPrivateFieldGet(this, _NodeVmPlugin_worker, "f") !== 'undefined')
|
|
197
|
-
return false;
|
|
198
|
-
// vm restriction settings, default is access to everything
|
|
199
|
-
const vmOptions = {
|
|
200
|
-
builtin: this.access, // TODO: reference access file
|
|
201
|
-
external: true, // TODO: reference access file
|
|
202
|
-
isTypeScript: this.isTypeScript,
|
|
203
|
-
};
|
|
204
|
-
this.commands = [];
|
|
205
|
-
try {
|
|
206
|
-
const config = await this.storage.getConfig();
|
|
207
|
-
if ((_a = this.pluginConfig) === null || _a === void 0 ? void 0 : _a.emitConfig) {
|
|
208
|
-
await fs_1.default.promises.writeFile(path_1.default.join(this.path, this.pluginConfig.emitConfig), JSON.stringify(config));
|
|
209
|
-
}
|
|
210
|
-
this.createWorker();
|
|
211
|
-
// tell the worker its name :)
|
|
212
|
-
await this.emit('name', this.getName());
|
|
213
|
-
// create the vm, export the plugin's class
|
|
214
|
-
logger_1.default.verbose('Loading safe plugin');
|
|
215
|
-
if (!(await this.emit('load', this.path, vmOptions))[0])
|
|
216
|
-
throw '';
|
|
217
|
-
// get some initial information to create an omegga proxy
|
|
218
|
-
const initialData = (0, proxyOmegga_1.bootstrap)(this.omegga);
|
|
219
|
-
// send all of the mock events to the proxy omegga
|
|
220
|
-
logger_1.default.verbose('Sending initial data to safe plugin');
|
|
221
|
-
for (const ev in initialData) {
|
|
222
|
-
try {
|
|
223
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").postMessage({
|
|
224
|
-
action: 'brickadiaEvent',
|
|
225
|
-
args: [ev, ...initialData[ev]],
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
catch (e) {
|
|
229
|
-
/* just writing 'safe' code :) */
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
// pass events through
|
|
233
|
-
this.omegga.on('*', this.eventPassthrough);
|
|
234
|
-
logger_1.default.verbose('Starting safe plugin');
|
|
235
|
-
// actually start the plugin
|
|
236
|
-
if (!(await this.emit('start', config))[0])
|
|
237
|
-
throw 'plugin failed start';
|
|
238
|
-
this.emitStatus();
|
|
239
|
-
return true;
|
|
240
|
-
}
|
|
241
|
-
catch (e) {
|
|
242
|
-
// kill the worker
|
|
243
|
-
await this.emit('kill');
|
|
244
|
-
logger_1.default.error('!>'.red, 'error loading node vm plugin', this.getName().brightRed.underline, e);
|
|
245
|
-
this.emitStatus();
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
// disrequire the plugin into the system, run the stop func
|
|
250
|
-
unload() {
|
|
251
|
-
let frozen = true, timed = false;
|
|
252
|
-
return Promise.race([
|
|
253
|
-
(async () => {
|
|
254
|
-
// can't unload the plugin if it hasn't been loaded
|
|
255
|
-
if (typeof __classPrivateFieldGet(this, _NodeVmPlugin_worker, "f") === 'undefined')
|
|
256
|
-
return false;
|
|
257
|
-
try {
|
|
258
|
-
// stop the plugin (cleanly)
|
|
259
|
-
await this.emit('stop');
|
|
260
|
-
// remove listeners
|
|
261
|
-
this.omegga.off('*', this.eventPassthrough);
|
|
262
|
-
// let the unload function wait for the worker to properly cleanup
|
|
263
|
-
const promise = new Promise(res => {
|
|
264
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").once('exit', res);
|
|
265
|
-
});
|
|
266
|
-
// kill the worker
|
|
267
|
-
await this.emit('kill');
|
|
268
|
-
// wait for the worker to exit
|
|
269
|
-
await promise;
|
|
270
|
-
frozen = false;
|
|
271
|
-
if (timed)
|
|
272
|
-
return;
|
|
273
|
-
this.emitStatus();
|
|
274
|
-
this.commands = [];
|
|
275
|
-
return true;
|
|
276
|
-
}
|
|
277
|
-
catch (e) {
|
|
278
|
-
frozen = false;
|
|
279
|
-
if (timed)
|
|
280
|
-
return;
|
|
281
|
-
logger_1.default.error('!>'.red, 'error unloading node plugin', this.getName().brightRed.underline, e);
|
|
282
|
-
this.emitStatus();
|
|
283
|
-
return false;
|
|
284
|
-
}
|
|
285
|
-
})(),
|
|
286
|
-
new Promise(resolve => {
|
|
287
|
-
// check if the worker is frozen (while true)
|
|
288
|
-
setTimeout(() => {
|
|
289
|
-
if (!frozen)
|
|
290
|
-
return;
|
|
291
|
-
this.plugin.emit('error', 0, 'I appear to be in an unresponsive state - terminating worker');
|
|
292
|
-
// remove listeners
|
|
293
|
-
this.omegga.off('*', this.eventPassthrough);
|
|
294
|
-
// tell the worker to exit
|
|
295
|
-
if (__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f"))
|
|
296
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").emit('exit');
|
|
297
|
-
// terminate the worker if it still exists
|
|
298
|
-
try {
|
|
299
|
-
if (__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f"))
|
|
300
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").terminate();
|
|
301
|
-
}
|
|
302
|
-
catch (err) {
|
|
303
|
-
console.error('error terminating worker:', err);
|
|
304
|
-
}
|
|
305
|
-
timed = true;
|
|
306
|
-
resolve(true);
|
|
307
|
-
this.emitStatus();
|
|
308
|
-
}, 5000);
|
|
309
|
-
}),
|
|
310
|
-
]);
|
|
311
|
-
}
|
|
312
|
-
// emit an action to the worker and return a promise with its response
|
|
313
|
-
emit(action, ...args) {
|
|
314
|
-
if (!__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f"))
|
|
315
|
-
return;
|
|
316
|
-
const messageId = 'message:' + this.messageCounter++;
|
|
317
|
-
// promise waits for the message to resolve
|
|
318
|
-
const promise = new Promise(resolve => this.plugin.once(messageId, (_, ...x) => resolve(x)));
|
|
319
|
-
// post the message
|
|
140
|
+
} else {
|
|
141
|
+
this.notify(resp);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
this.plugin.on("emitPlugin", async (resp, target, ev, args) => {
|
|
145
|
+
const plugin = this.omegga.pluginLoader.plugins.find(
|
|
146
|
+
(p) => p.getName() === target
|
|
147
|
+
);
|
|
148
|
+
if (plugin) {
|
|
149
|
+
let r = await plugin.emitPlugin(ev, name, args);
|
|
150
|
+
this.notify(resp, r);
|
|
151
|
+
} else {
|
|
152
|
+
logger.default.error(name.brightRed.underline, "!>".red, "error in emitPlugin");
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
this.plugin.on("command.registers", async (_, blob) => {
|
|
156
|
+
if (typeof blob !== "string") return;
|
|
157
|
+
const registers = JSON.parse(blob);
|
|
158
|
+
if (!(registers instanceof Array) || registers.some((i) => typeof i !== "string"))
|
|
159
|
+
return;
|
|
160
|
+
this.commands = registers;
|
|
161
|
+
});
|
|
162
|
+
this.eventPassthrough = this.eventPassthrough.bind(this);
|
|
163
|
+
}
|
|
164
|
+
// emit a custom plugin event
|
|
165
|
+
async emitPlugin(ev, from, args) {
|
|
166
|
+
const [r] = await this.emit("emitPlugin", ev, from, args) ?? [];
|
|
167
|
+
return r;
|
|
168
|
+
}
|
|
169
|
+
// documentation is based on doc.json file
|
|
170
|
+
getDocumentation() {
|
|
171
|
+
return this.documentation;
|
|
172
|
+
}
|
|
173
|
+
// loaded state is based on if a worker exists
|
|
174
|
+
isLoaded() {
|
|
175
|
+
return !!this.#worker;
|
|
176
|
+
}
|
|
177
|
+
// determing if a command is registered
|
|
178
|
+
isCommand(cmd) {
|
|
179
|
+
return this.commands.includes(cmd);
|
|
180
|
+
}
|
|
181
|
+
// require the plugin into the system, run the init func
|
|
182
|
+
async load() {
|
|
183
|
+
if (typeof this.#worker !== "undefined") return false;
|
|
184
|
+
const vmOptions = {
|
|
185
|
+
builtin: this.access,
|
|
186
|
+
// TODO: reference access file
|
|
187
|
+
external: true,
|
|
188
|
+
// TODO: reference access file
|
|
189
|
+
isTypeScript: this.isTypeScript
|
|
190
|
+
};
|
|
191
|
+
this.commands = [];
|
|
192
|
+
try {
|
|
193
|
+
const config = await this.storage.getConfig();
|
|
194
|
+
if (this.pluginConfig?.emitConfig) {
|
|
195
|
+
await fs.promises.writeFile(
|
|
196
|
+
path.join(this.path, this.pluginConfig.emitConfig),
|
|
197
|
+
JSON.stringify(config)
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
this.createWorker();
|
|
201
|
+
await this.emit("name", this.getName());
|
|
202
|
+
logger.default.verbose("Loading safe plugin");
|
|
203
|
+
if (!(await this.emit("load", this.path, vmOptions))[0]) throw "";
|
|
204
|
+
const initialData = proxyOmegga.bootstrap(this.omegga);
|
|
205
|
+
logger.default.verbose("Sending initial data to safe plugin");
|
|
206
|
+
for (const ev in initialData) {
|
|
320
207
|
try {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
catch (e) {
|
|
327
|
-
return Promise.reject(e);
|
|
208
|
+
this.#worker.postMessage({
|
|
209
|
+
action: "brickadiaEvent",
|
|
210
|
+
args: [ev, ...initialData[ev]]
|
|
211
|
+
});
|
|
212
|
+
} catch (e) {
|
|
328
213
|
}
|
|
329
|
-
|
|
330
|
-
|
|
214
|
+
}
|
|
215
|
+
this.omegga.on("*", this.eventPassthrough);
|
|
216
|
+
logger.default.verbose("Starting safe plugin");
|
|
217
|
+
if (!(await this.emit("start", config))[0]) throw "plugin failed start";
|
|
218
|
+
this.emitStatus();
|
|
219
|
+
return true;
|
|
220
|
+
} catch (e) {
|
|
221
|
+
await this.emit("kill");
|
|
222
|
+
logger.default.error(
|
|
223
|
+
"!>".red,
|
|
224
|
+
"error loading node vm plugin",
|
|
225
|
+
this.getName().brightRed.underline,
|
|
226
|
+
e
|
|
227
|
+
);
|
|
228
|
+
this.emitStatus();
|
|
229
|
+
return false;
|
|
331
230
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
231
|
+
}
|
|
232
|
+
// disrequire the plugin into the system, run the stop func
|
|
233
|
+
unload() {
|
|
234
|
+
let frozen = true, timed = false;
|
|
235
|
+
return Promise.race([
|
|
236
|
+
(async () => {
|
|
237
|
+
if (typeof this.#worker === "undefined") return false;
|
|
337
238
|
try {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
239
|
+
await this.emit("stop");
|
|
240
|
+
this.omegga.off("*", this.eventPassthrough);
|
|
241
|
+
const promise = new Promise((res) => {
|
|
242
|
+
this.#worker.once("exit", res);
|
|
243
|
+
});
|
|
244
|
+
await this.emit("kill");
|
|
245
|
+
await promise;
|
|
246
|
+
frozen = false;
|
|
247
|
+
if (timed) return;
|
|
248
|
+
this.emitStatus();
|
|
249
|
+
this.commands = [];
|
|
250
|
+
return true;
|
|
251
|
+
} catch (e) {
|
|
252
|
+
frozen = false;
|
|
253
|
+
if (timed) return;
|
|
254
|
+
logger.default.error(
|
|
255
|
+
"!>".red,
|
|
256
|
+
"error unloading node plugin",
|
|
257
|
+
this.getName().brightRed.underline,
|
|
258
|
+
e
|
|
259
|
+
);
|
|
260
|
+
this.emitStatus();
|
|
261
|
+
return false;
|
|
345
262
|
}
|
|
263
|
+
})(),
|
|
264
|
+
new Promise((resolve) => {
|
|
265
|
+
setTimeout(() => {
|
|
266
|
+
if (!frozen) return;
|
|
267
|
+
this.plugin.emit(
|
|
268
|
+
"error",
|
|
269
|
+
0,
|
|
270
|
+
"I appear to be in an unresponsive state - terminating worker"
|
|
271
|
+
);
|
|
272
|
+
this.omegga.off("*", this.eventPassthrough);
|
|
273
|
+
if (this.#worker) this.#worker.emit("exit");
|
|
274
|
+
try {
|
|
275
|
+
if (this.#worker) this.#worker.terminate();
|
|
276
|
+
} catch (err) {
|
|
277
|
+
console.error("error terminating worker:", err);
|
|
278
|
+
}
|
|
279
|
+
timed = true;
|
|
280
|
+
resolve(true);
|
|
281
|
+
this.emitStatus();
|
|
282
|
+
}, 5e3);
|
|
283
|
+
})
|
|
284
|
+
]);
|
|
285
|
+
}
|
|
286
|
+
// emit an action to the worker and return a promise with its response
|
|
287
|
+
emit(action, ...args) {
|
|
288
|
+
if (!this.#worker) return;
|
|
289
|
+
const messageId = "message:" + this.messageCounter++;
|
|
290
|
+
const promise = new Promise(
|
|
291
|
+
(resolve) => this.plugin.once(messageId, (_, ...x) => resolve(x))
|
|
292
|
+
);
|
|
293
|
+
try {
|
|
294
|
+
this.#worker.postMessage({
|
|
295
|
+
action,
|
|
296
|
+
args: [messageId, ...args]
|
|
297
|
+
});
|
|
298
|
+
} catch (e) {
|
|
299
|
+
return Promise.reject(e);
|
|
346
300
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
terminal: false,
|
|
359
|
-
}), "f");
|
|
360
|
-
__classPrivateFieldSet(this, _NodeVmPlugin_errInterface, readline_1.default.createInterface({
|
|
361
|
-
input: __classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").stderr,
|
|
362
|
-
terminal: false,
|
|
363
|
-
}), "f");
|
|
364
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_outInterface, "f").on('line', logger_1.default.log);
|
|
365
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_errInterface, "f").on('line', logger_1.default.error);
|
|
366
|
-
// attach message emitter
|
|
367
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").on('message', ({ action, args }) => this.plugin.emit(action, ...args));
|
|
368
|
-
// broadcast an error if there is one
|
|
369
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").on('error', err => {
|
|
370
|
-
logger_1.default.error('!>'.red, 'error in plugin', this.getName().brightRed.underline, err);
|
|
371
|
-
});
|
|
372
|
-
// when the worker exits - set its variable to undefined this knows it's stopped
|
|
373
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").on('exit', () => {
|
|
374
|
-
this.omegga.off('*', this.eventPassthrough);
|
|
375
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_outInterface, "f").removeAllListeners('line');
|
|
376
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_errInterface, "f").removeAllListeners('line');
|
|
377
|
-
try {
|
|
378
|
-
if (__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f"))
|
|
379
|
-
__classPrivateFieldGet(this, _NodeVmPlugin_worker, "f").terminate();
|
|
380
|
-
}
|
|
381
|
-
catch (err) {
|
|
382
|
-
logger_1.default.error('!>'.red, 'Error terminating worker for', this.getName().brightRed.underline, err);
|
|
383
|
-
}
|
|
384
|
-
__classPrivateFieldSet(this, _NodeVmPlugin_worker, undefined, "f");
|
|
385
|
-
this.emitStatus();
|
|
386
|
-
});
|
|
301
|
+
return promise;
|
|
302
|
+
}
|
|
303
|
+
// notify a response to the worker
|
|
304
|
+
notify(action, ...args) {
|
|
305
|
+
if (!this.#worker) return;
|
|
306
|
+
try {
|
|
307
|
+
this.#worker.postMessage({
|
|
308
|
+
action,
|
|
309
|
+
args: [...args]
|
|
310
|
+
});
|
|
311
|
+
} catch (e) {
|
|
387
312
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
catch (e) {
|
|
400
|
-
// make sure post message doesn't crash the entire app
|
|
401
|
-
logger_1.default.error('!>'.red, 'error sending to plugin', ...args, e);
|
|
313
|
+
}
|
|
314
|
+
// create the worker for this plugin, attach emitter
|
|
315
|
+
createWorker() {
|
|
316
|
+
this.#worker = new node_worker_threads.Worker(
|
|
317
|
+
// vite transpiles worker.ts to dist/worker.js
|
|
318
|
+
path.join(__dirname, "../../worker.js"),
|
|
319
|
+
{
|
|
320
|
+
stdout: true,
|
|
321
|
+
env: {
|
|
322
|
+
VERBOSE: logger.default.VERBOSE + ""
|
|
402
323
|
}
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
this.#outInterface = readline.createInterface({
|
|
327
|
+
input: this.#worker.stdout,
|
|
328
|
+
terminal: false
|
|
329
|
+
});
|
|
330
|
+
this.#errInterface = readline.createInterface({
|
|
331
|
+
input: this.#worker.stderr,
|
|
332
|
+
terminal: false
|
|
333
|
+
});
|
|
334
|
+
this.#outInterface.on("line", logger.default.log);
|
|
335
|
+
this.#errInterface.on("line", logger.default.error);
|
|
336
|
+
this.#worker.on(
|
|
337
|
+
"message",
|
|
338
|
+
({ action, args }) => this.plugin.emit(action, ...args)
|
|
339
|
+
);
|
|
340
|
+
this.#worker.on("error", (err) => {
|
|
341
|
+
logger.default.error(
|
|
342
|
+
"!>".red,
|
|
343
|
+
"error in plugin",
|
|
344
|
+
this.getName().brightRed.underline,
|
|
345
|
+
err
|
|
346
|
+
);
|
|
347
|
+
});
|
|
348
|
+
this.#worker.on("exit", () => {
|
|
349
|
+
this.omegga.off("*", this.eventPassthrough);
|
|
350
|
+
this.#outInterface.removeAllListeners("line");
|
|
351
|
+
this.#errInterface.removeAllListeners("line");
|
|
352
|
+
try {
|
|
353
|
+
if (this.#worker) this.#worker.terminate();
|
|
354
|
+
} catch (err) {
|
|
355
|
+
logger.default.error(
|
|
356
|
+
"!>".red,
|
|
357
|
+
"Error terminating worker for",
|
|
358
|
+
this.getName().brightRed.underline,
|
|
359
|
+
err
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
this.#worker = void 0;
|
|
363
|
+
this.emitStatus();
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
eventPassthrough(...args) {
|
|
367
|
+
if (!this.#worker) return;
|
|
368
|
+
try {
|
|
369
|
+
this.#worker.postMessage({
|
|
370
|
+
action: "brickadiaEvent",
|
|
371
|
+
args
|
|
372
|
+
});
|
|
373
|
+
} catch (e) {
|
|
374
|
+
logger.default.error("!>".red, "error sending to plugin", ...args, e);
|
|
403
375
|
}
|
|
376
|
+
}
|
|
404
377
|
}
|
|
405
|
-
_NodeVmPlugin_worker = new WeakMap(), _NodeVmPlugin_outInterface = new WeakMap(), _NodeVmPlugin_errInterface = new WeakMap();
|
|
406
378
|
exports.default = NodeVmPlugin;
|
|
407
|
-
//# sourceMappingURL=plugin_node_safe.js.map
|
|
379
|
+
//# sourceMappingURL=plugin_node_safe.js.map
|