hfs 0.26.8 → 0.26.9

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 (161) hide show
  1. package/admin/assets/index.bb5198ec.js +281 -0
  2. package/admin/assets/index.dcc78777.css +1 -0
  3. package/admin/assets/sha512.9dfe82e1.js +8 -0
  4. package/admin/index.html +3 -1
  5. package/admin/{public/logo.svg → logo.svg} +0 -0
  6. package/frontend/assets/index.27a78796.js +85 -0
  7. package/frontend/assets/index.93366732.css +1 -0
  8. package/frontend/assets/sha512.6af42937.js +8 -0
  9. package/frontend/{public/fontello.css → fontello.css} +0 -0
  10. package/frontend/{public/fontello.woff2 → fontello.woff2} +0 -0
  11. package/frontend/index.html +3 -1
  12. package/package.json +1 -1
  13. package/src/QuickZipStream.js +285 -0
  14. package/src/ThrottledStream.js +93 -0
  15. package/src/adminApis.js +169 -0
  16. package/src/api.accounts.js +59 -0
  17. package/src/api.auth.js +128 -0
  18. package/src/api.file_list.js +103 -0
  19. package/src/api.helpers.js +32 -0
  20. package/src/api.monitor.js +102 -0
  21. package/src/api.plugins.js +127 -0
  22. package/src/api.vfs.js +164 -0
  23. package/src/apiMiddleware.js +120 -0
  24. package/src/block.js +33 -0
  25. package/src/commands.js +124 -0
  26. package/src/config.js +168 -0
  27. package/src/connections.js +57 -0
  28. package/src/const.js +83 -0
  29. package/src/crypt.js +21 -0
  30. package/src/debounceAsync.js +48 -0
  31. package/src/events.js +9 -0
  32. package/src/frontEndApis.js +38 -0
  33. package/src/github.js +102 -0
  34. package/src/index.js +56 -0
  35. package/src/listen.js +235 -0
  36. package/src/log.js +137 -0
  37. package/src/middlewares.js +175 -0
  38. package/src/misc.js +160 -0
  39. package/src/pbkdf2.js +74 -0
  40. package/src/perm.js +181 -0
  41. package/src/plugins.js +343 -0
  42. package/src/serveFile.js +105 -0
  43. package/src/serveGuiFiles.js +113 -0
  44. package/src/sse.js +29 -0
  45. package/src/throttler.js +91 -0
  46. package/src/update.js +69 -0
  47. package/src/util-files.js +148 -0
  48. package/src/util-generators.js +30 -0
  49. package/src/util-http.js +30 -0
  50. package/src/vfs.js +230 -0
  51. package/src/watchLoad.js +73 -0
  52. package/src/zip.js +72 -0
  53. package/admin/.DS_Store +0 -0
  54. package/admin/.eslintrc +0 -8
  55. package/admin/.gitignore +0 -23
  56. package/admin/package.json +0 -67
  57. package/admin/src/AccountForm.ts +0 -92
  58. package/admin/src/AccountsPage.ts +0 -143
  59. package/admin/src/App.ts +0 -83
  60. package/admin/src/ArrayField.ts +0 -84
  61. package/admin/src/ConfigPage.ts +0 -279
  62. package/admin/src/FileField.ts +0 -52
  63. package/admin/src/FileForm.ts +0 -148
  64. package/admin/src/FilePicker.ts +0 -166
  65. package/admin/src/HomePage.ts +0 -96
  66. package/admin/src/InstalledPlugins.ts +0 -158
  67. package/admin/src/LoginRequired.ts +0 -75
  68. package/admin/src/LogoutPage.ts +0 -27
  69. package/admin/src/LogsPage.ts +0 -75
  70. package/admin/src/MainMenu.ts +0 -74
  71. package/admin/src/MenuButton.ts +0 -38
  72. package/admin/src/MonitorPage.ts +0 -200
  73. package/admin/src/OnlinePlugins.ts +0 -101
  74. package/admin/src/PermField.ts +0 -80
  75. package/admin/src/PluginsPage.ts +0 -27
  76. package/admin/src/VfsMenuBar.ts +0 -58
  77. package/admin/src/VfsPage.ts +0 -124
  78. package/admin/src/VfsTree.ts +0 -95
  79. package/admin/src/addFiles.ts +0 -59
  80. package/admin/src/api.ts +0 -246
  81. package/admin/src/dialog.ts +0 -203
  82. package/admin/src/index.css +0 -21
  83. package/admin/src/index.ts +0 -10
  84. package/admin/src/md.ts +0 -31
  85. package/admin/src/misc.ts +0 -141
  86. package/admin/src/react-app-env.d.ts +0 -1
  87. package/admin/src/reportWebVitals.ts +0 -15
  88. package/admin/src/setupTests.ts +0 -5
  89. package/admin/src/state.ts +0 -40
  90. package/admin/src/theme.ts +0 -37
  91. package/admin/tsconfig.json +0 -26
  92. package/admin/vite.config.ts +0 -32
  93. package/frontend/.DS_Store +0 -0
  94. package/frontend/.eslintrc +0 -8
  95. package/frontend/.gitignore +0 -23
  96. package/frontend/package.json +0 -51
  97. package/frontend/src/App.ts +0 -25
  98. package/frontend/src/Breadcrumbs.ts +0 -43
  99. package/frontend/src/BrowseFiles.ts +0 -141
  100. package/frontend/src/Head.ts +0 -45
  101. package/frontend/src/UserPanel.ts +0 -52
  102. package/frontend/src/api.ts +0 -78
  103. package/frontend/src/components.ts +0 -54
  104. package/frontend/src/dialog.css +0 -76
  105. package/frontend/src/dialog.ts +0 -105
  106. package/frontend/src/icons.ts +0 -46
  107. package/frontend/src/index.scss +0 -307
  108. package/frontend/src/index.ts +0 -10
  109. package/frontend/src/login.ts +0 -50
  110. package/frontend/src/menu.ts +0 -188
  111. package/frontend/src/misc.ts +0 -54
  112. package/frontend/src/options.ts +0 -52
  113. package/frontend/src/react-app-env.d.ts +0 -1
  114. package/frontend/src/reportWebVitals.ts +0 -15
  115. package/frontend/src/setupTests.ts +0 -5
  116. package/frontend/src/state.ts +0 -82
  117. package/frontend/src/useAuthorized.ts +0 -17
  118. package/frontend/src/useFetchList.ts +0 -144
  119. package/frontend/src/useTheme.ts +0 -23
  120. package/frontend/tsconfig.json +0 -26
  121. package/frontend/vite.config.ts +0 -21
  122. package/src/QuickZipStream.ts +0 -279
  123. package/src/ThrottledStream.ts +0 -98
  124. package/src/adminApis.ts +0 -161
  125. package/src/api.accounts.ts +0 -78
  126. package/src/api.auth.ts +0 -131
  127. package/src/api.file_list.ts +0 -102
  128. package/src/api.helpers.ts +0 -30
  129. package/src/api.monitor.ts +0 -106
  130. package/src/api.plugins.ts +0 -139
  131. package/src/api.vfs.ts +0 -182
  132. package/src/apiMiddleware.ts +0 -124
  133. package/src/block.ts +0 -35
  134. package/src/commands.ts +0 -122
  135. package/src/config.ts +0 -166
  136. package/src/connections.ts +0 -60
  137. package/src/const.ts +0 -57
  138. package/src/crypt.ts +0 -16
  139. package/src/debounceAsync.ts +0 -51
  140. package/src/events.ts +0 -6
  141. package/src/frontEndApis.ts +0 -17
  142. package/src/github.ts +0 -102
  143. package/src/index.ts +0 -53
  144. package/src/listen.ts +0 -220
  145. package/src/log.ts +0 -128
  146. package/src/middlewares.ts +0 -176
  147. package/src/misc.ts +0 -149
  148. package/src/pbkdf2.ts +0 -83
  149. package/src/perm.ts +0 -194
  150. package/src/plugins.ts +0 -342
  151. package/src/serveFile.ts +0 -104
  152. package/src/serveGuiFiles.ts +0 -95
  153. package/src/sse.ts +0 -29
  154. package/src/throttler.ts +0 -106
  155. package/src/update.ts +0 -67
  156. package/src/util-files.ts +0 -137
  157. package/src/util-generators.ts +0 -29
  158. package/src/util-http.ts +0 -29
  159. package/src/vfs.ts +0 -258
  160. package/src/watchLoad.ts +0 -75
  161. package/src/zip.ts +0 -69
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ // This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
26
+ var __importDefault = (this && this.__importDefault) || function (mod) {
27
+ return (mod && mod.__esModule) ? mod : { "default": mod };
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.serveGuiFiles = void 0;
31
+ const promises_1 = __importDefault(require("fs/promises"));
32
+ const const_1 = require("./const");
33
+ const serveFile_1 = require("./serveFile");
34
+ const plugins_1 = require("./plugins");
35
+ const api_auth_1 = require("./api.auth");
36
+ const apiMiddleware_1 = require("./apiMiddleware");
37
+ const path_1 = require("path");
38
+ const misc_1 = require("./misc");
39
+ // in case of dev env we have our static files within the 'dist' folder'
40
+ const DEV_STATIC = process.env.DEV ? 'dist/' : '';
41
+ function serveStatic(uri) {
42
+ const folder = uri.slice(2, -1); // we know folder is very similar to uri
43
+ const cache = {};
44
+ return async (ctx, next) => {
45
+ if (ctx.method === 'OPTIONS') {
46
+ ctx.status = const_1.NO_CONTENT;
47
+ ctx.set({ Allow: 'OPTIONS, GET' });
48
+ return;
49
+ }
50
+ if (ctx.method !== 'GET')
51
+ return ctx.status = const_1.METHOD_NOT_ALLOWED;
52
+ const serveApp = shouldServeApp(ctx);
53
+ const fullPath = (0, path_1.join)(__dirname, '..', DEV_STATIC, folder, serveApp ? '/index.html' : ctx.path);
54
+ const content = await (0, misc_1.getOrSet)(cache, ctx.path, async () => {
55
+ const data = await promises_1.default.readFile(fullPath).catch(() => null);
56
+ return serveApp || !data ? data
57
+ : adjustBundlerLinks(ctx.path, uri, data);
58
+ });
59
+ if (content === null)
60
+ return ctx.status = 404;
61
+ if (!serveApp)
62
+ return (0, serveFile_1.serveFile)(fullPath, 'auto', content)(ctx, next);
63
+ // we don't cache the index as it's small and may prevent plugins change to apply
64
+ ctx.body = await treatIndex(ctx, String(content), uri);
65
+ ctx.type = 'html';
66
+ ctx.set('Cache-Control', 'no-store, no-cache, must-revalidate');
67
+ };
68
+ }
69
+ function shouldServeApp(ctx) {
70
+ var _a;
71
+ return (_a = ctx.state).serveApp || (_a.serveApp = ctx.path.endsWith('/'));
72
+ }
73
+ function adjustBundlerLinks(path, uri, data) {
74
+ const ext = (0, path_1.extname)(path);
75
+ return ext && !ext.match(/\.(css|html|js|ts|scss)/) ? data
76
+ : String(data).replace(/((?:import | from )['"])\//g, `$1${uri}`);
77
+ }
78
+ async function treatIndex(ctx, body, filesUri) {
79
+ const session = await (0, api_auth_1.refresh_session)({}, ctx);
80
+ ctx.set('etag', '');
81
+ return body
82
+ .replace(/((?:src|href) *= *['"])\/?(?![a-z]+:\/\/)/g, '$1' + filesUri)
83
+ .replace('_HFS_SESSION_', session instanceof apiMiddleware_1.ApiError ? 'null' : JSON.stringify(session))
84
+ // replacing this text allow us to avoid injecting in frontends that don't support plugins. Don't use a <--comment--> or it will be removed by webpack
85
+ .replace('_HFS_PLUGINS_', pluginsInjection);
86
+ }
87
+ function serveProxied(port, uri) {
88
+ if (!port)
89
+ return;
90
+ console.debug('proxied on port', port);
91
+ let proxy;
92
+ Promise.resolve().then(() => __importStar(require('koa-better-http-proxy'))).then(lib => // dynamic import to avoid having this in final distribution
93
+ proxy = lib.default('127.0.0.1:' + port, {
94
+ proxyReqPathResolver: (ctx) => shouldServeApp(ctx) ? '/' : ctx.path,
95
+ userResDecorator(res, data, ctx) {
96
+ return shouldServeApp(ctx) ? treatIndex(ctx, String(data), uri)
97
+ : adjustBundlerLinks(ctx.path, uri, data);
98
+ }
99
+ }));
100
+ return function () {
101
+ return proxy.apply(this, arguments);
102
+ };
103
+ }
104
+ function pluginsInjection() {
105
+ const css = (0, plugins_1.mapPlugins)((plug, k) => { var _a; return (_a = plug.frontend_css) === null || _a === void 0 ? void 0 : _a.map(f => const_1.PLUGINS_PUB_URI + k + '/' + f); }).flat().filter(Boolean);
106
+ const js = (0, plugins_1.mapPlugins)((plug, k) => { var _a; return (_a = plug.frontend_js) === null || _a === void 0 ? void 0 : _a.map(f => const_1.PLUGINS_PUB_URI + k + '/' + f); }).flat().filter(Boolean);
107
+ return css.map(uri => `\n<link rel='stylesheet' type='text/css' href='${uri}'/>`).join('')
108
+ + js.map(uri => `\n<script defer src='${uri}'></script>`).join('');
109
+ }
110
+ function serveGuiFiles(proxyPort, uri) {
111
+ return serveProxied(proxyPort, uri) || serveStatic(uri);
112
+ }
113
+ exports.serveGuiFiles = serveGuiFiles;
package/src/sse.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ // This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const stream_1 = require("stream");
5
+ function createSSE(ctx) {
6
+ const { socket } = ctx.req;
7
+ socket.setTimeout(0);
8
+ socket.setNoDelay(true);
9
+ socket.setKeepAlive(true);
10
+ ctx.set({
11
+ 'Content-Type': 'text/event-stream',
12
+ 'Cache-Control': 'no-cache',
13
+ 'Connection': 'keep-alive',
14
+ 'X-Accel-Buffering': 'no', // avoid buffering when reverse-proxied through nginx
15
+ });
16
+ ctx.status = 200;
17
+ return ctx.body = new stream_1.Transform({
18
+ objectMode: true,
19
+ transform(chunk, encoding, cb) {
20
+ this.push(`data: ${JSON.stringify(chunk)}\n\n`);
21
+ cb();
22
+ },
23
+ flush(cb) {
24
+ this.push('data:\n\n');
25
+ cb();
26
+ }
27
+ });
28
+ }
29
+ exports.default = createSSE;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ // This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.totalInSpeed = exports.totalOutSpeed = exports.totalGot = exports.totalSent = exports.throttler = void 0;
8
+ const stream_1 = require("stream");
9
+ const ThrottledStream_1 = require("./ThrottledStream");
10
+ const config_1 = require("./config");
11
+ const misc_1 = require("./misc");
12
+ const connections_1 = require("./connections");
13
+ const lodash_1 = __importDefault(require("lodash"));
14
+ const events_1 = __importDefault(require("./events"));
15
+ const mainThrottleGroup = new ThrottledStream_1.ThrottleGroup(Infinity);
16
+ (0, config_1.defineConfig)('max_kbps', Infinity).sub(v => mainThrottleGroup.updateLimit(v));
17
+ const ip2group = {};
18
+ const SymThrStr = Symbol('stream');
19
+ const SymTimeout = Symbol('timeout');
20
+ const maxKbpsPerIp = (0, config_1.defineConfig)('max_kbps_per_ip', Infinity);
21
+ const throttler = async (ctx, next) => {
22
+ await next();
23
+ const { body } = ctx;
24
+ if (!body || !(body instanceof stream_1.Readable))
25
+ return;
26
+ // we wrap the stream also for unlimited connections to get speed and other features
27
+ const ipGroup = (0, misc_1.getOrSet)(ip2group, ctx.ip, () => {
28
+ var _a;
29
+ const doLimit = ((_a = ctx.state.account) === null || _a === void 0 ? void 0 : _a.ignore_limits) || (0, misc_1.isLocalHost)(ctx) ? undefined : true;
30
+ const group = new ThrottledStream_1.ThrottleGroup(Infinity, doLimit && mainThrottleGroup);
31
+ const unsub = doLimit && maxKbpsPerIp.sub(v => group.updateLimit(v));
32
+ return { group, count: 0, destroy: unsub };
33
+ });
34
+ const conn = ctx.state.connection;
35
+ if (!conn)
36
+ throw 'assert throttler connection';
37
+ const ts = conn[SymThrStr] = new ThrottledStream_1.ThrottledStream(ipGroup.group, conn[SymThrStr]);
38
+ let closed = false;
39
+ const DELAY = 1000;
40
+ const update = lodash_1.default.debounce(() => {
41
+ const ts = conn[SymThrStr];
42
+ const outSpeed = roundKb(ts.getSpeed());
43
+ (0, connections_1.updateConnection)(conn, { outSpeed, sent: ts.getBytesSent() });
44
+ /* in case this stream stands still for a while (before the end), we'll have neither 'sent' or 'close' events,
45
+ * so who will take care to updateConnection? This artificial next-call will ensure just that */
46
+ clearTimeout(conn[SymTimeout]);
47
+ if (outSpeed || !closed)
48
+ conn[SymTimeout] = setTimeout(update, DELAY);
49
+ }, DELAY, { maxWait: DELAY });
50
+ ts.on('sent', (n) => {
51
+ exports.totalSent += n;
52
+ update();
53
+ });
54
+ ++ipGroup.count;
55
+ ts.on('close', () => {
56
+ var _a;
57
+ update.flush();
58
+ closed = true;
59
+ if (--ipGroup.count)
60
+ return; // any left?
61
+ (_a = ipGroup.destroy) === null || _a === void 0 ? void 0 : _a.call(ipGroup);
62
+ delete ip2group[ctx.ip];
63
+ });
64
+ const bak = ctx.response.length; // preserve
65
+ ctx.body = ctx.body.pipe(ts);
66
+ if (bak)
67
+ ctx.response.length = bak;
68
+ };
69
+ exports.throttler = throttler;
70
+ function roundKb(n) {
71
+ return lodash_1.default.round(n, 1) || lodash_1.default.round(n, 3); // further precision if necessary
72
+ }
73
+ exports.totalSent = 0;
74
+ exports.totalGot = 0;
75
+ exports.totalOutSpeed = 0;
76
+ exports.totalInSpeed = 0;
77
+ let lastSent = exports.totalSent;
78
+ let lastGot = exports.totalGot;
79
+ let last = Date.now();
80
+ setInterval(() => {
81
+ const now = Date.now();
82
+ const past = (now - last) / 1000; // seconds
83
+ last = now;
84
+ const deltaSentKb = (exports.totalSent - lastSent) / 1000;
85
+ lastSent = exports.totalSent;
86
+ const deltaGotKb = (exports.totalGot - lastGot) / 1000;
87
+ lastGot = exports.totalGot;
88
+ exports.totalOutSpeed = roundKb(deltaSentKb / past);
89
+ exports.totalInSpeed = roundKb(deltaGotKb / past);
90
+ }, 1000);
91
+ events_1.default.on('connection', (c) => c.socket.on('data', data => exports.totalGot += data.length));
package/src/update.js ADDED
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.update = exports.getUpdate = void 0;
4
+ const github_1 = require("./github");
5
+ const const_1 = require("./const");
6
+ const path_1 = require("path");
7
+ const child_process_1 = require("child_process");
8
+ const misc_1 = require("./misc");
9
+ const fs_1 = require("fs");
10
+ const plugins_1 = require("./plugins");
11
+ const promises_1 = require("fs/promises");
12
+ const HFS_REPO = 'rejetto/hfs';
13
+ async function getUpdate() {
14
+ const [latest] = await (0, github_1.getRepoInfo)(HFS_REPO + '/releases?per_page=1');
15
+ if (latest.name === const_1.VERSION)
16
+ throw "you already have the latest version: " + const_1.VERSION;
17
+ return latest;
18
+ }
19
+ exports.getUpdate = getUpdate;
20
+ async function update() {
21
+ if (process.argv0.endsWith('node'))
22
+ throw "only binary versions are supported for now";
23
+ const update = await getUpdate();
24
+ const assetSearch = { win32: 'windows', darwin: 'mac', linux: 'linux' }[process.platform];
25
+ if (!assetSearch)
26
+ throw "this feature doesn't support your platform: " + process.platform;
27
+ const asset = update.assets.find((x) => x.name.endsWith('.zip') && x.name.includes(assetSearch));
28
+ if (!asset)
29
+ throw "asset not found";
30
+ const url = asset.browser_download_url;
31
+ console.log("downloading", url);
32
+ const bin = process.argv[0];
33
+ const binPath = (0, path_1.dirname)(bin);
34
+ const binFile = (0, path_1.basename)(bin);
35
+ const newBinFile = 'new-' + binFile;
36
+ plugins_1.pluginsWatcher.pause();
37
+ try {
38
+ await (0, misc_1.unzip)(await (0, misc_1.httpsStream)(url), path => (0, path_1.join)(binPath, path === binFile ? newBinFile : path));
39
+ const newBin = (0, path_1.join)(binPath, newBinFile);
40
+ if (!const_1.IS_WINDOWS) {
41
+ const { mode } = await (0, promises_1.stat)(bin);
42
+ await (0, promises_1.chmod)(newBin, mode).catch(console.error);
43
+ }
44
+ (0, misc_1.onProcessExit)(() => {
45
+ const oldBinFile = 'old-' + binFile;
46
+ console.log("old version is kept as", oldBinFile);
47
+ const oldBin = (0, path_1.join)(binPath, oldBinFile);
48
+ try {
49
+ (0, fs_1.unlinkSync)(oldBin);
50
+ }
51
+ catch (_a) { }
52
+ (0, fs_1.renameSync)(bin, oldBin);
53
+ console.log("launching new version in background", newBinFile);
54
+ (0, child_process_1.spawn)(newBin, ['--updating', binFile], { detached: true, shell: true })
55
+ .on('error', console.error);
56
+ });
57
+ console.log('quitting');
58
+ process.exit();
59
+ }
60
+ catch (_a) {
61
+ plugins_1.pluginsWatcher.unpause();
62
+ }
63
+ }
64
+ exports.update = update;
65
+ if (const_1.argv.updating) { // we were launched with a temporary name, restore original name to avoid breaking references
66
+ const bin = process.argv[0];
67
+ (0, fs_1.renameSync)(bin, (0, path_1.join)((0, path_1.dirname)(bin), const_1.argv.updating));
68
+ console.log("renamed binary file to", const_1.argv.updating);
69
+ }
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.unzip = exports.run = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isFile = exports.isDirectory = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const misc_1 = require("./misc");
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ const fast_glob_1 = __importDefault(require("fast-glob"));
12
+ const const_1 = require("./const");
13
+ const child_process_1 = require("child_process");
14
+ const stream_1 = require("stream");
15
+ // @ts-ignore
16
+ const unzip_stream_1 = __importDefault(require("unzip-stream"));
17
+ async function isDirectory(path) {
18
+ try {
19
+ return (await promises_1.default.stat(path)).isDirectory();
20
+ }
21
+ catch (_a) {
22
+ return false;
23
+ }
24
+ }
25
+ exports.isDirectory = isDirectory;
26
+ async function isFile(path) {
27
+ try {
28
+ return (await promises_1.default.stat(path)).isFile();
29
+ }
30
+ catch (_a) {
31
+ return false;
32
+ }
33
+ }
34
+ exports.isFile = isFile;
35
+ async function readFileBusy(path) {
36
+ return promises_1.default.readFile(path, 'utf8').catch(e => {
37
+ if ((e === null || e === void 0 ? void 0 : e.code) !== 'EBUSY')
38
+ throw e;
39
+ console.debug('busy');
40
+ return (0, misc_1.wait)(100).then(() => readFileBusy(path));
41
+ });
42
+ }
43
+ exports.readFileBusy = readFileBusy;
44
+ function watchDir(dir, cb) {
45
+ let watcher;
46
+ let paused = false;
47
+ try {
48
+ watcher = (0, fs_1.watch)(dir, controlledCb);
49
+ }
50
+ catch (_a) {
51
+ // failing watching the content of the dir, we try to monitor its parent, but filtering events only for our target dir
52
+ const base = (0, path_1.basename)(dir);
53
+ try {
54
+ watcher = (0, fs_1.watch)((0, path_1.dirname)(dir), (event, name) => {
55
+ if (name !== base)
56
+ return;
57
+ try {
58
+ watcher.close(); // if we succeed, we give up the parent watching
59
+ watcher = (0, fs_1.watch)(dir, controlledCb); // attempt at passing to a more specific watching
60
+ }
61
+ catch (_a) { }
62
+ controlledCb();
63
+ });
64
+ }
65
+ catch (e) {
66
+ console.debug(String(e));
67
+ }
68
+ }
69
+ return {
70
+ working() { return Boolean(watcher); },
71
+ stop() { watcher === null || watcher === void 0 ? void 0 : watcher.close(); },
72
+ pause() { paused = true; },
73
+ unpause() { paused = false; },
74
+ };
75
+ function controlledCb() {
76
+ if (!paused)
77
+ cb();
78
+ }
79
+ }
80
+ exports.watchDir = watchDir;
81
+ function dirTraversal(s) {
82
+ return s && /(^|[/\\])\.\.($|[/\\])/.test(s);
83
+ }
84
+ exports.dirTraversal = dirTraversal;
85
+ function isWindowsDrive(s) {
86
+ return s && /^[a-zA-Z]:$/.test(s);
87
+ }
88
+ exports.isWindowsDrive = isWindowsDrive;
89
+ // apply this to paths that may contain \ as separator (not supported by fast-glob) and other special chars to be escaped (parenthesis)
90
+ function adjustStaticPathForGlob(path) {
91
+ return fast_glob_1.default.escapePath(path.replace(/\\/g, '/'));
92
+ }
93
+ exports.adjustStaticPathForGlob = adjustStaticPathForGlob;
94
+ async function* dirStream(path, deep) {
95
+ if (!await isDirectory(path))
96
+ throw Error('ENOTDIR');
97
+ const dirStream = fast_glob_1.default.stream(deep ? '**/*' : '*', {
98
+ cwd: path,
99
+ dot: true,
100
+ deep,
101
+ onlyFiles: false,
102
+ suppressErrors: true,
103
+ objectMode: true,
104
+ });
105
+ const skip = await getItemsToSkip(path);
106
+ for await (const entry of dirStream) {
107
+ let { path, dirent } = entry;
108
+ if (!dirent.isDirectory() && !dirent.isFile())
109
+ continue;
110
+ path = String(path);
111
+ if (!(skip === null || skip === void 0 ? void 0 : skip.includes(path)))
112
+ yield path;
113
+ }
114
+ async function getItemsToSkip(path) {
115
+ if (!const_1.IS_WINDOWS)
116
+ return;
117
+ const out = await run('dir', ['/ah', '/b', path.replace(/\//g, '\\')])
118
+ .catch(() => ''); // error in case of no matching file
119
+ return out.split('\r\n').slice(0, -1);
120
+ }
121
+ }
122
+ exports.dirStream = dirStream;
123
+ function run(cmd, args = []) {
124
+ return new Promise((resolve, reject) => (0, child_process_1.execFile)('cmd', ['/c', cmd, ...args], (err, stdout) => {
125
+ if (err)
126
+ reject(err);
127
+ else
128
+ resolve(stdout);
129
+ }));
130
+ }
131
+ exports.run = run;
132
+ async function unzip(stream, cb) {
133
+ let pending = Promise.resolve();
134
+ return new Promise(resolve => stream.pipe(unzip_stream_1.default.Parse())
135
+ .on('end', () => pending.then(resolve))
136
+ .on('entry', async (entry) => {
137
+ const { path, type } = entry;
138
+ const dest = cb(path);
139
+ if (!dest || type !== 'File')
140
+ return entry.autodrain();
141
+ await pending; // don't overlap writings
142
+ console.debug('unzip', dest);
143
+ (0, fs_1.mkdirSync)((0, path_1.dirname)(dest), { recursive: true }); // easy way be sure to have the folder ready before proceeding
144
+ const thisFile = entry.pipe((0, fs_1.createWriteStream)(dest));
145
+ pending = (0, stream_1.once)(thisFile, 'finish');
146
+ }));
147
+ }
148
+ exports.unzip = unzip;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.asyncGeneratorToReadable = exports.asyncGeneratorToArray = exports.filterMapGenerator = void 0;
4
+ // callback can return undefined to skip element
5
+ const stream_1 = require("stream");
6
+ async function* filterMapGenerator(generator, filterMap) {
7
+ for await (const x of generator) {
8
+ const res = await filterMap(x);
9
+ if (res !== undefined)
10
+ yield res;
11
+ }
12
+ }
13
+ exports.filterMapGenerator = filterMapGenerator;
14
+ async function asyncGeneratorToArray(generator) {
15
+ const ret = [];
16
+ for await (const x of generator)
17
+ ret.push(x);
18
+ return ret;
19
+ }
20
+ exports.asyncGeneratorToArray = asyncGeneratorToArray;
21
+ function asyncGeneratorToReadable(generator) {
22
+ const iterator = generator[Symbol.asyncIterator]();
23
+ return new stream_1.Readable({
24
+ objectMode: true,
25
+ read() {
26
+ iterator.next().then(it => this.push(it.done ? null : it.value));
27
+ }
28
+ });
29
+ }
30
+ exports.asyncGeneratorToReadable = asyncGeneratorToReadable;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.httpsStream = exports.httpsString = void 0;
7
+ const node_https_1 = __importDefault(require("node:https"));
8
+ function httpsString(url, options = {}) {
9
+ return httpsStream(url, options).then(res => new Promise(resolve => {
10
+ let buf = '';
11
+ res.on('data', chunk => buf += chunk.toString());
12
+ res.on('end', () => resolve(Object.assign(res, {
13
+ ok: (res.statusCode || 400) < 400,
14
+ body: buf
15
+ })));
16
+ }));
17
+ }
18
+ exports.httpsString = httpsString;
19
+ function httpsStream(url, options = {}) {
20
+ return new Promise((resolve, reject) => {
21
+ node_https_1.default.request(url, options, res => {
22
+ if (!res.statusCode || res.statusCode >= 400)
23
+ throw res;
24
+ if (res.statusCode === 302 && res.headers.location)
25
+ return resolve(httpsStream(res.headers.location, options));
26
+ resolve(res);
27
+ }).on('error', reject).end();
28
+ });
29
+ }
30
+ exports.httpsStream = httpsStream;