core-3nweb-client-lib 0.44.7 → 0.44.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 (42) hide show
  1. package/build/api-defs/files.d.ts +1 -0
  2. package/build/api-defs/web3n.d.ts +2 -1
  3. package/build/core/asmail/inbox/inbox-events.d.ts +0 -1
  4. package/build/core/asmail/inbox/inbox-events.js +3 -5
  5. package/build/core/asmail/inbox/index.js +1 -1
  6. package/build/core/asmail/inbox/msg-downloader.d.ts +1 -2
  7. package/build/core/asmail/inbox/msg-downloader.js +3 -4
  8. package/build/core/storage/common/obj-info-file.d.ts +0 -1
  9. package/build/core/storage/common/obj-info-file.js +0 -10
  10. package/build/core/storage/synced/obj-status.d.ts +1 -0
  11. package/build/core/storage/synced/obj-status.js +8 -12
  12. package/build/core/storage/synced/remote-events.d.ts +0 -1
  13. package/build/core/storage/synced/remote-events.js +5 -7
  14. package/build/core/storage/synced/storage.js +2 -2
  15. package/build/core/storage/synced/upsyncer.d.ts +1 -2
  16. package/build/core/storage/synced/upsyncer.js +49 -25
  17. package/build/lib-client/3nstorage/storage-owner.js +1 -1
  18. package/build/lib-client/asmail/recipient.js +8 -4
  19. package/build/lib-client/cryptor/worker-js.js +4 -2
  20. package/build/lib-client/local-files/dev-file-sink.js +30 -28
  21. package/build/lib-client/local-files/dev-file-src.js +7 -6
  22. package/build/lib-client/local-files/device-fs.js +23 -23
  23. package/build/lib-client/objs-on-disk/obj-folders.js +6 -3
  24. package/build/lib-client/request-utils.d.ts +2 -1
  25. package/build/lib-client/request-utils.js +8 -19
  26. package/build/lib-client/user-with-mid-session.d.ts +2 -0
  27. package/build/lib-client/user-with-mid-session.js +33 -22
  28. package/build/lib-client/xsp-fs/attrs.js +4 -2
  29. package/build/lib-client/xsp-fs/exceptions.js +5 -4
  30. package/build/lib-client/xsp-fs/folder-node-serialization.js +4 -2
  31. package/build/lib-client/xsp-fs/node-in-fs.js +2 -5
  32. package/build/lib-common/async-fs-node.d.ts +30 -46
  33. package/build/lib-common/async-fs-node.js +71 -309
  34. package/build/lib-common/awaitable-state.js +3 -1
  35. package/build/lib-common/exceptions/file.d.ts +1 -1
  36. package/build/lib-common/exceptions/file.js +11 -6
  37. package/build/lib-common/exceptions/runtime.d.ts +7 -1
  38. package/build/lib-common/exceptions/runtime.js +16 -2
  39. package/build/lib-common/objs-on-disk/obj-version-file.d.ts +1 -1
  40. package/build/lib-common/objs-on-disk/obj-version-file.js +35 -33
  41. package/build/lib-index.d.ts +1 -1
  42. package/package.json +1 -1
@@ -1211,6 +1211,7 @@ declare namespace web3n.files {
1211
1211
 
1212
1212
  interface UploadStartEvent extends UploadEventBase {
1213
1213
  type: 'upload-started';
1214
+ isRestart: boolean;
1214
1215
  totalBytesToUpload: number;
1215
1216
  }
1216
1217
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (C) 2016 - 2018, 2020, 2025 3NSoft Inc.
2
+ Copyright (C) 2016 - 2018, 2020, 2025 - 2026 3NSoft Inc.
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify it under
5
5
  the terms of the GNU General Public License as published by the Free Software
@@ -31,6 +31,7 @@ declare namespace web3n {
31
31
  type?: string;
32
32
  cause?: any;
33
33
  message?: string;
34
+ stack?: string;
34
35
  }
35
36
 
36
37
  interface ConnectException extends RuntimeException {
@@ -31,7 +31,6 @@ export declare class InboxEvents {
31
31
  readonly connectionEvent$: Observable<InboxConnectionStatus>;
32
32
  private readonly wsProc;
33
33
  private disconnectedAt;
34
- private connection;
35
34
  constructor(msgReceiver: MailRecipient, getMsg: (msgId: string) => Promise<IncomingMessage>, listNewMsgs: (fromTS: number) => Promise<MsgInfo[]>, rmMsg: (msgId: string) => Promise<void>, logError: LogError);
36
35
  private makeProc;
37
36
  whenConnected(): Promise<void>;
@@ -22,7 +22,6 @@ const retrieval_1 = require("../../../lib-common/service-api/asmail/retrieval");
22
22
  const operators_1 = require("rxjs/operators");
23
23
  const utils_for_observables_1 = require("../../../lib-common/utils-for-observables");
24
24
  const ws_ipc_1 = require("../../../lib-common/ipc/ws-ipc");
25
- const awaitable_state_1 = require("../../../lib-common/awaitable-state");
26
25
  function toInboxConnectionStatus(status, params) {
27
26
  return (0, ws_ipc_1.addToStatus)(status, {
28
27
  service: 'inbox',
@@ -53,7 +52,6 @@ class InboxEvents {
53
52
  this.connectionEvents = new rxjs_1.Subject();
54
53
  this.connectionEvent$ = this.connectionEvents.asObservable().pipe((0, operators_1.share)());
55
54
  this.disconnectedAt = undefined;
56
- this.connection = new awaitable_state_1.AwaitableState();
57
55
  this.wsProc = new ws_ipc_1.WebSocketListening(SERVER_EVENTS_RESTART_WAIT_SECS, this.makeProc.bind(this));
58
56
  this.wsProc.startListening();
59
57
  Object.seal(this);
@@ -65,10 +63,10 @@ class InboxEvents {
65
63
  next: ev => {
66
64
  this.connectionEvents.next(toInboxConnectionStatus(ev));
67
65
  if (ev.type === 'heartbeat') {
68
- this.connection.setState();
66
+ this.msgReceiver.connectedState.setState();
69
67
  }
70
68
  else if ((ev.type === 'heartbeat-skip') || (ev.type === 'disconnected')) {
71
- this.connection.clearState();
69
+ this.msgReceiver.connectedState.clearState();
72
70
  }
73
71
  }
74
72
  });
@@ -87,7 +85,7 @@ class InboxEvents {
87
85
  return proc$;
88
86
  }
89
87
  async whenConnected() {
90
- return this.connection.whenStateIsSet();
88
+ return this.msgReceiver.connectedState.whenStateIsSet();
91
89
  }
92
90
  async getMessage(msgId) {
93
91
  try {
@@ -58,7 +58,7 @@ class InboxOnServer {
58
58
  try {
59
59
  (0, file_1.ensureCorrectFS)(syncedFS, 'synced', true);
60
60
  const msgReceiver = new recipient_1.MailRecipient(r.address, r.getSigner, () => r.asmailResolver(r.address), r.makeNet());
61
- const downloader = new msg_downloader_1.MsgDownloader(msgReceiver, () => inbox.inboxEvents.whenConnected());
61
+ const downloader = new msg_downloader_1.MsgDownloader(msgReceiver);
62
62
  const cache = await cached_msgs_1.CachedMessages.makeFor(cachePath, downloader, r.logError);
63
63
  const indexSyncedFS = await (0, fs_sync_utils_1.getOrMakeAndUploadFolderIn)(syncedFS, MSG_INDEX_FOLDER);
64
64
  const index = await msg_indexing_1.MsgIndex.make(indexSyncedFS);
@@ -3,9 +3,8 @@ import { ObjDownloader } from "../../../lib-client/objs-on-disk/obj-on-disk";
3
3
  import { MsgMeta } from "../../../lib-common/service-api/asmail/retrieval";
4
4
  export declare class MsgDownloader {
5
5
  private readonly msgReceiver;
6
- private readonly whenConnected;
7
6
  private readonly runner;
8
- constructor(msgReceiver: MailRecipient, whenConnected: () => Promise<void>);
7
+ constructor(msgReceiver: MailRecipient);
9
8
  getMsgMeta(msgId: string): Promise<MsgMeta>;
10
9
  getObjDownloader(msgId: string): ObjDownloader;
11
10
  private getLayoutWithHeaderAndFirstSegs;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2016 - 2019, 2025 3NSoft Inc.
3
+ Copyright (C) 2016 - 2019, 2025 - 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -21,9 +21,8 @@ const obj_on_disk_1 = require("../../../lib-client/objs-on-disk/obj-on-disk");
21
21
  const MAX_GETTING_CHUNK = 512 * 1024;
22
22
  const DOWNLOAD_START_CHUNK = 128 * 1024;
23
23
  class MsgDownloader {
24
- constructor(msgReceiver, whenConnected) {
24
+ constructor(msgReceiver) {
25
25
  this.msgReceiver = msgReceiver;
26
- this.whenConnected = whenConnected;
27
26
  this.runner = new obj_on_disk_1.DownloadsRunner();
28
27
  Object.freeze(this);
29
28
  }
@@ -36,7 +35,7 @@ class MsgDownloader {
36
35
  getSegs: (objId, v, start, end) => this.getSegs(msgId, objId, start, end),
37
36
  splitSegsDownloads: (start, end) => (0, obj_on_disk_1.splitSegsDownloads)(start, end, MAX_GETTING_CHUNK),
38
37
  schedule: this.runner.schedule.bind(this.runner),
39
- whenConnected: this.whenConnected
38
+ whenConnected: () => this.msgReceiver.connectedState.whenStateIsSet()
40
39
  };
41
40
  }
42
41
  async getLayoutWithHeaderAndFirstSegs(msgId, objId) {
@@ -41,7 +41,6 @@ export declare function rmNonArchVersionsIn(versions: VersionsInfo, ver: number)
41
41
  export declare function rmArchVersionFrom(versions: VersionsInfo, ver: number): boolean;
42
42
  export declare function setCurrentVersionIn(versions: VersionsInfo, version: number, baseVer: number | undefined): void;
43
43
  export declare function rmCurrentVersionIn(versions: VersionsInfo): number | undefined;
44
- export declare function rmVersionIn(version: number, vers: VersionsInfo): void;
45
44
  export declare function nonGarbageVersionsIn(versions: VersionsInfo): Set<number>;
46
45
  export interface NonGarbageVersions {
47
46
  gcMaxVer?: number;
@@ -23,7 +23,6 @@ exports.rmNonArchVersionsIn = rmNonArchVersionsIn;
23
23
  exports.rmArchVersionFrom = rmArchVersionFrom;
24
24
  exports.setCurrentVersionIn = setCurrentVersionIn;
25
25
  exports.rmCurrentVersionIn = rmCurrentVersionIn;
26
- exports.rmVersionIn = rmVersionIn;
27
26
  exports.nonGarbageVersionsIn = nonGarbageVersionsIn;
28
27
  exports.addWithBasesTo = addWithBasesTo;
29
28
  exports.addArchived = addArchived;
@@ -131,15 +130,6 @@ function rmCurrentVersionIn(versions) {
131
130
  }
132
131
  return current;
133
132
  }
134
- function rmVersionIn(version, vers) {
135
- if (vers.current === version) {
136
- vers.current = undefined;
137
- rmNonArchVersionsIn(vers, version);
138
- }
139
- if (isVersionIn(version, vers)) {
140
- rmArchVersionFrom(vers, version);
141
- }
142
- }
143
133
  function nonGarbageVersionsIn(versions) {
144
134
  const nonGarbage = new Set();
145
135
  addWithBasesTo(nonGarbage, versions.current, versions);
@@ -111,6 +111,7 @@ export declare class ObjStatus implements SyncedObjStatus, UploadStatusRecorder
111
111
  getNonGarbageVersions(): NonGarbage;
112
112
  removeCurrentVersion(): Promise<void>;
113
113
  private triggerSaveProc;
114
+ get upload(): UploadInfo | undefined;
114
115
  recordUploadStart(info: NewVersionUpload): Promise<void>;
115
116
  recordUploadInterimState(info: NewVersionUpload): Promise<void>;
116
117
  recordUploadCancellation(info: NewVersionUpload): Promise<void>;
@@ -197,10 +197,7 @@ class ObjStatus {
197
197
  return;
198
198
  }
199
199
  else {
200
- throw (0, runtime_1.makeRuntimeException)('file', {
201
- path: (0, path_1.join)(this.objFolder, exports.STATUS_FILE_NAME),
202
- fsEtityType: 'file', message: `Upload is in progress`
203
- }, { concurrentUpdate: true });
200
+ throw (0, runtime_1.makeRuntimeException)('file', { path: (0, path_1.join)(this.objFolder, exports.STATUS_FILE_NAME), fsEtityType: 'file', message: `Upload is in progress` }, { concurrentUpdate: true }, true);
204
201
  }
205
202
  }
206
203
  if (!remote.isArchived && remote.current) {
@@ -237,6 +234,9 @@ class ObjStatus {
237
234
  }
238
235
  }
239
236
  }
237
+ get upload() {
238
+ return this.status.upload;
239
+ }
240
240
  recordUploadStart(info) {
241
241
  var _a;
242
242
  if (this.status.upload) {
@@ -474,15 +474,11 @@ class ObjStatus {
474
474
  const local = this.status.local;
475
475
  (0, assert_1.assert)(local.diffToBase[version] === localBase);
476
476
  const lowerBase = local.diffToBase[localBase];
477
- if (localBase) {
478
- local.diffToBase[version] = lowerBase;
479
- local.baseToDiff[lowerBase] = version;
480
- }
481
- else {
482
- delete local.diffToBase[version];
477
+ if (lowerBase) {
478
+ // flip version's base to be new value before removing
479
+ (0, obj_info_file_1.addBaseToDiffLinkInVersInfo)(local, version, lowerBase);
483
480
  }
484
- delete local.diffToBase[localBase];
485
- delete local.baseToDiff[localBase];
481
+ (0, obj_info_file_1.rmNonArchVersionsIn)(local, localBase);
486
482
  return this.triggerSaveProc();
487
483
  }
488
484
  latestSyncedVersion() {
@@ -19,7 +19,6 @@ export declare class RemoteEvents {
19
19
  private readonly connectionEvents;
20
20
  readonly connectionEvent$: Observable<StorageConnectionStatus>;
21
21
  private readonly wsProc;
22
- private connection;
23
22
  constructor(remoteStorage: StorageOwner, files: ObjFiles, broadcastNodeEvent: Storage['broadcastNodeEvent'], logError: LogError);
24
23
  private makeProc;
25
24
  startListening(): void;
@@ -21,7 +21,6 @@ const rxjs_1 = require("rxjs");
21
21
  const owner_1 = require("../../../lib-common/service-api/3nstorage/owner");
22
22
  const operators_1 = require("rxjs/operators");
23
23
  const ws_ipc_1 = require("../../../lib-common/ipc/ws-ipc");
24
- const awaitable_state_1 = require("../../../lib-common/awaitable-state");
25
24
  function toStorageConnectionStatus(status, params) {
26
25
  return (0, ws_ipc_1.addToStatus)(status, {
27
26
  service: 'storage',
@@ -41,21 +40,20 @@ class RemoteEvents {
41
40
  this.logError = logError;
42
41
  this.connectionEvents = new rxjs_1.Subject();
43
42
  this.connectionEvent$ = this.connectionEvents.asObservable().pipe((0, operators_1.share)());
44
- this.connection = new awaitable_state_1.AwaitableState();
45
43
  this.wsProc = new ws_ipc_1.WebSocketListening(SERVER_EVENTS_RESTART_WAIT_SECS, this.makeProc.bind(this));
46
44
  Object.seal(this);
47
45
  }
48
46
  makeProc() {
49
47
  return (0, rxjs_1.from)(this.remoteStorage.openEventSource().then(({ client, heartbeat }) => {
50
- this.connection.setState();
48
+ this.remoteStorage.connectedState.setState();
51
49
  heartbeat.subscribe({
52
50
  next: ev => {
53
51
  this.connectionEvents.next(toStorageConnectionStatus(ev));
54
52
  if (ev.type === 'heartbeat') {
55
- this.connection.setState();
53
+ this.remoteStorage.connectedState.setState();
56
54
  }
57
55
  else if ((ev.type === 'heartbeat-skip') || (ev.type === 'disconnected')) {
58
- this.connection.clearState();
56
+ this.remoteStorage.connectedState.clearState();
59
57
  }
60
58
  }
61
59
  });
@@ -76,8 +74,8 @@ class RemoteEvents {
76
74
  this.connectionEvents.complete();
77
75
  this.wsProc.close();
78
76
  }
79
- async whenConnected() {
80
- return this.connection.whenStateIsSet();
77
+ whenConnected() {
78
+ return this.remoteStorage.connectedState.whenStateIsSet();
81
79
  }
82
80
  absorbObjChange(client) {
83
81
  return (new rxjs_1.Observable(obs => client.subscribe(owner_1.events.objChanged.EVENT_NAME, obs)))
@@ -40,7 +40,7 @@ class SyncedStore {
40
40
  this.nodes = new common_1.NodesContainer();
41
41
  this.events = new utils_for_observables_1.Broadcast();
42
42
  this.remoteEvents = new remote_events_1.RemoteEvents(this.remoteStorage, this.files, this.broadcastNodeEvent.bind(this), this.logError);
43
- this.uploader = new upsyncer_1.UpSyncer(this.remoteStorage, this.whenConnected.bind(this), this.logError);
43
+ this.uploader = new upsyncer_1.UpSyncer(this.remoteStorage, this.logError);
44
44
  Object.seal(this);
45
45
  }
46
46
  static async makeAndStart(path, user, getSigner, getStorages, cryptor, remoteServiceUrl, net, logError) {
@@ -249,7 +249,7 @@ class SyncedStore {
249
249
  return this.remoteEvents.connectionEvent$;
250
250
  }
251
251
  whenConnected() {
252
- return this.remoteEvents.whenConnected();
252
+ return this.remoteStorage.connectedState.whenStateIsSet();
253
253
  }
254
254
  }
255
255
  exports.SyncedStore = SyncedStore;
@@ -8,13 +8,12 @@ import { UploadEventSink, UploadHeaderChange } from "../../../lib-client/xsp-fs/
8
8
  export type FileWriteTapOperator = MonoTypeOperatorFunction<FileWrite[]>;
9
9
  export declare class UpSyncer {
10
10
  private readonly remoteStorage;
11
- private readonly whenConnected;
12
11
  private readonly logError;
13
12
  private readonly execPools;
14
13
  private readonly tasksByObjIds;
15
14
  private readonly tasksByIds;
16
15
  private readonly syncedUploadStarts;
17
- constructor(remoteStorage: StorageOwner, whenConnected: () => Promise<void>, logError: LogError);
16
+ constructor(remoteStorage: StorageOwner, logError: LogError);
18
17
  start(): void;
19
18
  stop(): Promise<void>;
20
19
  removeCurrentVersionOf(obj: SyncedObj): Promise<void>;
@@ -27,9 +27,8 @@ const synced_1 = require("../../../lib-common/processes/synced");
27
27
  const MAX_CHUNK_SIZE = 512 * 1024;
28
28
  const MAX_FAST_UPLOAD = 2 * 1024 * 1024;
29
29
  class UpSyncer {
30
- constructor(remoteStorage, whenConnected, logError) {
30
+ constructor(remoteStorage, logError) {
31
31
  this.remoteStorage = remoteStorage;
32
- this.whenConnected = whenConnected;
33
32
  this.logError = logError;
34
33
  this.tasksByObjIds = new Map();
35
34
  this.tasksByIds = new Map();
@@ -52,7 +51,7 @@ class UpSyncer {
52
51
  }
53
52
  catch (exc) {
54
53
  if (exc.type === 'connect') {
55
- await this.whenConnected();
54
+ await this.remoteStorage.connectedState.whenStateIsSet();
56
55
  return this.removeCurrentVersionOf(obj);
57
56
  }
58
57
  else {
@@ -83,7 +82,7 @@ class UpSyncer {
83
82
  if (uploadHeader) {
84
83
  await obj.saveUploadHeaderFile(uploadHeader);
85
84
  }
86
- const task = await UploadTask.for(obj, localVersion, uploadVersion, uploadHeader === null || uploadHeader === void 0 ? void 0 : uploadHeader.uploadHeader, syncedBase, createOnRemote, uploadTaskId, eventSink, this.remoteStorage, this.whenConnected, async () => {
85
+ const task = await UploadTask.for(obj, localVersion, uploadVersion, uploadHeader === null || uploadHeader === void 0 ? void 0 : uploadHeader.uploadHeader, syncedBase, createOnRemote, uploadTaskId, eventSink, this.remoteStorage, async () => {
87
86
  if (this.tasksByIds.delete(task.taskId)) {
88
87
  this.tasksByObjIds.delete(task.objId);
89
88
  }
@@ -108,10 +107,9 @@ exports.UpSyncer = UpSyncer;
108
107
  Object.freeze(UpSyncer.prototype);
109
108
  Object.freeze(UpSyncer);
110
109
  class UploadTask {
111
- constructor(taskId, remoteStorage, whenConnected, objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink) {
110
+ constructor(taskId, remoteStorage, objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink, isRestart) {
112
111
  this.taskId = taskId;
113
112
  this.remoteStorage = remoteStorage;
114
- this.whenConnected = whenConnected;
115
113
  this.objId = objId;
116
114
  this.objStatus = objStatus;
117
115
  this.src = src;
@@ -122,29 +120,51 @@ class UploadTask {
122
120
  this.uploadCompletion = (0, deferred_1.defer)();
123
121
  this.execLabel = executorLabelFor(this.info.needUpload);
124
122
  this.totalBytesToUpload = (0, obj_status_1.countBytesIn)(this.info);
125
- this.emitUploadEvent('upload-started', { totalBytesToUpload: this.totalBytesToUpload });
123
+ this.emitUploadEvent('upload-started', { totalBytesToUpload: this.totalBytesToUpload, isRestart });
126
124
  Object.seal(this);
127
125
  }
128
- static async for(obj, localVersion, uploadVersion, uploadHeader, syncedBase, createObj, taskId, eventSink, remoteStorage, whenConnected, doAtCompletion) {
126
+ static async for(obj, localVersion, uploadVersion, uploadHeader, syncedBase, createObj, taskId, eventSink, remoteStorage, doAtCompletion) {
129
127
  const src = await obj.getObjSrcFromLocalAndSyncedBranch(localVersion);
130
- let needUpload;
131
- if (syncedBase) {
132
- const { diff, newSegsPackOrder } = await obj.diffForUploadOf(localVersion);
133
- needUpload = await diffVerUpload(src, uploadHeader, diff, newSegsPackOrder);
128
+ const objStatus = obj.statusObj();
129
+ if (objStatus.upload) {
130
+ const info = objStatus.upload;
131
+ if ((info.type === 'new-version')
132
+ && (info.localVersion === localVersion) && (info.uploadVersion === uploadVersion)) {
133
+ return new UploadTask(taskId, remoteStorage, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink, true);
134
+ }
135
+ else {
136
+ let message;
137
+ if (info.type === 'new-version') {
138
+ message = `Upload type ${info.type} of local version ${info.localVersion} as new remote ${info.uploadVersion} is already scheduled, and is different from uploading local version ${localVersion} as remote ${uploadVersion}.`;
139
+ }
140
+ else {
141
+ message = `Upload type ${info.type} is already scheduled`;
142
+ }
143
+ throw (0, exceptions_1.makeFSSyncException)('sync-task', {
144
+ alreadyUploading: true,
145
+ message
146
+ });
147
+ }
134
148
  }
135
149
  else {
136
- needUpload = await wholeVerUpload(src, uploadHeader, createObj);
150
+ let needUpload;
151
+ if (syncedBase) {
152
+ const { diff, newSegsPackOrder } = await obj.diffForUploadOf(localVersion);
153
+ needUpload = await diffVerUpload(src, uploadHeader, diff, newSegsPackOrder);
154
+ }
155
+ else {
156
+ needUpload = await wholeVerUpload(src, uploadHeader, createObj);
157
+ }
158
+ const info = {
159
+ type: 'new-version',
160
+ localVersion,
161
+ uploadVersion,
162
+ baseVersion: syncedBase,
163
+ needUpload
164
+ };
165
+ await objStatus.recordUploadStart(info);
166
+ return new UploadTask(taskId, remoteStorage, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink, false);
137
167
  }
138
- const info = {
139
- type: 'new-version',
140
- localVersion,
141
- uploadVersion,
142
- baseVersion: syncedBase,
143
- needUpload
144
- };
145
- const objStatus = obj.statusObj();
146
- await objStatus.recordUploadStart(info);
147
- return new UploadTask(taskId, remoteStorage, whenConnected, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink);
148
168
  }
149
169
  neededExecutor() {
150
170
  return (!this.info.needUpload ? undefined : this.execLabel);
@@ -211,13 +231,17 @@ class UploadTask {
211
231
  catch (exc) {
212
232
  if (exc.type === 'connect') {
213
233
  this.emitUploadEvent('upload-disconnected', {});
214
- await this.whenConnected();
234
+ await this.remoteStorage.connectedState.whenStateIsSet();
215
235
  return false;
216
236
  }
217
237
  else {
238
+ if (exc.unexpectedStatus && this.info.needUpload.transactionId) {
239
+ await this.remoteStorage.cancelTransaction(this.objId, this.info.needUpload.transactionId)
240
+ .catch(noop);
241
+ }
218
242
  this.info.needUpload = undefined;
219
243
  this.uploadCompletion.reject((0, exceptions_1.makeFSSyncException)(`obj-upload`, {
220
- message: `Fail to upload local version ${this.info.uploadVersion}`,
244
+ message: `Fail to upload version ${this.info.uploadVersion} of local version ${this.info.localVersion}`,
221
245
  localVersion: this.info.uploadVersion,
222
246
  cause: exc
223
247
  }));
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2017, 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2015 - 2017, 2020, 2022, 2025 - 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015, 2017, 2025 3NSoft Inc.
3
+ Copyright (C) 2015, 2017, 2025 - 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -26,12 +26,14 @@ const user_with_mid_session_1 = require("../user-with-mid-session");
26
26
  const service_locator_1 = require("../service-locator");
27
27
  const ws_ipc_1 = require("../../lib-common/ipc/ws-ipc");
28
28
  const http_1 = require("../../lib-common/exceptions/http");
29
+ const runtime_1 = require("../../lib-common/exceptions/runtime");
29
30
  function makeMsgNotFoundException(msgId) {
30
31
  const exc = {
31
32
  runtimeException: true,
32
33
  type: 'inbox',
33
34
  msgId,
34
- msgNotFound: true
35
+ msgNotFound: true,
36
+ stack: (0, runtime_1.getStackHere)(1)
35
37
  };
36
38
  return exc;
37
39
  }
@@ -41,7 +43,8 @@ function makeObjNotFoundException(msgId, objId) {
41
43
  type: 'inbox',
42
44
  msgId,
43
45
  objNotFound: true,
44
- objId
46
+ objId,
47
+ stack: (0, runtime_1.getStackHere)(1)
45
48
  };
46
49
  return exc;
47
50
  }
@@ -50,7 +53,8 @@ function makeMsgIsBrokenException(msgId) {
50
53
  runtimeException: true,
51
54
  type: 'inbox',
52
55
  msgId,
53
- msgIsBroken: true
56
+ msgIsBroken: true,
57
+ stack: (0, runtime_1.getStackHere)(1)
54
58
  };
55
59
  return exc;
56
60
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2020 3NSoft Inc.
3
+ Copyright (C) 2020, 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -19,6 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
19
19
  const worker_threads_1 = require("worker_threads");
20
20
  const ecma_nacl_1 = require("ecma-nacl");
21
21
  const error_1 = require("../../lib-common/exceptions/error");
22
+ const runtime_1 = require("../../lib-common/exceptions/runtime");
22
23
  if (!worker_threads_1.parentPort) {
23
24
  throw new Error(`Missing expected parentPort. Is this called within WebWorker process?`);
24
25
  }
@@ -100,7 +101,8 @@ const funcs = {
100
101
  function wrapError(err) {
101
102
  const exc = {
102
103
  runtimeException: true,
103
- type: 'cryptor'
104
+ type: 'cryptor',
105
+ stack: (0, runtime_1.getStackHere)(1)
104
106
  };
105
107
  if (err.failedCipherVerification) {
106
108
  exc.failedCipherVerification = true;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2018, 2020 3NSoft Inc.
3
+ Copyright (C) 2015 - 2018, 2020, 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -21,6 +21,11 @@ const file_1 = require("../../lib-common/exceptions/file");
21
21
  const wrapping_1 = require("../../lib-common/byte-streaming/wrapping");
22
22
  const assert_1 = require("../../lib-common/assert");
23
23
  const buffer_utils_1 = require("../../lib-common/buffer-utils");
24
+ function throwRangeErrorParamsIf(conditionToThrow) {
25
+ if (conditionToThrow) {
26
+ throw RangeError(`Invalid parameters given`);
27
+ }
28
+ }
24
29
  class DevFileByteSink {
25
30
  constructor(path, pathPrefixMaskLen, size) {
26
31
  this.path = path;
@@ -44,13 +49,12 @@ class DevFileByteSink {
44
49
  };
45
50
  }
46
51
  async truncate(size) {
47
- (0, assert_1.assert)(Number.isInteger(size) && (size >= 0), `Invalid parameters given`);
52
+ throwRangeErrorParamsIf(!Number.isInteger(size) || (size < 0));
48
53
  await fs.truncate(this.path, size);
49
54
  this.size = size;
50
55
  }
51
56
  async splice(pos, del, bytes) {
52
- (0, assert_1.assert)(Number.isInteger(pos) && (pos >= 0)
53
- && Number.isInteger(del) && (del >= 0), `Invalid parameters given`);
57
+ throwRangeErrorParamsIf(!Number.isInteger(pos) || (pos < 0) || !Number.isInteger(del) || (del < 0));
54
58
  const ins = (bytes ? bytes.length : 0);
55
59
  if ((del === 0) && (ins === 0)) {
56
60
  return;
@@ -71,17 +75,17 @@ class DevFileByteSink {
71
75
  if (!bytes) {
72
76
  return;
73
77
  }
74
- let fd = undefined;
78
+ let fh = undefined;
75
79
  try {
76
- fd = await fs.open(this.path, 'r+');
77
- await fs.writeFromBuf(fd, pos, (0, buffer_utils_1.toBuffer)(bytes));
80
+ fh = await fs.open(this.path, 'r+');
81
+ await fs.writeFromBuf(fh, pos, (0, buffer_utils_1.toBuffer)(bytes));
78
82
  }
79
83
  catch (e) {
80
84
  throw (0, file_1.maskPathInExc)(this.pathPrefixMaskLen, e);
81
85
  }
82
86
  finally {
83
- if (fd !== undefined) {
84
- await fs.close(fd);
87
+ if (fh !== undefined) {
88
+ await fh.close();
85
89
  }
86
90
  }
87
91
  }
@@ -89,9 +93,8 @@ class DevFileByteSink {
89
93
  if (delta === 0) {
90
94
  return;
91
95
  }
92
- (0, assert_1.assert)(Number.isInteger(pos) && (pos >= 0)
93
- && Number.isInteger(delta) && Number.isInteger(initFileLen)
94
- && (pos <= initFileLen), `Invalid parameters given`);
96
+ throwRangeErrorParamsIf(!Number.isInteger(pos) || (pos < 0) || !Number.isInteger(delta) ||
97
+ !Number.isInteger(initFileLen) || (pos > initFileLen));
95
98
  if (delta > 0) {
96
99
  await this.insFileBytesAt(pos, delta, initFileLen);
97
100
  }
@@ -102,20 +105,19 @@ class DevFileByteSink {
102
105
  async insFileBytesAt(pos, ins, initFileLen) {
103
106
  const bytesToMove = Math.max(0, initFileLen - pos);
104
107
  const buf = Buffer.allocUnsafe(Math.min(MAX_SHIFT_BUFFER_SIZE, bytesToMove));
105
- let fd = undefined;
108
+ let fh = undefined;
106
109
  try {
107
- fd = await fs.open(this.path, 'r+');
108
- await fs.ftruncate(fd, initFileLen + ins);
110
+ fh = await fs.open(this.path, 'r+');
111
+ await fh.truncate(initFileLen + ins);
109
112
  let bytesLeft = bytesToMove;
110
113
  let readPos = initFileLen;
111
114
  let writePos = initFileLen + ins;
112
115
  while (bytesLeft > 0) {
113
- const chunk = ((buf.length <= bytesLeft) ?
114
- buf : buf.slice(0, bytesLeft));
116
+ const chunk = ((buf.length <= bytesLeft) ? buf : buf.slice(0, bytesLeft));
115
117
  readPos -= chunk.length;
116
118
  writePos -= chunk.length;
117
- await fs.readToBuf(fd, readPos, chunk);
118
- await fs.writeFromBuf(fd, writePos, chunk);
119
+ await fs.readToBuf(fh, readPos, chunk);
120
+ await fs.writeFromBuf(fh, writePos, chunk);
119
121
  bytesLeft -= chunk.length;
120
122
  }
121
123
  }
@@ -123,37 +125,37 @@ class DevFileByteSink {
123
125
  throw (0, file_1.maskPathInExc)(this.pathPrefixMaskLen, e);
124
126
  }
125
127
  finally {
126
- if (fd !== undefined) {
127
- await fs.close(fd);
128
+ if (fh !== undefined) {
129
+ await fh.close();
128
130
  }
129
131
  }
130
132
  }
131
133
  async rmFileBytesAt(pos, del, initFileLen) {
132
134
  const bytesToMove = Math.max(0, initFileLen - pos - del);
133
135
  const buf = Buffer.allocUnsafe(Math.min(MAX_SHIFT_BUFFER_SIZE, bytesToMove));
134
- let fd = undefined;
136
+ let fh = undefined;
135
137
  try {
136
- fd = await fs.open(this.path, 'r+');
138
+ fh = await fs.open(this.path, 'r+');
137
139
  let bytesLeft = bytesToMove;
138
140
  let readPos = pos + del;
139
141
  let writePos = pos;
140
142
  while (bytesLeft > 0) {
141
143
  const chunk = ((buf.length <= bytesLeft) ?
142
144
  buf : buf.slice(0, bytesLeft));
143
- await fs.readToBuf(fd, readPos, chunk);
144
- await fs.writeFromBuf(fd, writePos, chunk);
145
+ await fs.readToBuf(fh, readPos, chunk);
146
+ await fs.writeFromBuf(fh, writePos, chunk);
145
147
  bytesLeft -= chunk.length;
146
148
  readPos += chunk.length;
147
149
  writePos += chunk.length;
148
150
  }
149
- await fs.ftruncate(fd, pos + bytesToMove);
151
+ await fh.truncate(pos + bytesToMove);
150
152
  }
151
153
  catch (e) {
152
154
  throw (0, file_1.maskPathInExc)(this.pathPrefixMaskLen, e);
153
155
  }
154
156
  finally {
155
- if (fd !== undefined) {
156
- await fs.close(fd);
157
+ if (fh !== undefined) {
158
+ await fh.close();
157
159
  }
158
160
  }
159
161
  }