hfs 0.57.26 → 0.57.27-beta2

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-DSkhXlWX.js} +103 -103
  2. package/admin/assets/{sha512-Dsv49IAs.js → sha512-CoddZKeD.js} +1 -1
  3. package/admin/index.html +1 -1
  4. package/frontend/assets/{index-legacy-BI8icwFp.js → index-legacy-C4Gclsbz.js} +4 -4
  5. package/frontend/assets/{sha512-legacy-D82alHBq.js → sha512-legacy-C-FMk44u.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 +13 -8
  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 +62 -73
  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 +11 -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 +80 -29
  67. package/src/util-os.js +2 -4
  68. package/src/vfs.js +77 -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;
@@ -83,6 +83,7 @@ exports.PATH = 'plugins';
83
83
  exports.DISABLING_SUFFIX = '-disabled';
84
84
  exports.DELETE_ME_SUFFIX = '-delete_me' + exports.DISABLING_SUFFIX;
85
85
  exports.STORAGE_FOLDER = 'storage';
86
+ exports.pluginsScanned = (0, misc_1.pendingPromise)();
86
87
  setTimeout(async () => {
87
88
  for (const x of await (0, promises_1.readdir)(exports.PATH))
88
89
  if (x.endsWith(exports.DELETE_ME_SUFFIX))
@@ -90,8 +91,7 @@ setTimeout(async () => {
90
91
  }, 1000);
91
92
  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
93
  function isPluginRunning(id) {
93
- var _a;
94
- return Boolean((_a = plugins.get(id)) === null || _a === void 0 ? void 0 : _a.started);
94
+ return Boolean(plugins.get(id)?.started);
95
95
  }
96
96
  function isPluginEnabled(id, considerSuspension = false) {
97
97
  return (!considerSuspension || !exports.suspendPlugins.get()) && exports.enablePlugins.get().includes(id);
@@ -113,8 +113,7 @@ async function stopPlugin(id) {
113
113
  await waitRunning(id, false);
114
114
  }
115
115
  async function startPlugin(id) {
116
- var _a;
117
- if ((_a = getPluginInfo(id)) === null || _a === void 0 ? void 0 : _a.isTheme)
116
+ if (getPluginInfo(id)?.isTheme)
118
117
  await Promise.all(mapPlugins((pl, id) => pl.isTheme && stopPlugin(id)));
119
118
  enablePlugin(id);
120
119
  await waitRunning(id);
@@ -132,7 +131,7 @@ function setPluginConfig(id, changes) {
132
131
  exports.pluginsConfig.set(allConfigs => {
133
132
  const fields = getPluginConfigFields(id);
134
133
  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); });
134
+ const newConfig = changes && lodash_1.default.pickBy({ ...oldConfig, ...changes }, (v, k) => v != null && !(0, misc_1.same)(v, fields?.[k]?.defaultValue));
136
135
  return { ...allConfigs, [id]: lodash_1.default.isEmpty(newConfig) ? undefined : newConfig };
137
136
  });
138
137
  }
@@ -146,16 +145,13 @@ function findPluginByRepo(repo) {
146
145
  return pl;
147
146
  return lodash_1.default.find(inactivePlugins, match);
148
147
  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);
148
+ return repo === (rec?.repo?.main ?? rec?.repo);
151
149
  }
152
150
  }
153
151
  function getPluginConfigFields(id) {
154
- var _a;
155
- return (_a = plugins.get(id)) === null || _a === void 0 ? void 0 : _a.getData().config;
152
+ return plugins.get(id)?.getData().config;
156
153
  }
157
154
  async function initPlugin(pl, morePassedToInit) {
158
- var _a;
159
155
  const undoEvents = [];
160
156
  const timeouts = [];
161
157
  const controlledEvents = Object.create(events_1.default, (0, misc_1.objFromKeys)(['on', 'once', 'multi'], k => ({
@@ -165,12 +161,12 @@ async function initPlugin(pl, morePassedToInit) {
165
161
  return ret;
166
162
  }
167
163
  })));
168
- const res = await ((_a = pl.init) === null || _a === void 0 ? void 0 : _a.call(pl, {
164
+ const res = await pl.init?.({
169
165
  Const, require,
170
166
  // intercept all subscriptions, so to be able to undo them on unload
171
167
  events: controlledEvents,
172
168
  log: console.log,
173
- setError(msg) { setError((morePassedToInit === null || morePassedToInit === void 0 ? void 0 : morePassedToInit.id) || 'server_code', msg); },
169
+ setError(msg) { setError(morePassedToInit?.id || 'server_code', msg); },
174
170
  getHfsConfig: config_1.getConfig,
175
171
  setInterval() {
176
172
  const ret = setInterval(...arguments);
@@ -194,7 +190,7 @@ async function initPlugin(pl, morePassedToInit) {
194
190
  customApiCall, notifyClient: frontEndApis_1.notifyClient, addBlock: block_1.addBlock, ctxBelongsTo: perm_1.ctxBelongsTo, getConnections: connections_1.getConnections,
195
191
  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
192
  ...morePassedToInit
197
- }));
193
+ });
198
194
  Object.assign(pl, typeof res === 'function' ? { unload: res } : res);
199
195
  (0, misc_1.patchKey)(pl, 'unload', was => () => {
200
196
  for (const x of timeouts)
@@ -215,15 +211,13 @@ function warnOnce(msg) {
215
211
  console.log('Warning: ' + msg);
216
212
  }
217
213
  const pluginsMiddleware = async (ctx, next) => {
218
- var _a;
219
214
  const after = {};
220
215
  // run middleware plugins
221
216
  let lastStatus = ctx.status;
222
217
  let lastBody = ctx.body;
223
218
  await Promise.all(mapPlugins(async (pl, id) => {
224
- var _a;
225
219
  try {
226
- const res = await ((_a = pl.middleware) === null || _a === void 0 ? void 0 : _a.call(pl, ctx));
220
+ const res = await pl.middleware?.(ctx);
227
221
  if (lastStatus !== ctx.status || lastBody !== ctx.body) {
228
222
  console.debug("plugin changed response", id);
229
223
  lastStatus = ctx.status;
@@ -248,7 +242,7 @@ const pluginsMiddleware = async (ctx, next) => {
248
242
  const a = path.substring(const_1.PLUGINS_PUB_URI.length).split('/');
249
243
  const name = a.shift();
250
244
  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('/'))
245
+ if (ctx.get('referer')?.endsWith('/'))
252
246
  ctx.state.considerAsGui = true;
253
247
  await (0, serveFile_1.serveFile)(ctx, plugins.get(name).folder + '/public/' + a.join('/'), const_1.MIME_AUTO);
254
248
  }
@@ -265,7 +259,7 @@ const pluginsMiddleware = async (ctx, next) => {
265
259
  printError(id, e);
266
260
  }
267
261
  function printError(id, e) {
268
- console.log(`error middleware plugin ${id}: ${(e === null || e === void 0 ? void 0 : e.message) || e}`);
262
+ console.log(`error middleware plugin ${id}: ${e?.message || e}`);
269
263
  console.debug(e);
270
264
  }
271
265
  };
@@ -275,12 +269,18 @@ events_1.default.once('app', () => Object.assign(index_1.app.context, {
275
269
  stop() { return this.isStopped = true; }
276
270
  }));
277
271
  class Plugin {
272
+ id;
273
+ folder;
274
+ data;
275
+ onUnload;
276
+ started = new Date();
277
+ icons;
278
+ log;
278
279
  constructor(id, folder, data, onUnload) {
279
280
  this.id = id;
280
281
  this.folder = folder;
281
282
  this.data = data;
282
283
  this.onUnload = onUnload;
283
- this.started = new Date();
284
284
  if (!data)
285
285
  throw 'invalid data';
286
286
  this.log = [];
@@ -313,41 +313,36 @@ class Plugin {
313
313
  plugins.set(k, temp);
314
314
  }
315
315
  }
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; }
316
+ get version() { return this.data?.version; }
317
+ get description() { return this.data?.description; }
318
+ get apiRequired() { return this.data?.apiRequired; }
319
+ get isTheme() { return this.data?.isTheme; }
320
+ get repo() { return this.data?.repo; }
321
+ get depend() { return this.data?.depend; }
322
+ get afterPlugin() { return this.data?.afterPlugin; }
323
+ get beforePlugin() { return this.data?.beforePlugin; }
324
324
  get middleware() {
325
- var _a;
326
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.middleware;
325
+ return this.data?.middleware;
327
326
  }
328
327
  get frontend_css() {
329
- var _a;
330
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.frontend_css;
328
+ return this.data?.frontend_css;
331
329
  }
332
330
  get frontend_js() {
333
- var _a;
334
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.frontend_js;
331
+ return this.data?.frontend_js;
335
332
  }
336
333
  get onDirEntry() {
337
- var _a;
338
- return (_a = this.data) === null || _a === void 0 ? void 0 : _a.onDirEntry;
334
+ return this.data?.onDirEntry;
339
335
  }
340
336
  getData() {
341
337
  return this.data;
342
338
  }
343
339
  async unload(reloading = false) {
344
- var _a, _b;
345
340
  if (!this.started)
346
341
  return;
347
342
  this.started = null;
348
343
  const { id } = this;
349
344
  try {
350
- await ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.unload) === null || _b === void 0 ? void 0 : _b.call(_a));
345
+ await this.data?.unload?.();
351
346
  }
352
347
  catch (e) {
353
348
  console.log('error unloading plugin', id, String(e));
@@ -362,11 +357,10 @@ class Plugin {
362
357
  exports.Plugin = Plugin;
363
358
  exports.SERVER_CODE_ID = '.'; // a name that will surely be not found among plugin folders
364
359
  const serverCode = (0, config_1.defineConfig)('server_code', '', async (script, { k }) => {
365
- var _a;
366
360
  try {
367
- (_a = (await serverCode.compiled())) === null || _a === void 0 ? void 0 : _a.unload();
361
+ (await serverCode.compiled())?.unload();
368
362
  }
369
- catch (_b) { }
363
+ catch { }
370
364
  const res = {};
371
365
  try {
372
366
  new Function('exports', script)(res); // parse
@@ -414,7 +408,7 @@ if (!(0, fs_1.existsSync)(exports.PATH))
414
408
  try {
415
409
  (0, fs_1.mkdirSync)(exports.PATH);
416
410
  }
417
- catch (_a) { }
411
+ catch { }
418
412
  exports.pluginsWatcher = (0, misc_1.watchDir)(exports.PATH, rescanAsap);
419
413
  exports.enablePlugins = (0, config_1.defineConfig)('enable_plugins', ['antibrute']);
420
414
  exports.enablePlugins.sub(rescanAsap);
@@ -426,22 +420,23 @@ async function rescan() {
426
420
  console.debug('scanning plugins');
427
421
  const patterns = [exports.PATH + '/*'];
428
422
  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 = [];
423
+ 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)
424
+ const existing = [];
431
425
  for (const { path, dirent } of await (0, fast_glob_1.default)(patterns, { onlyFiles: false, suppressErrors: true, objectMode: true })) {
432
426
  if (!dirent.isDirectory() || path.endsWith(exports.DISABLING_SUFFIX))
433
427
  continue;
434
428
  const id = path.split('/').slice(-1)[0];
435
- met.push(id);
429
+ existing.push(id);
436
430
  if (!pluginWatchers.has(id))
437
431
  pluginWatchers.set(id, watchPlugin(id, (0, path_1.join)(path, exports.PLUGIN_MAIN_FILE)));
438
432
  }
439
433
  for (const [id, cancelWatcher] of pluginWatchers.entries())
440
- if (!met.includes(id)) {
434
+ if (!existing.includes(id)) {
441
435
  enablePlugin(id, false);
442
436
  cancelWatcher();
443
437
  pluginWatchers.delete(id);
444
438
  }
439
+ exports.pluginsScanned.resolve();
445
440
  }
446
441
  function watchPlugin(id, path) {
447
442
  console.debug('plugin watch', id);
@@ -499,14 +494,13 @@ function watchPlugin(id, path) {
499
494
  events_1.default.emit('pluginStopped', p);
500
495
  }
501
496
  async function start() {
502
- var _a;
503
497
  if (starting)
504
498
  return;
505
499
  try {
506
500
  starting = (0, misc_1.pendingPromise)();
507
501
  // if dependencies are not ready right now, we give some time. Not super-solid but good enough for now.
508
502
  const info = await parsePlugin();
509
- if (!await (0, misc_1.waitFor)(() => lodash_1.default.isEmpty(getMissingDependencies(info)), { timeout: 5000 }))
503
+ if (!await (0, misc_1.waitFor)(() => lodash_1.default.isEmpty(getMissingDependencies(info)), { timeout: 5_000 }))
510
504
  throw Error("plugin missing dependencies: " + lodash_1.default.map(getMissingDependencies(info), x => x.repo).join(', '));
511
505
  if (getPluginInfo(id))
512
506
  setError(id, '');
@@ -517,7 +511,7 @@ function watchPlugin(id, path) {
517
511
  calculateBadApi(pluginData);
518
512
  if (pluginData.badApi)
519
513
  throw Error(pluginData.badApi);
520
- await (alreadyRunning === null || alreadyRunning === void 0 ? void 0 : alreadyRunning.unload(true));
514
+ await alreadyRunning?.unload(true);
521
515
  console.debug("starting plugin", id);
522
516
  const storageDir = (0, path_1.resolve)(exports.PATH, id, exports.STORAGE_FOLDER) + (const_1.IS_WINDOWS ? '\\' : '/');
523
517
  await (0, promises_1.mkdir)(storageDir, { recursive: true });
@@ -551,9 +545,8 @@ function watchPlugin(id, path) {
551
545
  });
552
546
  },
553
547
  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
548
+ const cur = exports.pluginsConfig.get()?.[id];
549
+ return cfgKey ? cur?.[cfgKey] ?? pluginData.config?.[cfgKey]?.defaultValue
557
550
  : lodash_1.default.defaults(cur, (0, misc_1.objSameKeys)(pluginData.config, x => x.defaultValue));
558
551
  },
559
552
  setConfig: (cfgKey, value) => setPluginConfig(id, { [cfgKey]: value }),
@@ -605,23 +598,22 @@ function watchPlugin(id, path) {
605
598
  }
606
599
  catch (e) {
607
600
  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]}` : '';
601
+ const parsed = e.stack?.split('\n\n'); // this form is used by syntax-errors inside the plugin, which is useful to show
602
+ const where = parsed?.length > 1 ? `\n${parsed[0]}` : '';
610
603
  e = (0, misc_1.prefix)('', e.message, where) || String(e);
611
604
  setError(id, e);
612
605
  }
613
606
  finally {
614
- starting === null || starting === void 0 ? void 0 : starting.resolve();
607
+ starting?.resolve();
615
608
  starting = undefined;
616
609
  }
617
610
  }
618
611
  }
619
612
  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); });
613
+ return mapPlugins(pl => pl.getData().customApi?.[method]?.(...params));
621
614
  }
622
615
  function getError(id) {
623
- var _a;
624
- return (_a = getPluginInfo(id)) === null || _a === void 0 ? void 0 : _a.error;
616
+ return getPluginInfo(id)?.error;
625
617
  }
626
618
  // returns true if there's an error, and it has changed
627
619
  function setError(id, error) {
@@ -638,15 +630,13 @@ function setError(id, error) {
638
630
  return true;
639
631
  }
640
632
  function deleteModule(id) {
641
- var _a;
642
- var _b;
643
633
  const { cache } = require;
644
634
  // build reversed map of dependencies
645
635
  const requiredBy = { '.': ['.'] }; // don't touch main entry
646
636
  for (const k in cache)
647
637
  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);
638
+ for (const child of (0, misc_1.wantArray)(cache[k]?.children))
639
+ (requiredBy[child.id] ||= []).push(k);
650
640
  const deleted = [];
651
641
  (function deleteCache(id) {
652
642
  const mod = cache[id];
@@ -661,17 +651,16 @@ function deleteModule(id) {
661
651
  }
662
652
  (0, first_1.onProcessExit)(() => Promise.allSettled(mapPlugins(pl => pl.unload())));
663
653
  function parsePluginSource(id, source) {
664
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
665
654
  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'
655
+ pl.description = (0, misc_1.tryJson)(/exports.description\s*=\s*(".*")/.exec(source)?.[1]);
656
+ pl.repo = (0, misc_1.tryJson)(/exports.repo\s*=\s*(\S*)/.exec(source)?.[1]);
657
+ pl.version = Number(/exports.version\s*=\s*(\d*\.?\d+)/.exec(source)?.[1]) ?? undefined;
658
+ pl.apiRequired = (0, misc_1.tryJson)(/exports.apiRequired\s*=\s*([ \d.,[\]]+)/.exec(source)?.[1]) ?? undefined;
659
+ pl.isTheme = (0, misc_1.tryJson)(/exports.isTheme\s*=\s*(true|false|"light"|"dark")/.exec(source)?.[1]) ?? (id.endsWith('-theme') || undefined);
660
+ pl.preview = (0, misc_1.tryJson)(/exports.preview\s*=\s*(.+)/.exec(source)?.[1]) ?? undefined;
661
+ 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
662
  || 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]);
663
+ pl.changelog = (0, misc_1.tryJson)(/exports.changelog\s*=\s*(\[[\s\S]*?])/m.exec(source)?.[1]);
675
664
  if (Array.isArray(pl.apiRequired) && (pl.apiRequired.length !== 2 || !pl.apiRequired.every(lodash_1.default.isFinite))) // validate [from,to] form
676
665
  pl.apiRequired = undefined;
677
666
  calculateBadApi(pl);
@@ -685,13 +674,13 @@ function calculateBadApi(data) {
685
674
  : undefined;
686
675
  }
687
676
  function getMissingDependencies(plugin) {
688
- return (0, misc_1.onlyTruthy)(((plugin === null || plugin === void 0 ? void 0 : plugin.depend) || []).map((dep) => {
677
+ return (0, misc_1.onlyTruthy)((plugin?.depend || []).map((dep) => {
689
678
  const res = findPluginByRepo(dep.repo);
690
679
  const error = !res ? 'missing'
691
680
  : (res.version || 0) < dep.version ? 'version'
692
681
  : !isPluginEnabled(res.id) ? 'disabled'
693
682
  : !isPluginRunning(res.id) ? 'stopped'
694
683
  : '';
695
- return error && { repo: dep.repo, error, id: res === null || res === void 0 ? void 0 : res.id };
684
+ return error && { repo: dep.repo, error, id: res?.id };
696
685
  }));
697
686
  }
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';
@@ -40,7 +40,7 @@ function serveStatic(uri) {
40
40
  return ctx.status = const_1.HTTP_METHOD_NOT_ALLOWED;
41
41
  const serveApp = shouldServeApp(ctx);
42
42
  const fullPath = (0, path_1.join)(__dirname, '..', folder, serveApp ? '/index.html' : ctx.path);
43
- const content = await (0, misc_1.parseFileContent)(fullPath, raw => serveApp || !raw.length ? raw : adjustBundlerLinks(ctx, uri, raw))
43
+ const content = await (0, misc_1.parseFile)(fullPath, raw => serveApp || !raw.length ? raw : adjustBundlerLinks(ctx, uri, raw))
44
44
  .catch(() => null);
45
45
  if (content === null)
46
46
  return ctx.status = const_1.HTTP_NOT_FOUND;
@@ -51,8 +51,7 @@ function serveStatic(uri) {
51
51
  };
52
52
  }
53
53
  function shouldServeApp(ctx) {
54
- var _a;
55
- return (_a = ctx.state).serveApp || (_a.serveApp = ctx.path.endsWith('/') && !ctx.headers.upgrade); // skip websockets
54
+ return ctx.state.serveApp ||= ctx.path.endsWith('/') && !ctx.headers.upgrade; // skip websockets
56
55
  }
57
56
  function adjustBundlerLinks(ctx, uri, data) {
58
57
  const ext = (0, path_1.extname)(ctx.path);
@@ -61,8 +60,8 @@ function adjustBundlerLinks(ctx, uri, data) {
61
60
  }
62
61
  const getFaviconTimestamp = (0, misc_1.debounceAsync)(async () => {
63
62
  const f = adminApis_1.favicon.get();
64
- return !f ? 0 : (0, misc_1.statWithTimeout)(f).then(x => (x === null || x === void 0 ? void 0 : x.mtimeMs) || 0, () => 0);
65
- }, { retain: 5000 });
63
+ return !f ? 0 : (0, misc_1.statWithTimeout)(f).then(x => x?.mtimeMs || 0, () => 0);
64
+ }, { retain: 5_000 });
66
65
  async function treatIndex(ctx, filesUri, body) {
67
66
  const session = await (0, api_auth_1.refresh_session)({}, ctx);
68
67
  ctx.set('etag', '');
@@ -72,13 +71,9 @@ async function treatIndex(ctx, filesUri, body) {
72
71
  const pub = ctx.state.revProxyPath + const_1.PLUGINS_PUB_URI;
73
72
  // expose plugins' configs that are declared with 'frontend' attribute
74
73
  const plugins = Object.fromEntries((0, misc_1.onlyTruthy)((0, plugins_1.mapPlugins)((pl, name) => {
75
- var _a, _b;
76
- let configs = (0, misc_1.newObj)((0, plugins_1.getPluginConfigFields)(name), (v, k, skip) => {
77
- var _a, _b, _c;
78
- return !v.frontend ? skip() :
79
- adjustValueByConfig((_b = (_a = plugins_1.pluginsConfig.get()) === null || _a === void 0 ? void 0 : _a[name]) === null || _b === void 0 ? void 0 : _b[k], (_c = pl.getData().config) === null || _c === void 0 ? void 0 : _c[k]);
80
- });
81
- configs = ((_b = (_a = (0, plugins_1.getPluginInfo)(name)).onFrontendConfig) === null || _b === void 0 ? void 0 : _b.call(_a, configs)) || configs;
74
+ let configs = (0, misc_1.newObj)((0, plugins_1.getPluginConfigFields)(name), (v, k, skip) => !v.frontend ? skip() :
75
+ adjustValueByConfig(plugins_1.pluginsConfig.get()?.[name]?.[k], pl.getData().config?.[k]));
76
+ configs = (0, plugins_1.getPluginInfo)(name).onFrontendConfig?.(configs) || configs;
82
77
  return !lodash_1.default.isEmpty(configs) && [name, configs];
83
78
  })));
84
79
  const timestamp = await getFaviconTimestamp();
@@ -98,7 +93,7 @@ async function treatIndex(ctx, filesUri, body) {
98
93
  SPECIAL_URI: const_1.SPECIAL_URI, PLUGINS_PUB_URI: const_1.PLUGINS_PUB_URI, FRONTEND_URI: const_1.FRONTEND_URI,
99
94
  session: session instanceof apiMiddleware_1.ApiError ? null : session,
100
95
  plugins,
101
- loadScripts: Object.fromEntries((0, plugins_1.mapPlugins)((p, id) => { var _a; return [id, (_a = p.frontend_js) === null || _a === void 0 ? void 0 : _a.map(f => f.includes('//') ? f : pub + id + '/' + f)]; })),
96
+ loadScripts: Object.fromEntries((0, plugins_1.mapPlugins)((p, id) => [id, p.frontend_js?.map(f => f.includes('//') ? f : pub + id + '/' + f)])),
102
97
  prefixUrl: ctx.state.revProxyPath,
103
98
  dontOverwriteUploading: upload_1.dontOverwriteUploading.get(),
104
99
  splitUploads: splitUploads.get(),
@@ -132,10 +127,7 @@ async function treatIndex(ctx, filesUri, body) {
132
127
  }
133
128
  ${isFrontend && (0, customHtml_1.getSection)('style')}
134
129
  </style>
135
- ${isFrontend && (0, plugins_1.mapPlugins)((plug, id) => {
136
- var _a;
137
- return (_a = plug.frontend_css) === null || _a === void 0 ? void 0 : _a.map(f => `<link rel='stylesheet' type='text/css' href='${f.includes('//') ? f : pub + id + '/' + f}' plugin=${JSON.stringify(id)}/>`);
138
- })
130
+ ${isFrontend && (0, plugins_1.mapPlugins)((plug, id) => plug.frontend_css?.map(f => `<link rel='stylesheet' type='text/css' href='${f.includes('//') ? f : pub + id + '/' + f}' plugin=${JSON.stringify(id)}/>`))
139
131
  .flat().filter(Boolean).join('\n')}
140
132
  `;
141
133
  if (isBody && isClose)
@@ -143,7 +135,7 @@ async function treatIndex(ctx, filesUri, body) {
143
135
  return all; // unchanged
144
136
  });
145
137
  function adjustValueByConfig(v, cfg) {
146
- v !== null && v !== void 0 ? v : (v = cfg.defaultValue);
138
+ v ??= cfg.defaultValue;
147
139
  const { type } = cfg;
148
140
  if (v && type === 'vfs_path') {
149
141
  v = (0, misc_1.enforceStarting)('/', v);
@@ -162,9 +154,8 @@ async function treatIndex(ctx, filesUri, body) {
162
154
  }
163
155
  }
164
156
  function serializeCss(v) {
165
- var _a;
166
157
  return typeof v === 'string' && /^#[0-9a-fA-F]{3,8}|rgba?\(.+\)$/.test(v) ? v // colors
167
- : (0, misc_1.isPrimitive)(v) ? (_a = JSON.stringify(v)) === null || _a === void 0 ? void 0 : _a.replace(/</g, '&lt;') : undefined;
158
+ : (0, misc_1.isPrimitive)(v) ? JSON.stringify(v)?.replace(/</g, '&lt;') : undefined;
168
159
  }
169
160
  function serveProxied(port, uri) {
170
161
  if (!port)