core-3nweb-client-lib 0.43.9 → 0.43.12

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 (58) hide show
  1. package/build/api-defs/files.d.ts +32 -8
  2. package/build/api-defs/web3n.d.ts +2 -0
  3. package/build/core/asmail/inbox/index.js +1 -1
  4. package/build/core/asmail/inbox/msg-downloader.d.ts +2 -12
  5. package/build/core/asmail/inbox/msg-downloader.js +13 -46
  6. package/build/core/storage/synced/downloader.d.ts +6 -15
  7. package/build/core/storage/synced/downloader.js +25 -48
  8. package/build/core/storage/synced/obj-files.d.ts +4 -2
  9. package/build/core/storage/synced/obj-files.js +7 -7
  10. package/build/core/storage/synced/storage.d.ts +4 -2
  11. package/build/core/storage/synced/storage.js +2 -2
  12. package/build/core/storage/synced/upsyncer.d.ts +2 -4
  13. package/build/core/storage/synced/upsyncer.js +19 -13
  14. package/build/core-ipc/file.d.ts +10 -0
  15. package/build/core-ipc/file.js +23 -13
  16. package/build/core-ipc/fs.js +15 -8
  17. package/build/lib-client/3nstorage/storage-owner.js +36 -29
  18. package/build/lib-client/3nweb-signup.js +7 -7
  19. package/build/lib-client/asmail/recipient.js +14 -11
  20. package/build/lib-client/asmail/sender.js +24 -25
  21. package/build/lib-client/asmail/service-config.js +3 -6
  22. package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
  23. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  24. package/build/lib-client/fs-utils/files.js +4 -4
  25. package/build/lib-client/mailer-id/login.js +7 -7
  26. package/build/lib-client/mailer-id/provisioner.js +9 -7
  27. package/build/lib-client/objs-on-disk/file-writing-proc.d.ts +1 -1
  28. package/build/lib-client/objs-on-disk/obj-on-disk.d.ts +51 -3
  29. package/build/lib-client/objs-on-disk/obj-on-disk.js +414 -34
  30. package/build/lib-client/request-utils.d.ts +0 -7
  31. package/build/lib-client/request-utils.js +16 -11
  32. package/build/lib-client/service-locator.js +11 -8
  33. package/build/lib-client/user-with-mid-session.js +2 -6
  34. package/build/lib-client/user-with-pkl-session.js +25 -24
  35. package/build/lib-client/xsp-fs/common.d.ts +8 -3
  36. package/build/lib-client/xsp-fs/common.js +1 -1
  37. package/build/lib-client/xsp-fs/file.d.ts +3 -1
  38. package/build/lib-client/xsp-fs/file.js +4 -4
  39. package/build/lib-client/xsp-fs/folder-node.d.ts +1 -1
  40. package/build/lib-client/xsp-fs/folder-node.js +4 -4
  41. package/build/lib-client/xsp-fs/fs.d.ts +3 -1
  42. package/build/lib-client/xsp-fs/fs.js +4 -4
  43. package/build/lib-client/xsp-fs/node-in-fs.d.ts +6 -4
  44. package/build/lib-client/xsp-fs/node-in-fs.js +14 -9
  45. package/build/lib-common/buffer-utils.js +4 -1
  46. package/build/lib-common/exceptions/http.d.ts +11 -1
  47. package/build/lib-common/exceptions/http.js +10 -2
  48. package/build/lib-common/objs-on-disk/utils.d.ts +1 -1
  49. package/build/lib-common/processes/labelled-exec-pools.d.ts +1 -1
  50. package/build/lib-common/processes/labelled-exec-pools.js +8 -2
  51. package/build/protos/asmail.proto.js +545 -116
  52. package/build/protos/file.proto.js +485 -56
  53. package/build/protos/fs.proto.js +545 -116
  54. package/package.json +1 -1
  55. package/protos/file.proto +8 -2
  56. package/protos/fs.proto +3 -3
  57. /package/build/lib-common/objs-on-disk/{obj-file.d.ts → obj-version-file.d.ts} +0 -0
  58. /package/build/lib-common/objs-on-disk/{obj-file.js → obj-version-file.js} +0 -0
@@ -17,16 +17,12 @@
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.ServiceUser = void 0;
20
- /**
21
- * This defines a base class for some service's client that logs in with
22
- * MailerId and uses respectively authenticated session.
23
- */
24
- const request_utils_1 = require("../lib-client/request-utils");
25
20
  const api = require("../lib-common/service-api/mailer-id/login");
26
21
  const ws_utils_1 = require("./ws-utils");
27
22
  const url_1 = require("url");
28
23
  const login_1 = require("./mailer-id/login");
29
24
  const assert_1 = require("../lib-common/assert");
25
+ const http_1 = require("../lib-common/exceptions/http");
30
26
  class ServiceUser {
31
27
  get serviceURI() {
32
28
  return this.uri;
@@ -162,7 +158,7 @@ class ServiceUser {
162
158
  this.sessionId = undefined;
163
159
  }
164
160
  else {
165
- throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
161
+ throw (0, http_1.makeUnexpectedStatusHTTPException)(rep);
166
162
  }
167
163
  }
168
164
  async callEnsuringLogin(func) {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2017, 2020 - 2021 3NSoft Inc.
3
+ Copyright (C) 2015 - 2017, 2020 - 2021, 2025 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
@@ -17,11 +17,7 @@
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.ServiceUser = void 0;
20
- /**
21
- * This defines a base class for some service's client that logs in with
22
- * Public Key Login process and uses respectively authenticated session.
23
- */
24
- const request_utils_1 = require("./request-utils");
20
+ const http_1 = require("../lib-common/exceptions/http");
25
21
  const buffer_utils_1 = require("../lib-common/buffer-utils");
26
22
  const ecma_nacl_1 = require("ecma-nacl");
27
23
  const session_encryptor_1 = require("../lib-common/session-encryptor");
@@ -82,40 +78,43 @@ class ServiceUser {
82
78
  if (rep.status == loginApi.start.SC.ok) {
83
79
  // set sessionid
84
80
  if (!rep.data || (typeof rep.data.sessionId !== 'string')) {
85
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply to starting session');
81
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep);
86
82
  }
87
83
  this.sessionId = rep.data.sessionId;
88
84
  // set server public key
89
85
  if (typeof rep.data.serverPubKey !== 'string') {
90
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply: serverPubKey string is missing.');
86
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, { message: 'serverPubKey string is missing.' });
91
87
  }
92
88
  try {
93
89
  this.serverPubKey = buffer_utils_1.base64.open(rep.data.serverPubKey);
94
90
  if (this.serverPubKey.length !== ecma_nacl_1.box.KEY_LENGTH) {
95
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply: server\'s key has a wrong size.');
91
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, { message: `server's key has a wrong size.` });
96
92
  }
97
93
  }
98
94
  catch (err) {
99
- throw (0, request_utils_1.makeException)(rep, `Malformed reply: bad serverPubKey string. Error: ${('string' === typeof err) ? err : err.message}`);
95
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, {
96
+ message: `bad serverPubKey string. Error: ${('string' === typeof err) ? err : err.message}`
97
+ });
100
98
  }
101
99
  // get encrypted session key from json body
102
100
  if (typeof rep.data.sessionKey !== 'string') {
103
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply: sessionKey string is missing.');
101
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, { message: 'sessionKey string is missing.' });
104
102
  }
105
103
  try {
106
104
  this.encChallenge = buffer_utils_1.base64.open(rep.data.sessionKey);
107
- if (this.encChallenge.length !==
108
- (ecma_nacl_1.secret_box.NONCE_LENGTH + ecma_nacl_1.secret_box.KEY_LENGTH)) {
109
- throw (0, request_utils_1.makeException)(rep, `Malformed reply: byte chunk with session key has a wrong size.`);
105
+ if (this.encChallenge.length !== (ecma_nacl_1.secret_box.NONCE_LENGTH + ecma_nacl_1.secret_box.KEY_LENGTH)) {
106
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, { message: `byte chunk with session key has a wrong size.` });
110
107
  }
111
108
  }
112
109
  catch (err) {
113
- throw (0, request_utils_1.makeException)(rep, `Malformed reply: bad sessionKey string. Error: ${(typeof err === 'string') ? err : err.message}`);
110
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, {
111
+ message: `bad sessionKey string. Error: ${(typeof err === 'string') ? err : err.message}`
112
+ });
114
113
  }
115
114
  // get key derivation parameters for a default key
116
115
  if (!keyId) {
117
116
  if (typeof rep.data.keyDerivParams !== 'object') {
118
- throw (0, request_utils_1.makeException)(rep, `Malformed reply: keyDerivParams string is missing.`);
117
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, { message: `keyDerivParams string is missing.` });
119
118
  }
120
119
  this.keyDerivationParams = rep.data.keyDerivParams;
121
120
  }
@@ -124,11 +123,13 @@ class ServiceUser {
124
123
  (rep.status === loginApi.start.SC.redirect)) {
125
124
  const rd = rep.data;
126
125
  if (!rd || ('string' !== typeof rd.redirect)) {
127
- throw (0, request_utils_1.makeException)(rep, 'Malformed reply');
126
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep);
128
127
  }
129
128
  // refuse second redirect
130
129
  if (this.redirectedFrom !== undefined) {
131
- throw (0, request_utils_1.makeException)(rep, `Redirected too many times. First redirect was from ${this.redirectedFrom} to ${this.serviceURI}. Second and forbidden redirect is to ${rd.redirect}`);
130
+ throw (0, http_1.makeMalformedReplyHTTPException)(rep, {
131
+ message: `Redirected too many times. First redirect was from ${this.redirectedFrom} to ${this.serviceURI}. Second and forbidden redirect is to ${rd.redirect}`
132
+ });
132
133
  }
133
134
  // set params
134
135
  this.redirectedFrom = this.serviceURI;
@@ -137,12 +138,12 @@ class ServiceUser {
137
138
  return this.startSession(keyId);
138
139
  }
139
140
  else if (rep.status === loginApi.start.SC.unknownUser) {
140
- const exc = (0, request_utils_1.makeException)(rep);
141
+ const exc = (0, http_1.makeHTTPException)(rep.url, rep.method, rep.status, {});
141
142
  exc.unknownUser = true;
142
143
  throw exc;
143
144
  }
144
145
  else {
145
- throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
146
+ throw (0, http_1.makeUnexpectedStatusHTTPException)(rep);
146
147
  }
147
148
  }
148
149
  openSessionKey(dhsharedKeyCalc) {
@@ -190,18 +191,18 @@ class ServiceUser {
190
191
  this.serverVerificationBytes = undefined;
191
192
  }
192
193
  else {
193
- const exc = (0, request_utils_1.makeException)(rep);
194
+ const exc = (0, http_1.makeHTTPException)(rep.url, rep.method, rep.status, {});
194
195
  exc.serverNotTrusted = true;
195
196
  throw exc;
196
197
  }
197
198
  }
198
199
  else if (rep.status === loginApi.complete.SC.authFailed) {
199
- const exc = (0, request_utils_1.makeException)(rep);
200
+ const exc = (0, http_1.makeHTTPException)(rep.url, rep.method, rep.status, {});
200
201
  exc.cryptoResponseNotAccepted = true;
201
202
  throw exc;
202
203
  }
203
204
  else {
204
- throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
205
+ throw (0, http_1.makeUnexpectedStatusHTTPException)(rep);
205
206
  }
206
207
  }
207
208
  /**
@@ -245,7 +246,7 @@ class ServiceUser {
245
246
  this.encryptor = undefined;
246
247
  }
247
248
  else {
248
- throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
249
+ throw (0, http_1.makeUnexpectedStatusHTTPException)(rep);
249
250
  }
250
251
  }
251
252
  }
@@ -13,6 +13,7 @@ type OptionsToAdopteRemote = web3n.files.OptionsToAdopteRemote;
13
13
  type FSSyncException = web3n.files.FSSyncException;
14
14
  type FileException = web3n.files.FileException;
15
15
  type UploadEvent = web3n.files.UploadEvent;
16
+ type DownloadEvent = web3n.files.DownloadEvent;
16
17
  export type FSChangeSrc = web3n.files.FSChangeEvent['src'];
17
18
  export interface Node {
18
19
  objId: string;
@@ -40,7 +41,7 @@ export interface NodeEvent {
40
41
  objId: ObjId;
41
42
  parentObjId?: ObjId;
42
43
  childObjId?: ObjId;
43
- event: FolderEvent | FileEvent | RemoteEvent | UploadEvent;
44
+ event: FolderEvent | FileEvent | RemoteEvent | UploadEvent | DownloadEvent;
44
45
  }
45
46
  export interface Storage {
46
47
  readonly type: StorageType;
@@ -93,6 +94,8 @@ export interface LocalObjStatus {
93
94
  }
94
95
  export declare function wrapStorageImplementation(impl: Storage): Storage;
95
96
  export type StorageGetter = (type: StorageType, location?: string) => Storage;
97
+ export type DownloadEventSink = (event: DownloadEvent) => void;
98
+ export type UploadEventSink = (event: UploadEvent) => void;
96
99
  export interface SyncedStorage extends Storage {
97
100
  getObjSrcOfRemoteVersion(objId: ObjId, version: number): Promise<ObjSource>;
98
101
  archiveVersionOnServer(objId: ObjId, version: number): Promise<void>;
@@ -103,8 +106,10 @@ export interface SyncedStorage extends Storage {
103
106
  adoptRemote(objId: ObjId, opts: OptionsToAdopteRemote | undefined): Promise<number | undefined>;
104
107
  updateStatusInfo(objId: ObjId): Promise<SyncStatus>;
105
108
  isRemoteVersionOnDisk(objId: ObjId, version: number): Promise<'partial' | 'complete' | 'none'>;
106
- download(objId: ObjId, version: number): Promise<void>;
107
- startUpload(objId: ObjId, localVersion: number, uploadVersion: number, uploadHeader: UploadHeaderChange | undefined, createOnRemote: boolean, eventSink: (event: UploadEvent) => void): Promise<{
109
+ startDownload(objId: ObjId, version: number, eventSink: DownloadEventSink): Promise<{
110
+ downloadTaskId: number;
111
+ } | undefined>;
112
+ startUpload(objId: ObjId, localVersion: number, uploadVersion: number, uploadHeader: UploadHeaderChange | undefined, createOnRemote: boolean, eventSink: UploadEventSink | undefined): Promise<{
108
113
  uploadTaskId: number;
109
114
  completion: Promise<void>;
110
115
  }>;
@@ -117,7 +117,7 @@ function wrapSyncStorageImplementation(impl) {
117
117
  wrap.getObjSrcOfRemoteVersion = impl.getObjSrcOfRemoteVersion.bind(impl);
118
118
  wrap.archiveVersionOnServer = impl.archiveVersionOnServer.bind(impl);
119
119
  wrap.isRemoteVersionOnDisk = impl.isRemoteVersionOnDisk.bind(impl);
120
- wrap.download = impl.download.bind(impl);
120
+ wrap.startDownload = impl.startDownload.bind(impl);
121
121
  wrap.startUpload = impl.startUpload.bind(impl);
122
122
  wrap.uploadObjRemoval = impl.uploadObjRemoval.bind(impl);
123
123
  wrap.dropCachedLocalObjVersionsLessOrEqual = impl.dropCachedLocalObjVersionsLessOrEqual.bind(impl);
@@ -106,7 +106,9 @@ declare class S implements WritableFileSyncAPI {
106
106
  status(skipServerCheck?: boolean): Promise<SyncStatus>;
107
107
  updateStatusInfo(): Promise<SyncStatus>;
108
108
  isRemoteVersionOnDisk(version: number): Promise<'complete' | 'partial' | 'none'>;
109
- download(version: number): Promise<void>;
109
+ startDownload(version: number): Promise<{
110
+ downloadTaskId: number;
111
+ } | undefined>;
110
112
  adoptRemote(opts?: OptionsToAdopteRemote): Promise<void>;
111
113
  }
112
114
  export {};
@@ -227,7 +227,7 @@ class S {
227
227
  async startUpload(opts) {
228
228
  this.n.ensureIsWritable();
229
229
  const node = await this.n.getNode();
230
- const startedUpload = await node.startUpload(opts);
230
+ const startedUpload = await node.startUpload(opts, true);
231
231
  if (startedUpload) {
232
232
  const { uploadTaskId, uploadVersion } = startedUpload;
233
233
  return { uploadTaskId, uploadVersion };
@@ -239,7 +239,7 @@ class S {
239
239
  async upload(opts) {
240
240
  this.n.ensureIsWritable();
241
241
  const node = await this.n.getNode();
242
- const startedUpload = await node.startUpload(opts);
242
+ const startedUpload = await node.startUpload(opts, false);
243
243
  if (!startedUpload) {
244
244
  return;
245
245
  }
@@ -261,9 +261,9 @@ class S {
261
261
  const isOnDisk = await node.isSyncedVersionOnDisk(version);
262
262
  return isOnDisk;
263
263
  }
264
- async download(version) {
264
+ async startDownload(version) {
265
265
  const node = await this.n.getNode();
266
- await node.download(version);
266
+ return await node.startDownload(version);
267
267
  }
268
268
  async adoptRemote(opts) {
269
269
  const node = await this.n.getNode();
@@ -144,7 +144,7 @@ export declare class FolderNode extends NodeInFS<FolderPersistance> {
144
144
  private removeChildrenObjsInSyncedStorage;
145
145
  private uploadRemovalOfObjs;
146
146
  getParamsForLink(): LinkParameters<FolderLinkParams>;
147
- startUpload(opts: OptionsToUploadLocal | undefined): Promise<{
147
+ startUpload(opts: OptionsToUploadLocal | undefined, emitEvents: boolean): Promise<{
148
148
  uploadVersion: number;
149
149
  completion: Promise<void>;
150
150
  uploadTaskId: number;
@@ -244,7 +244,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
244
244
  async listNonCurrent(flags) {
245
245
  const src = await this.getObjSrcOfVersion(flags);
246
246
  const { folderInfo } = await this.crypto.read(src);
247
- const lst = Object.values(folderInfo)
247
+ const lst = Object.values(folderInfo.nodes)
248
248
  .map(nodeInfoToListingEntry);
249
249
  return { lst, version: src.version };
250
250
  }
@@ -785,7 +785,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
785
785
  };
786
786
  return linkParams;
787
787
  }
788
- async startUpload(opts) {
788
+ async startUpload(opts, emitEvents) {
789
789
  try {
790
790
  const toUpload = await this.needUpload(opts);
791
791
  if (!toUpload) {
@@ -793,10 +793,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
793
793
  }
794
794
  const { localVersion, createOnRemote, uploadVersion } = toUpload;
795
795
  if (toUpload.createOnRemote) {
796
- return await this.startUploadProcess(localVersion, createOnRemote, uploadVersion);
796
+ return await this.startUploadProcess(localVersion, createOnRemote, uploadVersion, emitEvents);
797
797
  }
798
798
  const removedNodes = await this.getNodesRemovedBetweenVersions(localVersion, uploadVersion - 1);
799
- const { completion, uploadTaskId } = await this.startUploadProcess(localVersion, createOnRemote, uploadVersion);
799
+ const { completion, uploadTaskId } = await this.startUploadProcess(localVersion, createOnRemote, uploadVersion, emitEvents);
800
800
  if (removedNodes.length > 0) {
801
801
  // start upload of children's removal after folder's upload;
802
802
  // we also don't await for chidren removal in returned completion
@@ -170,7 +170,9 @@ declare class S implements WritableFSSyncAPI {
170
170
  status(path: string, skipServerCheck?: boolean): Promise<SyncStatus>;
171
171
  updateStatusInfo(path: string): Promise<SyncStatus>;
172
172
  isRemoteVersionOnDisk(path: string, version: number): Promise<'complete' | 'partial' | 'none'>;
173
- download(path: string, version: number): Promise<void>;
173
+ startDownload(path: string, version: number): Promise<{
174
+ downloadTaskId: number;
175
+ } | undefined>;
174
176
  adoptRemote(path: string, opts?: OptionsToAdopteRemote): Promise<void>;
175
177
  private getFolderNode;
176
178
  diffCurrentAndRemoteFolderVersions(path: string, remoteVersion?: number): Promise<FolderDiff | undefined>;
@@ -710,7 +710,7 @@ class S {
710
710
  this.n.ensureIsWritable();
711
711
  const node = await this.n.get(path);
712
712
  try {
713
- const startedUpload = await node.startUpload(opts);
713
+ const startedUpload = await node.startUpload(opts, true);
714
714
  if (startedUpload) {
715
715
  const { uploadTaskId, uploadVersion } = startedUpload;
716
716
  return { uploadTaskId, uploadVersion };
@@ -728,7 +728,7 @@ class S {
728
728
  this.n.ensureIsWritable();
729
729
  const node = await this.n.get(path);
730
730
  try {
731
- const startedUpload = await node.startUpload(opts);
731
+ const startedUpload = await node.startUpload(opts, false);
732
732
  if (!startedUpload) {
733
733
  return;
734
734
  }
@@ -765,10 +765,10 @@ class S {
765
765
  throw (0, common_1.setPathInExc)(exc, path);
766
766
  }
767
767
  }
768
- async download(path, version) {
768
+ async startDownload(path, version) {
769
769
  const node = await this.n.get(path);
770
770
  try {
771
- await node.download(version);
771
+ return await node.startDownload(version);
772
772
  }
773
773
  catch (exc) {
774
774
  throw (0, common_1.setPathInExc)(exc, path);
@@ -3,7 +3,7 @@ import { Observable } from 'rxjs';
3
3
  import { CommonAttrs, XAttrs } from './attrs';
4
4
  import { Attrs, NodePersistance } from './node-persistence';
5
5
  import { ObjSource } from 'xsp-files';
6
- export type FSEvent = web3n.files.FolderEvent | web3n.files.FileEvent | web3n.files.UploadEvent;
6
+ export type FSEvent = web3n.files.FolderEvent | web3n.files.FileEvent | web3n.files.UploadEvent | web3n.files.DownloadEvent;
7
7
  type RemoteEvent = web3n.files.RemoteEvent;
8
8
  type XAttrsChanges = web3n.files.XAttrsChanges;
9
9
  type SyncStatus = web3n.files.SyncStatus;
@@ -81,7 +81,9 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
81
81
  syncStatus(): Promise<SyncStatus>;
82
82
  updateStatusInfo(): Promise<SyncStatus>;
83
83
  isSyncedVersionOnDisk(version: number): Promise<'partial' | 'complete' | 'none'>;
84
- download(version: number): Promise<void>;
84
+ startDownload(version: number): Promise<{
85
+ downloadTaskId: number;
86
+ } | undefined>;
85
87
  protected abstract setCurrentStateFrom(src: ObjSource): Promise<void>;
86
88
  adoptRemote(opts: OptionsToAdopteRemote | undefined): Promise<void>;
87
89
  protected needUpload(opts: OptionsToUploadLocal | undefined): Promise<{
@@ -89,12 +91,12 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
89
91
  uploadVersion: number;
90
92
  createOnRemote: boolean;
91
93
  } | undefined>;
92
- startUpload(opts: OptionsToUploadLocal | undefined): Promise<{
94
+ startUpload(opts: OptionsToUploadLocal | undefined, emitEvents: boolean): Promise<{
93
95
  uploadVersion: number;
94
96
  completion: Promise<void>;
95
97
  uploadTaskId: number;
96
98
  } | undefined>;
97
- protected startUploadProcess(localVersion: number, createOnRemote: boolean, uploadVersion: number): Promise<{
99
+ protected startUploadProcess(localVersion: number, createOnRemote: boolean, uploadVersion: number, emitEvents: boolean): Promise<{
98
100
  uploadVersion: number;
99
101
  completion: Promise<void>;
100
102
  uploadTaskId: number;
@@ -361,9 +361,12 @@ class NodeInFS {
361
361
  const storage = this.syncedStorage();
362
362
  return storage.isRemoteVersionOnDisk(this.objId, version);
363
363
  }
364
- async download(version) {
364
+ async startDownload(version) {
365
365
  const storage = this.syncedStorage();
366
- return storage.download(this.objId, version);
366
+ return storage.startDownload(this.objId, version, event => {
367
+ event.path = this.name;
368
+ this.broadcastEvent(event);
369
+ });
367
370
  }
368
371
  adoptRemote(opts) {
369
372
  return this.doChange(true, async () => {
@@ -477,26 +480,28 @@ class NodeInFS {
477
480
  }
478
481
  return { createOnRemote: (uploadVersion === 1), localVersion, uploadVersion };
479
482
  }
480
- async startUpload(opts) {
483
+ async startUpload(opts, emitEvents) {
481
484
  try {
482
485
  const toUpload = await this.needUpload(opts);
483
486
  if (!toUpload) {
484
487
  return;
485
488
  }
486
489
  const { localVersion, createOnRemote, uploadVersion } = toUpload;
487
- return await this.startUploadProcess(localVersion, createOnRemote, uploadVersion);
490
+ return await this.startUploadProcess(localVersion, createOnRemote, uploadVersion, emitEvents);
488
491
  }
489
492
  catch (exc) {
490
493
  throw (0, common_1.setPathInExc)(exc, this.name);
491
494
  }
492
495
  }
493
- async startUploadProcess(localVersion, createOnRemote, uploadVersion) {
496
+ async startUploadProcess(localVersion, createOnRemote, uploadVersion, emitEvents) {
494
497
  const uploadHeader = await this.makeHeaderForUploadIfVersionChanges(localVersion, uploadVersion);
495
498
  const storage = this.syncedStorage();
496
- const { completion, uploadTaskId } = await storage.startUpload(this.objId, localVersion, uploadVersion, uploadHeader, createOnRemote, event => {
497
- event.path = this.name;
498
- this.broadcastEvent(event);
499
- });
499
+ const { completion, uploadTaskId } = await storage.startUpload(this.objId, localVersion, uploadVersion, uploadHeader, createOnRemote, (emitEvents ?
500
+ event => {
501
+ event.path = this.name;
502
+ this.broadcastEvent(event);
503
+ } :
504
+ undefined));
500
505
  return {
501
506
  completion: completion.then(() => this.doChange(true, async () => {
502
507
  if (this.currentVersion === localVersion) {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2016, 2018 - 2020 3NSoft Inc.
3
+ Copyright (C) 2016, 2018 - 2020, 2025 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
@@ -97,6 +97,9 @@ var utf8;
97
97
  })(utf8 || (exports.utf8 = utf8 = {}));
98
98
  Object.freeze(utf8);
99
99
  function joinByteArrs(arrs) {
100
+ if (arrs.length === 1) {
101
+ return arrs[0];
102
+ }
100
103
  let totalLen = 0;
101
104
  for (const arr of arrs) {
102
105
  totalLen += arr.length;
@@ -1,4 +1,14 @@
1
1
  export type ConnectException = web3n.HTTPConnectException;
2
2
  export type HTTPException = web3n.HTTPException;
3
3
  export declare function makeConnectionException(url: string | undefined, method: string | undefined, message?: string, cause?: any): ConnectException;
4
- export declare function makeHTTPException(url: string, method: string, status: number, message?: string, cause?: any): HTTPException;
4
+ export declare function makeHTTPException(url: string, method: string, status: number, params: Partial<HTTPException>): HTTPException;
5
+ export declare function makeMalformedReplyHTTPException({ url, method, status }: {
6
+ url: string;
7
+ method: string;
8
+ status: number;
9
+ }, params?: Partial<HTTPException>): HTTPException;
10
+ export declare function makeUnexpectedStatusHTTPException({ url, method, status }: {
11
+ url: string;
12
+ method: string;
13
+ status: number;
14
+ }, params?: Partial<HTTPException>): HTTPException;
@@ -17,11 +17,19 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.makeConnectionException = makeConnectionException;
19
19
  exports.makeHTTPException = makeHTTPException;
20
+ exports.makeMalformedReplyHTTPException = makeMalformedReplyHTTPException;
21
+ exports.makeUnexpectedStatusHTTPException = makeUnexpectedStatusHTTPException;
20
22
  const runtime_1 = require("./runtime");
21
23
  function makeConnectionException(url, method, message, cause) {
22
24
  return (0, runtime_1.makeRuntimeException)('connect', { connectType: 'http', url, method, cause, message }, {});
23
25
  }
24
- function makeHTTPException(url, method, status, message, cause) {
25
- return (0, runtime_1.makeRuntimeException)('http-request', { url, method, status, cause, message }, {});
26
+ function makeHTTPException(url, method, status, params) {
27
+ return (0, runtime_1.makeRuntimeException)('http-request', { url, method, status, ...params }, {});
28
+ }
29
+ function makeMalformedReplyHTTPException({ url, method, status }, params) {
30
+ return (0, runtime_1.makeRuntimeException)('http-request', { url, method, status, ...params }, { malformedResponse: true });
31
+ }
32
+ function makeUnexpectedStatusHTTPException({ url, method, status }, params) {
33
+ return (0, runtime_1.makeRuntimeException)('http-request', { url, method, status, ...params }, { unexpectedStatus: true });
26
34
  }
27
35
  Object.freeze(exports);
@@ -1,6 +1,6 @@
1
1
  import { Layout } from 'xsp-files';
2
2
  import { DiffInfo } from '../service-api/3nstorage/owner';
3
- import { ObjVersionFile } from './obj-file';
3
+ import { ObjVersionFile } from './obj-version-file';
4
4
  import { Readable } from 'stream';
5
5
  export declare function diffToLayout(diff: DiffInfo): Layout;
6
6
  export interface ChunkWithHeader {
@@ -1,6 +1,6 @@
1
1
  export interface Task<PoolLabel extends string> {
2
2
  neededExecutor(): PoolLabel | undefined;
3
- process(): Promise<void>;
3
+ process(): Promise<boolean>;
4
4
  cancel(): Promise<void>;
5
5
  }
6
6
  declare class ProcessingPool<PoolLabel extends string> {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2022 3NSoft Inc.
3
+ Copyright (C) 2022, 2025 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
@@ -52,9 +52,15 @@ class ProcessingPool {
52
52
  }
53
53
  let proc = undefined;
54
54
  try {
55
- proc = task.process().catch(this.doOnError);
55
+ let continueRun = false;
56
+ proc = task.process().then(done => {
57
+ continueRun = !done;
58
+ }, this.doOnError);
56
59
  this.inProcess.add(proc);
57
60
  await proc;
61
+ if (continueRun) {
62
+ this.queue.unshift(task);
63
+ }
58
64
  }
59
65
  catch (err) {
60
66
  await this.doOnError(err);