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.
- package/build/api-defs/files.d.ts +43 -4
- package/build/core-ipc/fs.d.ts +0 -9
- package/build/core-ipc/fs.js +69 -27
- package/build/lib-client/fs-utils/files.js +2 -1
- package/build/lib-client/xsp-fs/folder-node.d.ts +12 -0
- package/build/lib-client/xsp-fs/folder-node.js +143 -87
- package/build/lib-client/xsp-fs/fs.d.ts +2 -0
- package/build/lib-client/xsp-fs/fs.js +9 -9
- 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 +32 -16
|
@@ -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
|
-
|
|
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
|
|
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
|
}
|
package/build/core-ipc/fs.d.ts
CHANGED
|
@@ -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 {};
|
package/build/core-ipc/fs.js
CHANGED
|
@@ -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,
|
|
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:
|
|
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
|
-
|
|
968
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1028
|
-
|
|
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
|
-
|
|
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
|
|
1169
|
-
const
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
const
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
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
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
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
|
|
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 {};
|