@protontech/drive-sdk 0.0.12 → 0.1.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 (274) hide show
  1. package/dist/cache/index.d.ts +1 -0
  2. package/dist/cache/index.js +3 -1
  3. package/dist/cache/index.js.map +1 -1
  4. package/dist/cache/memoryCache.d.ts +1 -1
  5. package/dist/cache/nullCache.d.ts +14 -0
  6. package/dist/cache/nullCache.js +37 -0
  7. package/dist/cache/nullCache.js.map +1 -0
  8. package/dist/config.d.ts +16 -1
  9. package/dist/config.js +1 -1
  10. package/dist/config.js.map +1 -1
  11. package/dist/crypto/openPGPCrypto.js +2 -0
  12. package/dist/crypto/openPGPCrypto.js.map +1 -1
  13. package/dist/diagnostic/eventsGenerator.d.ts +14 -0
  14. package/dist/diagnostic/eventsGenerator.js +49 -0
  15. package/dist/diagnostic/eventsGenerator.js.map +1 -0
  16. package/dist/diagnostic/httpClient.d.ts +16 -0
  17. package/dist/diagnostic/httpClient.js +81 -0
  18. package/dist/diagnostic/httpClient.js.map +1 -0
  19. package/dist/diagnostic/index.d.ts +10 -0
  20. package/dist/diagnostic/index.js +35 -0
  21. package/dist/diagnostic/index.js.map +1 -0
  22. package/dist/diagnostic/integrityVerificationStream.d.ts +21 -0
  23. package/dist/diagnostic/integrityVerificationStream.js +56 -0
  24. package/dist/diagnostic/integrityVerificationStream.js.map +1 -0
  25. package/dist/diagnostic/interface.d.ts +102 -0
  26. package/dist/diagnostic/interface.js +3 -0
  27. package/dist/diagnostic/interface.js.map +1 -0
  28. package/dist/diagnostic/sdkDiagnostic.d.ts +22 -0
  29. package/dist/diagnostic/sdkDiagnostic.js +216 -0
  30. package/dist/diagnostic/sdkDiagnostic.js.map +1 -0
  31. package/dist/diagnostic/sdkDiagnosticFull.d.ts +18 -0
  32. package/dist/diagnostic/sdkDiagnosticFull.js +35 -0
  33. package/dist/diagnostic/sdkDiagnosticFull.js.map +1 -0
  34. package/dist/diagnostic/telemetry.d.ts +25 -0
  35. package/dist/diagnostic/telemetry.js +70 -0
  36. package/dist/diagnostic/telemetry.js.map +1 -0
  37. package/dist/diagnostic/zipGenerators.d.ts +9 -0
  38. package/dist/diagnostic/zipGenerators.js +64 -0
  39. package/dist/diagnostic/zipGenerators.js.map +1 -0
  40. package/dist/diagnostic/zipGenerators.test.js +144 -0
  41. package/dist/diagnostic/zipGenerators.test.js.map +1 -0
  42. package/dist/errors.d.ts +8 -3
  43. package/dist/errors.js +11 -4
  44. package/dist/errors.js.map +1 -1
  45. package/dist/interface/config.d.ts +26 -0
  46. package/dist/interface/config.js +3 -0
  47. package/dist/interface/config.js.map +1 -0
  48. package/dist/interface/download.d.ts +2 -2
  49. package/dist/interface/events.d.ts +60 -20
  50. package/dist/interface/events.js +11 -1
  51. package/dist/interface/events.js.map +1 -1
  52. package/dist/interface/httpClient.d.ts +0 -14
  53. package/dist/interface/index.d.ts +9 -5
  54. package/dist/interface/index.js +2 -1
  55. package/dist/interface/index.js.map +1 -1
  56. package/dist/interface/nodes.d.ts +21 -1
  57. package/dist/interface/nodes.js +11 -0
  58. package/dist/interface/nodes.js.map +1 -1
  59. package/dist/interface/sharing.d.ts +1 -0
  60. package/dist/interface/upload.d.ts +57 -3
  61. package/dist/internal/apiService/driveTypes.d.ts +1341 -465
  62. package/dist/internal/apiService/errors.js +2 -2
  63. package/dist/internal/apiService/errors.js.map +1 -1
  64. package/dist/internal/apiService/transformers.js +2 -0
  65. package/dist/internal/apiService/transformers.js.map +1 -1
  66. package/dist/internal/asyncIteratorMap.d.ts +15 -0
  67. package/dist/internal/asyncIteratorMap.js +59 -0
  68. package/dist/internal/asyncIteratorMap.js.map +1 -0
  69. package/dist/internal/asyncIteratorMap.test.js +120 -0
  70. package/dist/internal/asyncIteratorMap.test.js.map +1 -0
  71. package/dist/internal/download/apiService.js +32 -31
  72. package/dist/internal/download/apiService.js.map +1 -1
  73. package/dist/internal/download/fileDownloader.d.ts +2 -2
  74. package/dist/internal/download/fileDownloader.js.map +1 -1
  75. package/dist/internal/events/apiService.d.ts +4 -6
  76. package/dist/internal/events/apiService.js +15 -22
  77. package/dist/internal/events/apiService.js.map +1 -1
  78. package/dist/internal/events/coreEventManager.d.ts +7 -10
  79. package/dist/internal/events/coreEventManager.js +19 -36
  80. package/dist/internal/events/coreEventManager.js.map +1 -1
  81. package/dist/internal/events/coreEventManager.test.d.ts +1 -0
  82. package/dist/internal/events/coreEventManager.test.js +87 -0
  83. package/dist/internal/events/coreEventManager.test.js.map +1 -0
  84. package/dist/internal/events/eventManager.d.ts +11 -36
  85. package/dist/internal/events/eventManager.js +59 -105
  86. package/dist/internal/events/eventManager.js.map +1 -1
  87. package/dist/internal/events/eventManager.test.js +167 -82
  88. package/dist/internal/events/eventManager.test.js.map +1 -1
  89. package/dist/internal/events/index.d.ts +13 -33
  90. package/dist/internal/events/index.js +56 -72
  91. package/dist/internal/events/index.js.map +1 -1
  92. package/dist/internal/events/interface.d.ts +59 -14
  93. package/dist/internal/events/interface.js +13 -3
  94. package/dist/internal/events/interface.js.map +1 -1
  95. package/dist/internal/events/volumeEventManager.d.ts +7 -17
  96. package/dist/internal/events/volumeEventManager.js +58 -45
  97. package/dist/internal/events/volumeEventManager.js.map +1 -1
  98. package/dist/internal/events/volumeEventManager.test.d.ts +1 -0
  99. package/dist/internal/events/volumeEventManager.test.js +203 -0
  100. package/dist/internal/events/volumeEventManager.test.js.map +1 -0
  101. package/dist/internal/nodes/apiService.d.ts +2 -2
  102. package/dist/internal/nodes/apiService.js +16 -6
  103. package/dist/internal/nodes/apiService.js.map +1 -1
  104. package/dist/internal/nodes/apiService.test.js +30 -8
  105. package/dist/internal/nodes/apiService.test.js.map +1 -1
  106. package/dist/internal/nodes/cache.d.ts +10 -1
  107. package/dist/internal/nodes/cache.js +18 -0
  108. package/dist/internal/nodes/cache.js.map +1 -1
  109. package/dist/internal/nodes/cache.test.js +1 -0
  110. package/dist/internal/nodes/cache.test.js.map +1 -1
  111. package/dist/internal/nodes/cryptoService.d.ts +1 -1
  112. package/dist/internal/nodes/cryptoService.js.map +1 -1
  113. package/dist/internal/nodes/cryptoService.test.js +34 -0
  114. package/dist/internal/nodes/cryptoService.test.js.map +1 -1
  115. package/dist/internal/nodes/events.d.ts +7 -83
  116. package/dist/internal/nodes/events.js +43 -217
  117. package/dist/internal/nodes/events.js.map +1 -1
  118. package/dist/internal/nodes/events.test.js +27 -277
  119. package/dist/internal/nodes/events.test.js.map +1 -1
  120. package/dist/internal/nodes/index.d.ts +3 -4
  121. package/dist/internal/nodes/index.js +5 -5
  122. package/dist/internal/nodes/index.js.map +1 -1
  123. package/dist/internal/nodes/interface.d.ts +3 -1
  124. package/dist/internal/nodes/nodesAccess.d.ts +15 -0
  125. package/dist/internal/nodes/nodesAccess.js +65 -7
  126. package/dist/internal/nodes/nodesAccess.js.map +1 -1
  127. package/dist/internal/nodes/nodesAccess.test.js +132 -93
  128. package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
  129. package/dist/internal/nodes/nodesManagement.d.ts +1 -3
  130. package/dist/internal/nodes/nodesManagement.js +12 -26
  131. package/dist/internal/nodes/nodesManagement.js.map +1 -1
  132. package/dist/internal/nodes/nodesManagement.test.js +35 -14
  133. package/dist/internal/nodes/nodesManagement.test.js.map +1 -1
  134. package/dist/internal/shares/cache.d.ts +2 -0
  135. package/dist/internal/shares/cache.js +2 -0
  136. package/dist/internal/shares/cache.js.map +1 -1
  137. package/dist/internal/shares/manager.d.ts +1 -0
  138. package/dist/internal/shares/manager.js +3 -0
  139. package/dist/internal/shares/manager.js.map +1 -1
  140. package/dist/internal/sharing/apiService.js +20 -2
  141. package/dist/internal/sharing/apiService.js.map +1 -1
  142. package/dist/internal/sharing/cryptoService.js +1 -0
  143. package/dist/internal/sharing/cryptoService.js.map +1 -1
  144. package/dist/internal/sharing/events.d.ts +23 -55
  145. package/dist/internal/sharing/events.js +46 -138
  146. package/dist/internal/sharing/events.js.map +1 -1
  147. package/dist/internal/sharing/events.test.js +77 -180
  148. package/dist/internal/sharing/events.test.js.map +1 -1
  149. package/dist/internal/sharing/index.d.ts +4 -5
  150. package/dist/internal/sharing/index.js +5 -5
  151. package/dist/internal/sharing/index.js.map +1 -1
  152. package/dist/internal/sharing/interface.d.ts +3 -0
  153. package/dist/internal/sharing/sharingManagement.d.ts +2 -3
  154. package/dist/internal/sharing/sharingManagement.js +7 -9
  155. package/dist/internal/sharing/sharingManagement.js.map +1 -1
  156. package/dist/internal/sharing/sharingManagement.test.js +9 -39
  157. package/dist/internal/sharing/sharingManagement.test.js.map +1 -1
  158. package/dist/internal/upload/apiService.d.ts +2 -3
  159. package/dist/internal/upload/apiService.js +7 -4
  160. package/dist/internal/upload/apiService.js.map +1 -1
  161. package/dist/internal/upload/fileUploader.d.ts +49 -53
  162. package/dist/internal/upload/fileUploader.js +91 -395
  163. package/dist/internal/upload/fileUploader.js.map +1 -1
  164. package/dist/internal/upload/fileUploader.test.js +38 -292
  165. package/dist/internal/upload/fileUploader.test.js.map +1 -1
  166. package/dist/internal/upload/index.d.ts +5 -5
  167. package/dist/internal/upload/index.js +23 -44
  168. package/dist/internal/upload/index.js.map +1 -1
  169. package/dist/internal/upload/interface.d.ts +2 -0
  170. package/dist/internal/upload/manager.d.ts +6 -6
  171. package/dist/internal/upload/manager.js +32 -66
  172. package/dist/internal/upload/manager.js.map +1 -1
  173. package/dist/internal/upload/manager.test.js +100 -117
  174. package/dist/internal/upload/manager.test.js.map +1 -1
  175. package/dist/internal/upload/streamUploader.d.ts +62 -0
  176. package/dist/internal/upload/streamUploader.js +440 -0
  177. package/dist/internal/upload/streamUploader.js.map +1 -0
  178. package/dist/internal/upload/streamUploader.test.d.ts +1 -0
  179. package/dist/internal/upload/streamUploader.test.js +358 -0
  180. package/dist/internal/upload/streamUploader.test.js.map +1 -0
  181. package/dist/protonDriveClient.d.ts +22 -165
  182. package/dist/protonDriveClient.js +27 -191
  183. package/dist/protonDriveClient.js.map +1 -1
  184. package/dist/protonDrivePhotosClient.js +3 -2
  185. package/dist/protonDrivePhotosClient.js.map +1 -1
  186. package/package.json +4 -4
  187. package/src/cache/index.ts +1 -0
  188. package/src/cache/memoryCache.ts +1 -1
  189. package/src/cache/nullCache.ts +38 -0
  190. package/src/config.ts +17 -2
  191. package/src/crypto/openPGPCrypto.ts +2 -0
  192. package/src/diagnostic/eventsGenerator.ts +48 -0
  193. package/src/diagnostic/httpClient.ts +80 -0
  194. package/src/diagnostic/index.ts +38 -0
  195. package/src/diagnostic/integrityVerificationStream.ts +56 -0
  196. package/src/diagnostic/interface.ts +158 -0
  197. package/src/diagnostic/sdkDiagnostic.ts +238 -0
  198. package/src/diagnostic/sdkDiagnosticFull.ts +40 -0
  199. package/src/diagnostic/telemetry.ts +71 -0
  200. package/src/diagnostic/zipGenerators.test.ts +177 -0
  201. package/src/diagnostic/zipGenerators.ts +70 -0
  202. package/src/errors.ts +13 -4
  203. package/src/interface/config.ts +28 -0
  204. package/src/interface/download.ts +2 -2
  205. package/src/interface/events.ts +66 -21
  206. package/src/interface/httpClient.ts +0 -16
  207. package/src/interface/index.ts +9 -5
  208. package/src/interface/nodes.ts +32 -12
  209. package/src/interface/sharing.ts +1 -0
  210. package/src/interface/upload.ts +59 -3
  211. package/src/internal/apiService/driveTypes.ts +1341 -465
  212. package/src/internal/apiService/errors.ts +3 -2
  213. package/src/internal/apiService/transformers.ts +2 -0
  214. package/src/internal/asyncIteratorMap.test.ts +150 -0
  215. package/src/internal/asyncIteratorMap.ts +64 -0
  216. package/src/internal/download/apiService.ts +11 -8
  217. package/src/internal/download/fileDownloader.ts +2 -2
  218. package/src/internal/events/apiService.ts +25 -28
  219. package/src/internal/events/coreEventManager.test.ts +101 -0
  220. package/src/internal/events/coreEventManager.ts +20 -45
  221. package/src/internal/events/eventManager.test.ts +201 -88
  222. package/src/internal/events/eventManager.ts +69 -115
  223. package/src/internal/events/index.ts +54 -84
  224. package/src/internal/events/interface.ts +70 -15
  225. package/src/internal/events/volumeEventManager.test.ts +243 -0
  226. package/src/internal/events/volumeEventManager.ts +55 -53
  227. package/src/internal/nodes/apiService.test.ts +36 -7
  228. package/src/internal/nodes/apiService.ts +19 -7
  229. package/src/internal/nodes/cache.test.ts +1 -0
  230. package/src/internal/nodes/cache.ts +21 -2
  231. package/src/internal/nodes/cryptoService.test.ts +38 -0
  232. package/src/internal/nodes/cryptoService.ts +1 -1
  233. package/src/internal/nodes/events.test.ts +29 -335
  234. package/src/internal/nodes/events.ts +45 -253
  235. package/src/internal/nodes/index.ts +6 -8
  236. package/src/internal/nodes/interface.ts +6 -3
  237. package/src/internal/nodes/nodesAccess.test.ts +133 -91
  238. package/src/internal/nodes/nodesAccess.ts +70 -8
  239. package/src/internal/nodes/nodesManagement.test.ts +39 -15
  240. package/src/internal/nodes/nodesManagement.ts +12 -30
  241. package/src/internal/shares/cache.ts +4 -2
  242. package/src/internal/shares/manager.ts +9 -5
  243. package/src/internal/sharing/apiService.ts +25 -2
  244. package/src/internal/sharing/cache.ts +1 -1
  245. package/src/internal/sharing/cryptoService.ts +1 -0
  246. package/src/internal/sharing/events.test.ts +89 -195
  247. package/src/internal/sharing/events.ts +42 -156
  248. package/src/internal/sharing/index.ts +6 -9
  249. package/src/internal/sharing/interface.ts +6 -2
  250. package/src/internal/sharing/sharingManagement.test.ts +10 -40
  251. package/src/internal/sharing/sharingManagement.ts +7 -11
  252. package/src/internal/upload/apiService.ts +5 -6
  253. package/src/internal/upload/fileUploader.test.ts +46 -376
  254. package/src/internal/upload/fileUploader.ts +114 -494
  255. package/src/internal/upload/index.ts +30 -54
  256. package/src/internal/upload/interface.ts +2 -0
  257. package/src/internal/upload/manager.test.ts +107 -124
  258. package/src/internal/upload/manager.ts +48 -80
  259. package/src/internal/upload/streamUploader.test.ts +468 -0
  260. package/src/internal/upload/streamUploader.ts +550 -0
  261. package/src/protonDriveClient.ts +80 -248
  262. package/src/protonDrivePhotosClient.ts +4 -3
  263. package/dist/internal/events/cache.d.ts +0 -28
  264. package/dist/internal/events/cache.js +0 -67
  265. package/dist/internal/events/cache.js.map +0 -1
  266. package/dist/internal/events/cache.test.js +0 -43
  267. package/dist/internal/events/cache.test.js.map +0 -1
  268. package/dist/internal/nodes/index.test.js +0 -112
  269. package/dist/internal/nodes/index.test.js.map +0 -1
  270. package/src/internal/events/cache.test.ts +0 -47
  271. package/src/internal/events/cache.ts +0 -80
  272. package/src/internal/nodes/index.test.ts +0 -135
  273. /package/dist/{internal/events/cache.test.d.ts → diagnostic/zipGenerators.test.d.ts} +0 -0
  274. /package/dist/internal/{nodes/index.test.d.ts → asyncIteratorMap.test.d.ts} +0 -0
@@ -44,6 +44,18 @@ function generateAPIFolderNode(linkOverrides = {}, overrides = {}) {
44
44
  };
45
45
  }
46
46
 
47
+ function generateAPIAlbumNode(linkOverrides = {}, overrides = {}) {
48
+ const node = generateAPINode();
49
+ return {
50
+ Link: {
51
+ ...node.Link,
52
+ Type: 3,
53
+ ...linkOverrides,
54
+ },
55
+ ...overrides,
56
+ };
57
+ }
58
+
47
59
  function generateAPINode() {
48
60
  return {
49
61
  Link: {
@@ -107,6 +119,15 @@ function generateFolderNode(overrides = {}) {
107
119
  }
108
120
  }
109
121
 
122
+ function generateAlbumNode(overrides = {}) {
123
+ const node = generateNode();
124
+ return {
125
+ ...node,
126
+ type: NodeType.Album,
127
+ ...overrides
128
+ }
129
+ }
130
+
110
131
  function generateNode() {
111
132
  return {
112
133
  hash: "nameHash",
@@ -119,7 +140,7 @@ function generateNode() {
119
140
 
120
141
  shareId: undefined,
121
142
  isShared: false,
122
- directMemberRole: MemberRole.Inherited,
143
+ directMemberRole: MemberRole.Admin,
123
144
 
124
145
  encryptedCrypto: {
125
146
  armoredKey: "nodeKey",
@@ -149,13 +170,13 @@ describe("nodeAPIService", () => {
149
170
  });
150
171
 
151
172
  describe('iterateNodes', () => {
152
- async function testIterateNodes(mockedLink: any, expectedNode: any) {
173
+ async function testIterateNodes(mockedLink: any, expectedNode: any, ownVolumeId = 'volumeId') {
153
174
  // @ts-expect-error Mocking for testing purposes
154
175
  apiMock.post = jest.fn(async () => Promise.resolve({
155
176
  Links: [mockedLink],
156
177
  }));
157
178
 
158
- const nodes = await Array.fromAsync(api.iterateNodes(['volumeId~nodeId']));
179
+ const nodes = await Array.fromAsync(api.iterateNodes(['volumeId~nodeId'], ownVolumeId));
159
180
  expect(nodes).toStrictEqual([expectedNode]);
160
181
  }
161
182
 
@@ -180,6 +201,13 @@ describe("nodeAPIService", () => {
180
201
  );
181
202
  });
182
203
 
204
+ it('should get album node', async () => {
205
+ await testIterateNodes(
206
+ generateAPIAlbumNode(),
207
+ generateAlbumNode(),
208
+ );
209
+ });
210
+
183
211
  it('should get shared node', async () => {
184
212
  await testIterateNodes(
185
213
  generateAPIFolderNode({}, {
@@ -213,6 +241,7 @@ describe("nodeAPIService", () => {
213
241
  shareId: 'shareId',
214
242
  directMemberRole: MemberRole.Viewer,
215
243
  }),
244
+ 'myVolumeId',
216
245
  );
217
246
  });
218
247
 
@@ -240,7 +269,7 @@ describe("nodeAPIService", () => {
240
269
  ],
241
270
  }));
242
271
 
243
- const generator = api.iterateNodes(['volumeId~nodeId']);
272
+ const generator = api.iterateNodes(['volumeId~nodeId'], 'volumeId');
244
273
 
245
274
  const node1 = await generator.next();
246
275
  expect(node1.value).toStrictEqual(generateFolderNode());
@@ -272,10 +301,10 @@ describe("nodeAPIService", () => {
272
301
  ],
273
302
  }));
274
303
 
275
- const nodes = await Array.fromAsync(api.iterateNodes(['volumeId1~nodeId1', 'volumeId2~nodeId2']));
304
+ const nodes = await Array.fromAsync(api.iterateNodes(['volumeId1~nodeId1', 'volumeId2~nodeId2'], 'volumeId1'));
276
305
  expect(nodes).toStrictEqual([
277
- generateFolderNode({ uid: 'volumeId1~nodeId1', parentUid: 'volumeId1~parentNodeId1' }),
278
- generateFolderNode({ uid: 'volumeId2~nodeId2', parentUid: 'volumeId2~parentNodeId2' }),
306
+ generateFolderNode({ uid: 'volumeId1~nodeId1', parentUid: 'volumeId1~parentNodeId1', directMemberRole: MemberRole.Admin }),
307
+ generateFolderNode({ uid: 'volumeId2~nodeId2', parentUid: 'volumeId2~parentNodeId2', directMemberRole: MemberRole.Inherited }),
279
308
  ]);
280
309
  });
281
310
  });
@@ -2,7 +2,7 @@ import { c } from "ttag";
2
2
 
3
3
  import { ProtonDriveError, ValidationError } from "../../errors";
4
4
  import { Logger, NodeResult } from "../../interface";
5
- import { RevisionState } from "../../interface/nodes";
5
+ import { MemberRole, RevisionState } from "../../interface/nodes";
6
6
  import { DriveAPIService, drivePaths, isCodeOk, nodeTypeNumberToNodeType, permissionsToDirectMemberRole } from "../apiService";
7
7
  import { splitNodeUid, makeNodeUid, makeNodeRevisionUid, splitNodeRevisionUid, makeNodeThumbnailUid } from "../uids";
8
8
  import { EncryptedNode, EncryptedRevision, Thumbnail } from "./interface";
@@ -56,15 +56,15 @@ export class NodeAPIService {
56
56
  this.apiService = apiService;
57
57
  }
58
58
 
59
- async getNode(nodeUid: string, signal?: AbortSignal): Promise<EncryptedNode> {
60
- const nodesGenerator = this.iterateNodes([nodeUid], signal);
59
+ async getNode(nodeUid: string, ownVolumeId: string, signal?: AbortSignal): Promise<EncryptedNode> {
60
+ const nodesGenerator = this.iterateNodes([nodeUid], ownVolumeId, signal);
61
61
  const result = await nodesGenerator.next();
62
62
  await nodesGenerator.return("finish");
63
63
  return result.value;
64
64
  }
65
65
 
66
66
  // Improvement requested: split into multiple calls for many nodes.
67
- async* iterateNodes(nodeUids: string[], signal?: AbortSignal): AsyncGenerator<EncryptedNode> {
67
+ async* iterateNodes(nodeUids: string[], ownVolumeId: string, signal?: AbortSignal): AsyncGenerator<EncryptedNode> {
68
68
  const allNodeIds = nodeUids.map(splitNodeUid);
69
69
 
70
70
  const nodeIdsByVolumeId = new Map<string, string[]>();
@@ -81,13 +81,15 @@ export class NodeAPIService {
81
81
  const errors = [];
82
82
 
83
83
  for (const [volumeId, nodeIds] of nodeIdsByVolumeId.entries()) {
84
+ const isAdmin = volumeId === ownVolumeId;
85
+
84
86
  const response = await this.apiService.post<PostLoadLinksMetadataRequest, PostLoadLinksMetadataResponse>(`drive/v2/volumes/${volumeId}/links`, {
85
87
  LinkIDs: nodeIds,
86
88
  }, signal);
87
89
 
88
90
  for (const link of response.Links) {
89
91
  try {
90
- yield linkToEncryptedNode(this.logger, volumeId, link);
92
+ yield linkToEncryptedNode(this.logger, volumeId, link, isAdmin);
91
93
  } catch (error: unknown) {
92
94
  this.logger.error(`Failed to transform node ${link.Link.LinkID}`, error);
93
95
  errors.push(error);
@@ -363,7 +365,7 @@ function* handleResponseErrors(nodeUids: string[], volumeId: string, responses:
363
365
  }
364
366
  }
365
367
 
366
- function linkToEncryptedNode(logger: Logger, volumeId: string, link: PostLoadLinksMetadataResponse['Links'][0]): EncryptedNode {
368
+ function linkToEncryptedNode(logger: Logger, volumeId: string, link: PostLoadLinksMetadataResponse['Links'][0], isAdmin: boolean): EncryptedNode {
367
369
  const baseNodeMetadata = {
368
370
  // Internal metadata
369
371
  hash: link.Link.NameHash || undefined,
@@ -379,7 +381,7 @@ function linkToEncryptedNode(logger: Logger, volumeId: string, link: PostLoadLin
379
381
  // Sharing node metadata
380
382
  shareId: link.Sharing?.ShareID || undefined,
381
383
  isShared: !!link.Sharing,
382
- directMemberRole: permissionsToDirectMemberRole(logger, link.Membership?.Permissions),
384
+ directMemberRole: isAdmin ? MemberRole.Admin : permissionsToDirectMemberRole(logger, link.Membership?.Permissions),
383
385
  }
384
386
  const baseCryptoNodeMetadata = {
385
387
  signatureEmail: link.Link.SignatureEmail || undefined,
@@ -426,6 +428,15 @@ function linkToEncryptedNode(logger: Logger, volumeId: string, link: PostLoadLin
426
428
  }
427
429
  }
428
430
 
431
+ if (link.Link.Type === 3) {
432
+ return {
433
+ ...baseNodeMetadata,
434
+ encryptedCrypto: {
435
+ ...baseCryptoNodeMetadata,
436
+ },
437
+ }
438
+ }
439
+
429
440
  throw new Error(`Unknown node type: ${link.Link.Type}`);
430
441
  }
431
442
 
@@ -437,6 +448,7 @@ function transformRevisionResponse(
437
448
  return {
438
449
  uid: makeNodeRevisionUid(volumeId, nodeId, revision.ID),
439
450
  state: revision.State === APIRevisionState.Active ? RevisionState.Active : RevisionState.Superseded,
451
+ // @ts-expect-error: API doc is wrong, CreateTime is not optional.
440
452
  creationTime: new Date(revision.CreateTime*1000),
441
453
  storageSize: revision.Size,
442
454
  signatureEmail: revision.SignatureEmail || undefined,
@@ -108,6 +108,7 @@ describe('nodesCache', () => {
108
108
  creationTime: new Date('2021-01-01'),
109
109
  storageSize: 100,
110
110
  contentAuthor: resultOk('test@test.com'),
111
+ claimedModificationTime: new Date('2021-02-01')
111
112
  });
112
113
  const node = generateNode('node1', '', { activeRevision });
113
114
 
@@ -6,6 +6,7 @@ import { DecryptedNode, DecryptedRevision } from "./interface";
6
6
  export enum CACHE_TAG_KEYS {
7
7
  ParentUid = 'nodeParentUid',
8
8
  Trashed = 'nodeTrashed',
9
+ Roots = 'nodeRoot',
9
10
  }
10
11
 
11
12
  type DecryptedNodeResult = (
@@ -15,10 +16,10 @@ type DecryptedNodeResult = (
15
16
 
16
17
  /**
17
18
  * Provides caching for nodes metadata.
18
- *
19
+ *
19
20
  * The cache is responsible for serialising and deserialising node metadata,
20
21
  * recording parent-child relationships, and recursively removing nodes.
21
- *
22
+ *
22
23
  * The cache of node metadata should not contain any crypto material.
23
24
  */
24
25
  export class NodesCache {
@@ -35,6 +36,8 @@ export class NodesCache {
35
36
  const tags = [`volume:${volumeId}`];
36
37
  if (node.parentUid) {
37
38
  tags.push(`${CACHE_TAG_KEYS.ParentUid}:${node.parentUid}`)
39
+ } else {
40
+ tags.push(`${CACHE_TAG_KEYS.Roots}:${volumeId}`)
38
41
  }
39
42
  if (node.trashTime) {
40
43
  tags.push(`${CACHE_TAG_KEYS.Trashed}`)
@@ -74,6 +77,17 @@ export class NodesCache {
74
77
  }
75
78
  }
76
79
 
80
+ /**
81
+ * Remove all entries associated with a volume.
82
+ *
83
+ * This is needed when a user looses access to a volume.
84
+ */
85
+ async removeVolume(volumeId: string): Promise<void> {
86
+ for await (const result of this.iterateRootNodeUids(volumeId)) {
87
+ await this.removeNodes([result.key]);
88
+ }
89
+ }
90
+
77
91
  /**
78
92
  * Remove corrupted node never throws, but it logs so we can know
79
93
  * about issues and fix them. It is crucial to remove corrupted
@@ -142,6 +156,10 @@ export class NodesCache {
142
156
  }
143
157
  }
144
158
 
159
+ async *iterateRootNodeUids(volumeId: string): AsyncGenerator<EntityResult<string>> {
160
+ yield* this.driveCache.iterateEntitiesByTag(`${CACHE_TAG_KEYS.Roots}:${volumeId}`);
161
+ }
162
+
145
163
  async *iterateTrashedNodes(): AsyncGenerator<DecryptedNodeResult> {
146
164
  for await (const result of this.driveCache.iterateEntitiesByTag(CACHE_TAG_KEYS.Trashed)) {
147
165
  const node = await this.convertCacheResult(result);
@@ -261,6 +279,7 @@ function deserialiseRevision(revision: any): Result<DecryptedRevision, Error> {
261
279
  return resultOk({
262
280
  ...revision.value,
263
281
  creationTime: new Date(revision.value.creationTime),
282
+ claimedModificationTime: new Date(revision.value.claimedModificationTime)
264
283
  });
265
284
  }
266
285
 
@@ -578,6 +578,44 @@ describe("nodesCryptoService", () => {
578
578
  });
579
579
  });
580
580
 
581
+ describe("album node", () => {
582
+ const encryptedNode = {
583
+ uid: "volumeId~nodeId",
584
+ parentUid: "volumeId~parentId",
585
+ encryptedCrypto: {
586
+ signatureEmail: "signatureEmail",
587
+ nameSignatureEmail: "nameSignatureEmail",
588
+ armoredKey: "armoredKey",
589
+ armoredNodePassphrase: "armoredNodePassphrase",
590
+ armoredNodePassphraseSignature: "armoredNodePassphraseSignature",
591
+ },
592
+ } as EncryptedNode;
593
+
594
+ it("should decrypt successfuly", async () => {
595
+ const result = await cryptoService.decryptNode(encryptedNode, parentKey);
596
+
597
+ expect(result).toMatchObject({
598
+ node: {
599
+ name: { ok: true, value: "name" },
600
+ keyAuthor: { ok: true, value: "signatureEmail" },
601
+ nameAuthor: { ok: true, value: "nameSignatureEmail" },
602
+ folder: undefined,
603
+ activeRevision: undefined,
604
+ errors: undefined,
605
+ },
606
+ keys: {
607
+ passphrase: "pass",
608
+ key: "decryptedKey",
609
+ passphraseSessionKey: "passphraseSessionKey",
610
+ hashKey: new Uint8Array(),
611
+ }
612
+ });
613
+
614
+ expect(account.getPublicKeys).toHaveBeenCalledTimes(2);
615
+ expect(telemetry.logEvent).not.toHaveBeenCalled();
616
+ });
617
+ });
618
+
581
619
  describe("anonymous node", () => {
582
620
  const encryptedNode = {
583
621
  uid: "volumeId~nodeId",
@@ -422,7 +422,7 @@ export class NodesCryptoService {
422
422
  };
423
423
 
424
424
  async moveNode(
425
- node: DecryptedNode,
425
+ node: Pick<DecryptedNode, 'name'>,
426
426
  keys: { passphrase: string, passphraseSessionKey: SessionKey, nameSessionKey: SessionKey },
427
427
  parentKeys: { key: PrivateKey, hashKey: Uint8Array },
428
428
  address: { email: string, addressKey: PrivateKey },