hfs 0.55.1 → 0.55.2

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.
@@ -1,4 +1,4 @@
1
- System.register(["./index-legacy-BoMy1vEB.js"],(function(h,t){"use strict";var i,s;return{setters:[function(h){i=h.g,s=h.c}],execute:function(){function t(h,t){for(var i=function(){var i=t[s];if("string"!=typeof i&&!Array.isArray(i)){var r=function(t){if("default"!==t&&!(t in h)){var s=Object.getOwnPropertyDescriptor(i,t);s&&Object.defineProperty(h,t,s.get?s:{enumerable:!0,get:function(){return i[t]}})}};for(var e in i)r(e)}},s=0;s<t.length;s++)i();return Object.freeze(Object.defineProperty(h,Symbol.toStringTag,{value:"Module"}))}var r={exports:{}};
1
+ System.register(["./index-legacy-BFUS5Ol_.js"],(function(h,t){"use strict";var i,s;return{setters:[function(h){i=h.g,s=h.c}],execute:function(){function t(h,t){for(var i=function(){var i=t[s];if("string"!=typeof i&&!Array.isArray(i)){var r=function(t){if("default"!==t&&!(t in h)){var s=Object.getOwnPropertyDescriptor(i,t);s&&Object.defineProperty(h,t,s.get?s:{enumerable:!0,get:function(){return i[t]}})}};for(var e in i)r(e)}},s=0;s<t.length;s++)i();return Object.freeze(Object.defineProperty(h,Symbol.toStringTag,{value:"Module"}))}var r={exports:{}};
2
2
  /*
3
3
  * [js-sha512]{@link https://github.com/emn178/js-sha512}
4
4
  *
@@ -22,6 +22,6 @@
22
22
  document.getElementById('root').innerHTML = 'Loading...'
23
23
  </script>
24
24
  <script crossorigin id="vite-legacy-polyfill" src="/assets/polyfills-legacy-DMrMt_pQ.js"></script>
25
- <script crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-BoMy1vEB.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
25
+ <script crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-BFUS5Ol_.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
26
26
  </body>
27
27
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hfs",
3
- "version": "0.55.1",
3
+ "version": "0.55.2",
4
4
  "description": "HTTP File Server",
5
5
  "keywords": ["file server", "http server"],
6
6
  "homepage": "https://rejetto.com/hfs",
package/src/argv.js ADDED
@@ -0,0 +1,8 @@
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.argv = void 0;
7
+ const minimist_1 = __importDefault(require("minimist"));
8
+ exports.argv = (0, minimist_1.default)(process.argv.slice(2));
package/src/commands.js CHANGED
@@ -17,7 +17,8 @@ const fileAttr_1 = require("./fileAttr");
17
17
  const github_1 = require("./github");
18
18
  const cross_1 = require("./cross");
19
19
  const api_monitor_1 = __importDefault(require("./api.monitor"));
20
- if (!const_1.argv.updating)
20
+ const argv_1 = require("./argv");
21
+ if (!argv_1.argv.updating)
21
22
  try {
22
23
  /*
23
24
  is this try-block useful in case the stdin is unavailable?
package/src/config.js CHANGED
@@ -38,12 +38,13 @@ const path_1 = require("path");
38
38
  const events_1 = __importDefault(require("./events"));
39
39
  const promises_1 = require("fs/promises");
40
40
  const immer_1 = __importStar(require("immer"));
41
+ const argv_1 = require("./argv");
41
42
  (0, immer_1.setAutoFreeze)(false); // we still want to mess with objects later (eg: account.belongs)
42
43
  // keep definition of config properties
43
44
  const configProps = {};
44
45
  let started = false; // this will tell the difference for subscribeConfig()s that are called before or after config is loaded
45
46
  let state = {}; // current state of config properties
46
- const filePath = (0, misc_1.with_)(const_1.argv.config || process.env.HFS_CONFIG, p => {
47
+ const filePath = (0, misc_1.with_)(argv_1.argv.config || process.env.HFS_CONFIG, p => {
47
48
  if (!p)
48
49
  return const_1.CONFIG_FILE;
49
50
  p = (0, path_1.resolve)(const_1.ORIGINAL_CWD, p);
@@ -139,7 +140,7 @@ function setConfig(newCfg, save) {
139
140
  const version = lodash_1.default.isString(newCfg.version) ? new Version(newCfg.version) : undefined;
140
141
  const considerEnvs = !process.env['HFS_ENV_BOOTSTRAP'] || !started && lodash_1.default.isEmpty(newCfg);
141
142
  // first time we consider also CLI args
142
- const argCfg = !started && lodash_1.default.pickBy((0, misc_1.newObj)(configProps, (x, k) => { var _a; return (_a = const_1.argv[k]) !== null && _a !== void 0 ? _a : (0, misc_1.tryJson)(considerEnvs ? process.env['HFS_' + k.toUpperCase().replaceAll('-', '_')] : '', lodash_1.default.identity); }), x => x !== undefined);
143
+ const argCfg = !started && lodash_1.default.pickBy((0, misc_1.newObj)(configProps, (x, k) => { var _a; return (_a = argv_1.argv[k]) !== null && _a !== void 0 ? _a : (0, misc_1.tryJson)(considerEnvs ? process.env['HFS_' + k.toUpperCase().replaceAll('-', '_')] : '', lodash_1.default.identity); }), x => x !== undefined);
143
144
  if (!lodash_1.default.isEmpty(argCfg)) {
144
145
  (0, exports.saveConfigAsap)(); // don't set `save` argument, as it would interfere below at check `save===false`
145
146
  Object.assign(newCfg, argCfg);
@@ -196,10 +197,6 @@ const saveDebounced = (0, misc_1.debounceAsync)(async () => {
196
197
  const aWeekAgo = Date.now() - misc_1.DAY * 7;
197
198
  if (await (0, promises_1.stat)(bak).then(x => aWeekAgo > Number(x.mtime || x.ctime), () => true))
198
199
  await (0, promises_1.copyFile)(filePath, bak).catch(() => { }); // ignore errors
199
- if (lodash_1.default.isEmpty(state)) {
200
- console.error('saving empty config');
201
- debugger;
202
- }
203
200
  await exports.configFile.save(stringify({ ...state, version: const_1.VERSION }))
204
201
  .catch(err => console.error('Failed at saving config file, please ensure it is writable.', String(err)));
205
202
  });
package/src/consoleLog.js CHANGED
@@ -7,9 +7,9 @@ exports.consoleLog = void 0;
7
7
  const events_1 = __importDefault(require("./events"));
8
8
  const cross_1 = require("./cross");
9
9
  const fs_1 = require("fs");
10
- const const_1 = require("./const");
10
+ const argv_1 = require("./argv");
11
11
  exports.consoleLog = [];
12
- const f = const_1.argv.consoleFile ? (0, fs_1.createWriteStream)(const_1.argv.consoleFile, 'utf-8') : null;
12
+ const f = argv_1.argv.consoleFile ? (0, fs_1.createWriteStream)(argv_1.argv.consoleFile, 'utf-8') : null;
13
13
  for (const k of ['log', 'warn', 'error']) {
14
14
  const original = console[k];
15
15
  console[k] = (...args) => {
package/src/const.js CHANGED
@@ -30,31 +30,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
30
30
  return (mod && mod.__esModule) ? mod : { "default": mod };
31
31
  };
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.CONFIG_FILE = exports.MIME_AUTO = exports.APP_PATH = exports.IS_BINARY = exports.IS_MAC = exports.IS_WINDOWS = exports.HFS_REPO_BRANCH = exports.RUNNING_BETA = exports.VERSION = exports.BUILD_TIMESTAMP = exports.HFS_STARTED = exports.ORIGINAL_CWD = exports.DEV = exports.ARGS_FILE = exports.argv = exports.COMPATIBLE_API_VERSION = exports.API_VERSION = void 0;
33
+ exports.CONFIG_FILE = exports.MIME_AUTO = exports.APP_PATH = exports.IS_BINARY = exports.IS_MAC = exports.IS_WINDOWS = exports.HFS_REPO_BRANCH = exports.RUNNING_BETA = exports.VERSION = exports.BUILD_TIMESTAMP = exports.HFS_STARTED = exports.ORIGINAL_CWD = exports.DEV = exports.ARGS_FILE = exports.COMPATIBLE_API_VERSION = exports.API_VERSION = void 0;
34
34
  const minimist_1 = __importDefault(require("minimist"));
35
35
  const fs = __importStar(require("fs"));
36
36
  const os_1 = require("os");
37
37
  const lodash_1 = __importDefault(require("lodash"));
38
38
  const path_1 = require("path");
39
39
  const cross_1 = require("./cross");
40
+ const argv_1 = require("./argv");
40
41
  __exportStar(require("./cross-const"), exports);
41
42
  exports.API_VERSION = 10.3;
42
43
  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
43
- exports.argv = (0, minimist_1.default)(process.argv.slice(2));
44
44
  // you can add arguments with this file, currently used for the update process on mac/linux
45
45
  exports.ARGS_FILE = (0, path_1.join)((0, os_1.homedir)(), 'hfs-args');
46
46
  try {
47
47
  const s = fs.readFileSync(exports.ARGS_FILE, 'utf-8');
48
48
  console.log('additional arguments', s);
49
- lodash_1.default.defaults(exports.argv, (0, minimist_1.default)(JSON.parse(s)));
49
+ lodash_1.default.defaults(argv_1.argv, (0, minimist_1.default)(JSON.parse(s)));
50
50
  fs.unlinkSync(exports.ARGS_FILE);
51
51
  }
52
52
  catch (_a) { }
53
- exports.DEV = process.env.DEV || exports.argv.dev ? 'DEV' : '';
53
+ exports.DEV = process.env.DEV || argv_1.argv.dev ? 'DEV' : '';
54
54
  exports.ORIGINAL_CWD = process.cwd();
55
55
  exports.HFS_STARTED = new Date();
56
56
  const PKG_PATH = (0, path_1.join)(__dirname, '..', 'package.json');
57
- exports.BUILD_TIMESTAMP = "2025-01-01T17:07:20.752Z";
57
+ exports.BUILD_TIMESTAMP = "2025-01-05T19:25:48.693Z";
58
58
  const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
59
59
  exports.VERSION = pkg.version;
60
60
  exports.RUNNING_BETA = exports.VERSION.includes('-');
@@ -75,12 +75,12 @@ console.log(`© Massimo Melina <a@rejetto.com> - License https://www.gnu.org/lic
75
75
  console.log('started', (0, cross_1.formatTimestamp)(exports.HFS_STARTED), exports.DEV);
76
76
  console.log('version', exports.VERSION || '-');
77
77
  console.log('build', exports.BUILD_TIMESTAMP || '-');
78
- console.debug('arguments', exports.argv);
78
+ console.debug('arguments', argv_1.argv);
79
79
  // still considering whether to use ".hfs" with Windows users, who may be less accustomed to it
80
- const dir = exports.argv.cwd || useHomeDir() && (0, path_1.join)((0, os_1.homedir)(), '.hfs');
80
+ const dir = argv_1.argv.cwd || useHomeDir() && (0, path_1.join)((0, os_1.homedir)(), '.hfs');
81
81
  if (dir) {
82
82
  try {
83
- fs.mkdirSync(dir);
83
+ fs.mkdirSync(dir, { recursive: true });
84
84
  }
85
85
  catch (e) {
86
86
  if (e.code !== 'EEXIST')
@@ -88,6 +88,8 @@ if (dir) {
88
88
  }
89
89
  process.chdir(dir);
90
90
  }
91
+ else if (process.cwd().startsWith(process.env.windir + '\\')) // this happens if you run hfs from task scheduler
92
+ process.chdir(exports.APP_PATH);
91
93
  console.log('working directory (cwd)', process.cwd());
92
94
  if (exports.APP_PATH !== process.cwd())
93
95
  console.log('app', exports.APP_PATH);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HTTP_MESSAGES = exports.HTTP_SERVICE_UNAVAILABLE = exports.HTTP_SERVER_ERROR = exports.HTTP_TOO_MANY_REQUESTS = exports.HTTP_FAILED_DEPENDENCY = exports.HTTP_FOOL = exports.HTTP_RANGE_NOT_SATISFIABLE = exports.HTTP_PAYLOAD_TOO_LARGE = exports.HTTP_PRECONDITION_FAILED = exports.HTTP_CONFLICT = exports.HTTP_NOT_ACCEPTABLE = exports.HTTP_METHOD_NOT_ALLOWED = exports.HTTP_NOT_FOUND = exports.HTTP_FORBIDDEN = exports.HTTP_UNAUTHORIZED = exports.HTTP_BAD_REQUEST = exports.HTTP_NOT_MODIFIED = exports.HTTP_TEMPORARY_REDIRECT = exports.HTTP_MOVED_PERMANENTLY = exports.HTTP_PARTIAL_CONTENT = exports.HTTP_NO_CONTENT = exports.HTTP_OK = exports.HFS_REPO = exports.PLUGIN_CUSTOM_REST_PREFIX = exports.NBSP = exports.PORT_DISABLED = exports.PLUGINS_PUB_URI = exports.API_URI = exports.ADMIN_URI = exports.FRONTEND_URI = exports.SPECIAL_URI = void 0;
3
+ exports.HTTP_MESSAGES = exports.HTTP_SERVICE_UNAVAILABLE = exports.HTTP_SERVER_ERROR = exports.HTTP_TOO_MANY_REQUESTS = exports.HTTP_FAILED_DEPENDENCY = exports.HTTP_FOOL = exports.HTTP_RANGE_NOT_SATISFIABLE = exports.HTTP_PAYLOAD_TOO_LARGE = exports.HTTP_PRECONDITION_FAILED = exports.HTTP_CONFLICT = exports.HTTP_NOT_ACCEPTABLE = exports.HTTP_METHOD_NOT_ALLOWED = exports.HTTP_NOT_FOUND = exports.HTTP_FORBIDDEN = exports.HTTP_UNAUTHORIZED = exports.HTTP_BAD_REQUEST = exports.HTTP_NOT_MODIFIED = exports.HTTP_TEMPORARY_REDIRECT = exports.HTTP_MOVED_PERMANENTLY = exports.HTTP_PARTIAL_CONTENT = exports.HTTP_NO_CONTENT = exports.HTTP_OK = exports.UPLOAD_STATUS = exports.UPLOAD_RESUMABLE = exports.HFS_REPO = exports.PLUGIN_CUSTOM_REST_PREFIX = exports.NBSP = exports.PORT_DISABLED = exports.PLUGINS_PUB_URI = exports.API_URI = exports.ADMIN_URI = exports.FRONTEND_URI = exports.SPECIAL_URI = void 0;
4
4
  exports.SPECIAL_URI = '/~/';
5
5
  exports.FRONTEND_URI = exports.SPECIAL_URI + 'frontend/';
6
6
  exports.ADMIN_URI = exports.SPECIAL_URI + 'admin/';
@@ -10,6 +10,8 @@ exports.PORT_DISABLED = -1;
10
10
  exports.NBSP = '\xA0';
11
11
  exports.PLUGIN_CUSTOM_REST_PREFIX = '_';
12
12
  exports.HFS_REPO = 'rejetto/hfs';
13
+ exports.UPLOAD_RESUMABLE = 'upload.resumable';
14
+ exports.UPLOAD_STATUS = 'upload.status';
13
15
  exports.HTTP_OK = 200;
14
16
  exports.HTTP_NO_CONTENT = 204;
15
17
  exports.HTTP_PARTIAL_CONTENT = 206;
package/src/cross.js CHANGED
@@ -534,22 +534,3 @@ const BROWSERS = {
534
534
  Xbox: /xbox/i,
535
535
  UC: /UCBrowser/i,
536
536
  };
537
- Object.defineProperties(Object.prototype, {
538
- _L: {
539
- enumerable: false,
540
- writable: true,
541
- value(msg = '') {
542
- const val = this instanceof Number || this instanceof String || this instanceof Boolean ? this.valueOf() : this;
543
- console.log('**', msg, val);
544
- return val;
545
- }
546
- },
547
- _D: {
548
- enumerable: false,
549
- writable: true,
550
- value(msg = '') {
551
- debugger;
552
- return this._L(msg);
553
- }
554
- }
555
- });
package/src/github.js CHANGED
@@ -15,6 +15,7 @@ const promises_1 = require("fs/promises");
15
15
  const path_1 = require("path");
16
16
  const fs_1 = require("fs");
17
17
  const persistence_1 = require("./persistence");
18
+ const argv_1 = require("./argv");
18
19
  const DIST_ROOT = 'dist';
19
20
  exports.downloading = {};
20
21
  function downloadProgress(repo, status) {
@@ -236,7 +237,7 @@ exports.blacklistedInstalledPlugins = [];
236
237
  // centralized hosted information, to be used as little as possible
237
238
  const FN = 'central.json';
238
239
  let builtIn = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', FN), 'utf8'));
239
- exports.getProjectInfo = (0, misc_1.debounceAsync)(() => const_1.argv.central === false ? Promise.resolve(builtIn) : readGithubFile(`${const_1.HFS_REPO}/${const_1.HFS_REPO_BRANCH}/${FN}`)
240
+ exports.getProjectInfo = (0, misc_1.debounceAsync)(() => argv_1.argv.central === false ? Promise.resolve(builtIn) : readGithubFile(`${const_1.HFS_REPO}/${const_1.HFS_REPO_BRANCH}/${FN}`)
240
241
  .then(JSON.parse, () => null)
241
242
  .then(o => {
242
243
  if (o)
package/src/i18n.js CHANGED
@@ -40,6 +40,8 @@ function i18nFromTranslations(translations, embedded = 'en') {
40
40
  for (const lang of searchLangs)
41
41
  if (found = (_b = (_a = state.translations[selectedLang = lang]) === null || _a === void 0 ? void 0 : _a.translate) === null || _b === void 0 ? void 0 : _b[key])
42
42
  break;
43
+ if (found)
44
+ break;
43
45
  if (!warns.has(key) && langs.length && langs[0] !== embedded) {
44
46
  warns.add(key);
45
47
  console.debug("miss i18n:", key);
package/src/listen.js CHANGED
@@ -46,6 +46,7 @@ const events_1 = __importDefault(require("./events"));
46
46
  const net_1 = require("net");
47
47
  const nat_1 = require("./nat");
48
48
  const persistence_1 = require("./persistence");
49
+ const argv_1 = require("./argv");
49
50
  let httpSrv;
50
51
  let httpsSrv;
51
52
  const openBrowserAtStart = (0, config_1.defineConfig)('open_browser_at_start', !const_1.DEV);
@@ -75,7 +76,7 @@ const considerHttp = (0, misc_1.debounceAsync)(async () => {
75
76
  return;
76
77
  httpSrv.on('connection', connections_1.newConnection);
77
78
  printUrls(httpSrv.name);
78
- if (openBrowserAtStart.get() && !const_1.argv.updated)
79
+ if (openBrowserAtStart.get() && !argv_1.argv.updated)
79
80
  openAdmin();
80
81
  });
81
82
  exports.portCfg = (0, config_1.defineConfig)('port', 80);
@@ -54,6 +54,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
54
54
  ctx.status = cross_const_1.HTTP_SERVER_ERROR;
55
55
  ctx.body = err.message || String(err);
56
56
  });
57
+ ctx.req.on('close', () => dest.end());
57
58
  const uri = await dest.lockMiddleware; // we need to wait more than just the stream
58
59
  ctx.body = { uri };
59
60
  }
package/src/update.js CHANGED
@@ -19,6 +19,7 @@ const util_os_1 = require("./util-os");
19
19
  const first_1 = require("./first");
20
20
  const persistence_1 = require("./persistence");
21
21
  const lodash_1 = __importDefault(require("lodash"));
22
+ const argv_1 = require("./argv");
22
23
  const updateToBeta = (0, config_1.defineConfig)('update_to_beta', false);
23
24
  const autoCheckUpdate = (0, config_1.defineConfig)('auto_check_update', true);
24
25
  const lastCheckUpdate = persistence_1.storedMap.singleSync('lastCheckUpdate', 0);
@@ -92,7 +93,7 @@ function localUpdateAvailable() {
92
93
  }
93
94
  exports.localUpdateAvailable = localUpdateAvailable;
94
95
  async function updateSupported() {
95
- return const_1.argv.forceupdate || const_1.IS_BINARY && !await util_os_1.RUNNING_AS_SERVICE;
96
+ return argv_1.argv.forceupdate || const_1.IS_BINARY && !await util_os_1.RUNNING_AS_SERVICE;
96
97
  }
97
98
  exports.updateSupported = updateSupported;
98
99
  async function update(tagOrUrl = '') {
@@ -170,12 +171,12 @@ exports.update = update;
170
171
  function launch(cmd, pars = [], options) {
171
172
  return ((options === null || options === void 0 ? void 0 : options.sync) ? child_process_1.spawnSync : child_process_1.spawn)((0, util_os_1.cmdEscape)(cmd), pars, { detached: true, shell: true, stdio: [0, 1, 2], ...options });
172
173
  }
173
- if (const_1.argv.updating) { // we were launched with a temporary name, restore original name to avoid breaking references
174
+ if (argv_1.argv.updating) { // we were launched with a temporary name, restore original name to avoid breaking references
174
175
  const bin = process.execPath;
175
- const dest = (0, path_1.join)((0, path_1.dirname)(bin), const_1.argv.updating);
176
+ const dest = (0, path_1.join)((0, path_1.dirname)(bin), argv_1.argv.updating);
176
177
  (0, fs_1.renameSync)(bin, dest);
177
178
  // have to relaunch with new name, or otherwise next update will fail with EBUSY on hfs.exe
178
- console.log("renamed binary file to", const_1.argv.updating, "and restarting");
179
+ console.log("renamed binary file to", argv_1.argv.updating, "and restarting");
179
180
  // be sure to test launching both double-clicking and in a terminal
180
181
  if (const_1.IS_WINDOWS) // this method on Mac works only once, and without console
181
182
  (0, first_1.onProcessExit)(() => launch(dest, ['--updated', '--cwd .'])); // launch+sync here would cause old process to stay open, locking ports
package/src/upload.js CHANGED
@@ -37,7 +37,7 @@ function setUploadMeta(path, ctx) {
37
37
  }
38
38
  // stay sync because we use this function with formidable()
39
39
  const diskSpaceCache = (0, expiringCache_1.expiringCache)(3000); // invalidate shortly
40
- const openFiles = new Set();
40
+ const uploadingFiles = new Set();
41
41
  function uploadWriter(base, baseUri, path, ctx) {
42
42
  let fullPath = '';
43
43
  if ((0, misc_1.dirTraversal)(path))
@@ -78,12 +78,12 @@ function uploadWriter(base, baseUri, path, ctx) {
78
78
  catch (e) { // warn, but let it through
79
79
  console.warn("can't check disk size:", e.message || String(e));
80
80
  }
81
- if (openFiles.has(fullPath))
82
- return fail(const_1.HTTP_CONFLICT, 'uploading');
83
81
  // optionally 'skip'
84
82
  if (ctx.query.existing === 'skip' && fs_1.default.existsSync(fullPath))
85
83
  return fail(const_1.HTTP_CONFLICT, 'exists');
86
- openFiles.add(fullPath);
84
+ if (uploadingFiles.has(fullPath))
85
+ return fail(const_1.HTTP_CONFLICT, 'uploading');
86
+ uploadingFiles.add(fullPath);
87
87
  let overwriteRequestedButForbidden = false;
88
88
  try {
89
89
  // if upload creates a folder, then add meta to it too
@@ -91,38 +91,42 @@ function uploadWriter(base, baseUri, path, ctx) {
91
91
  setUploadMeta(dir, ctx);
92
92
  // use temporary name while uploading
93
93
  const keepName = (0, path_1.basename)(fullPath).slice(-200);
94
- let tempName = (0, path_1.join)(dir, 'hfs$upload-' + keepName);
95
- const resumable = fs_1.default.existsSync(tempName) && !openFiles.has(tempName) && tempName; // resumable is temp-file-1
96
- if (resumable)
97
- tempName = (0, path_1.join)(dir, 'hfs$upload2-' + keepName);
94
+ const firstTempName = (0, path_1.join)(dir, 'hfs$upload-' + keepName);
95
+ const altTempName = (0, path_1.join)(dir, 'hfs$upload2-' + keepName);
96
+ const splitAndPreserving = ctx.query.preserveTempFile; // frontend knows about existing temp that can be resumed, but it is not resuming that, but instead it is continuing split-uploading on alternative temp file
97
+ let tempName = splitAndPreserving ? altTempName : firstTempName;
98
+ const stats = (0, misc_1.try_)(() => fs_1.default.statSync(tempName));
99
+ const resumableSize = (stats === null || stats === void 0 ? void 0 : stats.size) || 0; // we use size to even when user has not required resume, yet, to notify frontend of the possibility
100
+ const resumableTempName = resumableSize > 0 && tempName;
101
+ if (resumableTempName)
102
+ tempName = altTempName;
98
103
  // checks for resume feature
99
104
  let resume = Number(ctx.query.resume);
100
- const size = resumable && (0, misc_1.try_)(() => fs_1.default.statSync(resumable).size);
101
- if (size === undefined) // stat failed
102
- return fail(const_1.HTTP_SERVER_ERROR);
103
- if (lodash_1.default.isNumber(size) && resume > size)
105
+ if (resume > resumableSize)
104
106
  return fail(const_1.HTTP_RANGE_NOT_SATISFIABLE);
105
107
  // warn frontend about resume possibility
106
108
  let resumableLost = false;
107
- if (!resume && resumable) {
109
+ if (!resume && !resumableTempName)
110
+ (0, frontEndApis_1.notifyClient)(ctx, const_1.UPLOAD_RESUMABLE, { [path]: 0 });
111
+ if (!resume && resumableTempName) {
108
112
  const timeout = 30;
109
- (0, frontEndApis_1.notifyClient)(ctx, 'upload.resumable', { [path]: size, expires: Date.now() + timeout * 1000 });
110
- delayedDelete(resumable, timeout, () => // if user resumes, this upload is interrupted, and next upload will cancel this delayedDelete
111
- fs_1.default.rename(tempName, resumable, err => {
113
+ (0, frontEndApis_1.notifyClient)(ctx, const_1.UPLOAD_RESUMABLE, { [path]: resumableSize, expires: Date.now() + timeout * 1000 });
114
+ delayedDelete(resumableTempName, timeout, () => // if user resumes, this upload is interrupted, and next upload will cancel this delayedDelete
115
+ fs_1.default.rename(tempName, resumableTempName, err => {
112
116
  if (err)
113
117
  return;
114
- tempName = resumable;
118
+ tempName = resumableTempName;
115
119
  resumableLost = true;
116
120
  }));
117
121
  }
118
122
  // append if resuming
119
- const resuming = resume && resumable;
123
+ const resuming = resume && resumableTempName;
120
124
  if (!resuming)
121
125
  resume = 0;
122
126
  const writeStream = (0, misc_1.createStreamLimiter)(reqSize !== null && reqSize !== void 0 ? reqSize : Infinity);
123
- if (resuming) {
127
+ if (resuming && !splitAndPreserving) {
124
128
  fs_1.default.rm(tempName, () => { });
125
- tempName = resumable;
129
+ tempName = resumableTempName;
126
130
  }
127
131
  cancelDeletion(tempName);
128
132
  ctx.state.uploadDestinationPath = tempName;
@@ -131,7 +135,7 @@ function uploadWriter(base, baseUri, path, ctx) {
131
135
  const resEvent = events_1.default.emit('uploadStart', obj);
132
136
  if (resEvent === null || resEvent === void 0 ? void 0 : resEvent.isDefaultPrevented())
133
137
  return;
134
- const fileStream = resuming ? fs_1.default.createWriteStream(resumable, { flags: 'r+', start: resume })
138
+ const fileStream = resuming ? fs_1.default.createWriteStream(resumableTempName, { flags: 'r+', start: resume })
135
139
  : fs_1.default.createWriteStream(tempName);
136
140
  writeStream.on('error', e => {
137
141
  releaseFile();
@@ -145,7 +149,7 @@ function uploadWriter(base, baseUri, path, ctx) {
145
149
  try {
146
150
  await new Promise(res => fileStream.close(res)); // this only seem to be necessary on Windows
147
151
  if (ctx.req.aborted) {
148
- if (resumable && !resumableLost && !resuming) // we don't want to be left with 2 temp files
152
+ if (resumableTempName && !resumableLost && !resuming) // we don't want to be left with 2 temp files
149
153
  return (0, promises_1.rm)(tempName);
150
154
  const sec = exports.deleteUnfinishedUploadsAfter.get();
151
155
  return lodash_1.default.isNumber(sec) && delayedDelete(tempName, sec);
@@ -168,12 +172,14 @@ function uploadWriter(base, baseUri, path, ctx) {
168
172
  try {
169
173
  await (0, promises_1.rename)(tempName, dest);
170
174
  cancelDeletion(tempName); // not necessary, as deletion's failure is silent, but still
175
+ if (splitAndPreserving) // we've been using altTempName, but now we're done, so we can delete firstTempName
176
+ delayedDelete(firstTempName, 0);
171
177
  ctx.state.uploadDestinationPath = dest;
172
178
  setUploadMeta(dest, ctx);
173
179
  if (ctx.query.comment)
174
180
  void (0, comments_1.setCommentFor)(dest, String(ctx.query.comment));
175
- if (resumable && !resuming) // this happens if user decided to not resume and the new upload finished before delayedDelete
176
- (0, promises_1.rm)(resumable).catch(console.warn);
181
+ if (resumableTempName && !resuming) // this happens if user decided to not resume and the new upload finished before delayedDelete
182
+ (0, promises_1.rm)(resumableTempName).catch(console.warn);
177
183
  obj.uri = (0, misc_1.enforceFinal)('/', baseUri) + (0, misc_1.pathEncode)((0, path_1.basename)(dest));
178
184
  events_1.default.emit('uploadFinished', obj);
179
185
  if (resEvent)
@@ -236,7 +242,7 @@ function uploadWriter(base, baseUri, path, ctx) {
236
242
  delete waitingToBeDeleted[path];
237
243
  }
238
244
  function releaseFile() {
239
- openFiles.delete(fullPath);
245
+ uploadingFiles.delete(fullPath);
240
246
  }
241
247
  function fail(status, msg) {
242
248
  console.debug('upload failed', status, msg);
@@ -245,7 +251,7 @@ function uploadWriter(base, baseUri, path, ctx) {
245
251
  ctx.status = status;
246
252
  if (msg)
247
253
  ctx.body = msg;
248
- (0, frontEndApis_1.notifyClient)(ctx, 'upload.status', { [path]: ctx.status }); // allow browsers to detect failure while still sending body
254
+ (0, frontEndApis_1.notifyClient)(ctx, const_1.UPLOAD_STATUS, { [path]: ctx.status }); // allow browsers to detect failure while still sending body
249
255
  }
250
256
  }
251
257
  exports.uploadWriter = uploadWriter;