core-3nweb-client-lib 0.44.11 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/build/core/asmail/msg/opener.js +1 -1
  2. package/build/core/asmail/msg/packer.js +1 -1
  3. package/build/core/index.d.ts +2 -2
  4. package/build/core/keyring/correspondent-keys.js +1 -1
  5. package/build/core/keyring/index.js +1 -1
  6. package/build/core/startup/sign-in.d.ts +1 -1
  7. package/build/core/startup/sign-up.d.ts +1 -1
  8. package/build/core/storage/index.d.ts +1 -1
  9. package/build/lib-client/key-derivation.d.ts +1 -1
  10. package/build/lib-client/xsp-fs/attrs.d.ts +3 -2
  11. package/build/lib-client/xsp-fs/attrs.js +7 -6
  12. package/build/lib-client/xsp-fs/folder-node.js +1 -1
  13. package/build/lib-client/xsp-fs/node-in-fs.js +1 -0
  14. package/build/lib-client/xsp-fs/node-persistence.js +1 -1
  15. package/build/lib-client/xsp-fs/xsp-payload-v2.js +1 -1
  16. package/build/tests/caps-api/asmail/specs/events.d.ts +2 -0
  17. package/build/tests/caps-api/asmail/specs/events.js +63 -0
  18. package/build/tests/caps-api/asmail/specs/send-to-wrong-address.d.ts +2 -0
  19. package/build/tests/caps-api/asmail/specs/send-to-wrong-address.js +68 -0
  20. package/build/tests/caps-api/asmail/specs/send-with-attacment-from-storage.d.ts +2 -0
  21. package/build/tests/caps-api/asmail/specs/send-with-attacment-from-storage.js +259 -0
  22. package/build/tests/caps-api/asmail/specs/send-without-attachments.d.ts +2 -0
  23. package/build/tests/caps-api/asmail/specs/send-without-attachments.js +90 -0
  24. package/build/tests/caps-api/asmail/test-utils.d.ts +12 -0
  25. package/build/tests/caps-api/asmail/test-utils.js +60 -0
  26. package/build/tests/caps-api/asmail.js +86 -0
  27. package/build/tests/caps-api/file-sink-checks/different-cases.d.ts +2 -0
  28. package/build/tests/caps-api/file-sink-checks/different-cases.js +47 -0
  29. package/build/tests/caps-api/file-sink-checks/splice.d.ts +2 -0
  30. package/build/tests/caps-api/file-sink-checks/splice.js +122 -0
  31. package/build/tests/caps-api/file-sink-checks/truncate.d.ts +2 -0
  32. package/build/tests/caps-api/file-sink-checks/truncate.js +122 -0
  33. package/build/tests/caps-api/fs-checks/local-to-synced-linking/link.d.ts +2 -0
  34. package/build/tests/caps-api/fs-checks/local-to-synced-linking/link.js +82 -0
  35. package/build/tests/caps-api/fs-checks/local-to-synced-linking/reversed-linking.d.ts +2 -0
  36. package/build/tests/caps-api/fs-checks/local-to-synced-linking/reversed-linking.js +50 -0
  37. package/build/tests/caps-api/fs-checks/not-versioned/deleteFile.d.ts +2 -0
  38. package/build/tests/caps-api/fs-checks/not-versioned/deleteFile.js +73 -0
  39. package/build/tests/caps-api/fs-checks/not-versioned/deleteFolder.d.ts +2 -0
  40. package/build/tests/caps-api/fs-checks/not-versioned/deleteFolder.js +75 -0
  41. package/build/tests/caps-api/fs-checks/not-versioned/getByteSink.d.ts +2 -0
  42. package/build/tests/caps-api/fs-checks/not-versioned/getByteSink.js +96 -0
  43. package/build/tests/caps-api/fs-checks/not-versioned/getByteSource.d.ts +2 -0
  44. package/build/tests/caps-api/fs-checks/not-versioned/getByteSource.js +67 -0
  45. package/build/tests/caps-api/fs-checks/not-versioned/getXAttr.d.ts +2 -0
  46. package/build/tests/caps-api/fs-checks/not-versioned/getXAttr.js +77 -0
  47. package/build/tests/caps-api/fs-checks/not-versioned/link.d.ts +2 -0
  48. package/build/tests/caps-api/fs-checks/not-versioned/link.js +115 -0
  49. package/build/tests/caps-api/fs-checks/not-versioned/listFolder.d.ts +2 -0
  50. package/build/tests/caps-api/fs-checks/not-versioned/listFolder.js +129 -0
  51. package/build/tests/caps-api/fs-checks/not-versioned/listXAttrs.d.ts +2 -0
  52. package/build/tests/caps-api/fs-checks/not-versioned/listXAttrs.js +73 -0
  53. package/build/tests/caps-api/fs-checks/not-versioned/makeFolder.d.ts +2 -0
  54. package/build/tests/caps-api/fs-checks/not-versioned/makeFolder.js +95 -0
  55. package/build/tests/caps-api/fs-checks/not-versioned/move.d.ts +2 -0
  56. package/build/tests/caps-api/fs-checks/not-versioned/move.js +127 -0
  57. package/build/tests/caps-api/fs-checks/not-versioned/readBytes.d.ts +2 -0
  58. package/build/tests/caps-api/fs-checks/not-versioned/readBytes.js +80 -0
  59. package/build/tests/caps-api/fs-checks/not-versioned/readJSONFile.d.ts +2 -0
  60. package/build/tests/caps-api/fs-checks/not-versioned/readJSONFile.js +59 -0
  61. package/build/tests/caps-api/fs-checks/not-versioned/readLink.d.ts +2 -0
  62. package/build/tests/caps-api/fs-checks/not-versioned/readLink.js +39 -0
  63. package/build/tests/caps-api/fs-checks/not-versioned/readTxtFile.d.ts +2 -0
  64. package/build/tests/caps-api/fs-checks/not-versioned/readTxtFile.js +54 -0
  65. package/build/tests/caps-api/fs-checks/not-versioned/readonlyFile.d.ts +2 -0
  66. package/build/tests/caps-api/fs-checks/not-versioned/readonlyFile.js +55 -0
  67. package/build/tests/caps-api/fs-checks/not-versioned/readonlySubRoot.d.ts +2 -0
  68. package/build/tests/caps-api/fs-checks/not-versioned/readonlySubRoot.js +55 -0
  69. package/build/tests/caps-api/fs-checks/not-versioned/select.d.ts +2 -0
  70. package/build/tests/caps-api/fs-checks/not-versioned/select.js +119 -0
  71. package/build/tests/caps-api/fs-checks/not-versioned/stat.d.ts +2 -0
  72. package/build/tests/caps-api/fs-checks/not-versioned/stat.js +96 -0
  73. package/build/tests/caps-api/fs-checks/not-versioned/updateXAttrs.d.ts +2 -0
  74. package/build/tests/caps-api/fs-checks/not-versioned/updateXAttrs.js +126 -0
  75. package/build/tests/caps-api/fs-checks/not-versioned/writableFile.d.ts +2 -0
  76. package/build/tests/caps-api/fs-checks/not-versioned/writableFile.js +79 -0
  77. package/build/tests/caps-api/fs-checks/not-versioned/writableSubRoot.d.ts +2 -0
  78. package/build/tests/caps-api/fs-checks/not-versioned/writableSubRoot.js +90 -0
  79. package/build/tests/caps-api/fs-checks/not-versioned/writeBytes.d.ts +2 -0
  80. package/build/tests/caps-api/fs-checks/not-versioned/writeBytes.js +137 -0
  81. package/build/tests/caps-api/fs-checks/not-versioned/writeJSONFile.d.ts +2 -0
  82. package/build/tests/caps-api/fs-checks/not-versioned/writeJSONFile.js +101 -0
  83. package/build/tests/caps-api/fs-checks/not-versioned/writeTxtFile.d.ts +2 -0
  84. package/build/tests/caps-api/fs-checks/not-versioned/writeTxtFile.js +100 -0
  85. package/build/tests/caps-api/fs-checks/sync-on-one-dev/startUpload.d.ts +2 -0
  86. package/build/tests/caps-api/fs-checks/sync-on-one-dev/startUpload.js +187 -0
  87. package/build/tests/caps-api/fs-checks/sync-on-one-dev/stat.d.ts +2 -0
  88. package/build/tests/caps-api/fs-checks/sync-on-one-dev/stat.js +70 -0
  89. package/build/tests/caps-api/fs-checks/sync-on-one-dev/status.d.ts +2 -0
  90. package/build/tests/caps-api/fs-checks/sync-on-one-dev/status.js +53 -0
  91. package/build/tests/caps-api/fs-checks/sync-on-one-dev/upload.d.ts +2 -0
  92. package/build/tests/caps-api/fs-checks/sync-on-one-dev/upload.js +194 -0
  93. package/build/tests/caps-api/fs-checks/sync-with-two-devs/conflicts.d.ts +2 -0
  94. package/build/tests/caps-api/fs-checks/sync-with-two-devs/conflicts.js +396 -0
  95. package/build/tests/caps-api/fs-checks/sync-with-two-devs/update-propagation.d.ts +2 -0
  96. package/build/tests/caps-api/fs-checks/sync-with-two-devs/update-propagation.js +229 -0
  97. package/build/tests/caps-api/fs-checks/test-utils.d.ts +34 -0
  98. package/build/tests/caps-api/fs-checks/test-utils.js +95 -0
  99. package/build/tests/caps-api/fs-checks/versioned/archiveCurrent.d.ts +2 -0
  100. package/build/tests/caps-api/fs-checks/versioned/archiveCurrent.js +73 -0
  101. package/build/tests/caps-api/fs-checks/versioned/getByteSink.d.ts +2 -0
  102. package/build/tests/caps-api/fs-checks/versioned/getByteSink.js +122 -0
  103. package/build/tests/caps-api/fs-checks/versioned/getByteSource.d.ts +2 -0
  104. package/build/tests/caps-api/fs-checks/versioned/getByteSource.js +71 -0
  105. package/build/tests/caps-api/fs-checks/versioned/listFolder.d.ts +2 -0
  106. package/build/tests/caps-api/fs-checks/versioned/listFolder.js +109 -0
  107. package/build/tests/caps-api/fs-checks/versioned/listVersions.d.ts +2 -0
  108. package/build/tests/caps-api/fs-checks/versioned/listVersions.js +48 -0
  109. package/build/tests/caps-api/fs-checks/versioned/readBytes.d.ts +2 -0
  110. package/build/tests/caps-api/fs-checks/versioned/readBytes.js +90 -0
  111. package/build/tests/caps-api/fs-checks/versioned/readJSONFile.d.ts +2 -0
  112. package/build/tests/caps-api/fs-checks/versioned/readJSONFile.js +60 -0
  113. package/build/tests/caps-api/fs-checks/versioned/readTxtFile.d.ts +2 -0
  114. package/build/tests/caps-api/fs-checks/versioned/readTxtFile.js +56 -0
  115. package/build/tests/caps-api/fs-checks/versioned/stat.d.ts +2 -0
  116. package/build/tests/caps-api/fs-checks/versioned/stat.js +80 -0
  117. package/build/tests/caps-api/fs-checks/versioned/watchFile.d.ts +2 -0
  118. package/build/tests/caps-api/fs-checks/versioned/watchFile.js +64 -0
  119. package/build/tests/caps-api/fs-checks/versioned/writeBytes.d.ts +2 -0
  120. package/build/tests/caps-api/fs-checks/versioned/writeBytes.js +128 -0
  121. package/build/tests/caps-api/fs-checks/versioned/writeJSONFile.d.ts +2 -0
  122. package/build/tests/caps-api/fs-checks/versioned/writeJSONFile.js +111 -0
  123. package/build/tests/caps-api/fs-checks/versioned/writeTxtFile.d.ts +2 -0
  124. package/build/tests/caps-api/fs-checks/versioned/writeTxtFile.js +107 -0
  125. package/build/tests/caps-api/fs-checks/with-core-restarts/xattrs.d.ts +2 -0
  126. package/build/tests/caps-api/fs-checks/with-core-restarts/xattrs.js +50 -0
  127. package/build/tests/caps-api/keyrings.js +69 -0
  128. package/build/tests/caps-api/mailerid.d.ts +1 -0
  129. package/build/tests/caps-api/mailerid.js +59 -0
  130. package/build/tests/caps-api/startup/signin-empty-cache.d.ts +1 -0
  131. package/build/tests/caps-api/startup/signin-empty-cache.js +108 -0
  132. package/build/tests/caps-api/startup/signin-with-cache.d.ts +1 -0
  133. package/build/tests/caps-api/startup/signin-with-cache.js +83 -0
  134. package/build/tests/caps-api/startup/signup-with-token.d.ts +1 -0
  135. package/build/tests/caps-api/startup/signup-with-token.js +53 -0
  136. package/build/tests/caps-api/startup/signup.d.ts +1 -0
  137. package/build/tests/caps-api/startup/signup.js +86 -0
  138. package/build/tests/caps-api/storage.d.ts +1 -0
  139. package/build/tests/caps-api/storage.js +225 -0
  140. package/build/tests/computer.3nweb.core/id-manager.d.ts +1 -0
  141. package/build/tests/computer.3nweb.core/id-manager.js +78 -0
  142. package/build/tests/computer.3nweb.core/inbox/msg-indexing.d.ts +1 -0
  143. package/build/tests/computer.3nweb.core/inbox/msg-indexing.js +145 -0
  144. package/build/tests/computer.3nweb.core/keyrings.d.ts +1 -0
  145. package/build/tests/computer.3nweb.core/keyrings.js +64 -0
  146. package/build/tests/computer.3nweb.core/test-utils.d.ts +21 -0
  147. package/build/tests/computer.3nweb.core/test-utils.js +92 -0
  148. package/build/tests/jasmine.d.ts +1 -0
  149. package/build/tests/jasmine.js +45 -0
  150. package/build/tests/libs-for-tests/bytes-equal.d.ts +1 -0
  151. package/build/tests/libs-for-tests/bytes-equal.js +32 -0
  152. package/build/tests/libs-for-tests/caps-ipc-wrap.d.ts +11 -0
  153. package/build/tests/libs-for-tests/caps-ipc-wrap.js +55 -0
  154. package/build/tests/libs-for-tests/core-runner.d.ts +39 -0
  155. package/build/tests/libs-for-tests/core-runner.js +231 -0
  156. package/build/tests/libs-for-tests/jasmine-utils.d.ts +13 -0
  157. package/build/tests/libs-for-tests/jasmine-utils.js +110 -0
  158. package/build/tests/libs-for-tests/json-equal.d.ts +1 -0
  159. package/build/tests/libs-for-tests/json-equal.js +78 -0
  160. package/build/tests/libs-for-tests/services-runner.d.ts +18 -0
  161. package/build/tests/libs-for-tests/services-runner.js +64 -0
  162. package/build/tests/libs-for-tests/setups.d.ts +51 -0
  163. package/build/tests/libs-for-tests/setups.js +305 -0
  164. package/build/tests/libs-for-tests/spec-module.d.ts +16 -0
  165. package/build/tests/libs-for-tests/spec-module.js +92 -0
  166. package/build/tests/libs-for-tests/startup.d.ts +1 -0
  167. package/build/tests/libs-for-tests/startup.js +29 -0
  168. package/build/tests/libs-for-tests/watching.d.ts +7 -0
  169. package/build/tests/libs-for-tests/watching.js +33 -0
  170. package/build/tests/units/canonical-address.d.ts +1 -0
  171. package/build/tests/units/canonical-address.js +41 -0
  172. package/build/tests/units/device-fs.d.ts +1 -0
  173. package/build/tests/units/device-fs.js +70 -0
  174. package/build/tests/units/folder-node-serialization.d.ts +1 -0
  175. package/build/tests/units/folder-node-serialization.js +74 -0
  176. package/build/tests/units/mid-sigs-NaCl-Ed.d.ts +1 -0
  177. package/build/tests/units/mid-sigs-NaCl-Ed.js +123 -0
  178. package/build/tests/units/number-line.d.ts +1 -0
  179. package/build/tests/units/number-line.js +63 -0
  180. package/build/tests/units/obj-folders.d.ts +1 -0
  181. package/build/tests/units/obj-folders.js +152 -0
  182. package/package.json +11 -3
  183. package/postinstall.js +1 -1
  184. package/build/cryptors.d.ts +0 -1
  185. package/build/cryptors.js +0 -34
  186. package/build/lib-client/cryptor/cryptor-in-worker.d.ts +0 -20
  187. package/build/lib-client/cryptor/cryptor-in-worker.js +0 -357
  188. package/build/lib-client/cryptor/cryptor-wasm.js +0 -1
  189. package/build/lib-client/cryptor/cryptor.d.ts +0 -30
  190. package/build/lib-client/cryptor/cryptor.js +0 -44
  191. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  192. package/build/lib-client/cryptor/in-proc-js.d.ts +0 -2
  193. package/build/lib-client/cryptor/in-proc-js.js +0 -57
  194. package/build/lib-client/cryptor/in-proc-wasm.d.ts +0 -2
  195. package/build/lib-client/cryptor/in-proc-wasm.js +0 -176
  196. package/build/lib-client/cryptor/serialization-for-wasm.d.ts +0 -35
  197. package/build/lib-client/cryptor/serialization-for-wasm.js +0 -57
  198. package/build/lib-client/cryptor/wasm-mp1-modules.d.ts +0 -5
  199. package/build/lib-client/cryptor/wasm-mp1-modules.js +0 -78
  200. package/build/lib-client/cryptor/worker-js.js +0 -131
  201. package/build/lib-client/cryptor/worker-wasm.js +0 -37
  202. package/build/protos/cryptor.proto.js +0 -1804
  203. /package/build/lib-client/{cryptor/cryptor-work-labels.d.ts → cryptor-work-labels.d.ts} +0 -0
  204. /package/build/lib-client/{cryptor/cryptor-work-labels.js → cryptor-work-labels.js} +0 -0
  205. /package/build/{lib-client/cryptor/worker-js.d.ts → tests/caps-api/asmail.d.ts} +0 -0
  206. /package/build/{lib-client/cryptor/worker-wasm.d.ts → tests/caps-api/keyrings.d.ts} +0 -0
@@ -0,0 +1,396 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (C) 2022, 2025 - 2026 3NSoft Inc.
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU General Public License as published by the Free Software
7
+ Foundation, either version 3 of the License, or (at your option) any later
8
+ version.
9
+
10
+ This program is distributed in the hope that it will be useful, but
11
+ WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ See the GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License along with
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.specs = void 0;
20
+ const random_node_1 = require("../../../../lib-common/random-node");
21
+ const json_equal_1 = require("../../../libs-for-tests/json-equal");
22
+ const watching_1 = require("../../../libs-for-tests/watching");
23
+ exports.specs = {
24
+ description: '--',
25
+ its: []
26
+ };
27
+ let it = {
28
+ expectation: 'conflict in folder can be resolved by adopting remote version'
29
+ };
30
+ it.func = async function ({ dev1FS, dev2FS }) {
31
+ const file = 'file-for-conflict';
32
+ let folderStatus = await dev2FS().v.sync.status('');
33
+ expect(folderStatus.state).withContext(`from setup`).toBe('synced');
34
+ // make file simulatneously on both devices
35
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
36
+ await dev2FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(70));
37
+ folderStatus = await dev2FS().v.sync.status('');
38
+ expect(folderStatus.state).toBe('unsynced');
39
+ // and upload changes from dev1
40
+ await dev1FS().v.sync.upload(file);
41
+ await dev1FS().v.sync.upload('');
42
+ folderStatus = await dev2FS().v.sync.status('');
43
+ expect(folderStatus.state).toBe('conflicting');
44
+ expect(await dev2FS().readTxtFile(file))
45
+ .withContext(`we have placed a different content into these conflicting file versions`)
46
+ .not.toBe(await dev1FS().readTxtFile(file));
47
+ // folder versions diff is a tool for getting folder conflict details
48
+ const diff = await dev2FS().v.sync.diffCurrentAndRemoteFolderVersions('');
49
+ expect(diff).toBeDefined();
50
+ expect(diff.currentVersion).toBe(folderStatus.local.latest);
51
+ expect(diff.remoteVersion).toBe(folderStatus.remote.latest);
52
+ expect(diff.added.inLocal.includes(file)).toBeTrue();
53
+ expect(diff.added.inRemote.includes(file)).toBeTrue();
54
+ expect(diff.nameOverlaps).toContain(file);
55
+ const syncEvents = (0, watching_1.watchForEvents)(obs => dev2FS().watchFolder('', obs), 2, ev => (ev.src === 'sync'));
56
+ // adopt remote in a conflict state
57
+ await dev2FS().v.sync.adoptRemote('').then(() => fail(``), (exc) => {
58
+ expect(exc.type).toBe('fs-sync');
59
+ expect(exc.conflict).toBeTrue();
60
+ });
61
+ await dev2FS().v.sync.adoptRemote('', { remoteVersion: folderStatus.remote.latest });
62
+ await syncEvents.completion;
63
+ expect(syncEvents.collectedEvents.find(ev => ((ev.type === 'entry-removal') && (ev.name === file))))
64
+ .withContext(`Different object on the same path is removed`)
65
+ .toBeDefined();
66
+ expect(syncEvents.collectedEvents.find(ev => ((ev.type === 'entry-addition') && (ev.entry.name === file))))
67
+ .withContext(`Element from remote version is added`)
68
+ .toBeDefined();
69
+ folderStatus = await dev2FS().v.sync.status('');
70
+ expect(folderStatus.state).toBe('synced');
71
+ // we have also adopted here new file object on the same path
72
+ expect(await dev2FS().readTxtFile(file))
73
+ .withContext(`after adoption of folder dev2 reads correct file object`)
74
+ .toBe(await dev1FS().readTxtFile(file));
75
+ let fileStatus = await dev2FS().v.sync.status(file);
76
+ expect(fileStatus.state)
77
+ .withContext(`when a file system item is brought the first time from a server, its state should necessarily be synced`)
78
+ .toBe('synced');
79
+ };
80
+ exports.specs.its.push(it);
81
+ it = {
82
+ expectation: `conflict in folder can be resolved by uploading local version, assembled from elements on both sides of the conflict`
83
+ };
84
+ it.func = async function ({ dev1FS, dev2FS }) {
85
+ var _a, _b, _c, _d, _e, _f, _g;
86
+ const file = 'file-for-conflict';
87
+ const fileFromDev1 = 'file-from-dev1';
88
+ const fileFromDev2 = 'file-from-dev2';
89
+ let folderStatus = await dev2FS().v.sync.status('');
90
+ expect(folderStatus.state).withContext(`from setup`).toBe('synced');
91
+ expect((_a = folderStatus.synced) === null || _a === void 0 ? void 0 : _a.latest).withContext(`from setup`).toBe(1);
92
+ // make file simulatneously on both devices
93
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
94
+ await dev1FS().writeTxtFile(fileFromDev1, (0, random_node_1.stringOfB64CharsSync)(100));
95
+ await dev2FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(70));
96
+ await dev2FS().writeTxtFile(fileFromDev2, (0, random_node_1.stringOfB64CharsSync)(70));
97
+ folderStatus = await dev2FS().v.sync.status('');
98
+ expect(folderStatus.state).toBe('unsynced');
99
+ // and upload changes from dev1
100
+ await dev1FS().v.sync.upload(file);
101
+ await dev1FS().v.sync.upload(fileFromDev1);
102
+ await dev1FS().v.sync.upload('');
103
+ // and upload on dev2 files, one will be adopted later, another removed
104
+ await dev2FS().v.sync.upload(file);
105
+ await dev2FS().v.sync.upload(fileFromDev2);
106
+ folderStatus = await dev2FS().v.sync.status('');
107
+ expect(folderStatus.state).toBe('conflicting');
108
+ expect((_b = folderStatus.remote) === null || _b === void 0 ? void 0 : _b.latest).toBe(2);
109
+ // folder versions diff is a tool for getting folder conflict details
110
+ const diff = await dev2FS().v.sync.diffCurrentAndRemoteFolderVersions('');
111
+ expect(diff).toBeDefined();
112
+ expect(diff.currentVersion).toBe(folderStatus.local.latest);
113
+ expect(diff.remoteVersion).toBe(folderStatus.remote.latest);
114
+ expect(diff.added.inLocal.includes(file)).toBeTrue();
115
+ expect(diff.added.inLocal.includes(fileFromDev2)).toBeTrue();
116
+ expect(diff.added.inRemote.includes(file)).toBeTrue();
117
+ expect(diff.added.inRemote.includes(fileFromDev1)).toBeTrue();
118
+ expect(diff.nameOverlaps).toContain(file);
119
+ // we can stat remote child
120
+ let statsRemote = await dev2FS().v.sync.statRemoteItem('', file, diff.remoteVersion);
121
+ let statsLocal = await dev2FS().stat(file);
122
+ let statsOn1 = await dev1FS().stat(file);
123
+ expect((_c = statsRemote.mtime) === null || _c === void 0 ? void 0 : _c.valueOf()).not.toBe((_d = statsLocal.mtime) === null || _d === void 0 ? void 0 : _d.valueOf());
124
+ expect((_e = statsRemote.mtime) === null || _e === void 0 ? void 0 : _e.valueOf()).toBe((_f = statsOn1.mtime) === null || _f === void 0 ? void 0 : _f.valueOf());
125
+ expect(statsRemote.size).not.toBe(statsLocal.size);
126
+ expect(statsRemote.size).toBe(statsOn1.size);
127
+ // we can read remote child
128
+ let remoteChild = await dev2FS().v.sync.getRemoteFileItem('', file, diff.remoteVersion);
129
+ expect(await remoteChild.readTxt()).toBe(await dev1FS().readTxtFile(file));
130
+ expect((await remoteChild.stat()).size).toBe(statsOn1.size);
131
+ // adopt on dev2 some remote elements from dev1
132
+ await dev2FS().v.sync.adoptRemoteFolderItem('', file, { replaceLocalItem: true });
133
+ await dev2FS().v.sync.adoptRemoteFolderItem('', fileFromDev1);
134
+ expect(await dev2FS().readTxtFile(file))
135
+ .toBe(await dev1FS().readTxtFile(file));
136
+ expect(await dev2FS().readTxtFile(fileFromDev1))
137
+ .toBe(await dev1FS().readTxtFile(fileFromDev1));
138
+ expect(await dev1FS().checkFilePresence(fileFromDev2)).toBeFalse();
139
+ // note need of explicit parameters when uploading from conflict state
140
+ folderStatus = await dev2FS().v.sync.status('');
141
+ expect(folderStatus.state).toBe('conflicting');
142
+ await dev2FS().v.sync.upload('').then(() => fail(`Upload in conflict must require explicit parameters`), (exc) => {
143
+ expect(exc.type).toBe('fs-sync');
144
+ expect(exc.versionMismatch).toBeTrue();
145
+ });
146
+ // upload new version, now from dev2
147
+ await dev2FS().v.sync.upload('', { uploadVersion: folderStatus.remote.latest + 1 });
148
+ folderStatus = await dev2FS().v.sync.status('');
149
+ expect(folderStatus.state).toBe('synced');
150
+ expect((_g = folderStatus.synced) === null || _g === void 0 ? void 0 : _g.latest).toBe(3);
151
+ // get new version on dev1 and check contents
152
+ await dev1FS().v.sync.adoptRemote('');
153
+ const lst = await dev1FS().listFolder('');
154
+ expect(lst.find(e => ((e.name === file) && e.isFile))).toBeDefined();
155
+ expect(lst.find(e => ((e.name === fileFromDev1) && e.isFile))).toBeDefined();
156
+ expect(lst.find(e => ((e.name === fileFromDev2) && e.isFile))).toBeDefined();
157
+ expect(await dev2FS().readTxtFile(fileFromDev2))
158
+ .toBe(await dev1FS().readTxtFile(fileFromDev2));
159
+ };
160
+ exports.specs.its.push(it);
161
+ it = {
162
+ expectation: 'conflict in file can be resolved by adopting remote version'
163
+ };
164
+ it.func = async function ({ dev1FS, dev2FS }) {
165
+ const file = 'file-for-conflict';
166
+ // create file on dev1 and upload, so that dev2 can get it
167
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
168
+ await dev1FS().v.sync.upload(file);
169
+ await dev1FS().v.sync.upload('');
170
+ await dev2FS().v.sync.status(''); // implicit check of server
171
+ await dev2FS().v.sync.adoptRemote('');
172
+ let fileStatus = await dev2FS().v.sync.status(file);
173
+ expect(fileStatus.state).withContext(`when a file system item is brought the first time from a server, its state should necessarily be synced`)
174
+ .toBe('synced');
175
+ const fstObservedVersion = fileStatus.synced.latest;
176
+ // change file on dev1 and propagate
177
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(200));
178
+ await dev1FS().v.sync.upload(file);
179
+ fileStatus = await dev2FS().v.sync.status(file);
180
+ expect(fileStatus.state).withContext(`changes to a file system item that come from a server can be adopted only explicitly, and state should indicate that current version is behind remote one`).toBe('behind');
181
+ expect(fileStatus.remote.latest).toBeGreaterThan(fstObservedVersion);
182
+ // change file on dev2 to reach conflict state
183
+ await dev2FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(150));
184
+ fileStatus = await dev2FS().v.sync.status(file);
185
+ expect(fileStatus.state).toBe('conflicting');
186
+ const syncEvents = (0, watching_1.watchForEvents)(obs => dev2FS().watchFile(file, obs), 1, ev => (ev.src === 'sync'));
187
+ // adopt remote in a conflict state
188
+ await dev2FS().v.sync.adoptRemote(file).then(() => fail(``), (exc) => {
189
+ expect(exc.type).toBe('fs-sync');
190
+ expect(exc.conflict).toBeTrue();
191
+ });
192
+ await dev2FS().v.sync.adoptRemote(file, { remoteVersion: fileStatus.remote.latest });
193
+ await syncEvents.completion;
194
+ expect(syncEvents.collectedEvents.find(ev => (ev.type === 'file-change')))
195
+ .withContext(``)
196
+ .toBeDefined();
197
+ fileStatus = await dev2FS().v.sync.status('');
198
+ expect(fileStatus.state).toBe('synced');
199
+ expect(await dev2FS().readTxtFile(file))
200
+ .toBe(await dev1FS().readTxtFile(file));
201
+ };
202
+ exports.specs.its.push(it);
203
+ it = {
204
+ expectation: 'conflict in file can be resolved by uploading local version'
205
+ };
206
+ it.func = async function ({ dev1FS, dev2FS }) {
207
+ const file = 'file-for-conflict';
208
+ // create file on dev1 and upload, so that dev2 can get it
209
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
210
+ await dev1FS().v.sync.upload(file);
211
+ await dev1FS().v.sync.upload('');
212
+ await dev2FS().v.sync.status(''); // implicit check of server
213
+ await dev2FS().v.sync.adoptRemote('');
214
+ // change file on dev1 and dev2
215
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(200));
216
+ await dev2FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(150));
217
+ // and upload changes from dev1 to reach conflict on dev2
218
+ await dev1FS().v.sync.upload(file);
219
+ let fileStatusOnDev2 = await dev2FS().v.sync.status(file);
220
+ expect(fileStatusOnDev2.state).toBe('conflicting');
221
+ // push version on dev2 higher to see it going down to uploaded level
222
+ for (let i = 0; i < 3; i += 1) {
223
+ await dev2FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(151 + i));
224
+ }
225
+ const remoteVersionBeforeUpload = fileStatusOnDev2.remote.latest;
226
+ expect((await dev2FS().stat(file)).version)
227
+ .toBeGreaterThan(remoteVersionBeforeUpload + 1);
228
+ await dev2FS().v.sync.upload(file).then(() => fail(`Upload in conflicting state should require explicit versioning`), (exc) => {
229
+ expect(exc.versionMismatch).toBeTrue();
230
+ });
231
+ await dev2FS().v.sync.upload(file, { uploadVersion: fileStatusOnDev2.remote.latest + 1 });
232
+ fileStatusOnDev2 = await dev2FS().v.sync.status(file);
233
+ expect(fileStatusOnDev2.state).toBe('synced');
234
+ expect(fileStatusOnDev2.synced.latest).toBe(remoteVersionBeforeUpload + 1);
235
+ await dev1FS().v.sync.status(file); // implicit check of server
236
+ await dev1FS().v.sync.adoptRemote(file);
237
+ expect(await dev2FS().readTxtFile(file))
238
+ .toBe(await dev1FS().readTxtFile(file));
239
+ };
240
+ exports.specs.its.push(it);
241
+ it = {
242
+ expectation: 'upload over conflict concurrent with file write via sink'
243
+ };
244
+ it.func = async function ({ dev1FS, dev2FS }) {
245
+ const file = 'file-for-conflict';
246
+ // create file on dev1 and upload, so that dev2 can get it
247
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
248
+ await dev1FS().v.sync.upload(file);
249
+ await dev1FS().v.sync.upload('');
250
+ await dev2FS().v.sync.status(''); // implicit check of server
251
+ await dev2FS().v.sync.adoptRemote('');
252
+ // change file on dev1 and dev2
253
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(200));
254
+ await dev2FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(150));
255
+ // and upload changes from dev1 to reach conflict on dev2
256
+ await dev1FS().v.sync.upload(file);
257
+ let fileStatusOnDev2 = await dev2FS().v.sync.status(file);
258
+ expect(fileStatusOnDev2.state).toBe('conflicting');
259
+ expect(fileStatusOnDev2.remote.latest).toBe(2);
260
+ // push version on dev2 higher to see it going down to uploaded level
261
+ let contentBeforeUpload = undefined;
262
+ for (let i = 0; i < 3; i += 1) {
263
+ contentBeforeUpload = (0, random_node_1.stringOfB64CharsSync)(151 + i);
264
+ await dev2FS().writeTxtFile(file, contentBeforeUpload);
265
+ }
266
+ // start long write to run concurrent with upload
267
+ const longWrite = await dev2FS().v.getByteSink(file);
268
+ // make concurrent upload
269
+ const uploadCompletion = dev2FS().v.sync.upload(file, { uploadVersion: fileStatusOnDev2.remote.latest + 1 });
270
+ await longWrite.sink.truncate(20);
271
+ // complete the write
272
+ await longWrite.sink.done();
273
+ // upload was scheduled after write completion, hence, awaiting after it
274
+ await uploadCompletion;
275
+ fileStatusOnDev2 = await dev2FS().v.sync.status(file);
276
+ expect(fileStatusOnDev2.state).toBe('unsynced');
277
+ expect(fileStatusOnDev2.synced.latest).toBe(3);
278
+ expect(fileStatusOnDev2.local.latest).toBe(longWrite.version);
279
+ await dev1FS().v.sync.status(file);
280
+ await dev1FS().v.sync.adoptRemote(file);
281
+ expect(await dev1FS().readTxtFile(file)).toBe(contentBeforeUpload);
282
+ await dev2FS().v.sync.upload(file);
283
+ fileStatusOnDev2 = await dev2FS().v.sync.status(file);
284
+ expect(fileStatusOnDev2.state).toBe('synced');
285
+ expect(fileStatusOnDev2.synced.latest).toBe(4);
286
+ await dev1FS().v.sync.status(file);
287
+ await dev1FS().v.sync.adoptRemote(file);
288
+ expect(await dev2FS().readTxtFile(file))
289
+ .toBe(await dev1FS().readTxtFile(file));
290
+ };
291
+ exports.specs.its.push(it);
292
+ it = {
293
+ expectation: 'viewing and adopting remote folder item'
294
+ };
295
+ it.func = async function ({ dev1FS, dev2FS }) {
296
+ const fileA = `file-a`;
297
+ const folder = 'folder-for-conflict';
298
+ const file1 = `file-1`;
299
+ const file1path = `${folder}/${file1}`;
300
+ const file2 = `file-2`;
301
+ const file2path = `${folder}/${file2}`;
302
+ // create tree on dev1 and upload
303
+ for (const path of [file1path, file2path, fileA]) {
304
+ await dev1FS().writeTxtFile(path, (0, random_node_1.stringOfB64CharsSync)(100));
305
+ }
306
+ for (const path of [file1path, file2path, folder, fileA, '']) {
307
+ await dev1FS().v.sync.upload(path);
308
+ }
309
+ // tree is not local on dev2
310
+ let syncStatus = await dev2FS().v.sync.status(''); // implicit check of server
311
+ expect(syncStatus.state).toBe('behind');
312
+ expect(await dev2FS().checkFolderPresence(folder)).toBeFalse();
313
+ // can read remote items
314
+ let lst = await dev2FS().v.sync.listRemoteFolderItem('', folder);
315
+ let remoteFS = await dev2FS().v.sync.getRemoteFolderItem('', folder);
316
+ expect((0, json_equal_1.deepEqual)(lst, await remoteFS.listFolder(''))).toBeTrue();
317
+ expect(remoteFS.writable).toBeFalse();
318
+ expect(await remoteFS.readTxtFile(file1)).toBe(await dev1FS().readTxtFile(file1path));
319
+ expect(await remoteFS.readTxtFile(file2)).toBe(await dev1FS().readTxtFile(file2path));
320
+ // making a conflicting folder on dev2
321
+ const fileB = `file-b`;
322
+ const file3 = `file-3`;
323
+ const file3path = `${folder}/${file3}`;
324
+ for (const path of [file1path, file3path, fileB]) {
325
+ await dev2FS().writeTxtFile(path, (0, random_node_1.stringOfB64CharsSync)(100));
326
+ }
327
+ for (const path of [file1path, file3path, folder, fileB]) {
328
+ await dev2FS().v.sync.upload(path);
329
+ }
330
+ syncStatus = await dev2FS().v.sync.status(''); // implicit check of server
331
+ expect(syncStatus.state).toBe('conflicting');
332
+ const diff = await dev2FS().v.sync.diffCurrentAndRemoteFolderVersions('', syncStatus.remote.latest);
333
+ expect(diff.added.inLocal.includes(folder)).toBeTrue();
334
+ expect(diff.added.inLocal.includes(fileB)).toBeTrue();
335
+ expect(diff.added.inRemote.includes(folder)).toBeTrue();
336
+ expect(diff.added.inRemote.includes(fileA)).toBeTrue();
337
+ expect(diff.nameOverlaps).toContain(folder);
338
+ await dev2FS().v.sync.absorbRemoteFolderChanges('').then(() => fail(`Overlapping names require presence of prefix`), (exc) => {
339
+ expect(exc.type).toBe('fs-sync');
340
+ expect(Array.isArray(exc.nameOverlaps)).toBeTrue();
341
+ });
342
+ const postfixForNameOverlaps = `-remote`;
343
+ let version = await dev2FS().v.sync.absorbRemoteFolderChanges('', { postfixForNameOverlaps });
344
+ expect(version).toBe(diff.currentVersion + 1);
345
+ expect(await dev2FS().checkFilePresence(fileA)).toBeTrue();
346
+ expect(await dev2FS().readTxtFile(fileA)).toBe(await dev1FS().readTxtFile(fileA));
347
+ expect((0, json_equal_1.deepEqual)(await dev2FS().listFolder(`${folder}${postfixForNameOverlaps}`), await dev1FS().listFolder(folder))).toBeTrue();
348
+ };
349
+ exports.specs.its.push(it);
350
+ it = {
351
+ expectation: `viewing remote folder items when it wasn't local or was removed locally`
352
+ };
353
+ it.func = async function ({ dev1FS, dev2FS }) {
354
+ const file = `file_to_remove`;
355
+ const folder = `folder_to_remove`;
356
+ const fileA = `file-A`;
357
+ const folderA = `folder-A`;
358
+ // make file on dev1 and upload
359
+ await dev1FS().writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
360
+ await dev1FS().v.sync.upload(file);
361
+ await dev1FS().makeFolder(folder);
362
+ await dev1FS().v.sync.upload(folder);
363
+ await dev1FS().v.sync.upload('');
364
+ await dev2FS().v.sync.adoptRemote('');
365
+ expect(await dev2FS().checkFilePresence(file, true)).toBeTrue();
366
+ // change dev1 for conflict condition on folder path
367
+ await dev1FS().writeTxtFile(fileA, (0, random_node_1.stringOfB64CharsSync)(50));
368
+ await dev1FS().v.sync.upload(fileA);
369
+ await dev1FS().makeFolder(folderA);
370
+ await dev1FS().v.sync.upload(folderA);
371
+ await dev1FS().v.sync.upload('');
372
+ // remove file on dev2
373
+ await dev2FS().deleteFile(file);
374
+ await dev2FS().deleteFolder(folder);
375
+ const diff = await dev2FS().v.sync.diffCurrentAndRemoteFolderVersions('');
376
+ expect((await dev2FS().v.sync.statRemoteItem('', fileA, diff.remoteVersion)).size)
377
+ .toBe((await dev1FS().stat(fileA)).size);
378
+ expect((await dev2FS().v.sync.statRemoteItem('', file, diff.remoteVersion)).size)
379
+ .toBe((await dev1FS().stat(file)).size);
380
+ expect((await dev2FS().v.sync.statRemoteItem('', folderA, diff.remoteVersion)).mtime.valueOf())
381
+ .toBe((await dev1FS().stat(folderA)).mtime.valueOf());
382
+ expect((await dev2FS().v.sync.statRemoteItem('', folder, diff.remoteVersion)).mtime.valueOf())
383
+ .toBe((await dev1FS().stat(folder)).mtime.valueOf());
384
+ let fileObj = await dev2FS().v.sync.getRemoteFileItem('', file, diff.remoteVersion);
385
+ expect((await fileObj.readTxt())).toBe(await dev1FS().readTxtFile(file));
386
+ fileObj = await dev2FS().v.sync.getRemoteFileItem('', fileA, diff.remoteVersion);
387
+ expect((await fileObj.readTxt())).toBe(await dev1FS().readTxtFile(fileA));
388
+ let folderObj = await dev2FS().v.sync.getRemoteFolderItem('', folder, diff.remoteVersion);
389
+ expect((0, json_equal_1.deepEqual)(await folderObj.listFolder(''), await dev1FS().listFolder(folder))).toBeTrue();
390
+ expect(folderObj.v).toBeUndefined();
391
+ folderObj = await dev2FS().v.sync.getRemoteFolderItem('', folderA, diff.remoteVersion);
392
+ expect((0, json_equal_1.deepEqual)(await folderObj.listFolder(''), await dev1FS().listFolder(folderA))).toBeTrue();
393
+ expect(folderObj.v).toBeUndefined();
394
+ };
395
+ exports.specs.its.push(it);
396
+ Object.freeze(exports);
@@ -0,0 +1,2 @@
1
+ import { SpecDescribe } from '../../../libs-for-tests/spec-module';
2
+ export declare const specs: SpecDescribe;
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (C) 2022, 2025 3NSoft Inc.
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU General Public License as published by the Free Software
7
+ Foundation, either version 3 of the License, or (at your option) any later
8
+ version.
9
+
10
+ This program is distributed in the hope that it will be useful, but
11
+ WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ See the GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License along with
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.specs = void 0;
20
+ const buffer_utils_1 = require("../../../../lib-common/buffer-utils");
21
+ const deferred_1 = require("../../../../lib-common/processes/deferred");
22
+ const random_node_1 = require("../../../../lib-common/random-node");
23
+ const bytes_equal_1 = require("../../../libs-for-tests/bytes-equal");
24
+ const json_equal_1 = require("../../../libs-for-tests/json-equal");
25
+ const test_utils_1 = require("../test-utils");
26
+ exports.specs = {
27
+ description: '--',
28
+ its: []
29
+ };
30
+ let it = {
31
+ expectation: 'when online, other device observes events'
32
+ };
33
+ it.func = async function ({ dev1FS, dev2FS }) {
34
+ const file = 'file-1';
35
+ let fs1 = dev1FS();
36
+ let fs2 = dev2FS();
37
+ const evAtDev2 = (0, test_utils_1.observeFolderForOneEvent)(fs2);
38
+ let status = await fs2.v.sync.status('');
39
+ expect(status.state).withContext(`from setup`).toBe('synced');
40
+ await fs1.writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
41
+ await fs1.v.sync.upload(file);
42
+ await fs1.v.sync.upload('');
43
+ const folderChangeEvent = await evAtDev2;
44
+ expect(folderChangeEvent.type).toBe('remote-change');
45
+ status = await fs2.v.sync.status('');
46
+ expect(status.state).toBe('behind');
47
+ await fs2.readTxtFile(file).then(() => fail(`There should be no file still in folder on dev 2`), (exc) => expect(exc.notFound).toBeTrue());
48
+ await fs2.v.sync.adoptRemote('');
49
+ status = await fs2.v.sync.status('');
50
+ const statusOnDev1 = await fs1.v.sync.status('');
51
+ expect(status.state).toBe('synced');
52
+ expect(status.synced.latest).toBe(statusOnDev1.synced.latest);
53
+ expect(await fs2.readTxtFile(file))
54
+ .toBe(await fs1.readTxtFile(file));
55
+ };
56
+ exports.specs.its.push(it);
57
+ it = {
58
+ expectation: 'other device should check updates when coming online'
59
+ };
60
+ it.func = async function ({ dev1FS, dev2FS, dev2 }) {
61
+ const file = 'file-1';
62
+ let fs1 = dev1FS();
63
+ let fs2 = dev2FS();
64
+ let status = await fs2.v.sync.status('');
65
+ expect(status.state).withContext(`from setup`).toBe('synced');
66
+ await dev2.stop();
67
+ await fs1.writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
68
+ await fs1.v.sync.upload(file);
69
+ await fs1.v.sync.upload('');
70
+ await dev2.start();
71
+ fs2 = dev2FS();
72
+ status = await fs2.v.sync.status('', true);
73
+ expect(status.state).toBe('synced');
74
+ status = await fs2.v.sync.status('');
75
+ expect(status.state).toBe('behind');
76
+ await fs2.v.sync.adoptRemote('');
77
+ status = await fs2.v.sync.status('');
78
+ const statusOnDev1 = await fs1.v.sync.status('');
79
+ expect(status.state).toBe('synced');
80
+ expect(status.synced.latest).toBe(statusOnDev1.synced.latest);
81
+ expect(await fs2.readTxtFile(file))
82
+ .toBe(await fs1.readTxtFile(file));
83
+ };
84
+ exports.specs.its.push(it);
85
+ function collectFileDownloadEvents(fs, path) {
86
+ const startEvent = (0, deferred_1.defer)();
87
+ const doneEvent = (0, deferred_1.defer)();
88
+ const progressEvents = [];
89
+ const unsub = fs.watchFile(path, {
90
+ next: ev => {
91
+ switch (ev.type) {
92
+ case 'download-started':
93
+ startEvent.resolve(ev);
94
+ break;
95
+ case 'download-done':
96
+ doneEvent.resolve(ev);
97
+ unsub();
98
+ break;
99
+ case 'download-progress':
100
+ progressEvents.push(ev);
101
+ break;
102
+ }
103
+ }
104
+ });
105
+ return {
106
+ startEvent: startEvent.promise,
107
+ doneEvent: doneEvent.promise,
108
+ progressEvents
109
+ };
110
+ }
111
+ it = {
112
+ expectation: 'remote version is downloaded non-automatically'
113
+ };
114
+ it.func = async function ({ dev1FS, dev2FS }) {
115
+ const file = 'file-1';
116
+ let fs1 = dev1FS();
117
+ let fs2 = dev2FS();
118
+ // case 1: remote version of folder
119
+ const folderEventAt2 = (0, test_utils_1.observeFolderForOneEvent)(fs2);
120
+ await fs1.writeTxtFile(file, (0, random_node_1.stringOfB64CharsSync)(100));
121
+ await fs1.v.sync.upload(file);
122
+ await fs1.v.sync.upload('');
123
+ const folderEv = await folderEventAt2;
124
+ expect(folderEv.type).toBe('remote-change');
125
+ expect((0, json_equal_1.deepEqual)(folderEv.syncStatus, await fs2.v.sync.status(''))).toBeTrue();
126
+ expect(await fs2.v.sync.isRemoteVersionOnDisk('', folderEv.newRemoteVersion)).toBe('none');
127
+ let startedDownload = await fs2.v.sync.startDownload('', folderEv.newRemoteVersion);
128
+ expect(startedDownload)
129
+ .withContext(`long download is not started, cause small entity is completely downloaded in the first request`)
130
+ .toBeUndefined();
131
+ expect(await fs2.v.sync.isRemoteVersionOnDisk('', folderEv.newRemoteVersion))
132
+ .withContext(`expect to see entity completely on a disk, when download has started, as not being needed`)
133
+ .toBe('complete');
134
+ expect((await fs2.v.listFolder('', { remoteVersion: folderEv.newRemoteVersion })).lst.map(({ name }) => name)).toContain(file);
135
+ // case 2: remote version of file
136
+ expect(await fs2.checkFilePresence(file)).toBeFalse();
137
+ await fs2.v.sync.adoptRemote('');
138
+ expect(await fs2.readTxtFile(file)).toBe(await fs1.readTxtFile(file));
139
+ let fileEventAt2 = (0, test_utils_1.observeFileForOneEvent)(fs2, file);
140
+ await fs1.writeBytes(file, await (0, random_node_1.bytes)(88000000));
141
+ await fs1.v.sync.upload(file);
142
+ let fileEv = await fileEventAt2;
143
+ expect(fileEv.type).toBe('remote-change');
144
+ expect((0, json_equal_1.deepEqual)(fileEv.syncStatus, await fs2.v.sync.status(file))).toBeTrue();
145
+ expect(await fs2.v.sync.isRemoteVersionOnDisk(file, fileEv.newRemoteVersion)).toBe('none');
146
+ let events = collectFileDownloadEvents(fs2, file);
147
+ startedDownload = await fs2.v.sync.startDownload(file, fileEv.newRemoteVersion);
148
+ expect(await fs2.v.sync.isRemoteVersionOnDisk(file, fileEv.newRemoteVersion)).toBe('partial');
149
+ expect(startedDownload).toBeDefined();
150
+ expect((await events.startEvent).downloadTaskId).toBe(startedDownload.downloadTaskId);
151
+ expect((await events.doneEvent).downloadTaskId).toBe(startedDownload.downloadTaskId);
152
+ expect(events.progressEvents.length).toBeGreaterThan(0);
153
+ expect(await fs2.v.sync.isRemoteVersionOnDisk(file, fileEv.newRemoteVersion)).toBe('complete');
154
+ expect((0, bytes_equal_1.bytesEqual)((await fs2.v.readBytes(file, undefined, undefined, { remoteVersion: fileEv.newRemoteVersion })).bytes, (await fs1.readBytes(file)))).toBeTrue();
155
+ // case 3: reading remote version of file without adopting it and without explicit download
156
+ fileEventAt2 = (0, test_utils_1.observeFileForOneEvent)(fs2, file);
157
+ await fs1.writeBytes(file, await (0, random_node_1.bytes)(770000));
158
+ await fs1.v.sync.upload(file);
159
+ fileEv = await fileEventAt2;
160
+ expect(await fs2.v.sync.isRemoteVersionOnDisk(file, fileEv.newRemoteVersion)).toBe('none');
161
+ expect((0, bytes_equal_1.bytesEqual)((await fs2.v.readBytes(file, undefined, undefined, { remoteVersion: fileEv.newRemoteVersion })).bytes, (await fs1.readBytes(file)))).toBeTrue();
162
+ expect(await fs2.v.sync.isRemoteVersionOnDisk(file, fileEv.newRemoteVersion)).toBe('complete');
163
+ };
164
+ it.timeout = 30000;
165
+ exports.specs.its.push(it);
166
+ it = {
167
+ expectation: 'file incrementally written and uploaded, then read on a second device'
168
+ };
169
+ it.func = async function ({ dev1FS, dev2FS }) {
170
+ const file = 'incremental-file';
171
+ let fs1 = dev1FS();
172
+ let fs2 = dev2FS();
173
+ const COMMA_BYTE = buffer_utils_1.utf8.pack(',');
174
+ const SQ_BRACKET_BYTE = buffer_utils_1.utf8.pack(']');
175
+ const completeContent = [
176
+ {
177
+ type: "addition",
178
+ record: {
179
+ msgId: "F-vo1A4zInEBGq994-e3KvrE9a8QXLcr",
180
+ msgType: "mail",
181
+ deliveryTS: 1664923830399,
182
+ key: "0Uz7wGW4P7hdik7fuStC+avi7iXk7AZ5B1KxJCxIOQk=",
183
+ keyStatus: "published_intro",
184
+ mainObjHeaderOfs: 72,
185
+ removeAfter: 0
186
+ }
187
+ },
188
+ {
189
+ type: "addition",
190
+ record: {
191
+ msgId: "JYXfEEcg3-iX7UDjG3BU0Jha9DYX_Jt-",
192
+ msgType: "mail",
193
+ deliveryTS: 1664923830658,
194
+ key: "gjArW3Mr3ACnoFds/wKFZJm+pp9De1TlNhWIkpyd4Ow=",
195
+ keyStatus: "published_intro",
196
+ mainObjHeaderOfs: 72,
197
+ removeAfter: 0
198
+ }
199
+ }
200
+ ];
201
+ // we do this file writing and uploading, cause this pattern hit an error,
202
+ // hence, we add this test with this seemingly out of the blue setup
203
+ await fs1.writeTxtFile(file, `[]`);
204
+ await fs1.v.sync.upload(file);
205
+ await fs1.v.sync.upload('');
206
+ let sink = await fs1.getByteSink(file, { truncate: false });
207
+ await sink.splice(1, 1);
208
+ let bytes = buffer_utils_1.utf8.pack(JSON.stringify(completeContent[0]));
209
+ await sink.splice(1, 0, bytes);
210
+ await sink.splice(1 + bytes.length, 0, SQ_BRACKET_BYTE);
211
+ await sink.done();
212
+ await fs1.v.sync.upload(file);
213
+ sink = await fs1.getByteSink(file, { truncate: false });
214
+ const len = await sink.getSize();
215
+ await sink.splice(len - 1, 1, COMMA_BYTE);
216
+ bytes = buffer_utils_1.utf8.pack(JSON.stringify(completeContent[1]));
217
+ await sink.splice(len, 0, bytes);
218
+ await sink.splice(len + bytes.length, 0, SQ_BRACKET_BYTE);
219
+ await sink.done();
220
+ expect((0, json_equal_1.deepEqual)(completeContent, await fs1.readJSONFile(file))).toBeTrue();
221
+ await fs1.v.sync.upload(file);
222
+ // and on the second device
223
+ expect((await fs2.v.sync.status('')).state).toBe('behind');
224
+ await fs2.v.sync.adoptRemote('');
225
+ expect((await fs2.v.sync.status(file)).state).toBe('synced');
226
+ expect((0, json_equal_1.deepEqual)(completeContent, await fs2.readJSONFile(file))).toBeTrue();
227
+ };
228
+ exports.specs.its.push(it);
229
+ Object.freeze(exports);
@@ -0,0 +1,34 @@
1
+ import { MultiUserSetup } from "../../libs-for-tests/setups";
2
+ import { SpecIt as GenericSpecIt } from "../../libs-for-tests/spec-module";
3
+ type WritableFS = web3n.files.WritableFS;
4
+ type ReadonlyFS = web3n.files.ReadonlyFS;
5
+ export interface SetupWithTestFS {
6
+ isUp: boolean;
7
+ testFS: web3n.files.WritableFS;
8
+ }
9
+ export type SpecIt = GenericSpecIt<SetupWithTestFS>;
10
+ export declare function clearFS(fs: WritableFS): Promise<void>;
11
+ export interface SetupWithTwoFSs {
12
+ isUp: boolean;
13
+ syncedTestFS: WritableFS;
14
+ localTestFS: WritableFS;
15
+ }
16
+ export type SpecItWithTwoFSs = GenericSpecIt<SetupWithTwoFSs>;
17
+ export interface SetupWithTwoDevsFSs {
18
+ isUp: boolean;
19
+ dev1FS: () => WritableFS;
20
+ dev2: {
21
+ stop(): Promise<void>;
22
+ start(): Promise<void>;
23
+ };
24
+ dev2FS: () => WritableFS;
25
+ resetFS: () => Promise<void>;
26
+ }
27
+ export type SpecItWithTwoDevsFSs = GenericSpecIt<SetupWithTwoDevsFSs>;
28
+ export declare function makeSetupWithTwoDevsFSs(testFolder: string): {
29
+ fsSetup: SetupWithTwoDevsFSs;
30
+ setupDevsAndFSs: (baseSetup: MultiUserSetup) => Promise<void>;
31
+ };
32
+ export declare function observeFolderForOneEvent<T>(fs: ReadonlyFS, path?: string): Promise<T>;
33
+ export declare function observeFileForOneEvent<T>(fs: ReadonlyFS, path: string): Promise<T>;
34
+ export {};