hfs 0.44.0 → 0.45.0-alpha3
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.
- package/README.md +3 -26
- package/admin/assets/index-282a6921.js +510 -0
- package/admin/assets/{sha512-d091720e.js → sha512-40c08671.js} +2 -2
- package/admin/index.html +1 -1
- package/frontend/assets/index-4fe980c3.js +94 -0
- package/frontend/assets/{sha512-96fd938f.js → sha512-bc83ec21.js} +2 -2
- package/frontend/fontello.css +4 -3
- package/frontend/fontello.woff2 +0 -0
- package/frontend/index.html +1 -1
- package/package.json +1 -1
- package/plugins/download-counter/plugin.js +13 -6
- package/src/adminApis.js +8 -0
- package/src/api.vfs.js +3 -3
- package/src/commands.js +14 -13
- package/src/config.js +1 -1
- package/src/const.js +7 -4
- package/src/customHtml.js +31 -21
- package/src/lang.js +2 -0
- package/src/langs/embedded.js +2 -1
- package/src/langs/hfs-lang-fr.json +106 -0
- package/src/langs/hfs-lang-it.json +2 -1
- package/src/listen.js +2 -2
- package/src/log.js +2 -4
- package/src/middlewares.js +12 -1
- package/src/misc.js +9 -2
- package/src/plugins.js +7 -2
- package/src/serveGuiFiles.js +6 -6
- package/src/update.js +44 -17
- package/src/util-files.js +13 -10
- package/src/vfs.js +27 -12
- package/src/watchLoad.js +4 -4
- package/admin/assets/index-ef68a7ab.js +0 -510
- package/frontend/assets/index-a3b0d6ac.js +0 -94
package/src/log.js
CHANGED
|
@@ -34,7 +34,6 @@ const fs_1 = require("fs");
|
|
|
34
34
|
const util = __importStar(require("util"));
|
|
35
35
|
const promises_1 = require("fs/promises");
|
|
36
36
|
const const_1 = require("./const");
|
|
37
|
-
const events_1 = __importDefault(require("./events"));
|
|
38
37
|
const lodash_1 = __importDefault(require("lodash"));
|
|
39
38
|
const util_files_1 = require("./util-files");
|
|
40
39
|
const perm_1 = require("./perm");
|
|
@@ -62,8 +61,8 @@ class Logger {
|
|
|
62
61
|
this.reopen();
|
|
63
62
|
}
|
|
64
63
|
reopen() {
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
var _a;
|
|
65
|
+
return this.stream = (_a = (0, util_files_1.createFileWithPath)(this.path, { flags: 'a' })) === null || _a === void 0 ? void 0 : _a.on('error', () => this.stream = undefined);
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
// we'll have names same as config keys. These are used also by the get_log api.
|
|
@@ -122,7 +121,6 @@ function log() {
|
|
|
122
121
|
const date = a[2] + '/' + a[1] + '/' + a[3] + ':' + a[4] + ' ' + ((_b = a[5]) === null || _b === void 0 ? void 0 : _b.slice(3));
|
|
123
122
|
const user = (0, perm_1.getCurrentUsername)(ctx);
|
|
124
123
|
const length = (_c = ctx.state.length) !== null && _c !== void 0 ? _c : ctx.length;
|
|
125
|
-
events_1.default.emit(logger.name, Object.assign(lodash_1.default.pick(ctx, ['ip', 'method', 'status']), { length, user, ts: now, uri: ctx.path }));
|
|
126
124
|
debounce(() => // once in a while we check if the file is still good (not deleted, etc), or we'll reopen it
|
|
127
125
|
(0, promises_1.stat)(logger.path).catch(() => logger.reopen())); // async = smoother but we may lose some entries
|
|
128
126
|
stream.write(util.format(format, ctx.ip, user || '-', date, ctx.method, ctx.path, ctx.req.httpVersion, ctx.status, (_d = length === null || length === void 0 ? void 0 : length.toString()) !== null && _d !== void 0 ? _d : '-'));
|
package/src/middlewares.js
CHANGED
|
@@ -132,9 +132,20 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
132
132
|
}
|
|
133
133
|
ctx.set({ server: 'HFS ' + const_1.BUILD_TIMESTAMP });
|
|
134
134
|
return ctx.query.get === 'zip' ? (0, zip_1.zipStreamFromFolder)(node, ctx)
|
|
135
|
-
:
|
|
135
|
+
: ctx.query.get === 'list' ? sendFolderList(node, ctx)
|
|
136
|
+
: serveFrontendFiles(ctx, next);
|
|
136
137
|
};
|
|
137
138
|
exports.serveGuiAndSharedFiles = serveGuiAndSharedFiles;
|
|
139
|
+
async function sendFolderList(node, ctx) {
|
|
140
|
+
const { depth = 0, folders } = ctx.query;
|
|
141
|
+
ctx.type = 'text';
|
|
142
|
+
const walker = (0, vfs_1.walkNode)(node, ctx, depth === '*' ? Infinity : Number(depth) + 1);
|
|
143
|
+
ctx.body = (0, misc_1.asyncGeneratorToReadable)((0, misc_1.filterMapGenerator)(walker, async (el) => {
|
|
144
|
+
const isFolder = await (0, vfs_1.nodeIsDirectory)(el);
|
|
145
|
+
return !folders && isFolder ? undefined
|
|
146
|
+
: el.name + (isFolder ? '/' : '') + '\n';
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
138
149
|
let proxyDetected;
|
|
139
150
|
const someSecurity = async (ctx, next) => {
|
|
140
151
|
ctx.request.ip = (0, connections_1.normalizeIp)(ctx.ip);
|
package/src/misc.js
CHANGED
|
@@ -181,8 +181,15 @@ function isLocalHost(c) {
|
|
|
181
181
|
exports.isLocalHost = isLocalHost;
|
|
182
182
|
function makeNetMatcher(mask, emptyMaskReturns = false) {
|
|
183
183
|
return !mask ? () => emptyMaskReturns
|
|
184
|
-
: mask.includes('/') ? (
|
|
185
|
-
:
|
|
184
|
+
: !mask.includes('/') ? makeMatcher(mask)
|
|
185
|
+
: (() => {
|
|
186
|
+
var _a;
|
|
187
|
+
const all = mask.split('|');
|
|
188
|
+
const neg = ((_a = all[0]) === null || _a === void 0 ? void 0 : _a[0]) === '!';
|
|
189
|
+
if (neg)
|
|
190
|
+
all[0] = all[0].slice(1);
|
|
191
|
+
return (ip) => neg !== all.some(x => cidr_tools_1.default.contains(x, ip));
|
|
192
|
+
})();
|
|
186
193
|
}
|
|
187
194
|
exports.makeNetMatcher = makeNetMatcher;
|
|
188
195
|
function makeMatcher(mask, emptyMaskReturns = false) {
|
package/src/plugins.js
CHANGED
|
@@ -41,6 +41,7 @@ const promises_1 = require("fs/promises");
|
|
|
41
41
|
const fs_1 = require("fs");
|
|
42
42
|
const connections_1 = require("./connections");
|
|
43
43
|
const path_1 = require("path");
|
|
44
|
+
const customHtml_1 = require("./customHtml");
|
|
44
45
|
exports.PATH = 'plugins';
|
|
45
46
|
exports.DISABLING_POSTFIX = '-disabled';
|
|
46
47
|
const plugins = {};
|
|
@@ -297,8 +298,12 @@ function loadPlugin(id, path) {
|
|
|
297
298
|
},
|
|
298
299
|
getHfsConfig: config_1.getConfig,
|
|
299
300
|
}));
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
const folder = (0, path_1.dirname)(module);
|
|
302
|
+
Object.assign(data, res, {
|
|
303
|
+
customHtml: (0, customHtml_1.newCustomHtmlState)()
|
|
304
|
+
});
|
|
305
|
+
const customHtmlWatcher = (0, customHtml_1.watchLoadCustomHtml)(data.customHtml, folder);
|
|
306
|
+
const plugin = new Plugin(id, folder, data, lodash_1.default.flow(unwatch, customHtmlWatcher.unwatch));
|
|
302
307
|
if (alreadyRunning)
|
|
303
308
|
events_1.default.emit('pluginUpdated', Object.assign(lodash_1.default.pick(plugin, 'started'), getPluginInfo(id)));
|
|
304
309
|
else {
|
package/src/serveGuiFiles.js
CHANGED
|
@@ -37,7 +37,7 @@ const apiMiddleware_1 = require("./apiMiddleware");
|
|
|
37
37
|
const path_1 = require("path");
|
|
38
38
|
const misc_1 = require("./misc");
|
|
39
39
|
const adminApis_1 = require("./adminApis");
|
|
40
|
-
const
|
|
40
|
+
const vanilla_1 = require("valtio/vanilla");
|
|
41
41
|
const customHtml_1 = require("./customHtml");
|
|
42
42
|
const lodash_1 = __importDefault(require("lodash"));
|
|
43
43
|
const config_1 = require("./config");
|
|
@@ -47,7 +47,7 @@ const DEV_STATIC = process.env.DEV ? 'dist/' : '';
|
|
|
47
47
|
function serveStatic(uri) {
|
|
48
48
|
const folder = uri.slice(2, -1); // we know folder is very similar to uri
|
|
49
49
|
let cache = {};
|
|
50
|
-
(0,
|
|
50
|
+
(0, vanilla_1.subscribe)(customHtml_1.customHtmlState, () => cache = {}); // reset cache at every change
|
|
51
51
|
return async (ctx) => {
|
|
52
52
|
if (ctx.method === 'OPTIONS') {
|
|
53
53
|
ctx.status = const_1.HTTP_NO_CONTENT;
|
|
@@ -129,14 +129,14 @@ async function treatIndex(ctx, filesUri, body) {
|
|
|
129
129
|
${lodash_1.default.map(plugins, (configs, pluginName) => lodash_1.default.map(configs, (v, k) => `--${pluginName}-${k}: ${serializeCss(v)};`).join('\n')).join('')}
|
|
130
130
|
}
|
|
131
131
|
</style>
|
|
132
|
-
${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug,
|
|
132
|
+
${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug, id) => {
|
|
133
133
|
var _a;
|
|
134
|
-
return (_a = plug.frontend_css) === null || _a === void 0 ? void 0 : _a.map(f => `<link rel='stylesheet' type='text/css' href='${pub +
|
|
134
|
+
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)}/>`);
|
|
135
135
|
})
|
|
136
136
|
.flat().filter(Boolean).join('\n')}
|
|
137
|
-
${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug,
|
|
137
|
+
${!isFrontend ? '' : (0, plugins_1.mapPlugins)((plug, id) => {
|
|
138
138
|
var _a;
|
|
139
|
-
return (_a = plug.frontend_js) === null || _a === void 0 ? void 0 : _a.map(f => `<script defer plugin=${JSON.stringify(
|
|
139
|
+
return (_a = plug.frontend_js) === null || _a === void 0 ? void 0 : _a.map(f => `<script defer plugin=${JSON.stringify(id)} src='${f.includes('//') ? f : pub + id + '/' + f}'></script>`);
|
|
140
140
|
})
|
|
141
141
|
.flat().filter(Boolean).join('\n')}
|
|
142
142
|
`);
|
package/src/update.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// This file is part of HFS - Copyright 2021-2023, 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
|
+
};
|
|
3
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.update = exports.getUpdate = void 0;
|
|
7
|
+
exports.update = exports.updateSupported = exports.localUpdateAvailable = exports.getUpdate = void 0;
|
|
5
8
|
const github_1 = require("./github");
|
|
6
9
|
const const_1 = require("./const");
|
|
7
10
|
const path_1 = require("path");
|
|
@@ -10,6 +13,7 @@ const misc_1 = require("./misc");
|
|
|
10
13
|
const fs_1 = require("fs");
|
|
11
14
|
const plugins_1 = require("./plugins");
|
|
12
15
|
const promises_1 = require("fs/promises");
|
|
16
|
+
const open_1 = __importDefault(require("open"));
|
|
13
17
|
async function getUpdate() {
|
|
14
18
|
const [latest] = await (0, github_1.getRepoInfo)(const_1.HFS_REPO + '/releases?per_page=1');
|
|
15
19
|
if (latest.name === const_1.VERSION)
|
|
@@ -17,25 +21,38 @@ async function getUpdate() {
|
|
|
17
21
|
return latest;
|
|
18
22
|
}
|
|
19
23
|
exports.getUpdate = getUpdate;
|
|
24
|
+
const LOCAL_UPDATE = 'hfs-update.zip'; // update from file takes precedence over net
|
|
25
|
+
function localUpdateAvailable() {
|
|
26
|
+
return (0, promises_1.access)(LOCAL_UPDATE).then(() => true, () => false);
|
|
27
|
+
}
|
|
28
|
+
exports.localUpdateAvailable = localUpdateAvailable;
|
|
29
|
+
function updateSupported() {
|
|
30
|
+
return const_1.IS_BINARY;
|
|
31
|
+
}
|
|
32
|
+
exports.updateSupported = updateSupported;
|
|
20
33
|
async function update() {
|
|
21
|
-
if (!
|
|
34
|
+
if (!updateSupported())
|
|
22
35
|
throw "only binary versions are supported for now";
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
let updateSource = await localUpdateAvailable() && (0, fs_1.createReadStream)(LOCAL_UPDATE);
|
|
37
|
+
if (!updateSource) {
|
|
38
|
+
const update = await getUpdate();
|
|
39
|
+
const assetSearch = { win32: 'windows', darwin: 'mac', linux: 'linux' }[process.platform];
|
|
40
|
+
if (!assetSearch)
|
|
41
|
+
throw "this feature doesn't support your platform: " + process.platform;
|
|
42
|
+
const asset = update.assets.find((x) => x.name.endsWith('.zip') && x.name.includes(assetSearch));
|
|
43
|
+
if (!asset)
|
|
44
|
+
throw "asset not found";
|
|
45
|
+
const url = asset.browser_download_url;
|
|
46
|
+
console.log("downloading", url);
|
|
47
|
+
updateSource = await (0, misc_1.httpsStream)(url);
|
|
48
|
+
}
|
|
32
49
|
const bin = process.execPath;
|
|
33
50
|
const binPath = (0, path_1.dirname)(bin);
|
|
34
51
|
const binFile = (0, path_1.basename)(bin);
|
|
35
52
|
const newBinFile = 'new-' + binFile;
|
|
36
53
|
plugins_1.pluginsWatcher.pause();
|
|
37
54
|
try {
|
|
38
|
-
await (0, misc_1.unzip)(
|
|
55
|
+
await (0, misc_1.unzip)(updateSource, path => (0, path_1.join)(binPath, path === binFile ? newBinFile : path));
|
|
39
56
|
const newBin = (0, path_1.join)(binPath, newBinFile);
|
|
40
57
|
if (!const_1.IS_WINDOWS) {
|
|
41
58
|
const { mode } = await (0, promises_1.stat)(bin);
|
|
@@ -51,19 +68,29 @@ async function update() {
|
|
|
51
68
|
catch (_a) { }
|
|
52
69
|
(0, fs_1.renameSync)(bin, oldBin);
|
|
53
70
|
console.log("launching new version in background", newBinFile);
|
|
54
|
-
(
|
|
55
|
-
.on('error', console.error);
|
|
71
|
+
launch(newBin, ['--updating', binFile], { sync: true }); // sync necessary to work on mac by double-click
|
|
56
72
|
});
|
|
57
73
|
console.log('quitting');
|
|
58
|
-
process.exit();
|
|
74
|
+
setTimeout(() => process.exit()); // give time to return (and caller to complete, eg: rest api to reply)
|
|
59
75
|
}
|
|
60
76
|
catch (_a) {
|
|
61
77
|
plugins_1.pluginsWatcher.unpause();
|
|
62
78
|
}
|
|
63
79
|
}
|
|
64
80
|
exports.update = update;
|
|
81
|
+
function launch(cmd, pars = [], options) {
|
|
82
|
+
return ((options === null || options === void 0 ? void 0 : options.sync) ? child_process_1.spawnSync : child_process_1.spawn)(cmd, pars, { detached: true, shell: true, stdio: [0, 1, 2], ...options });
|
|
83
|
+
}
|
|
65
84
|
if (const_1.argv.updating) { // we were launched with a temporary name, restore original name to avoid breaking references
|
|
66
85
|
const bin = process.execPath;
|
|
67
|
-
|
|
68
|
-
|
|
86
|
+
const dest = (0, path_1.join)((0, path_1.dirname)(bin), const_1.argv.updating);
|
|
87
|
+
(0, fs_1.renameSync)(bin, dest);
|
|
88
|
+
// have to relaunch with new name, or otherwise next update will fail with EBUSY on hfs.exe
|
|
89
|
+
console.log("renamed binary file to", const_1.argv.updating, "and restarting");
|
|
90
|
+
// be sure to test launching both double-clicking and in a terminal
|
|
91
|
+
if (const_1.IS_WINDOWS) // this method on Mac works only once, and without console
|
|
92
|
+
(0, misc_1.onProcessExit)(() => launch(dest, ['--updated'])); // launch+sync here would cause old process to stay open, locking ports
|
|
93
|
+
else
|
|
94
|
+
(0, open_1.default)(dest).then();
|
|
95
|
+
process.exit();
|
|
69
96
|
}
|
package/src/util-files.js
CHANGED
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.isValidFileName = exports.prepareFolder = exports.unzip = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.
|
|
7
|
+
exports.isValidFileName = exports.createFileWithPath = exports.prepareFolder = exports.unzip = exports.dirStream = exports.adjustStaticPathForGlob = exports.isWindowsDrive = exports.dirTraversal = exports.watchDir = exports.readFileBusy = exports.isDirectory = void 0;
|
|
8
8
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
9
|
const misc_1 = require("./misc");
|
|
10
10
|
const fs_1 = require("fs");
|
|
@@ -24,15 +24,6 @@ async function isDirectory(path) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
exports.isDirectory = isDirectory;
|
|
27
|
-
async function isFile(path) {
|
|
28
|
-
try {
|
|
29
|
-
return (await promises_1.default.stat(path)).isFile();
|
|
30
|
-
}
|
|
31
|
-
catch (_a) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
exports.isFile = isFile;
|
|
36
27
|
async function readFileBusy(path) {
|
|
37
28
|
return promises_1.default.readFile(path, 'utf8').catch(e => {
|
|
38
29
|
if ((e === null || e === void 0 ? void 0 : e.code) !== 'EBUSY')
|
|
@@ -154,6 +145,18 @@ async function prepareFolder(path, dirnameIt = true) {
|
|
|
154
145
|
}
|
|
155
146
|
}
|
|
156
147
|
exports.prepareFolder = prepareFolder;
|
|
148
|
+
function createFileWithPath(path, options) {
|
|
149
|
+
const folder = (0, path_1.dirname)(path);
|
|
150
|
+
if (!isWindowsDrive(folder))
|
|
151
|
+
try {
|
|
152
|
+
(0, fs_1.mkdirSync)(folder, { recursive: true });
|
|
153
|
+
}
|
|
154
|
+
catch (_a) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
return (0, fs_1.createWriteStream)(path, options);
|
|
158
|
+
}
|
|
159
|
+
exports.createFileWithPath = createFileWithPath;
|
|
157
160
|
function isValidFileName(name) {
|
|
158
161
|
return !/^\.\.?$|[/:*?"<>|\\]/.test(name);
|
|
159
162
|
}
|
package/src/vfs.js
CHANGED
|
@@ -26,17 +26,20 @@ exports.defaultPerms = {
|
|
|
26
26
|
exports.PERM_KEYS = (0, misc_1.typedKeys)(exports.defaultPerms);
|
|
27
27
|
exports.MIME_AUTO = 'auto';
|
|
28
28
|
function inheritFromParent(parent, child) {
|
|
29
|
-
var _a, _b, _c;
|
|
29
|
+
var _a, _b, _c, _d;
|
|
30
30
|
for (const k of (0, misc_1.typedKeys)(exports.defaultPerms)) {
|
|
31
|
-
|
|
31
|
+
let dueParent = parent;
|
|
32
|
+
while (((_a = dueParent === null || dueParent === void 0 ? void 0 : dueParent.propagate) === null || _a === void 0 ? void 0 : _a[k]) === false)
|
|
33
|
+
dueParent = dueParent.parent;
|
|
34
|
+
const v = dueParent === null || dueParent === void 0 ? void 0 : dueParent[k];
|
|
32
35
|
if (v !== undefined) // small optimization: don't expand the object
|
|
33
|
-
(
|
|
36
|
+
(_b = child[k]) !== null && _b !== void 0 ? _b : (child[k] = v);
|
|
34
37
|
}
|
|
35
38
|
if (typeof parent.mime === 'object' && typeof child.mime === 'object')
|
|
36
39
|
lodash_1.default.defaults(child.mime, parent.mime);
|
|
37
40
|
else
|
|
38
|
-
(
|
|
39
|
-
(
|
|
41
|
+
(_c = child.mime) !== null && _c !== void 0 ? _c : (child.mime = parent.mime);
|
|
42
|
+
(_d = child.accept) !== null && _d !== void 0 ? _d : (child.accept = parent.accept);
|
|
40
43
|
return child;
|
|
41
44
|
}
|
|
42
45
|
function isSameFilenameAs(name) {
|
|
@@ -45,7 +48,9 @@ function isSameFilenameAs(name) {
|
|
|
45
48
|
}
|
|
46
49
|
exports.isSameFilenameAs = isSameFilenameAs;
|
|
47
50
|
function applyParentToChild(child, parent, name) {
|
|
51
|
+
var _a;
|
|
48
52
|
const ret = {
|
|
53
|
+
isFolder: ((_a = child === null || child === void 0 ? void 0 : child.children) === null || _a === void 0 ? void 0 : _a.length) ? true : undefined,
|
|
49
54
|
...child,
|
|
50
55
|
original: child,
|
|
51
56
|
isTemp: true,
|
|
@@ -76,9 +81,9 @@ async function urlToNode(url, ctx, parent = exports.vfs, getRest) {
|
|
|
76
81
|
// does the tree node have a child that goes by this name?
|
|
77
82
|
const child = (_a = parent.children) === null || _a === void 0 ? void 0 : _a.find(isSameFilenameAs(name));
|
|
78
83
|
if (!child && !parent.source)
|
|
79
|
-
return; // on tree or on disk
|
|
84
|
+
return; // on tree or on disk, or it doesn't exist
|
|
80
85
|
const ret = applyParentToChild(child, parent, name);
|
|
81
|
-
if (child)
|
|
86
|
+
if (child)
|
|
82
87
|
return urlToNode(rest, ctx, ret, getRest);
|
|
83
88
|
let onDisk = name;
|
|
84
89
|
if (parent.rename) { // reverse the mapping
|
|
@@ -96,8 +101,9 @@ async function urlToNode(url, ctx, parent = exports.vfs, getRest) {
|
|
|
96
101
|
return urlToNode(rest, ctx, ret, getRest);
|
|
97
102
|
if (ret.source)
|
|
98
103
|
try {
|
|
99
|
-
await promises_1.default.stat(ret.source);
|
|
100
|
-
|
|
104
|
+
const st = await promises_1.default.stat(ret.source); // check existence
|
|
105
|
+
ret.isFolder = st.isDirectory();
|
|
106
|
+
}
|
|
101
107
|
catch (_b) {
|
|
102
108
|
if (!getRest)
|
|
103
109
|
return;
|
|
@@ -130,7 +136,15 @@ function getNodeName(node) {
|
|
|
130
136
|
}
|
|
131
137
|
exports.getNodeName = getNodeName;
|
|
132
138
|
async function nodeIsDirectory(node) {
|
|
133
|
-
|
|
139
|
+
var _a;
|
|
140
|
+
if (node.isFolder !== undefined)
|
|
141
|
+
return node.isFolder;
|
|
142
|
+
const isFolder = Boolean(((_a = node.children) === null || _a === void 0 ? void 0 : _a.length) || !node.source || await (0, misc_1.isDirectory)(node.source));
|
|
143
|
+
if (node.isTemp)
|
|
144
|
+
node.isFolder = isFolder;
|
|
145
|
+
else
|
|
146
|
+
(0, misc_1.setHidden)(node, { isFolder }); // don't make it to the storage
|
|
147
|
+
return isFolder;
|
|
134
148
|
}
|
|
135
149
|
exports.nodeIsDirectory = nodeIsDirectory;
|
|
136
150
|
function hasPermission(node, perm, ctx) {
|
|
@@ -201,7 +215,7 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm)
|
|
|
201
215
|
const map = new Map();
|
|
202
216
|
map.set(lastDir, parent);
|
|
203
217
|
// it's important to keep using dirStream in deep-mode, as it is manyfold faster (it parallelizes)
|
|
204
|
-
for await (const [path,
|
|
218
|
+
for await (const [path, isFolder] of (0, misc_1.dirStream)(source, depth)) {
|
|
205
219
|
if (ctx === null || ctx === void 0 ? void 0 : ctx.req.aborted)
|
|
206
220
|
return;
|
|
207
221
|
const name = prefixPath + (((_a = parent.rename) === null || _a === void 0 ? void 0 : _a[path]) || path);
|
|
@@ -214,12 +228,13 @@ async function* walkNode(parent, ctx, depth = 0, prefixPath = '', requiredPerm)
|
|
|
214
228
|
}
|
|
215
229
|
const item = {
|
|
216
230
|
name,
|
|
231
|
+
isFolder,
|
|
217
232
|
source: (0, path_1.join)(source, path),
|
|
218
233
|
rename: renameUnderPath(parent.rename, path),
|
|
219
234
|
};
|
|
220
235
|
if (!canSee(item))
|
|
221
236
|
continue;
|
|
222
|
-
if (
|
|
237
|
+
if (isFolder)
|
|
223
238
|
map.set(name, item);
|
|
224
239
|
yield item;
|
|
225
240
|
}
|
package/src/watchLoad.js
CHANGED
|
@@ -7,9 +7,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.watchLoad = void 0;
|
|
8
8
|
const fs_1 = require("fs");
|
|
9
9
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
10
|
-
const yaml_1 = __importDefault(require("yaml"));
|
|
11
10
|
const misc_1 = require("./misc");
|
|
12
|
-
function watchLoad(path, parser, { failedOnFirstAttempt } = {}) {
|
|
11
|
+
function watchLoad(path, parser, { failedOnFirstAttempt, immediateFirst } = {}) {
|
|
13
12
|
let doing = false;
|
|
14
13
|
let watcher;
|
|
15
14
|
const debounced = (0, misc_1.debounceAsync)(load, 500, { maxWait: 1000 });
|
|
@@ -32,6 +31,8 @@ function watchLoad(path, parser, { failedOnFirstAttempt } = {}) {
|
|
|
32
31
|
debounced().then();
|
|
33
32
|
});
|
|
34
33
|
debounced().catch(x => x);
|
|
34
|
+
if (immediateFirst)
|
|
35
|
+
debounced.flush().then();
|
|
35
36
|
}
|
|
36
37
|
catch (e) {
|
|
37
38
|
retry = setTimeout(install, 3000); // manual watching until watch is successful
|
|
@@ -60,8 +61,7 @@ function watchLoad(path, parser, { failedOnFirstAttempt } = {}) {
|
|
|
60
61
|
console.debug('loaded', path);
|
|
61
62
|
uninstall();
|
|
62
63
|
install(); // reinstall, as the original file could have been renamed. We watch by the name.
|
|
63
|
-
|
|
64
|
-
await parser(decoded);
|
|
64
|
+
await parser(text);
|
|
65
65
|
}
|
|
66
66
|
finally {
|
|
67
67
|
doing = false;
|