core-3nweb-client-lib 0.26.0 → 0.27.1

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 (199) hide show
  1. package/build/api-defs/asmail.d.ts +1 -1
  2. package/build/api-defs/files.d.ts +278 -69
  3. package/build/core/app-files.js +7 -7
  4. package/build/core/asmail/config/common.js +2 -2
  5. package/build/core/asmail/config/index.js +2 -2
  6. package/build/core/asmail/config/published-intro-key.js +1 -1
  7. package/build/core/asmail/delivery/common.js +7 -7
  8. package/build/core/asmail/delivery/index.js +5 -5
  9. package/build/core/asmail/delivery/msg.js +4 -4
  10. package/build/core/asmail/delivery/per-recipient-wip.js +1 -1
  11. package/build/core/asmail/inbox/attachments/fs.js +5 -1
  12. package/build/core/asmail/inbox/cached-msgs.js +1 -1
  13. package/build/core/asmail/inbox/inbox-events.js +4 -4
  14. package/build/core/asmail/inbox/index.js +10 -10
  15. package/build/core/asmail/inbox/msg-downloader.js +1 -1
  16. package/build/core/asmail/inbox/msg-indexing.js +1 -1
  17. package/build/core/asmail/inbox/msg-on-disk.js +5 -5
  18. package/build/core/asmail/index.d.ts +3 -3
  19. package/build/core/asmail/index.js +13 -8
  20. package/build/core/asmail/key-verification.js +5 -5
  21. package/build/core/asmail/keyring/common.js +7 -6
  22. package/build/core/asmail/keyring/correspondent-keys.js +8 -7
  23. package/build/core/asmail/keyring/id-to-email-map.js +2 -1
  24. package/build/core/asmail/keyring/index.d.ts +7 -8
  25. package/build/core/asmail/keyring/index.js +15 -14
  26. package/build/core/asmail/keyring/keyring-storage.js +2 -1
  27. package/build/core/asmail/msg/opener.js +3 -3
  28. package/build/core/asmail/msg/packer.js +13 -13
  29. package/build/core/asmail/sending-params/own-params.js +2 -2
  30. package/build/core/asmail/sending-params/params-from-others.js +1 -1
  31. package/build/core/id-manager.js +6 -3
  32. package/build/core/index.d.ts +2 -1
  33. package/build/core/index.js +14 -14
  34. package/build/core/sign-in.js +5 -5
  35. package/build/core/sign-up.js +9 -9
  36. package/build/core/storage/common/json-saving.js +2 -2
  37. package/build/core/storage/common/obj-info-file.d.ts +12 -4
  38. package/build/core/storage/common/obj-info-file.js +66 -34
  39. package/build/core/storage/common/utils.d.ts +2 -0
  40. package/build/core/storage/common/utils.js +32 -0
  41. package/build/core/storage/index.d.ts +3 -17
  42. package/build/core/storage/index.js +56 -76
  43. package/build/core/storage/local/obj-files-gc.d.ts +2 -0
  44. package/build/core/storage/local/obj-files-gc.js +49 -37
  45. package/build/core/storage/local/obj-files.d.ts +4 -7
  46. package/build/core/storage/local/obj-files.js +7 -10
  47. package/build/core/storage/local/obj-status.d.ts +12 -6
  48. package/build/core/storage/local/obj-status.js +24 -9
  49. package/build/core/storage/local/storage.d.ts +9 -6
  50. package/build/core/storage/local/storage.js +29 -18
  51. package/build/core/storage/synced/downloader.js +1 -1
  52. package/build/core/storage/synced/obj-files-gc.d.ts +5 -1
  53. package/build/core/storage/synced/obj-files-gc.js +91 -37
  54. package/build/core/storage/synced/obj-files.d.ts +42 -36
  55. package/build/core/storage/synced/obj-files.js +178 -147
  56. package/build/core/storage/synced/obj-status.d.ts +87 -85
  57. package/build/core/storage/synced/obj-status.js +463 -259
  58. package/build/core/storage/synced/remote-events.d.ts +11 -12
  59. package/build/core/storage/synced/remote-events.js +73 -56
  60. package/build/core/storage/synced/storage.d.ts +18 -9
  61. package/build/core/storage/synced/storage.js +108 -48
  62. package/build/core/storage/synced/upload-header-file.d.ts +4 -0
  63. package/build/core/storage/synced/upload-header-file.js +64 -0
  64. package/build/core/storage/synced/upsyncer.d.ts +12 -7
  65. package/build/core/storage/synced/upsyncer.js +204 -280
  66. package/build/core/storage/system-folders/apps-data.d.ts +16 -0
  67. package/build/core/storage/system-folders/apps-data.js +110 -0
  68. package/build/core/storage/system-folders/index.d.ts +18 -0
  69. package/build/core/storage/system-folders/index.js +77 -0
  70. package/build/core-ipc/common-caps.js +3 -3
  71. package/build/core-ipc/generic.js +8 -8
  72. package/build/core-ipc/startup-caps.js +2 -2
  73. package/build/cryptors.js +6 -2
  74. package/build/ipc-via-protobuf/asmail-cap.js +58 -57
  75. package/build/ipc-via-protobuf/bytes.js +16 -17
  76. package/build/ipc-via-protobuf/connector-clients-side.d.ts +3 -0
  77. package/build/ipc-via-protobuf/connector-clients-side.js +61 -24
  78. package/build/ipc-via-protobuf/connector-services-side.js +10 -10
  79. package/build/ipc-via-protobuf/connector.js +4 -4
  80. package/build/ipc-via-protobuf/file.d.ts +48 -12
  81. package/build/ipc-via-protobuf/file.js +474 -126
  82. package/build/ipc-via-protobuf/fs.d.ts +8 -0
  83. package/build/ipc-via-protobuf/fs.js +577 -142
  84. package/build/ipc-via-protobuf/log-cap.js +2 -2
  85. package/build/ipc-via-protobuf/mailerid.js +3 -3
  86. package/build/ipc-via-protobuf/protobuf-msg.d.ts +1 -0
  87. package/build/ipc-via-protobuf/protobuf-msg.js +11 -7
  88. package/build/ipc-via-protobuf/startup-cap.js +21 -21
  89. package/build/ipc-via-protobuf/storage-cap.js +12 -12
  90. package/build/ipc.js +7 -2
  91. package/build/lib-client/3nstorage/exceptions.d.ts +3 -0
  92. package/build/lib-client/3nstorage/exceptions.js +13 -1
  93. package/build/lib-client/3nstorage/service.d.ts +15 -2
  94. package/build/lib-client/3nstorage/service.js +104 -38
  95. package/build/lib-client/3nstorage/util/file-based-json.d.ts +2 -1
  96. package/build/lib-client/3nstorage/util/file-based-json.js +1 -1
  97. package/build/lib-client/3nstorage/xsp-fs/attrs.js +17 -17
  98. package/build/lib-client/3nstorage/xsp-fs/common.d.ts +42 -18
  99. package/build/lib-client/3nstorage/xsp-fs/common.js +29 -19
  100. package/build/lib-client/3nstorage/xsp-fs/file-node.d.ts +1 -0
  101. package/build/lib-client/3nstorage/xsp-fs/file-node.js +17 -13
  102. package/build/lib-client/3nstorage/xsp-fs/file.d.ts +31 -6
  103. package/build/lib-client/3nstorage/xsp-fs/file.js +73 -25
  104. package/build/lib-client/3nstorage/xsp-fs/folder-node-serialization.js +4 -4
  105. package/build/lib-client/3nstorage/xsp-fs/folder-node.d.ts +24 -11
  106. package/build/lib-client/3nstorage/xsp-fs/folder-node.js +575 -179
  107. package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +35 -4
  108. package/build/lib-client/3nstorage/xsp-fs/fs.js +231 -110
  109. package/build/lib-client/3nstorage/xsp-fs/link-node.d.ts +1 -0
  110. package/build/lib-client/3nstorage/xsp-fs/link-node.js +7 -2
  111. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +30 -24
  112. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +229 -123
  113. package/build/lib-client/3nstorage/xsp-fs/node-persistence.d.ts +1 -1
  114. package/build/lib-client/3nstorage/xsp-fs/node-persistence.js +17 -18
  115. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +3 -3
  116. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.js +53 -53
  117. package/build/lib-client/3nweb-signup.js +4 -4
  118. package/build/lib-client/asmail/recipient.js +15 -15
  119. package/build/lib-client/asmail/sender.js +22 -22
  120. package/build/lib-client/asmail/service-config.js +3 -3
  121. package/build/lib-client/cryptor/cryptor-in-worker.js +18 -16
  122. package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
  123. package/build/lib-client/cryptor/cryptor.js +4 -2
  124. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  125. package/build/lib-client/cryptor/in-proc-js.js +1 -1
  126. package/build/lib-client/cryptor/in-proc-wasm.js +6 -6
  127. package/build/lib-client/cryptor/worker-js.js +2 -2
  128. package/build/lib-client/cryptor/worker-wasm.js +2 -2
  129. package/build/lib-client/files-select.js +1 -1
  130. package/build/lib-client/files.d.ts +1 -1
  131. package/build/lib-client/files.js +71 -6
  132. package/build/lib-client/fs-collection.js +1 -1
  133. package/build/lib-client/fs-sync-utils.d.ts +5 -0
  134. package/build/lib-client/fs-sync-utils.js +61 -0
  135. package/build/lib-client/fs-view.d.ts +14 -0
  136. package/build/lib-client/fs-view.js +33 -0
  137. package/build/lib-client/key-derivation.js +1 -1
  138. package/build/lib-client/local-files/dev-file-sink.js +9 -9
  139. package/build/lib-client/local-files/dev-file-src.js +2 -2
  140. package/build/lib-client/local-files/device-fs.d.ts +1 -1
  141. package/build/lib-client/local-files/device-fs.js +56 -54
  142. package/build/lib-client/logging/log-to-file.d.ts +1 -1
  143. package/build/lib-client/logging/log-to-file.js +7 -7
  144. package/build/lib-client/mailer-id/login.js +7 -7
  145. package/build/lib-client/mailer-id/provisioner.js +12 -12
  146. package/build/lib-client/objs-on-disk/file-writing-proc.js +3 -3
  147. package/build/lib-client/objs-on-disk/obj-folders.js +31 -31
  148. package/build/lib-client/objs-on-disk/obj-on-disk.d.ts +13 -2
  149. package/build/lib-client/objs-on-disk/obj-on-disk.js +24 -9
  150. package/build/lib-client/request-utils.d.ts +1 -0
  151. package/build/lib-client/request-utils.js +13 -13
  152. package/build/lib-client/server-events.d.ts +3 -3
  153. package/build/lib-client/server-events.js +9 -8
  154. package/build/lib-client/service-locator.js +10 -10
  155. package/build/lib-client/user-with-mid-session.js +7 -7
  156. package/build/lib-client/user-with-pkl-session.js +25 -25
  157. package/build/lib-client/ws-utils.js +2 -2
  158. package/build/lib-common/async-cryptor-wrap.js +4 -4
  159. package/build/lib-common/async-fs-node.d.ts +5 -3
  160. package/build/lib-common/async-fs-node.js +16 -16
  161. package/build/lib-common/byte-streaming/pipe.js +1 -1
  162. package/build/lib-common/byte-streaming/wrapping.js +13 -13
  163. package/build/lib-common/canonical-address.js +1 -1
  164. package/build/lib-common/exceptions/error.d.ts +1 -0
  165. package/build/lib-common/exceptions/error.js +7 -6
  166. package/build/lib-common/exceptions/file.js +4 -0
  167. package/build/lib-common/ipc/ws-ipc.js +2 -2
  168. package/build/lib-common/mid-sigs-NaCl-Ed.js +14 -14
  169. package/build/lib-common/objs-on-disk/file-layout.d.ts +19 -0
  170. package/build/lib-common/objs-on-disk/file-layout.js +130 -12
  171. package/build/lib-common/objs-on-disk/obj-file.d.ts +13 -2
  172. package/build/lib-common/objs-on-disk/obj-file.js +96 -35
  173. package/build/lib-common/objs-on-disk/utils.d.ts +1 -0
  174. package/build/lib-common/objs-on-disk/utils.js +3 -3
  175. package/build/lib-common/objs-on-disk/v1-obj-file-format.js +14 -14
  176. package/build/lib-common/processes/labelled-exec-pools.d.ts +1 -1
  177. package/build/lib-common/processes/labelled-exec-pools.js +1 -1
  178. package/build/lib-common/processes/pressure.js +2 -2
  179. package/build/lib-common/processes/synced.js +1 -1
  180. package/build/lib-common/processes/timeout.js +2 -2
  181. package/build/lib-common/random-node.js +7 -7
  182. package/build/lib-common/service-api/3nstorage/owner.d.ts +95 -39
  183. package/build/lib-common/service-api/3nstorage/owner.js +82 -40
  184. package/build/lib-common/service-api/asmail/delivery.js +2 -2
  185. package/build/lib-common/service-api/asmail/retrieval.js +1 -1
  186. package/build/lib-common/timed-cache.d.ts +1 -0
  187. package/build/lib-common/timed-non-weak-cache.d.ts +1 -0
  188. package/build/lib-common/timed-non-weak-cache.js +11 -0
  189. package/build/lib-common/utils-for-observables.js +4 -4
  190. package/build/lib-common/weak-cache.d.ts +1 -0
  191. package/build/lib-common/weak-cache.js +12 -1
  192. package/build/lib-index.d.ts +2 -1
  193. package/build/lib-index.js +10 -7
  194. package/build/protos/asmail.proto.js +12955 -7496
  195. package/build/protos/file.proto.js +4867 -2744
  196. package/build/protos/fs.proto.js +9227 -3768
  197. package/package.json +6 -5
  198. package/protos/file.proto +91 -19
  199. package/protos/fs.proto +107 -8
@@ -21,103 +21,163 @@ const path_1 = require("path");
21
21
  const exceptions_1 = require("../../../lib-client/3nstorage/exceptions");
22
22
  const json_saving_1 = require("../common/json-saving");
23
23
  const obj_info_file_1 = require("../common/obj-info-file");
24
- const json_utils_1 = require("../../../lib-common/json-utils");
24
+ const assert_1 = require("../../../lib-common/assert");
25
+ function makeVersions() {
26
+ return {
27
+ baseToDiff: {},
28
+ diffToBase: {},
29
+ };
30
+ }
31
+ function makeObjStatusInfo(objId) {
32
+ return {
33
+ objId,
34
+ remote: makeVersions()
35
+ };
36
+ }
37
+ function syncStateOf({ local, synced, remote }) {
38
+ const syncedIsCurrent = isSyncedCurrentWithRemote(synced, remote);
39
+ if (local) {
40
+ switch (syncedIsCurrent) {
41
+ case undefined:
42
+ case true:
43
+ return ((local.isArchived && (synced === null || synced === void 0 ? void 0 : synced.isArchived)) ?
44
+ 'synced' : 'unsynced');
45
+ case false:
46
+ return 'conflicting';
47
+ }
48
+ }
49
+ else {
50
+ switch (syncedIsCurrent) {
51
+ case undefined:
52
+ return 'unsynced';
53
+ case true:
54
+ return 'synced';
55
+ case false:
56
+ return 'behind';
57
+ }
58
+ }
59
+ }
60
+ function isSyncedCurrentWithRemote(synced, remote) {
61
+ if (synced) {
62
+ return ((synced.version === remote.current)
63
+ && (synced.isArchived === remote.isArchived));
64
+ }
65
+ else {
66
+ return (isRemoteEmpty(remote) ? undefined : false);
67
+ }
68
+ }
69
+ function isRemoteEmpty(remote) {
70
+ return (0, obj_info_file_1.isEmptyVersions)(remote) && !remote.isArchived;
71
+ }
72
+ function nonGarbageWithMaxVer(v) {
73
+ return {
74
+ gcMaxVer: v.current,
75
+ nonGarbage: (0, obj_info_file_1.nonGarbageVersionsIn)(v)
76
+ };
77
+ }
78
+ function identifyNonGarbage(status) {
79
+ var _a;
80
+ let local = undefined;
81
+ let uploadVersion = undefined;
82
+ if (status.local) {
83
+ local = nonGarbageWithMaxVer(status.local);
84
+ if (status.local.upload) {
85
+ const { localVersion } = status.local.upload;
86
+ if (status.local.current !== localVersion) {
87
+ (0, obj_info_file_1.addWithBasesTo)(local.nonGarbage, localVersion, status.local);
88
+ }
89
+ uploadVersion = status.local.upload.uploadVersion;
90
+ }
91
+ }
92
+ const remote = nonGarbageWithMaxVer(status.remote);
93
+ if ((_a = status.synced) === null || _a === void 0 ? void 0 : _a.version) {
94
+ remote.nonGarbage.add(status.synced.version);
95
+ if (status.synced.base) {
96
+ (0, obj_info_file_1.addWithBasesTo)(remote.nonGarbage, status.synced.base, status.remote);
97
+ }
98
+ }
99
+ return { local, remote, uploadVersion };
100
+ }
25
101
  exports.STATUS_FILE_NAME = 'status';
26
102
  class ObjStatus {
27
103
  constructor(objFolder, status, logError) {
28
104
  this.objFolder = objFolder;
29
105
  this.status = status;
30
106
  this.logError = logError;
31
- this.saveProc = new json_saving_1.JSONSavingProc(path_1.join(this.objFolder, exports.STATUS_FILE_NAME), () => this.status);
32
- Object.freeze(this);
107
+ this.saveProc = new json_saving_1.JSONSavingProc((0, path_1.join)(this.objFolder, exports.STATUS_FILE_NAME), () => this.status);
108
+ this.updateStateIndicator();
109
+ Object.seal(this);
33
110
  }
34
111
  static async readFrom(objFolder, objId, logError) {
35
112
  const status = await readAndCheckStatus(objFolder, objId);
36
113
  return new ObjStatus(objFolder, status, logError);
37
114
  }
38
115
  static async makeNew(objFolder, objId, logError) {
39
- const status = {
40
- objId,
41
- sync: {
42
- state: 'unsynced'
43
- },
44
- versions: {
45
- baseToDiff: {},
46
- diffToBase: {},
47
- }
48
- };
116
+ const status = makeObjStatusInfo(objId);
49
117
  const s = new ObjStatus(objFolder, status, logError);
50
118
  await s.triggerSaveProc();
51
119
  return s;
52
120
  }
53
121
  static async makeForDownloadedVersion(objFolder, objId, version, currentRemote, logError) {
54
- const status = {
55
- objId,
56
- sync: {
57
- state: 'synced',
58
- remote: currentRemote,
59
- latest: currentRemote,
60
- },
61
- versions: {
62
- current: version,
63
- baseToDiff: {},
64
- diffToBase: {}
65
- }
66
- };
122
+ const status = makeObjStatusInfo(objId);
123
+ status.remote.current = currentRemote;
124
+ status.synced = { version: currentRemote };
125
+ if (currentRemote > version) {
126
+ status.remote.archived = [version];
127
+ }
128
+ else if (currentRemote !== version) {
129
+ throw new Error(`Downloaded version can't be greater than current remote`);
130
+ }
67
131
  const s = new ObjStatus(objFolder, status, logError);
68
132
  await s.triggerSaveProc();
69
133
  return s;
70
134
  }
71
135
  static async fileShowsObjNotInSyncedState(objFolder, objId) {
72
136
  const status = await readAndCheckStatus(objFolder, objId);
73
- return (status.sync.state !== 'synced');
137
+ return (syncStateOf(status) !== 'synced');
138
+ }
139
+ updateStateIndicator() {
140
+ this.stateIndicator = syncStateOf(this.status);
74
141
  }
75
142
  isArchived() {
76
- return !!this.status.isArchived;
143
+ var _a;
144
+ return !!((_a = this.status.local) === null || _a === void 0 ? void 0 : _a.isArchived);
77
145
  }
78
- getCurrentVersionOrThrow() {
79
- if (typeof this.status.versions.current !== 'number') {
80
- throw new Error(`Object ${this.status.objId} has no current version.`);
146
+ getCurrentLocalOrSynced() {
147
+ var _a, _b;
148
+ const state = this.stateIndicator;
149
+ const current = (((state === 'unsynced') || (state === 'conflicting')) ?
150
+ (_a = this.status.local) === null || _a === void 0 ? void 0 : _a.current : (_b = this.status.synced) === null || _b === void 0 ? void 0 : _b.version);
151
+ if (current) {
152
+ return current;
81
153
  }
82
- return this.status.versions.current;
83
- }
84
- getNonGarbageVersions() {
85
- const versions = this.status.versions;
86
- const nonGarbage = obj_info_file_1.nonGarbageVersionsIn(versions);
87
- if (this.status.syncTasks) {
88
- const tasks = this.status.syncTasks;
89
- if (tasks.current) {
90
- obj_info_file_1.addWithBasesTo(nonGarbage, nonGarbageVersionInTask(tasks.current), versions);
91
- }
92
- for (const t of tasks.queued) {
93
- obj_info_file_1.addWithBasesTo(nonGarbage, nonGarbageVersionInTask(t), versions);
94
- }
154
+ else {
155
+ throw (0, exceptions_1.makeStorageException)({
156
+ objNotFound: true,
157
+ message: 'Current version is not found'
158
+ });
95
159
  }
96
- return {
97
- nonGarbage,
98
- gcMaxVer: versions.current
99
- };
100
160
  }
101
- isRemoteVersionGreaterOrEqualTo(newRemoteVersion) {
102
- return ((typeof this.status.sync.remote === 'number') ?
103
- (this.status.sync.remote >= newRemoteVersion) : false);
104
- }
105
- isDeletedOnRemote() {
106
- return !!this.status.sync.deletedOnRemote;
107
- }
108
- syncedVersionGreaterOrEqual(version) {
109
- return ((typeof this.status.sync.latest !== 'number') ?
110
- false : (version <= this.status.sync.latest));
161
+ getNonGarbageVersions() {
162
+ return identifyNonGarbage(this.status);
111
163
  }
112
- async removeCurrentVersion(verObjs) {
113
- this.status.isArchived = true;
114
- const current = obj_info_file_1.rmCurrentVersionIn(this.status.versions);
115
- if (typeof current === 'number') {
116
- verObjs.delete(current);
164
+ async removeCurrentVersion() {
165
+ let { local, synced } = this.status;
166
+ if ((synced === null || synced === void 0 ? void 0 : synced.isArchived) || (local === null || local === void 0 ? void 0 : local.isArchived)) {
167
+ return;
117
168
  }
118
- this.addRemoveCurrentToQueue();
169
+ if (local) {
170
+ (0, obj_info_file_1.rmCurrentVersionIn)(local);
171
+ }
172
+ else {
173
+ local = makeVersions();
174
+ }
175
+ local.isArchived = true;
176
+ this.updateStateIndicator();
177
+ ;
119
178
  await this.triggerSaveProc().catch((exc) => {
120
- if (exc.notFound && this.status.isArchived) {
179
+ var _a;
180
+ if (exc.notFound && ((_a = this.status.local) === null || _a === void 0 ? void 0 : _a.isArchived)) {
121
181
  return;
122
182
  }
123
183
  else {
@@ -140,256 +200,400 @@ class ObjStatus {
140
200
  }
141
201
  }
142
202
  }
143
- async setDeletedOnRemote() {
144
- this.status.sync.deletedOnRemote = true;
145
- await this.triggerSaveProc();
203
+ recordUploadStart(info) {
204
+ (0, assert_1.assert)(!!this.status.local);
205
+ const local = this.status.local;
206
+ if (local.upload) {
207
+ throw (0, exceptions_1.makeFSSyncException)('obj-status', {
208
+ alreadyUploading: true,
209
+ message: `Status already has upload of version ${local.upload.uploadVersion} and can't start another upload with version ${info.uploadVersion}`
210
+ });
211
+ }
212
+ if (info.localVersion === local.current) {
213
+ local.upload = info;
214
+ }
215
+ else {
216
+ throw (0, exceptions_1.makeFSSyncException)('obj-status', {
217
+ localVersion: info.localVersion,
218
+ versionNotFound: true
219
+ });
220
+ }
221
+ return this.triggerSaveProc();
222
+ }
223
+ recordUploadInterimState(info) {
224
+ (0, assert_1.assert)(!!this.status.local);
225
+ const local = this.status.local;
226
+ (0, assert_1.assert)(!!local.upload &&
227
+ (local.upload.uploadVersion === info.uploadVersion));
228
+ local.upload = info;
229
+ return this.triggerSaveProc();
230
+ }
231
+ recordUploadCancellation(info) {
232
+ (0, assert_1.assert)(!!this.status.local);
233
+ const local = this.status.local;
234
+ (0, assert_1.assert)(!!local.upload &&
235
+ (local.upload.uploadVersion === info.uploadVersion));
236
+ local.upload = undefined;
237
+ return this.triggerSaveProc();
238
+ }
239
+ async recordArchVersionRemoval(version) {
240
+ if ((0, obj_info_file_1.rmArchVersionFrom)(this.status.remote, version)) {
241
+ return this.triggerSaveProc();
242
+ }
243
+ }
244
+ async recordVersionArchival(version) {
245
+ if ((0, obj_info_file_1.addArchived)(this.status.remote, version)) {
246
+ return this.triggerSaveProc();
247
+ }
248
+ }
249
+ async recordRemoteRemoval() {
250
+ const { local, synced, remote } = this.status;
251
+ if ((local === null || local === void 0 ? void 0 : local.isArchived) || (synced === null || synced === void 0 ? void 0 : synced.isArchived)) {
252
+ return;
253
+ }
254
+ remote.isArchived = true;
255
+ (0, obj_info_file_1.rmCurrentVersionIn)(remote);
256
+ this.updateStateIndicator();
257
+ return this.triggerSaveProc();
146
258
  }
147
- async setRemoteVersion(version) {
148
- if (this.status.sync.remote >= version) {
259
+ async recordRemoteChange(version) {
260
+ const { local, synced, remote } = this.status;
261
+ if (((local === null || local === void 0 ? void 0 : local.upload) && (local.upload.uploadVersion === version))
262
+ || ((synced === null || synced === void 0 ? void 0 : synced.version) && (synced.version >= version))) {
149
263
  return;
150
264
  }
151
- this.status.sync.remote = version;
152
- if (this.status.sync.state === 'synced') {
153
- if (this.status.versions.current < this.status.sync.remote) {
154
- this.status.sync.state = 'behind';
265
+ remote.current = version;
266
+ this.updateStateIndicator();
267
+ return this.triggerSaveProc();
268
+ }
269
+ recordSyncOfObjRemoval() {
270
+ this.status.local = undefined;
271
+ (0, obj_info_file_1.rmCurrentVersionIn)(this.status.remote);
272
+ this.status.remote.isArchived = true;
273
+ if (this.status.synced) {
274
+ this.status.synced.isArchived = true;
275
+ this.status.synced.version = undefined;
276
+ if (this.status.synced.base) {
277
+ (0, obj_info_file_1.rmNonArchVersionsIn)(this.status.remote, this.status.synced.base);
278
+ this.status.synced.base = undefined;
155
279
  }
156
280
  }
157
- else if (this.status.sync.state === 'unsynced') {
158
- this.status.sync.state = 'conflicting';
159
- }
160
- await this.triggerSaveProc();
161
- }
162
- async markVersionSynced(version) {
163
- if (!this.status.sync.latest
164
- || (this.status.sync.latest < version)) {
165
- this.status.sync.latest = version;
166
- if (this.status.versions.current === version) {
167
- this.status.sync.state = 'synced';
281
+ else {
282
+ this.status.synced = { isArchived: true };
283
+ }
284
+ this.updateStateIndicator();
285
+ return this.triggerSaveProc();
286
+ }
287
+ async recordStatusFromServer({ archived, current }) {
288
+ const remote = this.status.remote;
289
+ let changedCurrent = false;
290
+ if (current) {
291
+ if (!remote.current) {
292
+ remote.current = current;
293
+ changedCurrent = true;
168
294
  }
295
+ else if (remote.current < current) {
296
+ (0, obj_info_file_1.rmCurrentVersionIn)(remote);
297
+ remote.current = current;
298
+ changedCurrent = true;
299
+ }
300
+ }
301
+ else if (remote.current) {
302
+ (0, obj_info_file_1.rmCurrentVersionIn)(remote);
303
+ remote.isArchived = true;
304
+ changedCurrent = true;
305
+ }
306
+ const rmArchived = removeArchVersionsNotInList(remote, archived);
307
+ const addedArchived = addArchVersionsFromList(remote, archived);
308
+ if (rmArchived || addedArchived || changedCurrent) {
309
+ this.updateStateIndicator();
169
310
  await this.triggerSaveProc();
170
311
  }
171
312
  }
172
- async setUnsyncedCurrentVersion(version, baseVer) {
173
- obj_info_file_1.setCurrentVersionIn(this.status.versions, version, baseVer);
174
- this.status.sync.state = 'unsynced';
175
- await this.triggerSaveProc();
176
- }
177
313
  /**
178
- * This method ignores remote conflicting versions.
179
- * @param version
314
+ * When given object version is a diff on some base, this method returns
315
+ * a whole trace of local base versions up to synced one.
316
+ * Local bases, if present, are return in an array with highest version
317
+ * first.
318
+ * This returns undefined, when given object version is not a diff.
319
+ * @param version that is local, for which we want to get base versions, if
320
+ * it is a diff version.
180
321
  */
181
- isVersionSynced(version) {
182
- if (this.status.versions.current === undefined) {
183
- return false;
184
- }
185
- if (this.status.sync.state == 'synced') {
186
- return true;
322
+ baseOfLocalVersion(version) {
323
+ (0, assert_1.assert)(!!this.status.local);
324
+ const local = this.status.local;
325
+ (0, assert_1.assert)((0, obj_info_file_1.isVersionIn)(version, local));
326
+ let base = local.diffToBase[version];
327
+ if (!base) {
328
+ return;
187
329
  }
188
- if (this.status.sync.latest === undefined) {
189
- return false;
330
+ if ((0, obj_info_file_1.isVersionIn)(base, this.status.remote)) {
331
+ return { syncedBase: base };
332
+ }
333
+ const localBases = [];
334
+ do {
335
+ localBases.push(base);
336
+ base = local.diffToBase[base];
337
+ } while (base);
338
+ const lastBase = localBases[localBases.length - 1];
339
+ if ((0, obj_info_file_1.isVersionIn)(lastBase, this.status.remote)) {
340
+ return {
341
+ localBases: localBases.slice(0, localBases.length - 1),
342
+ syncedBase: lastBase
343
+ };
190
344
  }
191
- return (this.status.sync.latest >= version);
192
- }
193
- isVersionArchived(version) {
194
- if (!this.status.versions.archived) {
195
- return false;
345
+ else {
346
+ return { localBases };
196
347
  }
197
- return this.status.versions.archived.includes(version);
198
348
  }
199
- queueTask(t) {
200
- if (t.type === 'upload') {
201
- this.addUploadToQueue(t);
349
+ markLocalVersionSynced(localVersion, uploadVersion) {
350
+ const { local, synced, remote } = this.status;
351
+ (0, assert_1.assert)(!!(local === null || local === void 0 ? void 0 : local.upload) &&
352
+ ((local === null || local === void 0 ? void 0 : local.upload.uploadVersion) === uploadVersion));
353
+ const syncedBase = local.upload.baseVersion;
354
+ if (!remote.current || (remote.current <= uploadVersion)) {
355
+ (0, obj_info_file_1.setCurrentVersionIn)(remote, uploadVersion, syncedBase);
202
356
  }
203
- else if (t.type === 'removal') {
204
- if (t.currentVersion) {
205
- throw new Error(`Removal of current task needs other method`);
357
+ if (synced) {
358
+ synced.version = uploadVersion;
359
+ if (synced.base && (synced.base !== syncedBase)) {
360
+ (0, obj_info_file_1.rmNonArchVersionsIn)(remote, synced.base);
206
361
  }
207
- else if (t.archivedVersions) {
208
- this.addRemoveArchivedToQueue(t.archivedVersions);
209
- }
210
- }
211
- else if (t.type === 'archiving') {
212
- this.addArchivalToQueue(t);
362
+ synced.base = syncedBase;
213
363
  }
214
364
  else {
215
- throw new Error(`Unsupported upsync task type`);
365
+ this.status.synced = { version: uploadVersion, base: syncedBase };
216
366
  }
217
- }
218
- addUploadToQueue(u) {
219
- if (!this.status.syncTasks) {
220
- this.status.syncTasks = { queued: [u] };
367
+ if (local.current === localVersion) {
368
+ this.status.local = undefined;
221
369
  }
222
370
  else {
223
- const q = this.status.syncTasks.queued;
224
- const last = lastIn(q);
225
- if (last) {
226
- if (last.type === 'upload') {
227
- if (!this.isVersionArchived(last.version)) {
228
- if (last.createObj) {
229
- u.createObj = true;
230
- }
231
- q[q.length - 1] = u;
232
- }
233
- else {
234
- q.push(u);
235
- }
236
- }
237
- else if (last.type === 'archiving') {
238
- q.push(u);
239
- }
240
- else if ((last.type === 'removal') && last.archivedVersions) {
241
- q.push(u);
242
- }
243
- }
244
- else {
245
- q.push(u);
246
- }
371
+ local.upload = undefined;
247
372
  }
248
- this.triggerSaveProc(true);
373
+ this.updateStateIndicator();
374
+ return this.triggerSaveProc();
249
375
  }
250
- addRemoveCurrentToQueue() {
251
- const r = { type: 'removal', currentVersion: true };
252
- if (this.status.syncTasks) {
253
- const q = this.status.syncTasks.queued;
254
- const last = lastIn(q);
255
- if (last) {
256
- if (last.type === 'archiving') {
257
- q.push(r);
258
- }
259
- else if (last.type === 'upload') {
260
- if (this.isVersionArchived(last.version)) {
261
- q.push(r);
262
- }
263
- else if (this.status.sync.latest
264
- || this.status.syncTasks.current) {
265
- q[q.length - 1] = r;
266
- }
267
- else {
268
- q.splice(q.length - 1, 1);
269
- this.addRemoveCurrentToQueue();
270
- return;
271
- }
272
- }
273
- }
274
- else if (this.status.sync.latest
275
- || this.status.syncTasks.current) {
276
- q.push(r);
277
- }
278
- else {
279
- this.status.syncTasks = undefined;
280
- }
281
- }
282
- else {
283
- if (this.status.sync.latest) {
284
- this.status.syncTasks = { queued: [r] };
285
- }
376
+ async setLocalCurrentVersion(version, baseVer) {
377
+ if (!this.status.local) {
378
+ this.status.local = makeVersions();
286
379
  }
380
+ (0, obj_info_file_1.setCurrentVersionIn)(this.status.local, version, baseVer);
381
+ this.updateStateIndicator();
382
+ await this.triggerSaveProc();
287
383
  }
288
- addRemoveArchivedToQueue(archVer) {
289
- const r = { type: 'removal', archivedVersions: archVer };
290
- if (this.status.syncTasks) {
291
- this.status.syncTasks.queued.push(r);
292
- }
293
- else {
294
- this.status.syncTasks = { queued: [r] };
295
- }
296
- this.triggerSaveProc(true);
384
+ listVersions() {
385
+ var _a;
386
+ const { local, synced, remote } = this.status;
387
+ switch (this.stateIndicator) {
388
+ case 'unsynced':
389
+ case 'conflicting':
390
+ (0, assert_1.assert)(!!local);
391
+ return {
392
+ current: local.current,
393
+ archived: ((synced === null || synced === void 0 ? void 0 : synced.version) ?
394
+ versionsToBranch(remote, synced.version, false).archived :
395
+ undefined)
396
+ };
397
+ case 'synced':
398
+ case 'behind':
399
+ (0, assert_1.assert)(!!synced);
400
+ return {
401
+ current: synced.version,
402
+ archived: ((synced === null || synced === void 0 ? void 0 : synced.version) ?
403
+ versionsToBranch(remote, synced.version, false).archived :
404
+ (_a = remote.archived) === null || _a === void 0 ? void 0 : _a.slice())
405
+ };
406
+ default:
407
+ throw new Error(`Unimplemented state ${this.stateIndicator}`);
408
+ }
409
+ }
410
+ async archiveCurrentVersion() {
411
+ const { synced, remote } = this.status;
412
+ (0, assert_1.assert)(!!(synced === null || synced === void 0 ? void 0 : synced.version));
413
+ (0, obj_info_file_1.addArchived)(remote, synced.version);
414
+ await this.triggerSaveProc();
297
415
  }
298
- addArchivalToQueue(a) {
299
- if (!this.status.syncTasks) {
300
- this.status.syncTasks = { queued: [a] };
416
+ absorbLocalVersionBase(version, localBase) {
417
+ (0, assert_1.assert)(!!this.status.local);
418
+ const local = this.status.local;
419
+ (0, assert_1.assert)(local.diffToBase[version] === localBase);
420
+ const lowerBase = local.diffToBase[localBase];
421
+ if (localBase) {
422
+ local.diffToBase[version] = lowerBase;
423
+ local.baseToDiff[lowerBase] = version;
301
424
  }
302
425
  else {
303
- this.status.syncTasks.queued.push(a);
426
+ delete local.diffToBase[version];
304
427
  }
305
- this.triggerSaveProc(true);
428
+ delete local.diffToBase[localBase];
429
+ delete local.baseToDiff[localBase];
430
+ return this.triggerSaveProc();
306
431
  }
307
- async getTaskForProcessing() {
308
- const syncTasks = this.status.syncTasks;
309
- if (!syncTasks) {
310
- return;
311
- }
312
- if (syncTasks.current) {
313
- return syncTasks.current;
314
- }
315
- syncTasks.current = syncTasks.queued.shift();
316
- if (syncTasks.current) {
317
- await this.triggerSaveProc();
318
- }
319
- return syncTasks.current;
432
+ latestSyncedVersion() {
433
+ var _a;
434
+ return (_a = this.status.synced) === null || _a === void 0 ? void 0 : _a.version;
320
435
  }
321
- glanceOnNextTask() {
322
- const syncTasks = this.status.syncTasks;
323
- if (!syncTasks) {
324
- return;
325
- }
326
- if (syncTasks.current) {
327
- return syncTasks.current;
328
- }
329
- else if (syncTasks.queued.length > 0) {
330
- return syncTasks.queued[0];
331
- }
436
+ syncStatus() {
437
+ const { remote, synced } = splitVersionsIntoBranches(this.status.remote, this.status.synced);
438
+ return {
439
+ state: this.stateIndicator,
440
+ local: localVersionFromStatus(this.status.local),
441
+ remote,
442
+ synced
443
+ };
332
444
  }
333
- async recordInterimStateOfCurrentTask(t) {
334
- const syncTasks = this.status.syncTasks;
335
- if (!syncTasks) {
336
- throw new Error(`This method is called too early.`);
337
- }
338
- if (syncTasks.current === t) {
339
- await this.triggerSaveProc();
340
- }
341
- else {
342
- throw new Error(`Can save interim state of a current task only`);
343
- }
445
+ neverUploaded() {
446
+ const synced = this.status.synced;
447
+ return (!(synced === null || synced === void 0 ? void 0 : synced.version) && !(synced === null || synced === void 0 ? void 0 : synced.isArchived));
344
448
  }
345
- async recordTaskCompletion(t) {
346
- const syncTasks = this.status.syncTasks;
347
- if (!syncTasks) {
348
- throw new Error(`This method is called too early.`);
449
+ async adoptRemoteVersion(version, dropLocalVer = false) {
450
+ var _a;
451
+ const { local, remote } = this.status;
452
+ if (this.stateIndicator !== 'behind') {
453
+ if (this.stateIndicator === 'synced') {
454
+ return;
455
+ }
456
+ else if (!dropLocalVer) {
457
+ throw (0, exceptions_1.makeFSSyncException)('', {
458
+ localVersion: local === null || local === void 0 ? void 0 : local.current,
459
+ remoteVersion: remote.current,
460
+ conflict: true,
461
+ message: `Can't adopt remote version in '${this.stateIndicator}' state`
462
+ });
463
+ }
349
464
  }
350
- if (syncTasks.current === t) {
351
- if (syncTasks.queued.length > 0) {
352
- syncTasks.current = undefined;
465
+ if (version) {
466
+ if ((remote.current === version)
467
+ || ((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(version))) {
468
+ this.status.synced = { version, base: remote.diffToBase[version] };
353
469
  }
354
470
  else {
355
- this.status.syncTasks = undefined;
471
+ throw (0, exceptions_1.makeFSSyncException)('', {
472
+ remoteVersion: remote.current,
473
+ versionNotFound: true,
474
+ message: `Remote version ${version} is not in status info`
475
+ });
356
476
  }
357
- await this.triggerSaveProc();
358
477
  }
359
- }
360
- isSyncDone() {
361
- return !this.status.syncTasks;
362
- }
363
- isFileSaved() {
364
- return this.saveProc.isSaved();
365
- }
366
- stat() {
367
- return json_utils_1.copy(this.status.sync);
478
+ else if (remote.current) {
479
+ version = remote.current;
480
+ this.status.synced = { version, base: remote.diffToBase[version] };
481
+ }
482
+ else {
483
+ throw (0, exceptions_1.makeFSSyncException)('', {
484
+ versionMismatch: true,
485
+ message: `Current remote version is not set in status info`
486
+ });
487
+ }
488
+ if (local) {
489
+ this.status.local = undefined;
490
+ }
491
+ this.updateStateIndicator();
492
+ await this.triggerSaveProc();
368
493
  }
369
494
  }
370
495
  exports.ObjStatus = ObjStatus;
371
496
  Object.freeze(ObjStatus.prototype);
372
497
  Object.freeze(ObjStatus);
373
498
  async function readAndCheckStatus(objFolder, objId) {
374
- const status = await obj_info_file_1.readJSONInfoFileIn(objFolder, exports.STATUS_FILE_NAME);
499
+ const status = await (0, obj_info_file_1.readJSONInfoFileIn)(objFolder, exports.STATUS_FILE_NAME);
375
500
  if (!status) {
376
- throw exceptions_1.makeStorageException({
501
+ throw (0, exceptions_1.makeStorageException)({
377
502
  message: `Obj status file is not found in obj folder ${objFolder}`
378
503
  });
379
504
  }
380
505
  // XXX we may do some checks and sanitization here
381
506
  if (objId !== status.objId) {
382
- throw exceptions_1.makeStorageException({ message: `Invalid objId in status file for obj ${objId}, in folder ${objFolder}.\nInvalid content:\n${JSON.stringify(status, null, 2)}` });
507
+ throw (0, exceptions_1.makeStorageException)({
508
+ message: `Invalid objId in status file for obj ${objId}, in folder ${objFolder}.\nInvalid content:\n${JSON.stringify(status, null, 2)}`
509
+ });
383
510
  }
384
511
  return status;
385
512
  }
386
513
  exports.readAndCheckStatus = readAndCheckStatus;
387
- function lastIn(arr) {
388
- return ((arr.length > 0) ? arr[arr.length - 1] : undefined);
514
+ function localVersionFromStatus(tagged) {
515
+ return (tagged ? {
516
+ latest: tagged.current,
517
+ isArchived: tagged.isArchived
518
+ } : undefined);
389
519
  }
390
- function nonGarbageVersionInTask(task) {
391
- if (task.type === 'upload') {
392
- return task.version;
520
+ function splitVersionsIntoBranches(remote, synced) {
521
+ if (synced) {
522
+ if (isSyncedCurrentWithRemote(synced, remote)) {
523
+ return {
524
+ synced: versionsToBranch(remote)
525
+ };
526
+ }
527
+ else {
528
+ (0, assert_1.assert)(!!synced.version);
529
+ return {
530
+ synced: versionsToBranch(remote, synced.version, false),
531
+ remote: versionsToBranch(remote, synced.version, true)
532
+ };
533
+ }
534
+ }
535
+ else {
536
+ return (isRemoteEmpty(remote) ? {} : {
537
+ remote: versionsToBranch(remote)
538
+ });
539
+ }
540
+ }
541
+ function versionsToBranch({ current, archived, isArchived }, splitVersion, aboveSplit) {
542
+ if (splitVersion) {
543
+ let splitArchived = undefined;
544
+ if (archived) {
545
+ const indAboveSplit = archived.findIndex(v => (v > splitVersion));
546
+ if (aboveSplit) {
547
+ if (indAboveSplit >= 0) {
548
+ splitArchived = archived.slice(indAboveSplit);
549
+ }
550
+ }
551
+ else {
552
+ if (indAboveSplit > 0) {
553
+ splitArchived = archived.slice(0, indAboveSplit);
554
+ }
555
+ else {
556
+ splitArchived = archived.slice();
557
+ }
558
+ }
559
+ }
560
+ return {
561
+ archived: splitArchived,
562
+ latest: (aboveSplit ? current : splitVersion),
563
+ isArchived: isArchived
564
+ };
565
+ }
566
+ else {
567
+ return {
568
+ archived: archived === null || archived === void 0 ? void 0 : archived.slice(),
569
+ latest: current,
570
+ isArchived: isArchived
571
+ };
572
+ }
573
+ }
574
+ function removeArchVersionsNotInList(remote, versionsToKeep) {
575
+ let isAnythingChanged = false;
576
+ if (remote.archived) {
577
+ for (const v of remote.archived) {
578
+ if (!(versionsToKeep === null || versionsToKeep === void 0 ? void 0 : versionsToKeep.includes(v))) {
579
+ (0, obj_info_file_1.rmArchVersionFrom)(remote, v);
580
+ isAnythingChanged = true;
581
+ }
582
+ }
583
+ }
584
+ return isAnythingChanged;
585
+ }
586
+ function addArchVersionsFromList(remote, existingVersions) {
587
+ var _a;
588
+ if (!existingVersions) {
589
+ return false;
590
+ }
591
+ let isAnythingChanged = false;
592
+ for (const v of existingVersions) {
593
+ if (!((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(v))) {
594
+ (0, obj_info_file_1.addArchived)(remote, v);
595
+ }
393
596
  }
597
+ return isAnythingChanged;
394
598
  }
395
599
  Object.freeze(exports);