hfs 0.57.26 → 0.57.27-beta3

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.
Files changed (71) hide show
  1. package/admin/assets/{index-CHMhmNYS.js → index-CrWL6F86.js} +104 -103
  2. package/admin/assets/{sha512-Dsv49IAs.js → sha512-Dt-WJwnp.js} +1 -1
  3. package/admin/index.html +1 -1
  4. package/frontend/assets/{index-legacy-BI8icwFp.js → index-legacy-BdpconSd.js} +4 -4
  5. package/frontend/assets/{sha512-legacy-D82alHBq.js → sha512-legacy-Dbrn-acf.js} +1 -1
  6. package/frontend/index.html +1 -1
  7. package/package.json +4 -3
  8. package/src/QuickZipStream.js +11 -8
  9. package/src/SendList.js +10 -8
  10. package/src/ThrottledStream.js +8 -6
  11. package/src/acme.js +5 -7
  12. package/src/adminApis.js +6 -7
  13. package/src/api.accounts.js +4 -6
  14. package/src/api.auth.js +7 -11
  15. package/src/api.get_file_list.js +11 -16
  16. package/src/api.lang.js +1 -1
  17. package/src/api.monitor.js +2 -3
  18. package/src/api.net.js +1 -2
  19. package/src/api.plugins.js +8 -10
  20. package/src/api.vfs.js +14 -19
  21. package/src/apiMiddleware.js +4 -4
  22. package/src/auth.js +6 -9
  23. package/src/basicWeb.js +1 -2
  24. package/src/block.js +1 -1
  25. package/src/commands.js +9 -9
  26. package/src/comments.js +4 -5
  27. package/src/config.js +8 -9
  28. package/src/connections.js +11 -6
  29. package/src/consoleLog.js +6 -6
  30. package/src/const.js +4 -4
  31. package/src/cross.js +19 -21
  32. package/src/customHtml.js +3 -4
  33. package/src/ddns.js +4 -4
  34. package/src/debounceAsync.js +3 -3
  35. package/src/errorPages.js +2 -3
  36. package/src/events.js +7 -10
  37. package/src/fileAttr.js +6 -6
  38. package/src/first.js +7 -5
  39. package/src/frontEndApis.js +5 -5
  40. package/src/geo.js +3 -5
  41. package/src/github.js +14 -17
  42. package/src/i18n.js +3 -4
  43. package/src/icons.js +1 -1
  44. package/src/index.js +2 -3
  45. package/src/lang.js +5 -6
  46. package/src/listen.js +25 -28
  47. package/src/log.js +18 -17
  48. package/src/middlewares.js +12 -15
  49. package/src/misc.js +9 -11
  50. package/src/nat.js +14 -16
  51. package/src/outboundProxy.js +7 -7
  52. package/src/perm.js +7 -12
  53. package/src/persistence.js +1 -1
  54. package/src/plugins.js +64 -74
  55. package/src/roots.js +1 -2
  56. package/src/selfCheck.js +5 -4
  57. package/src/serveFile.js +6 -7
  58. package/src/serveGuiAndSharedFiles.js +7 -9
  59. package/src/serveGuiFiles.js +13 -20
  60. package/src/stat.js +40 -0
  61. package/src/statWorker.js +11 -0
  62. package/src/throttler.js +5 -7
  63. package/src/update.js +7 -7
  64. package/src/upload.js +11 -13
  65. package/src/util-files.js +42 -32
  66. package/src/util-http.js +22 -22
  67. package/src/util-os.js +2 -4
  68. package/src/vfs.js +78 -68
  69. package/src/walkDir.js +9 -9
  70. package/src/watchLoad.js +4 -4
  71. package/src/zip.js +5 -6
package/src/plugins.js CHANGED
@@ -37,7 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.PLUGIN_MAIN_FILE = exports.pluginsConfig = exports.suspendPlugins = exports.enablePlugins = exports.pluginsWatcher = exports.SERVER_CODE_ID = exports.Plugin = exports.pluginsMiddleware = exports.STORAGE_FOLDER = exports.DELETE_ME_SUFFIX = exports.DISABLING_SUFFIX = exports.PATH = void 0;
40
+ exports.PLUGIN_MAIN_FILE = exports.pluginsConfig = exports.suspendPlugins = exports.enablePlugins = exports.pluginsWatcher = exports.SERVER_CODE_ID = exports.Plugin = exports.pluginsMiddleware = exports.pluginsScanned = exports.STORAGE_FOLDER = exports.DELETE_ME_SUFFIX = exports.DISABLING_SUFFIX = exports.PATH = void 0;
41
41
  exports.isPluginRunning = isPluginRunning;
42
42
  exports.isPluginEnabled = isPluginEnabled;
43
43
  exports.enablePlugin = enablePlugin;
@@ -61,6 +61,7 @@ const Const = __importStar(require("./const"));
61
61
  const misc_1 = require("./misc");
62
62
  const misc = __importStar(require("./misc"));
63
63
  const config_1 = require("./config");
64
+ const vfs_1 = require("./vfs");
64
65
  const serveFile_1 = require("./serveFile");
65
66
  const events_1 = __importDefault(require("./events"));
66
67
  const promises_1 = require("fs/promises");
@@ -83,6 +84,7 @@ exports.PATH = 'plugins';
83
84
  exports.DISABLING_SUFFIX = '-disabled';
84
85
  exports.DELETE_ME_SUFFIX = '-delete_me' + exports.DISABLING_SUFFIX;
85
86
  exports.STORAGE_FOLDER = 'storage';
87
+ exports.pluginsScanned = (0, misc_1.pendingPromise)();
86
88
  setTimeout(async () => {
87
89
  for (const x of await (0, promises_1.readdir)(exports.PATH))
88
90
  if (x.endsWith(exports.DELETE_ME_SUFFIX))
@@ -90,8 +92,7 @@ setTimeout(async () => {
90
92
  }, 1000);
91
93
  const plugins = new Map(); // now that we care about the order, a simple object wouldn't do, because numbers are always at the beginning
92
94
  function isPluginRunning(id) {
93
- var _a;
94
- return Boolean((_a = plugins.get(id)) === null || _a === void 0 ? void 0 : _a.started);
95
+ return Boolean(plugins.get(id)?.started);
95
96
  }
96
97
  function isPluginEnabled(id, considerSuspension = false) {
97
98
  return (!considerSuspension || !exports.suspendPlugins.get()) && exports.enablePlugins.get().includes(id);
@@ -113,8 +114,7 @@ async function stopPlugin(id) {
113
114
  await waitRunning(id, false);
114
115
  }
115
116
  async function startPlugin(id) {
116
- var _a;
117
- if ((_a = getPluginInfo(id)) === null || _a === void 0 ? void 0 : _a.isTheme)
117
+ if (getPluginInfo(id)?.isTheme)
118
118
  await Promise.all(mapPlugins((pl, id) => pl.isTheme && stopPlugin(id)));
119
119
  enablePlugin(id);
120
120
  await waitRunning(id);
@@ -132,7 +132,7 @@ function setPluginConfig(id, changes) {
132
132
  exports.pluginsConfig.set(allConfigs => {
133
133
  const fields = getPluginConfigFields(id);
134
134
  const oldConfig = allConfigs[id];
135
- const newConfig = changes && lodash_1.default.pickBy({ ...oldConfig, ...changes }, (v, k) => { var _a; return v != null && !(0, misc_1.same)(v, (_a = fields === null || fields === void 0 ? void 0 : fields[k]) === null || _a === void 0 ? void 0 : _a.defaultValue); });
135
+ const newConfig = changes && lodash_1.default.pickBy({ ...oldConfig, ...changes }, (v, k) => v != null && !(0, misc_1.same)(v, fields?.[k]?.defaultValue));
136
136
  return { ...allConfigs, [id]: lodash_1.default.isEmpty(newConfig) ? undefined : newConfig };
137
137
  });
138
138
  }
@@ -146,16 +146,13 @@ function findPluginByRepo(repo) {
146
146
  return pl;
147
147
  return lodash_1.default.find(inactivePlugins, match);
148
148
  function match(rec) {
149
- var _a, _b;
150
- return repo === ((_b = (_a = rec === null || rec === void 0 ? void 0 : rec.repo) === null || _a === void 0 ? void 0 : _a.main) !== null && _b !== void 0 ? _b : rec === null || rec === void 0 ? void 0 : rec.repo);
149
+ return repo === (rec?.repo?.main ?? rec?.repo);
151
150
  }
152
151
  }
153
152
  function getPluginConfigFields(id) {
154
- var _a;
155
- return (_a = plugins.get(id)) === null || _a === void 0 ? void 0 : _a.getData().config;
153
+ return plugins.get(id)?.getData().config;
156
154
  }
157
155
  async function initPlugin(pl, morePassedToInit) {
158
- var _a;
159
156
  const undoEvents = [];
160
157
  const timeouts = [];
161
158
  const controlledEvents = Object.create(events_1.default, (0, misc_1.objFromKeys)(['on', 'once', 'multi'], k => ({
@@ -165,12 +162,12 @@ async function initPlugin(pl, morePassedToInit) {
165
162
  return ret;
166
163
  }
167
164
  })));
168
- const res = await ((_a = pl.init) === null || _a === void 0 ? void 0 : _a.call(pl, {
165
+ const res = await pl.init?.({
169
166
  Const, require,
170
167
  // intercept all subscriptions, so to be able to undo them on unload
171
168
  events: controlledEvents,
172
169
  log: console.log,
173
- setError(msg) { setError((morePassedToInit === null || morePassedToInit === void 0 ? void 0 : morePassedToInit.id) || 'server_code', msg); },
170
+ setError(msg) { setError(morePassedToInit?.id || 'server_code', msg); },
174
171
  getHfsConfig: config_1.getConfig,
175
172
  setInterval() {
176
173
  const ret = setInterval(...arguments);
@@ -191,10 +188,10 @@ async function initPlugin(pl, morePassedToInit) {
191
188
  controlledEvents.on('listening', ({ server }) => cb(server));
192
189
  },
193
190
  misc, _: lodash_1.default,
194
- customApiCall, notifyClient: frontEndApis_1.notifyClient, addBlock: block_1.addBlock, ctxBelongsTo: perm_1.ctxBelongsTo, getConnections: connections_1.getConnections,
191
+ customApiCall, notifyClient: frontEndApis_1.notifyClient, addBlock: block_1.addBlock, ctxBelongsTo: perm_1.ctxBelongsTo, getConnections: connections_1.getConnections, normalizeFilename: vfs_1.normalizeFilename,
195
192
  getCurrentUsername: auth_1.getCurrentUsername, getAccount: perm_1.getAccount, getUsernames: perm_1.getUsernames, addAccount: perm_1.addAccount, delAccount: perm_1.delAccount, updateAccount: perm_1.updateAccount, renameAccount: perm_1.renameAccount,
196
193
  ...morePassedToInit
197
- }));
194
+ });
198
195
  Object.assign(pl, typeof res === 'function' ? { unload: res } : res);
199
196
  (0, misc_1.patchKey)(pl, 'unload', was => () => {
200
197
  for (const x of timeouts)
@@ -215,15 +212,13 @@ function warnOnce(msg) {
215
212
  console.log('Warning: ' + msg);
216
213
  }
217
214
  const pluginsMiddleware = async (ctx, next) => {
218
- var _a;
219
215
  const after = {};
220
216
  // run middleware plugins
221
217
  let lastStatus = ctx.status;
222
218
  let lastBody = ctx.body;
223
219
  await Promise.all(mapPlugins(async (pl, id) => {
224
- var _a;
225
220
  try {
226
- const res = await ((_a = pl.middleware) === null || _a === void 0 ? void 0 : _a.call(pl, ctx));
221
+ const res = await pl.middleware?.(ctx);
227
222
  if (lastStatus !== ctx.status || lastBody !== ctx.body) {
228
223
  console.debug("plugin changed response", id);
229
224
  lastStatus = ctx.status;
@@ -248,7 +243,7 @@ const pluginsMiddleware = async (ctx, next) => {
248
243
  const a = path.substring(const_1.PLUGINS_PUB_URI.length).split('/');
249
244
  const name = a.shift();
250
245
  if (plugins.has(name)) { // do it only if the plugin is loaded
251
- if ((_a = ctx.get('referer')) === null || _a === void 0 ? void 0 : _a.endsWith('/'))
246
+ if (ctx.get('referer')?.endsWith('/'))
252
247
  ctx.state.considerAsGui = true;
253
248
  await (0, serveFile_1.serveFile)(ctx, plugins.get(name).folder + '/public/' + a.join('/'), const_1.MIME_AUTO);
254
249
  }
@@ -265,7 +260,7 @@ const pluginsMiddleware = async (ctx, next) => {
265
260
  printError(id, e);
266
261
  }
267
262
  function printError(id, e) {
268
- console.log(`error middleware plugin ${id}: ${(e === null || e === void 0 ? void 0 : e.message) || e}`);
263
+ console.log(`error middleware plugin ${id}: ${e?.message || e}`);
269
264
  console.debug(e);
270
265
  }
271
266
  };
@@ -275,12 +270,18 @@ events_1.default.once('app', () => Object.assign(index_1.app.context, {
275
270
  stop() { return this.isStopped = true; }
276
271
  }));
277
272
  class Plugin {
273
+ id;
274
+ folder;
275
+ data;
276
+ onUnload;
277
+ started = new Date();
278
+ icons;
279
+ log;
278
280
  constructor(id, folder, data, onUnload) {
279
281
  this.id = id;
280
282
  this.folder = folder;
281
283
  this.data = data;
282
284
  this.onUnload = onUnload;
283
- this.started = new Date();
284
285
  if (!data)
285
286
  throw 'invalid data';
286
287
  this.log = [];
@@ -313,41 +314,36 @@ class Plugin {
313
314
  plugins.set(k, temp);
314
315
  }
315
316
  }
316
- get version() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.version; }
317
- get description() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.description; }
318
- get apiRequired() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.apiRequired; }
319
- get isTheme() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.isTheme; }
320
- get repo() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.repo; }
321
- get depend() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.depend; }
322
- get afterPlugin() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.afterPlugin; }
323
- get beforePlugin() { var _a; return (_a = this.data) === null || _a === void 0 ? void 0 : _a.beforePlugin; }
317
+ get version() { return this.data?.version; }
318
+ get description() { return this.data?.description; }
319
+ get apiRequired() { return this.data?.apiRequired; }
320
+ get isTheme() { return this.data?.isTheme; }
321
+ get repo() { return this.data?.repo; }
322
+ get depend() { return this.data?.depend; }
323
+ get afterPlugin() { return this.data?.afterPlugin; }
324
+ get beforePlugin() { return this.data?.beforePlugin; }
324
325
  get middleware() {
325
- var _a;
326
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.middleware;
326
+ return this.data?.middleware;
327
327
  }
328
328
  get frontend_css() {
329
- var _a;
330
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.frontend_css;
329
+ return this.data?.frontend_css;
331
330
  }
332
331
  get frontend_js() {
333
- var _a;
334
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.frontend_js;
332
+ return this.data?.frontend_js;
335
333
  }
336
334
  get onDirEntry() {
337
- var _a;
338
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.onDirEntry;
335
+ return this.data?.onDirEntry;
339
336
  }
340
337
  getData() {
341
338
  return this.data;
342
339
  }
343
340
  async unload(reloading = false) {
344
- var _a, _b;
345
341
  if (!this.started)
346
342
  return;
347
343
  this.started = null;
348
344
  const { id } = this;
349
345
  try {
350
- await ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.unload) === null || _b === void 0 ? void 0 : _b.call(_a));
346
+ await this.data?.unload?.();
351
347
  }
352
348
  catch (e) {
353
349
  console.log('error unloading plugin', id, String(e));
@@ -362,11 +358,10 @@ class Plugin {
362
358
  exports.Plugin = Plugin;
363
359
  exports.SERVER_CODE_ID = '.'; // a name that will surely be not found among plugin folders
364
360
  const serverCode = (0, config_1.defineConfig)('server_code', '', async (script, { k }) => {
365
- var _a;
366
361
  try {
367
- (_a = (await serverCode.compiled())) === null || _a === void 0 ? void 0 : _a.unload();
362
+ (await serverCode.compiled())?.unload();
368
363
  }
369
- catch (_b) { }
364
+ catch { }
370
365
  const res = {};
371
366
  try {
372
367
  new Function('exports', script)(res); // parse
@@ -414,7 +409,7 @@ if (!(0, fs_1.existsSync)(exports.PATH))
414
409
  try {
415
410
  (0, fs_1.mkdirSync)(exports.PATH);
416
411
  }
417
- catch (_a) { }
412
+ catch { }
418
413
  exports.pluginsWatcher = (0, misc_1.watchDir)(exports.PATH, rescanAsap);
419
414
  exports.enablePlugins = (0, config_1.defineConfig)('enable_plugins', ['antibrute']);
420
415
  exports.enablePlugins.sub(rescanAsap);
@@ -426,22 +421,23 @@ async function rescan() {
426
421
  console.debug('scanning plugins');
427
422
  const patterns = [exports.PATH + '/*'];
428
423
  if (const_1.APP_PATH !== process.cwd())
429
- patterns.unshift((0, misc_1.adjustStaticPathForGlob)(const_1.APP_PATH) + '/' + patterns[0]); // first search bundled plugins, because otherwise they won't be loaded because of the folders with same name in .hfs/plugins (used for storage)
430
- const met = [];
424
+ patterns.unshift((0, misc_1.escapeGlobPath)(const_1.APP_PATH) + '/' + patterns[0]); // first search bundled plugins, because otherwise they won't be loaded because of the folders with same name in .hfs/plugins (used for storage)
425
+ const existing = [];
431
426
  for (const { path, dirent } of await (0, fast_glob_1.default)(patterns, { onlyFiles: false, suppressErrors: true, objectMode: true })) {
432
427
  if (!dirent.isDirectory() || path.endsWith(exports.DISABLING_SUFFIX))
433
428
  continue;
434
429
  const id = path.split('/').slice(-1)[0];
435
- met.push(id);
430
+ existing.push(id);
436
431
  if (!pluginWatchers.has(id))
437
432
  pluginWatchers.set(id, watchPlugin(id, (0, path_1.join)(path, exports.PLUGIN_MAIN_FILE)));
438
433
  }
439
434
  for (const [id, cancelWatcher] of pluginWatchers.entries())
440
- if (!met.includes(id)) {
435
+ if (!existing.includes(id)) {
441
436
  enablePlugin(id, false);
442
437
  cancelWatcher();
443
438
  pluginWatchers.delete(id);
444
439
  }
440
+ exports.pluginsScanned.resolve();
445
441
  }
446
442
  function watchPlugin(id, path) {
447
443
  console.debug('plugin watch', id);
@@ -499,14 +495,13 @@ function watchPlugin(id, path) {
499
495
  events_1.default.emit('pluginStopped', p);
500
496
  }
501
497
  async function start() {
502
- var _a;
503
498
  if (starting)
504
499
  return;
505
500
  try {
506
501
  starting = (0, misc_1.pendingPromise)();
507
502
  // if dependencies are not ready right now, we give some time. Not super-solid but good enough for now.
508
503
  const info = await parsePlugin();
509
- if (!await (0, misc_1.waitFor)(() => lodash_1.default.isEmpty(getMissingDependencies(info)), { timeout: 5000 }))
504
+ if (!await (0, misc_1.waitFor)(() => lodash_1.default.isEmpty(getMissingDependencies(info)), { timeout: 5_000 }))
510
505
  throw Error("plugin missing dependencies: " + lodash_1.default.map(getMissingDependencies(info), x => x.repo).join(', '));
511
506
  if (getPluginInfo(id))
512
507
  setError(id, '');
@@ -517,7 +512,7 @@ function watchPlugin(id, path) {
517
512
  calculateBadApi(pluginData);
518
513
  if (pluginData.badApi)
519
514
  throw Error(pluginData.badApi);
520
- await (alreadyRunning === null || alreadyRunning === void 0 ? void 0 : alreadyRunning.unload(true));
515
+ await alreadyRunning?.unload(true);
521
516
  console.debug("starting plugin", id);
522
517
  const storageDir = (0, path_1.resolve)(exports.PATH, id, exports.STORAGE_FOLDER) + (const_1.IS_WINDOWS ? '\\' : '/');
523
518
  await (0, promises_1.mkdir)(storageDir, { recursive: true });
@@ -551,9 +546,8 @@ function watchPlugin(id, path) {
551
546
  });
552
547
  },
553
548
  getConfig(cfgKey) {
554
- var _a, _b, _c, _d;
555
- const cur = (_a = exports.pluginsConfig.get()) === null || _a === void 0 ? void 0 : _a[id];
556
- return cfgKey ? (_b = cur === null || cur === void 0 ? void 0 : cur[cfgKey]) !== null && _b !== void 0 ? _b : (_d = (_c = pluginData.config) === null || _c === void 0 ? void 0 : _c[cfgKey]) === null || _d === void 0 ? void 0 : _d.defaultValue
549
+ const cur = exports.pluginsConfig.get()?.[id];
550
+ return cfgKey ? cur?.[cfgKey] ?? pluginData.config?.[cfgKey]?.defaultValue
557
551
  : lodash_1.default.defaults(cur, (0, misc_1.objSameKeys)(pluginData.config, x => x.defaultValue));
558
552
  },
559
553
  setConfig: (cfgKey, value) => setPluginConfig(id, { [cfgKey]: value }),
@@ -605,23 +599,22 @@ function watchPlugin(id, path) {
605
599
  }
606
600
  catch (e) {
607
601
  await markItInactive();
608
- const parsed = (_a = e.stack) === null || _a === void 0 ? void 0 : _a.split('\n\n'); // this form is used by syntax-errors inside the plugin, which is useful to show
609
- const where = (parsed === null || parsed === void 0 ? void 0 : parsed.length) > 1 ? `\n${parsed[0]}` : '';
602
+ const parsed = e.stack?.split('\n\n'); // this form is used by syntax-errors inside the plugin, which is useful to show
603
+ const where = parsed?.length > 1 ? `\n${parsed[0]}` : '';
610
604
  e = (0, misc_1.prefix)('', e.message, where) || String(e);
611
605
  setError(id, e);
612
606
  }
613
607
  finally {
614
- starting === null || starting === void 0 ? void 0 : starting.resolve();
608
+ starting?.resolve();
615
609
  starting = undefined;
616
610
  }
617
611
  }
618
612
  }
619
613
  function customApiCall(method, ...params) {
620
- return mapPlugins(pl => { var _a, _b; return (_b = (_a = pl.getData().customApi) === null || _a === void 0 ? void 0 : _a[method]) === null || _b === void 0 ? void 0 : _b.call(_a, ...params); });
614
+ return mapPlugins(pl => pl.getData().customApi?.[method]?.(...params));
621
615
  }
622
616
  function getError(id) {
623
- var _a;
624
- return (_a = getPluginInfo(id)) === null || _a === void 0 ? void 0 : _a.error;
617
+ return getPluginInfo(id)?.error;
625
618
  }
626
619
  // returns true if there's an error, and it has changed
627
620
  function setError(id, error) {
@@ -638,15 +631,13 @@ function setError(id, error) {
638
631
  return true;
639
632
  }
640
633
  function deleteModule(id) {
641
- var _a;
642
- var _b;
643
634
  const { cache } = require;
644
635
  // build reversed map of dependencies
645
636
  const requiredBy = { '.': ['.'] }; // don't touch main entry
646
637
  for (const k in cache)
647
638
  if (k !== id)
648
- for (const child of (0, misc_1.wantArray)((_a = cache[k]) === null || _a === void 0 ? void 0 : _a.children))
649
- (requiredBy[_b = child.id] || (requiredBy[_b] = [])).push(k);
639
+ for (const child of (0, misc_1.wantArray)(cache[k]?.children))
640
+ (requiredBy[child.id] ||= []).push(k);
650
641
  const deleted = [];
651
642
  (function deleteCache(id) {
652
643
  const mod = cache[id];
@@ -661,17 +652,16 @@ function deleteModule(id) {
661
652
  }
662
653
  (0, first_1.onProcessExit)(() => Promise.allSettled(mapPlugins(pl => pl.unload())));
663
654
  function parsePluginSource(id, source) {
664
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
665
655
  const pl = { id };
666
- pl.description = (0, misc_1.tryJson)((_a = /exports.description\s*=\s*(".*")/.exec(source)) === null || _a === void 0 ? void 0 : _a[1]);
667
- pl.repo = (0, misc_1.tryJson)((_b = /exports.repo\s*=\s*(\S*)/.exec(source)) === null || _b === void 0 ? void 0 : _b[1]);
668
- pl.version = (_d = Number((_c = /exports.version\s*=\s*(\d*\.?\d+)/.exec(source)) === null || _c === void 0 ? void 0 : _c[1])) !== null && _d !== void 0 ? _d : undefined;
669
- pl.apiRequired = (_f = (0, misc_1.tryJson)((_e = /exports.apiRequired\s*=\s*([ \d.,[\]]+)/.exec(source)) === null || _e === void 0 ? void 0 : _e[1])) !== null && _f !== void 0 ? _f : undefined;
670
- pl.isTheme = (_h = (0, misc_1.tryJson)((_g = /exports.isTheme\s*=\s*(true|false|"light"|"dark")/.exec(source)) === null || _g === void 0 ? void 0 : _g[1])) !== null && _h !== void 0 ? _h : (id.endsWith('-theme') || undefined);
671
- pl.preview = (_k = (0, misc_1.tryJson)((_j = /exports.preview\s*=\s*(.+)/.exec(source)) === null || _j === void 0 ? void 0 : _j[1])) !== null && _k !== void 0 ? _k : undefined;
672
- pl.depend = (_m = (0, misc_1.tryJson)((_l = /exports.depend\s*=\s*(\[[\s\S]*?])/m.exec(source)) === null || _l === void 0 ? void 0 : _l[1])) === null || _m === void 0 ? void 0 : _m.filter((x) => typeof x.repo === 'string' && x.version === undefined || typeof x.version === 'number'
656
+ pl.description = (0, misc_1.tryJson)(/exports.description\s*=\s*(".*")/.exec(source)?.[1]);
657
+ pl.repo = (0, misc_1.tryJson)(/exports.repo\s*=\s*(\S*)/.exec(source)?.[1]);
658
+ pl.version = Number(/exports.version\s*=\s*(\d*\.?\d+)/.exec(source)?.[1]) ?? undefined;
659
+ pl.apiRequired = (0, misc_1.tryJson)(/exports.apiRequired\s*=\s*([ \d.,[\]]+)/.exec(source)?.[1]) ?? undefined;
660
+ pl.isTheme = (0, misc_1.tryJson)(/exports.isTheme\s*=\s*(true|false|"light"|"dark")/.exec(source)?.[1]) ?? (id.endsWith('-theme') || undefined);
661
+ pl.preview = (0, misc_1.tryJson)(/exports.preview\s*=\s*(.+)/.exec(source)?.[1]) ?? undefined;
662
+ pl.depend = (0, misc_1.tryJson)(/exports.depend\s*=\s*(\[[\s\S]*?])/m.exec(source)?.[1])?.filter((x) => typeof x.repo === 'string' && x.version === undefined || typeof x.version === 'number'
673
663
  || console.warn("plugin dependency discarded", x));
674
- pl.changelog = (0, misc_1.tryJson)((_o = /exports.changelog\s*=\s*(\[[\s\S]*?])/m.exec(source)) === null || _o === void 0 ? void 0 : _o[1]);
664
+ pl.changelog = (0, misc_1.tryJson)(/exports.changelog\s*=\s*(\[[\s\S]*?])/m.exec(source)?.[1]);
675
665
  if (Array.isArray(pl.apiRequired) && (pl.apiRequired.length !== 2 || !pl.apiRequired.every(lodash_1.default.isFinite))) // validate [from,to] form
676
666
  pl.apiRequired = undefined;
677
667
  calculateBadApi(pl);
@@ -685,13 +675,13 @@ function calculateBadApi(data) {
685
675
  : undefined;
686
676
  }
687
677
  function getMissingDependencies(plugin) {
688
- return (0, misc_1.onlyTruthy)(((plugin === null || plugin === void 0 ? void 0 : plugin.depend) || []).map((dep) => {
678
+ return (0, misc_1.onlyTruthy)((plugin?.depend || []).map((dep) => {
689
679
  const res = findPluginByRepo(dep.repo);
690
680
  const error = !res ? 'missing'
691
681
  : (res.version || 0) < dep.version ? 'version'
692
682
  : !isPluginEnabled(res.id) ? 'disabled'
693
683
  : !isPluginRunning(res.id) ? 'stopped'
694
684
  : '';
695
- return error && { repo: dep.repo, error, id: res === null || res === void 0 ? void 0 : res.id };
685
+ return error && { repo: dep.repo, error, id: res?.id };
696
686
  }));
697
687
  }
package/src/roots.js CHANGED
@@ -17,7 +17,6 @@ exports.roots = (0, config_1.defineConfig)(misc_1.CFG.roots, {}, map => {
17
17
  });
18
18
  const forceAddress = (0, config_1.defineConfig)(misc_1.CFG.force_address, false);
19
19
  const rootsMiddleware = (ctx, next) => (() => {
20
- var _a;
21
20
  if (!ctx.path) // it was once reported "Cannot read properties of null (reading 'startsWith')" but I can't reproduce it, and it shouldn't happen anyway
22
21
  return (0, connections_1.disconnect)(ctx, 'no path'); // let's assume that such requests can't be served anyway. This will leave a trace with an ip, anyway
23
22
  ctx.state.originalPath = ctx.path;
@@ -33,7 +32,7 @@ const rootsMiddleware = (ctx, next) => (() => {
33
32
  }
34
33
  if (lodash_1.default.isEmpty(exports.roots.get()))
35
34
  return;
36
- const root = ctx.state.root = (_a = exports.roots.compiled()) === null || _a === void 0 ? void 0 : _a(ctx.host);
35
+ const root = ctx.state.root = exports.roots.compiled()?.(ctx.host);
37
36
  if (!ctx.state.skipFilters && forceAddress.get()
38
37
  && root === undefined && !(0, misc_1.isLocalHost)(ctx) && ctx.host !== listen_1.baseUrl.compiled())
39
38
  return (0, connections_1.disconnect)(ctx, forceAddress.key()); // returning truthy will not call next
package/src/selfCheck.js CHANGED
@@ -21,7 +21,6 @@ const selfCheckMiddleware = (ctx, next) => {
21
21
  };
22
22
  exports.selfCheckMiddleware = selfCheckMiddleware;
23
23
  async function selfCheck(url) {
24
- var _a;
25
24
  const prjInfo = await (0, github_1.getProjectInfo)();
26
25
  console.log(`checking server ${url}`);
27
26
  const parsed = new URL(url);
@@ -39,7 +38,7 @@ async function selfCheck(url) {
39
38
  console.debug(svc);
40
39
  body = applySymbols(body);
41
40
  serviceUrl = applySymbols(serviceUrl);
42
- const res = await (0, cross_1.haveTimeout)(6000, (0, util_http_1.httpString)(serviceUrl, { family, ...rest, body }));
41
+ const res = await (0, cross_1.haveTimeout)(6_000, (0, util_http_1.httpString)(serviceUrl, { family, ...rest, body }));
43
42
  const success = new RegExp(regexpSuccess).test(res);
44
43
  const failure = new RegExp(regexpFailure).test(res);
45
44
  if (success === failure)
@@ -49,7 +48,7 @@ async function selfCheck(url) {
49
48
  }));
50
49
  }
51
50
  catch (e) {
52
- console.debug(((_a = e === null || e === void 0 ? void 0 : e.errors) === null || _a === void 0 ? void 0 : _a.map(String)) || (e === null || e === void 0 ? void 0 : e.cause) || String(e));
51
+ console.debug(e?.errors?.map(String) || e?.cause || String(e));
53
52
  }
54
53
  }
55
54
  }
@@ -57,6 +56,8 @@ async function selfCheck(url) {
57
56
  selfChecking = false;
58
57
  }
59
58
  function applySymbols(s) {
60
- return s === null || s === void 0 ? void 0 : s.replace('$IP', parsed.hostname).replace('$PORT', parsed.port || (parsed.protocol === 'https:' ? '443' : '80')).replace('$URL', url.replace(/\/$/, '') + CHECK_URL);
59
+ return s?.replace('$IP', parsed.hostname)
60
+ .replace('$PORT', parsed.port || (parsed.protocol === 'https:' ? '443' : '80'))
61
+ .replace('$URL', url.replace(/\/$/, '') + CHECK_URL);
61
62
  }
62
63
  }
package/src/serveFile.js CHANGED
@@ -41,7 +41,6 @@ function disposition(ctx, name, forceDownload = false) {
41
41
  + `filename="${toAsciiEquivalent(name)}"; filename*=UTF-8''${encodeURIComponent(name)}`);
42
42
  }
43
43
  async function serveFileNode(ctx, node) {
44
- var _a;
45
44
  const { source, mime } = node;
46
45
  const name = (0, vfs_1.getNodeName)(node);
47
46
  const mimeString = typeof mime === 'string' ? mime
@@ -55,7 +54,7 @@ async function serveFileNode(ctx, node) {
55
54
  ctx.state.vfsNode = node; // useful to tell service files from files shared by the user
56
55
  const download = 'dl' in ctx.query;
57
56
  disposition(ctx, name, download);
58
- if (!download && ((_a = ctx.get('referer')) === null || _a === void 0 ? void 0 : _a.endsWith('/')) && (0, misc_1.with_)(ctx.get('accept'), x => x && !x.includes('text')))
57
+ if (!download && ctx.get('referer')?.endsWith('/') && (0, misc_1.with_)(ctx.get('accept'), x => x && !x.includes('text')))
59
58
  ctx.state.considerAsGui = true;
60
59
  await serveFile(ctx, source || '', mimeString);
61
60
  if (await maxDownloadsPerAccount(ctx) === undefined) // returning false will not execute other limits
@@ -71,7 +70,7 @@ const cacheControlDiskFiles = (0, config_1.defineConfig)('cache_control_disk_fil
71
70
  async function serveFile(ctx, source, mime, content) {
72
71
  if (!source)
73
72
  return;
74
- mime !== null && mime !== void 0 ? mime : (mime = mimeCfg.compiled()((0, path_1.basename)(source)));
73
+ mime ??= mimeCfg.compiled()((0, path_1.basename)(source));
75
74
  if (mime === undefined || mime === const_1.MIME_AUTO)
76
75
  mime = mime_types_1.default.lookup(source) || '';
77
76
  if (mime)
@@ -104,7 +103,7 @@ async function serveFile(ctx, source, mime, content) {
104
103
  const range = applyRange(ctx, size);
105
104
  ctx.body = (0, fs_1.createReadStream)(source, range);
106
105
  if (ctx.state.vfsNode)
107
- monitorAsDownload(ctx, size, range === null || range === void 0 ? void 0 : range.start);
106
+ monitorAsDownload(ctx, size, range?.start);
108
107
  }
109
108
  catch (e) {
110
109
  return ctx.status = const_1.HTTP_NOT_FOUND;
@@ -133,10 +132,10 @@ function applyRange(ctx, totalSize = ctx.response.length) {
133
132
  const [unit, ranges] = range.split('=');
134
133
  if (unit !== 'bytes')
135
134
  return ctx.throw(const_1.HTTP_BAD_REQUEST, 'bad range unit');
136
- if (ranges === null || ranges === void 0 ? void 0 : ranges.includes(','))
135
+ if (ranges?.includes(','))
137
136
  return ctx.throw(const_1.HTTP_BAD_REQUEST, 'multi-range not supported');
138
- let bytes = ranges === null || ranges === void 0 ? void 0 : ranges.split('-');
139
- if (!(bytes === null || bytes === void 0 ? void 0 : bytes.length))
137
+ let bytes = ranges?.split('-');
138
+ if (!bytes?.length)
140
139
  return ctx.throw(const_1.HTTP_BAD_REQUEST, 'bad range');
141
140
  const max = totalSize - 1;
142
141
  const start = bytes[0] ? Number(bytes[0]) : Math.max(0, totalSize - Number(bytes[1])); // a negative start is relative to the end
@@ -33,12 +33,11 @@ const serveFrontendPrefixed = (0, koa_mount_1.default)(cross_const_1.FRONTEND_UR
33
33
  const serveAdminFiles = (0, serveGuiFiles_1.serveGuiFiles)(process.env.ADMIN_PROXY, cross_const_1.ADMIN_URI);
34
34
  const serveAdminPrefixed = (0, koa_mount_1.default)(cross_const_1.ADMIN_URI.slice(0, -1), serveAdminFiles);
35
35
  const serveGuiAndSharedFiles = async (ctx, next) => {
36
- var _a, _b;
37
36
  const { path } = ctx;
38
37
  // dynamic import on frontend|admin (used for non-https login) while developing (vite4) is not producing a relative path
39
38
  if (const_1.DEV && path.startsWith('/node_modules/')) {
40
39
  const { referer: r } = ctx.headers;
41
- return (0, misc_1.try_)(() => { var _a; return r && ((_a = new URL(r).pathname) === null || _a === void 0 ? void 0 : _a.startsWith(cross_const_1.ADMIN_URI)); }) ? serveAdminFiles(ctx, next)
40
+ return (0, misc_1.try_)(() => r && new URL(r).pathname?.startsWith(cross_const_1.ADMIN_URI)) ? serveAdminFiles(ctx, next)
42
41
  : serveFrontendFiles(ctx, next);
43
42
  }
44
43
  if (path.startsWith(cross_const_1.FRONTEND_URI))
@@ -53,11 +52,11 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
53
52
  if (!iconName)
54
53
  return;
55
54
  const plugin = a.length > 1 && (0, plugins_1.getPluginInfo)(a[0]); // an extra level in the path indicates a plugin
56
- const file = plugin ? (_a = plugin.icons) === null || _a === void 0 ? void 0 : _a[iconName] : icons_1.customizedIcons === null || icons_1.customizedIcons === void 0 ? void 0 : icons_1.customizedIcons[iconName];
55
+ const file = plugin ? plugin.icons?.[iconName] : icons_1.customizedIcons?.[iconName];
57
56
  if (!file)
58
57
  return;
59
58
  ctx.state.considerAsGui = true;
60
- return (0, serveFile_1.serveFile)(ctx, (0, path_1.join)((plugin === null || plugin === void 0 ? void 0 : plugin.folder) || '', icons_1.ICONS_FOLDER, file), const_1.MIME_AUTO);
59
+ return (0, serveFile_1.serveFile)(ctx, (0, path_1.join)(plugin?.folder || '', icons_1.ICONS_FOLDER, file), const_1.MIME_AUTO);
61
60
  }
62
61
  const { get } = ctx.query;
63
62
  const getUploadTempHash = get === cross_const_1.UPLOAD_TEMP_HASH;
@@ -71,7 +70,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
71
70
  ctx.state.uploadPath = decPath;
72
71
  if (getUploadTempHash)
73
72
  return !folder.source ? (0, errorPages_1.sendErrorPage)(ctx, cross_const_1.HTTP_NOT_FOUND)
74
- : ctx.body = await (0, misc_1.parseFile)((0, upload_1.getUploadTempFor)((0, path_1.join)(folder.source, rest)), calcHash); // negligible memory leak
73
+ : ctx.body = await (0, misc_1.loadFileCached)((0, upload_1.getUploadTempFor)((0, path_1.join)(folder.source, rest)), calcHash); // negligible memory leak
75
74
  const dest = (0, upload_1.uploadWriter)(folder, folderUri, rest, ctx);
76
75
  if (dest) {
77
76
  ctx.req.pipe(dest).on('error', err => {
@@ -126,7 +125,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
126
125
  if ((0, vfs_1.statusCodeForMissingPerm)(node, 'can_delete', ctx))
127
126
  return;
128
127
  try {
129
- if ((_b = (await events_1.default.emitAsync('deleting', { node, ctx }))) === null || _b === void 0 ? void 0 : _b.isDefaultPrevented())
128
+ if ((await events_1.default.emitAsync('deleting', { node, ctx }))?.isDefaultPrevented())
130
129
  return ctx.status = cross_const_1.HTTP_FAILED_DEPENDENCY;
131
130
  await (0, promises_1.rm)(source, { recursive: true });
132
131
  void (0, comments_1.setCommentFor)(source, ''); // necessary only to clean a possible descript.ion or kvstorage
@@ -141,7 +140,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
141
140
  const found = await (0, vfs_1.urlToNode)(node.default, ctx, node);
142
141
  if (found && /\.html?/i.test(node.default))
143
142
  ctx.state.considerAsGui = true;
144
- node = found !== null && found !== void 0 ? found : node;
143
+ node = found ?? node;
145
144
  }
146
145
  if (get === 'icon')
147
146
  return (0, serveFile_1.serveFile)(ctx, node.icon || '|'); // pipe to cause not-found
@@ -172,8 +171,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
172
171
  };
173
172
  exports.serveGuiAndSharedFiles = serveGuiAndSharedFiles;
174
173
  async function sendFolderList(node, ctx) {
175
- var _a;
176
- if ((_a = (await events_1.default.emitAsync('getList', { node, ctx }))) === null || _a === void 0 ? void 0 : _a.isDefaultPrevented())
174
+ if ((await events_1.default.emitAsync('getList', { node, ctx }))?.isDefaultPrevented())
177
175
  return;
178
176
  let { depth = 0, folders, prepend } = ctx.query;
179
177
  ctx.type = 'text';