core-3nweb-client-lib 0.43.16 → 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.
- package/build/api-defs/files.d.ts +50 -2
- package/build/core/id-manager/index.js +1 -4
- package/build/core-ipc/fs.d.ts +0 -9
- package/build/core-ipc/fs.js +99 -27
- package/build/lib-client/fs-utils/files.js +4 -1
- package/build/lib-client/xsp-fs/folder-node.d.ts +13 -0
- package/build/lib-client/xsp-fs/folder-node.js +149 -87
- package/build/lib-client/xsp-fs/fs.d.ts +4 -0
- package/build/lib-client/xsp-fs/fs.js +25 -13
- package/build/protos/asmail.proto.js +711 -0
- package/build/protos/fs.proto.js +711 -0
- package/package.json +1 -1
- package/protos/fs.proto +36 -16
|
@@ -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
|
|
@@ -334,6 +334,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
334
334
|
if (exc.objNotFound && fromCurrentNodes) {
|
|
335
335
|
await this.fixMissingChildAndThrow(exc, info);
|
|
336
336
|
}
|
|
337
|
+
else if (exc.failedCipherVerification) {
|
|
338
|
+
exc = (0, file_1.makeFileException)('ioError', `${this.name}/${info.name}`, exc);
|
|
339
|
+
}
|
|
340
|
+
// XXX why and what ?
|
|
337
341
|
deferred.reject((0, error_1.errWithCause)(exc, `Failed to instantiate fs node '${this.name}/${info.name}'`));
|
|
338
342
|
return nodeSet;
|
|
339
343
|
}
|
|
@@ -367,6 +371,75 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
367
371
|
fileExc.inconsistentStateOfFS = true;
|
|
368
372
|
throw fileExc;
|
|
369
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
|
+
}
|
|
370
443
|
/**
|
|
371
444
|
* This method prepares a transition state, runs given action, and completes
|
|
372
445
|
* transition to a new version.
|
|
@@ -403,6 +476,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
403
476
|
const { event, childObjId } = changeEvents;
|
|
404
477
|
this.broadcastEvent(event, false, childObjId);
|
|
405
478
|
}
|
|
479
|
+
return version;
|
|
406
480
|
}
|
|
407
481
|
/**
|
|
408
482
|
* This function only creates folder node, but it doesn't insert it anywhere.
|
|
@@ -891,14 +965,6 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
891
965
|
return removedNodes;
|
|
892
966
|
}
|
|
893
967
|
async adoptRemoteFolderItem(remoteItemName, opts) {
|
|
894
|
-
if (opts === null || opts === void 0 ? void 0 : opts.localVersion) {
|
|
895
|
-
if (this.version !== opts.localVersion) {
|
|
896
|
-
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
897
|
-
versionMismatch: true,
|
|
898
|
-
message: `Given local version ${opts.localVersion} is not equal to current ${this.version}`
|
|
899
|
-
});
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
968
|
const remoteChildNode = await this.getRemoteChildNodeInfo(remoteItemName, opts === null || opts === void 0 ? void 0 : opts.remoteVersion);
|
|
903
969
|
let dstItemName = remoteItemName;
|
|
904
970
|
if (typeof (opts === null || opts === void 0 ? void 0 : opts.newItemName) === 'string') {
|
|
@@ -909,15 +975,14 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
909
975
|
}
|
|
910
976
|
const localNodeWithSameName = this.getCurrentNodeInfo(dstItemName, true);
|
|
911
977
|
if (!localNodeWithSameName) {
|
|
912
|
-
return await this.addRemoteChild(remoteChildNode, dstItemName);
|
|
978
|
+
return await this.addRemoteChild(remoteChildNode, dstItemName, opts === null || opts === void 0 ? void 0 : opts.localVersion);
|
|
913
979
|
}
|
|
914
980
|
else if (localNodeWithSameName.objId === remoteChildNode.objId) {
|
|
915
|
-
(0, assert_1.assert)(typeOfNode(localNodeWithSameName) === typeOfNode(remoteChildNode));
|
|
916
981
|
// XXX
|
|
917
982
|
throw new Error(`Adaptation of changing keys needs implementation`);
|
|
918
983
|
}
|
|
919
984
|
else if (opts === null || opts === void 0 ? void 0 : opts.replaceLocalItem) {
|
|
920
|
-
return await this.replaceLocalChildWithRemote(remoteChildNode);
|
|
985
|
+
return await this.replaceLocalChildWithRemote(remoteChildNode, opts === null || opts === void 0 ? void 0 : opts.localVersion);
|
|
921
986
|
}
|
|
922
987
|
else {
|
|
923
988
|
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
@@ -961,10 +1026,8 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
961
1026
|
});
|
|
962
1027
|
}
|
|
963
1028
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
await this.doTransition(async (state, version) => {
|
|
967
|
-
newVersion = version;
|
|
1029
|
+
addRemoteChild(remoteChildNode, childName, initLocalVersion) {
|
|
1030
|
+
return this.doChangeWhileTrackingVersion(initLocalVersion, async (state, newVersion) => {
|
|
968
1031
|
remoteChildNode.name = childName;
|
|
969
1032
|
state.nodes[remoteChildNode.name] = remoteChildNode;
|
|
970
1033
|
const event = {
|
|
@@ -976,13 +1039,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
976
1039
|
};
|
|
977
1040
|
return { event, childObjId: remoteChildNode.objId };
|
|
978
1041
|
});
|
|
979
|
-
return newVersion;
|
|
980
1042
|
}
|
|
981
|
-
async replaceLocalChildWithRemote(remoteChildNode) {
|
|
1043
|
+
async replaceLocalChildWithRemote(remoteChildNode, initLocalVersion) {
|
|
982
1044
|
let origChildNode;
|
|
983
|
-
|
|
984
|
-
await this.doTransition(async (state, version) => {
|
|
985
|
-
newVersion = version;
|
|
1045
|
+
const newVersion = await this.doChangeWhileTrackingVersion(initLocalVersion, async (state, newVersion) => {
|
|
986
1046
|
origChildNode = state.nodes[remoteChildNode.name];
|
|
987
1047
|
state.nodes[remoteChildNode.name] = remoteChildNode;
|
|
988
1048
|
const additionEvent = {
|
|
@@ -1008,8 +1068,12 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1008
1068
|
this.uploadRemovalOfObjs(removalsToUpload);
|
|
1009
1069
|
return newVersion;
|
|
1010
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
|
+
}
|
|
1011
1076
|
async diffCurrentAndRemote(remoteVersion) {
|
|
1012
|
-
var _a;
|
|
1013
1077
|
const { state, remote } = await this.syncStatus();
|
|
1014
1078
|
let isCurrentLocal;
|
|
1015
1079
|
if (state === 'behind') {
|
|
@@ -1021,26 +1085,13 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1021
1085
|
else {
|
|
1022
1086
|
return;
|
|
1023
1087
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
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);
|
|
1026
1092
|
}
|
|
1027
1093
|
else {
|
|
1028
|
-
|
|
1029
|
-
if ((remoteVersion !== remote.latest)
|
|
1030
|
-
&& !((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(remoteVersion))) {
|
|
1031
|
-
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
1032
|
-
versionMismatch: true,
|
|
1033
|
-
message: `Unknown remote version ${remoteVersion}`
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
else {
|
|
1038
|
-
remoteVersion = remote.latest;
|
|
1039
|
-
}
|
|
1040
|
-
const storage = this.syncedStorage();
|
|
1041
|
-
const srcOfRemote = await storage.getObjSrcOfRemoteVersion(this.objId, remote.latest);
|
|
1042
|
-
const { folderInfo, attrs, xattrs } = await this.crypto.read(srcOfRemote);
|
|
1043
|
-
return this.diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs);
|
|
1094
|
+
return this.diffWithArchivedRemote(isCurrentLocal);
|
|
1044
1095
|
}
|
|
1045
1096
|
}
|
|
1046
1097
|
diffWithArchivedRemote(isCurrentLocal) {
|
|
@@ -1076,6 +1127,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1076
1127
|
const remoteChildNodeInfo = await this.getRemoteChildNodeInfo(remoteItemName, remoteVersion);
|
|
1077
1128
|
return await this.getOrMakeChildNodeForInfo(remoteChildNodeInfo, false);
|
|
1078
1129
|
}
|
|
1130
|
+
getStorage() {
|
|
1131
|
+
return this.storage;
|
|
1132
|
+
}
|
|
1079
1133
|
}
|
|
1080
1134
|
exports.FolderNode = FolderNode;
|
|
1081
1135
|
Object.freeze(FolderNode.prototype);
|
|
@@ -1112,20 +1166,6 @@ function nodeToListingEntry({ name, type }) {
|
|
|
1112
1166
|
return { name };
|
|
1113
1167
|
}
|
|
1114
1168
|
}
|
|
1115
|
-
function typeOfNode(nodeInfo) {
|
|
1116
|
-
if (nodeInfo.isFolder) {
|
|
1117
|
-
return 'folder';
|
|
1118
|
-
}
|
|
1119
|
-
else if (nodeInfo.isFile) {
|
|
1120
|
-
return 'file';
|
|
1121
|
-
}
|
|
1122
|
-
else if (nodeInfo.isLink) {
|
|
1123
|
-
return 'link';
|
|
1124
|
-
}
|
|
1125
|
-
else {
|
|
1126
|
-
throw new Error(`Unknown type of node info`);
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
1169
|
function addToTransitionState(state, f, key) {
|
|
1130
1170
|
const nodeInfo = {
|
|
1131
1171
|
name: f.name,
|
|
@@ -1159,42 +1199,46 @@ function diffAttrs(current, remote) {
|
|
|
1159
1199
|
};
|
|
1160
1200
|
}
|
|
1161
1201
|
function diffNodes(current, remote) {
|
|
1162
|
-
const
|
|
1163
|
-
const
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
const
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
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
|
+
}
|
|
1174
1229
|
}
|
|
1175
1230
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
if (n1.name !== n2.name) {
|
|
1180
|
-
return false;
|
|
1181
|
-
}
|
|
1182
|
-
if (n1.isFile && !n2.isFile) {
|
|
1183
|
-
return false;
|
|
1184
|
-
}
|
|
1185
|
-
if (n1.isFolder && !n2.isFolder) {
|
|
1186
|
-
return false;
|
|
1187
|
-
}
|
|
1188
|
-
if (n1.isLink && !n2.isLink) {
|
|
1189
|
-
return false;
|
|
1190
|
-
}
|
|
1191
|
-
if (n1.objId !== n2.objId) {
|
|
1192
|
-
return false;
|
|
1193
|
-
}
|
|
1194
|
-
if (!areBytesEqual(n1.key, n2.key)) {
|
|
1195
|
-
return false;
|
|
1231
|
+
const inCurrent = [];
|
|
1232
|
+
for (const localNode of nodesInCurrentById.values()) {
|
|
1233
|
+
inCurrent.push(nodeInfoToListingEntry(localNode));
|
|
1196
1234
|
}
|
|
1197
|
-
return
|
|
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
|
+
};
|
|
1198
1242
|
}
|
|
1199
1243
|
function combineCheckingNameOverlaps(inCurrent, inRemote) {
|
|
1200
1244
|
if (inCurrent) {
|
|
@@ -1337,4 +1381,22 @@ function identifyChanges(originalNodes, newNodes) {
|
|
|
1337
1381
|
}
|
|
1338
1382
|
return { addedNodes, removedNodes, renamedNodes };
|
|
1339
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
|
+
}
|
|
1340
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 {
|
|
@@ -56,6 +57,7 @@ export declare class XspFS implements WritableFS {
|
|
|
56
57
|
*/
|
|
57
58
|
static fromExistingRoot(storage: Storage, key: Uint8Array): Promise<WritableFS>;
|
|
58
59
|
static fromASMailMsgRootFromJSON(storage: Storage, folderJson: FolderInJSON, rootName?: string): ReadonlyFS;
|
|
60
|
+
static fromFolderNode(folderNode: FolderNode): ReadonlyFS;
|
|
59
61
|
/**
|
|
60
62
|
* Note that this method doesn't close storage.
|
|
61
63
|
*/
|
|
@@ -180,5 +182,7 @@ declare class S implements WritableFSSyncAPI {
|
|
|
180
182
|
statRemoteItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<Stats>;
|
|
181
183
|
listRemoteFolderItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ListingEntry[]>;
|
|
182
184
|
getRemoteFileItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ReadonlyFile>;
|
|
185
|
+
getRemoteFolderItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ReadonlyFS>;
|
|
186
|
+
adoptAllRemoteItems(path: string, opts?: OptionsToAdoptAllRemoteItems): Promise<number | undefined>;
|
|
183
187
|
}
|
|
184
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
|
|
@@ -77,8 +77,7 @@ class XspFS {
|
|
|
77
77
|
const pathParts = splitPathIntoParts(path);
|
|
78
78
|
const root = this.v.getRootIfNotClosed(path);
|
|
79
79
|
const folder = await root.getFolderInThisSubTree(pathParts, false).catch(setExcPath(path));
|
|
80
|
-
const folderName = ((pathParts.length === 0) ?
|
|
81
|
-
this.name : pathParts[pathParts.length - 1]);
|
|
80
|
+
const folderName = ((pathParts.length === 0) ? this.name : pathParts[pathParts.length - 1]);
|
|
82
81
|
const fs = new XspFS(this.storage(), false, folder, folderName);
|
|
83
82
|
return (0, files_1.wrapReadonlyFS)(fs);
|
|
84
83
|
}
|
|
@@ -86,8 +85,7 @@ class XspFS {
|
|
|
86
85
|
const pathParts = splitPathIntoParts(path);
|
|
87
86
|
const root = this.v.getRootIfNotClosed(path);
|
|
88
87
|
const folder = await root.getFolderInThisSubTree(pathParts, flags.create, flags.exclusive).catch(setExcPath(path));
|
|
89
|
-
const folderName = ((pathParts.length === 0) ?
|
|
90
|
-
this.name : pathParts[pathParts.length - 1]);
|
|
88
|
+
const folderName = ((pathParts.length === 0) ? this.name : pathParts[pathParts.length - 1]);
|
|
91
89
|
const fs = new XspFS(this.storage(), true, folder, folderName);
|
|
92
90
|
return (0, files_1.wrapWritableFS)(fs);
|
|
93
91
|
}
|
|
@@ -119,6 +117,10 @@ class XspFS {
|
|
|
119
117
|
const fs = new XspFS(storage, false, root, rootName);
|
|
120
118
|
return (0, files_1.wrapIntoVersionlessReadonlyFS)(fs);
|
|
121
119
|
}
|
|
120
|
+
static fromFolderNode(folderNode) {
|
|
121
|
+
const fs = new XspFS(folderNode.getStorage(), false, folderNode, folderNode.name);
|
|
122
|
+
return (0, files_1.wrapIntoVersionlessReadonlyFS)(fs);
|
|
123
|
+
}
|
|
122
124
|
/**
|
|
123
125
|
* Note that this method doesn't close storage.
|
|
124
126
|
*/
|
|
@@ -752,14 +754,12 @@ class S {
|
|
|
752
754
|
}
|
|
753
755
|
async updateStatusInfo(path) {
|
|
754
756
|
const node = await this.n.get(path);
|
|
755
|
-
|
|
756
|
-
return status;
|
|
757
|
+
return await node.updateStatusInfo();
|
|
757
758
|
}
|
|
758
759
|
async isRemoteVersionOnDisk(path, version) {
|
|
759
760
|
const node = await this.n.get(path);
|
|
760
761
|
try {
|
|
761
|
-
|
|
762
|
-
return isOnDisk;
|
|
762
|
+
return await node.isSyncedVersionOnDisk(version);
|
|
763
763
|
}
|
|
764
764
|
catch (exc) {
|
|
765
765
|
throw (0, common_1.setPathInExc)(exc, path);
|
|
@@ -793,8 +793,7 @@ class S {
|
|
|
793
793
|
async diffCurrentAndRemoteFolderVersions(path, remoteVersion) {
|
|
794
794
|
const node = await this.getFolderNode(path);
|
|
795
795
|
try {
|
|
796
|
-
|
|
797
|
-
return diff;
|
|
796
|
+
return await node.diffCurrentAndRemote(remoteVersion);
|
|
798
797
|
}
|
|
799
798
|
catch (exc) {
|
|
800
799
|
throw (0, common_1.setPathInExc)(exc, path);
|
|
@@ -803,8 +802,7 @@ class S {
|
|
|
803
802
|
async adoptRemoteFolderItem(path, itemName, opts) {
|
|
804
803
|
const node = await this.getFolderNode(path);
|
|
805
804
|
try {
|
|
806
|
-
|
|
807
|
-
return newVersion;
|
|
805
|
+
return await node.adoptRemoteFolderItem(itemName, opts);
|
|
808
806
|
}
|
|
809
807
|
catch (exc) {
|
|
810
808
|
throw (0, common_1.setPathInExc)(exc, path);
|
|
@@ -835,6 +833,20 @@ class S {
|
|
|
835
833
|
throw (0, file_1.makeFileException)('notFile', `${path}/${remoteItemName}`);
|
|
836
834
|
}
|
|
837
835
|
}
|
|
836
|
+
async getRemoteFolderItem(path, remoteItemName, remoteVersion) {
|
|
837
|
+
const folderNode = await this.getFolderNode(path);
|
|
838
|
+
const remoteChild = await folderNode.getRemoteItemNode(remoteItemName, remoteVersion);
|
|
839
|
+
if (remoteChild.type === 'folder') {
|
|
840
|
+
return XspFS.fromFolderNode(remoteChild);
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
throw (0, file_1.makeFileException)('notDirectory', `${path}/${remoteItemName}`);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
async adoptAllRemoteItems(path, opts) {
|
|
847
|
+
const folderNode = await this.getFolderNode(path);
|
|
848
|
+
return await folderNode.adoptItemsFromRemoteVersion(opts);
|
|
849
|
+
}
|
|
838
850
|
}
|
|
839
851
|
Object.freeze(S.prototype);
|
|
840
852
|
Object.freeze(S);
|