core-3nweb-client-lib 0.43.17 → 0.43.19

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,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.nodes[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.nodes[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) {
@@ -1061,7 +1109,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
1061
1109
  }
1062
1110
  diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs) {
1063
1111
  const { ctime, mtime } = diffAttrs(this.attrs, attrs);
1064
- const { inCurrent, inRemote, nameOverlaps } = diffNodes(this.currentState, folderInfo);
1112
+ const { inCurrent, inRemote, nameOverlaps, differentKeys, differentNames } = diffNodes(this.currentState, folderInfo);
1065
1113
  return {
1066
1114
  currentVersion: this.version,
1067
1115
  isCurrentLocal,
@@ -1070,6 +1118,8 @@ class FolderNode extends node_in_fs_1.NodeInFS {
1070
1118
  inCurrent,
1071
1119
  inRemote,
1072
1120
  nameOverlaps,
1121
+ differentKeys,
1122
+ differentNames,
1073
1123
  ctime,
1074
1124
  mtime,
1075
1125
  xattrs: diffXAttrs(this.xattrs, xattrs)
@@ -1118,20 +1168,6 @@ function nodeToListingEntry({ name, type }) {
1118
1168
  return { name };
1119
1169
  }
1120
1170
  }
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
1171
  function addToTransitionState(state, f, key) {
1136
1172
  const nodeInfo = {
1137
1173
  name: f.name,
@@ -1165,42 +1201,46 @@ function diffAttrs(current, remote) {
1165
1201
  };
1166
1202
  }
1167
1203
  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));
1204
+ const inRemote = [];
1205
+ const nodesInCurrentById = new Map();
1206
+ for (const node of Object.values(current.nodes)) {
1207
+ nodesInCurrentById.set(node.objId, node);
1208
+ }
1209
+ const nameOverlaps = [];
1210
+ const differentNames = [];
1211
+ const differentKeys = [];
1212
+ for (const remoteNode of Object.values(remote.nodes)) {
1213
+ const localNode = nodesInCurrentById.get(remoteNode.objId);
1214
+ if (localNode) {
1215
+ if (localNode.name !== remoteNode.name) {
1216
+ differentNames.push({
1217
+ localName: localNode.name,
1218
+ remoteName: remoteNode.name
1219
+ });
1220
+ }
1221
+ if (!areBytesEqual(localNode.key, remoteNode.key)) {
1222
+ differentKeys.push(localNode.name);
1223
+ }
1224
+ nodesInCurrentById.delete(remoteNode.objId);
1225
+ }
1226
+ else {
1227
+ inRemote.push(nodeInfoToListingEntry(remoteNode));
1228
+ if (current.nodes[remoteNode.name]) {
1229
+ nameOverlaps.push(remoteNode.name);
1230
+ }
1180
1231
  }
1181
1232
  }
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;
1233
+ const inCurrent = [];
1234
+ for (const localNode of nodesInCurrentById.values()) {
1235
+ inCurrent.push(nodeInfoToListingEntry(localNode));
1202
1236
  }
1203
- return true;
1237
+ return {
1238
+ inCurrent: ((inCurrent.length > 0) ? inCurrent : undefined),
1239
+ inRemote: ((inRemote.length > 0) ? inRemote : undefined),
1240
+ differentNames: ((differentNames.length > 0) ? differentNames : undefined),
1241
+ nameOverlaps: ((nameOverlaps.length > 0) ? nameOverlaps : undefined),
1242
+ differentKeys: ((differentKeys.length > 0) ? differentKeys : undefined)
1243
+ };
1204
1244
  }
1205
1245
  function combineCheckingNameOverlaps(inCurrent, inRemote) {
1206
1246
  if (inCurrent) {
@@ -1343,4 +1383,22 @@ function identifyChanges(originalNodes, newNodes) {
1343
1383
  }
1344
1384
  return { addedNodes, removedNodes, renamedNodes };
1345
1385
  }
1386
+ function versionFromRemoteBranch(remote, remoteVersion) {
1387
+ var _a;
1388
+ if (remote.isArchived) {
1389
+ return;
1390
+ }
1391
+ if (remoteVersion) {
1392
+ if ((remoteVersion !== remote.latest)
1393
+ && !((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(remoteVersion))) {
1394
+ throw (0, exceptions_1.makeFSSyncException)(this.name, {
1395
+ versionMismatch: true,
1396
+ message: `Unknown remote version ${remoteVersion}`
1397
+ });
1398
+ }
1399
+ }
1400
+ else {
1401
+ return remote.latest;
1402
+ }
1403
+ }
1346
1404
  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 {};
@@ -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
@@ -754,14 +754,12 @@ class S {
754
754
  }
755
755
  async updateStatusInfo(path) {
756
756
  const node = await this.n.get(path);
757
- const status = await node.updateStatusInfo();
758
- return status;
757
+ return await node.updateStatusInfo();
759
758
  }
760
759
  async isRemoteVersionOnDisk(path, version) {
761
760
  const node = await this.n.get(path);
762
761
  try {
763
- const isOnDisk = await node.isSyncedVersionOnDisk(version);
764
- return isOnDisk;
762
+ return await node.isSyncedVersionOnDisk(version);
765
763
  }
766
764
  catch (exc) {
767
765
  throw (0, common_1.setPathInExc)(exc, path);
@@ -795,8 +793,7 @@ class S {
795
793
  async diffCurrentAndRemoteFolderVersions(path, remoteVersion) {
796
794
  const node = await this.getFolderNode(path);
797
795
  try {
798
- const diff = await node.diffCurrentAndRemote(remoteVersion);
799
- return diff;
796
+ return await node.diffCurrentAndRemote(remoteVersion);
800
797
  }
801
798
  catch (exc) {
802
799
  throw (0, common_1.setPathInExc)(exc, path);
@@ -805,8 +802,7 @@ class S {
805
802
  async adoptRemoteFolderItem(path, itemName, opts) {
806
803
  const node = await this.getFolderNode(path);
807
804
  try {
808
- const newVersion = await node.adoptRemoteFolderItem(itemName, opts);
809
- return newVersion;
805
+ return await node.adoptRemoteFolderItem(itemName, opts);
810
806
  }
811
807
  catch (exc) {
812
808
  throw (0, common_1.setPathInExc)(exc, path);
@@ -847,6 +843,10 @@ class S {
847
843
  throw (0, file_1.makeFileException)('notDirectory', `${path}/${remoteItemName}`);
848
844
  }
849
845
  }
846
+ async adoptAllRemoteItems(path, opts) {
847
+ const folderNode = await this.getFolderNode(path);
848
+ return await folderNode.adoptItemsFromRemoteVersion(opts);
849
+ }
850
850
  }
851
851
  Object.freeze(S.prototype);
852
852
  Object.freeze(S);