@elementspanel/epanel-plugin-file 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,3885 @@
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 map = new Map();
70
+ static set(k, v) {
71
+ GlobalVariable.map.set(k, v);
72
+ }
73
+ static get(k, def) {
74
+ if (GlobalVariable.map.has(k)) {
75
+ return GlobalVariable.map.get(k);
76
+ }
77
+ else {
78
+ return def;
79
+ }
80
+ }
81
+ static del(k) {
82
+ return GlobalVariable.map.delete(k);
83
+ }
84
+ }
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
+ listenMap = new Map();
177
+ disconnectHandlers = new Map();
178
+ requestForward(socket, instanceUuid) {
179
+ const sockets = this.listenMap.get(instanceUuid) ?? [];
180
+ if (sockets.some((listener) => listener.id === socket.id))
181
+ return;
182
+ sockets.push(socket);
183
+ this.listenMap.set(instanceUuid, sockets);
184
+ if (!this.disconnectHandlers.has(socket)) {
185
+ const disconnect = () => {
186
+ for (const uuid of this.listenMap.keys())
187
+ this.cannelForward(socket, uuid);
188
+ };
189
+ this.disconnectHandlers.set(socket, disconnect);
190
+ socket.once("disconnect", disconnect);
191
+ }
192
+ }
193
+ cannelForward(socket, instanceUuid) {
194
+ const remaining = this.listenMap
195
+ .get(instanceUuid)
196
+ ?.filter((listener) => listener.id !== socket.id);
197
+ if (remaining?.length)
198
+ this.listenMap.set(instanceUuid, remaining);
199
+ else
200
+ this.listenMap.delete(instanceUuid);
201
+ if (![...this.listenMap.values()].some((sockets) => sockets.includes(socket))) {
202
+ const disconnect = this.disconnectHandlers.get(socket);
203
+ if (disconnect)
204
+ socket.off("disconnect", disconnect);
205
+ this.disconnectHandlers.delete(socket);
206
+ }
207
+ }
208
+ forward(instanceUuid, data) {
209
+ this.forwardViaCallback(instanceUuid, (socket) => socket.emit("instance/stdout", data));
210
+ }
211
+ forwardViaCallback(instanceUuid, callback) {
212
+ for (const socket of this.listenMap.get(instanceUuid) ?? []) {
213
+ if (socket.connected)
214
+ callback(socket);
215
+ else
216
+ this.cannelForward(socket, instanceUuid);
217
+ }
218
+ }
219
+ hasListenInstance(instanceUuid) {
220
+ return this.listenMap.get(instanceUuid)?.some((socket) => socket.connected) ?? false;
221
+ }
222
+ }
223
+ exports["default"] = InstanceStreamListener;
224
+
225
+
226
+ /***/ },
227
+
228
+ /***/ "../common/src/mcping.ts"
229
+ (__unused_webpack_module, exports, __webpack_require__) {
230
+
231
+
232
+ var __importDefault = (this && this.__importDefault) || function (mod) {
233
+ return (mod && mod.__esModule) ? mod : { "default": mod };
234
+ };
235
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
236
+ const net_1 = __importDefault(__webpack_require__("net"));
237
+ class PingMinecraftServer {
238
+ port;
239
+ host;
240
+ status;
241
+ client;
242
+ pending;
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
+ if (!values || typeof values !== "object" || Array.isArray(values))
476
+ throw new Error("Invalid plugin settings.");
477
+ const input = values;
478
+ for (const field of fields) {
479
+ if (!field.key || field.type === "link")
480
+ continue;
481
+ const value = input[field.key];
482
+ if (value === undefined || value === null) {
483
+ if (field.required)
484
+ throw new Error(`${field.title || field.key}: required`);
485
+ continue;
486
+ }
487
+ if (field.type === "list") {
488
+ if (!Array.isArray(value) || value.length > (field.maxItems ?? 100))
489
+ throw new Error(`${field.title || field.key}: invalid list`);
490
+ for (const item of value)
491
+ validatePluginSettings(field.fields || [], item);
492
+ continue;
493
+ }
494
+ const valid = field.type === "number"
495
+ ? typeof value === "number" &&
496
+ Number.isFinite(value) &&
497
+ (field.min === undefined || value >= field.min) &&
498
+ (field.max === undefined || value <= field.max)
499
+ : field.type === "boolean"
500
+ ? typeof value === "boolean"
501
+ : field.type === "select"
502
+ ? field.options?.some((option) => option.value === value)
503
+ : typeof value === "string";
504
+ if (!valid)
505
+ throw new Error(`${field.title || field.key}: invalid value`);
506
+ }
507
+ }
508
+
509
+
510
+ /***/ },
511
+
512
+ /***/ "../common/src/plugin_lifecycle.ts"
513
+ (__unused_webpack_module, exports) {
514
+
515
+
516
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
517
+ exports.trackPluginDisposal = trackPluginDisposal;
518
+ /** Cordis 3 starts async disposers without awaiting them. Track them per host. */
519
+ function trackPluginDisposal(ctx) {
520
+ const pending = new Set();
521
+ const failures = [];
522
+ const tracked = new WeakSet();
523
+ const scopes = new WeakSet();
524
+ const observe = (scope) => {
525
+ if (scopes.has(scope))
526
+ return;
527
+ scopes.add(scope);
528
+ const reset = scope.reset;
529
+ scope.reset = function () {
530
+ this.disposables = this.disposables.map((dispose) => {
531
+ if (tracked.has(dispose))
532
+ return dispose;
533
+ const wrapper = (...args) => {
534
+ let result;
535
+ try {
536
+ result = dispose(...args);
537
+ }
538
+ catch (error) {
539
+ failures.push(error);
540
+ throw error;
541
+ }
542
+ if (result && typeof result.then === "function") {
543
+ const task = Promise.resolve(result)
544
+ .catch((error) => {
545
+ failures.push(error);
546
+ })
547
+ .finally(() => pending.delete(task));
548
+ pending.add(task);
549
+ }
550
+ return result;
551
+ };
552
+ // Cordis marks persistent disposers with a symbol; preserve its semantics.
553
+ for (const key of Object.getOwnPropertySymbols(dispose))
554
+ Object.defineProperty(wrapper, key, Object.getOwnPropertyDescriptor(dispose, key));
555
+ tracked.add(wrapper);
556
+ return wrapper;
557
+ });
558
+ return reset.call(this);
559
+ };
560
+ };
561
+ ctx.on("internal/runtime", observe);
562
+ ctx.on("internal/fork", observe);
563
+ return async () => {
564
+ do {
565
+ await ctx.events.flush();
566
+ await Promise.all([...pending]);
567
+ } while (pending.size);
568
+ if (failures.length) {
569
+ const errors = failures.splice(0);
570
+ throw new Error(`Plugin cleanup failed: ${errors.map(String).join("; ")}`);
571
+ }
572
+ };
573
+ }
574
+
575
+
576
+ /***/ },
577
+
578
+ /***/ "../common/src/plugin_manifest.ts"
579
+ (__unused_webpack_module, exports, __webpack_require__) {
580
+
581
+
582
+ var __importDefault = (this && this.__importDefault) || function (mod) {
583
+ return (mod && mod.__esModule) ? mod : { "default": mod };
584
+ };
585
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
586
+ exports.createFrontendPluginMetadata = createFrontendPluginMetadata;
587
+ exports.readPluginManifest = readPluginManifest;
588
+ exports.resolvePluginEntry = resolvePluginEntry;
589
+ exports.discoverPlugins = discoverPlugins;
590
+ exports.discoverPluginsFromRoots = discoverPluginsFromRoots;
591
+ exports.sortPlugins = sortPlugins;
592
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
593
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
594
+ function stringArray(value) {
595
+ if (!Array.isArray(value))
596
+ return undefined;
597
+ const result = value.filter((item) => typeof item === "string" && !!item.trim());
598
+ return result.length ? [...new Set(result.map((item) => item.trim()))] : undefined;
599
+ }
600
+ /**
601
+ * Redacts a full plugin manifest to the fields a browser is allowed to see.
602
+ * Backend `config` may contain credentials, so only `frontendConfig` crosses
603
+ * this boundary.
604
+ */
605
+ function createFrontendPluginMetadata(manifest, extras = {}) {
606
+ const frontendInject = stringArray(manifest.frontendInject);
607
+ return {
608
+ id: manifest.id,
609
+ ...(manifest.version === undefined ? {} : { version: manifest.version }),
610
+ ...(manifest.description === undefined ? {} : { description: manifest.description }),
611
+ ...(manifest.priority === undefined ? {} : { priority: manifest.priority }),
612
+ ...(manifest.elements === undefined ? {} : { elements: manifest.elements }),
613
+ ...(frontendInject === undefined ? {} : { frontendInject }),
614
+ ...(manifest.frontendImmediate === undefined
615
+ ? {}
616
+ : { frontendImmediate: Boolean(manifest.frontendImmediate) }),
617
+ ...(manifest.frontendRequired === undefined
618
+ ? {}
619
+ : { frontendRequired: Boolean(manifest.frontendRequired) }),
620
+ ...(manifest.frontendConfig === undefined ? {} : { config: manifest.frontendConfig }),
621
+ ...(extras.restartRequired === undefined ? {} : extras)
622
+ };
623
+ }
624
+ const MANIFEST_FILES = ["plugin.json", "manifest.json", "package.json"];
625
+ /** Reads the manifest of one plugin directory, or null if it has none. */
626
+ function readPluginManifest(directory, onWarning, fallbackId = node_path_1.default.basename(directory)) {
627
+ for (const file of MANIFEST_FILES) {
628
+ const filePath = node_path_1.default.join(directory, file);
629
+ if (!node_fs_1.default.existsSync(filePath))
630
+ continue;
631
+ try {
632
+ const value = JSON.parse(node_fs_1.default.readFileSync(filePath, "utf8"));
633
+ if (!value || typeof value !== "object" || Array.isArray(value))
634
+ return null;
635
+ const id = typeof value.id === "string" ? value.id : fallbackId;
636
+ if (!id.trim())
637
+ return null;
638
+ return { ...value, id: id.trim() };
639
+ }
640
+ catch (error) {
641
+ onWarning?.(`Failed to read plugin manifest: ${filePath}`, error);
642
+ return null;
643
+ }
644
+ }
645
+ return null;
646
+ }
647
+ /**
648
+ * Resolves one plugin's entry module. Returns null when the manifest names an
649
+ * entry that does not exist, or when none of the fallback candidates is present.
650
+ * Paths that would escape the plugin directory are rejected.
651
+ */
652
+ function resolvePluginEntry(directory, manifest, options) {
653
+ const configured = options.entryFields
654
+ .map((field) => manifest[field])
655
+ .find((entry) => typeof entry === "string" && entry.length > 0);
656
+ const candidates = configured ? [configured] : options.entryCandidates ?? [];
657
+ const root = node_path_1.default.resolve(directory);
658
+ for (const candidate of candidates) {
659
+ const entry = node_path_1.default.resolve(directory, candidate);
660
+ if (entry.startsWith(`${root}${node_path_1.default.sep}`) && node_fs_1.default.existsSync(entry))
661
+ return entry;
662
+ }
663
+ return null;
664
+ }
665
+ function discoverPluginDirectory(directory, options, folder = node_path_1.default.basename(directory)) {
666
+ // Npm packages expose a side directory; its name is not the public plugin id.
667
+ const manifest = readPluginManifest(directory, options.onWarning, folder);
668
+ if (!manifest)
669
+ return null;
670
+ if (manifest.enabled === false && !options.includeDisabled)
671
+ return null;
672
+ const entry = resolvePluginEntry(directory, manifest, options);
673
+ if (!entry && options.entryFields.some((field) => typeof manifest[field] === "string")) {
674
+ options.onWarning?.(`Plugin "${manifest.id}" has no valid entry module.`);
675
+ return null;
676
+ }
677
+ return { manifest, directory, folder, entry: entry ?? undefined };
678
+ }
679
+ /**
680
+ * Lists the usable plugins below `root`, in load order: ascending `priority`,
681
+ * then by id so the order is stable. Duplicate ids are dropped, and disabled
682
+ * ones too unless `includeDisabled` says otherwise. A plugin whose manifest names an entry that cannot be resolved is
683
+ * dropped too; one that names none keeps `entry` undefined, because a plugin may
684
+ * legitimately contribute to only one side of the panel.
685
+ */
686
+ function discoverPlugins(root, options) {
687
+ if (!node_fs_1.default.existsSync(root))
688
+ return [];
689
+ const plugins = [];
690
+ const seenIds = new Set();
691
+ for (const item of node_fs_1.default.readdirSync(root, { withFileTypes: true })) {
692
+ if (!item.isDirectory())
693
+ continue;
694
+ const directory = node_path_1.default.join(root, item.name);
695
+ const plugin = discoverPluginDirectory(directory, options, item.name);
696
+ if (!plugin || seenIds.has(plugin.manifest.id)) {
697
+ if (plugin && seenIds.has(plugin.manifest.id)) {
698
+ options.onWarning?.(`Ignoring duplicate plugin id: ${plugin.manifest.id}`);
699
+ }
700
+ continue;
701
+ }
702
+ seenIds.add(plugin.manifest.id);
703
+ plugins.push(plugin);
704
+ }
705
+ return sortPlugins(plugins);
706
+ }
707
+ /**
708
+ * Discovers plugins from several roots while keeping the first root's plugin
709
+ * when ids collide. The built-in root is intentionally passed first by the
710
+ * panel and daemon loaders, so an installed market plugin cannot shadow a
711
+ * built-in npm dependency. A root can also force an installed project plugin
712
+ * into the disabled state; the user-owned override layer may enable it later.
713
+ */
714
+ function discoverPluginsFromRoots(roots, options) {
715
+ const discovered = [];
716
+ const seenIds = new Set();
717
+ for (const root of roots) {
718
+ const isDirectPlugin = MANIFEST_FILES.some((file) => node_fs_1.default.existsSync(node_path_1.default.join(root.directory, file)));
719
+ const plugins = isDirectPlugin
720
+ ? [discoverPluginDirectory(root.directory, options, root.folder)]
721
+ : discoverPlugins(root.directory, options);
722
+ for (const plugin of plugins) {
723
+ if (!plugin)
724
+ continue;
725
+ const manifest = root.defaultEnabled === false ? { ...plugin.manifest, enabled: false } : plugin.manifest;
726
+ if (manifest.enabled === false && !options.includeDisabled)
727
+ continue;
728
+ if (seenIds.has(plugin.manifest.id)) {
729
+ options.onWarning?.(`Ignoring duplicate plugin id: ${plugin.manifest.id}`);
730
+ continue;
731
+ }
732
+ seenIds.add(plugin.manifest.id);
733
+ discovered.push({
734
+ ...plugin,
735
+ manifest,
736
+ ...(root.folder ? { folder: root.folder } : {})
737
+ });
738
+ }
739
+ }
740
+ return sortPlugins(discovered);
741
+ }
742
+ /** Load order: ascending `priority`, then by id so it never depends on the filesystem. */
743
+ function sortPlugins(plugins) {
744
+ return plugins.sort((a, b) => (Number(a.manifest.priority) || 0) - (Number(b.manifest.priority) || 0) ||
745
+ a.manifest.id.localeCompare(b.manifest.id));
746
+ }
747
+
748
+
749
+ /***/ },
750
+
751
+ /***/ "../common/src/plugin_npm.ts"
752
+ (__unused_webpack_module, exports, __webpack_require__) {
753
+
754
+
755
+ var __importDefault = (this && this.__importDefault) || function (mod) {
756
+ return (mod && mod.__esModule) ? mod : { "default": mod };
757
+ };
758
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
759
+ exports.currentPackageRoot = currentPackageRoot;
760
+ exports.currentProjectRoot = currentProjectRoot;
761
+ exports.npmPluginRoots = npmPluginRoots;
762
+ exports.listNpmPlugins = listNpmPlugins;
763
+ exports.installNpmPlugin = installNpmPlugin;
764
+ exports.uninstallNpmPlugin = uninstallNpmPlugin;
765
+ const child_process_1 = __webpack_require__("child_process");
766
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
767
+ const path_1 = __importDefault(__webpack_require__("path"));
768
+ const module_1 = __webpack_require__("module");
769
+ const PLUGIN_ID = /^[a-z][a-z0-9_-]{1,63}$/;
770
+ const PACKAGE_NAME = /^(?:@[a-z0-9_.-]+\/)?epanel-plugin-[a-z0-9_.-]+$/;
771
+ const VERSION = /^[0-9][^\s/]{0,63}$/;
772
+ function readJson(filename) {
773
+ try {
774
+ const parsed = JSON.parse(fs_extra_1.default.readFileSync(filename, "utf8"));
775
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
776
+ ? parsed
777
+ : null;
778
+ }
779
+ catch (error) {
780
+ if (error?.code === "ENOENT")
781
+ return null;
782
+ throw error;
783
+ }
784
+ }
785
+ function objectValue(value) {
786
+ return value && typeof value === "object" && !Array.isArray(value)
787
+ ? value
788
+ : undefined;
789
+ }
790
+ function stringValue(value) {
791
+ return typeof value === "string" ? value : "";
792
+ }
793
+ function currentPackageRoot() {
794
+ return path_1.default.resolve(process.env.EPANEL_PACKAGE_ROOT || process.cwd());
795
+ }
796
+ function currentProjectRoot(packageRoot = currentPackageRoot()) {
797
+ // The npm worker sets EPANEL_PROJECT_ROOT to the installation directory. In a
798
+ // development checkout the runtime package sits directly under the project.
799
+ if (process.env.EPANEL_PROJECT_ROOT)
800
+ return path_1.default.resolve(process.env.EPANEL_PROJECT_ROOT);
801
+ const scope = path_1.default.resolve(packageRoot, "..");
802
+ const nodeModules = path_1.default.dirname(scope);
803
+ if (path_1.default.basename(nodeModules) === "node_modules" && path_1.default.basename(scope).startsWith("@"))
804
+ return path_1.default.dirname(nodeModules);
805
+ return scope;
806
+ }
807
+ function npmPluginRoots(options = {}) {
808
+ const packageRoot = path_1.default.resolve(options.packageRoot ?? currentPackageRoot());
809
+ return {
810
+ packageRoot,
811
+ projectRoot: path_1.default.resolve(options.projectRoot ?? currentProjectRoot(packageRoot))
812
+ };
813
+ }
814
+ function projectManifestFile(projectRoot) {
815
+ return path_1.default.join(projectRoot, "package.json");
816
+ }
817
+ function readProjectManifest(projectRoot) {
818
+ return (readJson(projectManifestFile(projectRoot)) ?? {
819
+ private: true,
820
+ dependencies: {},
821
+ elementspanel: { plugins: {} }
822
+ });
823
+ }
824
+ function writeProjectManifest(projectRoot, manifest) {
825
+ fs_extra_1.default.writeFileSync(projectManifestFile(projectRoot), `${JSON.stringify(manifest, null, 2)}\n`);
826
+ }
827
+ function dependenciesOf(manifest) {
828
+ return objectValue(manifest?.dependencies) ?? {};
829
+ }
830
+ function mappingsOf(manifest) {
831
+ return objectValue(objectValue(manifest?.elementspanel)?.plugins) ?? {};
832
+ }
833
+ function pluginRecord(pluginId, name, source, packageRoot, directory, folder, version) {
834
+ return { pluginId, name, version, sides: [], directory, folder, packageRoot, source };
835
+ }
836
+ function readPackageEntry(packageRoot, name) {
837
+ const hostRequire = (0, module_1.createRequire)(path_1.default.join(packageRoot, "package.json"));
838
+ const manifestPath = hostRequire.resolve(`${name}/package.json`);
839
+ const metadata = readJson(manifestPath);
840
+ if (!metadata)
841
+ throw new Error(`Missing package metadata for ${name}.`);
842
+ return { root: path_1.default.dirname(manifestPath), metadata };
843
+ }
844
+ function sideDirectory(packageRoot, metadata, side) {
845
+ const elements = objectValue(metadata.elementspanel);
846
+ const definition = objectValue(elements?.[side]);
847
+ const directory = stringValue(definition?.directory);
848
+ if (!definition || !directory)
849
+ return undefined;
850
+ const target = path_1.default.resolve(packageRoot, directory);
851
+ const relative = path_1.default.relative(packageRoot, target);
852
+ if (relative === "" || relative.startsWith(`..${path_1.default.sep}`) || path_1.default.isAbsolute(relative))
853
+ return undefined;
854
+ return target;
855
+ }
856
+ function recordFromPackage(pluginId, name, source, packageRoot, metadata, side) {
857
+ const elements = objectValue(metadata.elementspanel);
858
+ if (!elements || elements.id !== pluginId)
859
+ return undefined;
860
+ const version = stringValue(metadata.version);
861
+ const sides = ["panel", "daemon"].filter((item) => Boolean(sideDirectory(packageRoot, metadata, item)));
862
+ if (!sides.length)
863
+ return undefined;
864
+ const target = side ?? sides[0];
865
+ if (!sides.includes(target))
866
+ return undefined;
867
+ const directory = sideDirectory(packageRoot, metadata, target);
868
+ const folder = stringValue(objectValue(elements[target])?.folder);
869
+ if (!directory || !folder)
870
+ return undefined;
871
+ return {
872
+ ...pluginRecord(pluginId, name, source, packageRoot, directory, folder, version),
873
+ sides
874
+ };
875
+ }
876
+ /**
877
+ * Every npm plugin the runtime can load for a side, built-in and project-installed.
878
+ *
879
+ * Built-in mappings win over a project mapping for the same id: a third-party
880
+ * package must not shadow a plugin that ships with the runtime. A project package
881
+ * that does not describe the requested side is skipped instead of failing, which
882
+ * is what lets a two-sided project share one dependency list between sides.
883
+ */
884
+ function listNpmPlugins(side, options = {}) {
885
+ const { packageRoot, projectRoot } = npmPluginRoots(options);
886
+ const host = readJson(path_1.default.join(packageRoot, "package.json"));
887
+ if (!host)
888
+ throw new Error(`Missing runtime package metadata: ${packageRoot}`);
889
+ const project = path_1.default.resolve(projectRoot) === path_1.default.resolve(packageRoot) ? null : readProjectManifest(projectRoot);
890
+ const hostMappings = mappingsOf(host);
891
+ const projectMappings = mappingsOf(project);
892
+ const mappings = new Map();
893
+ for (const [pluginId, name] of Object.entries(projectMappings)) {
894
+ if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
895
+ continue;
896
+ mappings.set(pluginId, { name, source: "project" });
897
+ }
898
+ for (const [pluginId, name] of Object.entries(hostMappings)) {
899
+ if (!PLUGIN_ID.test(pluginId) || typeof name !== "string" || !PACKAGE_NAME.test(name))
900
+ continue;
901
+ mappings.set(pluginId, { name, source: "bundled" });
902
+ }
903
+ const hostDependencies = dependenciesOf(host);
904
+ const projectDependencies = dependenciesOf(project);
905
+ const folders = new Set();
906
+ const records = [];
907
+ for (const [pluginId, mapping] of mappings) {
908
+ const declared = hostDependencies[mapping.name] ?? projectDependencies[mapping.name];
909
+ if (declared === undefined) {
910
+ if (options.skipInvalid)
911
+ continue;
912
+ throw new Error(`Missing npm plugin dependency: ${mapping.name}. Run npm install in the project directory.`);
913
+ }
914
+ let entry;
915
+ try {
916
+ entry = readPackageEntry(packageRoot, mapping.name);
917
+ }
918
+ catch (error) {
919
+ if (options.skipInvalid)
920
+ continue;
921
+ throw error;
922
+ }
923
+ const record = recordFromPackage(pluginId, mapping.name, mapping.source, entry.root, entry.metadata, side);
924
+ if (!record) {
925
+ if (options.skipInvalid || mapping.source === "project")
926
+ continue;
927
+ throw new Error(`Invalid ${side ?? "plugin"} entry in npm plugin ${mapping.name}.`);
928
+ }
929
+ const folder = record.folder;
930
+ if (folders.has(folder)) {
931
+ if (options.skipInvalid)
932
+ continue;
933
+ throw new Error(`Duplicate npm plugin asset directory: ${folder}.`);
934
+ }
935
+ folders.add(folder);
936
+ records.push(record);
937
+ }
938
+ return records;
939
+ }
940
+ function runNpm(args, cwd) {
941
+ return new Promise((resolve, reject) => {
942
+ const npmCLI = process.env.npm_execpath;
943
+ const invocation = npmCLI && /npm(?:-cli)?\.(?:c?js|mjs)$/.test(npmCLI)
944
+ ? { command: process.execPath, args: [npmCLI, ...args], shell: false }
945
+ : process.platform === "win32"
946
+ ? {
947
+ command: process.env.ComSpec || "cmd.exe",
948
+ args: ["/d", "/s", "/c", `npm ${args.map((item) => `"${item.replace(/"/g, '""')}"`).join(" ")}`],
949
+ shell: false
950
+ }
951
+ : { command: "npm", args, shell: false };
952
+ const child = (0, child_process_1.spawn)(invocation.command, invocation.args, {
953
+ cwd,
954
+ shell: invocation.shell,
955
+ windowsHide: true,
956
+ stdio: ["ignore", "pipe", "pipe"],
957
+ env: { ...process.env, npm_config_update_notifier: "false" }
958
+ });
959
+ let output = "";
960
+ const append = (data) => {
961
+ output += data.toString();
962
+ if (output.length > 16000)
963
+ output = output.slice(-16000);
964
+ };
965
+ child.stdout?.on("data", append);
966
+ child.stderr?.on("data", append);
967
+ const timer = setTimeout(() => {
968
+ child.kill("SIGKILL");
969
+ reject(new Error(`npm ${args[0] ?? ""} timed out.`));
970
+ }, 10 * 60 * 1000);
971
+ timer.unref?.();
972
+ child.once("error", (error) => {
973
+ clearTimeout(timer);
974
+ reject(error);
975
+ });
976
+ child.once("close", (code) => {
977
+ clearTimeout(timer);
978
+ if (code === 0)
979
+ return resolve(output);
980
+ reject(new Error(`npm ${args[0] ?? ""} failed (${code}): ${output.trim()}`));
981
+ });
982
+ });
983
+ }
984
+ const operations = new Map();
985
+ function withProjectLock(projectRoot, operation) {
986
+ const key = process.platform === "win32" ? projectRoot.toLowerCase() : projectRoot;
987
+ const previous = operations.get(key) ?? Promise.resolve();
988
+ const result = previous.then(operation);
989
+ const settled = result.then(() => { }, () => { });
990
+ operations.set(key, settled);
991
+ return result.finally(() => {
992
+ if (operations.get(key) === settled)
993
+ operations.delete(key);
994
+ });
995
+ }
996
+ /**
997
+ * Installs (or updates) one npm plugin as a project dependency.
998
+ *
999
+ * The version is pinned with `--save-exact`: the panel performs updates, so a
1000
+ * later bare `npm install` must not silently move the plugin to another release.
1001
+ */
1002
+ async function installNpmPlugin(options) {
1003
+ const { name, pluginId, version, side } = options;
1004
+ if (!PLUGIN_ID.test(pluginId))
1005
+ throw new Error(`Invalid plugin id: ${pluginId}`);
1006
+ if (!PACKAGE_NAME.test(name))
1007
+ throw new Error(`Invalid npm plugin package: ${name}`);
1008
+ if (!VERSION.test(version))
1009
+ throw new Error(`Invalid plugin version: ${version}`);
1010
+ const { packageRoot, projectRoot } = npmPluginRoots(options);
1011
+ return withProjectLock(projectRoot, async () => {
1012
+ const host = readJson(path_1.default.join(packageRoot, "package.json"));
1013
+ if (!host)
1014
+ throw new Error(`Missing runtime package metadata: ${packageRoot}`);
1015
+ if (mappingsOf(host)[pluginId] !== undefined)
1016
+ throw new Error(`BUNDLED:${pluginId}`);
1017
+ const existing = mappingsOf(readProjectManifest(projectRoot))[pluginId];
1018
+ if (existing !== undefined && existing !== name)
1019
+ throw new Error(`Plugin id ${pluginId} is already installed as ${String(existing)}.`);
1020
+ await fs_extra_1.default.ensureDir(projectRoot);
1021
+ await runNpm(["install", `${name}@${version}`, "--save", "--save-exact", "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot);
1022
+ let entry;
1023
+ try {
1024
+ entry = readPackageEntry(packageRoot, name);
1025
+ }
1026
+ catch (error) {
1027
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
1028
+ throw error;
1029
+ }
1030
+ const record = recordFromPackage(pluginId, name, "project", entry.root, entry.metadata, side);
1031
+ if (!record) {
1032
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
1033
+ throw new Error(`The package ${name} does not provide a ${side} plugin named ${pluginId}.`);
1034
+ }
1035
+ if (record.version !== version) {
1036
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot).catch(() => { });
1037
+ throw new Error(`The installed package ${name} is ${record.version}, expected ${version}.`);
1038
+ }
1039
+ const manifest = readProjectManifest(projectRoot);
1040
+ const dependencies = { ...dependenciesOf(manifest), [name]: version };
1041
+ const elementspanel = { ...(objectValue(manifest.elementspanel) ?? {}) };
1042
+ const plugins = { ...mappingsOf(manifest), [pluginId]: name };
1043
+ manifest.dependencies = dependencies;
1044
+ manifest.elementspanel = { ...elementspanel, plugins };
1045
+ writeProjectManifest(projectRoot, manifest);
1046
+ return record;
1047
+ });
1048
+ }
1049
+ /** Removes one project-installed npm plugin. Built-in packages are left alone. */
1050
+ async function uninstallNpmPlugin(pluginId, options = {}) {
1051
+ if (!PLUGIN_ID.test(pluginId))
1052
+ throw new Error(`Invalid plugin id: ${pluginId}`);
1053
+ const { packageRoot, projectRoot } = npmPluginRoots(options);
1054
+ return withProjectLock(projectRoot, async () => {
1055
+ const host = readJson(path_1.default.join(packageRoot, "package.json"));
1056
+ if (host && mappingsOf(host)[pluginId] !== undefined)
1057
+ throw new Error(`BUNDLED:${pluginId}`);
1058
+ const manifest = readProjectManifest(projectRoot);
1059
+ const name = mappingsOf(manifest)[pluginId];
1060
+ if (typeof name !== "string" || !PACKAGE_NAME.test(name))
1061
+ return null;
1062
+ const record = listNpmPlugins(undefined, { packageRoot, projectRoot, skipInvalid: true }).find((item) => item.pluginId === pluginId);
1063
+ await runNpm(["uninstall", name, "--no-fund", "--no-audit", "--ignore-scripts"], projectRoot);
1064
+ const plugins = { ...mappingsOf(manifest) };
1065
+ delete plugins[pluginId];
1066
+ const elementspanel = { ...(objectValue(manifest.elementspanel) ?? {}) };
1067
+ if (Object.keys(plugins).length)
1068
+ elementspanel.plugins = plugins;
1069
+ else
1070
+ delete elementspanel.plugins;
1071
+ manifest.elementspanel = elementspanel;
1072
+ writeProjectManifest(projectRoot, manifest);
1073
+ return record ?? null;
1074
+ });
1075
+ }
1076
+
1077
+
1078
+ /***/ },
1079
+
1080
+ /***/ "../common/src/plugin_overrides.ts"
1081
+ (__unused_webpack_module, exports, __webpack_require__) {
1082
+
1083
+
1084
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1085
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1086
+ };
1087
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1088
+ exports.pluginOverridesPath = pluginOverridesPath;
1089
+ exports.readPluginOverrides = readPluginOverrides;
1090
+ exports.validatePluginOverride = validatePluginOverride;
1091
+ exports.applyPluginOverrides = applyPluginOverrides;
1092
+ exports.writePluginOverride = writePluginOverride;
1093
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
1094
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
1095
+ const node_crypto_1 = __webpack_require__("node:crypto");
1096
+ function pluginOverridesPath() {
1097
+ return node_path_1.default.resolve(process.cwd(), "data", "plugin-overrides.json");
1098
+ }
1099
+ /** Package defaults stay immutable; only the user's last layer lives in data. */
1100
+ function readPluginOverrides(filename = pluginOverridesPath()) {
1101
+ let raw;
1102
+ try {
1103
+ raw = node_fs_1.default.readFileSync(filename, "utf8");
1104
+ }
1105
+ catch (error) {
1106
+ if (error.code === "ENOENT")
1107
+ return { version: 1, plugins: {} };
1108
+ throw error;
1109
+ }
1110
+ const data = JSON.parse(raw);
1111
+ if (data?.version !== 1 ||
1112
+ !data.plugins ||
1113
+ typeof data.plugins !== "object" ||
1114
+ Array.isArray(data.plugins))
1115
+ throw new Error("Invalid plugin-overrides.json");
1116
+ for (const entry of Object.values(data.plugins))
1117
+ validatePluginOverride(entry);
1118
+ return data;
1119
+ }
1120
+ function validatePluginOverride(value) {
1121
+ if (!value || typeof value !== "object" || Array.isArray(value))
1122
+ throw new Error("Invalid plugin override.");
1123
+ const entry = value;
1124
+ if (entry.enabled !== undefined && typeof entry.enabled !== "boolean")
1125
+ throw new Error("Invalid plugin enablement.");
1126
+ if (entry.config !== undefined &&
1127
+ (!entry.config || typeof entry.config !== "object" || Array.isArray(entry.config)))
1128
+ throw new Error("Plugin config must be an object.");
1129
+ if (Object.keys(value).some((key) => !["enabled", "config"].includes(key)))
1130
+ throw new Error("Unknown plugin override field.");
1131
+ }
1132
+ function applyPluginOverrides(plugins, filename = pluginOverridesPath()) {
1133
+ const overrides = readPluginOverrides(filename).plugins;
1134
+ return plugins.map((plugin) => ({
1135
+ ...plugin,
1136
+ manifest: {
1137
+ ...plugin.manifest,
1138
+ ...(Object.prototype.hasOwnProperty.call(overrides, plugin.manifest.id)
1139
+ ? overrides[plugin.manifest.id]
1140
+ : {})
1141
+ }
1142
+ }));
1143
+ }
1144
+ /** Call inside the host's change queue; rename keeps readers off partial JSON. */
1145
+ function writePluginOverride(id, patch, filename = pluginOverridesPath()) {
1146
+ validatePluginOverride(patch);
1147
+ if (!id || ["__proto__", "constructor", "prototype"].includes(id))
1148
+ throw new Error("Invalid plugin id.");
1149
+ const data = readPluginOverrides(filename);
1150
+ data.plugins[id] = {
1151
+ ...(Object.prototype.hasOwnProperty.call(data.plugins, id) ? data.plugins[id] : {}),
1152
+ ...patch
1153
+ };
1154
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(filename), { recursive: true });
1155
+ const temporary = `${filename}.${(0, node_crypto_1.randomBytes)(8).toString("hex")}.tmp`;
1156
+ try {
1157
+ node_fs_1.default.writeFileSync(temporary, `${JSON.stringify(data, null, 2)}\n`, { mode: 0o600, flag: "wx" });
1158
+ node_fs_1.default.renameSync(temporary, filename);
1159
+ }
1160
+ finally {
1161
+ node_fs_1.default.rmSync(temporary, { force: true });
1162
+ }
1163
+ }
1164
+
1165
+
1166
+ /***/ },
1167
+
1168
+ /***/ "../common/src/plugin_revision.ts"
1169
+ (__unused_webpack_module, exports, __webpack_require__) {
1170
+
1171
+
1172
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1173
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1174
+ };
1175
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1176
+ exports.pluginDirectoryRevision = pluginDirectoryRevision;
1177
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
1178
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
1179
+ const node_crypto_1 = __webpack_require__("node:crypto");
1180
+ const cache = new Map();
1181
+ /** One revision addresses the complete module graph, including CSS and nested chunks. */
1182
+ function pluginDirectoryRevision(directory) {
1183
+ const files = [];
1184
+ const walk = (root) => {
1185
+ if (!node_fs_1.default.existsSync(root))
1186
+ return;
1187
+ for (const item of node_fs_1.default
1188
+ .readdirSync(root, { withFileTypes: true })
1189
+ .sort((a, b) => a.name.localeCompare(b.name))) {
1190
+ const absolute = node_path_1.default.join(root, item.name);
1191
+ if (item.isDirectory())
1192
+ walk(absolute);
1193
+ else if (item.isFile())
1194
+ files.push({
1195
+ relative: node_path_1.default.relative(directory, absolute),
1196
+ absolute,
1197
+ stat: node_fs_1.default.statSync(absolute)
1198
+ });
1199
+ }
1200
+ };
1201
+ walk(directory);
1202
+ const signature = JSON.stringify(files.map(({ relative, stat }) => [relative, stat.size, stat.mtimeMs, stat.ctimeMs]));
1203
+ const previous = cache.get(directory);
1204
+ if (previous?.signature === signature)
1205
+ return previous.revision;
1206
+ const hash = (0, node_crypto_1.createHash)("sha256");
1207
+ for (const file of files)
1208
+ hash
1209
+ .update(file.relative)
1210
+ .update("\0")
1211
+ .update(new Uint8Array(node_fs_1.default.readFileSync(file.absolute)))
1212
+ .update("\0");
1213
+ const revision = hash.digest("hex").slice(0, 24);
1214
+ if (cache.size > 1024)
1215
+ cache.clear();
1216
+ cache.set(directory, { signature, revision });
1217
+ return revision;
1218
+ }
1219
+
1220
+
1221
+ /***/ },
1222
+
1223
+ /***/ "../common/src/process_tools.ts"
1224
+ (__unused_webpack_module, exports, __webpack_require__) {
1225
+
1226
+
1227
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1228
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1229
+ };
1230
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1231
+ exports.ProcessWrapper = exports.StartError = void 0;
1232
+ exports.killProcess = killProcess;
1233
+ const child_process_1 = __webpack_require__("child_process");
1234
+ const os_1 = __importDefault(__webpack_require__("os"));
1235
+ const child_process_2 = __importDefault(__webpack_require__("child_process"));
1236
+ const path_1 = __importDefault(__webpack_require__("path"));
1237
+ const events_1 = __importDefault(__webpack_require__("events"));
1238
+ const iconv_lite_1 = __importDefault(__webpack_require__("iconv-lite"));
1239
+ const process_1 = __importDefault(__webpack_require__("process"));
1240
+ class StartError extends Error {
1241
+ }
1242
+ exports.StartError = StartError;
1243
+ class ProcessWrapper extends events_1.default {
1244
+ file;
1245
+ args;
1246
+ cwd;
1247
+ timeout;
1248
+ code;
1249
+ option;
1250
+ process;
1251
+ pid;
1252
+ lastExitCode;
1253
+ completed = false;
1254
+ errMsg = {
1255
+ timeoutErr: "task timeout!",
1256
+ exitErr: "task error!",
1257
+ startErr: "task start error!"
1258
+ };
1259
+ constructor(file, args, cwd, timeout = 0, code = "utf-8", option = {}) {
1260
+ super();
1261
+ this.file = file;
1262
+ this.args = args;
1263
+ this.cwd = cwd;
1264
+ this.timeout = timeout;
1265
+ this.code = code;
1266
+ this.option = option;
1267
+ }
1268
+ setErrMsg(errMsg) {
1269
+ this.errMsg = errMsg;
1270
+ }
1271
+ start() {
1272
+ if (this.process)
1273
+ return Promise.reject(new Error("The process is already running"));
1274
+ return new Promise((resolve, reject) => {
1275
+ const stdoutDecoder = iconv_lite_1.default.decodeStream(this.code);
1276
+ const stderrDecoder = iconv_lite_1.default.decodeStream(this.code);
1277
+ let timeTask;
1278
+ let settled = false;
1279
+ let spawned = false;
1280
+ const settle = (error) => {
1281
+ if (settled)
1282
+ return;
1283
+ settled = true;
1284
+ if (timeTask)
1285
+ clearTimeout(timeTask);
1286
+ if (error)
1287
+ reject(error);
1288
+ else
1289
+ resolve(true);
1290
+ };
1291
+ const subProcess = child_process_2.default.spawn(this.file, this.args, {
1292
+ stdio: "pipe",
1293
+ windowsHide: true,
1294
+ cwd: path_1.default.normalize(this.cwd),
1295
+ ...this.option
1296
+ });
1297
+ this.process = subProcess;
1298
+ this.pid = subProcess.pid;
1299
+ this.lastExitCode = undefined;
1300
+ this.completed = false;
1301
+ const fail = (error) => {
1302
+ if (settled)
1303
+ return;
1304
+ settle(error);
1305
+ if (subProcess.pid && subProcess.exitCode === null && subProcess.signalCode === null) {
1306
+ try {
1307
+ killProcess(subProcess.pid, subProcess);
1308
+ }
1309
+ catch (error) {
1310
+ console.error("[ProcessWrapper kill error]", error);
1311
+ }
1312
+ }
1313
+ };
1314
+ subProcess.once("spawn", () => {
1315
+ spawned = true;
1316
+ this.emit("start", subProcess.pid);
1317
+ });
1318
+ for (const [source, decoder] of [
1319
+ [subProcess.stdout, stdoutDecoder],
1320
+ [subProcess.stderr, stderrDecoder]
1321
+ ]) {
1322
+ decoder.on("data", (text) => this.emit("data", text));
1323
+ decoder.on("error", fail);
1324
+ source.on("error", fail);
1325
+ source.pipe(decoder);
1326
+ }
1327
+ subProcess.stdin.on("error", fail);
1328
+ subProcess.once("error", (error) => {
1329
+ fail(new Error(`${spawned ? this.errMsg.exitErr : this.errMsg.startErr} ${error.message}`));
1330
+ });
1331
+ subProcess.once("exit", (code) => {
1332
+ this.lastExitCode = code;
1333
+ this.emit("exit", code);
1334
+ });
1335
+ // `close` follows the final stdout/stderr data and also follows a failed spawn.
1336
+ subProcess.once("close", (code) => {
1337
+ this.lastExitCode = code;
1338
+ this.completed = true;
1339
+ this.process = undefined;
1340
+ settle(code === 0 ? undefined : new Error(this.errMsg.exitErr));
1341
+ });
1342
+ if (this.timeout > 0) {
1343
+ timeTask = setTimeout(() => {
1344
+ fail(new Error(this.errMsg.timeoutErr));
1345
+ }, 1000 * this.timeout);
1346
+ }
1347
+ });
1348
+ }
1349
+ getPid() {
1350
+ return this.process?.pid;
1351
+ }
1352
+ write(data) {
1353
+ return this.process?.stdin?.write(iconv_lite_1.default.encode(data, this.code));
1354
+ }
1355
+ kill() {
1356
+ if (this.process?.pid)
1357
+ killProcess(this.process?.pid, this.process);
1358
+ }
1359
+ status() {
1360
+ return this.completed;
1361
+ }
1362
+ exitCode() {
1363
+ return this.process?.exitCode ?? this.lastExitCode;
1364
+ }
1365
+ }
1366
+ exports.ProcessWrapper = ProcessWrapper;
1367
+ function killProcess(pid, process, signal) {
1368
+ const numericPid = Number(pid);
1369
+ if (!Number.isSafeInteger(numericPid) || numericPid <= 0) {
1370
+ throw new Error("Invalid process ID");
1371
+ }
1372
+ try {
1373
+ if (os_1.default.platform() === "win32") {
1374
+ (0, child_process_1.execFileSync)("taskkill", ["/PID", String(numericPid), "/T", "/F"], { windowsHide: true });
1375
+ return true;
1376
+ }
1377
+ return process_1.default.kill(numericPid, signal || "SIGKILL");
1378
+ }
1379
+ catch (err) {
1380
+ return signal ? process.kill(signal) : process.kill("SIGKILL");
1381
+ }
1382
+ }
1383
+
1384
+
1385
+ /***/ },
1386
+
1387
+ /***/ "../common/src/query_wrapper.ts"
1388
+ (__unused_webpack_module, exports) {
1389
+
1390
+
1391
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1392
+ exports.QueryWrapper = exports.LocalFileSource = exports.MySqlSource = exports.QueryMapWrapper = void 0;
1393
+ function paginate(data, page, pageSize) {
1394
+ if (!Number.isSafeInteger(page) || page < 1 || !Number.isSafeInteger(pageSize) || pageSize < 1) {
1395
+ throw new RangeError("page and pageSize must be positive integers");
1396
+ }
1397
+ const start = (page - 1) * pageSize;
1398
+ return {
1399
+ page,
1400
+ pageSize,
1401
+ maxPage: Math.ceil(data.length / pageSize),
1402
+ total: data.length,
1403
+ data: data.slice(start, start + pageSize)
1404
+ };
1405
+ }
1406
+ // Provide the MAP query interface used by the routing layer
1407
+ class QueryMapWrapper {
1408
+ map;
1409
+ constructor(map) {
1410
+ this.map = map;
1411
+ }
1412
+ select(condition) {
1413
+ const result = [];
1414
+ this.map.forEach((v) => {
1415
+ if (condition(v))
1416
+ result.push(v);
1417
+ });
1418
+ return result;
1419
+ }
1420
+ page(data, page = 1, pageSize = 10) {
1421
+ return paginate(data, page, pageSize);
1422
+ }
1423
+ }
1424
+ exports.QueryMapWrapper = QueryMapWrapper;
1425
+ // MYSQL data source
1426
+ class MySqlSource {
1427
+ data;
1428
+ constructor(data) {
1429
+ this.data = data;
1430
+ }
1431
+ selectPage(condition, page, pageSize) {
1432
+ return {
1433
+ page,
1434
+ pageSize,
1435
+ maxPage: 0,
1436
+ total: 0,
1437
+ data: []
1438
+ };
1439
+ }
1440
+ select(condition) {
1441
+ return [];
1442
+ }
1443
+ update(condition, data) { }
1444
+ delete(condition) { }
1445
+ insert(data) { }
1446
+ }
1447
+ exports.MySqlSource = MySqlSource;
1448
+ // local file data source (embedded microdatabase)
1449
+ class LocalFileSource {
1450
+ data;
1451
+ constructor(data) {
1452
+ this.data = data;
1453
+ }
1454
+ selectPage(condition, page = 1, pageSize = 10) {
1455
+ return this.page(this.select(condition), page, pageSize);
1456
+ }
1457
+ page(data, page = 1, pageSize = 10) {
1458
+ return paginate(data, page, pageSize);
1459
+ }
1460
+ select(condition = {}) {
1461
+ const result = [];
1462
+ const entries = Object.entries(condition);
1463
+ this.data.forEach((v) => {
1464
+ for (const [key, targetValue] of entries) {
1465
+ const dataValue = v[key];
1466
+ if (typeof targetValue === "string" &&
1467
+ targetValue.startsWith("%") &&
1468
+ targetValue.endsWith("%")) {
1469
+ if (typeof dataValue !== "string" || !dataValue.includes(targetValue.slice(1, -1)))
1470
+ return;
1471
+ }
1472
+ else if (targetValue !== dataValue) {
1473
+ return;
1474
+ }
1475
+ }
1476
+ result.push(v);
1477
+ });
1478
+ return result;
1479
+ }
1480
+ update(condition, data) { }
1481
+ delete(condition) { }
1482
+ insert(data) { }
1483
+ }
1484
+ exports.LocalFileSource = LocalFileSource;
1485
+ // Provide the unified data query interface used by the routing layer
1486
+ class QueryWrapper {
1487
+ dataSource;
1488
+ constructor(dataSource) {
1489
+ this.dataSource = dataSource;
1490
+ }
1491
+ selectPage(condition, page = 1, pageSize = 10) {
1492
+ return this.dataSource.selectPage(condition, page, pageSize);
1493
+ }
1494
+ }
1495
+ exports.QueryWrapper = QueryWrapper;
1496
+
1497
+
1498
+ /***/ },
1499
+
1500
+ /***/ "../common/src/runtime_paths.ts"
1501
+ (__unused_webpack_module, exports, __webpack_require__) {
1502
+
1503
+
1504
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1505
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1506
+ };
1507
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1508
+ exports.isPackagedRuntime = isPackagedRuntime;
1509
+ exports.packagePath = packagePath;
1510
+ exports.packagePluginRoots = packagePluginRoots;
1511
+ exports.isPackagePlugin = isPackagePlugin;
1512
+ exports.bundledToolPath = bundledToolPath;
1513
+ exports.ensureExecutable = ensureExecutable;
1514
+ const node_fs_1 = __importDefault(__webpack_require__("node:fs"));
1515
+ const node_os_1 = __importDefault(__webpack_require__("node:os"));
1516
+ const node_path_1 = __importDefault(__webpack_require__("node:path"));
1517
+ /** Set by the npm worker before any application module is loaded. */
1518
+ function isPackagedRuntime() {
1519
+ return Boolean(process.env.EPANEL_PACKAGE_ROOT);
1520
+ }
1521
+ /** Code and bundled assets belong to the package; cwd always belongs to the user. */
1522
+ function packagePath(...parts) {
1523
+ return node_path_1.default.resolve(process.env.EPANEL_PACKAGE_ROOT || process.cwd(), ...parts);
1524
+ }
1525
+ function npmPluginRoots(side) {
1526
+ // The same resolver is used by the CLI before the bundled application starts.
1527
+ // A development checkout keeps it in the repository, beside the side packages,
1528
+ // so project-installed npm plugins work there as well.
1529
+ const runtimeRequire = eval("require");
1530
+ const resolver = isPackagedRuntime()
1531
+ ? packagePath("runtime/npm-plugins.cjs")
1532
+ : node_path_1.default.resolve(packagePath(), "..", "scripts", "runtime", "npm-plugins.cjs");
1533
+ // A development process may run from a fixture directory without a runtime
1534
+ // package; there is nothing to resolve in that case.
1535
+ if (!node_fs_1.default.existsSync(node_path_1.default.join(packagePath(), "package.json")))
1536
+ return [];
1537
+ if (!isPackagedRuntime() && !node_fs_1.default.existsSync(resolver))
1538
+ return [];
1539
+ const { resolveNpmPlugins } = runtimeRequire(resolver);
1540
+ return resolveNpmPlugins(packagePath(), side, { skipInvalid: true }).map((record) => ({
1541
+ directory: record.directory,
1542
+ ...(record.folder ? { folder: record.folder } : {}),
1543
+ // Built-in packages are part of the runtime's default configuration. A
1544
+ // project dependency is installed but remains dormant until the user
1545
+ // enables it through the plugin configuration service.
1546
+ defaultEnabled: record.defaultEnabled !== false
1547
+ }));
1548
+ }
1549
+ function packagePluginRoots(side) {
1550
+ const roots = isPackagedRuntime()
1551
+ ? []
1552
+ : [{ directory: packagePath("plugins"), defaultEnabled: true }];
1553
+ // Project-installed npm plugins load in development too: they are dependencies
1554
+ // of the development project, not of the published runtime package.
1555
+ roots.push(...npmPluginRoots(side));
1556
+ return roots;
1557
+ }
1558
+ function isPackagePlugin(directory) {
1559
+ return npmPluginRoots().some((root) => {
1560
+ const relative = node_path_1.default.relative(root.directory, node_path_1.default.resolve(directory));
1561
+ return (relative === "" ||
1562
+ (!relative.startsWith(`..${node_path_1.default.sep}`) && relative !== ".." && !node_path_1.default.isAbsolute(relative)));
1563
+ });
1564
+ }
1565
+ function bundledToolPath(name) {
1566
+ const platform = node_os_1.default.platform();
1567
+ const arch = node_os_1.default.arch();
1568
+ const suffix = platform === "win32" ? ".exe" : "";
1569
+ const filename = `${name}_${platform}_${arch}${suffix}`;
1570
+ // Published daemon packages download native tools into the installation's
1571
+ // writable lib directory on first start. Development checkouts use the same
1572
+ // repository-local sibling of data and logs.
1573
+ const root = isPackagedRuntime() ? node_path_1.default.resolve(process.cwd(), "lib") : packagePath("lib");
1574
+ const primary = node_path_1.default.join(root, filename);
1575
+ // Zip-Tools names its Intel macOS binary "amd64", while Node reports "x64".
1576
+ if (!node_fs_1.default.existsSync(primary) && name === "file_zip" && platform === "darwin" && arch === "x64") {
1577
+ const alternate = node_path_1.default.join(root, "file_zip_darwin_amd64");
1578
+ if (node_fs_1.default.existsSync(alternate))
1579
+ return alternate;
1580
+ }
1581
+ return primary;
1582
+ }
1583
+ /** Published binaries already carry executable permissions, including in read-only installs. */
1584
+ function ensureExecutable(filename) {
1585
+ if (node_os_1.default.platform() === "win32")
1586
+ return;
1587
+ try {
1588
+ node_fs_1.default.accessSync(filename, node_fs_1.default.constants.X_OK);
1589
+ }
1590
+ catch {
1591
+ node_fs_1.default.chmodSync(filename, 0o755);
1592
+ }
1593
+ }
1594
+
1595
+
1596
+ /***/ },
1597
+
1598
+ /***/ "../common/src/string_utils.ts"
1599
+ (__unused_webpack_module, exports) {
1600
+
1601
+
1602
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1603
+ exports.removeTrail = removeTrail;
1604
+ function removeTrail(origin, trail) {
1605
+ if (origin.endsWith(trail)) {
1606
+ return origin.slice(0, origin.length - trail.length);
1607
+ }
1608
+ else {
1609
+ return origin;
1610
+ }
1611
+ }
1612
+
1613
+
1614
+ /***/ },
1615
+
1616
+ /***/ "../common/src/system_info.ts"
1617
+ (__unused_webpack_module, exports, __webpack_require__) {
1618
+
1619
+
1620
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1621
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1622
+ };
1623
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1624
+ exports.systemInfo = systemInfo;
1625
+ const os_1 = __importDefault(__webpack_require__("os"));
1626
+ const os_utils_1 = __importDefault(__webpack_require__("os-utils"));
1627
+ const fs_1 = __importDefault(__webpack_require__("fs"));
1628
+ // System details are updated every time
1629
+ const info = {
1630
+ type: os_1.default.type(),
1631
+ hostname: os_1.default.hostname(),
1632
+ platform: os_1.default.platform(),
1633
+ release: os_1.default.release(),
1634
+ uptime: os_1.default.uptime(),
1635
+ cwd: process.cwd(),
1636
+ loadavg: os_1.default.loadavg(),
1637
+ freemem: 0,
1638
+ cpuUsage: 0,
1639
+ memUsage: 0,
1640
+ totalmem: 0,
1641
+ processCpu: 0,
1642
+ processMem: 0
1643
+ };
1644
+ let previousCpu = process.cpuUsage();
1645
+ let previousTime = process.hrtime.bigint();
1646
+ // periodically refresh the cache
1647
+ function refresh() {
1648
+ const now = process.hrtime.bigint();
1649
+ const cpu = process.cpuUsage();
1650
+ const elapsed = Number(now - previousTime) / 1000;
1651
+ info.processCpu =
1652
+ elapsed > 0 ? (cpu.user - previousCpu.user + cpu.system - previousCpu.system) / elapsed : 0;
1653
+ previousCpu = cpu;
1654
+ previousTime = now;
1655
+ info.uptime = os_1.default.uptime();
1656
+ info.loadavg = os_1.default.loadavg();
1657
+ info.processMem = process.memoryUsage().rss;
1658
+ if (os_1.default.platform() === "linux") {
1659
+ return setLinuxSystemInfo();
1660
+ }
1661
+ return otherSystemInfo();
1662
+ }
1663
+ refresh();
1664
+ setInterval(refresh, 3000).unref();
1665
+ function otherSystemInfo() {
1666
+ info.freemem = os_1.default.freemem();
1667
+ info.totalmem = os_1.default.totalmem();
1668
+ info.memUsage = (os_1.default.totalmem() - os_1.default.freemem()) / os_1.default.totalmem();
1669
+ os_utils_1.default.cpuUsage((p) => (info.cpuUsage = p));
1670
+ }
1671
+ function setLinuxSystemInfo() {
1672
+ try {
1673
+ // read memory data based on /proc/meminfo
1674
+ const data = fs_1.default.readFileSync("/proc/meminfo", { encoding: "utf-8" });
1675
+ const list = data.split("\n");
1676
+ const infoTable = {};
1677
+ list.forEach((line) => {
1678
+ const kv = line.split(":");
1679
+ if (kv.length === 2) {
1680
+ const k = kv[0].replace(/ /gim, "").replace(/\t/gim, "").trim().toLowerCase();
1681
+ let v = kv[1].replace(/ /gim, "").replace(/\t/gim, "").trim().toLowerCase();
1682
+ v = v.replace(/kb/gim, "").replace(/mb/gim, "").replace(/gb/gim, "");
1683
+ let vNumber = parseInt(v);
1684
+ if (isNaN(vNumber))
1685
+ vNumber = 0;
1686
+ infoTable[k] = vNumber;
1687
+ }
1688
+ });
1689
+ const memAvailable = infoTable["memavailable"] ?? infoTable["memfree"];
1690
+ const memTotal = infoTable["memtotal"];
1691
+ info.freemem = memAvailable * 1024;
1692
+ info.totalmem = memTotal * 1024;
1693
+ info.memUsage = (info.totalmem - info.freemem) / info.totalmem;
1694
+ os_utils_1.default.cpuUsage((p) => (info.cpuUsage = p));
1695
+ }
1696
+ catch (error) {
1697
+ // If the reading is wrong, the default general reading method is automatically used
1698
+ otherSystemInfo();
1699
+ }
1700
+ }
1701
+ function systemInfo() {
1702
+ return info;
1703
+ }
1704
+
1705
+
1706
+ /***/ },
1707
+
1708
+ /***/ "../common/src/system_storage.ts"
1709
+ (__unused_webpack_module, exports, __webpack_require__) {
1710
+
1711
+
1712
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1713
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1714
+ };
1715
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1716
+ const crypto_1 = __webpack_require__("crypto");
1717
+ const path_1 = __importDefault(__webpack_require__("path"));
1718
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
1719
+ class StorageSubsystem {
1720
+ static DATA_PATH = path_1.default.resolve(process.cwd(), "data");
1721
+ static INDEX_PATH = path_1.default.join(StorageSubsystem.DATA_PATH, "Index");
1722
+ resolvePath(name) {
1723
+ if (typeof name !== "string" ||
1724
+ !name ||
1725
+ /[\0:]/.test(name) ||
1726
+ path_1.default.isAbsolute(name) ||
1727
+ path_1.default.win32.isAbsolute(name)) {
1728
+ throw new Error(`Invalid storage path: ${name}`);
1729
+ }
1730
+ const target = path_1.default.resolve(StorageSubsystem.DATA_PATH, name);
1731
+ const relative = path_1.default.relative(StorageSubsystem.DATA_PATH, target);
1732
+ if (!relative ||
1733
+ relative === ".." ||
1734
+ relative.startsWith(`..${path_1.default.sep}`) ||
1735
+ path_1.default.isAbsolute(relative)) {
1736
+ throw new Error(`Invalid storage path: ${name}`);
1737
+ }
1738
+ const realRelative = path_1.default.relative(this.realPath(StorageSubsystem.DATA_PATH), this.realPath(target));
1739
+ if (realRelative === ".." ||
1740
+ realRelative.startsWith(`..${path_1.default.sep}`) ||
1741
+ path_1.default.isAbsolute(realRelative)) {
1742
+ throw new Error(`Invalid storage path: ${name}`);
1743
+ }
1744
+ return target;
1745
+ }
1746
+ realPath(target) {
1747
+ if (fs_extra_1.default.existsSync(target))
1748
+ return fs_extra_1.default.realpathSync(target);
1749
+ const parent = path_1.default.dirname(target);
1750
+ return parent === target ? target : path_1.default.join(this.realPath(parent), path_1.default.basename(target));
1751
+ }
1752
+ entityPath(category, uuid) {
1753
+ if (typeof uuid !== "string" || !uuid || /[\\/\0:]/.test(uuid) || uuid.includes("..")) {
1754
+ throw new Error(`UUID ${uuid} does not conform to specification`);
1755
+ }
1756
+ this.resolvePath(category);
1757
+ return path_1.default.join(category, `${uuid}.json`);
1758
+ }
1759
+ writeFile(name, data) {
1760
+ const targetPath = this.resolvePath(name);
1761
+ fs_extra_1.default.ensureDirSync(path_1.default.dirname(targetPath));
1762
+ const temporaryPath = `${targetPath}.${(0, crypto_1.randomUUID)()}.tmp`;
1763
+ const mode = fs_extra_1.default.existsSync(targetPath) ? fs_extra_1.default.statSync(targetPath).mode : 0o600;
1764
+ try {
1765
+ fs_extra_1.default.writeFileSync(temporaryPath, data, { encoding: "utf8", flag: "wx", mode });
1766
+ fs_extra_1.default.renameSync(temporaryPath, targetPath);
1767
+ }
1768
+ finally {
1769
+ if (fs_extra_1.default.existsSync(temporaryPath))
1770
+ fs_extra_1.default.unlinkSync(temporaryPath);
1771
+ }
1772
+ }
1773
+ readFile(name) {
1774
+ return fs_extra_1.default.readFileSync(this.resolvePath(name), "utf8");
1775
+ }
1776
+ readDir(dirName) {
1777
+ const targetPath = this.resolvePath(dirName);
1778
+ if (!fs_extra_1.default.existsSync(targetPath))
1779
+ return [];
1780
+ return fs_extra_1.default.readdirSync(targetPath).map((name) => path_1.default.join(dirName, name));
1781
+ }
1782
+ deleteFile(name) {
1783
+ fs_extra_1.default.removeSync(this.resolvePath(name));
1784
+ }
1785
+ fileExists(name) {
1786
+ return fs_extra_1.default.existsSync(this.resolvePath(name));
1787
+ }
1788
+ store(category, uuid, object) {
1789
+ this.writeFile(this.entityPath(category, uuid), JSON.stringify(object, null, 4));
1790
+ }
1791
+ // Restore declared fields while keeping defaults for fields absent in older data.
1792
+ defineAttr(target, object) {
1793
+ for (const key of Object.keys(target)) {
1794
+ if (!Object.prototype.hasOwnProperty.call(object, key) || object[key] === undefined)
1795
+ continue;
1796
+ const value = object[key];
1797
+ if (value !== null &&
1798
+ typeof value === "object" &&
1799
+ !Array.isArray(value) &&
1800
+ target[key] !== null &&
1801
+ typeof target[key] === "object" &&
1802
+ !Array.isArray(target[key])) {
1803
+ this.defineAttr(target[key], value);
1804
+ }
1805
+ else {
1806
+ target[key] = value;
1807
+ }
1808
+ }
1809
+ return target;
1810
+ }
1811
+ load(category, classz, uuid) {
1812
+ const file = this.entityPath(category, uuid);
1813
+ if (!this.fileExists(file))
1814
+ return null;
1815
+ const object = JSON.parse(this.readFile(file));
1816
+ if (!object || typeof object !== "object" || Array.isArray(object)) {
1817
+ throw new Error(`Invalid stored entity: ${file}`);
1818
+ }
1819
+ return this.defineAttr(new classz(), object);
1820
+ }
1821
+ list(category) {
1822
+ const directory = this.resolvePath(category);
1823
+ if (!fs_extra_1.default.existsSync(directory))
1824
+ return [];
1825
+ return fs_extra_1.default
1826
+ .readdirSync(directory, { withFileTypes: true })
1827
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
1828
+ .map((entry) => entry.name.slice(0, -5));
1829
+ }
1830
+ delete(category, uuid) {
1831
+ this.deleteFile(this.entityPath(category, uuid));
1832
+ }
1833
+ }
1834
+ exports["default"] = StorageSubsystem;
1835
+
1836
+
1837
+ /***/ },
1838
+
1839
+ /***/ "../common/src/typecheck.ts"
1840
+ (__unused_webpack_module, exports) {
1841
+
1842
+
1843
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1844
+ exports.configureEntityParams = configureEntityParams;
1845
+ exports.toText = toText;
1846
+ exports.toNumber = toNumber;
1847
+ exports.toBoolean = toBoolean;
1848
+ exports.isEmpty = isEmpty;
1849
+ exports.supposeValue = supposeValue;
1850
+ function configureEntityParams(self, args, key, typeFn) {
1851
+ const selfDefaultValue = self[key] ?? null;
1852
+ const v = args[key] != null ? args[key] : selfDefaultValue;
1853
+ if (typeFn === Number) {
1854
+ if (v === "" || v == null) {
1855
+ self[key] = null;
1856
+ }
1857
+ else {
1858
+ if (isNaN(Number(v)))
1859
+ throw new Error(`ConfigureEntityParams Error: Expected type to be Number, but got ${typeof v}`);
1860
+ self[key] = Number(v);
1861
+ }
1862
+ return;
1863
+ }
1864
+ if (typeFn === String) {
1865
+ if (v == null) {
1866
+ self[key] = null;
1867
+ }
1868
+ else {
1869
+ self[key] = String(v);
1870
+ }
1871
+ return;
1872
+ }
1873
+ if (typeFn === Boolean) {
1874
+ if (v == null) {
1875
+ self[key] = false;
1876
+ }
1877
+ else {
1878
+ self[key] = Boolean(v);
1879
+ }
1880
+ return;
1881
+ }
1882
+ if (typeFn) {
1883
+ self[key] = typeFn(v);
1884
+ }
1885
+ else {
1886
+ self[key] = v;
1887
+ }
1888
+ }
1889
+ function toText(v) {
1890
+ if (isEmpty(v))
1891
+ return null;
1892
+ return String(v);
1893
+ }
1894
+ function toNumber(v) {
1895
+ if (isEmpty(v))
1896
+ return null;
1897
+ if (isNaN(Number(v)))
1898
+ return null;
1899
+ return Number(v);
1900
+ }
1901
+ function toBoolean(v) {
1902
+ if (isEmpty(v))
1903
+ return null;
1904
+ return Boolean(v);
1905
+ }
1906
+ function isEmpty(v) {
1907
+ return v === null || v === undefined;
1908
+ }
1909
+ function supposeValue(v, def) {
1910
+ if (isEmpty(v))
1911
+ return def;
1912
+ return v;
1913
+ }
1914
+
1915
+
1916
+ /***/ },
1917
+
1918
+ /***/ "./plugins/file/src/backend/file_router.ts"
1919
+ (__unused_webpack_module, exports, __webpack_require__) {
1920
+
1921
+
1922
+ var __importDefault = (this && this.__importDefault) || function (mod) {
1923
+ return (mod && mod.__esModule) ? mod : { "default": mod };
1924
+ };
1925
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
1926
+ exports.registerFileEvents = registerFileEvents;
1927
+ const os_1 = __importDefault(__webpack_require__("os"));
1928
+ const file_service_1 = __webpack_require__("./plugins/file/src/backend/file_service.ts");
1929
+ const runtime_1 = __webpack_require__("./plugins/file/src/backend/runtime.ts");
1930
+ const upload_manager_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/upload_manager.ts"));
1931
+ const url_1 = __webpack_require__("./plugins/file/src/backend/url.ts");
1932
+ /**
1933
+ * Every `file/*` protocol event, plus the middleware that gates them.
1934
+ *
1935
+ * Registered from `apply()`, so all of it — the middleware included — leaves with
1936
+ * the plugin. The middleware runs after `plugins/auth`'s, which loads first.
1937
+ */
1938
+ function registerFileEvents() {
1939
+ // Some routers operate router authentication middleware
1940
+ (0, runtime_1.protocol)().use((event, ctx, data, next) => {
1941
+ if (event.startsWith("file/")) {
1942
+ const instanceUuid = data.instanceUuid;
1943
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(instanceUuid);
1944
+ if (!instance) {
1945
+ return (0, runtime_1.protocol)().error(ctx, event, {
1946
+ instanceUuid: instanceUuid,
1947
+ err: (0, runtime_1.$t)("TXT_CODE_file_router.instanceNotExist", { instanceUuid: instanceUuid })
1948
+ });
1949
+ }
1950
+ if ([(0, runtime_1.instances)().Instance.STATUS_BUSY, (0, runtime_1.instances)().Instance.STATUS_STARTING].includes(instance.status()) &&
1951
+ !["file/list", "file/status"].includes(event)) {
1952
+ return (0, runtime_1.protocol)().error(ctx, event, {
1953
+ instanceUuid: instanceUuid,
1954
+ err: (0, runtime_1.$t)("TXT_CODE_bbedcf29")
1955
+ });
1956
+ }
1957
+ }
1958
+ next();
1959
+ });
1960
+ // List the files in the specified instance working directory
1961
+ (0, runtime_1.protocol)().on("file/list", async (ctx, data) => {
1962
+ try {
1963
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
1964
+ const { page, pageSize, target, fileName } = data;
1965
+ fileManager.cd(target);
1966
+ const overview = await fileManager.list(page, pageSize, fileName);
1967
+ (0, runtime_1.protocol)().response(ctx, overview);
1968
+ }
1969
+ catch (error) {
1970
+ (0, runtime_1.protocol)().responseError(ctx, error);
1971
+ }
1972
+ });
1973
+ // Preview archive contents without extracting the archive
1974
+ (0, runtime_1.protocol)().on("file/preview", async (ctx, data) => {
1975
+ const maxFileTask = (0, runtime_1.settings)().config.maxFileTask;
1976
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(data.instanceUuid);
1977
+ let taskStarted = false;
1978
+ try {
1979
+ if (!instance)
1980
+ throw new Error((0, runtime_1.$t)("TXT_CODE_3bfb9e04"));
1981
+ if (instance.info.fileLock >= maxFileTask) {
1982
+ throw new Error((0, runtime_1.$t)("TXT_CODE_file_router.unzipLimit", {
1983
+ maxFileTask,
1984
+ fileLock: instance.info.fileLock
1985
+ }));
1986
+ }
1987
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
1988
+ instance.info.fileLock++;
1989
+ runtime_1.fileTasks.count++;
1990
+ taskStarted = true;
1991
+ const entries = await fileManager.previewArchive(data.target, data.code);
1992
+ (0, runtime_1.protocol)().response(ctx, { items: entries, total: entries.length });
1993
+ }
1994
+ catch (error) {
1995
+ (0, runtime_1.protocol)().responseError(ctx, error);
1996
+ }
1997
+ finally {
1998
+ if (instance && taskStarted) {
1999
+ instance.info.fileLock = Math.max(0, instance.info.fileLock - 1);
2000
+ runtime_1.fileTasks.count = Math.max(0, runtime_1.fileTasks.count - 1);
2001
+ }
2002
+ }
2003
+ });
2004
+ // File chmod (only Linux)
2005
+ (0, runtime_1.protocol)().on("file/chmod", async (ctx, data) => {
2006
+ try {
2007
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2008
+ const { chmod, target, deep } = data;
2009
+ await fileManager.chmod(target, chmod, deep);
2010
+ (0, runtime_1.protocol)().response(ctx, true);
2011
+ }
2012
+ catch (error) {
2013
+ (0, runtime_1.protocol)().responseError(ctx, error);
2014
+ }
2015
+ });
2016
+ (0, runtime_1.protocol)().on("file/chmod_batch", async (ctx, data) => {
2017
+ try {
2018
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2019
+ const { chmod, targets, deep: rawDeep } = data;
2020
+ const deep = Boolean(rawDeep);
2021
+ const results = [];
2022
+ let success = 0;
2023
+ let failed = 0;
2024
+ for (const target of targets || []) {
2025
+ const currentTarget = String(target);
2026
+ try {
2027
+ await fileManager.chmod(currentTarget, chmod, deep);
2028
+ success += 1;
2029
+ results.push({
2030
+ target: currentTarget,
2031
+ success: true
2032
+ });
2033
+ }
2034
+ catch (error) {
2035
+ failed += 1;
2036
+ results.push({
2037
+ target: currentTarget,
2038
+ success: false,
2039
+ error: error?.message || String(error)
2040
+ });
2041
+ }
2042
+ }
2043
+ (0, runtime_1.protocol)().response(ctx, {
2044
+ success,
2045
+ failed,
2046
+ total: results.length,
2047
+ results
2048
+ });
2049
+ }
2050
+ catch (error) {
2051
+ (0, runtime_1.protocol)().responseError(ctx, error);
2052
+ }
2053
+ });
2054
+ // Query the status of the file management system
2055
+ (0, runtime_1.protocol)().on("file/status", async (ctx, data) => {
2056
+ try {
2057
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(data.instanceUuid);
2058
+ if (!instance)
2059
+ throw new Error((0, runtime_1.$t)("TXT_CODE_3bfb9e04"));
2060
+ const downloads = (0, runtime_1.transfer)().downloads;
2061
+ const downloadTasks = [];
2062
+ if (downloads.task) {
2063
+ downloadTasks.push({
2064
+ path: downloads.task.path,
2065
+ total: downloads.task.total,
2066
+ current: downloads.task.current,
2067
+ status: downloads.task.status,
2068
+ error: downloads.task.error
2069
+ });
2070
+ }
2071
+ (0, runtime_1.protocol)().response(ctx, {
2072
+ instanceFileTask: instance.info.fileLock ?? 0,
2073
+ globalFileTask: runtime_1.fileTasks.count ?? 0,
2074
+ downloadFileFromURLTask: downloads.downloadingCount,
2075
+ downloadTasks,
2076
+ platform: os_1.default.platform(),
2077
+ isGlobalInstance: data.instanceUuid === (0, runtime_1.instances)().subsystem.GLOBAL_INSTANCE_UUID,
2078
+ disks: (0, file_service_1.getWindowsDisks)()
2079
+ });
2080
+ }
2081
+ catch (error) {
2082
+ (0, runtime_1.protocol)().responseError(ctx, error);
2083
+ }
2084
+ });
2085
+ // Create a new file
2086
+ (0, runtime_1.protocol)().on("file/create-text", async (ctx, data) => {
2087
+ try {
2088
+ if (typeof data.target !== "string" ||
2089
+ !data.target ||
2090
+ data.target.length > 1024 ||
2091
+ typeof data.text !== "string" ||
2092
+ Buffer.byteLength(data.text, "utf8") > 64 * 1024 ||
2093
+ /[\x00-\x08\x0b\x0c\x0e-\x1f\ufffd]/.test(data.text))
2094
+ throw new Error("Invalid text file request");
2095
+ const result = await (0, file_service_1.getFileManager)(data.instanceUuid).createTextFile(data.target, data.text);
2096
+ (0, runtime_1.protocol)().response(ctx, result);
2097
+ }
2098
+ catch (error) {
2099
+ (0, runtime_1.protocol)().responseError(ctx, error);
2100
+ }
2101
+ });
2102
+ (0, runtime_1.protocol)().on("file/remove-file", async (ctx, data) => {
2103
+ try {
2104
+ if (typeof data.target !== "string" || !data.target || data.target.length > 1024)
2105
+ throw new Error("Invalid file request");
2106
+ const result = await (0, file_service_1.getFileManager)(data.instanceUuid).removeFile(data.target);
2107
+ (0, runtime_1.protocol)().response(ctx, result);
2108
+ }
2109
+ catch (error) {
2110
+ (0, runtime_1.protocol)().responseError(ctx, error);
2111
+ }
2112
+ });
2113
+ (0, runtime_1.protocol)().on("file/touch", (ctx, data) => {
2114
+ try {
2115
+ const target = data.target;
2116
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2117
+ fileManager.newFile(target);
2118
+ (0, runtime_1.protocol)().response(ctx, true);
2119
+ }
2120
+ catch (error) {
2121
+ (0, runtime_1.protocol)().responseError(ctx, error);
2122
+ }
2123
+ });
2124
+ // Create a directory
2125
+ (0, runtime_1.protocol)().on("file/mkdir", (ctx, data) => {
2126
+ try {
2127
+ const target = data.target;
2128
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2129
+ fileManager.mkdir(target);
2130
+ (0, runtime_1.protocol)().response(ctx, true);
2131
+ }
2132
+ catch (error) {
2133
+ (0, runtime_1.protocol)().responseError(ctx, error);
2134
+ }
2135
+ });
2136
+ // download a file from url
2137
+ (0, runtime_1.protocol)().on("file/download_from_url", async (ctx, data) => {
2138
+ try {
2139
+ const url = data.url;
2140
+ const fileName = data.fileName;
2141
+ if (!(0, url_1.checkSafeUrl)(url) || (data.fallbackUrl && !(0, url_1.checkSafeUrl)(data.fallbackUrl))) {
2142
+ (0, runtime_1.protocol)().responseError(ctx, (0, runtime_1.$t)("TXT_CODE_3fe1b194"), {
2143
+ disablePrint: true
2144
+ });
2145
+ return;
2146
+ }
2147
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2148
+ if (!fileManager.checkPath(fileName))
2149
+ throw new Error("Access denied: Invalid destination");
2150
+ const targetPath = fileManager.toAbsolutePath(fileName);
2151
+ // Start download in background
2152
+ const fallbackUrl = data.fallbackUrl;
2153
+ const maxDownloadFromUrlFileCount = (0, runtime_1.settings)().config.maxDownloadFromUrlFileCount;
2154
+ if ((data.ifIdle === true && (0, runtime_1.transfer)().downloads.downloadingCount > 0) ||
2155
+ (maxDownloadFromUrlFileCount > 0 &&
2156
+ (0, runtime_1.transfer)().downloads.downloadingCount >= maxDownloadFromUrlFileCount)) {
2157
+ (0, runtime_1.protocol)().responseError(ctx, (0, runtime_1.$t)("TXT_CODE_821a742e", {
2158
+ count: data.ifIdle === true ? 1 : maxDownloadFromUrlFileCount
2159
+ }), {
2160
+ disablePrint: true
2161
+ });
2162
+ return;
2163
+ }
2164
+ (0, runtime_1.transfer)()
2165
+ .downloads.downloadFromUrl(url, targetPath, fallbackUrl)
2166
+ .catch((err) => {
2167
+ (0, runtime_1.logger)().error(`Download failed: ${url} -> ${targetPath}`, err);
2168
+ });
2169
+ (0, runtime_1.protocol)().response(ctx, {});
2170
+ }
2171
+ catch (error) {
2172
+ (0, runtime_1.protocol)().responseError(ctx, error);
2173
+ }
2174
+ });
2175
+ // stop download from url
2176
+ (0, runtime_1.protocol)().on("file/download_stop", (ctx, data) => {
2177
+ try {
2178
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2179
+ if (!fileManager.checkPath(data.fileName))
2180
+ throw new Error("Access denied: Invalid destination");
2181
+ const targetPath = fileManager.toAbsolutePath(data.fileName);
2182
+ const result = (0, runtime_1.transfer)().downloads.stop(targetPath);
2183
+ (0, runtime_1.protocol)().response(ctx, result);
2184
+ }
2185
+ catch (error) {
2186
+ (0, runtime_1.protocol)().responseError(ctx, error);
2187
+ }
2188
+ });
2189
+ // copy the file
2190
+ (0, runtime_1.protocol)().on("file/copy", async (ctx, data) => {
2191
+ try {
2192
+ // [["a.txt","b.txt"],["cxz","zzz"]]
2193
+ const targets = data.targets;
2194
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2195
+ for (const target of targets) {
2196
+ await fileManager.copy(target[0], target[1]);
2197
+ }
2198
+ (0, runtime_1.protocol)().response(ctx, true);
2199
+ }
2200
+ catch (error) {
2201
+ (0, runtime_1.protocol)().responseError(ctx, error);
2202
+ }
2203
+ });
2204
+ // move the file
2205
+ (0, runtime_1.protocol)().on("file/move", async (ctx, data) => {
2206
+ try {
2207
+ // [["a.txt","b.txt"],["cxz","zzz"]]
2208
+ const targets = data.targets;
2209
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2210
+ for (const target of targets) {
2211
+ await fileManager.move(target[0], target[1]);
2212
+ }
2213
+ (0, runtime_1.protocol)().response(ctx, true);
2214
+ }
2215
+ catch (error) {
2216
+ (0, runtime_1.protocol)().responseError(ctx, error);
2217
+ }
2218
+ });
2219
+ // Delete Files
2220
+ (0, runtime_1.protocol)().on("file/delete", async (ctx, data) => {
2221
+ try {
2222
+ const targets = data.targets;
2223
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2224
+ for (const target of targets) {
2225
+ const path = fileManager.toAbsolutePath(target);
2226
+ const uploadTask = upload_manager_1.default.getByPath(path);
2227
+ if (uploadTask != undefined) {
2228
+ upload_manager_1.default.delete(uploadTask.id);
2229
+ await uploadTask.writer.stop();
2230
+ }
2231
+ else {
2232
+ // async delete
2233
+ await fileManager.delete(target);
2234
+ }
2235
+ }
2236
+ (0, runtime_1.protocol)().response(ctx, true);
2237
+ }
2238
+ catch (error) {
2239
+ (0, runtime_1.protocol)().responseError(ctx, error);
2240
+ }
2241
+ });
2242
+ // edit file
2243
+ (0, runtime_1.protocol)().on("file/edit", async (ctx, data) => {
2244
+ try {
2245
+ const target = data.target;
2246
+ const text = data.text;
2247
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2248
+ const result = await fileManager.edit(target, text);
2249
+ (0, runtime_1.protocol)().response(ctx, result ? result : true);
2250
+ }
2251
+ catch (error) {
2252
+ (0, runtime_1.protocol)().responseError(ctx, error);
2253
+ }
2254
+ });
2255
+ // compress/decompress the file
2256
+ (0, runtime_1.protocol)().on("file/compress", async (ctx, data) => {
2257
+ const maxFileTask = (0, runtime_1.settings)().config.maxFileTask;
2258
+ try {
2259
+ const source = data.source;
2260
+ const targets = data.targets;
2261
+ const type = data.type;
2262
+ const code = data.code;
2263
+ const fileManager = (0, file_service_1.getFileManager)(data.instanceUuid);
2264
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(data.instanceUuid);
2265
+ if (!instance)
2266
+ throw new Error((0, runtime_1.$t)("TXT_CODE_3bfb9e04"));
2267
+ if (instance.info.fileLock >= maxFileTask) {
2268
+ throw new Error((0, runtime_1.$t)("TXT_CODE_file_router.unzipLimit", {
2269
+ maxFileTask: maxFileTask,
2270
+ fileLock: instance.info.fileLock
2271
+ }));
2272
+ }
2273
+ // Statistics of the number of tasks in a single instance file and the number of tasks in the entire daemon process
2274
+ function fileTaskStart() {
2275
+ if (instance) {
2276
+ instance.info.fileLock++;
2277
+ runtime_1.fileTasks.count++;
2278
+ }
2279
+ }
2280
+ function fileTaskEnd() {
2281
+ if (instance) {
2282
+ instance.info.fileLock--;
2283
+ runtime_1.fileTasks.count--;
2284
+ }
2285
+ }
2286
+ // start decompressing or compressing the file
2287
+ fileTaskStart();
2288
+ try {
2289
+ if (type === 1) {
2290
+ await fileManager.zip(source, targets, code);
2291
+ }
2292
+ else {
2293
+ await fileManager.unzip(source, targets, code);
2294
+ }
2295
+ (0, runtime_1.protocol)().response(ctx, true);
2296
+ }
2297
+ catch (error) {
2298
+ throw error;
2299
+ }
2300
+ finally {
2301
+ fileTaskEnd();
2302
+ }
2303
+ }
2304
+ catch (error) {
2305
+ (0, runtime_1.protocol)().responseError(ctx, error);
2306
+ }
2307
+ });
2308
+ }
2309
+
2310
+
2311
+ /***/ },
2312
+
2313
+ /***/ "./plugins/file/src/backend/file_service.ts"
2314
+ (__unused_webpack_module, exports, __webpack_require__) {
2315
+
2316
+
2317
+ var __importDefault = (this && this.__importDefault) || function (mod) {
2318
+ return (mod && mod.__esModule) ? mod : { "default": mod };
2319
+ };
2320
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2321
+ exports.getFileManager = getFileManager;
2322
+ exports.getWindowsDisks = getWindowsDisks;
2323
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
2324
+ const system_file_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/system_file.ts"));
2325
+ const runtime_1 = __webpack_require__("./plugins/file/src/backend/runtime.ts");
2326
+ const os_1 = __importDefault(__webpack_require__("os"));
2327
+ function getFileManager(instanceUuid) {
2328
+ // Initialize a file manager for the instance, and assign codes, restrictions, etc.
2329
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(instanceUuid);
2330
+ if (!instance)
2331
+ throw new Error((0, runtime_1.$t)("TXT_CODE_file_router_service.instanceNotExit", { uuid: instanceUuid }));
2332
+ const fileCode = instance.config?.fileCode;
2333
+ return new system_file_1.default(instance.absoluteCwdPath(), fileCode);
2334
+ }
2335
+ let cacheDisks = [];
2336
+ function getWindowsDisks() {
2337
+ if (os_1.default.platform() !== "win32")
2338
+ return [];
2339
+ if (cacheDisks.length > 0)
2340
+ return cacheDisks;
2341
+ const res = [];
2342
+ // A - Z
2343
+ for (let i = 65; i <= 90; i++) {
2344
+ const letter = String.fromCharCode(i);
2345
+ try {
2346
+ if (fs_extra_1.default.existsSync(`${letter}:\\`))
2347
+ res.push(letter);
2348
+ }
2349
+ catch (error) {
2350
+ // ignore error
2351
+ }
2352
+ }
2353
+ cacheDisks = res;
2354
+ return res;
2355
+ }
2356
+
2357
+
2358
+ /***/ },
2359
+
2360
+ /***/ "./plugins/file/src/backend/file_writer.ts"
2361
+ (__unused_webpack_module, exports, __webpack_require__) {
2362
+
2363
+
2364
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
2365
+ if (k2 === undefined) k2 = k;
2366
+ var desc = Object.getOwnPropertyDescriptor(m, k);
2367
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
2368
+ desc = { enumerable: true, get: function() { return m[k]; } };
2369
+ }
2370
+ Object.defineProperty(o, k2, desc);
2371
+ }) : (function(o, m, k, k2) {
2372
+ if (k2 === undefined) k2 = k;
2373
+ o[k2] = m[k];
2374
+ }));
2375
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
2376
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
2377
+ }) : function(o, v) {
2378
+ o["default"] = v;
2379
+ });
2380
+ var __importStar = (this && this.__importStar) || (function () {
2381
+ var ownKeys = function(o) {
2382
+ ownKeys = Object.getOwnPropertyNames || function (o) {
2383
+ var ar = [];
2384
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
2385
+ return ar;
2386
+ };
2387
+ return ownKeys(o);
2388
+ };
2389
+ return function (mod) {
2390
+ if (mod && mod.__esModule) return mod;
2391
+ var result = {};
2392
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
2393
+ __setModuleDefault(result, mod);
2394
+ return result;
2395
+ };
2396
+ })();
2397
+ var __importDefault = (this && this.__importDefault) || function (mod) {
2398
+ return (mod && mod.__esModule) ? mod : { "default": mod };
2399
+ };
2400
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2401
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
2402
+ const path_1 = __importDefault(__webpack_require__("path"));
2403
+ const lockfile = __importStar(__webpack_require__("proper-lockfile"));
2404
+ const system_file_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/system_file.ts"));
2405
+ const runtime_1 = __webpack_require__("./plugins/file/src/backend/runtime.ts");
2406
+ const upload_manager_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/upload_manager.ts"));
2407
+ class FileWriter {
2408
+ cwd;
2409
+ filename;
2410
+ size;
2411
+ unzip;
2412
+ zipCode;
2413
+ path;
2414
+ id;
2415
+ releaseLock;
2416
+ fd = null;
2417
+ operations = Promise.resolve();
2418
+ completed = false;
2419
+ received = [];
2420
+ lastUpdate = Date.now();
2421
+ onFinish;
2422
+ get cancellable() {
2423
+ return !this.completed;
2424
+ }
2425
+ constructor(cwd, filename, size, unzip, zipCode, filePath) {
2426
+ this.cwd = cwd;
2427
+ this.filename = filename;
2428
+ this.size = size;
2429
+ this.unzip = unzip;
2430
+ this.zipCode = zipCode;
2431
+ if (!system_file_1.default.checkFileName(path_1.default.basename(this.filename)))
2432
+ throw new Error("Access denied: Malformed file name");
2433
+ if (!Number.isSafeInteger(size) || size < 0)
2434
+ throw new Error("Invalid file size");
2435
+ this.path = filePath;
2436
+ }
2437
+ static async getPath(cwd, dir, filename, overwrite) {
2438
+ const fileManager = new system_file_1.default(cwd);
2439
+ const ext = path_1.default.extname(filename);
2440
+ const basename = path_1.default.basename(filename, ext);
2441
+ let tempFileSaveName = basename + ext;
2442
+ let counter = 1;
2443
+ const checkFile = async (name) => {
2444
+ const absolutePath = fileManager.toAbsolutePath(path_1.default.normalize(path_1.default.join(dir, name)));
2445
+ const isLock = await lockfile
2446
+ .check(absolutePath)
2447
+ .then((isLock) => isLock)
2448
+ .catch(() => false);
2449
+ const isAccess = await fs_extra_1.default
2450
+ .access(absolutePath)
2451
+ .then(() => true)
2452
+ .catch(() => false);
2453
+ return isAccess && !isLock && !overwrite;
2454
+ };
2455
+ while (await checkFile(tempFileSaveName)) {
2456
+ if (counter == 1) {
2457
+ tempFileSaveName = `${basename}-copy${ext}`;
2458
+ }
2459
+ else {
2460
+ tempFileSaveName = `${basename}-copy-${counter}${ext}`;
2461
+ }
2462
+ counter++;
2463
+ if (counter > 100) {
2464
+ throw new Error("Access denied: File name already exists!");
2465
+ }
2466
+ }
2467
+ const fileSaveRelativePath = path_1.default.normalize(path_1.default.join(dir, tempFileSaveName));
2468
+ if (!fileManager.checkPath(fileSaveRelativePath))
2469
+ throw new Error("Access denied: Invalid destination");
2470
+ return fileManager.toAbsolutePath(fileSaveRelativePath);
2471
+ }
2472
+ async init() {
2473
+ if (this.fd != null)
2474
+ return;
2475
+ try {
2476
+ // Lock before opening with w+: a competing upload must not truncate the file.
2477
+ this.releaseLock = await lockfile.lock(this.path, { realpath: false });
2478
+ this.fd = await fs_extra_1.default.open(this.path, "w+");
2479
+ await fs_extra_1.default.ftruncate(this.fd, this.size);
2480
+ }
2481
+ catch (e) {
2482
+ try {
2483
+ await this.close();
2484
+ }
2485
+ finally {
2486
+ await this.unlock();
2487
+ }
2488
+ throw e;
2489
+ }
2490
+ }
2491
+ enqueue(operation) {
2492
+ const pending = this.operations.then(operation);
2493
+ this.operations = pending.catch(() => { });
2494
+ return pending;
2495
+ }
2496
+ write(offset, chunk) {
2497
+ return this.enqueue(async () => {
2498
+ if (!Number.isSafeInteger(offset) || offset < 0 || offset + chunk.length > this.size) {
2499
+ throw new Error("Write exceeds file size limit");
2500
+ }
2501
+ if (this.fd === null || this.completed)
2502
+ throw new Error("File is not opened");
2503
+ this.lastUpdate = Date.now();
2504
+ let written = 0;
2505
+ while (written < chunk.length) {
2506
+ const { bytesWritten } = await fs_extra_1.default.write(this.fd, chunk, written, chunk.length - written, offset + written);
2507
+ if (bytesWritten === 0)
2508
+ throw new Error("Unable to write upload chunk");
2509
+ written += bytesWritten;
2510
+ }
2511
+ this.addWrittenRange(offset, offset + chunk.length);
2512
+ if (this.isFullyCovered())
2513
+ await this.finish(false);
2514
+ });
2515
+ }
2516
+ done() {
2517
+ return this.enqueue(() => this.finish(false));
2518
+ }
2519
+ stop() {
2520
+ return this.enqueue(() => this.finish(true));
2521
+ }
2522
+ async close() {
2523
+ const fd = this.fd;
2524
+ this.fd = null;
2525
+ if (fd != null)
2526
+ await fs_extra_1.default.close(fd);
2527
+ }
2528
+ async unlock() {
2529
+ const releaseLock = this.releaseLock;
2530
+ this.releaseLock = undefined;
2531
+ await releaseLock?.();
2532
+ }
2533
+ async finish(cancelled) {
2534
+ if (this.completed)
2535
+ return;
2536
+ this.completed = true;
2537
+ let failure;
2538
+ try {
2539
+ await this.close();
2540
+ if (cancelled) {
2541
+ await fs_extra_1.default.remove(this.path);
2542
+ (0, runtime_1.logger)().info("Browser Upload Task Stopped:", this.path);
2543
+ }
2544
+ else {
2545
+ (0, runtime_1.logger)().info("Browser Uploaded File:", this.path);
2546
+ if (this.unzip) {
2547
+ const instanceFiles = new system_file_1.default(this.cwd);
2548
+ await instanceFiles.unzip(this.path, ".", this.zipCode);
2549
+ (0, runtime_1.logger)().info("File unzipped:", this.path);
2550
+ }
2551
+ }
2552
+ }
2553
+ catch (error) {
2554
+ failure = error;
2555
+ throw error;
2556
+ }
2557
+ finally {
2558
+ try {
2559
+ // Keep ownership until removal/extraction completes, so a newer upload
2560
+ // cannot start using the same path while this task is still changing it.
2561
+ await this.unlock();
2562
+ }
2563
+ catch (error) {
2564
+ failure ||= error;
2565
+ throw error;
2566
+ }
2567
+ finally {
2568
+ if (this.id != null)
2569
+ upload_manager_1.default.delete(this.id);
2570
+ this.onFinish?.(failure, cancelled);
2571
+ }
2572
+ }
2573
+ }
2574
+ addWrittenRange(start, end) {
2575
+ if (start >= end)
2576
+ return;
2577
+ let i = 0;
2578
+ let ranges = this.received;
2579
+ while (i < ranges.length && ranges[i].end < start)
2580
+ i++;
2581
+ let mergeStart = start, mergeEnd = end;
2582
+ let removeCount = 0;
2583
+ while (i + removeCount < ranges.length && ranges[i + removeCount].start <= mergeEnd) {
2584
+ mergeStart = Math.min(mergeStart, ranges[i + removeCount].start);
2585
+ mergeEnd = Math.max(mergeEnd, ranges[i + removeCount].end);
2586
+ removeCount++;
2587
+ }
2588
+ ranges.splice(i, removeCount, { start: mergeStart, end: mergeEnd });
2589
+ }
2590
+ isFullyCovered() {
2591
+ return (this.received.length === 1 &&
2592
+ this.received[0].start === 0 &&
2593
+ this.received[0].end === this.size);
2594
+ }
2595
+ }
2596
+ exports["default"] = FileWriter;
2597
+
2598
+
2599
+ /***/ },
2600
+
2601
+ /***/ "./plugins/file/src/backend/filepath.ts"
2602
+ (__unused_webpack_module, exports, __webpack_require__) {
2603
+
2604
+
2605
+ var __importDefault = (this && this.__importDefault) || function (mod) {
2606
+ return (mod && mod.__esModule) ? mod : { "default": mod };
2607
+ };
2608
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2609
+ exports.checkFileName = checkFileName;
2610
+ exports.clearUploadFiles = clearUploadFiles;
2611
+ exports.normalizedJoin = normalizedJoin;
2612
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
2613
+ const os_1 = __importDefault(__webpack_require__("os"));
2614
+ const path_1 = __importDefault(__webpack_require__("path"));
2615
+ function checkFileName(fileName) {
2616
+ return (typeof fileName === "string" &&
2617
+ fileName.length > 0 &&
2618
+ fileName !== "." &&
2619
+ fileName !== ".." &&
2620
+ !/[\\/|?*><;":\0]/.test(fileName));
2621
+ }
2622
+ function clearUploadFiles(file) {
2623
+ if (!file)
2624
+ return;
2625
+ if (file instanceof Array) {
2626
+ file.forEach((v) => {
2627
+ fs_extra_1.default.remove(v.filepath, () => { });
2628
+ });
2629
+ }
2630
+ else {
2631
+ fs_extra_1.default.remove(file.filepath, () => { });
2632
+ }
2633
+ }
2634
+ function normalizedJoin(...paths) {
2635
+ if (os_1.default.platform() === "win32") {
2636
+ return joinWin32(...paths);
2637
+ }
2638
+ return path_1.default.normalize(path_1.default.join(...paths));
2639
+ }
2640
+ function joinWin32(...paths) {
2641
+ if (!paths.length)
2642
+ return ".";
2643
+ if (paths.length == 1)
2644
+ return paths[0];
2645
+ const parts = path_1.default.win32.parse(paths[1]);
2646
+ let p;
2647
+ if (parts.root) {
2648
+ p = paths[1];
2649
+ }
2650
+ else {
2651
+ p = path_1.default.normalize(path_1.default.join(paths[0], paths[1]));
2652
+ }
2653
+ if (paths.length <= 2)
2654
+ return p;
2655
+ return joinWin32(p, ...paths.slice(2));
2656
+ }
2657
+
2658
+
2659
+ /***/ },
2660
+
2661
+ /***/ "./plugins/file/src/backend/http_router.ts"
2662
+ (__unused_webpack_module, exports, __webpack_require__) {
2663
+
2664
+
2665
+ var __importDefault = (this && this.__importDefault) || function (mod) {
2666
+ return (mod && mod.__esModule) ? mod : { "default": mod };
2667
+ };
2668
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2669
+ exports.registerHttpRoutes = registerHttpRoutes;
2670
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
2671
+ const path_1 = __importDefault(__webpack_require__("path"));
2672
+ const file_writer_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/file_writer.ts"));
2673
+ const filepath_1 = __webpack_require__("./plugins/file/src/backend/filepath.ts");
2674
+ const runtime_1 = __webpack_require__("./plugins/file/src/backend/runtime.ts");
2675
+ const system_file_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/system_file.ts"));
2676
+ const upload_manager_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/upload_manager.ts"));
2677
+ /**
2678
+ * The upload and download HTTP routes.
2679
+ *
2680
+ * Both are authorized by a passport the panel registered over the protocol first
2681
+ * — the server plugin issues those (`passport/register`) — and the upload routes
2682
+ * sit behind the runtime plugin's upload middleware, which the web server mounts ahead of
2683
+ * the body parser.
2684
+ */
2685
+ function registerHttpRoutes() {
2686
+ const router = (0, runtime_1.core)().koa.router();
2687
+ // File download route
2688
+ router.get("/download/:key/:fileName", async (ctx) => {
2689
+ const key = ctx.params.key;
2690
+ const paramsFileName = ctx.params.fileName;
2691
+ try {
2692
+ // Get the task from the task center
2693
+ const mission = (0, runtime_1.transfer)().passports.getMission(key, "download");
2694
+ if (!mission)
2695
+ throw new Error((ctx.body = "Access denied: No task found"));
2696
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(mission.parameter.instanceUuid);
2697
+ if (!instance)
2698
+ throw new Error((0, runtime_1.$t)("TXT_CODE_http_router.instanceNotExist"));
2699
+ if (!system_file_1.default.checkFileName(paramsFileName))
2700
+ throw new Error((0, runtime_1.$t)("TXT_CODE_http_router.fileNameNotSpec"));
2701
+ const cwd = instance.absoluteCwdPath();
2702
+ const fileRelativePath = mission.parameter.fileName;
2703
+ // Check for file cross-directory security risks
2704
+ const fileManager = new system_file_1.default(cwd);
2705
+ if (!fileManager.check(fileRelativePath))
2706
+ throw new Error((ctx.body = "Access denied: Invalid destination"));
2707
+ const fileAbsPath = fileManager.toAbsolutePath(fileRelativePath);
2708
+ await (0, runtime_1.transfer)().sendFile(ctx, fileAbsPath);
2709
+ }
2710
+ catch (error) {
2711
+ if (!ctx.res.headersSent) {
2712
+ ctx.body = (0, runtime_1.$t)("TXT_CODE_http_router.downloadErr", { error: error.message });
2713
+ ctx.status = 500;
2714
+ }
2715
+ }
2716
+ finally {
2717
+ (0, runtime_1.transfer)().passports.deleteMission(key);
2718
+ }
2719
+ });
2720
+ // Old version upload route
2721
+ router.post("/upload/:key", async (ctx) => {
2722
+ const key = String(ctx.params.key);
2723
+ const unzip = ctx.query.unzip === "true";
2724
+ const zipCode = String(ctx.query.code);
2725
+ const tmpFiles = ctx.request.files?.file;
2726
+ try {
2727
+ const mission = (0, runtime_1.transfer)().passports.getMission(key, "upload");
2728
+ if (!mission)
2729
+ throw new Error("Access denied: No task found");
2730
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(mission.parameter.instanceUuid);
2731
+ if (!instance)
2732
+ throw new Error("Access denied: No instance found");
2733
+ const uploadDir = mission.parameter.uploadDir;
2734
+ const cwd = instance.absoluteCwdPath();
2735
+ if (tmpFiles) {
2736
+ let uploadedFile;
2737
+ if (tmpFiles instanceof Array) {
2738
+ uploadedFile = tmpFiles[0];
2739
+ }
2740
+ else if (tmpFiles) {
2741
+ uploadedFile = tmpFiles;
2742
+ }
2743
+ else {
2744
+ throw new Error("Empty File!");
2745
+ }
2746
+ const originFileName = uploadedFile.originalFilename || "";
2747
+ if (!system_file_1.default.checkFileName(path_1.default.basename(originFileName)))
2748
+ throw new Error("Access denied: Malformed file name");
2749
+ const fileManager = new system_file_1.default(cwd);
2750
+ const ext = path_1.default.extname(originFileName);
2751
+ const basename = path_1.default.basename(originFileName, ext);
2752
+ let tempFileSaveName = basename + ext;
2753
+ let counter = 1;
2754
+ while (fs_extra_1.default.existsSync(fileManager.toAbsolutePath(path_1.default.normalize(path_1.default.join(uploadDir, tempFileSaveName)))) &&
2755
+ ctx.query.overwrite === "false") {
2756
+ if (counter == 1) {
2757
+ tempFileSaveName = `${basename}-copy${ext}`;
2758
+ }
2759
+ else {
2760
+ tempFileSaveName = `${basename}-copy-${counter}${ext}`;
2761
+ }
2762
+ counter++;
2763
+ }
2764
+ let fileSaveRelativePath = path_1.default.normalize(path_1.default.join(uploadDir, tempFileSaveName));
2765
+ if (!fileManager.checkPath(fileSaveRelativePath))
2766
+ throw new Error("Access denied: Invalid destination");
2767
+ const fileSaveAbsolutePath = fileManager.toAbsolutePath(fileSaveRelativePath);
2768
+ await fs_extra_1.default.move(uploadedFile.filepath, fileSaveAbsolutePath, {
2769
+ overwrite: true
2770
+ });
2771
+ if (unzip) {
2772
+ const instanceFiles = new system_file_1.default(instance.absoluteCwdPath());
2773
+ await instanceFiles.unzip(fileSaveAbsolutePath, ".", zipCode);
2774
+ }
2775
+ ctx.body = "OK";
2776
+ return;
2777
+ }
2778
+ ctx.body = "Access denied: No file found";
2779
+ ctx.status = 500;
2780
+ }
2781
+ catch (error) {
2782
+ ctx.body = error.message;
2783
+ ctx.status = 500;
2784
+ }
2785
+ finally {
2786
+ (0, runtime_1.transfer)().passports.deleteMission(key);
2787
+ if (tmpFiles)
2788
+ (0, filepath_1.clearUploadFiles)(tmpFiles);
2789
+ }
2790
+ });
2791
+ router.post("/upload-new/:key", async (ctx) => {
2792
+ const key = String(ctx.params.key);
2793
+ const unzip = ctx.query.unzip === "true";
2794
+ const zipCode = String(ctx.query.code);
2795
+ const filename = String(ctx.query.filename);
2796
+ const size = Number(ctx.query.size);
2797
+ if (ctx.query.stop) {
2798
+ const writer = upload_manager_1.default.get(key);
2799
+ if (writer) {
2800
+ await writer.stop();
2801
+ upload_manager_1.default.delete(key);
2802
+ ctx.body = "OK";
2803
+ return;
2804
+ }
2805
+ else {
2806
+ ctx.body = "Access denied: No task found";
2807
+ ctx.status = 500;
2808
+ return;
2809
+ }
2810
+ }
2811
+ try {
2812
+ const mission = (0, runtime_1.transfer)().passports.getMission(key, "upload");
2813
+ if (!mission)
2814
+ throw new Error("Access denied: No task found");
2815
+ const instance = (0, runtime_1.instances)().subsystem.getInstance(mission.parameter.instanceUuid);
2816
+ if (!instance)
2817
+ throw new Error("Access denied: No instance found");
2818
+ const uploadDir = mission.parameter.uploadDir;
2819
+ const cwd = instance.absoluteCwdPath();
2820
+ const overwrite = ctx.query.overwrite !== "false";
2821
+ if (!Number.isSafeInteger(size) || size < 0)
2822
+ throw new Error("Invalid file size");
2823
+ const filePath = await file_writer_1.default.getPath(cwd, uploadDir, filename, overwrite);
2824
+ let fr = upload_manager_1.default.getByPath(filePath);
2825
+ if (fr && size != fr.writer.size) {
2826
+ upload_manager_1.default.delete(fr.id);
2827
+ await fr.writer.stop();
2828
+ fr = undefined;
2829
+ }
2830
+ if (!fr) {
2831
+ const fileWriter = new file_writer_1.default(cwd, filename, size, unzip, zipCode, filePath);
2832
+ await fileWriter.init();
2833
+ const id = upload_manager_1.default.add(fileWriter);
2834
+ fr = { id, writer: fileWriter };
2835
+ const tasks = (0, runtime_1.core)().get("backgroundTasks");
2836
+ tasks?.runRequest(unzip ? "file/upload_extract" : "file/upload", {
2837
+ _taskOwner: mission.parameter._taskOwner,
2838
+ instanceUuid: mission.parameter.instanceUuid,
2839
+ fileName: filename
2840
+ }, () => {
2841
+ tasks.progress(() => ({
2842
+ current: fileWriter.received.reduce((sum, range) => sum + range.end - range.start, 0),
2843
+ total: size,
2844
+ cancellable: fileWriter.cancellable
2845
+ }), () => { void fileWriter.stop().catch((err) => (0, runtime_1.core)().logger.warn(err)); });
2846
+ tasks.follow(new Promise((resolve, reject) => {
2847
+ fileWriter.onFinish = (error, cancelled) => {
2848
+ if (error)
2849
+ reject(error);
2850
+ else if (cancelled)
2851
+ reject(Object.assign(new Error("Upload cancelled"), { code: "ABORT_ERR" }));
2852
+ else
2853
+ resolve();
2854
+ };
2855
+ }));
2856
+ });
2857
+ }
2858
+ if (size === 0)
2859
+ await fr.writer.done();
2860
+ ctx.body = {
2861
+ data: {
2862
+ id: fr.id,
2863
+ received: fr.writer.received
2864
+ },
2865
+ status: 200
2866
+ };
2867
+ return;
2868
+ }
2869
+ catch (error) {
2870
+ ctx.body = error.message;
2871
+ ctx.status = 500;
2872
+ }
2873
+ finally {
2874
+ (0, runtime_1.transfer)().passports.deleteMission(key);
2875
+ }
2876
+ });
2877
+ router.post("/upload-piece/:id", async (ctx) => {
2878
+ const id = String(ctx.params.id);
2879
+ const offset = Number(ctx.query.offset);
2880
+ const tmpFiles = ctx.request.files?.file;
2881
+ try {
2882
+ if (!tmpFiles) {
2883
+ ctx.body = "Access denied: No file found";
2884
+ ctx.status = 500;
2885
+ }
2886
+ let uploadedFile;
2887
+ if (tmpFiles instanceof Array) {
2888
+ uploadedFile = tmpFiles[0];
2889
+ }
2890
+ else if (tmpFiles) {
2891
+ uploadedFile = tmpFiles;
2892
+ }
2893
+ else {
2894
+ throw new Error("Empty File!");
2895
+ }
2896
+ const writer = upload_manager_1.default.get(id);
2897
+ if (!writer)
2898
+ throw new Error("Access denied: No task found");
2899
+ const chunk = await fs_extra_1.default.readFile(uploadedFile.filepath);
2900
+ await writer.write(offset, chunk);
2901
+ ctx.body = "OK";
2902
+ return;
2903
+ }
2904
+ catch (error) {
2905
+ ctx.body = error.message;
2906
+ ctx.status = 500;
2907
+ }
2908
+ finally {
2909
+ (0, filepath_1.clearUploadFiles)(tmpFiles);
2910
+ }
2911
+ });
2912
+ }
2913
+
2914
+
2915
+ /***/ },
2916
+
2917
+ /***/ "./plugins/file/src/backend/index.ts"
2918
+ (__unused_webpack_module, exports, __webpack_require__) {
2919
+
2920
+
2921
+ var __importDefault = (this && this.__importDefault) || function (mod) {
2922
+ return (mod && mod.__esModule) ? mod : { "default": mod };
2923
+ };
2924
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2925
+ exports.inject = void 0;
2926
+ exports.apply = apply;
2927
+ const i18n_1 = __webpack_require__("./plugins/file/src/i18n/index.ts");
2928
+ const file_router_1 = __webpack_require__("./plugins/file/src/backend/file_router.ts");
2929
+ const file_service_1 = __webpack_require__("./plugins/file/src/backend/file_service.ts");
2930
+ const http_router_1 = __webpack_require__("./plugins/file/src/backend/http_router.ts");
2931
+ const runtime_1 = __webpack_require__("./plugins/file/src/backend/runtime.ts");
2932
+ const system_file_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/system_file.ts"));
2933
+ const upload_manager_1 = __importDefault(__webpack_require__("./plugins/file/src/backend/upload_manager.ts"));
2934
+ const settings_1 = __webpack_require__("./plugins/file/src/backend/settings.ts");
2935
+ // The daemon's file subsystem.
2936
+ //
2937
+ // Everything about reading and writing instance files lives here: the
2938
+ // `FileManager` that resolves and sandboxes a path, the chunked upload manager,
2939
+ // the fourteen `file/*` protocol events and the upload/download HTTP routes.
2940
+ //
2941
+ // The primitives are handed to the rest of the daemon as `ctx.files`, because
2942
+ // instance creation, the Java manager, SteamCMD and the mod service all need to
2943
+ // touch files too. Consumers resolve the service through their plugin context,
2944
+ // so removing this plugin removes the daemon's
2945
+ // ability to touch instance files rather than breaking the build.
2946
+ // File routes resolve the instance service when a request arrives. Keeping the
2947
+ // dependency lazy avoids a startup cycle: the instance plugin depends on the
2948
+ // file primitives, while the file routes only need instances at request time.
2949
+ exports.inject = {
2950
+ i18n: { required: true },
2951
+ settings: { required: true },
2952
+ protocol: { required: true },
2953
+ archive: { required: true },
2954
+ transfer: { required: true },
2955
+ koa: { required: true },
2956
+ // File routes resolve the instance subsystem lazily to avoid a startup
2957
+ // cycle: the instance plugin requires the file service in return.
2958
+ instances: { required: false }
2959
+ };
2960
+ function apply(ctx) {
2961
+ // Before anything else: the modules below read the logger, the configuration,
2962
+ // the instances and `$t` through this handle.
2963
+ (0, runtime_1.setPluginContext)(ctx);
2964
+ ctx.i18n.define(i18n_1.localeMessages);
2965
+ (0, settings_1.registerSettings)(ctx);
2966
+ // `ctx.set()` from inside a plugin belongs to that plugin: the primitives — and
2967
+ // with them the daemon's access to instance files — leave when it unloads.
2968
+ ctx.set("files", {
2969
+ FileManager: system_file_1.default,
2970
+ uploads: upload_manager_1.default,
2971
+ getFileManager: file_service_1.getFileManager,
2972
+ getWindowsDisks: file_service_1.getWindowsDisks
2973
+ });
2974
+ (0, file_router_1.registerFileEvents)();
2975
+ (0, http_router_1.registerHttpRoutes)();
2976
+ // Chunked uploads hold open file handles and lock files, so they are stopped
2977
+ // with the plugin. The daemon used to do this from its own shutdown path.
2978
+ ctx.on("dispose", () => upload_manager_1.default.exit());
2979
+ }
2980
+
2981
+
2982
+ /***/ },
2983
+
2984
+ /***/ "./plugins/file/src/backend/runtime.ts"
2985
+ (__unused_webpack_module, exports) {
2986
+
2987
+
2988
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2989
+ exports.fileTasks = exports.instances = exports.$t = exports.transfer = exports.archive = exports.protocol = exports.settings = exports.logger = void 0;
2990
+ exports.setPluginContext = setPluginContext;
2991
+ exports.core = core;
2992
+ /**
2993
+ * This plugin's private handle on its cordis context.
2994
+ *
2995
+ * The daemon core is bundled into `app.js`, so a plugin cannot import its
2996
+ * singletons. The only channel is the context `apply()` receives, and this
2997
+ * plugin is six modules deep — a `FileManager` throws translated errors, a
2998
+ * `FileWriter` logs from inside a stream callback — so threading a parameter
2999
+ * through all of them would say nothing the accessors below do not.
3000
+ *
3001
+ * A plugin with only a handful of such call sites should pass `ctx` as an
3002
+ * argument instead.
3003
+ */
3004
+ let context;
3005
+ function setPluginContext(value) {
3006
+ context = value;
3007
+ }
3008
+ function core() {
3009
+ if (!context)
3010
+ throw new Error("The file plugin has not been initialized yet.");
3011
+ return context;
3012
+ }
3013
+ /**
3014
+ * `ctx.logger` is bound to this plugin's own cordis scope, so it is gone once
3015
+ * that scope is disposed — and the disposer stops every upload, a path that
3016
+ * logs. Shutting down must not fail on a log line.
3017
+ */
3018
+ const SILENT = {
3019
+ info() { },
3020
+ warn() { },
3021
+ error() { },
3022
+ debug() { },
3023
+ success() { },
3024
+ extend: () => SILENT
3025
+ };
3026
+ const logger = () => core().logger ?? SILENT;
3027
+ exports.logger = logger;
3028
+ const settings = () => core().settings;
3029
+ exports.settings = settings;
3030
+ const protocol = () => core().protocol;
3031
+ exports.protocol = protocol;
3032
+ const archive = () => core().archive;
3033
+ exports.archive = archive;
3034
+ const transfer = () => core().transfer;
3035
+ exports.transfer = transfer;
3036
+ const $t = (key, options) => (core().get("i18n")?.$t(key, options) ?? key);
3037
+ exports.$t = $t;
3038
+ /**
3039
+ * The file plugin can load before the instance plugin. `get()` avoids Cordis'
3040
+ * undeclared-property warning while keeping the existing lazy dependency.
3041
+ */
3042
+ const instances = () => {
3043
+ const service = core().get("instances");
3044
+ if (!service)
3045
+ throw new Error("Instance access requires the daemon instance plugin.");
3046
+ return service;
3047
+ };
3048
+ exports.instances = instances;
3049
+ /**
3050
+ * How many file tasks are running across the whole daemon. It used to be
3051
+ * `globalEnv` in the core's configuration module, read by nothing but the file
3052
+ * routes, so it lives with them now.
3053
+ */
3054
+ exports.fileTasks = { count: 0 };
3055
+
3056
+
3057
+ /***/ },
3058
+
3059
+ /***/ "./plugins/file/src/backend/settings.ts"
3060
+ (__unused_webpack_module, exports) {
3061
+
3062
+
3063
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
3064
+ exports.registerSettings = registerSettings;
3065
+ function registerSettings(ctx) {
3066
+ const config = ctx.settings.config;
3067
+ const $t = ctx.i18n.$t;
3068
+ const speedOptions = (current) => [...new Set([0, 5, 10, 16, 32, 64, 96, 128, 160, 240, 320, 480, current])].map((value) => ({
3069
+ value,
3070
+ label: value === 0
3071
+ ? $t("TXT_CODE_e3a77a77")
3072
+ : value < 16
3073
+ ? `${value * 64}KB/s`
3074
+ : `${value / 16}MB/s`
3075
+ }));
3076
+ ctx.inject(["settingsForm"], (settingsCtx) => settingsCtx.settingsForm.declare({
3077
+ fields: () => [
3078
+ {
3079
+ key: "uploadSpeedRate",
3080
+ type: "select",
3081
+ title: $t("TXT_CODE_fde31068"),
3082
+ description: $t("TXT_CODE_d8d19932"),
3083
+ options: speedOptions(config.uploadSpeedRate)
3084
+ },
3085
+ {
3086
+ key: "downloadSpeedRate",
3087
+ type: "select",
3088
+ title: $t("TXT_CODE_785a0fcf"),
3089
+ description: $t("TXT_CODE_b9fc604c"),
3090
+ options: speedOptions(config.downloadSpeedRate)
3091
+ },
3092
+ {
3093
+ key: "maxDownloadFromUrlFileCount",
3094
+ type: "number",
3095
+ title: $t("TXT_CODE_a15fca22"),
3096
+ description: $t("TXT_CODE_ecaf78a2"),
3097
+ min: 0
3098
+ }
3099
+ ],
3100
+ read: () => ({
3101
+ uploadSpeedRate: config.uploadSpeedRate,
3102
+ downloadSpeedRate: config.downloadSpeedRate,
3103
+ maxDownloadFromUrlFileCount: config.maxDownloadFromUrlFileCount
3104
+ }),
3105
+ write: (values) => {
3106
+ const count = values.maxDownloadFromUrlFileCount;
3107
+ if (count != null && (!Number.isInteger(count) || Number(count) < 0)) {
3108
+ throw new Error($t("TXT_CODE_ecaf78a2"));
3109
+ }
3110
+ if (values.uploadSpeedRate != null)
3111
+ config.uploadSpeedRate = Number(values.uploadSpeedRate);
3112
+ if (values.downloadSpeedRate != null)
3113
+ config.downloadSpeedRate = Number(values.downloadSpeedRate);
3114
+ if (count != null)
3115
+ config.maxDownloadFromUrlFileCount = Number(count);
3116
+ ctx.settings.save();
3117
+ }
3118
+ }));
3119
+ }
3120
+
3121
+
3122
+ /***/ },
3123
+
3124
+ /***/ "./plugins/file/src/backend/system_file.ts"
3125
+ (__unused_webpack_module, exports, __webpack_require__) {
3126
+
3127
+
3128
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3129
+ return (mod && mod.__esModule) ? mod : { "default": mod };
3130
+ };
3131
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
3132
+ const fs_extra_1 = __importDefault(__webpack_require__("fs-extra"));
3133
+ const iconv_lite_1 = __importDefault(__webpack_require__("iconv-lite"));
3134
+ const mcsmanager_common_1 = __webpack_require__("../common/src/index.ts");
3135
+ const os_1 = __importDefault(__webpack_require__("os"));
3136
+ const path_1 = __importDefault(__webpack_require__("path"));
3137
+ const filepath_1 = __webpack_require__("./plugins/file/src/backend/filepath.ts");
3138
+ const runtime_1 = __webpack_require__("./plugins/file/src/backend/runtime.ts");
3139
+ /** Resolved per use: the module is required before `apply()` runs. */
3140
+ const ERROR_MSG_01 = () => (0, runtime_1.$t)("TXT_CODE_system_file.illegalAccess");
3141
+ const MAX_EDIT_SIZE = 1024 * 1024 * 5;
3142
+ class FileManager {
3143
+ topPath;
3144
+ fileCode;
3145
+ cwd = ".";
3146
+ constructor(topPath = "", fileCode) {
3147
+ this.topPath = topPath;
3148
+ this.fileCode = fileCode;
3149
+ if (!path_1.default.isAbsolute(topPath)) {
3150
+ this.topPath = path_1.default.normalize(path_1.default.join(process.cwd(), topPath));
3151
+ }
3152
+ else {
3153
+ this.topPath = path_1.default.normalize(topPath);
3154
+ }
3155
+ if (!fileCode) {
3156
+ this.fileCode = "utf-8";
3157
+ if ((0, runtime_1.settings)().config.language === "zh_cn")
3158
+ this.fileCode = "gbk";
3159
+ }
3160
+ }
3161
+ isRootTopRath() {
3162
+ return this.topPath === "/" || this.topPath === "\\";
3163
+ }
3164
+ toAbsolutePath(fileName = "") {
3165
+ const topAbsolutePath = this.topPath;
3166
+ if (path_1.default.normalize(fileName).indexOf(topAbsolutePath) === 0) {
3167
+ const resolved = path_1.default.resolve(fileName);
3168
+ this.assertInsideRoot(resolved);
3169
+ return resolved;
3170
+ }
3171
+ let finalPath = "";
3172
+ if (os_1.default.platform() === "win32") {
3173
+ const reg = new RegExp("^[A-Za-z]{1}:[\\\\/]{1}");
3174
+ if (reg.test(this.cwd)) {
3175
+ finalPath = path_1.default.normalize(path_1.default.join(this.cwd, fileName));
3176
+ }
3177
+ else if (reg.test(fileName)) {
3178
+ finalPath = path_1.default.normalize(fileName);
3179
+ }
3180
+ }
3181
+ if (!finalPath) {
3182
+ finalPath = path_1.default.normalize(path_1.default.join(this.topPath, this.cwd, fileName));
3183
+ }
3184
+ this.assertInsideRoot(finalPath);
3185
+ return finalPath;
3186
+ }
3187
+ assertInsideRoot(target) {
3188
+ if (this.isRootTopRath())
3189
+ return;
3190
+ const isInside = (root, candidate) => {
3191
+ const relative = path_1.default.relative(root, candidate);
3192
+ return (relative !== ".." && !relative.startsWith(`..${path_1.default.sep}`) && !path_1.default.isAbsolute(relative));
3193
+ };
3194
+ if (!isInside(this.topPath, target)) {
3195
+ throw new Error(ERROR_MSG_01());
3196
+ }
3197
+ // New files need the same protection as existing files: resolve the nearest
3198
+ // existing parent so a symlink/junction cannot escape an instance directory.
3199
+ if (!fs_extra_1.default.existsSync(this.topPath))
3200
+ return;
3201
+ const realRoot = fs_extra_1.default.realpathSync(this.topPath);
3202
+ let ancestor = target;
3203
+ while (true) {
3204
+ try {
3205
+ fs_extra_1.default.lstatSync(ancestor);
3206
+ break;
3207
+ }
3208
+ catch (error) {
3209
+ if (error.code !== "ENOENT")
3210
+ throw error;
3211
+ }
3212
+ const parent = path_1.default.dirname(ancestor);
3213
+ if (parent === ancestor)
3214
+ throw new Error(ERROR_MSG_01());
3215
+ ancestor = parent;
3216
+ }
3217
+ if (!isInside(realRoot, fs_extra_1.default.realpathSync(ancestor)))
3218
+ throw new Error(ERROR_MSG_01());
3219
+ }
3220
+ checkPath(fileNameOrPath) {
3221
+ if (this.isRootTopRath())
3222
+ return true;
3223
+ const destAbsolutePath = path_1.default.normalize(this.toAbsolutePath(fileNameOrPath));
3224
+ const topAbsolutePath = path_1.default.normalize(this.topPath);
3225
+ const destPath = destAbsolutePath.endsWith(path_1.default.sep)
3226
+ ? destAbsolutePath.slice(0, -1)
3227
+ : destAbsolutePath;
3228
+ const topPath = topAbsolutePath.endsWith(path_1.default.sep)
3229
+ ? topAbsolutePath.slice(0, -1)
3230
+ : topAbsolutePath;
3231
+ if (destPath.startsWith(topPath)) {
3232
+ const parts = destPath.split(path_1.default.sep);
3233
+ return topPath.split(path_1.default.sep).every((part, index) => {
3234
+ return part === parts[index];
3235
+ });
3236
+ }
3237
+ return false;
3238
+ }
3239
+ check(destPath) {
3240
+ if (this.isRootTopRath())
3241
+ return true;
3242
+ return this.checkPath(destPath) && fs_extra_1.default.existsSync(this.toAbsolutePath(destPath));
3243
+ }
3244
+ cd(dirName) {
3245
+ if (!this.check(dirName))
3246
+ throw new Error(ERROR_MSG_01());
3247
+ this.cwd = (0, filepath_1.normalizedJoin)(this.cwd, dirName);
3248
+ }
3249
+ async list(page, pageSize = 40, searchFileName) {
3250
+ if (pageSize > 100 || pageSize <= 0 || page < 0)
3251
+ throw new Error("Beyond the value limit");
3252
+ // Use withFileTypes option to get file type directly, reducing stat calls
3253
+ const dirents = await fs_extra_1.default.readdir(this.toAbsolutePath(), { withFileTypes: true });
3254
+ // Filter search results and create basic file info with type
3255
+ let filteredItems = dirents
3256
+ .filter((dirent) => !searchFileName || dirent.name.toLowerCase().includes(searchFileName.toLowerCase()))
3257
+ .map((dirent) => ({
3258
+ name: dirent.name,
3259
+ type: dirent.isFile() ? 1 : 0
3260
+ }));
3261
+ const total = filteredItems.length;
3262
+ // Sort: directories first (type 0), then files (type 1), both alphabetically
3263
+ filteredItems.sort((a, b) => {
3264
+ if (a.type !== b.type)
3265
+ return a.type - b.type;
3266
+ return a.name.localeCompare(b.name);
3267
+ });
3268
+ const sliceStart = page * pageSize;
3269
+ const sliceEnd = sliceStart + pageSize;
3270
+ const targetItems = filteredItems.slice(sliceStart, sliceEnd);
3271
+ const statPromises = targetItems.map(async (item) => {
3272
+ try {
3273
+ const info = await fs_extra_1.default.stat(this.toAbsolutePath(item.name));
3274
+ const mode = parseInt(String(parseInt(info.mode?.toString(8), 10)).slice(-3));
3275
+ return {
3276
+ name: item.name,
3277
+ size: info.isFile() ? info.size : 0,
3278
+ time: info.atime.toString(),
3279
+ mode,
3280
+ type: item.type
3281
+ };
3282
+ }
3283
+ catch (error) {
3284
+ return {
3285
+ name: item.name,
3286
+ size: 0,
3287
+ time: new Date().toString(),
3288
+ mode: 0,
3289
+ type: item.type
3290
+ };
3291
+ }
3292
+ });
3293
+ // Execute all stat operations concurrently
3294
+ const resultList = await Promise.all(statPromises);
3295
+ return {
3296
+ items: resultList,
3297
+ page,
3298
+ pageSize,
3299
+ total,
3300
+ absolutePath: this.toAbsolutePath()
3301
+ };
3302
+ }
3303
+ async chmod(fileName, chmodValue, deep) {
3304
+ if (!this.check(fileName) || isNaN(parseInt(chmodValue)))
3305
+ throw new Error(ERROR_MSG_01());
3306
+ const absPath = this.toAbsolutePath(fileName);
3307
+ const defaultPath = "/bin/chmod";
3308
+ let file = "chmod";
3309
+ if (fs_extra_1.default.existsSync(defaultPath))
3310
+ file = defaultPath;
3311
+ const params = [];
3312
+ if (deep)
3313
+ params.push("-R");
3314
+ params.push(String(chmodValue));
3315
+ params.push(absPath);
3316
+ return await new mcsmanager_common_1.ProcessWrapper(file, params, ".", 60 * 10).start();
3317
+ }
3318
+ async readFile(fileName) {
3319
+ if (!this.check(fileName))
3320
+ throw new Error(ERROR_MSG_01());
3321
+ const absPath = this.toAbsolutePath(fileName);
3322
+ const buf = await fs_extra_1.default.readFile(absPath);
3323
+ const text = iconv_lite_1.default.decode(buf, this.fileCode || "utf-8");
3324
+ return text;
3325
+ }
3326
+ async writeFile(fileName, data) {
3327
+ if (!this.check(fileName))
3328
+ throw new Error(ERROR_MSG_01());
3329
+ const absPath = this.toAbsolutePath(fileName);
3330
+ const buf = iconv_lite_1.default.encode(data, this.fileCode || "utf-8");
3331
+ return await fs_extra_1.default.writeFile(absPath, buf);
3332
+ }
3333
+ async newFile(fileName) {
3334
+ // if (!FileManager.checkFileName(fileName)) throw new Error(ERROR_MSG_01());
3335
+ if (!this.checkPath(fileName))
3336
+ throw new Error(ERROR_MSG_01());
3337
+ const target = this.toAbsolutePath(fileName);
3338
+ await fs_extra_1.default.createFile(target);
3339
+ }
3340
+ /** Exclusive creation: never truncate an existing file or follow its symlink. */
3341
+ async createTextFile(target, text) {
3342
+ if (!this.checkPath(target))
3343
+ throw new Error(ERROR_MSG_01());
3344
+ const content = iconv_lite_1.default.encode(text, this.fileCode || "utf-8");
3345
+ if (content.length > 64 * 1024)
3346
+ throw new Error("File content exceeds 64 KiB");
3347
+ await fs_extra_1.default.writeFile(this.toAbsolutePath(target), content, { flag: "wx" });
3348
+ return true;
3349
+ }
3350
+ /** Unlink one regular file; never recursively remove directories. */
3351
+ async removeFile(target) {
3352
+ if (!this.check(target))
3353
+ throw new Error(ERROR_MSG_01());
3354
+ const absolute = this.toAbsolutePath(target);
3355
+ if (!(await fs_extra_1.default.lstat(absolute)).isFile())
3356
+ throw new Error("Expected a regular file");
3357
+ await fs_extra_1.default.unlink(absolute);
3358
+ return true;
3359
+ }
3360
+ async copy(target1, target2) {
3361
+ if (!this.checkPath(target2) || !this.check(target1))
3362
+ throw new Error(ERROR_MSG_01());
3363
+ const targetPath = this.toAbsolutePath(target1);
3364
+ target2 = this.toAbsolutePath(target2);
3365
+ return await fs_extra_1.default.copy(targetPath, target2);
3366
+ }
3367
+ mkdir(target) {
3368
+ if (!this.checkPath(target))
3369
+ throw new Error(ERROR_MSG_01());
3370
+ const targetPath = this.toAbsolutePath(target);
3371
+ return fs_extra_1.default.mkdirSync(targetPath);
3372
+ }
3373
+ async delete(target) {
3374
+ if (!this.check(target))
3375
+ throw new Error(ERROR_MSG_01());
3376
+ const targetPath = this.toAbsolutePath(target);
3377
+ return new Promise((r, j) => {
3378
+ fs_extra_1.default.remove(targetPath, (err) => {
3379
+ if (!err)
3380
+ r(true);
3381
+ else
3382
+ j(err);
3383
+ });
3384
+ });
3385
+ }
3386
+ async move(target, destPath) {
3387
+ if (!this.check(target))
3388
+ throw new Error(ERROR_MSG_01());
3389
+ if (!this.checkPath(destPath))
3390
+ throw new Error(ERROR_MSG_01());
3391
+ const targetPath = this.toAbsolutePath(target);
3392
+ destPath = this.toAbsolutePath(destPath);
3393
+ await fs_extra_1.default.move(targetPath, destPath);
3394
+ }
3395
+ zipFileCheck(path) {
3396
+ const fileInfo = fs_extra_1.default.statSync(path);
3397
+ const MAX_ZIP_GB = (0, runtime_1.settings)().config.maxZipFileSize;
3398
+ if (fileInfo.size > 1024 * 1024 * 1024 * MAX_ZIP_GB)
3399
+ throw new Error((0, runtime_1.$t)("TXT_CODE_system_file.unzipLimit", { max: MAX_ZIP_GB }));
3400
+ }
3401
+ async unzip(sourceZip, destDir, code) {
3402
+ if (!code)
3403
+ code = this.fileCode;
3404
+ if (!this.check(sourceZip) || !this.checkPath(destDir))
3405
+ throw new Error(ERROR_MSG_01());
3406
+ this.zipFileCheck(this.toAbsolutePath(sourceZip));
3407
+ return await (0, runtime_1.archive)().decompress(this.toAbsolutePath(sourceZip), this.toAbsolutePath(destDir), code);
3408
+ }
3409
+ async previewArchive(sourceZip, code) {
3410
+ if (!this.check(sourceZip))
3411
+ throw new Error(ERROR_MSG_01());
3412
+ this.zipFileCheck(this.toAbsolutePath(sourceZip));
3413
+ return await (0, runtime_1.archive)().listArchiveEntries(this.toAbsolutePath(sourceZip), code || this.fileCode);
3414
+ }
3415
+ async zip(sourceZip, files, code) {
3416
+ if (!code)
3417
+ code = this.fileCode;
3418
+ if (!this.checkPath(sourceZip))
3419
+ throw new Error(ERROR_MSG_01());
3420
+ const MAX_ZIP_GB = (0, runtime_1.settings)().config.maxZipFileSize;
3421
+ const MAX_TOTAL_FIELS_SIZE = 1024 * 1024 * 1024 * MAX_ZIP_GB;
3422
+ const sourceZipPath = this.toAbsolutePath(sourceZip);
3423
+ const filesPath = [];
3424
+ let totalSize = 0;
3425
+ for (const iterator of files) {
3426
+ if (this.check(iterator)) {
3427
+ filesPath.push(this.toAbsolutePath(iterator));
3428
+ try {
3429
+ totalSize += fs_extra_1.default.statSync(this.toAbsolutePath(iterator))?.size;
3430
+ }
3431
+ catch (error) { }
3432
+ }
3433
+ }
3434
+ if (totalSize > MAX_TOTAL_FIELS_SIZE)
3435
+ throw new Error((0, runtime_1.$t)("TXT_CODE_system_file.unzipLimit", { max: MAX_ZIP_GB }));
3436
+ return await (0, runtime_1.archive)().compress(sourceZipPath, filesPath, code);
3437
+ }
3438
+ async edit(target, data) {
3439
+ if (!this.check(target))
3440
+ throw new Error(ERROR_MSG_01());
3441
+ if (data || typeof data === "string") {
3442
+ return await this.writeFile(target, data);
3443
+ }
3444
+ else {
3445
+ const absPath = this.toAbsolutePath(target);
3446
+ const info = fs_extra_1.default.statSync(absPath);
3447
+ if (info.size > MAX_EDIT_SIZE) {
3448
+ throw new Error((0, runtime_1.$t)("TXT_CODE_system_file.execLimit"));
3449
+ }
3450
+ return await this.readFile(target);
3451
+ }
3452
+ }
3453
+ rename(target, newName) {
3454
+ if (!this.check(target))
3455
+ throw new Error(ERROR_MSG_01());
3456
+ if (!this.checkPath(newName))
3457
+ throw new Error(ERROR_MSG_01());
3458
+ const targetPath = this.toAbsolutePath(target);
3459
+ const newPath = this.toAbsolutePath(newName);
3460
+ fs_extra_1.default.renameSync(targetPath, newPath);
3461
+ }
3462
+ static checkFileName(fileName) {
3463
+ return (0, filepath_1.checkFileName)(fileName);
3464
+ }
3465
+ }
3466
+ exports["default"] = FileManager;
3467
+
3468
+
3469
+ /***/ },
3470
+
3471
+ /***/ "./plugins/file/src/backend/upload_manager.ts"
3472
+ (__unused_webpack_module, exports, __webpack_require__) {
3473
+
3474
+
3475
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
3476
+ const uuid_1 = __webpack_require__("uuid");
3477
+ class UploadManager {
3478
+ uploads = new Map();
3479
+ static timeout = 60 * 60 * 1000; // 1 hour
3480
+ cleanupTimer;
3481
+ startCleanup() {
3482
+ if (this.cleanupTimer)
3483
+ return;
3484
+ this.cleanupTimer = setInterval(async () => {
3485
+ await this.clearExpired();
3486
+ }, 5 * 60 * 1000 // 5 min
3487
+ );
3488
+ this.cleanupTimer.unref();
3489
+ }
3490
+ add(file) {
3491
+ this.startCleanup();
3492
+ const key = (0, uuid_1.v4)();
3493
+ file.id = key;
3494
+ this.uploads.set(key, file);
3495
+ return key;
3496
+ }
3497
+ getUploads() {
3498
+ return this.uploads.entries();
3499
+ }
3500
+ get(key) {
3501
+ return this.uploads.get(key);
3502
+ }
3503
+ delete(key) {
3504
+ return this.uploads.delete(key);
3505
+ }
3506
+ getByPath(path) {
3507
+ for (const [id, writer] of this.uploads.entries()) {
3508
+ if (writer.path == path) {
3509
+ return { id, writer };
3510
+ }
3511
+ }
3512
+ return undefined;
3513
+ }
3514
+ async clearExpired() {
3515
+ const now = Date.now();
3516
+ for (const [key, writer] of this.uploads.entries()) {
3517
+ if (now - writer.lastUpdate > UploadManager.timeout) {
3518
+ try {
3519
+ await writer.stop();
3520
+ this.uploads.delete(key);
3521
+ }
3522
+ catch (e) {
3523
+ console.error(`Failed to stop upload writer for key ${key}:`, e);
3524
+ }
3525
+ }
3526
+ }
3527
+ }
3528
+ async exit() {
3529
+ clearInterval(this.cleanupTimer);
3530
+ this.cleanupTimer = undefined;
3531
+ for (const [key, writer] of this.uploads.entries()) {
3532
+ try {
3533
+ await writer.stop();
3534
+ this.uploads.delete(key);
3535
+ }
3536
+ catch (e) {
3537
+ console.error(`Failed to stop upload writer for key ${key}:`, e);
3538
+ }
3539
+ }
3540
+ }
3541
+ }
3542
+ const uploadManager = new UploadManager();
3543
+ exports["default"] = uploadManager;
3544
+
3545
+
3546
+ /***/ },
3547
+
3548
+ /***/ "./plugins/file/src/backend/url.ts"
3549
+ (__unused_webpack_module, exports) {
3550
+
3551
+
3552
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
3553
+ exports.checkSafeUrl = checkSafeUrl;
3554
+ function checkSafeUrl(url) {
3555
+ try {
3556
+ const urlObj = new URL(url);
3557
+ if (!["http:", "https:"].includes(urlObj.protocol) || urlObj.username || urlObj.password) {
3558
+ return false;
3559
+ }
3560
+ const hostname = urlObj.hostname.toLowerCase();
3561
+ // Reject IPv6 addresses (IPv6 addresses are wrapped in brackets by URL object)
3562
+ if (hostname.startsWith("[") && hostname.endsWith("]")) {
3563
+ return false;
3564
+ }
3565
+ // Reject IPv4 address format
3566
+ const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
3567
+ if (ipv4Regex.test(hostname)) {
3568
+ return false;
3569
+ }
3570
+ // Reject local domains and loopback addresses
3571
+ const localDomains = ["localhost", "127.0.0.1", "0.0.0.0", "::1"];
3572
+ if (localDomains.includes(hostname)) {
3573
+ return false;
3574
+ }
3575
+ // Reject .local domains
3576
+ if (hostname.endsWith(".local")) {
3577
+ return false;
3578
+ }
3579
+ // Must contain at least one dot (ensure it's a valid domain, not a single word)
3580
+ if (!hostname.includes(".")) {
3581
+ return false;
3582
+ }
3583
+ // Domain must have at least a top-level domain (exclude single dot cases)
3584
+ const parts = hostname.split(".");
3585
+ if (parts.length < 2 || parts.some((part) => part.length === 0)) {
3586
+ return false;
3587
+ }
3588
+ return true;
3589
+ }
3590
+ catch (error) {
3591
+ return false;
3592
+ }
3593
+ }
3594
+
3595
+
3596
+ /***/ },
3597
+
3598
+ /***/ "./plugins/file/src/i18n/index.ts"
3599
+ (__unused_webpack_module, exports, __webpack_require__) {
3600
+
3601
+
3602
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3603
+ return (mod && mod.__esModule) ? mod : { "default": mod };
3604
+ };
3605
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
3606
+ exports.localeMessages = void 0;
3607
+ const de_DE_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/de_DE.json"));
3608
+ const en_US_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/en_US.json"));
3609
+ const es_ES_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/es_ES.json"));
3610
+ const fr_FR_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/fr_FR.json"));
3611
+ const ja_JP_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/ja_JP.json"));
3612
+ const ko_KR_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/ko_KR.json"));
3613
+ const pt_BR_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/pt_BR.json"));
3614
+ const ru_RU_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/ru_RU.json"));
3615
+ const th_TH_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/th_TH.json"));
3616
+ const tr_TR_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/tr_TR.json"));
3617
+ const zh_CN_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/zh_CN.json"));
3618
+ const zh_TW_json_1 = __importDefault(__webpack_require__("./plugins/file/src/i18n/zh_TW.json"));
3619
+ // The translated errors the file subsystem throws: path sandbox violations, the
3620
+ // per-instance task limit and the archive size limit. Registered at setup, so the
3621
+ // foundational `plugins/i18n` catalogue carries nothing file-specific.
3622
+ exports.localeMessages = {
3623
+ de_de: de_DE_json_1.default,
3624
+ en_us: en_US_json_1.default,
3625
+ es_es: es_ES_json_1.default,
3626
+ fr_fr: fr_FR_json_1.default,
3627
+ ja_jp: ja_JP_json_1.default,
3628
+ ko_kr: ko_KR_json_1.default,
3629
+ pt_br: pt_BR_json_1.default,
3630
+ ru_ru: ru_RU_json_1.default,
3631
+ th_th: th_TH_json_1.default,
3632
+ tr_tr: tr_TR_json_1.default,
3633
+ zh_cn: zh_CN_json_1.default,
3634
+ zh_tw: zh_TW_json_1.default
3635
+ };
3636
+
3637
+
3638
+ /***/ },
3639
+
3640
+ /***/ "events"
3641
+ (module) {
3642
+
3643
+ module.exports = require("events");
3644
+
3645
+ /***/ },
3646
+
3647
+ /***/ "fs-extra"
3648
+ (module) {
3649
+
3650
+ module.exports = require("fs-extra");
3651
+
3652
+ /***/ },
3653
+
3654
+ /***/ "iconv-lite"
3655
+ (module) {
3656
+
3657
+ module.exports = require("iconv-lite");
3658
+
3659
+ /***/ },
3660
+
3661
+ /***/ "os-utils"
3662
+ (module) {
3663
+
3664
+ module.exports = require("os-utils");
3665
+
3666
+ /***/ },
3667
+
3668
+ /***/ "proper-lockfile"
3669
+ (module) {
3670
+
3671
+ module.exports = require("proper-lockfile");
3672
+
3673
+ /***/ },
3674
+
3675
+ /***/ "uuid"
3676
+ (module) {
3677
+
3678
+ module.exports = require("uuid");
3679
+
3680
+ /***/ },
3681
+
3682
+ /***/ "child_process"
3683
+ (module) {
3684
+
3685
+ module.exports = require("child_process");
3686
+
3687
+ /***/ },
3688
+
3689
+ /***/ "crypto"
3690
+ (module) {
3691
+
3692
+ module.exports = require("crypto");
3693
+
3694
+ /***/ },
3695
+
3696
+ /***/ "fs"
3697
+ (module) {
3698
+
3699
+ module.exports = require("fs");
3700
+
3701
+ /***/ },
3702
+
3703
+ /***/ "module"
3704
+ (module) {
3705
+
3706
+ module.exports = require("module");
3707
+
3708
+ /***/ },
3709
+
3710
+ /***/ "net"
3711
+ (module) {
3712
+
3713
+ module.exports = require("net");
3714
+
3715
+ /***/ },
3716
+
3717
+ /***/ "node:crypto"
3718
+ (module) {
3719
+
3720
+ module.exports = require("node:crypto");
3721
+
3722
+ /***/ },
3723
+
3724
+ /***/ "node:fs"
3725
+ (module) {
3726
+
3727
+ module.exports = require("node:fs");
3728
+
3729
+ /***/ },
3730
+
3731
+ /***/ "node:os"
3732
+ (module) {
3733
+
3734
+ module.exports = require("node:os");
3735
+
3736
+ /***/ },
3737
+
3738
+ /***/ "node:path"
3739
+ (module) {
3740
+
3741
+ module.exports = require("node:path");
3742
+
3743
+ /***/ },
3744
+
3745
+ /***/ "os"
3746
+ (module) {
3747
+
3748
+ module.exports = require("os");
3749
+
3750
+ /***/ },
3751
+
3752
+ /***/ "path"
3753
+ (module) {
3754
+
3755
+ module.exports = require("path");
3756
+
3757
+ /***/ },
3758
+
3759
+ /***/ "process"
3760
+ (module) {
3761
+
3762
+ module.exports = require("process");
3763
+
3764
+ /***/ },
3765
+
3766
+ /***/ "./plugins/file/src/i18n/de_DE.json"
3767
+ (module) {
3768
+
3769
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"Instanz {{instanceUuid}} existiert nicht","TXT_CODE_file_router.unzipLimit":"Die maximale Anzahl gleichzeitiger Dekomprimierungsaufgaben wurde überschritten. Maximal sind {{maxFileTask}} zulässig; derzeit werden {{fileLock}} Aufgaben ausgeführt.","TXT_CODE_file_router_service.instanceNotExit":"Instanz {{uuid}} existiert nicht","TXT_CODE_system_file.execLimit":"Maximale Dateibearbeitungsgrenze überschritten","TXT_CODE_system_file.illegalAccess":"Falscher Zugriffspfad","TXT_CODE_system_file.unzipLimit":"Die Dateidekomprimierung unterstützt nur die Dekomprimierung von Dateien bis zu {{max}} GB. Wenn Sie die Obergrenze ändern müssen, gehen Sie bitte zur Datei data/Config/global.json.","TXT_CODE_e3a77a77":"Unbegrenzt","TXT_CODE_fde31068":"Upload -Rate für Benutzerdatei","TXT_CODE_d8d19932":"Begrenzung pro HTTP","TXT_CODE_785a0fcf":"Benutzerdatei -Download -Rate","TXT_CODE_b9fc604c":"Limit pro HTTP -Anforderung, Maximale Datei -Download -Geschwindigkeit","TXT_CODE_a15fca22":"Maximale Downloads von URL","TXT_CODE_ecaf78a2":"0 für unbegrenzt"}');
3770
+
3771
+ /***/ },
3772
+
3773
+ /***/ "./plugins/file/src/i18n/en_US.json"
3774
+ (module) {
3775
+
3776
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"Instance {{instanceUuid}} does not exist","TXT_CODE_file_router.unzipLimit":"Exceeded the maximum number of concurrent decompression tasks. The maximum allowed is {{maxFileTask}}, and currently, {{fileLock}} tasks are in progress. Please be patient.","TXT_CODE_file_router_service.instanceNotExit":"Instance {{uuid}} does not exist","TXT_CODE_system_file.execLimit":"Exceeded maximum file editing limit","TXT_CODE_system_file.illegalAccess":"Illegal access path","TXT_CODE_system_file.unzipLimit":"File decompression only supports file up to {{max}}GB. To change this limit, please go to the data/Config/global.json file.","TXT_CODE_e3a77a77":"Unlimited","TXT_CODE_fde31068":"User file upload rate","TXT_CODE_d8d19932":"Limit per HTTP request, maximum file upload speed","TXT_CODE_785a0fcf":"User file download rate","TXT_CODE_b9fc604c":"Limit per HTTP request, maximum file download speed","TXT_CODE_a15fca22":"Maximum of download from URL","TXT_CODE_ecaf78a2":"Set to 0 to unlimited"}');
3777
+
3778
+ /***/ },
3779
+
3780
+ /***/ "./plugins/file/src/i18n/es_ES.json"
3781
+ (module) {
3782
+
3783
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"La instancia {{instanceUuid}} no existe","TXT_CODE_file_router.unzipLimit":"Se ha excedido el número máximo de tareas de descompresión simultáneas. El máximo permitido es {{maxFileTask}}. Actualmente hay {{fileLock}} tareas en progreso.","TXT_CODE_file_router_service.instanceNotExit":"La instancia {{uuid}} no existe","TXT_CODE_system_file.execLimit":"Se superó el límite máximo de edición de archivos","TXT_CODE_system_file.illegalAccess":"Ruta de acceso incorrecta","TXT_CODE_system_file.unzipLimit":"La descompresión de archivos solo admite la descompresión de archivos de hasta {{max}} GB. Si necesita cambiar el límite superior, vaya al archivo data/Config/global.json.","TXT_CODE_e3a77a77":"Ilimitado","TXT_CODE_fde31068":"Tasa de carga de archivo de usuario","TXT_CODE_d8d19932":"Límite por solicitud HTTP, velocidad máxima de carga de archivo","TXT_CODE_785a0fcf":"Tasa de descarga de archivos de usuario","TXT_CODE_b9fc604c":"Límite por solicitud HTTP, velocidad máxima de descarga de archivo","TXT_CODE_a15fca22":"Máximo de descargas desde URL","TXT_CODE_ecaf78a2":"Establecer en 0 para ilimitado"}');
3784
+
3785
+ /***/ },
3786
+
3787
+ /***/ "./plugins/file/src/i18n/fr_FR.json"
3788
+ (module) {
3789
+
3790
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"L\'instance {{instanceUuid}} n\'existe pas","TXT_CODE_file_router.unzipLimit":"Le nombre maximum de tâches de décompression simultanées a été dépassé. Le maximum autorisé est de {{maxFileTask}}. Il y a actuellement {{fileLock}} tâches en cours.","TXT_CODE_file_router_service.instanceNotExit":"L\'instance {{uuid}} n\'existe pas","TXT_CODE_system_file.execLimit":"Limite maximale de modification de fichier dépassée","TXT_CODE_system_file.illegalAccess":"Mauvais chemin d\'accès","TXT_CODE_system_file.unzipLimit":"La décompression de fichiers ne prend en charge que la décompression de fichiers jusqu\'à {{max}} Go. Si vous devez modifier la limite supérieure, veuillez accéder au fichier data/Config/global.json.","TXT_CODE_e3a77a77":"Illimité","TXT_CODE_fde31068":"Taux de téléchargement de fichiers utilisateur","TXT_CODE_d8d19932":"Limite par demande HTTP, vitesse maximale de téléchargement de fichiers","TXT_CODE_785a0fcf":"Taux de téléchargement des fichiers utilisateur","TXT_CODE_b9fc604c":"Limite par demande HTTP, vitesse de téléchargement de fichiers maximum","TXT_CODE_a15fca22":"Maximum de téléchargements depuis l\'URL","TXT_CODE_ecaf78a2":"Mettre 0 pour illimité"}');
3791
+
3792
+ /***/ },
3793
+
3794
+ /***/ "./plugins/file/src/i18n/ja_JP.json"
3795
+ (module) {
3796
+
3797
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"インスタンス {{instanceUuid}} は存在しません","TXT_CODE_file_router.unzipLimit":"同時解凍タスクの最大数は {{maxFileTask}} を超えています。現在進行中のタスクは {{fileLock}} です。しばらくお待ちください。","TXT_CODE_file_router_service.instanceNotExit":"インスタンス {{uuid}} は存在しません","TXT_CODE_system_file.execLimit":"ファイル編集の最大制限を超えました","TXT_CODE_system_file.illegalAccess":"間違ったアクセスパス","TXT_CODE_system_file.unzipLimit":"ファイルの解凍では、最大 {{max}} GB のファイルの解凍のみがサポートされます。上限を変更する必要がある場合は、data/Config/global.json ファイルに移動してください。","TXT_CODE_e3a77a77":"無制限","TXT_CODE_fde31068":"ユーザーファイルのアップロードレート","TXT_CODE_d8d19932":"HTTPリクエストごとに制限、最大ファイルアップロード速度","TXT_CODE_785a0fcf":"ユーザーファイルのダウンロードレート","TXT_CODE_b9fc604c":"HTTP要求ごとに制限、最大ファイルのダウンロード速度","TXT_CODE_a15fca22":"URLからの最大ダウンロード数","TXT_CODE_ecaf78a2":"0で無制限に設定"}');
3798
+
3799
+ /***/ },
3800
+
3801
+ /***/ "./plugins/file/src/i18n/ko_KR.json"
3802
+ (module) {
3803
+
3804
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"{{instanceUuid}} 인스턴스가 존재하지 않습니다.","TXT_CODE_file_router.unzipLimit":"동시 압축 해제 작업의 최대 개수는 {{maxFileTask}}개를 초과했습니다. 현재 진행 중인 작업은 {{fileLock}}개입니다.","TXT_CODE_file_router_service.instanceNotExit":"{{uuid}} 인스턴스가 존재하지 않습니다.","TXT_CODE_system_file.execLimit":"최대 파일 편집 제한을 초과했습니다.","TXT_CODE_system_file.illegalAccess":"잘못된 액세스 경로","TXT_CODE_system_file.unzipLimit":"파일 압축 해제는 최대 {{max}}GB까지의 파일 압축 해제만 지원합니다. 상한을 변경해야 하는 경우 data/Config/global.json 파일로 이동하세요.","TXT_CODE_e3a77a77":"제한 없는","TXT_CODE_fde31068":"사용자 파일 업로드 속도","TXT_CODE_d8d19932":"HTTP 요청 당 제한, 최대 파일 업로드 속도","TXT_CODE_785a0fcf":"사용자 파일 다운로드 속도","TXT_CODE_b9fc604c":"HTTP 요청 당 제한, 최대 파일 다운로드 속도","TXT_CODE_a15fca22":"URL 최대 다운로드 수","TXT_CODE_ecaf78a2":"0으로 설정 시 무제한"}');
3805
+
3806
+ /***/ },
3807
+
3808
+ /***/ "./plugins/file/src/i18n/pt_BR.json"
3809
+ (module) {
3810
+
3811
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"A instância {{instanceUuid}} não existe","TXT_CODE_file_router.unzipLimit":"Excedido o número máximo de tarefas de descompressão simultâneas. O máximo permitido é {{maxFileTask}}, e atualmente, {{fileLock}} tarefas estão em andamento. Por favor, seja paciente.","TXT_CODE_file_router_service.instanceNotExit":"A instância {{uuid}} não existe","TXT_CODE_system_file.execLimit":"Limite máximo de edição de arquivos excedido","TXT_CODE_system_file.illegalAccess":"Caminho de acesso ilegal","TXT_CODE_system_file.unzipLimit":"A descompactação de arquivos suporta apenas arquivos de até {{max}}GB. Para alterar esse limite, vá até o arquivo data/Config/global.json.","TXT_CODE_e3a77a77":"Ilimitado","TXT_CODE_fde31068":"Taxa de upload de arquivos do usuário","TXT_CODE_d8d19932":"Limite por solicitação HTTP, velocidade máxima de upload do arquivo","TXT_CODE_785a0fcf":"Taxa de download de arquivos do usuário","TXT_CODE_b9fc604c":"Limite por solicitação HTTP, velocidade máxima de download de arquivo","TXT_CODE_a15fca22":"Máximo de downloads por URL","TXT_CODE_ecaf78a2":"Defina 0 para ilimitado"}');
3812
+
3813
+ /***/ },
3814
+
3815
+ /***/ "./plugins/file/src/i18n/ru_RU.json"
3816
+ (module) {
3817
+
3818
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"Экземпляр {{instanceUuid}} не существует","TXT_CODE_file_router.unzipLimit":"Превышено максимальное количество одновременных задач разархивирования. Максимально допустимое количество — {{maxFileTask}}, в настоящее время выполняется {{fileLock}} задач. Пожалуйста, будьте терпеливы.","TXT_CODE_file_router_service.instanceNotExit":"Экземпляр {{uuid}} не существует","TXT_CODE_system_file.execLimit":"Превышен лимит редактирования файлов","TXT_CODE_system_file.illegalAccess":"Незаконный путь доступа","TXT_CODE_system_file.unzipLimit":"Распаковка файлов поддерживается только для файлов до {{max}}GB. Чтобы изменить этот лимит, пожалуйста, перейдите в файл data/Config/global.json.","TXT_CODE_e3a77a77":"Неограничено","TXT_CODE_fde31068":"Пользовательская скорость загрузки файлов","TXT_CODE_d8d19932":"Ограничение на HTTP -запрос, максимальная скорость загрузки файлов","TXT_CODE_785a0fcf":"Пользовательская скорость загрузки файлов","TXT_CODE_b9fc604c":"Ограничение на HTTP -запрос, максимальная скорость загрузки файлов","TXT_CODE_a15fca22":"Максимум загрузок по URL","TXT_CODE_ecaf78a2":"0 - без ограничений"}');
3819
+
3820
+ /***/ },
3821
+
3822
+ /***/ "./plugins/file/src/i18n/th_TH.json"
3823
+ (module) {
3824
+
3825
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"ไม่พบอินสแตนซ์ {{instanceUuid}}","TXT_CODE_file_router.unzipLimit":"เกินจำนวนงานคลายการบีบอัดพร้อมกันสูงสุด อนุญาตสูงสุด {{maxFileTask}} งาน และขณะนี้มี {{fileLock}} งานกำลังดำเนินการ กรุณารอสักครู่","TXT_CODE_file_router_service.instanceNotExit":"ไม่พบอินสแตนซ์ {{uuid}}","TXT_CODE_system_file.execLimit":"เกินขีดจำกัดการแก้ไขไฟล์สูงสุด","TXT_CODE_system_file.illegalAccess":"เส้นทางการเข้าถึงไม่ถูกต้อง","TXT_CODE_system_file.unzipLimit":"การแตกไฟล์รองรับไฟล์ขนาดไม่เกิน {{max}}GB หากต้องการเปลี่ยนขีดจำกัดนี้ กรุณาไปที่ไฟล์ data/Config/global.json","TXT_CODE_e3a77a77":"ไม่จำกัด","TXT_CODE_fde31068":"อัตราการอัปโหลดไฟล์ผู้ใช้","TXT_CODE_d8d19932":"ขีด จำกัด ต่อคำขอ HTTP ความเร็วในการอัปโหลดไฟล์สูงสุด","TXT_CODE_785a0fcf":"อัตราการดาวน์โหลดไฟล์ผู้ใช้","TXT_CODE_b9fc604c":"ขีด จำกัด ต่อคำขอ HTTP ความเร็วในการดาวน์โหลดไฟล์สูงสุด","TXT_CODE_a15fca22":"จำนวนสูงสุดของการดาวน์โหลดจาก URL","TXT_CODE_ecaf78a2":"ตั้งเป็น 0 สำหรับไม่จำกัด"}');
3826
+
3827
+ /***/ },
3828
+
3829
+ /***/ "./plugins/file/src/i18n/tr_TR.json"
3830
+ (module) {
3831
+
3832
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"Örnek {{instanceUuid}} mevcut değil","TXT_CODE_file_router.unzipLimit":"Eşzamanlı dekompresyon görevlerinin maksimum sayısı aşıldı. İzin verilen maksimum sayı {{maxFileTask}} ve şu anda {{fileLock}} görevleri devam ediyor. Lütfen sabırlı olun.","TXT_CODE_file_router_service.instanceNotExit":"Örnek {{uuid}} mevcut değil","TXT_CODE_system_file.execLimit":"Maksimum dosya düzenleme sınırı aşıldı","TXT_CODE_system_file.illegalAccess":"Yasadışı erişim yolu","TXT_CODE_system_file.unzipLimit":"Dosya açma yalnızca {{max}}GB\'a kadar olan dosyaları destekler. Bu sınırı değiştirmek için lütfen data/Config/global.json dosyasına gidin.","TXT_CODE_e3a77a77":"Sınırsız","TXT_CODE_fde31068":"Kullanıcı Dosyası Yükleme Oranı","TXT_CODE_d8d19932":"HTTP isteği başına sınır, maksimum dosya yükleme hızı","TXT_CODE_785a0fcf":"Kullanıcı Dosyası İndirme Oranı","TXT_CODE_b9fc604c":"HTTP İsteği Başına Limit, Maksimum Dosya İndirme Hızı","TXT_CODE_a15fca22":"URL\'den maksimum indirme","TXT_CODE_ecaf78a2":"Sınırsız için 0\'a ayarla"}');
3833
+
3834
+ /***/ },
3835
+
3836
+ /***/ "./plugins/file/src/i18n/zh_CN.json"
3837
+ (module) {
3838
+
3839
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"实例 {{instanceUuid}} 不存在","TXT_CODE_file_router.unzipLimit":"超出最大同时解压缩任务量,最大准许{{maxFileTask}}个,目前有{{fileLock}}个任务正在进行,请耐心等待","TXT_CODE_file_router_service.instanceNotExit":"实例 {{uuid}} 不存在","TXT_CODE_system_file.execLimit":"超出最大文件编辑限制","TXT_CODE_system_file.illegalAccess":"非法访问路径","TXT_CODE_system_file.unzipLimit":"文件解压缩只支持最大 {{max}}GB 文件的解压缩,如需改变上限请前往 data/Config/global.json 文件","TXT_CODE_e3a77a77":"无限制","TXT_CODE_fde31068":"用户上传文件速率","TXT_CODE_d8d19932":"限制每个 HTTP 请求,上传文件最大速度","TXT_CODE_785a0fcf":"用户下载文件速率","TXT_CODE_b9fc604c":"限制每个 HTTP 请求,下载文件最大速度","TXT_CODE_a15fca22":"从URL下载文件最大任务数","TXT_CODE_ecaf78a2":"设置为 0 为无限制"}');
3840
+
3841
+ /***/ },
3842
+
3843
+ /***/ "./plugins/file/src/i18n/zh_TW.json"
3844
+ (module) {
3845
+
3846
+ module.exports = /*#__PURE__*/JSON.parse('{"TXT_CODE_file_router.instanceNotExist":"實例 {{instanceUuid}} 不存在","TXT_CODE_file_router.unzipLimit":"超出最大同時解壓縮任務量,最大允許{{maxFileTask}}個,目前有{{fileLock}}個任務正在進行,請耐心等待","TXT_CODE_file_router_service.instanceNotExit":"實例 {{uuid}} 不存在","TXT_CODE_system_file.execLimit":"超出最大檔案編輯限制","TXT_CODE_system_file.illegalAccess":"錯誤存取路徑","TXT_CODE_system_file.unzipLimit":"檔案解壓縮只支援最大 {{max}}GB 檔案的解壓縮,如需改變上限請前往 data/Config/global.json 檔案","TXT_CODE_e3a77a77":"無限制","TXT_CODE_fde31068":"使用者上傳檔案速率","TXT_CODE_d8d19932":"限制每個 HTTP 請求,上傳檔案最大速度","TXT_CODE_785a0fcf":"使用者下載檔案速率","TXT_CODE_b9fc604c":"限制每個 HTTP 請求,下載檔案最大速度","TXT_CODE_a15fca22":"網址下載上限","TXT_CODE_ecaf78a2":"設為 0 表示無限制"}');
3847
+
3848
+ /***/ }
3849
+
3850
+ /******/ });
3851
+ /************************************************************************/
3852
+ /******/ // The module cache
3853
+ /******/ var __webpack_module_cache__ = {};
3854
+ /******/
3855
+ /******/ // The require function
3856
+ /******/ function __webpack_require__(moduleId) {
3857
+ /******/ // Check if module is in cache
3858
+ /******/ var cachedModule = __webpack_module_cache__[moduleId];
3859
+ /******/ if (cachedModule !== undefined) {
3860
+ /******/ return cachedModule.exports;
3861
+ /******/ }
3862
+ /******/ // Create a new module (and put it into the cache)
3863
+ /******/ var module = __webpack_module_cache__[moduleId] = {
3864
+ /******/ // no module.id needed
3865
+ /******/ // no module.loaded needed
3866
+ /******/ exports: {}
3867
+ /******/ };
3868
+ /******/
3869
+ /******/ // Execute the module function
3870
+ /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
3871
+ /******/
3872
+ /******/ // Return the exports of the module
3873
+ /******/ return module.exports;
3874
+ /******/ }
3875
+ /******/
3876
+ /************************************************************************/
3877
+ /******/
3878
+ /******/ // startup
3879
+ /******/ // Load entry module and return exports
3880
+ /******/ // This entry module is referenced by other modules so it can't be inlined
3881
+ /******/ var __webpack_exports__ = __webpack_require__("./plugins/file/src/backend/index.ts");
3882
+ /******/ module.exports = __webpack_exports__;
3883
+ /******/
3884
+ /******/ })()
3885
+ ;