core-3nweb-client-lib 0.43.2 → 0.43.4

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.
@@ -77,6 +77,7 @@ declare namespace web3n.files {
77
77
  removedOnServer?: true;
78
78
  versionMismatch?: true;
79
79
  conflict?: true;
80
+ isBehind?: true;
80
81
  notSynced?: true;
81
82
  remoteIsArchived?: true;
82
83
  remoteFolderItemNotFound?: true;
@@ -497,6 +498,9 @@ declare namespace web3n.files {
497
498
  flags?: VersionedReadFlags
498
499
  ): Promise<{ current?: number; archived?: number[]; }>;
499
500
 
501
+ /**
502
+ * File from synced storage has this api
503
+ */
500
504
  sync?: ReadonlyFileSyncAPI;
501
505
 
502
506
  }
@@ -567,6 +571,9 @@ declare namespace web3n.files {
567
571
 
568
572
  archiveCurrent(version?: number): Promise<number>;
569
573
 
574
+ /**
575
+ * File from synced storage has this api
576
+ */
570
577
  sync?: WritableFileSyncAPI;
571
578
 
572
579
  }
@@ -580,12 +587,24 @@ declare namespace web3n.files {
580
587
  */
581
588
  status(skipServerCheck?: boolean): Promise<SyncStatus>;
582
589
 
590
+ /**
591
+ * Returns a state of on-disk cache.
592
+ * @param version
593
+ */
583
594
  isRemoteVersionOnDisk(
584
595
  version: number
585
596
  ): Promise<'partial'|'complete'|'none'>;
586
597
 
598
+ /**
599
+ * This downloads bytes onto disk, skipping decryption, as file content isn't read here.
600
+ * @param version
601
+ */
587
602
  download(version: number): Promise<void>;
588
603
 
604
+ /**
605
+ * Adopts remote version.
606
+ * @param opts options let one to pass exact remote version, to trigger download.
607
+ */
589
608
  adoptRemote(opts?: OptionsToAdopteRemote): Promise<void>;
590
609
 
591
610
  }
@@ -598,6 +617,10 @@ declare namespace web3n.files {
598
617
 
599
618
  interface WritableFileSyncAPI extends ReadonlyFileSyncAPI {
600
619
 
620
+ /**
621
+ * Upload in conflicting and behind state of sync requires explicit upload version.
622
+ * @param opts
623
+ */
601
624
  upload(opts?: OptionsToUploadLocal): Promise<number|undefined>;
602
625
 
603
626
  }
@@ -1106,6 +1129,9 @@ declare namespace web3n.files {
1106
1129
  path: string
1107
1130
  ): Promise<{ current?: number; archived?: number[]; }>;
1108
1131
 
1132
+ /**
1133
+ * Folder/FS from synced storage has this api
1134
+ */
1109
1135
  sync?: ReadonlyFSSyncAPI;
1110
1136
 
1111
1137
  }
@@ -1169,6 +1195,9 @@ declare namespace web3n.files {
1169
1195
 
1170
1196
  archiveCurrent(path: string, version?: number): Promise<number>;
1171
1197
 
1198
+ /**
1199
+ * Folder/FS from synced storage has this api
1200
+ */
1172
1201
  sync?: WritableFSSyncAPI;
1173
1202
 
1174
1203
  }
@@ -1183,14 +1212,33 @@ declare namespace web3n.files {
1183
1212
  */
1184
1213
  status(path: string, skipServerCheck?: boolean): Promise<SyncStatus>;
1185
1214
 
1215
+ /**
1216
+ * Returns a state of on-disk cache of an item in fs.
1217
+ * @param version
1218
+ */
1186
1219
  isRemoteVersionOnDisk(
1187
1220
  path: string, version: number
1188
1221
  ): Promise<'partial'|'complete'|'none'>;
1189
1222
 
1223
+ /**
1224
+ * This downloads bytes onto disk, skipping decryption, as item's content isn't read here.
1225
+ * @param path
1226
+ * @param version
1227
+ */
1190
1228
  download(path: string, version: number): Promise<void>;
1191
1229
 
1230
+ /**
1231
+ * Adopts remote version of fs object at given path
1232
+ * @param path
1233
+ * @param opts options let one to pass exact remote version, to trigger download.
1234
+ */
1192
1235
  adoptRemote(path: string, opts?: OptionsToAdopteRemote): Promise<void>;
1193
1236
 
1237
+ /**
1238
+ * Calculates diff between current local and remote states of folder at given path.
1239
+ * @param path
1240
+ * @param remoteVersion
1241
+ */
1194
1242
  diffCurrentAndRemoteFolderVersions(
1195
1243
  path: string, remoteVersion?: number
1196
1244
  ): Promise<FolderDiff|undefined>;
@@ -1222,10 +1270,22 @@ declare namespace web3n.files {
1222
1270
 
1223
1271
  interface WritableFSSyncAPI extends ReadonlyFSSyncAPI {
1224
1272
 
1273
+ /**
1274
+ * Upload in conflicting and behind state of sync requires explicit upload version.
1275
+ * @param path
1276
+ * @param opts
1277
+ */
1225
1278
  upload(
1226
1279
  path: string, opts?: OptionsToUploadLocal
1227
1280
  ): Promise<number|undefined>;
1228
1281
 
1282
+ /**
1283
+ * This method is for resolving conflicts on folders.
1284
+ * It adopts some folder items, and not the whole folder state.
1285
+ * @param path
1286
+ * @param itemName
1287
+ * @param opts
1288
+ */
1229
1289
  adoptRemoteFolderItem(
1230
1290
  path: string, itemName: string, opts?: OptionsToAdoptRemoteItem
1231
1291
  ): Promise<number>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2022 - 2023 3NSoft Inc.
3
+ Copyright (C) 2022 - 2023, 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
@@ -211,7 +211,7 @@ class SqliteFiles {
211
211
  (0, file_1.ensureCorrectFS)(syncedFS, 'synced', true);
212
212
  const files = new SqliteFiles(syncedFS);
213
213
  const records = await files.makeRecords();
214
- files.startSyncing();
214
+ // files.startSyncing();
215
215
  return { files, records };
216
216
  }
217
217
  async makeRecords() {
@@ -28,8 +28,11 @@ function openSocket(url, sessionId) {
28
28
  const headers = {};
29
29
  headers[request_utils_1.SESSION_ID_HEADER] = sessionId;
30
30
  const ws = new WebSocket(url, { headers, agent: https_1.globalAgent });
31
- const opening = (0, deferred_1.defer)();
32
- const initOnError = (err) => opening.reject((0, http_1.makeConnectionException)(url, undefined, `Cannot open websocket connection due to error: ${err.message}`));
31
+ let opening = (0, deferred_1.defer)();
32
+ const initOnError = (err) => {
33
+ opening === null || opening === void 0 ? void 0 : opening.reject((0, http_1.makeConnectionException)(url, undefined, `WebSocket connection error: ${err.message}`));
34
+ opening = undefined;
35
+ };
33
36
  const onNonOkReply = (req, res) => {
34
37
  const errReply = {
35
38
  url,
@@ -37,7 +40,8 @@ function openSocket(url, sessionId) {
37
40
  status: res.statusCode,
38
41
  data: undefined
39
42
  };
40
- opening.resolve(errReply);
43
+ opening === null || opening === void 0 ? void 0 : opening.resolve(errReply);
44
+ opening = undefined;
41
45
  };
42
46
  ws.on('error', initOnError);
43
47
  ws.on('unexpected-response', onNonOkReply);
@@ -48,10 +52,15 @@ function openSocket(url, sessionId) {
48
52
  status: 200,
49
53
  data: ws
50
54
  };
51
- opening.resolve(okReply);
55
+ opening === null || opening === void 0 ? void 0 : opening.resolve(okReply);
56
+ opening = undefined;
52
57
  ws.removeListener('error', initOnError);
53
58
  ws.removeListener('unexpected-response', onNonOkReply);
54
59
  });
60
+ ws.on('error', err => {
61
+ // XXX we need
62
+ console.error(`Error in ${ws.url} connection`, err);
63
+ });
55
64
  return opening.promise;
56
65
  }
57
66
  Object.freeze(exports);
@@ -145,7 +145,7 @@ export declare class FolderNode extends NodeInFS<FolderPersistance> {
145
145
  upload(opts: OptionsToUploadLocal | undefined): Promise<number | undefined>;
146
146
  private uploadRemovalOf;
147
147
  private listRemovedInTreeToUploadRm;
148
- protected needUpload(localVersion: number | undefined): Promise<{
148
+ protected needUpload(opts: OptionsToUploadLocal | undefined): Promise<{
149
149
  localVersion: number;
150
150
  uploadVersion: number;
151
151
  createOnRemote: boolean;
@@ -788,7 +788,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
788
788
  }
789
789
  async upload(opts) {
790
790
  try {
791
- const toUpload = await this.needUpload(opts === null || opts === void 0 ? void 0 : opts.localVersion);
791
+ const toUpload = await this.needUpload(opts);
792
792
  if (!toUpload) {
793
793
  return;
794
794
  }
@@ -848,8 +848,8 @@ class FolderNode extends node_in_fs_1.NodeInFS {
848
848
  return node.objId;
849
849
  }
850
850
  }
851
- async needUpload(localVersion) {
852
- const toUpload = await super.needUpload(localVersion);
851
+ async needUpload(opts) {
852
+ const toUpload = await super.needUpload(opts);
853
853
  if (!toUpload) {
854
854
  return;
855
855
  }
@@ -77,7 +77,7 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
77
77
  download(version: number): Promise<void>;
78
78
  protected abstract setCurrentStateFrom(src: ObjSource): Promise<void>;
79
79
  adoptRemote(opts: OptionsToAdopteRemote | undefined): Promise<void>;
80
- protected needUpload(localVersion: number | undefined): Promise<{
80
+ protected needUpload(opts: OptionsToUploadLocal | undefined): Promise<{
81
81
  localVersion: number;
82
82
  uploadVersion: number;
83
83
  createOnRemote: boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2020, 2022 3NSoft Inc.
3
+ Copyright (C) 2015 - 2020, 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
@@ -337,8 +337,10 @@ class NodeInFS {
337
337
  }
338
338
  });
339
339
  }
340
- async needUpload(localVersion) {
341
- const { local, remote, synced } = await this.syncStatus();
340
+ async needUpload(opts) {
341
+ var _a;
342
+ const { local, remote, synced, state } = await this.syncStatus();
343
+ let localVersion = opts === null || opts === void 0 ? void 0 : opts.localVersion;
342
344
  if (localVersion) {
343
345
  if (localVersion !== this.currentVersion) {
344
346
  throw (0, exceptions_1.makeFSSyncException)(this.name, {
@@ -349,8 +351,8 @@ class NodeInFS {
349
351
  }
350
352
  if (!local || (local.latest !== localVersion)) {
351
353
  throw (0, exceptions_1.makeFSSyncException)(this.name, {
352
- versionMismatch: true,
353
- message: `No local version ${localVersion} to upload`
354
+ versionNotFound: true,
355
+ message: `There is no local version ${localVersion} to upload`
354
356
  });
355
357
  }
356
358
  }
@@ -360,38 +362,73 @@ class NodeInFS {
360
362
  }
361
363
  localVersion = this.currentVersion;
362
364
  }
363
- if (remote) {
364
- if (remote.latest) {
365
- const uploadVersion = remote.latest + 1;
366
- return { createOnRemote: false, localVersion, uploadVersion };
365
+ if ((remote && !remote.latest) || (synced && !synced.latest)) {
366
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
367
+ versionMismatch: true,
368
+ removedOnServer: true
369
+ });
370
+ }
371
+ let uploadVersion = opts === null || opts === void 0 ? void 0 : opts.uploadVersion;
372
+ if (state === 'unsynced') {
373
+ if (uploadVersion) {
374
+ if (((synced === null || synced === void 0 ? void 0 : synced.latest) && ((synced.latest + 1) !== uploadVersion))) {
375
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
376
+ versionMismatch: true,
377
+ message: `Given uploadVersion is ${uploadVersion} is not a +1 increment over synced version ${(_a = synced.latest) !== null && _a !== void 0 ? _a : 0}, in unsynced state.`
378
+ });
379
+ }
380
+ }
381
+ else {
382
+ uploadVersion = (synced === null || synced === void 0 ? void 0 : synced.latest) ? ((synced === null || synced === void 0 ? void 0 : synced.latest) + 1) : 1;
383
+ }
384
+ }
385
+ else if (state === 'conflicting') {
386
+ if (uploadVersion) {
387
+ if (uploadVersion <= remote.latest) {
388
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
389
+ versionMismatch: true,
390
+ conflict: true,
391
+ message: `Given upload version ${uploadVersion} is not greater than remote version ${remote === null || remote === void 0 ? void 0 : remote.latest}.`
392
+ });
393
+ }
367
394
  }
368
395
  else {
369
396
  throw (0, exceptions_1.makeFSSyncException)(this.name, {
370
397
  versionMismatch: true,
371
- removedOnServer: true
398
+ conflict: true,
399
+ message: `Upload version is not given during upload from conflicting state.`
372
400
  });
373
401
  }
374
402
  }
375
- else if (synced) {
376
- if (synced.latest) {
377
- const uploadVersion = synced.latest + 1;
378
- return { createOnRemote: false, localVersion, uploadVersion };
403
+ else if (state === 'behind') {
404
+ if (uploadVersion) {
405
+ if (uploadVersion <= remote.latest) {
406
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
407
+ versionMismatch: true,
408
+ isBehind: true,
409
+ message: `Given upload version ${uploadVersion} is not greater than remote version ${remote === null || remote === void 0 ? void 0 : remote.latest}.`
410
+ });
411
+ }
379
412
  }
380
413
  else {
381
414
  throw (0, exceptions_1.makeFSSyncException)(this.name, {
382
415
  versionMismatch: true,
383
- removedOnServer: true
416
+ isBehind: true,
417
+ message: `Upload version is not given during upload when synced state is behind remote.`
384
418
  });
385
419
  }
386
420
  }
421
+ else if (state === 'synced') {
422
+ return;
423
+ }
387
424
  else {
388
- const uploadVersion = 1;
389
- return { createOnRemote: true, localVersion, uploadVersion };
425
+ throw new Error(`Unrecognized sync state ${state}`);
390
426
  }
427
+ return { createOnRemote: (uploadVersion === 1), localVersion, uploadVersion };
391
428
  }
392
429
  async upload(opts) {
393
430
  try {
394
- const toUpload = await this.needUpload(opts === null || opts === void 0 ? void 0 : opts.localVersion);
431
+ const toUpload = await this.needUpload(opts);
395
432
  if (!toUpload) {
396
433
  return;
397
434
  }
@@ -38,15 +38,12 @@ function makeJsonCommPoint(ws) {
38
38
  const observers = new generic_ipc_1.MultiObserverWrap();
39
39
  const { heartbeat, healthyBeat, otherBeat } = makeHeartbeat(ws.url);
40
40
  ws.on('message', data => {
41
- if (typeof data !== 'string') {
42
- return;
43
- }
44
41
  if (observers.done) {
45
42
  return;
46
43
  }
47
44
  let env;
48
45
  try {
49
- env = JSON.parse(data);
46
+ env = JSON.parse(data.toString('utf8'));
50
47
  }
51
48
  catch (err) {
52
49
  ws.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core-3nweb-client-lib",
3
- "version": "0.43.2",
3
+ "version": "0.43.4",
4
4
  "description": "3NWeb client core library, embeddable into different environments",
5
5
  "main": "build/lib-index.js",
6
6
  "types": "build/lib-index.d.ts",
@@ -32,13 +32,13 @@
32
32
  "protobufjs": "^7.0.1",
33
33
  "punycode": "^2.1.1",
34
34
  "rxjs": "^7.5.7",
35
- "ws": "^7.4.6",
35
+ "ws": "^8.18.3",
36
36
  "xsp-files": "^4.2.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/jasmine": "^3.9.1",
40
40
  "@types/node": "^16.11.7",
41
- "@types/ws": "^7.4.7",
41
+ "@types/ws": "^8.18.1",
42
42
  "jasmine": "^3.9.0",
43
43
  "protobufjs-cli": "^1.0.2",
44
44
  "spec-3nweb-server": "^1.8.0",