core-3nweb-client-lib 0.43.17 → 0.43.18

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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (C) 2016 - 2018, 2020, 2022, 2025 3NSoft Inc.
2
+ Copyright (C) 2016 - 2018, 2020, 2022, 2025 - 2026 3NSoft Inc.
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify it under
5
5
  the terms of the GNU General Public License as published by the Free Software
@@ -1331,8 +1331,17 @@ declare namespace web3n.files {
1331
1331
  */
1332
1332
  getRemoteFileItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ReadonlyFile>;
1333
1333
 
1334
+ /**
1335
+ * Returns child folder from remote version of a folder.
1336
+ * @param path of folder
1337
+ * @param remoteItemName
1338
+ * @param remoteVersion of folder. Default is current remote.
1339
+ */
1334
1340
  getRemoteFolderItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ReadonlyFS>;
1335
1341
 
1342
+ // XXX method to work around demaged files
1343
+ // reloadFromServer(path: string): Promise<SyncStatus>;
1344
+
1336
1345
  }
1337
1346
 
1338
1347
  /**
@@ -1346,8 +1355,12 @@ declare namespace web3n.files {
1346
1355
  inCurrent?: ListingEntry[];
1347
1356
  inRemote?: ListingEntry[];
1348
1357
 
1349
- // XXX
1350
- // differentNames?: ;
1358
+ // XXX add indication for items that have different name
1359
+ differentNames?: {
1360
+ localName: string;
1361
+ remoteName: string;
1362
+ }[];
1363
+ differentKeys?: string[];
1351
1364
 
1352
1365
  nameOverlaps?: string[];
1353
1366
  ctime: {
@@ -1391,7 +1404,8 @@ declare namespace web3n.files {
1391
1404
 
1392
1405
  /**
1393
1406
  * This method is for resolving conflicts on folders.
1394
- * It adopts some folder items, and not the whole folder state.
1407
+ * It adopts given folder item, that is present in remote version and is missing in local version.
1408
+ * Returns new local version.
1395
1409
  * @param path
1396
1410
  * @param remoteItemName
1397
1411
  * @param opts
@@ -1400,6 +1414,15 @@ declare namespace web3n.files {
1400
1414
  path: string, remoteItemName: string, opts?: OptionsToAdoptRemoteItem
1401
1415
  ): Promise<number>;
1402
1416
 
1417
+ /**
1418
+ * This method is for resolving conflicts on folders.
1419
+ * It adopts all folder items, that are present in remote version and are missing in local version.
1420
+ * Returns new local version, if there were remote items to adopt and their were added to local state.
1421
+ * @param path
1422
+ * @param opts
1423
+ */
1424
+ adoptAllRemoteItems(path: string, opts?: OptionsToAdoptAllRemoteItems): Promise<number|undefined>;
1425
+
1403
1426
  }
1404
1427
 
1405
1428
  interface OptionsToAdoptRemoteItem {
@@ -1422,6 +1445,22 @@ declare namespace web3n.files {
1422
1445
  newItemName?: string;
1423
1446
  }
1424
1447
 
1448
+ interface OptionsToAdoptAllRemoteItems {
1449
+ /**
1450
+ * Folder's local version. If not given, current local version is used.
1451
+ */
1452
+ localVersion?: number;
1453
+ /**
1454
+ * Folder's remote version. If not given, current remote version is used.
1455
+ */
1456
+ remoteVersion?: number;
1457
+ /**
1458
+ * Postfix to add to remote item names that have overlapping names with existing local items.
1459
+ * If there are name overlaps and postfix isn't given, then exception is thrown.
1460
+ */
1461
+ postfixForNameOverlaps?: string;
1462
+ }
1463
+
1425
1464
  interface FSEvent {
1426
1465
  path: string;
1427
1466
  }
@@ -4,7 +4,6 @@ import { Caller, CoreSideServices } from "../ipc-via-protobuf/connector";
4
4
  import { FileMsg } from "./file";
5
5
  type FS = web3n.files.FS;
6
6
  type FSItem = web3n.files.FSItem;
7
- type OptionsToAdoptRemoteItem = web3n.files.OptionsToAdoptRemoteItem;
8
7
  export declare function makeFSCaller(caller: Caller, fsMsg: FSMsg): FS;
9
8
  export declare function exposeFSService(fs: FS, expServices: CoreSideServices): FSMsg;
10
9
  export interface FSMsg {
@@ -38,12 +37,4 @@ export declare namespace fsItem {
38
37
  function exposeFSItem(expServices: CoreSideServices, item: FSItem): FSItemMsg;
39
38
  function fsItemFromMsg(caller: Caller, msg: FSItemMsg): FSItem;
40
39
  }
41
- interface OptionsToAdoptRemoteItemMsg {
42
- localVersion?: Value<number>;
43
- remoteVersion?: Value<number>;
44
- replaceLocalItem?: Value<boolean>;
45
- newItemName?: Value<string>;
46
- }
47
- export declare function optionsToAdoptRemoteItemToMsg(opts: OptionsToAdoptRemoteItem | undefined): OptionsToAdoptRemoteItemMsg | undefined;
48
- export declare function optionsToAdoptRemoteItemFromMsg(msg: OptionsToAdoptRemoteItemMsg | undefined): OptionsToAdoptRemoteItem | undefined;
49
40
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2020, 2022, 2025 - 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -19,8 +19,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.fsItem = exports.fsMsgType = void 0;
20
20
  exports.makeFSCaller = makeFSCaller;
21
21
  exports.exposeFSService = exposeFSService;
22
- exports.optionsToAdoptRemoteItemToMsg = optionsToAdoptRemoteItemToMsg;
23
- exports.optionsToAdoptRemoteItemFromMsg = optionsToAdoptRemoteItemFromMsg;
24
22
  const protobuf_msg_1 = require("../ipc-via-protobuf/protobuf-msg");
25
23
  const protobuf_type_1 = require("../lib-client/protobuf-type");
26
24
  const fs_proto_1 = require("../protos/fs.proto");
@@ -117,6 +115,7 @@ function makeFSCaller(caller, fsMsg) {
117
115
  fs.v.sync.startUpload = vsStartUpload.makeCaller(caller, vsPath);
118
116
  fs.v.sync.upload = vsUpload.makeCaller(caller, vsPath);
119
117
  fs.v.sync.adoptRemoteFolderItem = vsAdoptRemoteFolderItem.makeCaller(caller, vsPath);
118
+ fs.v.sync.adoptAllRemoteItems = vsAdoptAllRemoteItems.makeCaller(caller, vsPath);
120
119
  }
121
120
  }
122
121
  }
@@ -200,6 +199,7 @@ function exposeFSService(fs, expServices) {
200
199
  implExp.v.sync.startUpload = vsStartUpload.wrapService(fs.v.sync.startUpload);
201
200
  implExp.v.sync.upload = vsUpload.wrapService(fs.v.sync.upload);
202
201
  implExp.v.sync.adoptRemoteFolderItem = vsAdoptRemoteFolderItem.wrapService(fs.v.sync.adoptRemoteFolderItem);
202
+ implExp.v.sync.adoptAllRemoteFolderItems = vsAdoptAllRemoteItems.wrapService(fs.v.sync.adoptAllRemoteItems);
203
203
  }
204
204
  }
205
205
  }
@@ -1930,35 +1930,35 @@ var vsUpload;
1930
1930
  vsUpload.makeCaller = makeCaller;
1931
1931
  })(vsUpload || (vsUpload = {}));
1932
1932
  Object.freeze(vsUpload);
1933
- function optionsToAdoptRemoteItemToMsg(opts) {
1934
- if (!opts) {
1935
- return;
1936
- }
1937
- return {
1938
- localVersion: (0, protobuf_msg_1.toOptVal)(opts.localVersion),
1939
- remoteVersion: (0, protobuf_msg_1.toOptVal)(opts.remoteVersion),
1940
- replaceLocalItem: (0, protobuf_msg_1.toOptVal)(opts.replaceLocalItem),
1941
- newItemName: (0, protobuf_msg_1.toOptVal)(opts.newItemName)
1942
- };
1943
- }
1944
- function optionsToAdoptRemoteItemFromMsg(msg) {
1945
- if (!msg) {
1946
- return;
1947
- }
1948
- return {
1949
- localVersion: (0, protobuf_msg_1.valOfOptInt)(msg.localVersion),
1950
- remoteVersion: (0, protobuf_msg_1.valOfOptInt)(msg.remoteVersion),
1951
- replaceLocalItem: (0, protobuf_msg_1.valOfOpt)(msg.replaceLocalItem),
1952
- newItemName: (0, protobuf_msg_1.valOfOpt)(msg.newItemName)
1953
- };
1954
- }
1955
1933
  var vsAdoptRemoteFolderItem;
1956
1934
  (function (vsAdoptRemoteFolderItem) {
1957
1935
  const requestType = protobuf_type_1.ProtoType.for(fs_proto_1.fs.AdoptRemoteFolderItemRequestBody);
1936
+ function optionsFromMsg(msg) {
1937
+ if (!msg) {
1938
+ return;
1939
+ }
1940
+ return {
1941
+ localVersion: (0, protobuf_msg_1.valOfOptInt)(msg.localVersion),
1942
+ remoteVersion: (0, protobuf_msg_1.valOfOptInt)(msg.remoteVersion),
1943
+ replaceLocalItem: (0, protobuf_msg_1.valOfOpt)(msg.replaceLocalItem),
1944
+ newItemName: (0, protobuf_msg_1.valOfOpt)(msg.newItemName)
1945
+ };
1946
+ }
1947
+ function optionsToMsg(opts) {
1948
+ if (!opts) {
1949
+ return;
1950
+ }
1951
+ return {
1952
+ localVersion: (0, protobuf_msg_1.toOptVal)(opts.localVersion),
1953
+ remoteVersion: (0, protobuf_msg_1.toOptVal)(opts.remoteVersion),
1954
+ replaceLocalItem: (0, protobuf_msg_1.toOptVal)(opts.replaceLocalItem),
1955
+ newItemName: (0, protobuf_msg_1.toOptVal)(opts.newItemName)
1956
+ };
1957
+ }
1958
1958
  function wrapService(fn) {
1959
1959
  return buf => {
1960
1960
  const { path, itemName, opts } = requestType.unpack(buf);
1961
- const promise = fn(path, itemName, optionsToAdoptRemoteItemFromMsg(opts))
1961
+ const promise = fn(path, itemName, optionsFromMsg(opts))
1962
1962
  .then(protobuf_msg_1.packInt);
1963
1963
  return { promise };
1964
1964
  };
@@ -1968,13 +1968,55 @@ var vsAdoptRemoteFolderItem;
1968
1968
  const ipcPath = (0, protobuf_msg_1.methodPathFor)(objPath, 'adoptRemoteFolderItem');
1969
1969
  return (path, itemName, opts) => caller
1970
1970
  .startPromiseCall(ipcPath, requestType.pack({
1971
- path, itemName, opts: optionsToAdoptRemoteItemToMsg(opts)
1971
+ path, itemName, opts: optionsToMsg(opts)
1972
1972
  }))
1973
1973
  .then(protobuf_msg_1.unpackInt);
1974
1974
  }
1975
1975
  vsAdoptRemoteFolderItem.makeCaller = makeCaller;
1976
1976
  })(vsAdoptRemoteFolderItem || (vsAdoptRemoteFolderItem = {}));
1977
1977
  Object.freeze(vsAdoptRemoteFolderItem);
1978
+ var vsAdoptAllRemoteItems;
1979
+ (function (vsAdoptAllRemoteItems) {
1980
+ const requestType = protobuf_type_1.ProtoType.for(fs_proto_1.fs.AdoptAllRemoteFolderItemsRequestBody);
1981
+ function optionsFromMsg(msg) {
1982
+ if (!msg) {
1983
+ return;
1984
+ }
1985
+ return {
1986
+ localVersion: (0, protobuf_msg_1.valOfOptInt)(msg.localVersion),
1987
+ remoteVersion: (0, protobuf_msg_1.valOfOptInt)(msg.remoteVersion),
1988
+ postfixForNameOverlaps: (0, protobuf_msg_1.valOfOpt)(msg.postfixForNameOverlaps),
1989
+ };
1990
+ }
1991
+ function optionsToMsg(opts) {
1992
+ if (!opts) {
1993
+ return;
1994
+ }
1995
+ return {
1996
+ localVersion: (0, protobuf_msg_1.toOptVal)(opts.localVersion),
1997
+ remoteVersion: (0, protobuf_msg_1.toOptVal)(opts.remoteVersion),
1998
+ postfixForNameOverlaps: (0, protobuf_msg_1.toOptVal)(opts.postfixForNameOverlaps),
1999
+ };
2000
+ }
2001
+ const replyType = protobuf_type_1.ProtoType.for(fs_proto_1.fs.AdoptAllRemoteFolderItemsReplyBody);
2002
+ function wrapService(fn) {
2003
+ return buf => {
2004
+ const { path, opts } = requestType.unpack(buf);
2005
+ const promise = fn(path, optionsFromMsg(opts))
2006
+ .then(newVersion => replyType.pack({ newVersion: (0, protobuf_msg_1.toOptVal)(newVersion) }));
2007
+ return { promise };
2008
+ };
2009
+ }
2010
+ vsAdoptAllRemoteItems.wrapService = wrapService;
2011
+ function makeCaller(caller, objPath) {
2012
+ const ipcPath = (0, protobuf_msg_1.methodPathFor)(objPath, 'adoptAllRemoteItems');
2013
+ return (path, opts) => caller
2014
+ .startPromiseCall(ipcPath, requestType.pack({ path, opts: optionsToMsg(opts) }))
2015
+ .then(buf => (0, protobuf_msg_1.valOfOpt)(replyType.unpack(buf).newVersion));
2016
+ }
2017
+ vsAdoptAllRemoteItems.makeCaller = makeCaller;
2018
+ })(vsAdoptAllRemoteItems || (vsAdoptAllRemoteItems = {}));
2019
+ Object.freeze(vsAdoptAllRemoteItems);
1978
2020
  var vsAdoptRemote;
1979
2021
  (function (vsAdoptRemote) {
1980
2022
  const requestType = protobuf_type_1.ProtoType.for(fs_proto_1.fs.AdoptRemoteRequestBody);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2016 - 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2016 - 2022, 2025 - 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -241,6 +241,7 @@ function wrapWritableFSSyncAPI(sImpl) {
241
241
  startUpload: sImpl.startUpload.bind(sImpl),
242
242
  upload: sImpl.upload.bind(sImpl),
243
243
  adoptRemoteFolderItem: sImpl.adoptRemoteFolderItem.bind(sImpl),
244
+ adoptAllRemoteItems: sImpl.adoptAllRemoteItems.bind(sImpl),
244
245
  statRemoteItem: sImpl.statRemoteItem.bind(sImpl),
245
246
  listRemoteFolderItem: sImpl.listRemoteFolderItem.bind(sImpl),
246
247
  getRemoteFileItem: sImpl.getRemoteFileItem.bind(sImpl),
@@ -11,6 +11,7 @@ type XAttrsChanges = web3n.files.XAttrsChanges;
11
11
  type FolderDiff = web3n.files.FolderDiff;
12
12
  type OptionsToAdopteRemote = web3n.files.OptionsToAdopteRemote;
13
13
  type OptionsToAdoptRemoteItem = web3n.files.OptionsToAdoptRemoteItem;
14
+ type OptionsToAdoptAllRemoteItems = web3n.files.OptionsToAdoptAllRemoteItems;
14
15
  type OptionsToUploadLocal = web3n.files.OptionsToUploadLocal;
15
16
  type VersionedReadFlags = web3n.files.VersionedReadFlags;
16
17
  type Stats = web3n.files.Stats;
@@ -96,6 +97,16 @@ export declare class FolderNode extends NodeInFS<FolderPersistance> {
96
97
  getFile(name: string, undefOnMissing?: boolean): Promise<FileNode | undefined>;
97
98
  getLink(name: string, undefOnMissing?: boolean): Promise<LinkNode | undefined>;
98
99
  private fixMissingChildAndThrow;
100
+ adoptItemsFromRemoteVersion(opts: OptionsToAdoptAllRemoteItems | undefined): Promise<number | undefined>;
101
+ /**
102
+ * If no initial local version given, then this performs like doTransition(change) method.
103
+ * When initial local version is given and check, exceptions are thrown if versions mismatch,
104
+ * or when there is another concurrent process that is already transitioning folder state to new state.
105
+ * This returns value of new local version.
106
+ * @param initLocalVersion
107
+ * @param change
108
+ */
109
+ private doChangeWhileTrackingVersion;
99
110
  /**
100
111
  * This method prepares a transition state, runs given action, and completes
101
112
  * transition to a new version.
@@ -161,6 +172,7 @@ export declare class FolderNode extends NodeInFS<FolderPersistance> {
161
172
  private getRemoteChildNodeInfo;
162
173
  private addRemoteChild;
163
174
  private replaceLocalChildWithRemote;
175
+ private readRemoteVersion;
164
176
  diffCurrentAndRemote(remoteVersion: number | undefined): Promise<FolderDiff | undefined>;
165
177
  private diffWithArchivedRemote;
166
178
  private diffWithRemote;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2015 - 2020, 2022, 2025 - 2026 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -337,6 +337,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
337
337
  else if (exc.failedCipherVerification) {
338
338
  exc = (0, file_1.makeFileException)('ioError', `${this.name}/${info.name}`, exc);
339
339
  }
340
+ // XXX why and what ?
340
341
  deferred.reject((0, error_1.errWithCause)(exc, `Failed to instantiate fs node '${this.name}/${info.name}'`));
341
342
  return nodeSet;
342
343
  }
@@ -370,6 +371,75 @@ class FolderNode extends node_in_fs_1.NodeInFS {
370
371
  fileExc.inconsistentStateOfFS = true;
371
372
  throw fileExc;
372
373
  }
374
+ async adoptItemsFromRemoteVersion(opts) {
375
+ const { state, remote } = await this.syncStatus();
376
+ if ((state !== 'conflicting') && (state !== 'behind')) {
377
+ return;
378
+ }
379
+ const remoteVersion = versionFromRemoteBranch(remote, opts === null || opts === void 0 ? void 0 : opts.remoteVersion);
380
+ if (!remoteVersion) {
381
+ throw 'something';
382
+ }
383
+ const { folderInfo: remoteState } = await this.readRemoteVersion(remoteVersion);
384
+ return await this.doChangeWhileTrackingVersion(opts === null || opts === void 0 ? void 0 : opts.localVersion, async (state) => {
385
+ const { inRemote, nameOverlaps, differentKeys } = diffNodes(state, remoteState);
386
+ if (differentKeys) {
387
+ throw 'something';
388
+ }
389
+ if (!inRemote) {
390
+ return [];
391
+ }
392
+ const addedNodes = new Set();
393
+ if (nameOverlaps) {
394
+ const postfix = opts === null || opts === void 0 ? void 0 : opts.postfixForNameOverlaps;
395
+ if ((postfix === undefined) || (postfix.length < 0)) {
396
+ throw 'something';
397
+ }
398
+ for (const itemName of nameOverlaps) {
399
+ const node = remoteState.nodes[itemName];
400
+ let newName = `${itemName}${postfix}`;
401
+ while (state.nodes[newName]) {
402
+ newName = `${newName}${postfix}`;
403
+ }
404
+ node.name = newName;
405
+ state[newName] = node;
406
+ addedNodes.add(itemName);
407
+ }
408
+ }
409
+ for (const { name: itemName } of inRemote) {
410
+ if (addedNodes.has(itemName)) {
411
+ continue;
412
+ }
413
+ const node = remoteState.nodes[itemName];
414
+ state[itemName] = node;
415
+ }
416
+ return [];
417
+ });
418
+ }
419
+ /**
420
+ * If no initial local version given, then this performs like doTransition(change) method.
421
+ * When initial local version is given and check, exceptions are thrown if versions mismatch,
422
+ * or when there is another concurrent process that is already transitioning folder state to new state.
423
+ * This returns value of new local version.
424
+ * @param initLocalVersion
425
+ * @param change
426
+ */
427
+ async doChangeWhileTrackingVersion(initLocalVersion, change) {
428
+ if (initLocalVersion) {
429
+ if (this.version === initLocalVersion) {
430
+ return await this.doChange(false, () => this.performTransition(change));
431
+ }
432
+ else {
433
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
434
+ versionMismatch: true,
435
+ message: `Given local version ${initLocalVersion} is not equal to current ${this.version}`
436
+ });
437
+ }
438
+ }
439
+ else {
440
+ return await this.doChange(true, () => this.performTransition(change));
441
+ }
442
+ }
373
443
  /**
374
444
  * This method prepares a transition state, runs given action, and completes
375
445
  * transition to a new version.
@@ -406,6 +476,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
406
476
  const { event, childObjId } = changeEvents;
407
477
  this.broadcastEvent(event, false, childObjId);
408
478
  }
479
+ return version;
409
480
  }
410
481
  /**
411
482
  * This function only creates folder node, but it doesn't insert it anywhere.
@@ -894,14 +965,6 @@ class FolderNode extends node_in_fs_1.NodeInFS {
894
965
  return removedNodes;
895
966
  }
896
967
  async adoptRemoteFolderItem(remoteItemName, opts) {
897
- if (opts === null || opts === void 0 ? void 0 : opts.localVersion) {
898
- if (this.version !== opts.localVersion) {
899
- throw (0, exceptions_1.makeFSSyncException)(this.name, {
900
- versionMismatch: true,
901
- message: `Given local version ${opts.localVersion} is not equal to current ${this.version}`
902
- });
903
- }
904
- }
905
968
  const remoteChildNode = await this.getRemoteChildNodeInfo(remoteItemName, opts === null || opts === void 0 ? void 0 : opts.remoteVersion);
906
969
  let dstItemName = remoteItemName;
907
970
  if (typeof (opts === null || opts === void 0 ? void 0 : opts.newItemName) === 'string') {
@@ -912,15 +975,14 @@ class FolderNode extends node_in_fs_1.NodeInFS {
912
975
  }
913
976
  const localNodeWithSameName = this.getCurrentNodeInfo(dstItemName, true);
914
977
  if (!localNodeWithSameName) {
915
- return await this.addRemoteChild(remoteChildNode, dstItemName);
978
+ return await this.addRemoteChild(remoteChildNode, dstItemName, opts === null || opts === void 0 ? void 0 : opts.localVersion);
916
979
  }
917
980
  else if (localNodeWithSameName.objId === remoteChildNode.objId) {
918
- (0, assert_1.assert)(typeOfNode(localNodeWithSameName) === typeOfNode(remoteChildNode));
919
981
  // XXX
920
982
  throw new Error(`Adaptation of changing keys needs implementation`);
921
983
  }
922
984
  else if (opts === null || opts === void 0 ? void 0 : opts.replaceLocalItem) {
923
- return await this.replaceLocalChildWithRemote(remoteChildNode);
985
+ return await this.replaceLocalChildWithRemote(remoteChildNode, opts === null || opts === void 0 ? void 0 : opts.localVersion);
924
986
  }
925
987
  else {
926
988
  throw (0, exceptions_1.makeFSSyncException)(this.name, {
@@ -964,10 +1026,8 @@ class FolderNode extends node_in_fs_1.NodeInFS {
964
1026
  });
965
1027
  }
966
1028
  }
967
- async addRemoteChild(remoteChildNode, childName) {
968
- let newVersion;
969
- await this.doTransition(async (state, version) => {
970
- newVersion = version;
1029
+ addRemoteChild(remoteChildNode, childName, initLocalVersion) {
1030
+ return this.doChangeWhileTrackingVersion(initLocalVersion, async (state, newVersion) => {
971
1031
  remoteChildNode.name = childName;
972
1032
  state.nodes[remoteChildNode.name] = remoteChildNode;
973
1033
  const event = {
@@ -979,13 +1039,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
979
1039
  };
980
1040
  return { event, childObjId: remoteChildNode.objId };
981
1041
  });
982
- return newVersion;
983
1042
  }
984
- async replaceLocalChildWithRemote(remoteChildNode) {
1043
+ async replaceLocalChildWithRemote(remoteChildNode, initLocalVersion) {
985
1044
  let origChildNode;
986
- let newVersion;
987
- await this.doTransition(async (state, version) => {
988
- newVersion = version;
1045
+ const newVersion = await this.doChangeWhileTrackingVersion(initLocalVersion, async (state, newVersion) => {
989
1046
  origChildNode = state.nodes[remoteChildNode.name];
990
1047
  state.nodes[remoteChildNode.name] = remoteChildNode;
991
1048
  const additionEvent = {
@@ -1011,8 +1068,12 @@ class FolderNode extends node_in_fs_1.NodeInFS {
1011
1068
  this.uploadRemovalOfObjs(removalsToUpload);
1012
1069
  return newVersion;
1013
1070
  }
1071
+ async readRemoteVersion(remoteVersion) {
1072
+ const storage = this.syncedStorage();
1073
+ const srcOfRemote = await storage.getObjSrcOfRemoteVersion(this.objId, remoteVersion);
1074
+ return await this.crypto.read(srcOfRemote);
1075
+ }
1014
1076
  async diffCurrentAndRemote(remoteVersion) {
1015
- var _a;
1016
1077
  const { state, remote } = await this.syncStatus();
1017
1078
  let isCurrentLocal;
1018
1079
  if (state === 'behind') {
@@ -1024,26 +1085,13 @@ class FolderNode extends node_in_fs_1.NodeInFS {
1024
1085
  else {
1025
1086
  return;
1026
1087
  }
1027
- if (remote.isArchived) {
1028
- return this.diffWithArchivedRemote(isCurrentLocal);
1088
+ remoteVersion = versionFromRemoteBranch(remote, remoteVersion);
1089
+ if (remoteVersion) {
1090
+ const { folderInfo, attrs, xattrs } = await this.readRemoteVersion(remoteVersion);
1091
+ return this.diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs);
1029
1092
  }
1030
1093
  else {
1031
- if (remoteVersion) {
1032
- if ((remoteVersion !== remote.latest)
1033
- && !((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(remoteVersion))) {
1034
- throw (0, exceptions_1.makeFSSyncException)(this.name, {
1035
- versionMismatch: true,
1036
- message: `Unknown remote version ${remoteVersion}`
1037
- });
1038
- }
1039
- }
1040
- else {
1041
- remoteVersion = remote.latest;
1042
- }
1043
- const storage = this.syncedStorage();
1044
- const srcOfRemote = await storage.getObjSrcOfRemoteVersion(this.objId, remote.latest);
1045
- const { folderInfo, attrs, xattrs } = await this.crypto.read(srcOfRemote);
1046
- return this.diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs);
1094
+ return this.diffWithArchivedRemote(isCurrentLocal);
1047
1095
  }
1048
1096
  }
1049
1097
  diffWithArchivedRemote(isCurrentLocal) {
@@ -1118,20 +1166,6 @@ function nodeToListingEntry({ name, type }) {
1118
1166
  return { name };
1119
1167
  }
1120
1168
  }
1121
- function typeOfNode(nodeInfo) {
1122
- if (nodeInfo.isFolder) {
1123
- return 'folder';
1124
- }
1125
- else if (nodeInfo.isFile) {
1126
- return 'file';
1127
- }
1128
- else if (nodeInfo.isLink) {
1129
- return 'link';
1130
- }
1131
- else {
1132
- throw new Error(`Unknown type of node info`);
1133
- }
1134
- }
1135
1169
  function addToTransitionState(state, f, key) {
1136
1170
  const nodeInfo = {
1137
1171
  name: f.name,
@@ -1165,42 +1199,46 @@ function diffAttrs(current, remote) {
1165
1199
  };
1166
1200
  }
1167
1201
  function diffNodes(current, remote) {
1168
- const inCurrent = getOnlyNotEqualNodes(current.nodes, remote.nodes);
1169
- const inRemote = getOnlyNotEqualNodes(remote.nodes, current.nodes);
1170
- const combined = combineCheckingNameOverlaps(inCurrent, inRemote);
1171
- return (combined ? combined : {});
1172
- }
1173
- function getOnlyNotEqualNodes(src, exclude) {
1174
- const collected = [];
1175
- for (const [name, nodeInSrc] of Object.entries(src)) {
1176
- const nodeInExclude = exclude[name];
1177
- if (!nodeInExclude
1178
- || !areNodesEqual(nodeInSrc, nodeInExclude)) {
1179
- collected.push(nodeInfoToListingEntry(nodeInSrc));
1202
+ const inRemote = [];
1203
+ const nodesInCurrentById = new Map();
1204
+ for (const node of Object.values(current.nodes)) {
1205
+ nodesInCurrentById.set(node.objId, node);
1206
+ }
1207
+ const nameOverlaps = [];
1208
+ const differentNames = [];
1209
+ const differentKeys = [];
1210
+ for (const remoteNode of Object.values(remote.nodes)) {
1211
+ const localNode = nodesInCurrentById.get(remoteNode.objId);
1212
+ if (localNode) {
1213
+ if (localNode.name !== remoteNode.name) {
1214
+ differentNames.push({
1215
+ localName: localNode.name,
1216
+ remoteName: remoteNode.name
1217
+ });
1218
+ }
1219
+ if (!areBytesEqual(localNode.key, remoteNode.key)) {
1220
+ differentKeys.push(localNode.name);
1221
+ }
1222
+ nodesInCurrentById.delete(remoteNode.objId);
1223
+ }
1224
+ else {
1225
+ inRemote.push(nodeInfoToListingEntry(remoteNode));
1226
+ if (current.nodes[remoteNode.name]) {
1227
+ nameOverlaps.push(remoteNode.name);
1228
+ }
1180
1229
  }
1181
1230
  }
1182
- return ((collected.length > 0) ? collected : undefined);
1183
- }
1184
- function areNodesEqual(n1, n2) {
1185
- if (n1.name !== n2.name) {
1186
- return false;
1187
- }
1188
- if (n1.isFile && !n2.isFile) {
1189
- return false;
1190
- }
1191
- if (n1.isFolder && !n2.isFolder) {
1192
- return false;
1193
- }
1194
- if (n1.isLink && !n2.isLink) {
1195
- return false;
1196
- }
1197
- if (n1.objId !== n2.objId) {
1198
- return false;
1199
- }
1200
- if (!areBytesEqual(n1.key, n2.key)) {
1201
- return false;
1231
+ const inCurrent = [];
1232
+ for (const localNode of nodesInCurrentById.values()) {
1233
+ inCurrent.push(nodeInfoToListingEntry(localNode));
1202
1234
  }
1203
- return true;
1235
+ return {
1236
+ inCurrent: ((inCurrent.length > 0) ? inCurrent : undefined),
1237
+ inRemote: ((inRemote.length > 0) ? inRemote : undefined),
1238
+ differentNames: ((differentNames.length > 0) ? differentNames : undefined),
1239
+ nameOverlaps: ((nameOverlaps.length > 0) ? nameOverlaps : undefined),
1240
+ differentKeys: ((differentKeys.length > 0) ? differentKeys : undefined)
1241
+ };
1204
1242
  }
1205
1243
  function combineCheckingNameOverlaps(inCurrent, inRemote) {
1206
1244
  if (inCurrent) {
@@ -1343,4 +1381,22 @@ function identifyChanges(originalNodes, newNodes) {
1343
1381
  }
1344
1382
  return { addedNodes, removedNodes, renamedNodes };
1345
1383
  }
1384
+ function versionFromRemoteBranch(remote, remoteVersion) {
1385
+ var _a;
1386
+ if (remote.isArchived) {
1387
+ return;
1388
+ }
1389
+ if (remoteVersion) {
1390
+ if ((remoteVersion !== remote.latest)
1391
+ && !((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(remoteVersion))) {
1392
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
1393
+ versionMismatch: true,
1394
+ message: `Unknown remote version ${remoteVersion}`
1395
+ });
1396
+ }
1397
+ }
1398
+ else {
1399
+ return remote.latest;
1400
+ }
1401
+ }
1346
1402
  Object.freeze(exports);
@@ -28,6 +28,7 @@ type SyncStatus = web3n.files.SyncStatus;
28
28
  type WritableFSVersionedAPI = web3n.files.WritableFSVersionedAPI;
29
29
  type OptionsToAdopteRemote = web3n.files.OptionsToAdopteRemote;
30
30
  type OptionsToAdoptRemoteItem = web3n.files.OptionsToAdoptRemoteItem;
31
+ type OptionsToAdoptAllRemoteItems = web3n.files.OptionsToAdoptAllRemoteItems;
31
32
  type OptionsToUploadLocal = web3n.files.OptionsToUploadLocal;
32
33
  type FolderDiff = web3n.files.FolderDiff;
33
34
  export declare class XspFS implements WritableFS {
@@ -182,5 +183,6 @@ declare class S implements WritableFSSyncAPI {
182
183
  listRemoteFolderItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ListingEntry[]>;
183
184
  getRemoteFileItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ReadonlyFile>;
184
185
  getRemoteFolderItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ReadonlyFS>;
186
+ adoptAllRemoteItems(path: string, opts?: OptionsToAdoptAllRemoteItems): Promise<number | undefined>;
185
187
  }
186
188
  export {};