core-3nweb-client-lib 0.27.1 → 0.27.3

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 (56) hide show
  1. package/build/api-defs/files.d.ts +4 -7
  2. package/build/core/asmail/inbox/attachments/fs.d.ts +2 -1
  3. package/build/core/asmail/inbox/attachments/fs.js +4 -3
  4. package/build/core/asmail/inbox/index.js +1 -1
  5. package/build/core/id-manager/index.d.ts +43 -0
  6. package/build/core/{id-manager.js → id-manager/index.js} +33 -114
  7. package/build/core/id-manager/key-storage.d.ts +21 -0
  8. package/build/core/id-manager/key-storage.js +96 -0
  9. package/build/core/index.js +21 -23
  10. package/build/core/sign-in.d.ts +1 -2
  11. package/build/core/sign-in.js +4 -13
  12. package/build/core/sign-up.d.ts +2 -0
  13. package/build/core/sign-up.js +2 -1
  14. package/build/core/storage/index.d.ts +4 -2
  15. package/build/core/storage/index.js +36 -57
  16. package/build/core/storage/local/storage.d.ts +1 -1
  17. package/build/core/storage/synced/obj-files-gc.d.ts +1 -4
  18. package/build/core/storage/synced/obj-files-gc.js +1 -18
  19. package/build/core/storage/synced/obj-files.d.ts +9 -1
  20. package/build/core/storage/synced/obj-files.js +41 -33
  21. package/build/core/storage/synced/obj-status.d.ts +18 -7
  22. package/build/core/storage/synced/obj-status.js +148 -83
  23. package/build/core/storage/synced/storage.d.ts +7 -2
  24. package/build/core/storage/synced/storage.js +50 -10
  25. package/build/core/storage/synced/upsyncer.d.ts +4 -4
  26. package/build/core/storage/synced/upsyncer.js +12 -6
  27. package/build/lib-client/3nstorage/exceptions.d.ts +13 -1
  28. package/build/lib-client/3nstorage/exceptions.js +9 -3
  29. package/build/lib-client/3nstorage/service.d.ts +6 -1
  30. package/build/lib-client/3nstorage/service.js +31 -15
  31. package/build/lib-client/3nstorage/util/file-based-json.js +2 -1
  32. package/build/lib-client/3nstorage/util/for-arrays.d.ts +1 -0
  33. package/build/lib-client/3nstorage/util/for-arrays.js +32 -0
  34. package/build/lib-client/3nstorage/xsp-fs/common.d.ts +5 -4
  35. package/build/lib-client/3nstorage/xsp-fs/common.js +1 -0
  36. package/build/lib-client/3nstorage/xsp-fs/file.js +2 -2
  37. package/build/lib-client/3nstorage/xsp-fs/folder-node.d.ts +11 -5
  38. package/build/lib-client/3nstorage/xsp-fs/folder-node.js +232 -68
  39. package/build/lib-client/3nstorage/xsp-fs/fs.js +15 -19
  40. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +4 -9
  41. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +16 -17
  42. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +1 -1
  43. package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
  44. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  45. package/build/lib-client/local-files/device-fs.js +11 -11
  46. package/build/lib-client/user-with-mid-session.d.ts +2 -1
  47. package/build/lib-client/user-with-mid-session.js +7 -1
  48. package/build/lib-common/async-fs-node.js +8 -8
  49. package/build/lib-common/exceptions/file.d.ts +4 -2
  50. package/build/lib-common/exceptions/file.js +24 -58
  51. package/build/lib-common/ipc/generic-ipc.js +5 -4
  52. package/build/lib-common/objs-on-disk/utils.js +1 -1
  53. package/build/lib-common/service-api/3nstorage/owner.d.ts +8 -5
  54. package/build/lib-common/service-api/3nstorage/owner.js +2 -1
  55. package/package.json +3 -2
  56. package/build/core/id-manager.d.ts +0 -46
@@ -37,6 +37,7 @@ const folder_node_serialization_1 = require("./folder-node-serialization");
37
37
  const attrs_1 = require("./attrs");
38
38
  const node_persistence_1 = require("./node-persistence");
39
39
  const assert_1 = require("../../../lib-common/assert");
40
+ const for_arrays_1 = require("../util/for-arrays");
40
41
  function jsonToInfoAndAttrs(json) {
41
42
  const folderInfo = {
42
43
  nodes: (0, json_utils_1.copy)(json.nodes)
@@ -62,6 +63,14 @@ class FolderPersistance extends node_persistence_1.NodePersistance {
62
63
  const folderInfo = (0, folder_node_serialization_1.parseFolderInfo)(content);
63
64
  return { folderInfo, xattrs, attrs: attrs_1.CommonAttrs.fromAttrs(attrs) };
64
65
  }
66
+ static async readFolderContent(objId, key, src, cryptor) {
67
+ if (objId === null) {
68
+ throw new Error("Missing objId for non-root folder");
69
+ }
70
+ const zNonce = (0, xsp_files_1.idToHeaderNonce)(objId);
71
+ const { folderInfo } = await (new FolderPersistance(zNonce, key, cryptor)).read(src);
72
+ return folderInfo;
73
+ }
65
74
  }
66
75
  Object.freeze(FolderPersistance.prototype);
67
76
  Object.freeze(FolderPersistance);
@@ -84,7 +93,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
84
93
  (0, assert_1.assert)(!objId && !parentId, `Root folder must have both objId and parent as nulls.`);
85
94
  }
86
95
  else if (objId === null) {
87
- new Error("Missing objId for non-root folder");
96
+ throw new Error("Missing objId for non-root folder");
88
97
  }
89
98
  this.crypto = new FolderPersistance(zNonce, key, storage.cryptor);
90
99
  if (setNewAttrs) {
@@ -198,7 +207,16 @@ class FolderNode extends node_in_fs_1.NodeInFS {
198
207
  return;
199
208
  }
200
209
  for (const objToRm of objsToRm) {
201
- (await this.getOrMakeChildNodeForInfo(objToRm)).removeObj('sync');
210
+ const nodeToRm = await this.getOrMakeChildNodeForInfo(objToRm);
211
+ this.callRemoveObjOn('sync', nodeToRm);
212
+ }
213
+ }
214
+ callRemoveObjOn(src, node) {
215
+ if (node.type === 'folder') {
216
+ node.removeFolderObj(src);
217
+ }
218
+ else {
219
+ node.removeNonFolderObj(src);
202
220
  }
203
221
  }
204
222
  list() {
@@ -207,18 +225,25 @@ class FolderNode extends node_in_fs_1.NodeInFS {
207
225
  return { lst, version: this.version };
208
226
  }
209
227
  async childExistsInSyncedVersion(childObjId) {
210
- const status = await this.syncStatus();
211
- if (status.state === 'synced') {
228
+ const { state, synced } = await this.syncStatus();
229
+ if (state === 'synced') {
212
230
  return true;
213
231
  }
214
- if (!status.synced) {
232
+ if (!(synced === null || synced === void 0 ? void 0 : synced.latest)) {
233
+ return false;
234
+ }
235
+ const storage = this.syncedStorage();
236
+ try {
237
+ const syncedContent = await storage.getObjSrc(this.objId, synced.latest);
238
+ const { folderInfo } = await this.crypto.read(syncedContent);
239
+ const childIsInSynced = !!Object.values(folderInfo.nodes)
240
+ .find(({ objId }) => (objId === childObjId));
241
+ return childIsInSynced;
242
+ }
243
+ catch (exc) {
244
+ storage.logError(exc, `Exception thrown in checking whether child node's obj is present in synced version.`);
215
245
  return false;
216
246
  }
217
- // XXX FolderNode.childExistsInSyncedVersion() should implement check in synced version
218
- return false;
219
- }
220
- listFolders() {
221
- return Object.keys(this.currentState.nodes).filter(name => !!this.currentState.nodes[name].isFolder);
222
247
  }
223
248
  getNodeInfo(name, undefOnMissing = false) {
224
249
  const fj = this.currentState.nodes[name];
@@ -229,7 +254,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
229
254
  return;
230
255
  }
231
256
  else {
232
- throw (0, file_1.makeFileException)(file_1.Code.notFound, name);
257
+ throw (0, file_1.makeFileException)('notFound', name);
233
258
  }
234
259
  }
235
260
  hasChild(childName, throwIfMissing = false) {
@@ -242,13 +267,13 @@ class FolderNode extends node_in_fs_1.NodeInFS {
242
267
  }
243
268
  if (type) {
244
269
  if ((type === 'file') && !childInfo.isFile) {
245
- throw (0, file_1.makeFileException)(file_1.Code.notFile, childInfo.name);
270
+ throw (0, file_1.makeFileException)('notFile', childInfo.name);
246
271
  }
247
272
  else if ((type === 'folder') && !childInfo.isFolder) {
248
- throw (0, file_1.makeFileException)(file_1.Code.notDirectory, childInfo.name);
273
+ throw (0, file_1.makeFileException)('notDirectory', childInfo.name);
249
274
  }
250
275
  else if ((type === 'link') && !childInfo.isLink) {
251
- throw (0, file_1.makeFileException)(file_1.Code.notLink, childInfo.name);
276
+ throw (0, file_1.makeFileException)('notLink', childInfo.name);
252
277
  }
253
278
  }
254
279
  return this.getOrMakeChildNodeForInfo(childInfo);
@@ -314,7 +339,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
314
339
  };
315
340
  return { event, childObjId: childInfo.objId };
316
341
  }).catch(noop);
317
- const fileExc = (0, file_1.makeFileException)(file_1.Code.notFound, childInfo.name, exc);
342
+ const fileExc = (0, file_1.makeFileException)('notFound', childInfo.name, exc);
318
343
  fileExc.inconsistentStateOfFS = true;
319
344
  throw fileExc;
320
345
  }
@@ -421,7 +446,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
421
446
  // do check for concurrent creation of a node
422
447
  if (this.getNodeInfo(name, true)) {
423
448
  if (exclusive) {
424
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, name);
449
+ throw (0, file_1.makeFileException)('alreadyExists', name);
425
450
  }
426
451
  else if (type === 'folder') {
427
452
  return (await this.getNode('folder', name));
@@ -494,7 +519,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
494
519
  // explicitly do not wait on a result of child's delete, cause if it fails
495
520
  // we just get traceable garbage, yet, the rest of a live/non-deleted tree
496
521
  // stays consistent
497
- f.removeObj();
522
+ this.callRemoveObjOn('local', f);
498
523
  }
499
524
  changeChildName(initName, newName) {
500
525
  return this.doTransition(async (state, version) => {
@@ -519,7 +544,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
519
544
  }
520
545
  async moveChildTo(childName, dst, nameInDst) {
521
546
  if (dst.hasChild(nameInDst)) {
522
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, nameInDst);
547
+ throw (0, file_1.makeFileException)('alreadyExists', nameInDst);
523
548
  }
524
549
  if (dst === this) {
525
550
  // In this case we only need to change child's name
@@ -574,7 +599,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
574
599
  // existing folder at this point
575
600
  if (path.length === 1) {
576
601
  if (exclusiveCreate) {
577
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, path[0]);
602
+ throw (0, file_1.makeFileException)('alreadyExists', path[0]);
578
603
  }
579
604
  else {
580
605
  return f;
@@ -631,22 +656,91 @@ class FolderNode extends node_in_fs_1.NodeInFS {
631
656
  }
632
657
  return content;
633
658
  }
634
- async delete(src) {
635
- const childrenNodes = await this.getAllNodes();
636
- await this.storage.removeObj(this.objId);
637
- this.storage.nodes.delete(this);
638
- this.setCurrentVersion(-1);
639
- this.currentState = { nodes: {} };
640
- const event = {
641
- type: 'removed',
642
- path: this.name,
643
- src
644
- };
645
- this.broadcastEvent(event, true);
646
- for (const node of childrenNodes) {
647
- node.removeObj(src);
659
+ async removeFolderObj(src, passIdsForRmUpload = false) {
660
+ const childrenNodes = await this.doChange(true, async () => {
661
+ const childrenNodes = await this.getAllNodes();
662
+ await this.removeThisNodeAsLeaf(src);
663
+ return childrenNodes;
664
+ });
665
+ if (childrenNodes.length === 0) {
666
+ return;
667
+ }
668
+ if (this.isInSyncedStorage) {
669
+ if (passIdsForRmUpload) {
670
+ return this.removeChildrenObjsInSyncedStorage(childrenNodes, src, true);
671
+ }
672
+ else {
673
+ this.removeChildrenObjsInSyncedStorage(childrenNodes, src, false);
674
+ }
675
+ }
676
+ else {
677
+ this.callRemoveObjOnAll(src, childrenNodes);
678
+ }
679
+ }
680
+ callRemoveObjOnAll(src, nodes) {
681
+ for (const f of nodes) {
682
+ this.callRemoveObjOn(src, f);
683
+ }
684
+ }
685
+ async removeChildrenObjsInSyncedStorage(childrenNodes, src, passIdsForRmUpload) {
686
+ let uploadRmsHere;
687
+ let collectedIds;
688
+ if (passIdsForRmUpload) {
689
+ collectedIds = [];
690
+ uploadRmsHere = false;
691
+ }
692
+ else {
693
+ try {
694
+ const status = await this.syncedStorage().status(this.objId);
695
+ if (status.neverUploaded()) {
696
+ collectedIds = [];
697
+ uploadRmsHere = true;
698
+ }
699
+ else {
700
+ collectedIds = undefined;
701
+ uploadRmsHere = false;
702
+ }
703
+ }
704
+ catch (exc) {
705
+ if (exc.objNotFound) {
706
+ collectedIds = [];
707
+ uploadRmsHere = true;
708
+ }
709
+ else {
710
+ throw exc;
711
+ }
712
+ }
713
+ }
714
+ if (!collectedIds) {
715
+ this.callRemoveObjOnAll(src, childrenNodes);
716
+ return;
717
+ }
718
+ await Promise.allSettled(childrenNodes.map(async (child) => {
719
+ const status = await this.syncedStorage().status(child.objId);
720
+ if (!status.neverUploaded()) {
721
+ collectedIds.push(child.objId);
722
+ }
723
+ if (child.type === 'folder') {
724
+ const ids = await child.removeFolderObj(src, passIdsForRmUpload);
725
+ if (ids) {
726
+ collectedIds.push(...ids);
727
+ }
728
+ }
729
+ else {
730
+ await child.removeNonFolderObj(src);
731
+ }
732
+ }));
733
+ if (uploadRmsHere) {
734
+ await this.uploadRemovalOfObjs(collectedIds);
735
+ }
736
+ else {
737
+ return collectedIds;
648
738
  }
649
739
  }
740
+ async uploadRemovalOfObjs(objsToRm) {
741
+ objsToRm.sort(); // shuffle order
742
+ await Promise.allSettled(objsToRm.map(objToRm => this.syncedStorage().uploadObjRemoval(objToRm)));
743
+ }
650
744
  getParamsForLink() {
651
745
  if ((this.storage.type !== 'synced') && (this.storage.type !== 'local')) {
652
746
  throw new Error(`Creating link parameters to object in ${this.storage.type} file system, is not implemented.`);
@@ -664,24 +758,73 @@ class FolderNode extends node_in_fs_1.NodeInFS {
664
758
  return linkParams;
665
759
  }
666
760
  async upload(opts) {
667
- // XXX temporary use of super's method
668
- return super.upload(opts);
669
- // const storage = this.syncedStorage();
670
- // XXX
671
- // - use identifyChanges() to find changes, minding particular version,
672
- // ensuring that concurrent change won't mess things up.
673
- // - items not present in uploaded version, relative to latest sync,
674
- // i.e. removed, removal should be uploaded with
675
- // storage.uploadObjRemoval(objId);
761
+ try {
762
+ const toUpload = await this.needUpload(opts === null || opts === void 0 ? void 0 : opts.localVersion);
763
+ if (!toUpload) {
764
+ return;
765
+ }
766
+ if (toUpload.createOnRemote) {
767
+ await super.upload(opts);
768
+ return;
769
+ }
770
+ const storage = this.syncedStorage();
771
+ const { localVersion, uploadVersion } = toUpload;
772
+ const removedNodes = await this.getNodesRemovedBetweenVersions(localVersion, uploadVersion - 1);
773
+ const uploadHeader = await this.uploadHeaderChange(localVersion, uploadVersion);
774
+ await storage.upload(this.objId, localVersion, uploadVersion, uploadHeader, false);
775
+ if (removedNodes.length > 0) {
776
+ // start upload of children's removal after folder's upload;
777
+ // we also don't await for chidren removal
778
+ this.uploadRemovalOf(removedNodes);
779
+ }
780
+ }
781
+ catch (exc) {
782
+ throw (0, common_1.setPathInExc)(exc, this.name);
783
+ }
784
+ }
785
+ async uploadRemovalOf(removedNodes) {
786
+ const storage = this.syncedStorage();
787
+ const rmObjs = [];
788
+ for (const node of removedNodes) {
789
+ (0, for_arrays_1.appendArray)(rmObjs, await this.listRemovedInTreeToUploadRm(node));
790
+ }
791
+ await this.uploadRemovalOfObjs(rmObjs);
792
+ }
793
+ async listRemovedInTreeToUploadRm(node) {
794
+ const storage = this.syncedStorage();
795
+ let versionBeforeRm;
796
+ try {
797
+ const status = await storage.status(node.objId);
798
+ versionBeforeRm = status.versionBeforeUnsyncedRemoval();
799
+ if (!versionBeforeRm) {
800
+ return;
801
+ }
802
+ }
803
+ catch (exc) {
804
+ if (exc.objNotFound
805
+ || exc.notFound) {
806
+ return;
807
+ }
808
+ throw exc;
809
+ }
810
+ if (node.isFolder) {
811
+ const objs = [node.objId];
812
+ const src = await storage.getObjSrc(node.objId, versionBeforeRm, true);
813
+ const folderContent = await FolderPersistance.readFolderContent(node.objId, node.key, src, storage.cryptor);
814
+ for (const child of Object.values(folderContent.nodes)) {
815
+ (0, for_arrays_1.appendArray)(objs, await this.listRemovedInTreeToUploadRm(child));
816
+ }
817
+ return objs;
818
+ }
819
+ else {
820
+ return node.objId;
821
+ }
676
822
  }
677
823
  async needUpload(localVersion) {
678
824
  const toUpload = await super.needUpload(localVersion);
679
825
  if (!toUpload) {
680
826
  return;
681
827
  }
682
- // XXX can put the following into private ensureAllChildrenUploaded(),
683
- // but it also need to get a consistent state, while current one can
684
- // be broken by simultaneous change in folder.
685
828
  const storage = this.syncedStorage();
686
829
  if (toUpload.localVersion === this.version) {
687
830
  for (const { objId, name } of Object.values(this.currentState.nodes)) {
@@ -693,10 +836,29 @@ class FolderNode extends node_in_fs_1.NodeInFS {
693
836
  }
694
837
  }
695
838
  else {
696
- throw new Error(`Reading particular version is not implemented, yet`);
839
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
840
+ versionMismatch: true,
841
+ localVersion: toUpload.localVersion,
842
+ message: `Local version has concurrently changed from ${toUpload.localVersion} to current ${this.version}`
843
+ });
697
844
  }
698
845
  return toUpload;
699
846
  }
847
+ async getNodesRemovedBetweenVersions(newVer, syncedVer) {
848
+ const storage = this.syncedStorage();
849
+ let stateToUpload;
850
+ if (this.version === newVer) {
851
+ stateToUpload = this.currentState;
852
+ }
853
+ else {
854
+ const localVerSrc = await storage.getObjSrcOfRemoteVersion(this.objId, newVer);
855
+ ({ folderInfo: stateToUpload } = await this.crypto.read(localVerSrc));
856
+ }
857
+ const syncedVerSrc = await storage.getObjSrcOfRemoteVersion(this.objId, syncedVer);
858
+ const { folderInfo: syncedState } = await this.crypto.read(syncedVerSrc);
859
+ const { removedNodes } = identifyChanges(syncedState.nodes, stateToUpload.nodes);
860
+ return removedNodes;
861
+ }
700
862
  async adoptRemoteFolderItem(itemName, opts) {
701
863
  if (opts === null || opts === void 0 ? void 0 : opts.localVersion) {
702
864
  if (this.version !== opts.localVersion) {
@@ -741,10 +903,12 @@ class FolderNode extends node_in_fs_1.NodeInFS {
741
903
  return await this.addRemoteChild(remoteChildNode);
742
904
  }
743
905
  else if (localNodeToRm.objId === remoteChildNode.objId) {
744
- return await this.setRemoteNodeInfo(remoteChildNode);
906
+ (0, assert_1.assert)(typeOfNode(localNodeToRm) === typeOfNode(remoteChildNode));
907
+ // XXX
908
+ throw new Error(`Adaptation of changing keys needs implementation`);
745
909
  }
746
910
  else {
747
- return await this.replaceLocalChildWithRemote(localNodeToRm, remoteChildNode);
911
+ return await this.replaceLocalChildWithRemote(remoteChildNode);
748
912
  }
749
913
  }
750
914
  async addRemoteChild(remoteChildNode) {
@@ -761,25 +925,14 @@ class FolderNode extends node_in_fs_1.NodeInFS {
761
925
  };
762
926
  return { event, childObjId: remoteChildNode.objId };
763
927
  });
764
- // XXX child should update sync info, and adopt change.
765
928
  return newVersion;
766
929
  }
767
- async setRemoteNodeInfo(remoteChildNode) {
930
+ async replaceLocalChildWithRemote(remoteChildNode) {
931
+ let origChildNode;
768
932
  let newVersion;
769
933
  await this.doTransition(async (state, version) => {
770
934
  newVersion = version;
771
- state.nodes[remoteChildNode.name] = remoteChildNode;
772
- return [];
773
- });
774
- // XXX child should update sync info, and adopt change, cause changed key
775
- // requires changed cypher.
776
- return newVersion;
777
- }
778
- async replaceLocalChildWithRemote(origChildNode, remoteChildNode) {
779
- let newVersion;
780
- await this.doTransition(async (state, version) => {
781
- newVersion = version;
782
- const presentNode = state.nodes[remoteChildNode.name];
935
+ origChildNode = state.nodes[remoteChildNode.name];
783
936
  state.nodes[remoteChildNode.name] = remoteChildNode;
784
937
  const additionEvent = {
785
938
  type: 'entry-addition',
@@ -799,12 +952,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
799
952
  { event: additionEvent, childObjId: remoteChildNode.objId }
800
953
  ];
801
954
  });
802
- // XXX
803
- // remote child should update sync info, and adopt change.
804
- // original child:
805
- // - if only local, should be removed,
806
- // - else should update sync info, and adopt both removal and change.
807
- (await this.getOrMakeChildNodeForInfo(origChildNode)).removeObj('sync');
955
+ const origChild = await this.getOrMakeChildNodeForInfo(origChildNode);
956
+ const removalsToUpload = (await this.removeChildrenObjsInSyncedStorage([origChild], 'sync', true));
957
+ this.uploadRemovalOfObjs(removalsToUpload);
808
958
  return newVersion;
809
959
  }
810
960
  async diffCurrentAndRemote(remoteVersion) {
@@ -907,6 +1057,20 @@ function nodeToListingEntry({ name, type }) {
907
1057
  return { name };
908
1058
  }
909
1059
  }
1060
+ function typeOfNode(nodeInfo) {
1061
+ if (nodeInfo.isFolder) {
1062
+ return 'folder';
1063
+ }
1064
+ else if (nodeInfo.isFile) {
1065
+ return 'file';
1066
+ }
1067
+ else if (nodeInfo.isLink) {
1068
+ return 'link';
1069
+ }
1070
+ else {
1071
+ throw new Error(`Unknown type of node info`);
1072
+ }
1073
+ }
910
1074
  function addToTransitionState(state, f, key) {
911
1075
  const nodeInfo = {
912
1076
  name: f.name,
@@ -68,7 +68,7 @@ class XspFS {
68
68
  }
69
69
  storage() {
70
70
  if (!this.store) {
71
- throw (0, file_1.makeFileException)(file_1.Code.storageClosed, this.name);
71
+ throw (0, file_1.makeFileException)('storageClosed', this.name);
72
72
  }
73
73
  return this.store;
74
74
  }
@@ -146,8 +146,10 @@ class XspFS {
146
146
  const folder = (await parentFolder.getFolder(folderName)
147
147
  .catch(setExcPath(path)));
148
148
  if (!removeContent && !folder.isEmpty()) {
149
- throw (0, file_1.makeFileException)(file_1.Code.notEmpty, path);
149
+ throw (0, file_1.makeFileException)('notEmpty', path);
150
150
  }
151
+ // note that internal folder.delete() removes all children as a matter
152
+ // of not leaving inaccessible nodes, i.e. content is removed implicitly
151
153
  await parentFolder.removeChild(folder);
152
154
  }
153
155
  async deleteFile(path) {
@@ -252,17 +254,11 @@ class XspFS {
252
254
  return true;
253
255
  }
254
256
  else if (throwIfMissing) {
255
- let code = '';
256
- if (type === 'file') {
257
- code = file_1.Code.notFile;
257
+ switch (type) {
258
+ case 'file': throw (0, file_1.makeFileException)('notFile', path);
259
+ case 'folder': throw (0, file_1.makeFileException)('notDirectory', path);
260
+ case 'link': throw (0, file_1.makeFileException)('notLink', path);
258
261
  }
259
- else if (type === 'folder') {
260
- code = file_1.Code.notDirectory;
261
- }
262
- else if (type === 'link') {
263
- code = file_1.Code.notLink;
264
- }
265
- throw (0, file_1.makeFileException)(code, path);
266
262
  }
267
263
  else {
268
264
  return false;
@@ -415,14 +411,14 @@ class XspFS {
415
411
  const exists = await this.checkFilePresence(path);
416
412
  if (exists) {
417
413
  if (flags.create && flags.exclusive) {
418
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, path);
414
+ throw (0, file_1.makeFileException)('alreadyExists', path);
419
415
  }
420
416
  const fNode = await this.v.getOrCreateFile(path, flags);
421
417
  return (0, files_1.wrapWritableFile)(file_2.FileObject.makeExisting(fNode, true));
422
418
  }
423
419
  else {
424
420
  if (!flags.create) {
425
- throw (0, file_1.makeFileException)(file_1.Code.notFound, path);
421
+ throw (0, file_1.makeFileException)('notFound', path);
426
422
  }
427
423
  return (0, files_1.wrapWritableFile)(file_2.FileObject.makeForNotExisiting(path_1.posix.basename(path), () => this.v.getOrCreateFile(path, flags), !!this.v.sync));
428
424
  }
@@ -512,7 +508,7 @@ class V {
512
508
  }
513
509
  getRootIfNotClosed(excPath) {
514
510
  if (!this.rootNode) {
515
- throw (0, file_1.makeFileException)(file_1.Code.storageClosed, excPath);
511
+ throw (0, file_1.makeFileException)('storageClosed', excPath);
516
512
  }
517
513
  return this.rootNode;
518
514
  }
@@ -525,7 +521,7 @@ class V {
525
521
  .catch(setExcPath(path));
526
522
  if (file) {
527
523
  if (exclusive) {
528
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, path);
524
+ throw (0, file_1.makeFileException)('alreadyExists', path);
529
525
  }
530
526
  }
531
527
  else {
@@ -591,7 +587,7 @@ class V {
591
587
  return { txt, version };
592
588
  }
593
589
  catch (err) {
594
- throw (0, file_1.makeFileException)(file_1.Code.parsingError, path, err);
590
+ throw (0, file_1.makeFileException)('parsingError', path, err);
595
591
  }
596
592
  }
597
593
  writeJSONFile(path, json, flags = WRITE_NONEXCL_FLAGS) {
@@ -605,7 +601,7 @@ class V {
605
601
  return { json, version };
606
602
  }
607
603
  catch (err) {
608
- throw (0, file_1.makeFileException)(file_1.Code.parsingError, path, err);
604
+ throw (0, file_1.makeFileException)('parsingError', path, err);
609
605
  }
610
606
  }
611
607
  async getByteSink(path, flags = WRITE_NONEXCL_FLAGS) {
@@ -780,7 +776,7 @@ class S {
780
776
  async getFolderNode(path) {
781
777
  const node = await this.n.get(path);
782
778
  if (node.type !== 'folder') {
783
- throw (0, file_1.makeFileException)(file_1.Code.notDirectory, path);
779
+ throw (0, file_1.makeFileException)('notDirectory', path);
784
780
  }
785
781
  return node;
786
782
  }
@@ -1,4 +1,4 @@
1
- import { FSChangeSrc, Node, NodeType, Storage, SyncedStorage } from './common';
1
+ import { FSChangeSrc, Node, NodeType, Storage, SyncedStorage, UploadHeaderChange } from './common';
2
2
  import { Observable } from 'rxjs';
3
3
  import { CommonAttrs, XAttrs } from './attrs';
4
4
  import { NodePersistance } from './node-persistence';
@@ -40,13 +40,8 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
40
40
  archived?: number[];
41
41
  }>;
42
42
  archiveCurrent(version?: number): Promise<number>;
43
- removeObj(src?: FSChangeSrc): Promise<void>;
44
- /**
45
- * This non-synchronized method deletes object from storage, and detaches
46
- * this node from storage. Make sure to call it inside access synchronization
47
- * construct.
48
- */
49
- protected delete(src: FSChangeSrc): Promise<void>;
43
+ removeNonFolderObj(src: FSChangeSrc): Promise<void>;
44
+ protected removeThisNodeAsLeaf(src: FSChangeSrc): Promise<void>;
50
45
  /**
51
46
  * This method runs node changing function in an exclusive manner.
52
47
  * Returned promise resolves to whatever change function returns.
@@ -80,6 +75,6 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
80
75
  createOnRemote: boolean;
81
76
  } | undefined>;
82
77
  upload(opts: OptionsToUploadLocal | undefined): Promise<void>;
83
- private uploadHeaderChange;
78
+ protected uploadHeaderChange(localVersion: number, uploadVersion: number): Promise<UploadHeaderChange | undefined>;
84
79
  }
85
80
  export {};