core-3nweb-client-lib 0.27.0 → 0.27.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.
Files changed (81) hide show
  1. package/build/api-defs/files.d.ts +56 -26
  2. package/build/core/asmail/config/index.d.ts +2 -2
  3. package/build/core/asmail/config/index.js +2 -2
  4. package/build/core/asmail/config/invitations-anon.d.ts +10 -24
  5. package/build/core/asmail/config/invitations-anon.js +43 -31
  6. package/build/core/asmail/config/published-intro-key.d.ts +11 -22
  7. package/build/core/asmail/config/published-intro-key.js +47 -38
  8. package/build/core/asmail/inbox/attachments/fs.d.ts +2 -1
  9. package/build/core/asmail/inbox/attachments/fs.js +4 -3
  10. package/build/core/asmail/inbox/index.js +2 -2
  11. package/build/core/asmail/index.d.ts +1 -1
  12. package/build/core/asmail/index.js +2 -2
  13. package/build/core/asmail/keyring/correspondent-keys.d.ts +2 -2
  14. package/build/core/asmail/keyring/correspondent-keys.js +1 -1
  15. package/build/core/asmail/keyring/index.d.ts +9 -29
  16. package/build/core/asmail/keyring/index.js +82 -69
  17. package/build/core/id-manager/index.d.ts +43 -0
  18. package/build/core/{id-manager.js → id-manager/index.js} +33 -114
  19. package/build/core/id-manager/key-storage.d.ts +21 -0
  20. package/build/core/id-manager/key-storage.js +96 -0
  21. package/build/core/index.js +22 -25
  22. package/build/core/sign-in.d.ts +1 -2
  23. package/build/core/sign-in.js +5 -14
  24. package/build/core/sign-up.d.ts +2 -0
  25. package/build/core/sign-up.js +2 -1
  26. package/build/core/storage/index.d.ts +4 -2
  27. package/build/core/storage/index.js +36 -57
  28. package/build/core/storage/local/storage.d.ts +1 -1
  29. package/build/core/storage/synced/obj-files-gc.d.ts +1 -4
  30. package/build/core/storage/synced/obj-files-gc.js +1 -18
  31. package/build/core/storage/synced/obj-files.d.ts +11 -1
  32. package/build/core/storage/synced/obj-files.js +59 -34
  33. package/build/core/storage/synced/obj-status.d.ts +19 -7
  34. package/build/core/storage/synced/obj-status.js +158 -83
  35. package/build/core/storage/synced/storage.d.ts +7 -2
  36. package/build/core/storage/synced/storage.js +38 -15
  37. package/build/core/storage/synced/upsyncer.d.ts +4 -4
  38. package/build/core/storage/synced/upsyncer.js +14 -9
  39. package/build/ipc-via-protobuf/file.d.ts +7 -0
  40. package/build/ipc-via-protobuf/file.js +60 -27
  41. package/build/ipc-via-protobuf/fs.js +55 -38
  42. package/build/lib-client/3nstorage/exceptions.d.ts +13 -1
  43. package/build/lib-client/3nstorage/exceptions.js +9 -3
  44. package/build/lib-client/3nstorage/service.d.ts +6 -2
  45. package/build/lib-client/3nstorage/service.js +33 -17
  46. package/build/lib-client/3nstorage/util/file-based-json.js +2 -1
  47. package/build/lib-client/3nstorage/util/for-arrays.d.ts +1 -0
  48. package/build/lib-client/3nstorage/util/for-arrays.js +32 -0
  49. package/build/lib-client/3nstorage/xsp-fs/common.d.ts +5 -4
  50. package/build/lib-client/3nstorage/xsp-fs/common.js +1 -0
  51. package/build/lib-client/3nstorage/xsp-fs/file-node.d.ts +5 -10
  52. package/build/lib-client/3nstorage/xsp-fs/file-node.js +43 -45
  53. package/build/lib-client/3nstorage/xsp-fs/file.d.ts +7 -6
  54. package/build/lib-client/3nstorage/xsp-fs/file.js +14 -20
  55. package/build/lib-client/3nstorage/xsp-fs/folder-node.d.ts +16 -5
  56. package/build/lib-client/3nstorage/xsp-fs/folder-node.js +238 -68
  57. package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +18 -17
  58. package/build/lib-client/3nstorage/xsp-fs/fs.js +32 -37
  59. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +15 -11
  60. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +72 -22
  61. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +1 -1
  62. package/build/lib-client/local-files/device-fs.js +11 -11
  63. package/build/lib-client/objs-on-disk/obj-on-disk.d.ts +5 -2
  64. package/build/lib-client/objs-on-disk/obj-on-disk.js +16 -1
  65. package/build/lib-client/user-with-mid-session.d.ts +2 -1
  66. package/build/lib-client/user-with-mid-session.js +7 -1
  67. package/build/lib-common/async-fs-node.js +8 -8
  68. package/build/lib-common/exceptions/file.d.ts +4 -2
  69. package/build/lib-common/exceptions/file.js +24 -58
  70. package/build/lib-common/ipc/generic-ipc.js +5 -4
  71. package/build/lib-common/objs-on-disk/file-layout.js +1 -1
  72. package/build/lib-common/objs-on-disk/utils.js +1 -1
  73. package/build/lib-common/service-api/3nstorage/owner.d.ts +8 -9
  74. package/build/lib-common/service-api/3nstorage/owner.js +2 -1
  75. package/build/protos/asmail.proto.js +5943 -4348
  76. package/build/protos/file.proto.js +874 -0
  77. package/build/protos/fs.proto.js +7014 -5419
  78. package/package.json +3 -2
  79. package/protos/file.proto +23 -7
  80. package/protos/fs.proto +27 -13
  81. 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() {
@@ -206,19 +224,33 @@ class FolderNode extends node_in_fs_1.NodeInFS {
206
224
  .map(nodeInfoToListingEntry);
207
225
  return { lst, version: this.version };
208
226
  }
227
+ async listNonCurrent(flags) {
228
+ const src = await this.getObjSrcOfVersion(flags);
229
+ const { folderInfo } = await this.crypto.read(src);
230
+ const lst = Object.values(folderInfo)
231
+ .map(nodeInfoToListingEntry);
232
+ return { lst, version: src.version };
233
+ }
209
234
  async childExistsInSyncedVersion(childObjId) {
210
- const status = await this.syncStatus();
211
- if (status.state === 'synced') {
235
+ const { state, synced } = await this.syncStatus();
236
+ if (state === 'synced') {
212
237
  return true;
213
238
  }
214
- if (!status.synced) {
239
+ if (!(synced === null || synced === void 0 ? void 0 : synced.latest)) {
240
+ return false;
241
+ }
242
+ const storage = this.syncedStorage();
243
+ try {
244
+ const syncedContent = await storage.getObjSrc(this.objId, synced.latest);
245
+ const { folderInfo } = await this.crypto.read(syncedContent);
246
+ const childIsInSynced = !!Object.values(folderInfo.nodes)
247
+ .find(({ objId }) => (objId === childObjId));
248
+ return childIsInSynced;
249
+ }
250
+ catch (exc) {
251
+ storage.logError(exc, `Exception thrown in checking whether child node's obj is present in synced version.`);
215
252
  return false;
216
253
  }
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
254
  }
223
255
  getNodeInfo(name, undefOnMissing = false) {
224
256
  const fj = this.currentState.nodes[name];
@@ -229,7 +261,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
229
261
  return;
230
262
  }
231
263
  else {
232
- throw (0, file_1.makeFileException)(file_1.Code.notFound, name);
264
+ throw (0, file_1.makeFileException)('notFound', name);
233
265
  }
234
266
  }
235
267
  hasChild(childName, throwIfMissing = false) {
@@ -242,13 +274,13 @@ class FolderNode extends node_in_fs_1.NodeInFS {
242
274
  }
243
275
  if (type) {
244
276
  if ((type === 'file') && !childInfo.isFile) {
245
- throw (0, file_1.makeFileException)(file_1.Code.notFile, childInfo.name);
277
+ throw (0, file_1.makeFileException)('notFile', childInfo.name);
246
278
  }
247
279
  else if ((type === 'folder') && !childInfo.isFolder) {
248
- throw (0, file_1.makeFileException)(file_1.Code.notDirectory, childInfo.name);
280
+ throw (0, file_1.makeFileException)('notDirectory', childInfo.name);
249
281
  }
250
282
  else if ((type === 'link') && !childInfo.isLink) {
251
- throw (0, file_1.makeFileException)(file_1.Code.notLink, childInfo.name);
283
+ throw (0, file_1.makeFileException)('notLink', childInfo.name);
252
284
  }
253
285
  }
254
286
  return this.getOrMakeChildNodeForInfo(childInfo);
@@ -314,7 +346,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
314
346
  };
315
347
  return { event, childObjId: childInfo.objId };
316
348
  }).catch(noop);
317
- const fileExc = (0, file_1.makeFileException)(file_1.Code.notFound, childInfo.name, exc);
349
+ const fileExc = (0, file_1.makeFileException)('notFound', childInfo.name, exc);
318
350
  fileExc.inconsistentStateOfFS = true;
319
351
  throw fileExc;
320
352
  }
@@ -421,7 +453,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
421
453
  // do check for concurrent creation of a node
422
454
  if (this.getNodeInfo(name, true)) {
423
455
  if (exclusive) {
424
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, name);
456
+ throw (0, file_1.makeFileException)('alreadyExists', name);
425
457
  }
426
458
  else if (type === 'folder') {
427
459
  return (await this.getNode('folder', name));
@@ -494,7 +526,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
494
526
  // explicitly do not wait on a result of child's delete, cause if it fails
495
527
  // we just get traceable garbage, yet, the rest of a live/non-deleted tree
496
528
  // stays consistent
497
- f.removeObj();
529
+ this.callRemoveObjOn('local', f);
498
530
  }
499
531
  changeChildName(initName, newName) {
500
532
  return this.doTransition(async (state, version) => {
@@ -519,7 +551,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
519
551
  }
520
552
  async moveChildTo(childName, dst, nameInDst) {
521
553
  if (dst.hasChild(nameInDst)) {
522
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, nameInDst);
554
+ throw (0, file_1.makeFileException)('alreadyExists', nameInDst);
523
555
  }
524
556
  if (dst === this) {
525
557
  // In this case we only need to change child's name
@@ -574,7 +606,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
574
606
  // existing folder at this point
575
607
  if (path.length === 1) {
576
608
  if (exclusiveCreate) {
577
- throw (0, file_1.makeFileException)(file_1.Code.alreadyExists, path[0]);
609
+ throw (0, file_1.makeFileException)('alreadyExists', path[0]);
578
610
  }
579
611
  else {
580
612
  return f;
@@ -631,22 +663,91 @@ class FolderNode extends node_in_fs_1.NodeInFS {
631
663
  }
632
664
  return content;
633
665
  }
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);
666
+ async removeFolderObj(src, passIdsForRmUpload = false) {
667
+ const childrenNodes = await this.doChange(true, async () => {
668
+ const childrenNodes = await this.getAllNodes();
669
+ await this.removeThisNodeAsLeaf(src);
670
+ return childrenNodes;
671
+ });
672
+ if (childrenNodes.length === 0) {
673
+ return;
674
+ }
675
+ if (this.isInSyncedStorage) {
676
+ if (passIdsForRmUpload) {
677
+ return this.removeChildrenObjsInSyncedStorage(childrenNodes, src, true);
678
+ }
679
+ else {
680
+ this.removeChildrenObjsInSyncedStorage(childrenNodes, src, false);
681
+ }
682
+ }
683
+ else {
684
+ this.callRemoveObjOnAll(src, childrenNodes);
685
+ }
686
+ }
687
+ callRemoveObjOnAll(src, nodes) {
688
+ for (const f of nodes) {
689
+ this.callRemoveObjOn(src, f);
648
690
  }
649
691
  }
692
+ async removeChildrenObjsInSyncedStorage(childrenNodes, src, passIdsForRmUpload) {
693
+ let uploadRmsHere;
694
+ let collectedIds;
695
+ if (passIdsForRmUpload) {
696
+ collectedIds = [];
697
+ uploadRmsHere = false;
698
+ }
699
+ else {
700
+ try {
701
+ const status = await this.syncedStorage().status(this.objId);
702
+ if (status.neverUploaded()) {
703
+ collectedIds = [];
704
+ uploadRmsHere = true;
705
+ }
706
+ else {
707
+ collectedIds = undefined;
708
+ uploadRmsHere = false;
709
+ }
710
+ }
711
+ catch (exc) {
712
+ if (exc.objNotFound) {
713
+ collectedIds = [];
714
+ uploadRmsHere = true;
715
+ }
716
+ else {
717
+ throw exc;
718
+ }
719
+ }
720
+ }
721
+ if (!collectedIds) {
722
+ this.callRemoveObjOnAll(src, childrenNodes);
723
+ return;
724
+ }
725
+ await Promise.allSettled(childrenNodes.map(async (child) => {
726
+ const status = await this.syncedStorage().status(child.objId);
727
+ if (!status.neverUploaded()) {
728
+ collectedIds.push(child.objId);
729
+ }
730
+ if (child.type === 'folder') {
731
+ const ids = await child.removeFolderObj(src, passIdsForRmUpload);
732
+ if (ids) {
733
+ collectedIds.push(...ids);
734
+ }
735
+ }
736
+ else {
737
+ await child.removeNonFolderObj(src);
738
+ }
739
+ }));
740
+ if (uploadRmsHere) {
741
+ await this.uploadRemovalOfObjs(collectedIds);
742
+ }
743
+ else {
744
+ return collectedIds;
745
+ }
746
+ }
747
+ async uploadRemovalOfObjs(objsToRm) {
748
+ objsToRm.sort(); // shuffle order
749
+ await Promise.allSettled(objsToRm.map(objToRm => this.syncedStorage().uploadObjRemoval(objToRm)));
750
+ }
650
751
  getParamsForLink() {
651
752
  if ((this.storage.type !== 'synced') && (this.storage.type !== 'local')) {
652
753
  throw new Error(`Creating link parameters to object in ${this.storage.type} file system, is not implemented.`);
@@ -664,24 +765,72 @@ class FolderNode extends node_in_fs_1.NodeInFS {
664
765
  return linkParams;
665
766
  }
666
767
  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);
768
+ try {
769
+ const toUpload = await this.needUpload(opts === null || opts === void 0 ? void 0 : opts.localVersion);
770
+ if (!toUpload) {
771
+ return;
772
+ }
773
+ if (toUpload.createOnRemote) {
774
+ await super.upload(opts);
775
+ return;
776
+ }
777
+ const storage = this.syncedStorage();
778
+ const { localVersion, uploadVersion } = toUpload;
779
+ const removedNodes = await this.getNodesRemovedBetweenVersions(localVersion, uploadVersion - 1);
780
+ const uploadHeader = await this.uploadHeaderChange(localVersion, uploadVersion);
781
+ await storage.upload(this.objId, localVersion, uploadVersion, uploadHeader, false);
782
+ if (removedNodes.length > 0) {
783
+ // start upload of children's removal after folder's upload;
784
+ // we also don't await for chidren removal
785
+ this.uploadRemovalOf(removedNodes);
786
+ }
787
+ }
788
+ catch (exc) {
789
+ throw (0, common_1.setPathInExc)(exc, this.name);
790
+ }
791
+ }
792
+ async uploadRemovalOf(removedNodes) {
793
+ const rmObjs = [];
794
+ for (const node of removedNodes) {
795
+ (0, for_arrays_1.appendArray)(rmObjs, await this.listRemovedInTreeToUploadRm(node));
796
+ }
797
+ await this.uploadRemovalOfObjs(rmObjs);
798
+ }
799
+ async listRemovedInTreeToUploadRm(node) {
800
+ const storage = this.syncedStorage();
801
+ let versionBeforeRm;
802
+ try {
803
+ const status = await storage.status(node.objId);
804
+ versionBeforeRm = status.versionBeforeUnsyncedRemoval();
805
+ if (!versionBeforeRm) {
806
+ return;
807
+ }
808
+ }
809
+ catch (exc) {
810
+ if (exc.objNotFound
811
+ || exc.notFound) {
812
+ return;
813
+ }
814
+ throw exc;
815
+ }
816
+ if (node.isFolder) {
817
+ const objs = [node.objId];
818
+ const src = await storage.getObjSrc(node.objId, versionBeforeRm, true);
819
+ const folderContent = await FolderPersistance.readFolderContent(node.objId, node.key, src, storage.cryptor);
820
+ for (const child of Object.values(folderContent.nodes)) {
821
+ (0, for_arrays_1.appendArray)(objs, await this.listRemovedInTreeToUploadRm(child));
822
+ }
823
+ return objs;
824
+ }
825
+ else {
826
+ return node.objId;
827
+ }
676
828
  }
677
829
  async needUpload(localVersion) {
678
830
  const toUpload = await super.needUpload(localVersion);
679
831
  if (!toUpload) {
680
832
  return;
681
833
  }
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
834
  const storage = this.syncedStorage();
686
835
  if (toUpload.localVersion === this.version) {
687
836
  for (const { objId, name } of Object.values(this.currentState.nodes)) {
@@ -693,10 +842,29 @@ class FolderNode extends node_in_fs_1.NodeInFS {
693
842
  }
694
843
  }
695
844
  else {
696
- throw new Error(`Reading particular version is not implemented, yet`);
845
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
846
+ versionMismatch: true,
847
+ localVersion: toUpload.localVersion,
848
+ message: `Local version has concurrently changed from ${toUpload.localVersion} to current ${this.version}`
849
+ });
697
850
  }
698
851
  return toUpload;
699
852
  }
853
+ async getNodesRemovedBetweenVersions(newVer, syncedVer) {
854
+ const storage = this.syncedStorage();
855
+ let stateToUpload;
856
+ if (this.version === newVer) {
857
+ stateToUpload = this.currentState;
858
+ }
859
+ else {
860
+ const localVerSrc = await storage.getObjSrcOfRemoteVersion(this.objId, newVer);
861
+ ({ folderInfo: stateToUpload } = await this.crypto.read(localVerSrc));
862
+ }
863
+ const syncedVerSrc = await storage.getObjSrcOfRemoteVersion(this.objId, syncedVer);
864
+ const { folderInfo: syncedState } = await this.crypto.read(syncedVerSrc);
865
+ const { removedNodes } = identifyChanges(syncedState.nodes, stateToUpload.nodes);
866
+ return removedNodes;
867
+ }
700
868
  async adoptRemoteFolderItem(itemName, opts) {
701
869
  if (opts === null || opts === void 0 ? void 0 : opts.localVersion) {
702
870
  if (this.version !== opts.localVersion) {
@@ -741,10 +909,12 @@ class FolderNode extends node_in_fs_1.NodeInFS {
741
909
  return await this.addRemoteChild(remoteChildNode);
742
910
  }
743
911
  else if (localNodeToRm.objId === remoteChildNode.objId) {
744
- return await this.setRemoteNodeInfo(remoteChildNode);
912
+ (0, assert_1.assert)(typeOfNode(localNodeToRm) === typeOfNode(remoteChildNode));
913
+ // XXX
914
+ throw new Error(`Adaptation of changing keys needs implementation`);
745
915
  }
746
916
  else {
747
- return await this.replaceLocalChildWithRemote(localNodeToRm, remoteChildNode);
917
+ return await this.replaceLocalChildWithRemote(remoteChildNode);
748
918
  }
749
919
  }
750
920
  async addRemoteChild(remoteChildNode) {
@@ -761,25 +931,14 @@ class FolderNode extends node_in_fs_1.NodeInFS {
761
931
  };
762
932
  return { event, childObjId: remoteChildNode.objId };
763
933
  });
764
- // XXX child should update sync info, and adopt change.
765
934
  return newVersion;
766
935
  }
767
- async setRemoteNodeInfo(remoteChildNode) {
936
+ async replaceLocalChildWithRemote(remoteChildNode) {
937
+ let origChildNode;
768
938
  let newVersion;
769
939
  await this.doTransition(async (state, version) => {
770
940
  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];
941
+ origChildNode = state.nodes[remoteChildNode.name];
783
942
  state.nodes[remoteChildNode.name] = remoteChildNode;
784
943
  const additionEvent = {
785
944
  type: 'entry-addition',
@@ -799,12 +958,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
799
958
  { event: additionEvent, childObjId: remoteChildNode.objId }
800
959
  ];
801
960
  });
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');
961
+ const origChild = await this.getOrMakeChildNodeForInfo(origChildNode);
962
+ const removalsToUpload = (await this.removeChildrenObjsInSyncedStorage([origChild], 'sync', true));
963
+ this.uploadRemovalOfObjs(removalsToUpload);
808
964
  return newVersion;
809
965
  }
810
966
  async diffCurrentAndRemote(remoteVersion) {
@@ -907,6 +1063,20 @@ function nodeToListingEntry({ name, type }) {
907
1063
  return { name };
908
1064
  }
909
1065
  }
1066
+ function typeOfNode(nodeInfo) {
1067
+ if (nodeInfo.isFolder) {
1068
+ return 'folder';
1069
+ }
1070
+ else if (nodeInfo.isFile) {
1071
+ return 'file';
1072
+ }
1073
+ else if (nodeInfo.isLink) {
1074
+ return 'link';
1075
+ }
1076
+ else {
1077
+ throw new Error(`Unknown type of node info`);
1078
+ }
1079
+ }
910
1080
  function addToTransitionState(state, f, key) {
911
1081
  const nodeInfo = {
912
1082
  name: f.name,
@@ -21,6 +21,7 @@ declare type FSCollection = web3n.files.FSCollection;
21
21
  declare type FileFlags = web3n.files.FileFlags;
22
22
  declare type FileByteSource = web3n.files.FileByteSource;
23
23
  declare type FileByteSink = web3n.files.FileByteSink;
24
+ declare type VersionedReadFlags = web3n.files.VersionedReadFlags;
24
25
  declare type XAttrsChanges = web3n.files.XAttrsChanges;
25
26
  declare type WritableFSSyncAPI = web3n.files.WritableFSSyncAPI;
26
27
  declare type SyncStatus = web3n.files.SyncStatus;
@@ -39,7 +40,7 @@ export declare class XspFS implements WritableFS {
39
40
  private constructor();
40
41
  private storage;
41
42
  readonlySubRoot(path: string): Promise<ReadonlyFS>;
42
- writableSubRoot(path: string, flags?: web3n.files.VersionedFileFlags): Promise<WritableFS>;
43
+ writableSubRoot(path: string, flags?: web3n.files.VersionedFileWriteFlags): Promise<WritableFS>;
43
44
  /**
44
45
  * This creates in a root object in a given storage, returning fs object
45
46
  * representing created root.
@@ -88,7 +89,7 @@ export declare class XspFS implements WritableFS {
88
89
  watchFile(path: string, observer: Observer<FileEvent>): () => void;
89
90
  watchTree(path: string, depth: number | undefined, observer: Observer<FolderEvent | FileEvent>): () => void;
90
91
  readonlyFile(path: string): Promise<ReadonlyFile>;
91
- writableFile(path: string, flags?: web3n.files.VersionedFileFlags): Promise<WritableFile>;
92
+ writableFile(path: string, flags?: web3n.files.VersionedFileWriteFlags): Promise<WritableFile>;
92
93
  copyFile(src: string, dst: string, overwrite?: boolean): Promise<void>;
93
94
  saveFile(file: File, dst: string, overwrite?: boolean): Promise<void>;
94
95
  listFolder(folder: string): Promise<ListingEntry[]>;
@@ -96,10 +97,10 @@ export declare class XspFS implements WritableFS {
96
97
  readTxtFile(path: string): Promise<string>;
97
98
  readBytes(path: string, start?: number, end?: number): Promise<Uint8Array | undefined>;
98
99
  getByteSource(path: string): Promise<FileByteSource>;
99
- writeJSONFile(path: string, json: any, flags?: web3n.files.VersionedFileFlags): Promise<void>;
100
- writeTxtFile(path: string, txt: string, flags?: web3n.files.VersionedFileFlags): Promise<void>;
101
- writeBytes(path: string, bytes: Uint8Array, flags?: web3n.files.VersionedFileFlags): Promise<void>;
102
- getByteSink(path: string, flags?: web3n.files.VersionedFileFlags): Promise<FileByteSink>;
100
+ writeJSONFile(path: string, json: any, flags?: web3n.files.VersionedFileWriteFlags): Promise<void>;
101
+ writeTxtFile(path: string, txt: string, flags?: web3n.files.VersionedFileWriteFlags): Promise<void>;
102
+ writeBytes(path: string, bytes: Uint8Array, flags?: web3n.files.VersionedFileWriteFlags): Promise<void>;
103
+ getByteSink(path: string, flags?: web3n.files.VersionedFileWriteFlags): Promise<FileByteSink>;
103
104
  }
104
105
  interface N {
105
106
  get(path: string): Promise<NodeInFS<any>>;
@@ -121,38 +122,38 @@ declare class V implements WritableFSVersionedAPI, N {
121
122
  get(path: string): Promise<NodeInFS<any>>;
122
123
  ensureIsWritable(): void;
123
124
  updateXAttrs(path: string, changes: XAttrsChanges): Promise<number>;
124
- getXAttr(path: string, xaName: string): Promise<{
125
+ getXAttr(path: string, xaName: string, flags?: VersionedReadFlags): Promise<{
125
126
  attr: any;
126
127
  version: number;
127
128
  }>;
128
- listXAttrs(path: string): Promise<{
129
+ listXAttrs(path: string, flags?: VersionedReadFlags): Promise<{
129
130
  lst: string[];
130
131
  version: number;
131
132
  }>;
132
- listFolder(path: string): Promise<{
133
+ listFolder(path: string, flags?: VersionedReadFlags): Promise<{
133
134
  lst: ListingEntry[];
134
135
  version: number;
135
136
  }>;
136
- writeBytes(path: string, bytes: Uint8Array, flags?: web3n.files.VersionedFileFlags): Promise<number>;
137
- readBytes(path: string, start?: number, end?: number): Promise<{
137
+ writeBytes(path: string, bytes: Uint8Array, flags?: web3n.files.VersionedFileWriteFlags): Promise<number>;
138
+ readBytes(path: string, start?: number, end?: number, flags?: VersionedReadFlags): Promise<{
138
139
  bytes: Uint8Array | undefined;
139
140
  version: number;
140
141
  }>;
141
- writeTxtFile(path: string, txt: string, flags?: web3n.files.VersionedFileFlags): Promise<number>;
142
- readTxtFile(path: string): Promise<{
142
+ writeTxtFile(path: string, txt: string, flags?: web3n.files.VersionedFileWriteFlags): Promise<number>;
143
+ readTxtFile(path: string, flags?: VersionedReadFlags): Promise<{
143
144
  txt: string;
144
145
  version: number;
145
146
  }>;
146
- writeJSONFile(path: string, json: any, flags?: web3n.files.VersionedFileFlags): Promise<number>;
147
- readJSONFile<T>(path: string): Promise<{
147
+ writeJSONFile(path: string, json: any, flags?: web3n.files.VersionedFileWriteFlags): Promise<number>;
148
+ readJSONFile<T>(path: string, flags?: VersionedReadFlags): Promise<{
148
149
  json: T;
149
150
  version: number;
150
151
  }>;
151
- getByteSink(path: string, flags?: web3n.files.VersionedFileFlags): Promise<{
152
+ getByteSink(path: string, flags?: web3n.files.VersionedFileWriteFlags): Promise<{
152
153
  sink: FileByteSink;
153
154
  version: number;
154
155
  }>;
155
- getByteSource(path: string): Promise<{
156
+ getByteSource(path: string, flags?: VersionedReadFlags): Promise<{
156
157
  src: FileByteSource;
157
158
  version: number;
158
159
  }>;