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/api.net.js CHANGED
@@ -15,7 +15,7 @@ const net_1 = require("net");
15
15
  const nat_1 = require("./nat");
16
16
  const acme_1 = require("./acme");
17
17
  const selfCheck_1 = require("./selfCheck");
18
- const apis = {
18
+ exports.default = {
19
19
  get_nat: nat_1.getNatInfo,
20
20
  get_public_ips: nat_1.getPublicIps,
21
21
  async check_domain({ domain }) {
@@ -88,4 +88,3 @@ const apis = {
88
88
  return (0, listen_1.getCertObject)() || { none: true };
89
89
  }
90
90
  };
91
- exports.default = apis;
@@ -33,15 +33,14 @@ const apis = {
33
33
  const errs = {};
34
34
  list.events(ctx, {
35
35
  pluginDownload({ repo, status }) {
36
- var _a;
37
- list.update({ id: (_a = (0, plugins_1.findPluginByRepo)(repo)) === null || _a === void 0 ? void 0 : _a.id }, { downloading: status !== null && status !== void 0 ? status : null });
36
+ list.update({ id: (0, plugins_1.findPluginByRepo)(repo)?.id }, { downloading: status ?? null });
38
37
  },
39
38
  pluginDownloaded({ id }) {
40
39
  list.update({ id }, { updated: true });
41
40
  }
42
41
  });
42
+ await plugins_1.pluginsScanned;
43
43
  await Promise.allSettled(lodash_1.default.map((0, github_1.getFolder2repo)(), async (repo, folder) => {
44
- var _a;
45
44
  try {
46
45
  if (!repo)
47
46
  return;
@@ -63,7 +62,7 @@ const apis = {
63
62
  }
64
63
  catch (err) {
65
64
  if (err.message !== '404') // the plugin is declaring a wrong repo
66
- (errs[_a = err.code || err.message] || (errs[_a] = [])).push(repo);
65
+ (errs[err.code || err.message] ||= []).push(repo);
67
66
  }
68
67
  }));
69
68
  if (!lodash_1.default.isEmpty(errs))
@@ -98,7 +97,7 @@ const apis = {
98
97
  return {
99
98
  enabled: plugins_1.enablePlugins.get().includes(id),
100
99
  config: {
101
- ...(0, misc_1.newObj)((0, plugins_1.getPluginConfigFields)(id), v => v === null || v === void 0 ? void 0 : v.defaultValue),
100
+ ...(0, misc_1.newObj)((0, plugins_1.getPluginConfigFields)(id), v => v?.defaultValue),
102
101
  ...plugins_1.pluginsConfig.get()[id]
103
102
  }
104
103
  };
@@ -121,7 +120,7 @@ const apis = {
121
120
  },
122
121
  pluginDownload({ repo, status }) {
123
122
  if (repos.includes(repo))
124
- list.update({ id: repo }, { downloading: status !== null && status !== void 0 ? status : null });
123
+ list.update({ id: repo }, { downloading: status ?? null });
125
124
  }
126
125
  });
127
126
  try {
@@ -180,14 +179,13 @@ const apis = {
180
179
  };
181
180
  exports.default = apis;
182
181
  function serialize(p) {
183
- var _a;
184
182
  let o = 'getData' in p ? Object.assign(lodash_1.default.pick(p, ['id', 'started']), p.getData())
185
183
  : { ...p }; // _.defaults mutates object, and we don't want that
186
184
  if (typeof o.repo === 'object') // custom repo
187
185
  o.repo = o.repo.web;
188
- o.log = 'log' in p && ((_a = p.log) === null || _a === void 0 ? void 0 : _a.length) > 0;
189
- o.config && (o.config = lodash_1.default.isFunction(o.config) ? String(o.config)
190
- : JSON.stringify(o.config, (_k, v) => lodash_1.default.isFunction(v) ? String(v) : v)); // allow simple functions
186
+ o.log = 'log' in p && p.log?.length > 0;
187
+ o.config &&= lodash_1.default.isFunction(o.config) ? String(o.config)
188
+ : JSON.stringify(o.config, (_k, v) => lodash_1.default.isFunction(v) ? String(v) : v); // allow simple functions
191
189
  return lodash_1.default.defaults(o, { started: null, badApi: null }); // nulls should be used to be sure to overwrite previous values,
192
190
  }
193
191
  async function checkDependencies(plugin) {
package/src/api.vfs.js CHANGED
@@ -20,21 +20,20 @@ const walkDir_1 = require("./walkDir");
20
20
  // to manipulate the tree we need the original node
21
21
  async function urlToNodeOriginal(uri) {
22
22
  const n = await (0, vfs_1.urlToNode)(uri);
23
- return (n === null || n === void 0 ? void 0 : n.isTemp) ? n.original : n;
23
+ return n?.isTemp ? n.original : n;
24
24
  }
25
25
  const ALLOWED_KEYS = ['name', 'source', 'masks', 'default', 'accept', 'rename', 'mime', 'url',
26
26
  'target', 'comment', 'icon', 'order', ...misc_1.PERM_KEYS];
27
- const apis = {
27
+ exports.default = {
28
28
  async get_vfs() {
29
29
  return { root: await recur() };
30
30
  async function recur(node = vfs_1.vfs) {
31
- var _a, _b, _c;
32
31
  const { source } = node;
33
- const stats = !source ? undefined : (node.stats || await (0, misc_1.statWithTimeout)(source).catch(() => undefined));
34
- const isDir = !(0, vfs_1.nodeIsLink)(node) && (!source || ((_a = stats === null || stats === void 0 ? void 0 : stats.isDirectory()) !== null && _a !== void 0 ? _a : (source.endsWith('/') || ((_b = node.children) === null || _b === void 0 ? void 0 : _b.length) > 0)));
32
+ const stats = await (0, vfs_1.nodeStats)(node);
33
+ const isFolder = (0, vfs_1.nodeIsFolder)(node);
35
34
  const copyStats = stats ? lodash_1.default.pick(stats, ['size', 'birthtime', 'mtime'])
36
35
  : { size: source ? -1 : undefined };
37
- if (copyStats.mtime && ((stats === null || stats === void 0 ? void 0 : stats.mtimeMs) - (stats === null || stats === void 0 ? void 0 : stats.birthtimeMs)) < 1000)
36
+ if (copyStats.mtime && (stats?.mtimeMs - stats?.birthtimeMs) < 1000)
38
37
  delete copyStats.mtime;
39
38
  const inherited = node.parent && (0, vfs_1.permsFromParent)(node.parent, {});
40
39
  const byMasks = node.original && lodash_1.default.pickBy(node, (v, k) => v !== node.original[k] // something is changing me...
@@ -45,17 +44,16 @@ const apis = {
45
44
  ...node.original || node,
46
45
  inherited,
47
46
  byMasks: lodash_1.default.isEmpty(byMasks) ? undefined : byMasks,
48
- website: Boolean((_c = node.children) === null || _c === void 0 ? void 0 : _c.find((0, vfs_1.isSameFilenameAs)('index.html')))
49
- || isDir && source && await (0, misc_1.statWithTimeout)((0, path_1.join)(source, 'index.html')).then(() => true, () => undefined)
47
+ website: Boolean(node.children?.find((0, vfs_1.isSameFilenameAs)('index.html')))
48
+ || isFolder && source && await (0, misc_1.statWithTimeout)((0, path_1.join)(source, 'index.html')).then(() => true, () => undefined)
50
49
  || undefined,
51
50
  name: (0, vfs_1.getNodeName)(node),
52
- type: isDir ? 'folder' : undefined,
51
+ type: isFolder ? 'folder' : undefined,
53
52
  children: node.children && await Promise.all(node.children.map(async (child) => recur(await (0, vfs_1.applyParentToChild)(child, node))))
54
53
  };
55
54
  }
56
55
  },
57
56
  async move_vfs({ from, parent }) {
58
- var _a;
59
57
  if (!from || !parent)
60
58
  return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST);
61
59
  const fromNode = await urlToNodeOriginal(from);
@@ -69,18 +67,17 @@ const apis = {
69
67
  if (!parentNode)
70
68
  return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'parent not found');
71
69
  const name = (0, vfs_1.getNodeName)(fromNode);
72
- if ((_a = parentNode.children) === null || _a === void 0 ? void 0 : _a.find(x => name === (0, vfs_1.getNodeName)(x)))
70
+ if (parentNode.children?.find(x => name === (0, vfs_1.getNodeName)(x)))
73
71
  return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT, 'item with same name already present in destination');
74
72
  const oldParent = await urlToNodeOriginal((0, path_1.dirname)(from));
75
73
  lodash_1.default.pull(oldParent.children, fromNode);
76
74
  if (lodash_1.default.isEmpty(oldParent.children))
77
75
  delete oldParent.children;
78
- (parentNode.children || (parentNode.children = [])).push(fromNode);
76
+ (parentNode.children ||= []).push(fromNode);
79
77
  await (0, vfs_1.saveVfs)();
80
78
  return {};
81
79
  },
82
80
  async set_vfs({ uri, props }) {
83
- var _a;
84
81
  const n = await urlToNodeOriginal(uri);
85
82
  if (!n)
86
83
  return new apiMiddleware_1.ApiError(const_1.HTTP_NOT_FOUND, 'path not found');
@@ -88,7 +85,7 @@ const apis = {
88
85
  if (!(0, misc_1.isValidFileName)(props.name))
89
86
  return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'bad name');
90
87
  const parent = await urlToNodeOriginal((0, path_1.dirname)(uri));
91
- if ((_a = parent === null || parent === void 0 ? void 0 : parent.children) === null || _a === void 0 ? void 0 : _a.find(x => (0, vfs_1.getNodeName)(x) === props.name))
88
+ if (parent?.children?.find(x => (0, vfs_1.getNodeName)(x) === props.name))
92
89
  return new apiMiddleware_1.ApiError(const_1.HTTP_CONFLICT, 'name already present');
93
90
  }
94
91
  if (props.masks && typeof props.masks !== 'object')
@@ -100,7 +97,6 @@ const apis = {
100
97
  return n;
101
98
  },
102
99
  async add_vfs({ parent, source, name, ...rest }) {
103
- var _a;
104
100
  if (!source && !name)
105
101
  return new apiMiddleware_1.ApiError(const_1.HTTP_BAD_REQUEST, 'name or source required');
106
102
  if (!(0, misc_1.isValidFileName)(name))
@@ -120,11 +116,11 @@ const apis = {
120
116
  const ext = (0, path_1.extname)(name);
121
117
  const noExt = ext ? name.slice(0, -ext.length) : name;
122
118
  let idx = 2;
123
- while ((_a = parentNode.children) === null || _a === void 0 ? void 0 : _a.find((0, vfs_1.isSameFilenameAs)(name)))
119
+ while (parentNode.children?.find((0, vfs_1.isSameFilenameAs)(name)))
124
120
  name = `${noExt} ${idx++}${ext}`;
125
121
  child.name = name;
126
122
  simplifyName(child);
127
- (parentNode.children || (parentNode.children = [])).unshift(child);
123
+ (parentNode.children ||= []).unshift(child);
128
124
  await (0, vfs_1.saveVfs)();
129
125
  const link = rest.url ? undefined : await (0, listen_1.getBaseUrlOrDefault)()
130
126
  + (parent ? (0, misc_1.enforceStarting)('/', (0, misc_1.enforceFinal)('/', parent)) : '/')
@@ -207,7 +203,7 @@ const apis = {
207
203
  k: isDir ? 'd' : undefined,
208
204
  });
209
205
  }
210
- catch (_a) { } // just ignore entries we can't stat
206
+ catch { } // just ignore entries we can't stat
211
207
  });
212
208
  await sendPropsAsap.catch(() => { });
213
209
  list.close();
@@ -251,7 +247,6 @@ const apis = {
251
247
  return {};
252
248
  },
253
249
  };
254
- exports.default = apis;
255
250
  // pick only selected props, and consider null and empty string as undefined, as it's the default value and we don't want to store it
256
251
  function pickProps(o, keys) {
257
252
  const ret = {};
@@ -13,6 +13,7 @@ const const_1 = require("./const");
13
13
  const config_1 = require("./config");
14
14
  const plugins_1 = require("./plugins");
15
15
  class ApiError extends Error {
16
+ status;
16
17
  constructor(status, message) {
17
18
  super(typeof message === 'string' ? message : message && message instanceof Error ? message.message : JSON.stringify(message));
18
19
  this.status = status;
@@ -22,20 +23,19 @@ exports.ApiError = ApiError;
22
23
  const logApi = (0, config_1.defineConfig)(misc_1.CFG.log_api, true);
23
24
  function apiMiddleware(apis) {
24
25
  return async (ctx) => {
25
- var _a;
26
26
  if (!logApi.get())
27
27
  ctx.state.dontLog = true;
28
28
  const isPost = ctx.state.params;
29
29
  const params = isPost ? ctx.state.params || {} : ctx.query;
30
30
  const apiName = ctx.path;
31
31
  console.debug('API', ctx.method, apiName, { ...params });
32
- const noBrowser = (_a = ctx.get('user-agent')) === null || _a === void 0 ? void 0 : _a.startsWith('curl');
32
+ const noBrowser = ctx.get('user-agent')?.startsWith('curl');
33
33
  const safe = noBrowser || isPost && ctx.get('x-hfs-anti-csrf') // POST is safe because browser will enforce SameSite cookie
34
34
  || apiName.startsWith('get_'); // "get_" apis are safe because they make no change
35
35
  if (!safe)
36
36
  return send(const_1.HTTP_FOOL, "missing header x-hfs-anti-csrf=1");
37
37
  const customApiRest = apiName.startsWith(const_1.PLUGIN_CUSTOM_REST_PREFIX) && apiName.slice(const_1.PLUGIN_CUSTOM_REST_PREFIX.length);
38
- const apiFun = customApiRest && (0, plugins_1.firstPlugin)(pl => { var _a; return (_a = pl.getData().customRest) === null || _a === void 0 ? void 0 : _a[customApiRest]; })
38
+ const apiFun = customApiRest && (0, plugins_1.firstPlugin)(pl => pl.getData().customRest?.[customApiRest])
39
39
  || apis.hasOwnProperty(apiName) && apis[apiName];
40
40
  if (!apiFun)
41
41
  return send(const_1.HTTP_BAD_REQUEST, 'invalid api');
@@ -74,5 +74,5 @@ function apiMiddleware(apis) {
74
74
  };
75
75
  }
76
76
  function isAsyncGenerator(x) {
77
- return typeof (x === null || x === void 0 ? void 0 : x.next) === 'function';
77
+ return typeof x?.next === 'function';
78
78
  }
package/src/auth.js CHANGED
@@ -28,10 +28,10 @@ async function srpServerStep1(account) {
28
28
  const srpServer = await srpSession.step1(account.username, BigInt(salt), BigInt(verifier));
29
29
  return { srpServer, salt, pubKey: String(srpServer.B) }; // cast to string cause bigint can't be jsonized
30
30
  }
31
- const cache = (0, expiringCache_1.expiringCache)(60000);
31
+ const cache = (0, expiringCache_1.expiringCache)(60_000);
32
32
  async function srpCheck(username, password) {
33
33
  const account = (0, perm_1.getAccount)(username);
34
- if (!(account === null || account === void 0 ? void 0 : account.srp) || !password)
34
+ if (!account?.srp || !password)
35
35
  return;
36
36
  const k = (0, node_crypto_1.createHash)('sha256').update(username + password + account.srp).digest("hex");
37
37
  const good = await cache.try(k, async () => {
@@ -42,17 +42,15 @@ async function srpCheck(username, password) {
42
42
  return good ? account : undefined;
43
43
  }
44
44
  function getCurrentUsername(ctx) {
45
- var _a;
46
- return ((_a = ctx.state.account) === null || _a === void 0 ? void 0 : _a.username) || '';
45
+ return ctx.state.account?.username || '';
47
46
  }
48
47
  async function clearTextLogin(ctx, u, p, via) {
49
- var _a;
50
48
  if (!p)
51
49
  return;
52
- if ((_a = (await events_1.default.emitAsync('attemptingLogin', { ctx, username: u, via }))) === null || _a === void 0 ? void 0 : _a.isDefaultPrevented())
50
+ if ((await events_1.default.emitAsync('attemptingLogin', { ctx, username: u, via }))?.isDefaultPrevented())
53
51
  return;
54
52
  const plugins = await events_1.default.emitAsync('clearTextLogin', { ctx, username: u, password: p, via }); // provide clear password to plugins
55
- const a = (plugins === null || plugins === void 0 ? void 0 : plugins.some(x => x === true)) ? (0, perm_1.getAccount)(u) : await srpCheck(u, p);
53
+ const a = plugins?.some(x => x === true) ? (0, perm_1.getAccount)(u) : await srpCheck(u, p);
56
54
  if (a) {
57
55
  await setLoggedIn(ctx, a.username);
58
56
  ctx.headers['x-username'] = a.username; // give an easier way to determine if the login was successful
@@ -63,7 +61,6 @@ async function clearTextLogin(ctx, u, p, via) {
63
61
  }
64
62
  // centralized log-in state
65
63
  async function setLoggedIn(ctx, username) {
66
- var _a;
67
64
  const s = ctx.session;
68
65
  if (!s)
69
66
  return ctx.throw(cross_const_1.HTTP_SERVER_ERROR, 'session');
@@ -80,7 +77,7 @@ async function setLoggedIn(ctx, username) {
80
77
  s.username = (0, perm_1.normalizeUsername)(username);
81
78
  s.ts = Date.now();
82
79
  const k = cross_const_1.ALLOW_SESSION_IP_CHANGE;
83
- s[k] = k in ctx.query || Boolean((_a = ctx.state.params) === null || _a === void 0 ? void 0 : _a[k]) || undefined; // login APIs will get ctx.state.params, others can rely on ctx.query
80
+ s[k] = k in ctx.query || Boolean(ctx.state.params?.[k]) || undefined; // login APIs will get ctx.state.params, others can rely on ctx.query
84
81
  if (!a.expire && a.days_to_live)
85
82
  (0, perm_1.updateAccount)(a, { expire: new Date(Date.now() + a.days_to_live * cross_1.DAY) });
86
83
  await events_1.default.emitAsync('login', ctx);
package/src/basicWeb.js CHANGED
@@ -60,8 +60,7 @@ function basicWeb(ctx, node) {
60
60
  }
61
61
  }
62
62
  function detectBasicAgent(ctx) {
63
- var _a;
64
63
  const ua = ctx.get('user-agent');
65
64
  return autoBasic.get() && /^$|Mozilla\/4|WebKit\/([234]\d\d|5[012]\d|53[0123456])[. ]|Trident|Lynx|curl|Firefox\/(\d|[1234]\d)\./.test(ua)
66
- || ((_a = autoBasic.compiled()) === null || _a === void 0 ? void 0 : _a.test(ua));
65
+ || autoBasic.compiled()?.test(ua);
67
66
  }
package/src/block.js CHANGED
@@ -17,7 +17,7 @@ exports.block = (0, config_1.defineConfig)('block', [], rules => {
17
17
  const now = new Date();
18
18
  const ret = !Array.isArray(rules) ? []
19
19
  : (0, misc_1.onlyTruthy)(rules.map(rule => {
20
- rule.expire && (rule.expire = new Date(rule.expire));
20
+ rule.expire &&= new Date(rule.expire);
21
21
  return !rule.disabled && (rule.expire || now) >= now && (0, misc_1.makeNetMatcher)(rule.ip);
22
22
  }));
23
23
  // reapply new block to existing connections
package/src/commands.js CHANGED
@@ -39,15 +39,15 @@ if (!argv_1.argv.updating && !config_1.showHelp) {
39
39
  function clean() {
40
40
  if (isClean)
41
41
  return;
42
- return cleaning || (cleaning = new Promise(resolve => {
42
+ return cleaning ||= new Promise(resolve => {
43
43
  (0, node_readline_1.cursorTo)(process.stdout, 0, undefined, () => {
44
44
  resolve();
45
45
  cleaning = undefined;
46
46
  isClean = true;
47
47
  });
48
- }));
48
+ });
49
49
  }
50
- showPrompt === null || showPrompt === void 0 ? void 0 : showPrompt();
50
+ showPrompt?.();
51
51
  // print this hint when we have not been printing anything else for a while, to not get mixed too much
52
52
  let printHintOnce = tty && lodash_1.default.debounce(() => {
53
53
  (0, consoleLog_1.consoleHint)("this is an interactive console, you can enter commands");
@@ -63,13 +63,13 @@ if (!argv_1.argv.updating && !config_1.showHelp) {
63
63
  v(...args);
64
64
  }
65
65
  finally {
66
- showPrompt === null || showPrompt === void 0 ? void 0 : showPrompt();
67
- printHintOnce === null || printHintOnce === void 0 ? void 0 : printHintOnce();
66
+ showPrompt?.();
67
+ printHintOnce?.();
68
68
  }
69
69
  };
70
70
  });
71
71
  }
72
- catch (_a) {
72
+ catch {
73
73
  console.log("console commands not available");
74
74
  }
75
75
  }
@@ -79,7 +79,7 @@ async function parseCommandLine(line) {
79
79
  let [name, ...params] = line.trim().split(/ +/);
80
80
  name = aliases[name] || name;
81
81
  let cmd = commands[name];
82
- if (cmd === null || cmd === void 0 ? void 0 : cmd.alias)
82
+ if (cmd?.alias)
83
83
  cmd = commands[cmd.alias];
84
84
  if (!cmd)
85
85
  return console.error("invalid command, try 'help'");
@@ -90,7 +90,7 @@ async function parseCommandLine(line) {
90
90
  console.log("+++ command executed");
91
91
  }
92
92
  catch (err) {
93
- if (typeof err !== 'string' && !(err === null || err === void 0 ? void 0 : err.message))
93
+ if (typeof err !== 'string' && !err?.message)
94
94
  throw err;
95
95
  console.error("command failed:", err.message || err);
96
96
  }
@@ -131,7 +131,7 @@ const commands = {
131
131
  try {
132
132
  v = JSON.parse(v);
133
133
  }
134
- catch (_a) { }
134
+ catch { }
135
135
  await (0, config_1.setConfig)({ [key]: v });
136
136
  }
137
137
  },
package/src/comments.js CHANGED
@@ -19,8 +19,7 @@ const promises_1 = require("node:fs/promises");
19
19
  exports.DESCRIPT_ION = 'descript.ion';
20
20
  const commentsStorage = (0, config_1.defineConfig)(cross_1.CFG.comments_storage, '', v => ['', 'attr+ion'].includes(v)); // compiled tell us if we are using descript.ion
21
21
  (0, config_1.defineConfig)('descript_ion', true, (v, more) => {
22
- var _a;
23
- if (!v && ((_a = more.version) === null || _a === void 0 ? void 0 : _a.olderThan('0.57.0-alpha1')))
22
+ if (!v && more.version?.olderThan('0.57.0-alpha1'))
24
23
  commentsStorage.set('attr');
25
24
  });
26
25
  const descriptIonEncoding = (0, config_1.defineConfig)('descript_ion_encoding', 'utf8');
@@ -35,7 +34,7 @@ async function getCommentFor(path) {
35
34
  return !path ? undefined : Promise.all([
36
35
  commentsStorage.get() ? (0, misc_1.loadFileAttr)(path, COMMENT_ATTR) : undefined,
37
36
  readFromDescriptIon(path)
38
- ]).then(([fromAttr, fromIon]) => fromAttr || fromIon);
37
+ ]).then(([fromAttr, fromIon]) => fromAttr || fromIon || undefined);
39
38
  }
40
39
  async function setCommentFor(path, comment) {
41
40
  if (commentsStorage.get()) {
@@ -59,7 +58,7 @@ const setCommentDescriptIon = (0, misc_1.singleWorkerFromBatchWorker)(async (job
59
58
  if (!comments.size)
60
59
  return (0, promises_1.unlink)(path);
61
60
  // encode comments in descript.ion format
62
- const ws = await (0, util_files_1.safeWriteStream)(path);
61
+ const ws = await (0, util_files_1.createSafeWriteStream)(path);
63
62
  comments.forEach((comment, filename) => {
64
63
  const multiline = comment.includes('\n');
65
64
  const line = (filename.includes(' ') ? `"${filename}"` : filename)
@@ -78,7 +77,7 @@ function areCommentsEnabled() {
78
77
  const MULTILINE_SUFFIX = Buffer.from([4, 0xC2]);
79
78
  function readDescriptIon(path) {
80
79
  // decoding could also be done with native TextDecoder.decode, but we need iconv for the encoding anyway
81
- return (0, util_files_1.parseFileContent)((0, path_1.join)(path, exports.DESCRIPT_ION), raw => {
80
+ return (0, util_files_1.parseFile)((0, path_1.join)(path, exports.DESCRIPT_ION), raw => {
82
81
  // for simplicity we "remove" the sequence MULTILINE_SUFFIX before iconv.decode messes it up
83
82
  for (let i = 0; i < raw.length; i++)
84
83
  if (raw[i] === MULTILINE_SUFFIX[0] && raw[i + 1] === MULTILINE_SUFFIX[1] && [undefined, 13, 10].includes(raw[i + 2]))
package/src/config.js CHANGED
@@ -37,7 +37,7 @@ const filePath = (0, cross_1.with_)(argv_1.argv.config || process.env.HFS_CONFIG
37
37
  if ((0, fs_1.statSync)(p).isDirectory()) // try to detect if path points to a folder, in which case we add the standard filename
38
38
  return (0, path_1.join)(p, const_1.CONFIG_FILE);
39
39
  }
40
- catch (_a) { }
40
+ catch { }
41
41
  return p;
42
42
  });
43
43
  // takes a semver like 1.2.3-alpha1, but alpha and beta numbers must share the number progression
@@ -52,6 +52,7 @@ exports.versionToScalar = lodash_1.default.memoize((ver) => {
52
52
  return officialScalar - betaScalar;
53
53
  });
54
54
  class Version extends String {
55
+ scalar;
55
56
  constructor(v) {
56
57
  super(v);
57
58
  this.scalar = (0, exports.versionToScalar)(v);
@@ -101,7 +102,7 @@ function defineConfig(k, defaultValue, compiler) {
101
102
  return events_1.default.emitAsync(CONFIG_CHANGE_EVENT_PREFIX + k, was, was, const_1.VERSION, true);
102
103
  }
103
104
  };
104
- let compiled = compiler === null || compiler === void 0 ? void 0 : compiler(defaultValue, { k, version: exports.currentVersion, defaultValue, object });
105
+ let compiled = compiler?.(defaultValue, { k, version: exports.currentVersion, defaultValue, object });
105
106
  if (compiler)
106
107
  object.sub((v, more) => {
107
108
  if (!more.onlyCompileChanged)
@@ -114,13 +115,12 @@ function configKeyExists(k) {
114
115
  }
115
116
  const stack = [];
116
117
  function getConfig(k) {
117
- var _a, _b;
118
- return (_a = state[k]) !== null && _a !== void 0 ? _a : lodash_1.default.cloneDeep((_b = configProps[k]) === null || _b === void 0 ? void 0 : _b.defaultValue); // clone to avoid changing
118
+ return state[k] ?? lodash_1.default.cloneDeep(configProps[k]?.defaultValue); // clone to avoid changing
119
119
  }
120
120
  function getWholeConfig({ omit, only }) {
121
121
  const defs = (0, cross_1.newObj)(configProps, x => x.defaultValue);
122
122
  let copy = lodash_1.default.defaults({}, state, defs);
123
- if (omit === null || omit === void 0 ? void 0 : omit.length)
123
+ if (omit?.length)
124
124
  copy = lodash_1.default.omit(copy, omit);
125
125
  if (only)
126
126
  copy = lodash_1.default.pick(copy, only);
@@ -150,18 +150,17 @@ async function setConfig(newCfg, save) {
150
150
  await Promise.allSettled(Object.keys(configProps).map(k => newCfg.hasOwnProperty(k) || apply(k, undefined, true)));
151
151
  started = true;
152
152
  events_1.default.emit('configReady', startedWithoutConfig);
153
- if ((version === null || version === void 0 ? void 0 : version.valueOf()) !== const_1.VERSION) // be sure to save the new version in the file
153
+ if (version?.valueOf() !== const_1.VERSION) // be sure to save the new version in the file
154
154
  (0, exports.saveConfigAsap)();
155
155
  function apply(k, newV, isDefault = false) {
156
156
  return setConfig1(k, newV, save === undefined, argCfg && k in argCfg || isDefault ? exports.currentVersion : version);
157
157
  }
158
158
  }
159
159
  async function setConfig1(k, newV, saveChanges = true, valueVersion) {
160
- var _a;
161
160
  if (lodash_1.default.isPlainObject(newV))
162
161
  newV = lodash_1.default.pickBy(newV, x => x !== undefined);
163
- const def = (_a = configProps[k]) === null || _a === void 0 ? void 0 : _a.defaultValue;
164
- if (same(newV !== null && newV !== void 0 ? newV : null, def !== null && def !== void 0 ? def : null))
162
+ const def = configProps[k]?.defaultValue;
163
+ if (same(newV ?? null, def ?? null))
165
164
  newV = undefined;
166
165
  if (started && same(newV, state[k]))
167
166
  return; // no change
@@ -17,12 +17,18 @@ const events_1 = __importDefault(require("./events"));
17
17
  const geo_1 = require("./geo");
18
18
  const lodash_1 = __importDefault(require("lodash"));
19
19
  class Connection {
20
+ socket;
21
+ started = new Date();
22
+ sent = 0; // socket-scoped, not request-scoped
23
+ got = 0;
24
+ outSpeed;
25
+ inSpeed;
26
+ ctx; // this is set externally, during koa middleware, using updateConnectionForCtx, but only for regular requests; some connections may never have a ctx
27
+ country;
28
+ _cachedIp;
20
29
  // the sockets we collect are the plain ones, as soon as the tcp layer is connected
21
30
  constructor(socket) {
22
31
  this.socket = socket;
23
- this.started = new Date();
24
- this.sent = 0; // socket-scoped, not request-scoped
25
- this.got = 0;
26
32
  all.push(this);
27
33
  socket.on('close', () => {
28
34
  all.splice(all.indexOf(this), 1);
@@ -31,12 +37,11 @@ class Connection {
31
37
  events_1.default.emit('connection', this);
32
38
  }
33
39
  get ip() {
34
- var _a, _b;
35
40
  if (this._cachedIp && this.ctx && this._cachedIp !== this.ctx.ip) {
36
41
  events_1.default.emit('connectionNewIp', this, this._cachedIp, this.ctx.ip);
37
42
  this._cachedIp = undefined;
38
43
  }
39
- return ((_a = this.ctx) === null || _a === void 0 ? void 0 : _a.ip) || ((_b = this._cachedIp) !== null && _b !== void 0 ? _b : (this._cachedIp = normalizeIp(this.socket.remoteAddress || '')));
44
+ return this.ctx?.ip || (this._cachedIp ??= normalizeIp(this.socket.remoteAddress || ''));
40
45
  }
41
46
  get secure() {
42
47
  return this.socket.server.cert > '';
@@ -50,7 +55,7 @@ const all = [];
50
55
  function newConnection(socket) {
51
56
  const ip = normalizeIp(socket.remoteAddress || '');
52
57
  const res = events_1.default.emit('newSocket', { socket, ip });
53
- const msg = (res === null || res === void 0 ? void 0 : res.isDefaultPrevented()) ? 'plugin (newSocket)' : res === null || res === void 0 ? void 0 : res.find(lodash_1.default.isString);
58
+ const msg = res?.isDefaultPrevented() ? 'plugin (newSocket)' : res?.find(lodash_1.default.isString);
54
59
  if (!msg)
55
60
  return new Connection(socket);
56
61
  disconnect(socket, msg);
package/src/consoleLog.js CHANGED
@@ -21,10 +21,10 @@ for (const k of ['log', 'warn', 'error', 'debug']) {
21
21
  const msg = safeJoin(args); // if args contains a symbol, join will throw
22
22
  const rec = { ts, k, msg };
23
23
  exports.consoleLog.push(rec);
24
- if (exports.consoleLog.length > 100000) // limit to avoid infinite space
25
- exports.consoleLog.splice(0, 1000);
24
+ if (exports.consoleLog.length > 100_000) // limit to avoid infinite space
25
+ exports.consoleLog.splice(0, 1_000);
26
26
  events_1.default.emit('console', rec);
27
- f === null || f === void 0 ? void 0 : f.write(`${(0, cross_1.formatTimestamp)(ts)} [${k}] ${msg}\n`);
27
+ f?.write(`${(0, cross_1.formatTimestamp)(ts)} [${k}] ${msg}\n`);
28
28
  if (k !== 'log')
29
29
  args.unshift('!');
30
30
  }
@@ -35,20 +35,20 @@ function safeJoin(a) {
35
35
  try {
36
36
  return a.join(' ');
37
37
  }
38
- catch (_a) {
38
+ catch {
39
39
  return a.map(x => {
40
40
  if (x == null)
41
41
  return '';
42
42
  try {
43
43
  return String(x);
44
44
  }
45
- catch (_a) {
45
+ catch {
46
46
  if (Array.isArray(x))
47
47
  return `[${safeJoin(x)}]`;
48
48
  try {
49
49
  return JSON.stringify(x);
50
50
  }
51
- catch (_b) {
51
+ catch {
52
52
  return 'N/A';
53
53
  }
54
54
  }
package/src/const.js CHANGED
@@ -49,7 +49,7 @@ const path_1 = require("path");
49
49
  const cross_1 = require("./cross");
50
50
  const argv_1 = require("./argv");
51
51
  __exportStar(require("./cross-const"), exports);
52
- exports.API_VERSION = 12.94;
52
+ exports.API_VERSION = 12.95;
53
53
  exports.COMPATIBLE_API_VERSION = 1; // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
54
54
  // you can add arguments with this file, currently used for the update process on mac/linux
55
55
  exports.ARGS_FILE = (0, path_1.join)((0, os_1.homedir)(), 'hfs-args');
@@ -59,12 +59,12 @@ try {
59
59
  lodash_1.default.defaults(argv_1.argv, (0, minimist_1.default)(JSON.parse(s)));
60
60
  fs.unlinkSync(exports.ARGS_FILE);
61
61
  }
62
- catch (_a) { }
62
+ catch { }
63
63
  exports.DEV = process.env.DEV ? 'DEV' : '';
64
64
  exports.ORIGINAL_CWD = process.cwd();
65
65
  exports.HFS_STARTED = new Date();
66
66
  const PKG_PATH = (0, path_1.join)(__dirname, '..', 'package.json');
67
- exports.BUILD_TIMESTAMP = "2025-11-01T14:38:09.771Z";
67
+ exports.BUILD_TIMESTAMP = "2025-11-30T11:15:41.563Z";
68
68
  const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
69
69
  exports.VERSION = pkg.version;
70
70
  exports.RUNNING_BETA = exports.VERSION.includes('-');
@@ -123,7 +123,7 @@ function useHomeDir() {
123
123
  fs.writeFileSync(exports.CONFIG_FILE, ''); // not found, try to create
124
124
  fs.unlinkSync(exports.CONFIG_FILE);
125
125
  }
126
- catch (_a) {
126
+ catch {
127
127
  return true;
128
128
  }
129
129
  }