@elementspanel/epanel-plugin-config 0.0.0-stage → 1.0.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.
@@ -0,0 +1,2520 @@
1
+ /******/ (() => { // webpackBootstrap
2
+ /******/ "use strict";
3
+ /******/ var __webpack_modules__ = ({
4
+
5
+ /***/ "../common/src/array.ts"
6
+ (__unused_webpack_module, exports) {
7
+
8
+
9
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
10
+ exports.arrayUnique = arrayUnique;
11
+ function arrayUnique(arr, felidName) {
12
+ if (!felidName)
13
+ return Array.from(new Set(arr));
14
+ const map = new Map();
15
+ return arr.filter((v) => !map.has(v[felidName]) && map.set(v[felidName], v));
16
+ }
17
+
18
+
19
+ /***/ },
20
+
21
+ /***/ "../common/src/docker_utils.ts"
22
+ (__unused_webpack_module, exports) {
23
+
24
+
25
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
26
+ exports.normalizeDockerArchitecture = normalizeDockerArchitecture;
27
+ exports.normalizeDockerOS = normalizeDockerOS;
28
+ exports.normalizeDockerPlatform = normalizeDockerPlatform;
29
+ /**
30
+ * Normalizes Docker platform architecture names to standard format
31
+ * @param architecture The architecture string from Docker manifest
32
+ * @returns Normalized architecture string (amd64, arm64, arm, or original if not recognized)
33
+ */
34
+ function normalizeDockerArchitecture(architecture) {
35
+ if (!architecture) {
36
+ return "amd64"; // default fallback
37
+ }
38
+ // Return original if not one of the standard architectures
39
+ return architecture;
40
+ }
41
+ /**
42
+ * Normalizes Docker platform OS name
43
+ * @param os The OS string from Docker manifest
44
+ * @returns Normalized OS string (defaults to "linux" if not provided)
45
+ */
46
+ function normalizeDockerOS(os) {
47
+ return os || "linux";
48
+ }
49
+ /**
50
+ * Normalizes a Docker platform from manifest format to standard platform string
51
+ * @param platform Platform object from Docker manifest with os and architecture
52
+ * @returns Normalized platform string in format "os/arch" (e.g., "linux/amd64")
53
+ */
54
+ function normalizeDockerPlatform(platform) {
55
+ const os = normalizeDockerOS(platform.os);
56
+ const arch = normalizeDockerArchitecture(platform.architecture);
57
+ return `${os}/${arch}`;
58
+ }
59
+
60
+
61
+ /***/ },
62
+
63
+ /***/ "../common/src/global_variable.ts"
64
+ (__unused_webpack_module, exports) {
65
+
66
+
67
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
68
+ class GlobalVariable {
69
+ static set(k, v) {
70
+ GlobalVariable.map.set(k, v);
71
+ }
72
+ static get(k, def) {
73
+ if (GlobalVariable.map.has(k)) {
74
+ return GlobalVariable.map.get(k);
75
+ }
76
+ else {
77
+ return def;
78
+ }
79
+ }
80
+ static del(k) {
81
+ return GlobalVariable.map.delete(k);
82
+ }
83
+ }
84
+ GlobalVariable.map = new Map();
85
+ exports["default"] = GlobalVariable;
86
+
87
+
88
+ /***/ },
89
+
90
+ /***/ "../common/src/index.ts"
91
+ (__unused_webpack_module, exports, __webpack_require__) {
92
+
93
+
94
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
95
+ if (k2 === undefined) k2 = k;
96
+ var desc = Object.getOwnPropertyDescriptor(m, k);
97
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
98
+ desc = { enumerable: true, get: function() { return m[k]; } };
99
+ }
100
+ Object.defineProperty(o, k2, desc);
101
+ }) : (function(o, m, k, k2) {
102
+ if (k2 === undefined) k2 = k;
103
+ o[k2] = m[k];
104
+ }));
105
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
106
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
107
+ };
108
+ var __importDefault = (this && this.__importDefault) || function (mod) {
109
+ return (mod && mod.__esModule) ? mod : { "default": mod };
110
+ };
111
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
112
+ exports.StorageSubsystem = exports.MCServerStatus = exports.InstanceStreamListener = exports.GlobalVariable = exports.normalizeDockerPlatform = exports.normalizeDockerOS = exports.normalizeDockerArchitecture = exports.removeTrail = exports.uninstallNpmPlugin = exports.npmPluginRoots = exports.listNpmPlugins = exports.installNpmPlugin = exports.currentProjectRoot = exports.currentPackageRoot = exports.sortPlugins = exports.resolvePluginEntry = exports.readPluginManifest = exports.createFrontendPluginMetadata = exports.discoverPluginsFromRoots = exports.discoverPlugins = exports.arrayUnique = exports.toText = exports.toNumber = exports.toBoolean = exports.supposeValue = exports.isEmpty = exports.configureEntityParams = exports.systemInfo = exports.QueryWrapper = exports.QueryMapWrapper = exports.MySqlSource = exports.LocalFileSource = exports.killProcess = exports.ProcessWrapper = void 0;
113
+ const global_variable_1 = __importDefault(__webpack_require__("../common/src/global_variable.ts"));
114
+ exports.GlobalVariable = global_variable_1.default;
115
+ const instance_stream_1 = __importDefault(__webpack_require__("../common/src/instance_stream.ts"));
116
+ exports.InstanceStreamListener = instance_stream_1.default;
117
+ const system_storage_1 = __importDefault(__webpack_require__("../common/src/system_storage.ts"));
118
+ exports.StorageSubsystem = system_storage_1.default;
119
+ const mcping_1 = __importDefault(__webpack_require__("../common/src/mcping.ts"));
120
+ exports.MCServerStatus = mcping_1.default;
121
+ var process_tools_1 = __webpack_require__("../common/src/process_tools.ts");
122
+ Object.defineProperty(exports, "ProcessWrapper", ({ enumerable: true, get: function () { return process_tools_1.ProcessWrapper; } }));
123
+ Object.defineProperty(exports, "killProcess", ({ enumerable: true, get: function () { return process_tools_1.killProcess; } }));
124
+ var query_wrapper_1 = __webpack_require__("../common/src/query_wrapper.ts");
125
+ Object.defineProperty(exports, "LocalFileSource", ({ enumerable: true, get: function () { return query_wrapper_1.LocalFileSource; } }));
126
+ Object.defineProperty(exports, "MySqlSource", ({ enumerable: true, get: function () { return query_wrapper_1.MySqlSource; } }));
127
+ Object.defineProperty(exports, "QueryMapWrapper", ({ enumerable: true, get: function () { return query_wrapper_1.QueryMapWrapper; } }));
128
+ Object.defineProperty(exports, "QueryWrapper", ({ enumerable: true, get: function () { return query_wrapper_1.QueryWrapper; } }));
129
+ var system_info_1 = __webpack_require__("../common/src/system_info.ts");
130
+ Object.defineProperty(exports, "systemInfo", ({ enumerable: true, get: function () { return system_info_1.systemInfo; } }));
131
+ var typecheck_1 = __webpack_require__("../common/src/typecheck.ts");
132
+ Object.defineProperty(exports, "configureEntityParams", ({ enumerable: true, get: function () { return typecheck_1.configureEntityParams; } }));
133
+ Object.defineProperty(exports, "isEmpty", ({ enumerable: true, get: function () { return typecheck_1.isEmpty; } }));
134
+ Object.defineProperty(exports, "supposeValue", ({ enumerable: true, get: function () { return typecheck_1.supposeValue; } }));
135
+ Object.defineProperty(exports, "toBoolean", ({ enumerable: true, get: function () { return typecheck_1.toBoolean; } }));
136
+ Object.defineProperty(exports, "toNumber", ({ enumerable: true, get: function () { return typecheck_1.toNumber; } }));
137
+ Object.defineProperty(exports, "toText", ({ enumerable: true, get: function () { return typecheck_1.toText; } }));
138
+ var array_1 = __webpack_require__("../common/src/array.ts");
139
+ Object.defineProperty(exports, "arrayUnique", ({ enumerable: true, get: function () { return array_1.arrayUnique; } }));
140
+ __exportStar(__webpack_require__("../common/src/plugin_contract.ts"), exports);
141
+ __exportStar(__webpack_require__("../common/src/plugin_overrides.ts"), exports);
142
+ __exportStar(__webpack_require__("../common/src/plugin_lifecycle.ts"), exports);
143
+ __exportStar(__webpack_require__("../common/src/plugin_revision.ts"), exports);
144
+ __exportStar(__webpack_require__("../common/src/runtime_paths.ts"), exports);
145
+ var plugin_manifest_1 = __webpack_require__("../common/src/plugin_manifest.ts");
146
+ Object.defineProperty(exports, "discoverPlugins", ({ enumerable: true, get: function () { return plugin_manifest_1.discoverPlugins; } }));
147
+ Object.defineProperty(exports, "discoverPluginsFromRoots", ({ enumerable: true, get: function () { return plugin_manifest_1.discoverPluginsFromRoots; } }));
148
+ Object.defineProperty(exports, "createFrontendPluginMetadata", ({ enumerable: true, get: function () { return plugin_manifest_1.createFrontendPluginMetadata; } }));
149
+ Object.defineProperty(exports, "readPluginManifest", ({ enumerable: true, get: function () { return plugin_manifest_1.readPluginManifest; } }));
150
+ Object.defineProperty(exports, "resolvePluginEntry", ({ enumerable: true, get: function () { return plugin_manifest_1.resolvePluginEntry; } }));
151
+ Object.defineProperty(exports, "sortPlugins", ({ enumerable: true, get: function () { return plugin_manifest_1.sortPlugins; } }));
152
+ var plugin_npm_1 = __webpack_require__("../common/src/plugin_npm.ts");
153
+ Object.defineProperty(exports, "currentPackageRoot", ({ enumerable: true, get: function () { return plugin_npm_1.currentPackageRoot; } }));
154
+ Object.defineProperty(exports, "currentProjectRoot", ({ enumerable: true, get: function () { return plugin_npm_1.currentProjectRoot; } }));
155
+ Object.defineProperty(exports, "installNpmPlugin", ({ enumerable: true, get: function () { return plugin_npm_1.installNpmPlugin; } }));
156
+ Object.defineProperty(exports, "listNpmPlugins", ({ enumerable: true, get: function () { return plugin_npm_1.listNpmPlugins; } }));
157
+ Object.defineProperty(exports, "npmPluginRoots", ({ enumerable: true, get: function () { return plugin_npm_1.npmPluginRoots; } }));
158
+ Object.defineProperty(exports, "uninstallNpmPlugin", ({ enumerable: true, get: function () { return plugin_npm_1.uninstallNpmPlugin; } }));
159
+ var string_utils_1 = __webpack_require__("../common/src/string_utils.ts");
160
+ Object.defineProperty(exports, "removeTrail", ({ enumerable: true, get: function () { return string_utils_1.removeTrail; } }));
161
+ var docker_utils_1 = __webpack_require__("../common/src/docker_utils.ts");
162
+ Object.defineProperty(exports, "normalizeDockerArchitecture", ({ enumerable: true, get: function () { return docker_utils_1.normalizeDockerArchitecture; } }));
163
+ Object.defineProperty(exports, "normalizeDockerOS", ({ enumerable: true, get: function () { return docker_utils_1.normalizeDockerOS; } }));
164
+ Object.defineProperty(exports, "normalizeDockerPlatform", ({ enumerable: true, get: function () { return docker_utils_1.normalizeDockerPlatform; } }));
165
+
166
+
167
+ /***/ },
168
+
169
+ /***/ "../common/src/instance_stream.ts"
170
+ (__unused_webpack_module, exports) {
171
+
172
+
173
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
174
+ // Application instance data stream forwarding adapter
175
+ class InstanceStreamListener {
176
+ constructor() {
177
+ this.listenMap = new Map();
178
+ this.disconnectHandlers = new Map();
179
+ }
180
+ requestForward(socket, instanceUuid) {
181
+ var _a;
182
+ const sockets = (_a = this.listenMap.get(instanceUuid)) !== null && _a !== void 0 ? _a : [];
183
+ if (sockets.some((listener) => listener.id === socket.id))
184
+ return;
185
+ sockets.push(socket);
186
+ this.listenMap.set(instanceUuid, sockets);
187
+ if (!this.disconnectHandlers.has(socket)) {
188
+ const disconnect = () => {
189
+ for (const uuid of this.listenMap.keys())
190
+ this.cannelForward(socket, uuid);
191
+ };
192
+ this.disconnectHandlers.set(socket, disconnect);
193
+ socket.once("disconnect", disconnect);
194
+ }
195
+ }
196
+ cannelForward(socket, instanceUuid) {
197
+ var _a;
198
+ const remaining = (_a = this.listenMap
199
+ .get(instanceUuid)) === null || _a === void 0 ? void 0 : _a.filter((listener) => listener.id !== socket.id);
200
+ if (remaining === null || remaining === void 0 ? void 0 : remaining.length)
201
+ this.listenMap.set(instanceUuid, remaining);
202
+ else
203
+ this.listenMap.delete(instanceUuid);
204
+ if (![...this.listenMap.values()].some((sockets) => sockets.includes(socket))) {
205
+ const disconnect = this.disconnectHandlers.get(socket);
206
+ if (disconnect)
207
+ socket.off("disconnect", disconnect);
208
+ this.disconnectHandlers.delete(socket);
209
+ }
210
+ }
211
+ forward(instanceUuid, data) {
212
+ this.forwardViaCallback(instanceUuid, (socket) => socket.emit("instance/stdout", data));
213
+ }
214
+ forwardViaCallback(instanceUuid, callback) {
215
+ var _a;
216
+ for (const socket of (_a = this.listenMap.get(instanceUuid)) !== null && _a !== void 0 ? _a : []) {
217
+ if (socket.connected)
218
+ callback(socket);
219
+ else
220
+ this.cannelForward(socket, instanceUuid);
221
+ }
222
+ }
223
+ hasListenInstance(instanceUuid) {
224
+ var _a, _b;
225
+ return (_b = (_a = this.listenMap.get(instanceUuid)) === null || _a === void 0 ? void 0 : _a.some((socket) => socket.connected)) !== null && _b !== void 0 ? _b : false;
226
+ }
227
+ }
228
+ exports["default"] = InstanceStreamListener;
229
+
230
+
231
+ /***/ },
232
+
233
+ /***/ "../common/src/mcping.ts"
234
+ (__unused_webpack_module, exports, __webpack_require__) {
235
+
236
+
237
+ var __importDefault = (this && this.__importDefault) || function (mod) {
238
+ return (mod && mod.__esModule) ? mod : { "default": mod };
239
+ };
240
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
241
+ const net_1 = __importDefault(__webpack_require__("net"));
242
+ class PingMinecraftServer {
243
+ constructor(port, host) {
244
+ this.port = port;
245
+ this.host = host;
246
+ this.status = this.offlineStatus();
247
+ }
248
+ offlineStatus() {
249
+ return {
250
+ online: false,
251
+ host: this.host,
252
+ port: this.port,
253
+ version: "",
254
+ motd: "",
255
+ current_players: 0,
256
+ max_players: 0,
257
+ latency: 0
258
+ };
259
+ }
260
+ getStatus() {
261
+ if (this.pending)
262
+ return this.pending;
263
+ this.status = this.offlineStatus();
264
+ this.pending = new Promise((resolve, reject) => {
265
+ const startedAt = Date.now();
266
+ const client = net_1.default.connect({ host: this.host, port: this.port });
267
+ this.client = client;
268
+ let received = Buffer.alloc(0);
269
+ let settled = false;
270
+ const finish = (error) => {
271
+ if (settled)
272
+ return;
273
+ settled = true;
274
+ clearTimeout(timeout);
275
+ client.destroy();
276
+ this.client = undefined;
277
+ if (error)
278
+ reject(error);
279
+ else
280
+ resolve(this.status);
281
+ };
282
+ const timeout = setTimeout(() => finish(new Error("Minecraft status request timed out")), 15000);
283
+ client.once("connect", () => client.write(Buffer.from([0xfe, 0x01])));
284
+ client.on("data", (chunk) => {
285
+ if (settled)
286
+ return;
287
+ try {
288
+ received = Buffer.concat([received, chunk]);
289
+ // Legacy status packets contain an unsigned UTF-16 character count.
290
+ if (received.length > 3 + 0xffff * 2)
291
+ throw new Error("Minecraft status response is too large");
292
+ if (received.length < 3)
293
+ return;
294
+ if (received[0] !== 0xff)
295
+ throw new Error("Invalid Minecraft status packet");
296
+ const length = 3 + received.readUInt16BE(1) * 2;
297
+ if (received.length < length)
298
+ return;
299
+ const fields = Buffer.from(received.subarray(3, length))
300
+ .swap16()
301
+ .toString("utf16le")
302
+ .split("\0");
303
+ if (fields.length !== 6 ||
304
+ fields[0] !== "§1" ||
305
+ !/^\d+$/.test(fields[4]) ||
306
+ !/^\d+$/.test(fields[5])) {
307
+ throw new Error("Invalid Minecraft status response");
308
+ }
309
+ const currentPlayers = Number(fields[4]);
310
+ const maxPlayers = Number(fields[5]);
311
+ if (!Number.isSafeInteger(currentPlayers) || !Number.isSafeInteger(maxPlayers)) {
312
+ throw new Error("Invalid Minecraft player count");
313
+ }
314
+ this.status = {
315
+ host: this.host,
316
+ port: this.port,
317
+ online: true,
318
+ version: fields[2],
319
+ motd: fields[3],
320
+ current_players: currentPlayers,
321
+ max_players: maxPlayers,
322
+ latency: Date.now() - startedAt
323
+ };
324
+ finish();
325
+ }
326
+ catch (error) {
327
+ finish(error instanceof Error ? error : new Error(String(error)));
328
+ }
329
+ });
330
+ client.once("error", finish);
331
+ client.once("close", () => finish(received.length ? new Error("Incomplete Minecraft status response") : undefined));
332
+ }).finally(() => {
333
+ this.pending = undefined;
334
+ });
335
+ return this.pending;
336
+ }
337
+ asyncStatus() {
338
+ return this.getStatus();
339
+ }
340
+ }
341
+ exports["default"] = PingMinecraftServer;
342
+
343
+
344
+ /***/ },
345
+
346
+ /***/ "../common/src/plugin_contract.ts"
347
+ (__unused_webpack_module, exports) {
348
+
349
+
350
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
351
+ exports.PLUGIN_SDK_VERSION = exports.PLUGIN_API_VERSION = void 0;
352
+ exports.validatePluginCompatibility = validatePluginCompatibility;
353
+ exports.resolvePluginDependencyOrder = resolvePluginDependencyOrder;
354
+ exports.createPluginQueue = createPluginQueue;
355
+ exports.validatePluginSettings = validatePluginSettings;
356
+ /** Versioned contract shared by the host, plugin compiler and package registry. */
357
+ exports.PLUGIN_API_VERSION = 1;
358
+ exports.PLUGIN_SDK_VERSION = "1.0.0";
359
+ /** Omitted metadata denotes a legacy package. Unknown versions never execute. */
360
+ function validatePluginCompatibility(value) {
361
+ if (value === undefined)
362
+ return;
363
+ if (!value || typeof value !== "object" || Array.isArray(value))
364
+ throw new Error("Invalid ElementsPanel plugin compatibility metadata.");
365
+ const contract = value;
366
+ if (contract.api !== exports.PLUGIN_API_VERSION || (contract.sdk !== undefined && contract.sdk !== 1))
367
+ throw new Error(`Unsupported ElementsPanel plugin API/SDK: ${JSON.stringify(value)}`);
368
+ }
369
+ /**
370
+ * Stable topological ordering shared by plugin hosts.
371
+ *
372
+ * Invalid nodes are kept out of `ordered`: direct missing dependencies are
373
+ * reported first, then anything depending on an invalid node, and finally
374
+ * cycles (plus nodes blocked behind a cycle). Independent nodes retain the
375
+ * caller's priority/id comparator.
376
+ */
377
+ function resolvePluginDependencyOrder(items, options) {
378
+ const sorted = [...items].sort(options.compare);
379
+ const byId = new Map(sorted.map((item) => [options.id(item), item]));
380
+ const dependencies = new Map(sorted.map((item) => [
381
+ options.id(item),
382
+ [...new Set(options.dependencies(item) || [])].filter(Boolean)
383
+ ]));
384
+ const issues = new Map();
385
+ for (const item of sorted) {
386
+ const id = options.id(item);
387
+ const missing = dependencies.get(id).filter((dependency) => !byId.has(dependency));
388
+ if (!missing.length)
389
+ continue;
390
+ issues.set(id, {
391
+ type: "missing-dependency",
392
+ dependencies: missing,
393
+ message: `Missing frontend plugin dependencies: ${missing.join(", ")}`
394
+ });
395
+ }
396
+ const markUnavailable = () => {
397
+ let changed = false;
398
+ for (const item of sorted) {
399
+ const id = options.id(item);
400
+ if (issues.has(id))
401
+ continue;
402
+ const unavailable = dependencies.get(id).filter((dependency) => issues.has(dependency));
403
+ if (!unavailable.length)
404
+ continue;
405
+ issues.set(id, {
406
+ type: "dependency-unavailable",
407
+ dependencies: unavailable,
408
+ message: `Frontend plugin dependencies are unavailable: ${unavailable.join(", ")}`
409
+ });
410
+ changed = true;
411
+ }
412
+ return changed;
413
+ };
414
+ while (markUnavailable()) {
415
+ // Propagate direct graph failures before sorting the remaining nodes.
416
+ }
417
+ const candidates = sorted.filter((item) => !issues.has(options.id(item)));
418
+ const candidateIds = new Set(candidates.map(options.id));
419
+ const indegree = new Map(candidates.map((item) => [options.id(item), 0]));
420
+ const dependents = new Map();
421
+ for (const item of candidates) {
422
+ const id = options.id(item);
423
+ for (const dependency of dependencies.get(id)) {
424
+ if (!candidateIds.has(dependency))
425
+ continue;
426
+ indegree.set(id, indegree.get(id) + 1);
427
+ const bucket = dependents.get(dependency) || [];
428
+ bucket.push(item);
429
+ dependents.set(dependency, bucket);
430
+ }
431
+ }
432
+ const ready = candidates.filter((item) => indegree.get(options.id(item)) === 0);
433
+ ready.sort(options.compare);
434
+ const ordered = [];
435
+ while (ready.length) {
436
+ const item = ready.shift();
437
+ const id = options.id(item);
438
+ ordered.push(item);
439
+ for (const dependent of dependents.get(id) || []) {
440
+ const dependentId = options.id(dependent);
441
+ const next = indegree.get(dependentId) - 1;
442
+ indegree.set(dependentId, next);
443
+ if (next === 0) {
444
+ ready.push(dependent);
445
+ ready.sort(options.compare);
446
+ }
447
+ }
448
+ }
449
+ const unresolved = candidates.filter((item) => !ordered.includes(item));
450
+ if (unresolved.length) {
451
+ const unresolvedIds = new Set(unresolved.map(options.id));
452
+ for (const item of unresolved) {
453
+ const id = options.id(item);
454
+ const blockedBy = dependencies.get(id).filter((dependency) => unresolvedIds.has(dependency));
455
+ issues.set(id, {
456
+ type: "dependency-cycle",
457
+ dependencies: blockedBy,
458
+ message: `Frontend plugin dependency cycle: ${[id, ...blockedBy].join(" -> ")}`
459
+ });
460
+ }
461
+ }
462
+ return { ordered, issues };
463
+ }
464
+ /** A queue survives failures, so a failed change cannot block subsequent repairs. */
465
+ function createPluginQueue() {
466
+ let tail = Promise.resolve();
467
+ return (operation) => {
468
+ const next = tail.then(operation);
469
+ tail = next.catch(() => undefined);
470
+ return next;
471
+ };
472
+ }
473
+ /** Validate the form contract on the server before invoking plugin-owned validation. */
474
+ function validatePluginSettings(fields, values) {
475
+ var _a, _b;
476
+ if (!values || typeof values !== "object" || Array.isArray(values))
477
+ throw new Error("Invalid plugin settings.");
478
+ const input = values;
479
+ for (const field of fields) {
480
+ if (!field.key || field.type === "link")
481
+ continue;
482
+ const value = input[field.key];
483
+ if (value === undefined || value === null) {
484
+ if (field.required)
485
+ throw new Error(`${field.title || field.key}: required`);
486
+ continue;
487
+ }
488
+ if (field.type === "list") {
489
+ if (!Array.isArray(value) || value.length > ((_a = field.maxItems) !== null && _a !== void 0 ? _a : 100))
490
+ throw new Error(`${field.title || field.key}: invalid list`);
491
+ for (const item of value)
492
+ validatePluginSettings(field.fields || [], item);
493
+ continue;
494
+ }
495
+ const valid = field.type === "number"
496
+ ? typeof value === "number" &&
497
+ Number.isFinite(value) &&
498
+ (field.min === undefined || value >= field.min) &&
499
+ (field.max === undefined || value <= field.max)
500
+ : field.type === "boolean"
501
+ ? typeof value === "boolean"
502
+ : field.type === "select"
503
+ ? (_b = field.options) === null || _b === void 0 ? void 0 : _b.some((option) => option.value === value)
504
+ : typeof value === "string";
505
+ if (!valid)
506
+ throw new Error(`${field.title || field.key}: invalid value`);
507
+ }
508
+ }
509
+
510
+
511
+ /***/ },
512
+
513
+ /***/ "../common/src/plugin_lifecycle.ts"
514
+ (__unused_webpack_module, exports) {
515
+
516
+
517
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
518
+ exports.trackPluginDisposal = trackPluginDisposal;
519
+ /** Cordis 3 starts async disposers without awaiting them. Track them per host. */
520
+ function trackPluginDisposal(ctx) {
521
+ const pending = new Set();
522
+ const failures = [];
523
+ const tracked = new WeakSet();
524
+ const scopes = new WeakSet();
525
+ const observe = (scope) => {
526
+ if (scopes.has(scope))
527
+ return;
528
+ scopes.add(scope);
529
+ const reset = scope.reset;
530
+ scope.reset = function () {
531
+ this.disposables = this.disposables.map((dispose) => {
532
+ if (tracked.has(dispose))
533
+ return dispose;
534
+ const wrapper = (...args) => {
535
+ let result;
536
+ try {
537
+ result = dispose(...args);
538
+ }
539
+ catch (error) {
540
+ failures.push(error);
541
+ throw error;
542
+ }
543
+ if (result && typeof result.then === "function") {
544
+ const task = Promise.resolve(result)
545
+ .catch((error) => {
546
+ failures.push(error);
547
+ })
548
+ .finally(() => pending.delete(task));
549
+ pending.add(task);
550
+ }
551
+ return result;
552
+ };
553
+ // Cordis marks persistent disposers with a symbol; preserve its semantics.
554
+ for (const key of Object.getOwnPropertySymbols(dispose))
555
+ Object.defineProperty(wrapper, key, Object.getOwnPropertyDescriptor(dispose, key));
556
+ tracked.add(wrapper);
557
+ return wrapper;
558
+ });
559
+ return reset.call(this);
560
+ };
561
+ };
562
+ ctx.on("internal/runtime", observe);
563
+ ctx.on("internal/fork", observe);
564
+ return async () => {
565
+ do {
566
+ await ctx.events.flush();
567
+ await Promise.all([...pending]);
568
+ } while (pending.size);
569
+ if (failures.length) {
570
+ const errors = failures.splice(0);
571
+ throw new Error(`Plugin cleanup failed: ${errors.map(String).join("; ")}`);
572
+ }
573
+ };
574
+ }
575
+
576
+
577
+ /***/ },
578
+
579
+ /***/ "../common/src/plugin_manifest.ts"
580
+ (__unused_webpack_module, exports, __webpack_require__) {
581
+
582
+
583
+ var __importDefault = (this && this.__importDefault) || function (mod) {
584
+ return (mod && mod.__esModule) ? mod : { "default": mod };
585
+ };
586
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
587
+ exports.createFrontendPluginMetadata = createFrontendPluginMetadata;
588
+ exports.readPluginManifest = readPluginManifest;
589
+ exports.resolvePluginEntry = resolvePluginEntry;
590
+ exports.discoverPlugins = discoverPlugins;
591
+ exports.discoverPluginsFromRoots = discoverPluginsFromRoots;
592
+ exports.sortPlugins = sortPlugins;
593
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
594
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
595
+ function stringArray(value) {
596
+ if (!Array.isArray(value))
597
+ return undefined;
598
+ const result = value.filter((item) => typeof item === "string" && !!item.trim());
599
+ return result.length ? [...new Set(result.map((item) => item.trim()))] : undefined;
600
+ }
601
+ /**
602
+ * Redacts a full plugin manifest to the fields a browser is allowed to see.
603
+ * Backend `config` may contain credentials, so only `frontendConfig` crosses
604
+ * this boundary.
605
+ */
606
+ function createFrontendPluginMetadata(manifest, extras = {}) {
607
+ const frontendInject = stringArray(manifest.frontendInject);
608
+ return {
609
+ id: manifest.id,
610
+ ...(manifest.version === undefined ? {} : { version: manifest.version }),
611
+ ...(manifest.description === undefined ? {} : { description: manifest.description }),
612
+ ...(manifest.priority === undefined ? {} : { priority: manifest.priority }),
613
+ ...(manifest.elements === undefined ? {} : { elements: manifest.elements }),
614
+ ...(frontendInject === undefined ? {} : { frontendInject }),
615
+ ...(manifest.frontendImmediate === undefined
616
+ ? {}
617
+ : { frontendImmediate: Boolean(manifest.frontendImmediate) }),
618
+ ...(manifest.frontendRequired === undefined
619
+ ? {}
620
+ : { frontendRequired: Boolean(manifest.frontendRequired) }),
621
+ ...(manifest.frontendConfig === undefined ? {} : { config: manifest.frontendConfig }),
622
+ ...(extras.restartRequired === undefined ? {} : extras)
623
+ };
624
+ }
625
+ const MANIFEST_FILES = ["plugin.json", "manifest.json", "package.json"];
626
+ /** Reads the manifest of one plugin directory, or null if it has none. */
627
+ function readPluginManifest(directory, onWarning, fallbackId = node_path_1.default.basename(directory)) {
628
+ for (const file of MANIFEST_FILES) {
629
+ const filePath = node_path_1.default.join(directory, file);
630
+ if (!node_fs_1.default.existsSync(filePath))
631
+ continue;
632
+ try {
633
+ const value = JSON.parse(node_fs_1.default.readFileSync(filePath, "utf8"));
634
+ if (!value || typeof value !== "object" || Array.isArray(value))
635
+ return null;
636
+ const id = typeof value.id === "string" ? value.id : fallbackId;
637
+ if (!id.trim())
638
+ return null;
639
+ return { ...value, id: id.trim() };
640
+ }
641
+ catch (error) {
642
+ onWarning === null || onWarning === void 0 ? void 0 : onWarning(`Failed to read plugin manifest: ${filePath}`, error);
643
+ return null;
644
+ }
645
+ }
646
+ return null;
647
+ }
648
+ /**
649
+ * Resolves one plugin's entry module. Returns null when the manifest names an
650
+ * entry that does not exist, or when none of the fallback candidates is present.
651
+ * Paths that would escape the plugin directory are rejected.
652
+ */
653
+ function resolvePluginEntry(directory, manifest, options) {
654
+ var _a;
655
+ const configured = options.entryFields
656
+ .map((field) => manifest[field])
657
+ .find((entry) => typeof entry === "string" && entry.length > 0);
658
+ const candidates = configured ? [configured] : (_a = options.entryCandidates) !== null && _a !== void 0 ? _a : [];
659
+ const root = node_path_1.default.resolve(directory);
660
+ for (const candidate of candidates) {
661
+ const entry = node_path_1.default.resolve(directory, candidate);
662
+ if (entry.startsWith(`${root}${node_path_1.default.sep}`) && node_fs_1.default.existsSync(entry))
663
+ return entry;
664
+ }
665
+ return null;
666
+ }
667
+ function discoverPluginDirectory(directory, options, folder = node_path_1.default.basename(directory)) {
668
+ var _a;
669
+ // Npm packages expose a side directory; its name is not the public plugin id.
670
+ const manifest = readPluginManifest(directory, options.onWarning, folder);
671
+ if (!manifest)
672
+ return null;
673
+ if (manifest.enabled === false && !options.includeDisabled)
674
+ return null;
675
+ const entry = resolvePluginEntry(directory, manifest, options);
676
+ if (!entry && options.entryFields.some((field) => typeof manifest[field] === "string")) {
677
+ (_a = options.onWarning) === null || _a === void 0 ? void 0 : _a.call(options, `Plugin "${manifest.id}" has no valid entry module.`);
678
+ return null;
679
+ }
680
+ return { manifest, directory, folder, entry: entry !== null && entry !== void 0 ? entry : undefined };
681
+ }
682
+ /**
683
+ * Lists the usable plugins below `root`, in load order: ascending `priority`,
684
+ * then by id so the order is stable. Duplicate ids are dropped, and disabled
685
+ * ones too unless `includeDisabled` says otherwise. A plugin whose manifest names an entry that cannot be resolved is
686
+ * dropped too; one that names none keeps `entry` undefined, because a plugin may
687
+ * legitimately contribute to only one side of the panel.
688
+ */
689
+ function discoverPlugins(root, options) {
690
+ var _a;
691
+ if (!node_fs_1.default.existsSync(root))
692
+ return [];
693
+ const plugins = [];
694
+ const seenIds = new Set();
695
+ for (const item of node_fs_1.default.readdirSync(root, { withFileTypes: true })) {
696
+ if (!item.isDirectory())
697
+ continue;
698
+ const directory = node_path_1.default.join(root, item.name);
699
+ const plugin = discoverPluginDirectory(directory, options, item.name);
700
+ if (!plugin || seenIds.has(plugin.manifest.id)) {
701
+ if (plugin && seenIds.has(plugin.manifest.id)) {
702
+ (_a = options.onWarning) === null || _a === void 0 ? void 0 : _a.call(options, `Ignoring duplicate plugin id: ${plugin.manifest.id}`);
703
+ }
704
+ continue;
705
+ }
706
+ seenIds.add(plugin.manifest.id);
707
+ plugins.push(plugin);
708
+ }
709
+ return sortPlugins(plugins);
710
+ }
711
+ /**
712
+ * Discovers plugins from several roots while keeping the first root's plugin
713
+ * when ids collide. The built-in root is intentionally passed first by the
714
+ * panel and daemon loaders, so an installed market plugin cannot shadow a
715
+ * built-in npm dependency. A root can also force an installed project plugin
716
+ * into the disabled state; the user-owned override layer may enable it later.
717
+ */
718
+ function discoverPluginsFromRoots(roots, options) {
719
+ var _a;
720
+ const discovered = [];
721
+ const seenIds = new Set();
722
+ for (const root of roots) {
723
+ const isDirectPlugin = MANIFEST_FILES.some((file) => node_fs_1.default.existsSync(node_path_1.default.join(root.directory, file)));
724
+ const plugins = isDirectPlugin
725
+ ? [discoverPluginDirectory(root.directory, options, root.folder)]
726
+ : discoverPlugins(root.directory, options);
727
+ for (const plugin of plugins) {
728
+ if (!plugin)
729
+ continue;
730
+ const manifest = root.defaultEnabled === false ? { ...plugin.manifest, enabled: false } : plugin.manifest;
731
+ if (manifest.enabled === false && !options.includeDisabled)
732
+ continue;
733
+ if (seenIds.has(plugin.manifest.id)) {
734
+ (_a = options.onWarning) === null || _a === void 0 ? void 0 : _a.call(options, `Ignoring duplicate plugin id: ${plugin.manifest.id}`);
735
+ continue;
736
+ }
737
+ seenIds.add(plugin.manifest.id);
738
+ discovered.push({
739
+ ...plugin,
740
+ manifest,
741
+ ...(root.folder ? { folder: root.folder } : {})
742
+ });
743
+ }
744
+ }
745
+ return sortPlugins(discovered);
746
+ }
747
+ /** Load order: ascending `priority`, then by id so it never depends on the filesystem. */
748
+ function sortPlugins(plugins) {
749
+ return plugins.sort((a, b) => (Number(a.manifest.priority) || 0) - (Number(b.manifest.priority) || 0) ||
750
+ a.manifest.id.localeCompare(b.manifest.id));
751
+ }
752
+
753
+
754
+ /***/ },
755
+
756
+ /***/ "../common/src/plugin_npm.ts"
757
+ (__unused_webpack_module, exports, __webpack_require__) {
758
+
759
+
760
+ var __importDefault = (this && this.__importDefault) || function (mod) {
761
+ return (mod && mod.__esModule) ? mod : { "default": mod };
762
+ };
763
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
764
+ exports.currentPackageRoot = currentPackageRoot;
765
+ exports.currentProjectRoot = currentProjectRoot;
766
+ exports.npmPluginRoots = npmPluginRoots;
767
+ exports.listNpmPlugins = listNpmPlugins;
768
+ exports.installNpmPlugin = installNpmPlugin;
769
+ exports.uninstallNpmPlugin = uninstallNpmPlugin;
770
+ const child_process_1 = __webpack_require__("child_process");
771
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
772
+ const path_1 = __importDefault(__webpack_require__("path"));
773
+ const module_1 = __webpack_require__("module");
774
+ const PLUGIN_ID = /^[a-z][a-z0-9_-]{1,63}$/;
775
+ const PACKAGE_NAME = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
776
+ const VERSION = /^[0-9][^\s/]{0,63}$/;
777
+ function readJson(filename) {
778
+ try {
779
+ const parsed = JSON.parse(fs_extra_1.default.readFileSync(filename, "utf8"));
780
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
781
+ ? parsed
782
+ : null;
783
+ }
784
+ catch (error) {
785
+ if ((error === null || error === void 0 ? void 0 : error.code) === "ENOENT")
786
+ return null;
787
+ throw error;
788
+ }
789
+ }
790
+ function objectValue(value) {
791
+ return value && typeof value === "object" && !Array.isArray(value)
792
+ ? value
793
+ : undefined;
794
+ }
795
+ function stringValue(value) {
796
+ return typeof value === "string" ? value : "";
797
+ }
798
+ function currentPackageRoot() {
799
+ return path_1.default.resolve(process.env.EPANEL_PACKAGE_ROOT || process.cwd());
800
+ }
801
+ function currentProjectRoot(packageRoot = currentPackageRoot()) {
802
+ // The npm worker sets EPANEL_PROJECT_ROOT to the installation directory. In a
803
+ // development checkout the runtime package sits directly under the project.
804
+ if (process.env.EPANEL_PROJECT_ROOT)
805
+ return path_1.default.resolve(process.env.EPANEL_PROJECT_ROOT);
806
+ const scope = path_1.default.resolve(packageRoot, "..");
807
+ const nodeModules = path_1.default.dirname(scope);
808
+ if (path_1.default.basename(nodeModules) === "node_modules" && path_1.default.basename(scope).startsWith("@"))
809
+ return path_1.default.dirname(nodeModules);
810
+ return scope;
811
+ }
812
+ function npmPluginRoots(options = {}) {
813
+ var _a, _b;
814
+ const packageRoot = path_1.default.resolve((_a = options.packageRoot) !== null && _a !== void 0 ? _a : currentPackageRoot());
815
+ return {
816
+ packageRoot,
817
+ projectRoot: path_1.default.resolve((_b = options.projectRoot) !== null && _b !== void 0 ? _b : currentProjectRoot(packageRoot))
818
+ };
819
+ }
820
+ function projectManifestFile(projectRoot) {
821
+ return path_1.default.join(projectRoot, "package.json");
822
+ }
823
+ function readProjectManifest(projectRoot) {
824
+ var _a;
825
+ return ((_a = readJson(projectManifestFile(projectRoot))) !== null && _a !== void 0 ? _a : {
826
+ private: true,
827
+ dependencies: {},
828
+ elementspanel: { plugins: {} }
829
+ });
830
+ }
831
+ function writeProjectManifest(projectRoot, manifest) {
832
+ fs_extra_1.default.writeFileSync(projectManifestFile(projectRoot), `${JSON.stringify(manifest, null, 2)}\n`);
833
+ }
834
+ function dependenciesOf(manifest) {
835
+ var _a;
836
+ return (_a = objectValue(manifest === null || manifest === void 0 ? void 0 : manifest.dependencies)) !== null && _a !== void 0 ? _a : {};
837
+ }
838
+ function mappingsOf(manifest) {
839
+ var _a, _b;
840
+ return (_b = objectValue((_a = objectValue(manifest === null || manifest === void 0 ? void 0 : manifest.elementspanel)) === null || _a === void 0 ? void 0 : _a.plugins)) !== null && _b !== void 0 ? _b : {};
841
+ }
842
+ function pluginRecord(pluginId, name, source, packageRoot, directory, folder, version) {
843
+ return { pluginId, name, version, sides: [], directory, folder, packageRoot, source };
844
+ }
845
+ function readPackageEntry(packageRoot, name) {
846
+ const hostRequire = (0, module_1.createRequire)(path_1.default.join(packageRoot, "package.json"));
847
+ const manifestPath = hostRequire.resolve(`${name}/package.json`);
848
+ const metadata = readJson(manifestPath);
849
+ if (!metadata)
850
+ throw new Error(`Missing package metadata for ${name}.`);
851
+ return { root: path_1.default.dirname(manifestPath), metadata };
852
+ }
853
+ function sideDirectory(packageRoot, metadata, side) {
854
+ const elements = objectValue(metadata.elementspanel);
855
+ const definition = objectValue(elements === null || elements === void 0 ? void 0 : elements[side]);
856
+ const directory = stringValue(definition === null || definition === void 0 ? void 0 : definition.directory);
857
+ if (!definition || !directory)
858
+ return undefined;
859
+ const target = path_1.default.resolve(packageRoot, directory);
860
+ const relative = path_1.default.relative(packageRoot, target);
861
+ if (relative === "" || relative.startsWith(`..${path_1.default.sep}`) || path_1.default.isAbsolute(relative))
862
+ return undefined;
863
+ return target;
864
+ }
865
+ function recordFromPackage(pluginId, name, source, packageRoot, metadata, side) {
866
+ var _a;
867
+ const elements = objectValue(metadata.elementspanel);
868
+ if (!elements || elements.id !== pluginId)
869
+ return undefined;
870
+ const version = stringValue(metadata.version);
871
+ const sides = ["panel", "daemon"].filter((item) => Boolean(sideDirectory(packageRoot, metadata, item)));
872
+ if (!sides.length)
873
+ return undefined;
874
+ const target = side !== null && side !== void 0 ? side : sides[0];
875
+ if (!sides.includes(target))
876
+ return undefined;
877
+ const directory = sideDirectory(packageRoot, metadata, target);
878
+ const folder = stringValue((_a = objectValue(elements[target])) === null || _a === void 0 ? void 0 : _a.folder);
879
+ if (!directory || !folder)
880
+ return undefined;
881
+ return {
882
+ ...pluginRecord(pluginId, name, source, packageRoot, directory, folder, version),
883
+ sides
884
+ };
885
+ }
886
+ /**
887
+ * Every npm plugin the runtime can load for a side, built-in and project-installed.
888
+ *
889
+ * Built-in mappings win over a project mapping for the same id: a third-party
890
+ * package must not shadow a plugin that ships with the runtime. A project package
891
+ * that does not describe the requested side is skipped instead of failing, which
892
+ * is what lets a two-sided project share one dependency list between sides.
893
+ */
894
+ function listNpmPlugins(side, options = {}) {
895
+ var _a;
896
+ const { packageRoot, projectRoot } = npmPluginRoots(options);
897
+ const host = readJson(path_1.default.join(packageRoot, "package.json"));
898
+ if (!host)
899
+ throw new Error(`Missing runtime package metadata: ${packageRoot}`);
900
+ const project = path_1.default.resolve(projectRoot) === path_1.default.resolve(packageRoot) ? null : readProjectManifest(projectRoot);
901
+ const hostMappings = mappingsOf(host);
902
+ const projectMappings = mappingsOf(project);
903
+ const mappings = new Map();
904
+ for (const [pluginId, name] of Object.entries(projectMappings)) {
905
+ if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
906
+ continue;
907
+ mappings.set(pluginId, { name, source: "project" });
908
+ }
909
+ for (const [pluginId, name] of Object.entries(hostMappings)) {
910
+ if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
911
+ continue;
912
+ mappings.set(pluginId, { name, source: "bundled" });
913
+ }
914
+ const hostDependencies = dependenciesOf(host);
915
+ const projectDependencies = dependenciesOf(project);
916
+ const folders = new Set();
917
+ const records = [];
918
+ for (const [pluginId, mapping] of mappings) {
919
+ const declared = (_a = hostDependencies[mapping.name]) !== null && _a !== void 0 ? _a : projectDependencies[mapping.name];
920
+ if (declared === undefined) {
921
+ if (options.skipInvalid)
922
+ continue;
923
+ throw new Error(`Missing npm plugin dependency: ${mapping.name}. Run npm install in the project directory.`);
924
+ }
925
+ let entry;
926
+ try {
927
+ entry = readPackageEntry(packageRoot, mapping.name);
928
+ }
929
+ catch (error) {
930
+ if (options.skipInvalid)
931
+ continue;
932
+ throw error;
933
+ }
934
+ const record = recordFromPackage(pluginId, mapping.name, mapping.source, entry.root, entry.metadata, side);
935
+ if (!record) {
936
+ if (options.skipInvalid || mapping.source === "project")
937
+ continue;
938
+ throw new Error(`Invalid ${side !== null && side !== void 0 ? side : "plugin"} entry in npm plugin ${mapping.name}.`);
939
+ }
940
+ const folder = record.folder;
941
+ if (folders.has(folder)) {
942
+ if (options.skipInvalid)
943
+ continue;
944
+ throw new Error(`Duplicate npm plugin asset directory: ${folder}.`);
945
+ }
946
+ folders.add(folder);
947
+ records.push(record);
948
+ }
949
+ return records;
950
+ }
951
+ function runNpm(args, cwd) {
952
+ return new Promise((resolve, reject) => {
953
+ var _a, _b, _c;
954
+ const npmCLI = process.env.npm_execpath;
955
+ const invocation = npmCLI && /npm(?:-cli)?\.(?:c?js|mjs)$/.test(npmCLI)
956
+ ? { command: process.execPath, args: [npmCLI, ...args], shell: false }
957
+ : process.platform === "win32"
958
+ ? {
959
+ command: process.env.ComSpec || "cmd.exe",
960
+ args: ["/d", "/s", "/c", `npm ${args.map((item) => `"${item.replace(/"/g, '""')}"`).join(" ")}`],
961
+ shell: false
962
+ }
963
+ : { command: "npm", args, shell: false };
964
+ const child = (0, child_process_1.spawn)(invocation.command, invocation.args, {
965
+ cwd,
966
+ shell: invocation.shell,
967
+ windowsHide: true,
968
+ stdio: ["ignore", "pipe", "pipe"],
969
+ env: { ...process.env, npm_config_update_notifier: "false" }
970
+ });
971
+ let output = "";
972
+ const append = (data) => {
973
+ output += data.toString();
974
+ if (output.length > 16000)
975
+ output = output.slice(-16000);
976
+ };
977
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", append);
978
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", append);
979
+ const timer = setTimeout(() => {
980
+ var _a;
981
+ child.kill("SIGKILL");
982
+ reject(new Error(`npm ${(_a = args[0]) !== null && _a !== void 0 ? _a : ""} timed out.`));
983
+ }, 10 * 60 * 1000);
984
+ (_c = timer.unref) === null || _c === void 0 ? void 0 : _c.call(timer);
985
+ child.once("error", (error) => {
986
+ clearTimeout(timer);
987
+ reject(error);
988
+ });
989
+ child.once("close", (code) => {
990
+ var _a;
991
+ clearTimeout(timer);
992
+ if (code === 0)
993
+ return resolve(output);
994
+ reject(new Error(`npm ${(_a = args[0]) !== null && _a !== void 0 ? _a : ""} failed (${code}): ${output.trim()}`));
995
+ });
996
+ });
997
+ }
998
+ const operations = new Map();
999
+ function withProjectLock(projectRoot, operation) {
1000
+ var _a;
1001
+ const key = process.platform === "win32" ? projectRoot.toLowerCase() : projectRoot;
1002
+ const previous = (_a = operations.get(key)) !== null && _a !== void 0 ? _a : Promise.resolve();
1003
+ const result = previous.then(operation);
1004
+ const settled = result.then(() => { }, () => { });
1005
+ operations.set(key, settled);
1006
+ return result.finally(() => {
1007
+ if (operations.get(key) === settled)
1008
+ operations.delete(key);
1009
+ });
1010
+ }
1011
+ /**
1012
+ * Installs (or updates) one npm plugin as a project dependency.
1013
+ *
1014
+ * The version is pinned with `--save-exact`: the panel performs updates, so a
1015
+ * later bare `npm install` must not silently move the plugin to another release.
1016
+ */
1017
+ async function installNpmPlugin(options) {
1018
+ const { name, pluginId, version, side } = options;
1019
+ if (!PLUGIN_ID.test(pluginId))
1020
+ throw new Error(`Invalid plugin id: ${pluginId}`);
1021
+ if (!PACKAGE_NAME.test(name))
1022
+ throw new Error(`Invalid npm plugin package: ${name}`);
1023
+ if (!VERSION.test(version))
1024
+ throw new Error(`Invalid plugin version: ${version}`);
1025
+ const { packageRoot, projectRoot } = npmPluginRoots(options);
1026
+ return withProjectLock(projectRoot, async () => {
1027
+ var _a;
1028
+ const host = readJson(path_1.default.join(packageRoot, "package.json"));
1029
+ if (!host)
1030
+ throw new Error(`Missing runtime package metadata: ${packageRoot}`);
1031
+ if (mappingsOf(host)[pluginId] !== undefined)
1032
+ throw new Error(`BUNDLED:${pluginId}`);
1033
+ const existing = mappingsOf(readProjectManifest(projectRoot))[pluginId];
1034
+ if (existing !== undefined && existing !== name)
1035
+ throw new Error(`Plugin id ${pluginId} is already installed as ${String(existing)}.`);
1036
+ await fs_extra_1.default.ensureDir(projectRoot);
1037
+ await runNpm(["install", `${name}@${version}`, "--save", "--save-exact", "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot);
1038
+ let entry;
1039
+ try {
1040
+ entry = readPackageEntry(packageRoot, name);
1041
+ }
1042
+ catch (error) {
1043
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
1044
+ throw error;
1045
+ }
1046
+ const record = recordFromPackage(pluginId, name, "project", entry.root, entry.metadata, side);
1047
+ if (!record) {
1048
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
1049
+ throw new Error(`The package ${name} does not provide a ${side} plugin named ${pluginId}.`);
1050
+ }
1051
+ if (record.version !== version) {
1052
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
1053
+ throw new Error(`The installed package ${name} is ${record.version}, expected ${version}.`);
1054
+ }
1055
+ const manifest = readProjectManifest(projectRoot);
1056
+ const dependencies = { ...dependenciesOf(manifest), [name]: version };
1057
+ const elementspanel = { ...((_a = objectValue(manifest.elementspanel)) !== null && _a !== void 0 ? _a : {}) };
1058
+ const plugins = { ...mappingsOf(manifest), [pluginId]: name };
1059
+ manifest.dependencies = dependencies;
1060
+ manifest.elementspanel = { ...elementspanel, plugins };
1061
+ writeProjectManifest(projectRoot, manifest);
1062
+ return record;
1063
+ });
1064
+ }
1065
+ /** Removes one project-installed npm plugin. Built-in packages are left alone. */
1066
+ async function uninstallNpmPlugin(pluginId, options = {}) {
1067
+ if (!PLUGIN_ID.test(pluginId))
1068
+ throw new Error(`Invalid plugin id: ${pluginId}`);
1069
+ const { packageRoot, projectRoot } = npmPluginRoots(options);
1070
+ return withProjectLock(projectRoot, async () => {
1071
+ var _a;
1072
+ const host = readJson(path_1.default.join(packageRoot, "package.json"));
1073
+ if (host && mappingsOf(host)[pluginId] !== undefined)
1074
+ throw new Error(`BUNDLED:${pluginId}`);
1075
+ const manifest = readProjectManifest(projectRoot);
1076
+ const name = mappingsOf(manifest)[pluginId];
1077
+ if (typeof name !== "string" || !PACKAGE_NAME.test(name))
1078
+ return null;
1079
+ const record = listNpmPlugins(undefined, { packageRoot, projectRoot, skipInvalid: true }).find((item) => item.pluginId === pluginId);
1080
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot);
1081
+ const plugins = { ...mappingsOf(manifest) };
1082
+ delete plugins[pluginId];
1083
+ const elementspanel = { ...((_a = objectValue(manifest.elementspanel)) !== null && _a !== void 0 ? _a : {}) };
1084
+ if (Object.keys(plugins).length)
1085
+ elementspanel.plugins = plugins;
1086
+ else
1087
+ delete elementspanel.plugins;
1088
+ manifest.elementspanel = elementspanel;
1089
+ writeProjectManifest(projectRoot, manifest);
1090
+ return record !== null && record !== void 0 ? record : null;
1091
+ });
1092
+ }
1093
+
1094
+
1095
+ /***/ },
1096
+
1097
+ /***/ "../common/src/plugin_overrides.ts"
1098
+ (__unused_webpack_module, exports, __webpack_require__) {
1099
+
1100
+
1101
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1102
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1103
+ };
1104
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1105
+ exports.pluginOverridesPath = pluginOverridesPath;
1106
+ exports.readPluginOverrides = readPluginOverrides;
1107
+ exports.validatePluginOverride = validatePluginOverride;
1108
+ exports.applyPluginOverrides = applyPluginOverrides;
1109
+ exports.writePluginOverride = writePluginOverride;
1110
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
1111
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
1112
+ const node_crypto_1 = __webpack_require__("node:crypto");
1113
+ function pluginOverridesPath() {
1114
+ return node_path_1.default.resolve(process.cwd(), "data", "plugin-overrides.json");
1115
+ }
1116
+ /** Package defaults stay immutable; only the user's last layer lives in data. */
1117
+ function readPluginOverrides(filename = pluginOverridesPath()) {
1118
+ let raw;
1119
+ try {
1120
+ raw = node_fs_1.default.readFileSync(filename, "utf8");
1121
+ }
1122
+ catch (error) {
1123
+ if (error.code === "ENOENT")
1124
+ return { version: 1, plugins: {} };
1125
+ throw error;
1126
+ }
1127
+ const data = JSON.parse(raw);
1128
+ if ((data === null || data === void 0 ? void 0 : data.version) !== 1 ||
1129
+ !data.plugins ||
1130
+ typeof data.plugins !== "object" ||
1131
+ Array.isArray(data.plugins))
1132
+ throw new Error("Invalid plugin-overrides.json");
1133
+ for (const entry of Object.values(data.plugins))
1134
+ validatePluginOverride(entry);
1135
+ return data;
1136
+ }
1137
+ function validatePluginOverride(value) {
1138
+ if (!value || typeof value !== "object" || Array.isArray(value))
1139
+ throw new Error("Invalid plugin override.");
1140
+ const entry = value;
1141
+ if (entry.enabled !== undefined && typeof entry.enabled !== "boolean")
1142
+ throw new Error("Invalid plugin enablement.");
1143
+ if (entry.config !== undefined &&
1144
+ (!entry.config || typeof entry.config !== "object" || Array.isArray(entry.config)))
1145
+ throw new Error("Plugin config must be an object.");
1146
+ if (Object.keys(value).some((key) => !["enabled", "config"].includes(key)))
1147
+ throw new Error("Unknown plugin override field.");
1148
+ }
1149
+ function applyPluginOverrides(plugins, filename = pluginOverridesPath()) {
1150
+ const overrides = readPluginOverrides(filename).plugins;
1151
+ return plugins.map((plugin) => ({
1152
+ ...plugin,
1153
+ manifest: {
1154
+ ...plugin.manifest,
1155
+ ...(Object.prototype.hasOwnProperty.call(overrides, plugin.manifest.id)
1156
+ ? overrides[plugin.manifest.id]
1157
+ : {})
1158
+ }
1159
+ }));
1160
+ }
1161
+ /** Call inside the host's change queue; rename keeps readers off partial JSON. */
1162
+ function writePluginOverride(id, patch, filename = pluginOverridesPath()) {
1163
+ validatePluginOverride(patch);
1164
+ if (!id || ["__proto__", "constructor", "prototype"].includes(id))
1165
+ throw new Error("Invalid plugin id.");
1166
+ const data = readPluginOverrides(filename);
1167
+ data.plugins[id] = {
1168
+ ...(Object.prototype.hasOwnProperty.call(data.plugins, id) ? data.plugins[id] : {}),
1169
+ ...patch
1170
+ };
1171
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(filename), { recursive: true });
1172
+ const temporary = `${filename}.${(0, node_crypto_1.randomBytes)(8).toString("hex")}.tmp`;
1173
+ try {
1174
+ node_fs_1.default.writeFileSync(temporary, `${JSON.stringify(data, null, 2)}\n`, { mode: 0o600, flag: "wx" });
1175
+ node_fs_1.default.renameSync(temporary, filename);
1176
+ }
1177
+ finally {
1178
+ node_fs_1.default.rmSync(temporary, { force: true });
1179
+ }
1180
+ }
1181
+
1182
+
1183
+ /***/ },
1184
+
1185
+ /***/ "../common/src/plugin_revision.ts"
1186
+ (__unused_webpack_module, exports, __webpack_require__) {
1187
+
1188
+
1189
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1190
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1191
+ };
1192
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1193
+ exports.pluginDirectoryRevision = pluginDirectoryRevision;
1194
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
1195
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
1196
+ const node_crypto_1 = __webpack_require__("node:crypto");
1197
+ const cache = new Map();
1198
+ /** One revision addresses the complete module graph, including CSS and nested chunks. */
1199
+ function pluginDirectoryRevision(directory) {
1200
+ const files = [];
1201
+ const walk = (root) => {
1202
+ if (!node_fs_1.default.existsSync(root))
1203
+ return;
1204
+ for (const item of node_fs_1.default
1205
+ .readdirSync(root, { withFileTypes: true })
1206
+ .sort((a, b) => a.name.localeCompare(b.name))) {
1207
+ const absolute = node_path_1.default.join(root, item.name);
1208
+ if (item.isDirectory())
1209
+ walk(absolute);
1210
+ else if (item.isFile())
1211
+ files.push({
1212
+ relative: node_path_1.default.relative(directory, absolute),
1213
+ absolute,
1214
+ stat: node_fs_1.default.statSync(absolute)
1215
+ });
1216
+ }
1217
+ };
1218
+ walk(directory);
1219
+ const signature = JSON.stringify(files.map(({ relative, stat }) => [relative, stat.size, stat.mtimeMs, stat.ctimeMs]));
1220
+ const previous = cache.get(directory);
1221
+ if ((previous === null || previous === void 0 ? void 0 : previous.signature) === signature)
1222
+ return previous.revision;
1223
+ const hash = (0, node_crypto_1.createHash)("sha256");
1224
+ for (const file of files)
1225
+ hash
1226
+ .update(file.relative)
1227
+ .update("\0")
1228
+ .update(new Uint8Array(node_fs_1.default.readFileSync(file.absolute)))
1229
+ .update("\0");
1230
+ const revision = hash.digest("hex").slice(0, 24);
1231
+ if (cache.size > 1024)
1232
+ cache.clear();
1233
+ cache.set(directory, { signature, revision });
1234
+ return revision;
1235
+ }
1236
+
1237
+
1238
+ /***/ },
1239
+
1240
+ /***/ "../common/src/process_tools.ts"
1241
+ (__unused_webpack_module, exports, __webpack_require__) {
1242
+
1243
+
1244
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1245
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1246
+ };
1247
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1248
+ exports.ProcessWrapper = exports.StartError = void 0;
1249
+ exports.killProcess = killProcess;
1250
+ const child_process_1 = __webpack_require__("child_process");
1251
+ const os_1 = __importDefault(__webpack_require__("os"));
1252
+ const child_process_2 = __importDefault(__webpack_require__("child_process"));
1253
+ const path_1 = __importDefault(__webpack_require__("path"));
1254
+ const events_1 = __importDefault(__webpack_require__("events"));
1255
+ const iconv_lite_1 = __importDefault(__webpack_require__("iconv-lite"));
1256
+ const process_1 = __importDefault(__webpack_require__("process"));
1257
+ class StartError extends Error {
1258
+ }
1259
+ exports.StartError = StartError;
1260
+ class ProcessWrapper extends events_1.default {
1261
+ constructor(file, args, cwd, timeout = 0, code = "utf-8", option = {}) {
1262
+ super();
1263
+ this.file = file;
1264
+ this.args = args;
1265
+ this.cwd = cwd;
1266
+ this.timeout = timeout;
1267
+ this.code = code;
1268
+ this.option = option;
1269
+ this.completed = false;
1270
+ this.errMsg = {
1271
+ timeoutErr: "task timeout!",
1272
+ exitErr: "task error!",
1273
+ startErr: "task start error!"
1274
+ };
1275
+ }
1276
+ setErrMsg(errMsg) {
1277
+ this.errMsg = errMsg;
1278
+ }
1279
+ start() {
1280
+ if (this.process)
1281
+ return Promise.reject(new Error("The process is already running"));
1282
+ return new Promise((resolve, reject) => {
1283
+ const stdoutDecoder = iconv_lite_1.default.decodeStream(this.code);
1284
+ const stderrDecoder = iconv_lite_1.default.decodeStream(this.code);
1285
+ let timeTask;
1286
+ let settled = false;
1287
+ let spawned = false;
1288
+ const settle = (error) => {
1289
+ if (settled)
1290
+ return;
1291
+ settled = true;
1292
+ if (timeTask)
1293
+ clearTimeout(timeTask);
1294
+ if (error)
1295
+ reject(error);
1296
+ else
1297
+ resolve(true);
1298
+ };
1299
+ const subProcess = child_process_2.default.spawn(this.file, this.args, {
1300
+ stdio: "pipe",
1301
+ windowsHide: true,
1302
+ cwd: path_1.default.normalize(this.cwd),
1303
+ ...this.option
1304
+ });
1305
+ this.process = subProcess;
1306
+ this.pid = subProcess.pid;
1307
+ this.lastExitCode = undefined;
1308
+ this.completed = false;
1309
+ const fail = (error) => {
1310
+ if (settled)
1311
+ return;
1312
+ settle(error);
1313
+ if (subProcess.pid && subProcess.exitCode === null && subProcess.signalCode === null) {
1314
+ try {
1315
+ killProcess(subProcess.pid, subProcess);
1316
+ }
1317
+ catch (error) {
1318
+ console.error("[ProcessWrapper kill error]", error);
1319
+ }
1320
+ }
1321
+ };
1322
+ subProcess.once("spawn", () => {
1323
+ spawned = true;
1324
+ this.emit("start", subProcess.pid);
1325
+ });
1326
+ for (const [source, decoder] of [
1327
+ [subProcess.stdout, stdoutDecoder],
1328
+ [subProcess.stderr, stderrDecoder]
1329
+ ]) {
1330
+ decoder.on("data", (text) => this.emit("data", text));
1331
+ decoder.on("error", fail);
1332
+ source.on("error", fail);
1333
+ source.pipe(decoder);
1334
+ }
1335
+ subProcess.stdin.on("error", fail);
1336
+ subProcess.once("error", (error) => {
1337
+ fail(new Error(`${spawned ? this.errMsg.exitErr : this.errMsg.startErr} ${error.message}`));
1338
+ });
1339
+ subProcess.once("exit", (code) => {
1340
+ this.lastExitCode = code;
1341
+ this.emit("exit", code);
1342
+ });
1343
+ // `close` follows the final stdout/stderr data and also follows a failed spawn.
1344
+ subProcess.once("close", (code) => {
1345
+ this.lastExitCode = code;
1346
+ this.completed = true;
1347
+ this.process = undefined;
1348
+ settle(code === 0 ? undefined : new Error(this.errMsg.exitErr));
1349
+ });
1350
+ if (this.timeout > 0) {
1351
+ timeTask = setTimeout(() => {
1352
+ fail(new Error(this.errMsg.timeoutErr));
1353
+ }, 1000 * this.timeout);
1354
+ }
1355
+ });
1356
+ }
1357
+ getPid() {
1358
+ var _a;
1359
+ return (_a = this.process) === null || _a === void 0 ? void 0 : _a.pid;
1360
+ }
1361
+ write(data) {
1362
+ var _a, _b;
1363
+ return (_b = (_a = this.process) === null || _a === void 0 ? void 0 : _a.stdin) === null || _b === void 0 ? void 0 : _b.write(iconv_lite_1.default.encode(data, this.code));
1364
+ }
1365
+ kill() {
1366
+ var _a, _b;
1367
+ if ((_a = this.process) === null || _a === void 0 ? void 0 : _a.pid)
1368
+ killProcess((_b = this.process) === null || _b === void 0 ? void 0 : _b.pid, this.process);
1369
+ }
1370
+ status() {
1371
+ return this.completed;
1372
+ }
1373
+ exitCode() {
1374
+ var _a, _b;
1375
+ return (_b = (_a = this.process) === null || _a === void 0 ? void 0 : _a.exitCode) !== null && _b !== void 0 ? _b : this.lastExitCode;
1376
+ }
1377
+ }
1378
+ exports.ProcessWrapper = ProcessWrapper;
1379
+ function killProcess(pid, process, signal) {
1380
+ const numericPid = Number(pid);
1381
+ if (!Number.isSafeInteger(numericPid) || numericPid <= 0) {
1382
+ throw new Error("Invalid process ID");
1383
+ }
1384
+ try {
1385
+ if (os_1.default.platform() === "win32") {
1386
+ (0, child_process_1.execFileSync)("taskkill", ["/PID", String(numericPid), "/T", "/F"], { windowsHide: true });
1387
+ return true;
1388
+ }
1389
+ return process_1.default.kill(numericPid, signal || "SIGKILL");
1390
+ }
1391
+ catch (err) {
1392
+ return signal ? process.kill(signal) : process.kill("SIGKILL");
1393
+ }
1394
+ }
1395
+
1396
+
1397
+ /***/ },
1398
+
1399
+ /***/ "../common/src/query_wrapper.ts"
1400
+ (__unused_webpack_module, exports) {
1401
+
1402
+
1403
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1404
+ exports.QueryWrapper = exports.LocalFileSource = exports.MySqlSource = exports.QueryMapWrapper = void 0;
1405
+ function paginate(data, page, pageSize) {
1406
+ if (!Number.isSafeInteger(page) || page < 1 || !Number.isSafeInteger(pageSize) || pageSize < 1) {
1407
+ throw new RangeError("page and pageSize must be positive integers");
1408
+ }
1409
+ const start = (page - 1) * pageSize;
1410
+ return {
1411
+ page,
1412
+ pageSize,
1413
+ maxPage: Math.ceil(data.length / pageSize),
1414
+ total: data.length,
1415
+ data: data.slice(start, start + pageSize)
1416
+ };
1417
+ }
1418
+ // Provide the MAP query interface used by the routing layer
1419
+ class QueryMapWrapper {
1420
+ constructor(map) {
1421
+ this.map = map;
1422
+ }
1423
+ select(condition) {
1424
+ const result = [];
1425
+ this.map.forEach((v) => {
1426
+ if (condition(v))
1427
+ result.push(v);
1428
+ });
1429
+ return result;
1430
+ }
1431
+ page(data, page = 1, pageSize = 10) {
1432
+ return paginate(data, page, pageSize);
1433
+ }
1434
+ }
1435
+ exports.QueryMapWrapper = QueryMapWrapper;
1436
+ // MYSQL data source
1437
+ class MySqlSource {
1438
+ constructor(data) {
1439
+ this.data = data;
1440
+ }
1441
+ selectPage(condition, page, pageSize) {
1442
+ return {
1443
+ page,
1444
+ pageSize,
1445
+ maxPage: 0,
1446
+ total: 0,
1447
+ data: []
1448
+ };
1449
+ }
1450
+ select(condition) {
1451
+ return [];
1452
+ }
1453
+ update(condition, data) { }
1454
+ delete(condition) { }
1455
+ insert(data) { }
1456
+ }
1457
+ exports.MySqlSource = MySqlSource;
1458
+ // local file data source (embedded microdatabase)
1459
+ class LocalFileSource {
1460
+ constructor(data) {
1461
+ this.data = data;
1462
+ }
1463
+ selectPage(condition, page = 1, pageSize = 10) {
1464
+ return this.page(this.select(condition), page, pageSize);
1465
+ }
1466
+ page(data, page = 1, pageSize = 10) {
1467
+ return paginate(data, page, pageSize);
1468
+ }
1469
+ select(condition = {}) {
1470
+ const result = [];
1471
+ const entries = Object.entries(condition);
1472
+ this.data.forEach((v) => {
1473
+ for (const [key, targetValue] of entries) {
1474
+ const dataValue = v[key];
1475
+ if (typeof targetValue === "string" &&
1476
+ targetValue.startsWith("%") &&
1477
+ targetValue.endsWith("%")) {
1478
+ if (typeof dataValue !== "string" || !dataValue.includes(targetValue.slice(1, -1)))
1479
+ return;
1480
+ }
1481
+ else if (targetValue !== dataValue) {
1482
+ return;
1483
+ }
1484
+ }
1485
+ result.push(v);
1486
+ });
1487
+ return result;
1488
+ }
1489
+ update(condition, data) { }
1490
+ delete(condition) { }
1491
+ insert(data) { }
1492
+ }
1493
+ exports.LocalFileSource = LocalFileSource;
1494
+ // Provide the unified data query interface used by the routing layer
1495
+ class QueryWrapper {
1496
+ constructor(dataSource) {
1497
+ this.dataSource = dataSource;
1498
+ }
1499
+ selectPage(condition, page = 1, pageSize = 10) {
1500
+ return this.dataSource.selectPage(condition, page, pageSize);
1501
+ }
1502
+ }
1503
+ exports.QueryWrapper = QueryWrapper;
1504
+
1505
+
1506
+ /***/ },
1507
+
1508
+ /***/ "../common/src/runtime_paths.ts"
1509
+ (__unused_webpack_module, exports, __webpack_require__) {
1510
+
1511
+
1512
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1513
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1514
+ };
1515
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1516
+ exports.isPackagedRuntime = isPackagedRuntime;
1517
+ exports.packagePath = packagePath;
1518
+ exports.packagePluginRoots = packagePluginRoots;
1519
+ exports.isPackagePlugin = isPackagePlugin;
1520
+ exports.bundledToolPath = bundledToolPath;
1521
+ exports.ensureExecutable = ensureExecutable;
1522
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
1523
+ const node_os_1 = __importDefault(__webpack_require__("node:os"));
1524
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
1525
+ /** Set by the npm worker before any application module is loaded. */
1526
+ function isPackagedRuntime() {
1527
+ return Boolean(process.env.EPANEL_PACKAGE_ROOT);
1528
+ }
1529
+ /** Code and bundled assets belong to the package; cwd always belongs to the user. */
1530
+ function packagePath(...parts) {
1531
+ return node_path_1.default.resolve(process.env.EPANEL_PACKAGE_ROOT || process.cwd(), ...parts);
1532
+ }
1533
+ function npmPluginRoots(side) {
1534
+ // The same resolver is used by the CLI before the bundled application starts.
1535
+ // A development checkout keeps it in the repository, beside the side packages,
1536
+ // so project-installed npm plugins work there as well.
1537
+ const runtimeRequire = eval("require");
1538
+ const resolver = isPackagedRuntime()
1539
+ ? packagePath("runtime/npm-plugins.cjs")
1540
+ : node_path_1.default.resolve(packagePath(), "..", "scripts", "runtime", "npm-plugins.cjs");
1541
+ // A development process may run from a fixture directory without a runtime
1542
+ // package; there is nothing to resolve in that case.
1543
+ if (!node_fs_1.default.existsSync(node_path_1.default.join(packagePath(), "package.json")))
1544
+ return [];
1545
+ if (!isPackagedRuntime() && !node_fs_1.default.existsSync(resolver))
1546
+ return [];
1547
+ const { resolveNpmPlugins } = runtimeRequire(resolver);
1548
+ return resolveNpmPlugins(packagePath(), side, { skipInvalid: true }).map((record) => ({
1549
+ directory: record.directory,
1550
+ ...(record.folder ? { folder: record.folder } : {}),
1551
+ // Built-in packages are part of the runtime's default configuration. A
1552
+ // project dependency is installed but remains dormant until the user
1553
+ // enables it through the plugin configuration service.
1554
+ defaultEnabled: record.defaultEnabled !== false
1555
+ }));
1556
+ }
1557
+ function packagePluginRoots(side) {
1558
+ const roots = isPackagedRuntime()
1559
+ ? []
1560
+ : [{ directory: packagePath("plugins"), defaultEnabled: true }];
1561
+ // Project-installed npm plugins load in development too: they are dependencies
1562
+ // of the development project, not of the published runtime package.
1563
+ roots.push(...npmPluginRoots(side));
1564
+ return roots;
1565
+ }
1566
+ function isPackagePlugin(directory) {
1567
+ return npmPluginRoots().some((root) => {
1568
+ const relative = node_path_1.default.relative(root.directory, node_path_1.default.resolve(directory));
1569
+ return (relative === "" ||
1570
+ (!relative.startsWith(`..${node_path_1.default.sep}`) && relative !== ".." && !node_path_1.default.isAbsolute(relative)));
1571
+ });
1572
+ }
1573
+ function bundledToolPath(name) {
1574
+ const platform = node_os_1.default.platform();
1575
+ const arch = node_os_1.default.arch();
1576
+ const suffix = platform === "win32" ? ".exe" : "";
1577
+ const filename = `${name}_${platform}_${arch}${suffix}`;
1578
+ // Published daemon packages download native tools into the installation's
1579
+ // writable lib directory on first start. Development checkouts use the same
1580
+ // repository-local sibling of data and logs.
1581
+ const root = isPackagedRuntime() ? node_path_1.default.resolve(process.cwd(), "lib") : packagePath("lib");
1582
+ const primary = node_path_1.default.join(root, filename);
1583
+ // Zip-Tools names its Intel macOS binary "amd64", while Node reports "x64".
1584
+ if (!node_fs_1.default.existsSync(primary) && name === "file_zip" && platform === "darwin" && arch === "x64") {
1585
+ const alternate = node_path_1.default.join(root, "file_zip_darwin_amd64");
1586
+ if (node_fs_1.default.existsSync(alternate))
1587
+ return alternate;
1588
+ }
1589
+ return primary;
1590
+ }
1591
+ /** Published binaries already carry executable permissions, including in read-only installs. */
1592
+ function ensureExecutable(filename) {
1593
+ if (node_os_1.default.platform() === "win32")
1594
+ return;
1595
+ try {
1596
+ node_fs_1.default.accessSync(filename, node_fs_1.default.constants.X_OK);
1597
+ }
1598
+ catch (_a) {
1599
+ node_fs_1.default.chmodSync(filename, 0o755);
1600
+ }
1601
+ }
1602
+
1603
+
1604
+ /***/ },
1605
+
1606
+ /***/ "../common/src/string_utils.ts"
1607
+ (__unused_webpack_module, exports) {
1608
+
1609
+
1610
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1611
+ exports.removeTrail = removeTrail;
1612
+ function removeTrail(origin, trail) {
1613
+ if (origin.endsWith(trail)) {
1614
+ return origin.slice(0, origin.length - trail.length);
1615
+ }
1616
+ else {
1617
+ return origin;
1618
+ }
1619
+ }
1620
+
1621
+
1622
+ /***/ },
1623
+
1624
+ /***/ "../common/src/system_info.ts"
1625
+ (__unused_webpack_module, exports, __webpack_require__) {
1626
+
1627
+
1628
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1629
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1630
+ };
1631
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1632
+ exports.systemInfo = systemInfo;
1633
+ const os_1 = __importDefault(__webpack_require__("os"));
1634
+ const os_utils_1 = __importDefault(__webpack_require__("os-utils"));
1635
+ const fs_1 = __importDefault(__webpack_require__("fs"));
1636
+ // System details are updated every time
1637
+ const info = {
1638
+ type: os_1.default.type(),
1639
+ hostname: os_1.default.hostname(),
1640
+ platform: os_1.default.platform(),
1641
+ release: os_1.default.release(),
1642
+ uptime: os_1.default.uptime(),
1643
+ cwd: process.cwd(),
1644
+ loadavg: os_1.default.loadavg(),
1645
+ freemem: 0,
1646
+ cpuUsage: 0,
1647
+ memUsage: 0,
1648
+ totalmem: 0,
1649
+ processCpu: 0,
1650
+ processMem: 0
1651
+ };
1652
+ let previousCpu = process.cpuUsage();
1653
+ let previousTime = process.hrtime.bigint();
1654
+ // periodically refresh the cache
1655
+ function refresh() {
1656
+ const now = process.hrtime.bigint();
1657
+ const cpu = process.cpuUsage();
1658
+ const elapsed = Number(now - previousTime) / 1000;
1659
+ info.processCpu =
1660
+ elapsed > 0 ? (cpu.user - previousCpu.user + cpu.system - previousCpu.system) / elapsed : 0;
1661
+ previousCpu = cpu;
1662
+ previousTime = now;
1663
+ info.uptime = os_1.default.uptime();
1664
+ info.loadavg = os_1.default.loadavg();
1665
+ info.processMem = process.memoryUsage().rss;
1666
+ if (os_1.default.platform() === "linux") {
1667
+ return setLinuxSystemInfo();
1668
+ }
1669
+ return otherSystemInfo();
1670
+ }
1671
+ refresh();
1672
+ setInterval(refresh, 3000).unref();
1673
+ function otherSystemInfo() {
1674
+ info.freemem = os_1.default.freemem();
1675
+ info.totalmem = os_1.default.totalmem();
1676
+ info.memUsage = (os_1.default.totalmem() - os_1.default.freemem()) / os_1.default.totalmem();
1677
+ os_utils_1.default.cpuUsage((p) => (info.cpuUsage = p));
1678
+ }
1679
+ function setLinuxSystemInfo() {
1680
+ var _a;
1681
+ try {
1682
+ // read memory data based on /proc/meminfo
1683
+ const data = fs_1.default.readFileSync("/proc/meminfo", { encoding: "utf-8" });
1684
+ const list = data.split("\n");
1685
+ const infoTable = {};
1686
+ list.forEach((line) => {
1687
+ const kv = line.split(":");
1688
+ if (kv.length === 2) {
1689
+ const k = kv[0].replace(/ /gim, "").replace(/\t/gim, "").trim().toLowerCase();
1690
+ let v = kv[1].replace(/ /gim, "").replace(/\t/gim, "").trim().toLowerCase();
1691
+ v = v.replace(/kb/gim, "").replace(/mb/gim, "").replace(/gb/gim, "");
1692
+ let vNumber = parseInt(v);
1693
+ if (isNaN(vNumber))
1694
+ vNumber = 0;
1695
+ infoTable[k] = vNumber;
1696
+ }
1697
+ });
1698
+ const memAvailable = (_a = infoTable["memavailable"]) !== null && _a !== void 0 ? _a : infoTable["memfree"];
1699
+ const memTotal = infoTable["memtotal"];
1700
+ info.freemem = memAvailable * 1024;
1701
+ info.totalmem = memTotal * 1024;
1702
+ info.memUsage = (info.totalmem - info.freemem) / info.totalmem;
1703
+ os_utils_1.default.cpuUsage((p) => (info.cpuUsage = p));
1704
+ }
1705
+ catch (error) {
1706
+ // If the reading is wrong, the default general reading method is automatically used
1707
+ otherSystemInfo();
1708
+ }
1709
+ }
1710
+ function systemInfo() {
1711
+ return info;
1712
+ }
1713
+
1714
+
1715
+ /***/ },
1716
+
1717
+ /***/ "../common/src/system_storage.ts"
1718
+ (__unused_webpack_module, exports, __webpack_require__) {
1719
+
1720
+
1721
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1722
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1723
+ };
1724
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1725
+ const crypto_1 = __webpack_require__("crypto");
1726
+ const path_1 = __importDefault(__webpack_require__("path"));
1727
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
1728
+ class StorageSubsystem {
1729
+ resolvePath(name) {
1730
+ if (typeof name !== "string" ||
1731
+ !name ||
1732
+ /[\0:]/.test(name) ||
1733
+ path_1.default.isAbsolute(name) ||
1734
+ path_1.default.win32.isAbsolute(name)) {
1735
+ throw new Error(`Invalid storage path: ${name}`);
1736
+ }
1737
+ const target = path_1.default.resolve(StorageSubsystem.DATA_PATH, name);
1738
+ const relative = path_1.default.relative(StorageSubsystem.DATA_PATH, target);
1739
+ if (!relative ||
1740
+ relative === ".." ||
1741
+ relative.startsWith(`..${path_1.default.sep}`) ||
1742
+ path_1.default.isAbsolute(relative)) {
1743
+ throw new Error(`Invalid storage path: ${name}`);
1744
+ }
1745
+ const realRelative = path_1.default.relative(this.realPath(StorageSubsystem.DATA_PATH), this.realPath(target));
1746
+ if (realRelative === ".." ||
1747
+ realRelative.startsWith(`..${path_1.default.sep}`) ||
1748
+ path_1.default.isAbsolute(realRelative)) {
1749
+ throw new Error(`Invalid storage path: ${name}`);
1750
+ }
1751
+ return target;
1752
+ }
1753
+ realPath(target) {
1754
+ if (fs_extra_1.default.existsSync(target))
1755
+ return fs_extra_1.default.realpathSync(target);
1756
+ const parent = path_1.default.dirname(target);
1757
+ return parent === target ? target : path_1.default.join(this.realPath(parent), path_1.default.basename(target));
1758
+ }
1759
+ entityPath(category, uuid) {
1760
+ if (typeof uuid !== "string" || !uuid || /[\\/\0:]/.test(uuid) || uuid.includes("..")) {
1761
+ throw new Error(`UUID ${uuid} does not conform to specification`);
1762
+ }
1763
+ this.resolvePath(category);
1764
+ return path_1.default.join(category, `${uuid}.json`);
1765
+ }
1766
+ writeFile(name, data) {
1767
+ const targetPath = this.resolvePath(name);
1768
+ fs_extra_1.default.ensureDirSync(path_1.default.dirname(targetPath));
1769
+ const temporaryPath = `${targetPath}.${(0, crypto_1.randomUUID)()}.tmp`;
1770
+ const mode = fs_extra_1.default.existsSync(targetPath) ? fs_extra_1.default.statSync(targetPath).mode : 0o600;
1771
+ try {
1772
+ fs_extra_1.default.writeFileSync(temporaryPath, data, { encoding: "utf8", flag: "wx", mode });
1773
+ fs_extra_1.default.renameSync(temporaryPath, targetPath);
1774
+ }
1775
+ finally {
1776
+ if (fs_extra_1.default.existsSync(temporaryPath))
1777
+ fs_extra_1.default.unlinkSync(temporaryPath);
1778
+ }
1779
+ }
1780
+ readFile(name) {
1781
+ return fs_extra_1.default.readFileSync(this.resolvePath(name), "utf8");
1782
+ }
1783
+ readDir(dirName) {
1784
+ const targetPath = this.resolvePath(dirName);
1785
+ if (!fs_extra_1.default.existsSync(targetPath))
1786
+ return [];
1787
+ return fs_extra_1.default.readdirSync(targetPath).map((name) => path_1.default.join(dirName, name));
1788
+ }
1789
+ deleteFile(name) {
1790
+ fs_extra_1.default.removeSync(this.resolvePath(name));
1791
+ }
1792
+ fileExists(name) {
1793
+ return fs_extra_1.default.existsSync(this.resolvePath(name));
1794
+ }
1795
+ store(category, uuid, object) {
1796
+ this.writeFile(this.entityPath(category, uuid), JSON.stringify(object, null, 4));
1797
+ }
1798
+ // Restore declared fields while keeping defaults for fields absent in older data.
1799
+ defineAttr(target, object) {
1800
+ for (const key of Object.keys(target)) {
1801
+ if (!Object.prototype.hasOwnProperty.call(object, key) || object[key] === undefined)
1802
+ continue;
1803
+ const value = object[key];
1804
+ if (value !== null &&
1805
+ typeof value === "object" &&
1806
+ !Array.isArray(value) &&
1807
+ target[key] !== null &&
1808
+ typeof target[key] === "object" &&
1809
+ !Array.isArray(target[key])) {
1810
+ this.defineAttr(target[key], value);
1811
+ }
1812
+ else {
1813
+ target[key] = value;
1814
+ }
1815
+ }
1816
+ return target;
1817
+ }
1818
+ load(category, classz, uuid) {
1819
+ const file = this.entityPath(category, uuid);
1820
+ if (!this.fileExists(file))
1821
+ return null;
1822
+ const object = JSON.parse(this.readFile(file));
1823
+ if (!object || typeof object !== "object" || Array.isArray(object)) {
1824
+ throw new Error(`Invalid stored entity: ${file}`);
1825
+ }
1826
+ return this.defineAttr(new classz(), object);
1827
+ }
1828
+ list(category) {
1829
+ const directory = this.resolvePath(category);
1830
+ if (!fs_extra_1.default.existsSync(directory))
1831
+ return [];
1832
+ return fs_extra_1.default
1833
+ .readdirSync(directory, { withFileTypes: true })
1834
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
1835
+ .map((entry) => entry.name.slice(0, -5));
1836
+ }
1837
+ delete(category, uuid) {
1838
+ this.deleteFile(this.entityPath(category, uuid));
1839
+ }
1840
+ }
1841
+ StorageSubsystem.DATA_PATH = path_1.default.resolve(process.cwd(), "data");
1842
+ StorageSubsystem.INDEX_PATH = path_1.default.join(StorageSubsystem.DATA_PATH, "Index");
1843
+ exports["default"] = StorageSubsystem;
1844
+
1845
+
1846
+ /***/ },
1847
+
1848
+ /***/ "../common/src/typecheck.ts"
1849
+ (__unused_webpack_module, exports) {
1850
+
1851
+
1852
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1853
+ exports.configureEntityParams = configureEntityParams;
1854
+ exports.toText = toText;
1855
+ exports.toNumber = toNumber;
1856
+ exports.toBoolean = toBoolean;
1857
+ exports.isEmpty = isEmpty;
1858
+ exports.supposeValue = supposeValue;
1859
+ function configureEntityParams(self, args, key, typeFn) {
1860
+ var _a;
1861
+ const selfDefaultValue = (_a = self[key]) !== null && _a !== void 0 ? _a : null;
1862
+ const v = args[key] != null ? args[key] : selfDefaultValue;
1863
+ if (typeFn === Number) {
1864
+ if (v === "" || v == null) {
1865
+ self[key] = null;
1866
+ }
1867
+ else {
1868
+ if (isNaN(Number(v)))
1869
+ throw new Error(`ConfigureEntityParams Error: Expected type to be Number, but got ${typeof v}`);
1870
+ self[key] = Number(v);
1871
+ }
1872
+ return;
1873
+ }
1874
+ if (typeFn === String) {
1875
+ if (v == null) {
1876
+ self[key] = null;
1877
+ }
1878
+ else {
1879
+ self[key] = String(v);
1880
+ }
1881
+ return;
1882
+ }
1883
+ if (typeFn === Boolean) {
1884
+ if (v == null) {
1885
+ self[key] = false;
1886
+ }
1887
+ else {
1888
+ self[key] = Boolean(v);
1889
+ }
1890
+ return;
1891
+ }
1892
+ if (typeFn) {
1893
+ self[key] = typeFn(v);
1894
+ }
1895
+ else {
1896
+ self[key] = v;
1897
+ }
1898
+ }
1899
+ function toText(v) {
1900
+ if (isEmpty(v))
1901
+ return null;
1902
+ return String(v);
1903
+ }
1904
+ function toNumber(v) {
1905
+ if (isEmpty(v))
1906
+ return null;
1907
+ if (isNaN(Number(v)))
1908
+ return null;
1909
+ return Number(v);
1910
+ }
1911
+ function toBoolean(v) {
1912
+ if (isEmpty(v))
1913
+ return null;
1914
+ return Boolean(v);
1915
+ }
1916
+ function isEmpty(v) {
1917
+ return v === null || v === undefined;
1918
+ }
1919
+ function supposeValue(v, def) {
1920
+ if (isEmpty(v))
1921
+ return def;
1922
+ return v;
1923
+ }
1924
+
1925
+
1926
+ /***/ },
1927
+
1928
+ /***/ "./plugins/config/src/backend/settings.ts"
1929
+ (__unused_webpack_module, exports, __webpack_require__) {
1930
+
1931
+
1932
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1933
+ exports.SettingsFormService = void 0;
1934
+ const mcsmanager_common_1 = __webpack_require__("../common/src/index.ts");
1935
+ const cordis_1 = __webpack_require__("cordis");
1936
+ const cosmokit_1 = __webpack_require__("cosmokit");
1937
+ /**
1938
+ * The configuration registry belongs to the config plugin. A declaration is
1939
+ * scoped to the plugin that made it, so unloading that plugin removes its form
1940
+ * without leaving stale entries in the settings page.
1941
+ */
1942
+ class SettingsFormService extends cordis_1.Service {
1943
+ constructor(ctx) {
1944
+ super(ctx, "settingsForm", true);
1945
+ this.declarations = [];
1946
+ }
1947
+ declare(declaration) {
1948
+ const entry = { id: this.ctx.name, declaration };
1949
+ return this.ctx.effect(() => {
1950
+ this.declarations.push(entry);
1951
+ return () => (0, cosmokit_1.remove)(this.declarations, entry);
1952
+ });
1953
+ }
1954
+ declared() {
1955
+ return this.declarations.map((entry) => entry.id);
1956
+ }
1957
+ async read(id) {
1958
+ const entry = this.declarations.find((item) => item.id === id);
1959
+ if (!entry) {
1960
+ const schema = this.ctx.plugins.configuration(id);
1961
+ return schema.fields.length ? schema : null;
1962
+ }
1963
+ return {
1964
+ id,
1965
+ fields: entry.declaration.fields(),
1966
+ values: await entry.declaration.read()
1967
+ };
1968
+ }
1969
+ async write(id, values) {
1970
+ const entry = this.declarations.find((item) => item.id === id);
1971
+ if (!entry)
1972
+ return (await this.ctx.plugins.configure(id, values)).result;
1973
+ return this.ctx.plugins.runExclusive(async () => {
1974
+ (0, mcsmanager_common_1.validatePluginSettings)(entry.declaration.fields(), values);
1975
+ await entry.declaration.write(values);
1976
+ return {
1977
+ saved: true,
1978
+ application: entry.declaration.restartRequired ? "restart-required" : "applied"
1979
+ };
1980
+ });
1981
+ }
1982
+ }
1983
+ exports.SettingsFormService = SettingsFormService;
1984
+
1985
+
1986
+ /***/ },
1987
+
1988
+ /***/ "./plugins/config/src/i18n/index.ts"
1989
+ (__unused_webpack_module, exports, __webpack_require__) {
1990
+
1991
+
1992
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1993
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1994
+ };
1995
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1996
+ exports.localeMessages = void 0;
1997
+ const de_DE_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/de_DE.json"));
1998
+ const en_US_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/en_US.json"));
1999
+ const es_ES_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/es_ES.json"));
2000
+ const fr_FR_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/fr_FR.json"));
2001
+ const ja_JP_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/ja_JP.json"));
2002
+ const ko_KR_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/ko_KR.json"));
2003
+ const pt_BR_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/pt_BR.json"));
2004
+ const ru_RU_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/ru_RU.json"));
2005
+ const th_TH_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/th_TH.json"));
2006
+ const tr_TR_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/tr_TR.json"));
2007
+ const zh_CN_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/zh_CN.json"));
2008
+ const zh_TW_json_1 = __importDefault(__webpack_require__("./plugins/config/src/i18n/zh_TW.json"));
2009
+ exports.localeMessages = {
2010
+ de_de: de_DE_json_1.default,
2011
+ en_us: en_US_json_1.default,
2012
+ es_es: es_ES_json_1.default,
2013
+ fr_fr: fr_FR_json_1.default,
2014
+ ja_jp: ja_JP_json_1.default,
2015
+ ko_kr: ko_KR_json_1.default,
2016
+ pt_br: pt_BR_json_1.default,
2017
+ ru_ru: ru_RU_json_1.default,
2018
+ th_th: th_TH_json_1.default,
2019
+ tr_tr: tr_TR_json_1.default,
2020
+ zh_cn: zh_CN_json_1.default,
2021
+ zh_tw: zh_TW_json_1.default
2022
+ };
2023
+
2024
+
2025
+ /***/ },
2026
+
2027
+ /***/ "crypto"
2028
+ (module) {
2029
+
2030
+ module.exports = require("crypto");
2031
+
2032
+ /***/ },
2033
+
2034
+ /***/ "events"
2035
+ (module) {
2036
+
2037
+ module.exports = require("events");
2038
+
2039
+ /***/ },
2040
+
2041
+ /***/ "fs-extra"
2042
+ (module) {
2043
+
2044
+ module.exports = require("fs-extra");
2045
+
2046
+ /***/ },
2047
+
2048
+ /***/ "iconv-lite"
2049
+ (module) {
2050
+
2051
+ module.exports = require("iconv-lite");
2052
+
2053
+ /***/ },
2054
+
2055
+ /***/ "os-utils"
2056
+ (module) {
2057
+
2058
+ module.exports = require("os-utils");
2059
+
2060
+ /***/ },
2061
+
2062
+ /***/ "cordis"
2063
+ (module) {
2064
+
2065
+ module.exports = require("cordis");
2066
+
2067
+ /***/ },
2068
+
2069
+ /***/ "cosmokit"
2070
+ (module) {
2071
+
2072
+ module.exports = require("cosmokit");
2073
+
2074
+ /***/ },
2075
+
2076
+ /***/ "child_process"
2077
+ (module) {
2078
+
2079
+ module.exports = require("child_process");
2080
+
2081
+ /***/ },
2082
+
2083
+ /***/ "fs"
2084
+ (module) {
2085
+
2086
+ module.exports = require("fs");
2087
+
2088
+ /***/ },
2089
+
2090
+ /***/ "module"
2091
+ (module) {
2092
+
2093
+ module.exports = require("module");
2094
+
2095
+ /***/ },
2096
+
2097
+ /***/ "net"
2098
+ (module) {
2099
+
2100
+ module.exports = require("net");
2101
+
2102
+ /***/ },
2103
+
2104
+ /***/ "node:crypto"
2105
+ (module) {
2106
+
2107
+ module.exports = require("node:crypto");
2108
+
2109
+ /***/ },
2110
+
2111
+ /***/ "node:fs"
2112
+ (module) {
2113
+
2114
+ module.exports = require("node:fs");
2115
+
2116
+ /***/ },
2117
+
2118
+ /***/ "node:os"
2119
+ (module) {
2120
+
2121
+ module.exports = require("node:os");
2122
+
2123
+ /***/ },
2124
+
2125
+ /***/ "node:path"
2126
+ (module) {
2127
+
2128
+ module.exports = require("node:path");
2129
+
2130
+ /***/ },
2131
+
2132
+ /***/ "os"
2133
+ (module) {
2134
+
2135
+ module.exports = require("os");
2136
+
2137
+ /***/ },
2138
+
2139
+ /***/ "path"
2140
+ (module) {
2141
+
2142
+ module.exports = require("path");
2143
+
2144
+ /***/ },
2145
+
2146
+ /***/ "process"
2147
+ (module) {
2148
+
2149
+ module.exports = require("process");
2150
+
2151
+ /***/ },
2152
+
2153
+ /***/ "./plugins/config/src/i18n/de_DE.json"
2154
+ (module) {
2155
+
2156
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"Möchtest du das entsprechende Plugin auch auf den folgenden Knoten deaktivieren? Wähle die gewünschten Knoten aus.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"Möchtest du das entsprechende Plugin auch von den folgenden Knoten entfernen? Wähle die gewünschten Knoten aus.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"Die Plugins auf diesen Knoten konnten nicht geprüft werden: {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"Die Plugin-Aktion wurde auf diesen Knoten nicht abgeschlossen: {nodes}","TXT_CODE_PLUGIN_CONFIG":"Plugin-Konfiguration","TXT_CODE_PLUGIN_CANCEL":"Abbrechen","TXT_CODE_PLUGIN_DELETE":"Entfernen","TXT_CODE_PLUGIN_DELETE_CONFIRM":"Die Plugin-Dateien und gespeicherten Einstellungen werden dauerhaft entfernt.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"{name} entfernen?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"Plugin entfernt","TXT_CODE_PLUGIN_SAVE_SETTINGS":"Einstellungen speichern","TXT_CODE_PLUGIN_SAVE_REMINDER":"Denke daran, deine Einstellungen zu speichern!","TXT_CODE_PLUGIN_DISABLE":"Deaktivieren","TXT_CODE_PLUGIN_DISABLED":"Plugin deaktiviert","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"Alles, was dieses Plugin bereitstellt, wird sofort entfernt.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"{name} deaktivieren?","TXT_CODE_PLUGIN_ENABLE":"Aktivieren","TXT_CODE_PLUGIN_ENABLED":"Plugin aktiviert","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"Der Webserver kann nicht über das Panel deaktiviert werden, das er selbst bereitstellt. Setze stattdessen enabled auf false in seiner plugin.json.","TXT_CODE_PLUGIN_IS_DISABLED":"Dieses Plugin ist deaktiviert. Seine Seiten, Routen und API sind erst nach dem Aktivieren wieder verfügbar.","TXT_CODE_PLUGIN_LOAD_FAILED":"Dieses Plugin konnte nicht geladen werden","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"Die Plugins dieses Knotens konnten nicht aufgelistet werden.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"Dieser Knoten existiert nicht.","TXT_CODE_PLUGIN_NODE_OFFLINE":"nicht verbunden","TXT_CODE_PLUGIN_NODE_SELECT":"Knoten auswählen","TXT_CODE_PLUGIN_NO_CONFIG":"Dieses Plugin hat keine konfigurierbaren Optionen.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"Nicht zugeordnet","TXT_CODE_PLUGIN_GROUP_ADD":"Gruppe hinzufügen","TXT_CODE_PLUGIN_GROUP_EDIT":"Plugin-Gruppe bearbeiten","TXT_CODE_PLUGIN_GROUP_RENAME":"Gruppe umbenennen","TXT_CODE_PLUGIN_GROUP_DELETE":"Gruppe löschen","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"Gruppe {name} löschen?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"Die Gruppe und ihre Plugin-Zuordnungen werden entfernt. Die Plugins selbst werden nicht gelöscht.","TXT_CODE_PLUGIN_GROUP_NAME":"Gruppenname","TXT_CODE_PLUGIN_SCOPE_NODE":"Knoten","TXT_CODE_PLUGIN_SCOPE_PANEL":"Panel","TXT_CODE_PLUGIN_SELF_DISABLE":"Die Plugin-Verwaltung kann sich nicht selbst deaktivieren. Setze stattdessen enabled auf false in ihrer plugin.json.","TXT_CODE_PLUGIN_STATE_PENDING":"Wartet auf Abhängigkeiten","TXT_CODE_PLUGIN_STATE_DISABLED":"Deaktiviert","TXT_CODE_PLUGIN_STATE_LOADING":"Wird geladen","TXT_CODE_PLUGIN_STATE_ACTIVE":"Aktiv","TXT_CODE_PLUGIN_STATE_UNLOADING":"Wird entladen","TXT_CODE_PLUGIN_RESTART_REQUIRED":"Starten Sie den Dienst neu, um die Änderung anzuwenden.","TXT_CODE_PLUGIN_SAVED_PENDING":"Gespeichert; wartet auf Plugin-Abhängigkeiten.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"Browser-Plugin fehlgeschlagen","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"Laden Sie die Seite neu, um die aktualisierte Browser-Laufzeit zu laden."}');
2157
+
2158
+ /***/ },
2159
+
2160
+ /***/ "./plugins/config/src/i18n/en_US.json"
2161
+ (module) {
2162
+
2163
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"Also disable the matching plugin on the following nodes? Select the nodes to include.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"Also remove the matching plugin from the following nodes? Select the nodes to include.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"Could not check the plugins on these nodes: {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"The plugin action did not complete on these nodes: {nodes}","TXT_CODE_PLUGIN_CONFIG":"Plugin Configuration","TXT_CODE_PLUGIN_CANCEL":"Cancel","TXT_CODE_PLUGIN_DELETE":"Remove","TXT_CODE_PLUGIN_DELETE_CONFIRM":"The plugin files and saved configuration will be permanently removed.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"Remove {name}?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"Plugin removed","TXT_CODE_PLUGIN_SAVE_SETTINGS":"Save settings","TXT_CODE_PLUGIN_SAVE_REMINDER":"Remember to save your settings!","TXT_CODE_PLUGIN_DISABLE":"Disable","TXT_CODE_PLUGIN_DISABLED":"Plugin disabled","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"Everything this plugin provides is removed at once.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"Disable {name}?","TXT_CODE_PLUGIN_ENABLE":"Enable","TXT_CODE_PLUGIN_ENABLED":"Plugin enabled","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"The web server cannot be disabled from the panel it serves. Set enabled to false in its plugin.json instead.","TXT_CODE_PLUGIN_IS_DISABLED":"This plugin is disabled. Its pages, routes and API are unavailable until it is enabled again.","TXT_CODE_PLUGIN_LOAD_FAILED":"This plugin failed to load","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"This node\'s plugins could not be listed.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"That node does not exist.","TXT_CODE_PLUGIN_NODE_OFFLINE":"not connected","TXT_CODE_PLUGIN_NODE_SELECT":"Select a node","TXT_CODE_PLUGIN_NO_CONFIG":"This plugin has no configurable options.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"Unassigned","TXT_CODE_PLUGIN_GROUP_ADD":"Add group","TXT_CODE_PLUGIN_GROUP_EDIT":"Edit plugin group","TXT_CODE_PLUGIN_GROUP_RENAME":"Rename group","TXT_CODE_PLUGIN_GROUP_DELETE":"Delete group","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"Delete group {name}?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"The group and its plugin assignments will be removed. The plugins themselves will not be deleted.","TXT_CODE_PLUGIN_GROUP_NAME":"Group name","TXT_CODE_PLUGIN_SCOPE_NODE":"Nodes","TXT_CODE_PLUGIN_SCOPE_PANEL":"Panel","TXT_CODE_PLUGIN_SELF_DISABLE":"The plugin manager cannot disable itself. Set enabled to false in its plugin.json instead.","TXT_CODE_PLUGIN_STATE_PENDING":"Waiting for dependencies","TXT_CODE_PLUGIN_STATE_DISABLED":"Disabled","TXT_CODE_PLUGIN_STATE_LOADING":"Loading","TXT_CODE_PLUGIN_STATE_ACTIVE":"Running","TXT_CODE_PLUGIN_STATE_UNLOADING":"Unloading","TXT_CODE_PLUGIN_RESTART_REQUIRED":"Restart the service to apply this change.","TXT_CODE_PLUGIN_SAVED_PENDING":"Saved; waiting for plugin dependencies.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"Browser plugin failed","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"Refresh the page to load the updated browser runtime."}');
2164
+
2165
+ /***/ },
2166
+
2167
+ /***/ "./plugins/config/src/i18n/es_ES.json"
2168
+ (module) {
2169
+
2170
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"¿Quieres desactivar también el complemento correspondiente en los siguientes nodos? Selecciona los nodos que quieras incluir.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"¿Quieres eliminar también el complemento correspondiente de los siguientes nodos? Selecciona los nodos que quieras incluir.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"No se pudieron comprobar los complementos de estos nodos: {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"La operación del complemento no se completó en estos nodos: {nodes}","TXT_CODE_PLUGIN_CONFIG":"Configuracion de plugins","TXT_CODE_PLUGIN_CANCEL":"Cancelar","TXT_CODE_PLUGIN_DELETE":"Eliminar","TXT_CODE_PLUGIN_DELETE_CONFIRM":"Los archivos del complemento y su configuración guardada se eliminarán permanentemente.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"¿Eliminar {name}?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"Complemento eliminado","TXT_CODE_PLUGIN_SAVE_SETTINGS":"Guardar configuración","TXT_CODE_PLUGIN_SAVE_REMINDER":"¡Recuerda guardar la configuración!","TXT_CODE_PLUGIN_DISABLE":"Desactivar","TXT_CODE_PLUGIN_DISABLED":"Complemento desactivado","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"Todo lo que aporta este complemento se elimina de inmediato.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"¿Desactivar {name}?","TXT_CODE_PLUGIN_ENABLE":"Activar","TXT_CODE_PLUGIN_ENABLED":"Complemento activado","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"El servidor web no puede desactivarse desde el panel que él mismo sirve. Establece enabled en false en su plugin.json.","TXT_CODE_PLUGIN_IS_DISABLED":"Este complemento está desactivado. Sus páginas, rutas y API no están disponibles hasta que se vuelva a activar.","TXT_CODE_PLUGIN_LOAD_FAILED":"No se pudo cargar este complemento","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"No se pudieron listar los complementos de este nodo.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"Ese nodo no existe.","TXT_CODE_PLUGIN_NODE_OFFLINE":"sin conexión","TXT_CODE_PLUGIN_NODE_SELECT":"Seleccionar un nodo","TXT_CODE_PLUGIN_NO_CONFIG":"Este plugin no tiene opciones configurables.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"Sin asignar","TXT_CODE_PLUGIN_GROUP_ADD":"Añadir grupo","TXT_CODE_PLUGIN_GROUP_EDIT":"Editar grupo de plugins","TXT_CODE_PLUGIN_GROUP_RENAME":"Cambiar nombre del grupo","TXT_CODE_PLUGIN_GROUP_DELETE":"Eliminar grupo","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"¿Eliminar el grupo {name}?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"Se eliminarán el grupo y sus asignaciones de plugins. Los plugins no se eliminarán.","TXT_CODE_PLUGIN_GROUP_NAME":"Nombre del grupo","TXT_CODE_PLUGIN_SCOPE_NODE":"Nodos","TXT_CODE_PLUGIN_SCOPE_PANEL":"Panel","TXT_CODE_PLUGIN_SELF_DISABLE":"El gestor de complementos no puede desactivarse a sí mismo. Establece enabled en false en su plugin.json.","TXT_CODE_PLUGIN_STATE_PENDING":"Esperando dependencias","TXT_CODE_PLUGIN_STATE_DISABLED":"Desactivado","TXT_CODE_PLUGIN_STATE_LOADING":"Cargando","TXT_CODE_PLUGIN_STATE_ACTIVE":"En ejecución","TXT_CODE_PLUGIN_STATE_UNLOADING":"Descargando","TXT_CODE_PLUGIN_RESTART_REQUIRED":"Reinicia el servicio para aplicar el cambio.","TXT_CODE_PLUGIN_SAVED_PENDING":"Guardado; esperando dependencias del complemento.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"Error del complemento del navegador","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"Recarga la página para cargar el entorno actualizado del navegador."}');
2171
+
2172
+ /***/ },
2173
+
2174
+ /***/ "./plugins/config/src/i18n/fr_FR.json"
2175
+ (module) {
2176
+
2177
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"Voulez-vous aussi désactiver le plugin correspondant sur les nœuds suivants ? Sélectionnez les nœuds à inclure.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"Voulez-vous aussi supprimer le plugin correspondant des nœuds suivants ? Sélectionnez les nœuds à inclure.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"Impossible de vérifier les plugins sur ces nœuds : {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"L’opération sur le plugin n’a pas abouti sur ces nœuds : {nodes}","TXT_CODE_PLUGIN_CONFIG":"Configuration des plugins","TXT_CODE_PLUGIN_CANCEL":"Annuler","TXT_CODE_PLUGIN_DELETE":"Supprimer","TXT_CODE_PLUGIN_DELETE_CONFIRM":"Les fichiers du plugin et sa configuration enregistrée seront supprimés définitivement.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"Supprimer {name} ?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"Plugin supprimé","TXT_CODE_PLUGIN_SAVE_SETTINGS":"Enregistrer la configuration","TXT_CODE_PLUGIN_SAVE_REMINDER":"Pensez à enregistrer la configuration !","TXT_CODE_PLUGIN_DISABLE":"Désactiver","TXT_CODE_PLUGIN_DISABLED":"Extension désactivée","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"Tout ce que cette extension fournit est retiré immédiatement.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"Désactiver {name} ?","TXT_CODE_PLUGIN_ENABLE":"Activer","TXT_CODE_PLUGIN_ENABLED":"Extension activée","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"Le serveur web ne peut pas être désactivé depuis le panneau qu il sert lui-même. Définissez plutôt enabled à false dans son plugin.json.","TXT_CODE_PLUGIN_IS_DISABLED":"Cette extension est désactivée. Ses pages, routes et API ne sont pas disponibles avant sa réactivation.","TXT_CODE_PLUGIN_LOAD_FAILED":"Le chargement de cette extension a échoué","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"Impossible de lister les extensions de ce nœud.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"Ce nœud n existe pas.","TXT_CODE_PLUGIN_NODE_OFFLINE":"non connecté","TXT_CODE_PLUGIN_NODE_SELECT":"Sélectionner un nœud","TXT_CODE_PLUGIN_NO_CONFIG":"Ce plugin ne comporte aucune option configurable.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"Non attribués","TXT_CODE_PLUGIN_GROUP_ADD":"Ajouter un groupe","TXT_CODE_PLUGIN_GROUP_EDIT":"Modifier le groupe de plugins","TXT_CODE_PLUGIN_GROUP_RENAME":"Renommer le groupe","TXT_CODE_PLUGIN_GROUP_DELETE":"Supprimer le groupe","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"Supprimer le groupe {name} ?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"Le groupe et ses affectations de plugins seront supprimés. Les plugins eux-mêmes ne seront pas supprimés.","TXT_CODE_PLUGIN_GROUP_NAME":"Nom du groupe","TXT_CODE_PLUGIN_SCOPE_NODE":"Nœuds","TXT_CODE_PLUGIN_SCOPE_PANEL":"Panneau","TXT_CODE_PLUGIN_SELF_DISABLE":"Le gestionnaire d extensions ne peut pas se désactiver lui-même. Définissez plutôt enabled à false dans son plugin.json.","TXT_CODE_PLUGIN_STATE_PENDING":"En attente des dépendances","TXT_CODE_PLUGIN_STATE_DISABLED":"Désactivé","TXT_CODE_PLUGIN_STATE_LOADING":"Chargement","TXT_CODE_PLUGIN_STATE_ACTIVE":"Actif","TXT_CODE_PLUGIN_STATE_UNLOADING":"Déchargement","TXT_CODE_PLUGIN_RESTART_REQUIRED":"Redémarrez le service pour appliquer cette modification.","TXT_CODE_PLUGIN_SAVED_PENDING":"Enregistré ; en attente des dépendances du plugin.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"Échec du plugin du navigateur","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"Actualisez la page pour charger le nouvel environnement du navigateur."}');
2178
+
2179
+ /***/ },
2180
+
2181
+ /***/ "./plugins/config/src/i18n/ja_JP.json"
2182
+ (module) {
2183
+
2184
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"以下のノードにある同じプラグインも無効にしますか?対象のノードを選択してください。","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"以下のノードにある同じプラグインも削除しますか?対象のノードを選択してください。","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"以下のノードのプラグインを確認できませんでした:{nodes}。","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"以下のノードでプラグインの操作が完了しませんでした:{nodes}","TXT_CODE_PLUGIN_CONFIG":"プラグイン設定","TXT_CODE_PLUGIN_CANCEL":"キャンセル","TXT_CODE_PLUGIN_DELETE":"削除","TXT_CODE_PLUGIN_DELETE_CONFIRM":"プラグインファイルと保存済みの設定が完全に削除されます。","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"{name} を削除しますか?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"プラグインを削除しました","TXT_CODE_PLUGIN_SAVE_SETTINGS":"設定を保存","TXT_CODE_PLUGIN_SAVE_REMINDER":"設定の保存をお忘れなく!","TXT_CODE_PLUGIN_DISABLE":"無効化","TXT_CODE_PLUGIN_DISABLED":"プラグインを無効にしました","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"このプラグインが提供するすべての要素が即座に削除されます。","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"{name} を無効にしますか?","TXT_CODE_PLUGIN_ENABLE":"有効化","TXT_CODE_PLUGIN_ENABLED":"プラグインを有効にしました","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"Web サーバーは、それ自身が配信しているパネルからは無効にできません。plugin.json で enabled を false に設定してください。","TXT_CODE_PLUGIN_IS_DISABLED":"このプラグインは無効です。再度有効にするまで、ページ・ルート・API は利用できません。","TXT_CODE_PLUGIN_LOAD_FAILED":"このプラグインの読み込みに失敗しました","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"このノードのプラグイン一覧を取得できませんでした。","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"そのノードは存在しません。","TXT_CODE_PLUGIN_NODE_OFFLINE":"未接続","TXT_CODE_PLUGIN_NODE_SELECT":"ノードを選択","TXT_CODE_PLUGIN_NO_CONFIG":"このプラグインには設定可能な項目がありません。","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"未分類","TXT_CODE_PLUGIN_GROUP_ADD":"グループを追加","TXT_CODE_PLUGIN_GROUP_EDIT":"プラグイン グループを編集","TXT_CODE_PLUGIN_GROUP_RENAME":"グループ名を変更","TXT_CODE_PLUGIN_GROUP_DELETE":"グループを削除","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"グループ「{name}」を削除しますか?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"グループとプラグインの割り当てを削除します。プラグイン自体は削除されません。","TXT_CODE_PLUGIN_GROUP_NAME":"グループ名","TXT_CODE_PLUGIN_SCOPE_NODE":"ノード","TXT_CODE_PLUGIN_SCOPE_PANEL":"パネル","TXT_CODE_PLUGIN_SELF_DISABLE":"プラグイン管理自身は無効にできません。plugin.json で enabled を false に設定してください。","TXT_CODE_PLUGIN_STATE_PENDING":"依存関係を待機中","TXT_CODE_PLUGIN_STATE_DISABLED":"無効","TXT_CODE_PLUGIN_STATE_LOADING":"読み込み中","TXT_CODE_PLUGIN_STATE_ACTIVE":"実行中","TXT_CODE_PLUGIN_STATE_UNLOADING":"アンロード中","TXT_CODE_PLUGIN_RESTART_REQUIRED":"変更を適用するにはサービスを再起動してください。","TXT_CODE_PLUGIN_SAVED_PENDING":"保存しました。プラグインの依存関係を待機しています。","TXT_CODE_PLUGIN_FRONTEND_FAILED":"ブラウザープラグインの読み込みに失敗しました","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"更新されたブラウザーランタイムを読み込むにはページを再読み込みしてください。"}');
2185
+
2186
+ /***/ },
2187
+
2188
+ /***/ "./plugins/config/src/i18n/ko_KR.json"
2189
+ (module) {
2190
+
2191
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"다음 노드의 동일한 플러그인도 비활성화할까요? 함께 처리할 노드를 선택하세요.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"다음 노드의 동일한 플러그인도 삭제할까요? 함께 처리할 노드를 선택하세요.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"다음 노드의 플러그인을 확인할 수 없습니다: {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"다음 노드에서 플러그인 작업이 완료되지 않았습니다: {nodes}","TXT_CODE_PLUGIN_CONFIG":"플러그인 설정","TXT_CODE_PLUGIN_CANCEL":"취소","TXT_CODE_PLUGIN_DELETE":"삭제","TXT_CODE_PLUGIN_DELETE_CONFIRM":"플러그인 파일과 저장된 설정이 영구적으로 삭제됩니다.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"{name} 플러그인을 삭제할까요?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"플러그인을 삭제했습니다","TXT_CODE_PLUGIN_SAVE_SETTINGS":"설정 저장","TXT_CODE_PLUGIN_SAVE_REMINDER":"설정을 저장하는 것을 잊지 마세요!","TXT_CODE_PLUGIN_DISABLE":"비활성화","TXT_CODE_PLUGIN_DISABLED":"플러그인을 비활성화했습니다","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"이 플러그인이 제공하는 모든 구성 요소가 즉시 제거됩니다.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"{name}을(를) 비활성화할까요?","TXT_CODE_PLUGIN_ENABLE":"활성화","TXT_CODE_PLUGIN_ENABLED":"플러그인을 활성화했습니다","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"웹 서버는 자신이 제공하는 패널에서 비활성화할 수 없습니다. plugin.json에서 enabled 를 false 로 설정하세요.","TXT_CODE_PLUGIN_IS_DISABLED":"이 플러그인은 비활성화되어 있습니다. 다시 활성화할 때까지 페이지, 경로, API를 사용할 수 없습니다.","TXT_CODE_PLUGIN_LOAD_FAILED":"이 플러그인을 불러오지 못했습니다","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"이 노드의 플러그인 목록을 가져올 수 없습니다.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"해당 노드가 존재하지 않습니다.","TXT_CODE_PLUGIN_NODE_OFFLINE":"연결되지 않음","TXT_CODE_PLUGIN_NODE_SELECT":"노드 선택","TXT_CODE_PLUGIN_NO_CONFIG":"이 플러그인에는 구성 가능한 옵션이 없습니다.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"미분류","TXT_CODE_PLUGIN_GROUP_ADD":"그룹 추가","TXT_CODE_PLUGIN_GROUP_EDIT":"플러그인 그룹 편집","TXT_CODE_PLUGIN_GROUP_RENAME":"그룹 이름 변경","TXT_CODE_PLUGIN_GROUP_DELETE":"그룹 삭제","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"{name} 그룹을 삭제하시겠습니까?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"그룹과 플러그인 할당이 삭제됩니다. 플러그인 자체는 삭제되지 않습니다.","TXT_CODE_PLUGIN_GROUP_NAME":"그룹 이름","TXT_CODE_PLUGIN_SCOPE_NODE":"노드","TXT_CODE_PLUGIN_SCOPE_PANEL":"패널","TXT_CODE_PLUGIN_SELF_DISABLE":"플러그인 관리자는 자신을 비활성화할 수 없습니다. plugin.json에서 enabled 를 false 로 설정하세요.","TXT_CODE_PLUGIN_STATE_PENDING":"종속성 대기 중","TXT_CODE_PLUGIN_STATE_DISABLED":"비활성","TXT_CODE_PLUGIN_STATE_LOADING":"로드 중","TXT_CODE_PLUGIN_STATE_ACTIVE":"실행 중","TXT_CODE_PLUGIN_STATE_UNLOADING":"언로드 중","TXT_CODE_PLUGIN_RESTART_REQUIRED":"변경 사항을 적용하려면 서비스를 다시 시작하세요.","TXT_CODE_PLUGIN_SAVED_PENDING":"저장되었습니다. 플러그인 종속성을 기다리는 중입니다.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"브라우저 플러그인 로드 실패","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"업데이트된 브라우저 런타임을 로드하려면 페이지를 새로 고치세요."}');
2192
+
2193
+ /***/ },
2194
+
2195
+ /***/ "./plugins/config/src/i18n/pt_BR.json"
2196
+ (module) {
2197
+
2198
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"Desativar também o plugin correspondente nos seguintes nós? Selecione os nós que deseja incluir.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"Remover também o plugin correspondente dos seguintes nós? Selecione os nós que deseja incluir.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"Não foi possível verificar os plugins nestes nós: {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"A operação do plugin não foi concluída nestes nós: {nodes}","TXT_CODE_PLUGIN_CONFIG":"Configuracao de plugins","TXT_CODE_PLUGIN_CANCEL":"Cancelar","TXT_CODE_PLUGIN_DELETE":"Remover","TXT_CODE_PLUGIN_DELETE_CONFIRM":"Os arquivos do plugin e as configurações salvas serão removidos permanentemente.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"Remover {name}?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"Plugin removido","TXT_CODE_PLUGIN_SAVE_SETTINGS":"Salvar configurações","TXT_CODE_PLUGIN_SAVE_REMINDER":"Lembre-se de salvar as configurações!","TXT_CODE_PLUGIN_DISABLE":"Desativar","TXT_CODE_PLUGIN_DISABLED":"Plugin desativado","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"Tudo o que este plugin fornece é removido de imediato.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"Desativar {name}?","TXT_CODE_PLUGIN_ENABLE":"Ativar","TXT_CODE_PLUGIN_ENABLED":"Plugin ativado","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"O servidor web não pode ser desativado pelo painel que ele mesmo serve. Defina enabled como false no plugin.json dele.","TXT_CODE_PLUGIN_IS_DISABLED":"Este plugin está desativado. Suas páginas, rotas e API ficam indisponíveis até ser ativado novamente.","TXT_CODE_PLUGIN_LOAD_FAILED":"Falha ao carregar este plugin","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"Não foi possível listar os plugins deste nó.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"Esse nó não existe.","TXT_CODE_PLUGIN_NODE_OFFLINE":"não conectado","TXT_CODE_PLUGIN_NODE_SELECT":"Selecionar um nó","TXT_CODE_PLUGIN_NO_CONFIG":"Este plugin nao possui opcoes configuraveis.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"Não atribuídos","TXT_CODE_PLUGIN_GROUP_ADD":"Adicionar grupo","TXT_CODE_PLUGIN_GROUP_EDIT":"Editar grupo de plugins","TXT_CODE_PLUGIN_GROUP_RENAME":"Renomear grupo","TXT_CODE_PLUGIN_GROUP_DELETE":"Excluir grupo","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"Excluir o grupo {name}?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"O grupo e suas associações de plugins serão removidos. Os plugins não serão excluídos.","TXT_CODE_PLUGIN_GROUP_NAME":"Nome do grupo","TXT_CODE_PLUGIN_SCOPE_NODE":"Nós","TXT_CODE_PLUGIN_SCOPE_PANEL":"Painel","TXT_CODE_PLUGIN_SELF_DISABLE":"O gerenciador de plugins não pode desativar a si mesmo. Defina enabled como false no plugin.json dele.","TXT_CODE_PLUGIN_STATE_PENDING":"Aguardando dependências","TXT_CODE_PLUGIN_STATE_DISABLED":"Desativado","TXT_CODE_PLUGIN_STATE_LOADING":"Carregando","TXT_CODE_PLUGIN_STATE_ACTIVE":"Em execução","TXT_CODE_PLUGIN_STATE_UNLOADING":"Descarregando","TXT_CODE_PLUGIN_RESTART_REQUIRED":"Reinicie o serviço para aplicar a alteração.","TXT_CODE_PLUGIN_SAVED_PENDING":"Salvo; aguardando dependências do plugin.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"Falha no plugin do navegador","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"Atualize a página para carregar o novo ambiente do navegador."}');
2199
+
2200
+ /***/ },
2201
+
2202
+ /***/ "./plugins/config/src/i18n/ru_RU.json"
2203
+ (module) {
2204
+
2205
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"Отключить соответствующий плагин также на следующих узлах? Выберите нужные узлы.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"Удалить соответствующий плагин также со следующих узлов? Выберите нужные узлы.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"Не удалось проверить плагины на этих узлах: {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"Операция с плагином не завершена на этих узлах: {nodes}","TXT_CODE_PLUGIN_CONFIG":"Настройка плагинов","TXT_CODE_PLUGIN_CANCEL":"Отмена","TXT_CODE_PLUGIN_DELETE":"Удалить","TXT_CODE_PLUGIN_DELETE_CONFIRM":"Файлы плагина и сохранённые настройки будут удалены без возможности восстановления.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"Удалить {name}?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"Плагин удалён","TXT_CODE_PLUGIN_SAVE_SETTINGS":"Сохранить настройки","TXT_CODE_PLUGIN_SAVE_REMINDER":"Не забудьте сохранить настройки!","TXT_CODE_PLUGIN_DISABLE":"Отключить","TXT_CODE_PLUGIN_DISABLED":"Плагин отключён","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"Всё, что предоставляет этот плагин, будет удалено сразу.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"Отключить {name}?","TXT_CODE_PLUGIN_ENABLE":"Включить","TXT_CODE_PLUGIN_ENABLED":"Плагин включён","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"Веб-сервер нельзя отключить из панели, которую он сам и обслуживает. Укажите enabled: false в его plugin.json.","TXT_CODE_PLUGIN_IS_DISABLED":"Этот плагин отключён. Его страницы, маршруты и API недоступны, пока он не будет включён снова.","TXT_CODE_PLUGIN_LOAD_FAILED":"Не удалось загрузить этот плагин","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"Не удалось получить список плагинов этого узла.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"Такого узла не существует.","TXT_CODE_PLUGIN_NODE_OFFLINE":"не подключён","TXT_CODE_PLUGIN_NODE_SELECT":"Выберите узел","TXT_CODE_PLUGIN_NO_CONFIG":"У этого плагина нет настраиваемых параметров.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"Без группы","TXT_CODE_PLUGIN_GROUP_ADD":"Добавить группу","TXT_CODE_PLUGIN_GROUP_EDIT":"Редактировать группу плагинов","TXT_CODE_PLUGIN_GROUP_RENAME":"Переименовать группу","TXT_CODE_PLUGIN_GROUP_DELETE":"Удалить группу","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"Удалить группу {name}?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"Группа и привязанные к ней плагины будут удалены из списка. Сами плагины удалены не будут.","TXT_CODE_PLUGIN_GROUP_NAME":"Название группы","TXT_CODE_PLUGIN_SCOPE_NODE":"Узлы","TXT_CODE_PLUGIN_SCOPE_PANEL":"Панель","TXT_CODE_PLUGIN_SELF_DISABLE":"Менеджер плагинов не может отключить сам себя. Укажите enabled: false в его plugin.json.","TXT_CODE_PLUGIN_STATE_PENDING":"Ожидание зависимостей","TXT_CODE_PLUGIN_STATE_DISABLED":"Отключён","TXT_CODE_PLUGIN_STATE_LOADING":"Загрузка","TXT_CODE_PLUGIN_STATE_ACTIVE":"Работает","TXT_CODE_PLUGIN_STATE_UNLOADING":"Выгрузка","TXT_CODE_PLUGIN_RESTART_REQUIRED":"Перезапустите службу, чтобы применить изменение.","TXT_CODE_PLUGIN_SAVED_PENDING":"Сохранено; ожидание зависимостей плагина.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"Ошибка плагина браузера","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"Обновите страницу для загрузки новой среды браузера."}');
2206
+
2207
+ /***/ },
2208
+
2209
+ /***/ "./plugins/config/src/i18n/th_TH.json"
2210
+ (module) {
2211
+
2212
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"ต้องการปิดใช้งานปลั๊กอินเดียวกันบนโหนดต่อไปนี้ด้วยหรือไม่? เลือกโหนดที่ต้องการดำเนินการด้วย","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"ต้องการลบปลั๊กอินเดียวกันออกจากโหนดต่อไปนี้ด้วยหรือไม่? เลือกโหนดที่ต้องการดำเนินการด้วย","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"ไม่สามารถตรวจสอบปลั๊กอินบนโหนดเหล่านี้ได้: {nodes}","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"การดำเนินการกับปลั๊กอินบนโหนดเหล่านี้ไม่สำเร็จ: {nodes}","TXT_CODE_PLUGIN_CONFIG":"การกำหนดค่าปลั๊กอิน","TXT_CODE_PLUGIN_CANCEL":"ยกเลิก","TXT_CODE_PLUGIN_DELETE":"ลบ","TXT_CODE_PLUGIN_DELETE_CONFIRM":"ไฟล์ปลั๊กอินและการตั้งค่าที่บันทึกไว้จะถูกลบอย่างถาวร","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"ลบ {name} หรือไม่?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"ลบปลั๊กอินแล้ว","TXT_CODE_PLUGIN_SAVE_SETTINGS":"บันทึกการตั้งค่า","TXT_CODE_PLUGIN_SAVE_REMINDER":"อย่าลืมบันทึกการตั้งค่า!","TXT_CODE_PLUGIN_DISABLE":"ปิดใช้งาน","TXT_CODE_PLUGIN_DISABLED":"ปิดใช้งานปลั๊กอินแล้ว","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"ทุกอย่างที่ปลั๊กอินนี้ให้มาจะถูกลบออกทันที","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"ปิดใช้งาน {name} หรือไม่?","TXT_CODE_PLUGIN_ENABLE":"เปิดใช้งาน","TXT_CODE_PLUGIN_ENABLED":"เปิดใช้งานปลั๊กอินแล้ว","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"ไม่สามารถปิดใช้งานเว็บเซิร์ฟเวอร์จากแผงควบคุมที่ตัวมันเองให้บริการอยู่ กรุณาตั้ง enabled เป็น false ใน plugin.json ของมันแทน","TXT_CODE_PLUGIN_IS_DISABLED":"ปลั๊กอินนี้ถูกปิดใช้งาน หน้า เส้นทาง และ API จะใช้ไม่ได้จนกว่าจะเปิดใช้งานอีกครั้ง","TXT_CODE_PLUGIN_LOAD_FAILED":"โหลดปลั๊กอินนี้ไม่สำเร็จ","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"ไม่สามารถแสดงรายการปลั๊กอินของโหนดนี้ได้","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"ไม่มีโหนดนี้","TXT_CODE_PLUGIN_NODE_OFFLINE":"ไม่ได้เชื่อมต่อ","TXT_CODE_PLUGIN_NODE_SELECT":"เลือกโหนด","TXT_CODE_PLUGIN_NO_CONFIG":"ปลั๊กอินนี้ไม่มีตัวเลือกที่กำหนดค่าได้","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"ยังไม่ได้จัดกลุ่ม","TXT_CODE_PLUGIN_GROUP_ADD":"เพิ่มกลุ่ม","TXT_CODE_PLUGIN_GROUP_EDIT":"แก้ไขกลุ่มปลั๊กอิน","TXT_CODE_PLUGIN_GROUP_RENAME":"เปลี่ยนชื่อกลุ่ม","TXT_CODE_PLUGIN_GROUP_DELETE":"ลบกลุ่ม","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"ลบกลุ่ม {name} หรือไม่","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"กลุ่มและการกำหนดปลั๊กอินจะถูกลบ ปลั๊กอินจะไม่ถูกลบ","TXT_CODE_PLUGIN_GROUP_NAME":"ชื่อกลุ่ม","TXT_CODE_PLUGIN_SCOPE_NODE":"โหนด","TXT_CODE_PLUGIN_SCOPE_PANEL":"แผงควบคุม","TXT_CODE_PLUGIN_SELF_DISABLE":"ตัวจัดการปลั๊กอินปิดใช้งานตัวเองไม่ได้ กรุณาตั้ง enabled เป็น false ใน plugin.json ของมันแทน","TXT_CODE_PLUGIN_STATE_PENDING":"กำลังรอส่วนที่ต้องพึ่งพา","TXT_CODE_PLUGIN_STATE_DISABLED":"ปิดใช้งาน","TXT_CODE_PLUGIN_STATE_LOADING":"กำลังโหลด","TXT_CODE_PLUGIN_STATE_ACTIVE":"กำลังทำงาน","TXT_CODE_PLUGIN_STATE_UNLOADING":"กำลังยกเลิกการโหลด","TXT_CODE_PLUGIN_RESTART_REQUIRED":"รีสตาร์ทบริการเพื่อใช้การเปลี่ยนแปลงนี้","TXT_CODE_PLUGIN_SAVED_PENDING":"บันทึกแล้ว กำลังรอส่วนที่ปลั๊กอินต้องพึ่งพา","TXT_CODE_PLUGIN_FRONTEND_FAILED":"ปลั๊กอินเบราว์เซอร์ล้มเหลว","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"รีเฟรชหน้าเพื่อโหลดรันไทม์เบราว์เซอร์ที่อัปเดต"}');
2213
+
2214
+ /***/ },
2215
+
2216
+ /***/ "./plugins/config/src/i18n/tr_TR.json"
2217
+ (module) {
2218
+
2219
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"Aşağıdaki düğümlerdeki aynı eklenti de devre dışı bırakılsın mı? Dahil edilecek düğümleri seçin.","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"Aşağıdaki düğümlerdeki aynı eklenti de kaldırılsın mı? Dahil edilecek düğümleri seçin.","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"Bu düğümlerdeki eklentiler kontrol edilemedi: {nodes}.","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"Bu düğümlerde eklenti işlemi tamamlanamadı: {nodes}","TXT_CODE_PLUGIN_CONFIG":"Eklenti Yapilandirmasi","TXT_CODE_PLUGIN_CANCEL":"Iptal","TXT_CODE_PLUGIN_DELETE":"Kaldır","TXT_CODE_PLUGIN_DELETE_CONFIRM":"Eklenti dosyaları ve kaydedilmiş yapılandırması kalıcı olarak kaldırılacak.","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"{name} kaldırılsın mı?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"Plugins are installed as npm dependencies; remove them with npm.","TXT_CODE_PLUGIN_DELETED":"Eklenti kaldırıldı","TXT_CODE_PLUGIN_SAVE_SETTINGS":"Ayarları kaydet","TXT_CODE_PLUGIN_SAVE_REMINDER":"Ayarları kaydetmeyi unutmayın!","TXT_CODE_PLUGIN_DISABLE":"Devre dışı bırak","TXT_CODE_PLUGIN_DISABLED":"Eklenti devre dışı bırakıldı","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"Bu eklentinin sağladığı her şey hemen kaldırılır.","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"{name} devre dışı bırakılsın mı?","TXT_CODE_PLUGIN_ENABLE":"Etkinleştir","TXT_CODE_PLUGIN_ENABLED":"Eklenti etkinleştirildi","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"Web sunucusu, kendisinin sunduğu panel üzerinden devre dışı bırakılamaz. Bunun yerine plugin.json dosyasında enabled değerini false yapın.","TXT_CODE_PLUGIN_IS_DISABLED":"Bu eklenti devre dışı. Yeniden etkinleştirilene kadar sayfaları, yolları ve API si kullanılamaz.","TXT_CODE_PLUGIN_LOAD_FAILED":"Bu eklenti yüklenemedi","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"Bu düğümün eklentileri listelenemedi.","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"Böyle bir düğüm yok.","TXT_CODE_PLUGIN_NODE_OFFLINE":"bağlı değil","TXT_CODE_PLUGIN_NODE_SELECT":"Bir düğüm seçin","TXT_CODE_PLUGIN_NO_CONFIG":"Bu eklentinin yapilandirilabilir secenegi yok.","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"Atanmamış","TXT_CODE_PLUGIN_GROUP_ADD":"Grup ekle","TXT_CODE_PLUGIN_GROUP_EDIT":"Eklenti grubunu düzenle","TXT_CODE_PLUGIN_GROUP_RENAME":"Grubu yeniden adlandır","TXT_CODE_PLUGIN_GROUP_DELETE":"Grubu sil","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"{name} grubu silinsin mi?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"Grup ve eklenti atamaları kaldırılacak. Eklentilerin kendisi silinmeyecek.","TXT_CODE_PLUGIN_GROUP_NAME":"Grup adı","TXT_CODE_PLUGIN_SCOPE_NODE":"Düğümler","TXT_CODE_PLUGIN_SCOPE_PANEL":"Panel","TXT_CODE_PLUGIN_SELF_DISABLE":"Eklenti yöneticisi kendisini devre dışı bırakamaz. Bunun yerine plugin.json dosyasında enabled değerini false yapın.","TXT_CODE_PLUGIN_STATE_PENDING":"Bağımlılıklar bekleniyor","TXT_CODE_PLUGIN_STATE_DISABLED":"Devre dışı","TXT_CODE_PLUGIN_STATE_LOADING":"Yükleniyor","TXT_CODE_PLUGIN_STATE_ACTIVE":"Çalışıyor","TXT_CODE_PLUGIN_STATE_UNLOADING":"Kaldırılıyor","TXT_CODE_PLUGIN_RESTART_REQUIRED":"Değişikliği uygulamak için hizmeti yeniden başlatın.","TXT_CODE_PLUGIN_SAVED_PENDING":"Kaydedildi; eklenti bağımlılıkları bekleniyor.","TXT_CODE_PLUGIN_FRONTEND_FAILED":"Tarayıcı eklentisi başarısız oldu","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"Güncellenen tarayıcı çalışma zamanını yüklemek için sayfayı yenileyin."}');
2220
+
2221
+ /***/ },
2222
+
2223
+ /***/ "./plugins/config/src/i18n/zh_CN.json"
2224
+ (module) {
2225
+
2226
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"是否同时禁用以下节点上的对应插件?请勾选需要同步操作的节点。","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"是否同时删除以下节点上的对应插件?请勾选需要同步操作的节点。","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"无法检查以下节点的插件:{nodes}。","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"以下节点上的插件操作未完成:{nodes}","TXT_CODE_PLUGIN_CONFIG":"插件配置","TXT_CODE_PLUGIN_CANCEL":"取消","TXT_CODE_PLUGIN_DELETE":"删除插件","TXT_CODE_PLUGIN_DELETE_CONFIRM":"插件文件和已保存的配置将被永久删除。","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"确定删除 {name}?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"插件以 npm 依赖形式安装,请使用 npm 卸载。","TXT_CODE_PLUGIN_DELETED":"插件已删除","TXT_CODE_PLUGIN_SAVE_SETTINGS":"保存配置","TXT_CODE_PLUGIN_SAVE_REMINDER":"记得保存配置!","TXT_CODE_PLUGIN_DISABLE":"禁用","TXT_CODE_PLUGIN_DISABLED":"插件已禁用","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"该插件提供的所有组件都会被立即移除。","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"确定禁用 {name}?","TXT_CODE_PLUGIN_ENABLE":"启用","TXT_CODE_PLUGIN_ENABLED":"插件已启用","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"Web 服务器无法从它自己提供的页面上禁用,请改为在其 plugin.json 中把 enabled 设为 false。","TXT_CODE_PLUGIN_IS_DISABLED":"此插件已禁用,重新启用前其页面、路由与接口均不可用。","TXT_CODE_PLUGIN_LOAD_FAILED":"此插件加载失败","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"无法读取该节点的插件列表。","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"该节点不存在。","TXT_CODE_PLUGIN_NODE_OFFLINE":"未连接","TXT_CODE_PLUGIN_NODE_SELECT":"选择节点","TXT_CODE_PLUGIN_NO_CONFIG":"此插件没有可配置项","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"未分组","TXT_CODE_PLUGIN_GROUP_ADD":"添加分组","TXT_CODE_PLUGIN_GROUP_EDIT":"编辑插件分组","TXT_CODE_PLUGIN_GROUP_RENAME":"重命名分组","TXT_CODE_PLUGIN_GROUP_DELETE":"删除分组","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"删除分组“{name}”?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"将删除该分组及其插件归属,插件本身不会被删除。","TXT_CODE_PLUGIN_GROUP_NAME":"分组名称","TXT_CODE_PLUGIN_SCOPE_NODE":"节点","TXT_CODE_PLUGIN_SCOPE_PANEL":"面板","TXT_CODE_PLUGIN_SELF_DISABLE":"插件管理自身无法被禁用,请改为在其 plugin.json 中把 enabled 设为 false。","TXT_CODE_PLUGIN_STATE_PENDING":"等待依赖","TXT_CODE_PLUGIN_STATE_DISABLED":"已禁用","TXT_CODE_PLUGIN_STATE_LOADING":"加载中","TXT_CODE_PLUGIN_STATE_ACTIVE":"运行中","TXT_CODE_PLUGIN_STATE_UNLOADING":"卸载中","TXT_CODE_PLUGIN_RESTART_REQUIRED":"需要重启服务才能应用此更改。","TXT_CODE_PLUGIN_SAVED_PENDING":"已保存,正在等待插件依赖。","TXT_CODE_PLUGIN_FRONTEND_FAILED":"浏览器插件加载失败","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"需要刷新页面才能加载更新后的浏览器运行时。"}');
2227
+
2228
+ /***/ },
2229
+
2230
+ /***/ "./plugins/config/src/i18n/zh_TW.json"
2231
+ (module) {
2232
+
2233
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_PLUGIN_NODE_DISABLE_CONFIRM":"是否同時停用以下節點上的對應外掛?請勾選需要同步操作的節點。","TXT_CODE_PLUGIN_NODE_DELETE_CONFIRM":"是否同時刪除以下節點上的對應外掛?請勾選需要同步操作的節點。","TXT_CODE_PLUGIN_NODE_CHECK_FAILED":"無法檢查以下節點的外掛:{nodes}。","TXT_CODE_PLUGIN_NODE_ACTION_FAILED":"以下節點上的外掛操作未完成:{nodes}","TXT_CODE_PLUGIN_CONFIG":"插件設定","TXT_CODE_PLUGIN_CANCEL":"取消","TXT_CODE_PLUGIN_DELETE":"刪除外掛","TXT_CODE_PLUGIN_DELETE_CONFIRM":"外掛檔案與已儲存的設定將會永久刪除。","TXT_CODE_PLUGIN_DELETE_CONFIRM_TITLE":"確定刪除 {name}?","TXT_CODE_PLUGIN_DELETE_UNAVAILABLE":"外掛以 npm 相依形式安裝,請使用 npm 解除安裝。","TXT_CODE_PLUGIN_DELETED":"外掛已刪除","TXT_CODE_PLUGIN_SAVE_SETTINGS":"儲存設定","TXT_CODE_PLUGIN_SAVE_REMINDER":"記得儲存設定!","TXT_CODE_PLUGIN_DISABLE":"停用","TXT_CODE_PLUGIN_DISABLED":"外掛已停用","TXT_CODE_PLUGIN_DISABLE_CONFIRM":"該外掛提供的所有元件都會被立即移除。","TXT_CODE_PLUGIN_DISABLE_CONFIRM_TITLE":"確定停用 {name}?","TXT_CODE_PLUGIN_ENABLE":"啟用","TXT_CODE_PLUGIN_ENABLED":"外掛已啟用","TXT_CODE_PLUGIN_ESSENTIAL_DISABLE":"Web 伺服器無法從它自己提供的頁面上停用,請改為在其 plugin.json 中把 enabled 設為 false。","TXT_CODE_PLUGIN_IS_DISABLED":"此外掛已停用,重新啟用前其頁面、路由與介面皆不可用。","TXT_CODE_PLUGIN_LOAD_FAILED":"此外掛載入失敗","TXT_CODE_PLUGIN_NODE_LIST_FAILED":"無法讀取該節點的外掛清單。","TXT_CODE_PLUGIN_NODE_NOT_FOUND":"該節點不存在。","TXT_CODE_PLUGIN_NODE_OFFLINE":"未連線","TXT_CODE_PLUGIN_NODE_SELECT":"選擇節點","TXT_CODE_PLUGIN_NO_CONFIG":"此插件沒有可設定項目","TXT_CODE_PLUGIN_GROUP_UNASSIGNED":"未分組","TXT_CODE_PLUGIN_GROUP_ADD":"新增分組","TXT_CODE_PLUGIN_GROUP_EDIT":"編輯外掛分組","TXT_CODE_PLUGIN_GROUP_RENAME":"重新命名分組","TXT_CODE_PLUGIN_GROUP_DELETE":"刪除分組","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM_TITLE":"刪除分組「{name}」?","TXT_CODE_PLUGIN_GROUP_DELETE_CONFIRM":"將刪除該分組及其插件歸屬,插件本身不會被刪除。","TXT_CODE_PLUGIN_GROUP_NAME":"分組名稱","TXT_CODE_PLUGIN_SCOPE_NODE":"節點","TXT_CODE_PLUGIN_SCOPE_PANEL":"面板","TXT_CODE_PLUGIN_SELF_DISABLE":"外掛管理本身無法被停用,請改為在其 plugin.json 中把 enabled 設為 false。","TXT_CODE_PLUGIN_STATE_PENDING":"等待依賴","TXT_CODE_PLUGIN_STATE_DISABLED":"已停用","TXT_CODE_PLUGIN_STATE_LOADING":"載入中","TXT_CODE_PLUGIN_STATE_ACTIVE":"執行中","TXT_CODE_PLUGIN_STATE_UNLOADING":"卸載中","TXT_CODE_PLUGIN_RESTART_REQUIRED":"需要重新啟動服務才能套用此變更。","TXT_CODE_PLUGIN_SAVED_PENDING":"已儲存,正在等待外掛依賴。","TXT_CODE_PLUGIN_FRONTEND_FAILED":"瀏覽器外掛載入失敗","TXT_CODE_PLUGIN_REFRESH_REQUIRED":"需要重新整理頁面才能載入更新後的瀏覽器執行階段。"}');
2234
+
2235
+ /***/ }
2236
+
2237
+ /******/ });
2238
+ /************************************************************************/
2239
+ /******/ // The module cache
2240
+ /******/ var __webpack_module_cache__ = {};
2241
+ /******/
2242
+ /******/ // The require function
2243
+ /******/ function __webpack_require__(moduleId) {
2244
+ /******/ // Check if module is in cache
2245
+ /******/ var cachedModule = __webpack_module_cache__[moduleId];
2246
+ /******/ if (cachedModule !== undefined) {
2247
+ /******/ return cachedModule.exports;
2248
+ /******/ }
2249
+ /******/ // Create a new module (and put it into the cache)
2250
+ /******/ var module = __webpack_module_cache__[moduleId] = {
2251
+ /******/ // no module.id needed
2252
+ /******/ // no module.loaded needed
2253
+ /******/ exports: {}
2254
+ /******/ };
2255
+ /******/
2256
+ /******/ // Execute the module function
2257
+ /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
2258
+ /******/
2259
+ /******/ // Return the exports of the module
2260
+ /******/ return module.exports;
2261
+ /******/ }
2262
+ /******/
2263
+ /************************************************************************/
2264
+ var __webpack_exports__ = {};
2265
+ // This entry needs to be wrapped in an IIFE because it uses a non-standard name for the exports (exports).
2266
+ (() => {
2267
+ var exports = __webpack_exports__;
2268
+
2269
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2270
+ exports.inject = void 0;
2271
+ exports.apply = apply;
2272
+ const i18n_1 = __webpack_require__("./plugins/config/src/i18n/index.ts");
2273
+ const settings_1 = __webpack_require__("./plugins/config/src/backend/settings.ts");
2274
+ // Panel side of the plugin manager page. The container owns the mechanism —
2275
+ // `ctx.plugins` lists what is installed and persists the enable switch — and this
2276
+ // plugin only exposes it over HTTP, because it owns the page that drives it.
2277
+ //
2278
+ // The same page administers each connected node's plugins. That half is a thin
2279
+ // proxy onto the daemon-side `config` plugin: the daemon decides what it will
2280
+ // switch off, and this plugin only carries the question there and the answer
2281
+ // back. It lives inside `ctx.inject(["remote"], ...)` so that a panel without
2282
+ // `plugins/node` still manages its own plugins.
2283
+ /** Turning this plugin off would remove the page the request came from. */
2284
+ const SELF = "config";
2285
+ /**
2286
+ * Turning an essential plugin off would remove the interface or connection
2287
+ * that is needed to turn it back on.
2288
+ */
2289
+ const ESSENTIAL = new Set(["console", "i18n", "storage", "runtime", "server"]);
2290
+ const PLUGIN_GROUPS_CATEGORY = "PluginGroups";
2291
+ class StoredPluginGroups {
2292
+ constructor() {
2293
+ this.groups = [];
2294
+ }
2295
+ }
2296
+ function normalizePluginGroups(input) {
2297
+ if (!Array.isArray(input))
2298
+ throw new Error("Plugin groups must be an array.");
2299
+ if (input.length > 100)
2300
+ throw new Error("Too many plugin groups.");
2301
+ return input.map((value) => {
2302
+ var _a, _b;
2303
+ if (!value || typeof value !== "object")
2304
+ throw new Error("Invalid plugin group.");
2305
+ const group = value;
2306
+ const id = String((_a = group.id) !== null && _a !== void 0 ? _a : "").trim();
2307
+ const name = String((_b = group.name) !== null && _b !== void 0 ? _b : "").trim();
2308
+ if (!id || id.length > 128 || !name || name.length > 200) {
2309
+ throw new Error("Invalid plugin group.");
2310
+ }
2311
+ if (!Array.isArray(group.pluginIds) ||
2312
+ group.pluginIds.length > 2000 ||
2313
+ group.pluginIds.some((pluginId) => typeof pluginId !== "string")) {
2314
+ throw new Error("Invalid plugin group plugins.");
2315
+ }
2316
+ return {
2317
+ id,
2318
+ name,
2319
+ pluginIds: [...new Set(group.pluginIds.map((pluginId) => pluginId.trim()).filter(Boolean))]
2320
+ };
2321
+ });
2322
+ }
2323
+ exports.inject = [
2324
+ "koa",
2325
+ "i18n",
2326
+ "middleware",
2327
+ "roles",
2328
+ "plugins",
2329
+ "storage",
2330
+ "settings",
2331
+ "identity",
2332
+ "operations"
2333
+ ];
2334
+ function apply(ctx) {
2335
+ ctx.i18n.define(i18n_1.localeMessages);
2336
+ ctx.plugin(settings_1.SettingsFormService);
2337
+ const settingsForm = ctx.get("settingsForm");
2338
+ if (!settingsForm)
2339
+ throw new Error("Panel settings form service is unavailable.");
2340
+ const router = ctx.koa.router("/api/plugins");
2341
+ const requireAdmin = ctx.middleware.permission({ level: ctx.roles.ADMIN });
2342
+ // Remaining system settings are administered by this configuration plugin.
2343
+ // Plugin-owned settings are declared by their own backend and handled by the
2344
+ // generic routes below, so the core no longer mounts a settings router.
2345
+ const settingsRouter = ctx.koa.router("/api/overview");
2346
+ settingsRouter.get("/setting", requireAdmin, async (requestCtx) => {
2347
+ requestCtx.body = ctx.settings.config;
2348
+ });
2349
+ settingsRouter.put("/setting", requireAdmin, async (requestCtx) => {
2350
+ var _a;
2351
+ const config = ((_a = requestCtx.request.body) !== null && _a !== void 0 ? _a : {});
2352
+ const current = ctx.settings.config;
2353
+ if (!config || !current)
2354
+ throw new Error(ctx.i18n.$t("TXT_CODE_e4d6cc20"));
2355
+ if (config.gzip != null)
2356
+ current.gzip = config.gzip;
2357
+ if (config.maxCompress != null)
2358
+ current.maxCompress = config.maxCompress;
2359
+ if (config.maxDownload != null)
2360
+ current.maxDownload = config.maxDownload;
2361
+ if (config.zipType != null)
2362
+ current.zipType = config.zipType;
2363
+ if (config.forwardType != null)
2364
+ current.forwardType = Number(config.forwardType);
2365
+ if (config.dataPort != null)
2366
+ current.dataPort = Number(config.dataPort);
2367
+ ctx.operations.log("system_config_change", {
2368
+ operator_ip: requestCtx.ip,
2369
+ operator_name: ctx.identity.of(requestCtx).userName
2370
+ });
2371
+ await ctx.settings.save();
2372
+ requestCtx.body = "OK";
2373
+ });
2374
+ // Everything installed, disabled plugins included: the page needs to list one
2375
+ // to be able to enable it again.
2376
+ router.get("/", requireAdmin, async (requestCtx) => {
2377
+ const declared = new Set(settingsForm.declared());
2378
+ requestCtx.body = ctx.plugins.inventory().map((record) => ({
2379
+ ...record,
2380
+ // So the page can say "no configurable options" without a round trip.
2381
+ hasSettings: declared.has(record.id)
2382
+ }));
2383
+ });
2384
+ // One plugin's form and its current values, as its own backend describes them.
2385
+ // `null` when it declared nothing.
2386
+ router.get("/settings", requireAdmin, async (requestCtx) => {
2387
+ var _a;
2388
+ requestCtx.body = await settingsForm.read(String((_a = requestCtx.request.query.id) !== null && _a !== void 0 ? _a : ""));
2389
+ });
2390
+ router.put("/settings", requireAdmin, ctx.middleware.validator({ query: { id: String } }), async (requestCtx) => {
2391
+ var _a;
2392
+ const id = String(requestCtx.request.query.id);
2393
+ // The plugin's own `write()` validates: this route knows nothing about
2394
+ // what any particular plugin's values mean.
2395
+ requestCtx.body = await settingsForm.write(id, ((_a = requestCtx.request.body) !== null && _a !== void 0 ? _a : {}));
2396
+ });
2397
+ const groupsStorageId = (requestCtx) => String(ctx.identity.of(requestCtx).uuid || "anonymous");
2398
+ router.get("/groups", requireAdmin, async (requestCtx) => {
2399
+ var _a;
2400
+ const stored = (await ctx.storage.getStorage().load(PLUGIN_GROUPS_CATEGORY, StoredPluginGroups, groupsStorageId(requestCtx)));
2401
+ requestCtx.body = (_a = stored === null || stored === void 0 ? void 0 : stored.groups) !== null && _a !== void 0 ? _a : [];
2402
+ });
2403
+ router.put("/groups", requireAdmin, async (requestCtx) => {
2404
+ var _a;
2405
+ const groups = normalizePluginGroups((_a = requestCtx.request.body) === null || _a === void 0 ? void 0 : _a.groups);
2406
+ await ctx.storage.getStorage().store(PLUGIN_GROUPS_CATEGORY, groupsStorageId(requestCtx), {
2407
+ groups
2408
+ });
2409
+ requestCtx.body = groups;
2410
+ });
2411
+ router.put("/enabled", requireAdmin, ctx.middleware.validator({ body: { id: String, enabled: Boolean } }), async (requestCtx) => {
2412
+ const id = String(requestCtx.request.body.id);
2413
+ const enabled = Boolean(requestCtx.request.body.enabled);
2414
+ // Thrown rather than answered: the panel's response protocol turns an
2415
+ // Error into the standard envelope, which is what the page reports.
2416
+ if (id === SELF && !enabled)
2417
+ throw new Error(ctx.i18n.$t("TXT_CODE_PLUGIN_SELF_DISABLE"));
2418
+ if (ESSENTIAL.has(id) && !enabled)
2419
+ throw new Error(ctx.i18n.$t("TXT_CODE_PLUGIN_ESSENTIAL_DISABLE"));
2420
+ requestCtx.body = await ctx.plugins.setEnabled(id, enabled);
2421
+ });
2422
+ router.delete("/", requireAdmin, ctx.middleware.validator({ query: { id: String } }), async (requestCtx) => {
2423
+ await ctx.plugins.remove(String(requestCtx.request.query.id));
2424
+ requestCtx.body = { removed: true };
2425
+ });
2426
+ // The node half. `remote` is resolved here rather than injected at the top, so
2427
+ // removing `plugins/node` takes the node routes away and leaves the rest of the
2428
+ // page working.
2429
+ ctx.inject(["remote"], (scoped) => {
2430
+ const nodeRouter = scoped.koa.router("/api/plugins/node");
2431
+ const RemoteRequest = scoped.remote.Request;
2432
+ const nodeOf = (requestCtx) => {
2433
+ var _a;
2434
+ const daemonId = String((_a = requestCtx.request.query.daemonId) !== null && _a !== void 0 ? _a : "");
2435
+ const node = scoped.remote.services.getInstance(daemonId);
2436
+ if (!node)
2437
+ throw new Error(ctx.i18n.$t("TXT_CODE_PLUGIN_NODE_NOT_FOUND"));
2438
+ return node;
2439
+ };
2440
+ // Which nodes there are to administer. Unavailable ones are listed too, so
2441
+ // the page can say why it cannot reach one instead of hiding it.
2442
+ nodeRouter.get("/list", requireAdmin, async (requestCtx) => {
2443
+ requestCtx.body = Array.from(scoped.remote.services.services.entries()).map(([uuid, node]) => ({
2444
+ uuid,
2445
+ remarks: node.config.remarks,
2446
+ ip: node.config.ip,
2447
+ port: node.config.port,
2448
+ available: node.available
2449
+ }));
2450
+ });
2451
+ // Straight through to the daemon's own inventory.
2452
+ nodeRouter.get("/plugins", requireAdmin, async (requestCtx) => {
2453
+ requestCtx.body = await new RemoteRequest(nodeOf(requestCtx)).request("plugin/list");
2454
+ });
2455
+ nodeRouter.put("/enabled", requireAdmin, ctx.middleware.validator({
2456
+ query: { daemonId: String },
2457
+ body: { id: String, enabled: Boolean }
2458
+ }), async (requestCtx) => {
2459
+ const node = nodeOf(requestCtx);
2460
+ const id = String(requestCtx.request.body.id);
2461
+ const enabled = Boolean(requestCtx.request.body.enabled);
2462
+ // No id list is checked here: which of its plugins a daemon refuses to
2463
+ // switch off is the daemon's own business, and its refusal arrives as a
2464
+ // protocol error that the response protocol turns into this envelope.
2465
+ const record = await new RemoteRequest(node).request("plugin/enabled", { id, enabled });
2466
+ // A daemon binds its protocol events onto each socket as that socket
2467
+ // connects (`service/router.ts`), so a handler that has just appeared —
2468
+ // or just gone — is invisible to the connection we are holding. The node
2469
+ // is reconnected here, which is the only thing that makes the change
2470
+ // actually reachable; the daemon has already answered by now.
2471
+ node.refreshReconnect();
2472
+ requestCtx.body = record;
2473
+ });
2474
+ nodeRouter.delete("/", requireAdmin, ctx.middleware.validator({ query: { daemonId: String, id: String } }), async (requestCtx) => {
2475
+ const node = nodeOf(requestCtx);
2476
+ // Removing unloads the plugin's scope before the files go, which can
2477
+ // outlast the default request window; the market uninstall waits 30s too.
2478
+ await new RemoteRequest(node).request("plugin/remove", { id: String(requestCtx.request.query.id) }, 30000);
2479
+ node.refreshReconnect();
2480
+ requestCtx.body = { removed: true };
2481
+ });
2482
+ // A daemon plugin's configuration, described by the plugin itself and
2483
+ // rendered by the same generic form. Nothing about the form lives here.
2484
+ nodeRouter.get("/settings", requireAdmin, ctx.middleware.validator({ query: { daemonId: String, id: String } }), async (requestCtx) => {
2485
+ requestCtx.body = await new RemoteRequest(nodeOf(requestCtx)).request("plugin/config", {
2486
+ id: String(requestCtx.request.query.id)
2487
+ });
2488
+ });
2489
+ nodeRouter.put("/settings", requireAdmin, ctx.middleware.validator({ query: { daemonId: String, id: String } }), async (requestCtx) => {
2490
+ var _a;
2491
+ const request = new RemoteRequest(nodeOf(requestCtx));
2492
+ requestCtx.body = await request.request("plugin/config/write", {
2493
+ id: String(requestCtx.request.query.id),
2494
+ values: ((_a = requestCtx.request.body) !== null && _a !== void 0 ? _a : {})
2495
+ });
2496
+ // Refresh node-owned connection metadata before subsequent file/terminal requests.
2497
+ // A refresh failure must not turn a successfully saved setting into an error.
2498
+ try {
2499
+ await request.request("info/overview");
2500
+ }
2501
+ catch (error) {
2502
+ ctx.logger.warn("Failed to refresh node information after saving plugin settings:", error);
2503
+ }
2504
+ });
2505
+ nodeRouter.get("/groups", requireAdmin, ctx.middleware.validator({ query: { daemonId: String } }), async (requestCtx) => {
2506
+ requestCtx.body = await new RemoteRequest(nodeOf(requestCtx)).request("plugin/groups");
2507
+ });
2508
+ nodeRouter.put("/groups", requireAdmin, ctx.middleware.validator({ query: { daemonId: String } }), async (requestCtx) => {
2509
+ var _a;
2510
+ const groups = (_a = requestCtx.request.body) === null || _a === void 0 ? void 0 : _a.groups;
2511
+ requestCtx.body = await new RemoteRequest(nodeOf(requestCtx)).request("plugin/groups/write", { groups });
2512
+ });
2513
+ });
2514
+ }
2515
+
2516
+ })();
2517
+
2518
+ module.exports = __webpack_exports__;
2519
+ /******/ })()
2520
+ ;