@protontech/drive-sdk 0.1.1 → 0.1.2

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 (48) hide show
  1. package/dist/internal/events/eventManager.d.ts +1 -0
  2. package/dist/internal/events/eventManager.js +9 -0
  3. package/dist/internal/events/eventManager.js.map +1 -1
  4. package/dist/internal/events/eventManager.test.js +53 -38
  5. package/dist/internal/events/eventManager.test.js.map +1 -1
  6. package/dist/internal/events/index.d.ts +4 -3
  7. package/dist/internal/events/index.js +38 -32
  8. package/dist/internal/events/index.js.map +1 -1
  9. package/dist/internal/nodes/events.js +7 -7
  10. package/dist/internal/nodes/events.js.map +1 -1
  11. package/dist/internal/sharing/cache.d.ts +1 -0
  12. package/dist/internal/sharing/cache.js +9 -0
  13. package/dist/internal/sharing/cache.js.map +1 -1
  14. package/dist/internal/sharing/events.d.ts +1 -0
  15. package/dist/internal/sharing/events.js +28 -18
  16. package/dist/internal/sharing/events.js.map +1 -1
  17. package/dist/internal/sharing/events.test.js +98 -84
  18. package/dist/internal/sharing/events.test.js.map +1 -1
  19. package/dist/internal/upload/interface.d.ts +1 -0
  20. package/dist/internal/upload/manager.d.ts +1 -1
  21. package/dist/internal/upload/manager.js +8 -4
  22. package/dist/internal/upload/manager.js.map +1 -1
  23. package/dist/internal/upload/manager.test.js +7 -10
  24. package/dist/internal/upload/manager.test.js.map +1 -1
  25. package/dist/internal/upload/streamUploader.js +1 -1
  26. package/dist/internal/upload/streamUploader.js.map +1 -1
  27. package/dist/internal/upload/streamUploader.test.js +1 -1
  28. package/dist/internal/upload/streamUploader.test.js.map +1 -1
  29. package/dist/protonDriveClient.js +2 -2
  30. package/dist/protonDriveClient.js.map +1 -1
  31. package/dist/transformers.d.ts +1 -1
  32. package/dist/transformers.js +1 -0
  33. package/dist/transformers.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/internal/events/eventManager.test.ts +61 -40
  36. package/src/internal/events/eventManager.ts +10 -0
  37. package/src/internal/events/index.ts +53 -35
  38. package/src/internal/nodes/events.ts +6 -7
  39. package/src/internal/sharing/cache.ts +9 -0
  40. package/src/internal/sharing/events.test.ts +104 -89
  41. package/src/internal/sharing/events.ts +33 -18
  42. package/src/internal/upload/interface.ts +1 -0
  43. package/src/internal/upload/manager.test.ts +7 -10
  44. package/src/internal/upload/manager.ts +7 -4
  45. package/src/internal/upload/streamUploader.test.ts +1 -1
  46. package/src/internal/upload/streamUploader.ts +1 -1
  47. package/src/protonDriveClient.ts +2 -2
  48. package/src/transformers.ts +2 -0
@@ -21,6 +21,7 @@ describe('handleSharedByMeNodes', () => {
21
21
  removeSharedByMeNodeUid: jest.fn(),
22
22
  setSharedWithMeNodeUids: jest.fn(),
23
23
  getSharedByMeNodeUids: jest.fn().mockResolvedValue(['cachedNodeUid']),
24
+ hasSharedByMeNodeUidsLoaded: jest.fn().mockResolvedValue(true),
24
25
  };
25
26
  sharesManager = {
26
27
  isOwnVolume: jest.fn(async (volumeId: string) => volumeId === 'MyVolume1'),
@@ -28,94 +29,108 @@ describe('handleSharedByMeNodes', () => {
28
29
  sharingEventHandler = new SharingEventHandler(getMockLogger(), cache, sharesManager);
29
30
  });
30
31
 
31
- describe('node events trigger cache update', () => {
32
- it('should add if new own shared node is created', async () => {
33
- const event: DriveEvent = {
34
- eventId: '1',
35
- type: DriveEventType.NodeCreated,
36
- nodeUid: 'newNodeUid',
37
- parentNodeUid: 'parentUid',
38
- isTrashed: false,
39
- isShared: true,
40
- treeEventScopeId: 'MyVolume1',
41
- };
42
- await sharingEventHandler.handleDriveEvent(event);
43
- expect(cache.addSharedByMeNodeUid).toHaveBeenCalledWith('newNodeUid');
44
- expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
45
- });
46
-
47
- test('should not add if new shared node is not own', async () => {
48
- const event: DriveEvent = {
49
- eventId: '1',
50
- type: DriveEventType.NodeCreated,
51
- nodeUid: 'newNodeUid',
52
- parentNodeUid: 'parentUid',
53
- isTrashed: false,
54
- isShared: true,
55
- treeEventScopeId: 'NotOwnVolume',
56
- };
57
- await sharingEventHandler.handleDriveEvent(event);
58
- expect(cache.addSharedByMeNodeUid).not.toHaveBeenCalled();
59
- expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
60
- });
61
-
62
- it('should not add if new own node is not shared', async () => {
63
- const event: DriveEvent = {
64
- type: DriveEventType.NodeCreated,
65
- nodeUid: 'newNodeUid',
66
- parentNodeUid: 'parentUid',
67
- isTrashed: false,
68
- isShared: false,
69
- eventId: '1',
70
- treeEventScopeId: 'MyVolume1',
71
- };
72
- await sharingEventHandler.handleDriveEvent(event);
73
- expect(cache.addSharedByMeNodeUid).not.toHaveBeenCalled();
74
- expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
75
- });
76
-
77
- it('should add if own node is updated and shared', async () => {
78
- const event: DriveEvent = {
79
- type: DriveEventType.NodeUpdated,
80
- nodeUid: 'cachedNodeUid',
81
- parentNodeUid: 'parentUid',
82
- isTrashed: false,
83
- isShared: true,
84
- eventId: '1',
85
- treeEventScopeId: 'MyVolume1',
86
- };
87
- await sharingEventHandler.handleDriveEvent(event);
88
- expect(cache.addSharedByMeNodeUid).toHaveBeenCalledWith('cachedNodeUid');
89
- expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
90
- });
91
-
92
- it('should remove if shared node is un-shared', async () => {
93
- const event: DriveEvent = {
94
- type: DriveEventType.NodeUpdated,
95
- nodeUid: 'cachedNodeUid',
96
- parentNodeUid: 'parentUid',
97
- isTrashed: false,
98
- isShared: false,
99
- eventId: '1',
100
- treeEventScopeId: 'MyVolume1',
101
- };
102
- await sharingEventHandler.handleDriveEvent(event);
103
- expect(cache.removeSharedByMeNodeUid).toHaveBeenCalledWith('cachedNodeUid');
104
- expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
105
- });
106
-
107
- it('should remove if shared node is deleted', async () => {
108
- const event: DriveEvent = {
109
- type: DriveEventType.NodeDeleted,
110
- nodeUid: 'cachedNodeUid',
111
- parentNodeUid: 'parentUid',
112
- eventId: '1',
113
- treeEventScopeId: 'MyVolume1',
114
- };
115
- await sharingEventHandler.handleDriveEvent(event);
116
- expect(cache.removeSharedByMeNodeUid).toHaveBeenCalledWith('cachedNodeUid');
117
- expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
118
- });
32
+ it('should add if new own shared node is created', async () => {
33
+ const event: DriveEvent = {
34
+ eventId: '1',
35
+ type: DriveEventType.NodeCreated,
36
+ nodeUid: 'newNodeUid',
37
+ parentNodeUid: 'parentUid',
38
+ isTrashed: false,
39
+ isShared: true,
40
+ treeEventScopeId: 'MyVolume1',
41
+ };
42
+ await sharingEventHandler.handleDriveEvent(event);
43
+ expect(cache.addSharedByMeNodeUid).toHaveBeenCalledWith('newNodeUid');
44
+ expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
45
+ });
46
+
47
+ test('should not add if new shared node is not own', async () => {
48
+ const event: DriveEvent = {
49
+ eventId: '1',
50
+ type: DriveEventType.NodeCreated,
51
+ nodeUid: 'newNodeUid',
52
+ parentNodeUid: 'parentUid',
53
+ isTrashed: false,
54
+ isShared: true,
55
+ treeEventScopeId: 'NotOwnVolume',
56
+ };
57
+ await sharingEventHandler.handleDriveEvent(event);
58
+ expect(cache.addSharedByMeNodeUid).not.toHaveBeenCalled();
59
+ expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
60
+ });
61
+
62
+ it('should not add if new own node is not shared', async () => {
63
+ const event: DriveEvent = {
64
+ type: DriveEventType.NodeCreated,
65
+ nodeUid: 'newNodeUid',
66
+ parentNodeUid: 'parentUid',
67
+ isTrashed: false,
68
+ isShared: false,
69
+ eventId: '1',
70
+ treeEventScopeId: 'MyVolume1',
71
+ };
72
+ await sharingEventHandler.handleDriveEvent(event);
73
+ expect(cache.addSharedByMeNodeUid).not.toHaveBeenCalled();
74
+ expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
75
+ });
76
+
77
+ it('should add if own node is updated and shared', async () => {
78
+ const event: DriveEvent = {
79
+ type: DriveEventType.NodeUpdated,
80
+ nodeUid: 'cachedNodeUid',
81
+ parentNodeUid: 'parentUid',
82
+ isTrashed: false,
83
+ isShared: true,
84
+ eventId: '1',
85
+ treeEventScopeId: 'MyVolume1',
86
+ };
87
+ await sharingEventHandler.handleDriveEvent(event);
88
+ expect(cache.addSharedByMeNodeUid).toHaveBeenCalledWith('cachedNodeUid');
89
+ expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
90
+ });
91
+
92
+ it('should remove if shared node is un-shared', async () => {
93
+ const event: DriveEvent = {
94
+ type: DriveEventType.NodeUpdated,
95
+ nodeUid: 'cachedNodeUid',
96
+ parentNodeUid: 'parentUid',
97
+ isTrashed: false,
98
+ isShared: false,
99
+ eventId: '1',
100
+ treeEventScopeId: 'MyVolume1',
101
+ };
102
+ await sharingEventHandler.handleDriveEvent(event);
103
+ expect(cache.removeSharedByMeNodeUid).toHaveBeenCalledWith('cachedNodeUid');
104
+ expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
105
+ });
106
+
107
+ it('should remove if shared node is deleted', async () => {
108
+ const event: DriveEvent = {
109
+ type: DriveEventType.NodeDeleted,
110
+ nodeUid: 'cachedNodeUid',
111
+ parentNodeUid: 'parentUid',
112
+ eventId: '1',
113
+ treeEventScopeId: 'MyVolume1',
114
+ };
115
+ await sharingEventHandler.handleDriveEvent(event);
116
+ expect(cache.removeSharedByMeNodeUid).toHaveBeenCalledWith('cachedNodeUid');
117
+ expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
118
+ });
119
+
120
+ it('should not update cache if shared by me is not loaded', async () => {
121
+ cache.hasSharedByMeNodeUidsLoaded = jest.fn().mockResolvedValue(false);
122
+ const event: DriveEvent = {
123
+ eventId: '1',
124
+ type: DriveEventType.NodeCreated,
125
+ nodeUid: 'newNodeUid',
126
+ parentNodeUid: 'parentUid',
127
+ isTrashed: false,
128
+ isShared: true,
129
+ treeEventScopeId: 'MyVolume1',
130
+ };
131
+ await sharingEventHandler.handleDriveEvent(event);
132
+ expect(cache.addSharedByMeNodeUid).not.toHaveBeenCalled();
133
+ expect(cache.setSharedWithMeNodeUids).not.toHaveBeenCalled();
119
134
  });
120
135
  });
121
136
 
@@ -141,7 +156,7 @@ describe('handleSharedWithMeNodes', () => {
141
156
  } as any;
142
157
  });
143
158
 
144
- it('should only update cache', async () => {
159
+ it('should update cache', async () => {
145
160
  const event: DriveEvent = {
146
161
  type: DriveEventType.SharedWithMeUpdated,
147
162
  eventId: 'event1',
@@ -30,26 +30,41 @@ export class SharingEventHandler {
30
30
  await this.cache.setSharedWithMeNodeUids(undefined);
31
31
  return;
32
32
  }
33
- if (!(await this.shares.isOwnVolume(event.treeEventScopeId))) {
34
- return;
35
- }
36
- if (event.type === DriveEventType.NodeCreated || event.type == DriveEventType.NodeUpdated) {
37
- if (event.isShared && !event.isTrashed) {
38
- await this.cache.addSharedByMeNodeUid(event.nodeUid);
39
- } else {
40
- await this.cache.removeSharedByMeNodeUid(event.nodeUid);
41
- }
42
- return;
43
- }
44
- if (event.type === DriveEventType.NodeDeleted) {
45
- await this.cache.removeSharedByMeNodeUid(event.nodeUid);
46
- return;
47
- }
48
- if (event.type === DriveEventType.TreeRefresh || event.type === DriveEventType.TreeRemove) {
49
- await this.cache.setSharedWithMeNodeUids(undefined);
50
- }
33
+ await this.handleSharedByMeNodeUidsLoaded(event);
51
34
  } catch (error: unknown) {
52
35
  this.logger.error(`Skipping shared by me node cache update`, error);
53
36
  }
54
37
  }
38
+
39
+ private async handleSharedByMeNodeUidsLoaded(event: DriveEvent) {
40
+ if (event.type === DriveEventType.TreeRefresh || event.type === DriveEventType.TreeRemove) {
41
+ await this.cache.setSharedWithMeNodeUids(undefined);
42
+ return;
43
+ }
44
+
45
+ if (![DriveEventType.NodeCreated, DriveEventType.NodeUpdated, DriveEventType.NodeDeleted].includes(event.type)) {
46
+ return;
47
+ }
48
+
49
+ const hasSharedByMeLoaded = await this.cache.hasSharedByMeNodeUidsLoaded();
50
+ if (!hasSharedByMeLoaded) {
51
+ return;
52
+ }
53
+
54
+ const isOwnVolume = await this.shares.isOwnVolume(event.treeEventScopeId);
55
+ if (!isOwnVolume) {
56
+ return;
57
+ }
58
+
59
+ if (event.type === DriveEventType.NodeCreated || event.type == DriveEventType.NodeUpdated) {
60
+ if (event.isShared && !event.isTrashed) {
61
+ await this.cache.addSharedByMeNodeUid(event.nodeUid);
62
+ } else {
63
+ await this.cache.removeSharedByMeNodeUid(event.nodeUid);
64
+ }
65
+ }
66
+ if (event.type === DriveEventType.NodeDeleted) {
67
+ await this.cache.removeSharedByMeNodeUid(event.nodeUid);
68
+ }
69
+ }
55
70
  }
@@ -106,6 +106,7 @@ export interface NodesService {
106
106
  addressKeyId: string;
107
107
  }>;
108
108
  notifyChildCreated(nodeUid: string): Promise<void>;
109
+ notifyNodeChanged(nodeUid: string): Promise<void>;
109
110
  }
110
111
 
111
112
  /**
@@ -91,9 +91,8 @@ describe('UploadManager', () => {
91
91
  email: 'signatureEmail',
92
92
  addressId: 'addressId',
93
93
  }),
94
- notifyChildCreated: jest.fn(async (nodeUid: string) => {
95
- return;
96
- }),
94
+ notifyChildCreated: jest.fn(),
95
+ notifyNodeChanged: jest.fn(),
97
96
  };
98
97
 
99
98
  manager = new UploadManager(telemetry, apiService, cryptoService, nodesService, clientUid);
@@ -337,10 +336,6 @@ describe('UploadManager', () => {
337
336
  },
338
337
  };
339
338
  const manifest = new Uint8Array([1, 2, 3]);
340
- const metadata = {
341
- mediaType: 'myMimeType',
342
- expectedSize: 123456,
343
- };
344
339
  const extendedAttributes = {
345
340
  modificationTime: new Date(),
346
341
  digests: {
@@ -349,7 +344,7 @@ describe('UploadManager', () => {
349
344
  };
350
345
 
351
346
  it('should commit revision draft', async () => {
352
- await manager.commitDraft(nodeRevisionDraft as any, manifest, metadata, extendedAttributes);
347
+ await manager.commitDraft(nodeRevisionDraft as any, manifest, extendedAttributes);
353
348
 
354
349
  expect(cryptoService.commitFile).toHaveBeenCalledWith(
355
350
  nodeRevisionDraft.nodeKeys,
@@ -360,7 +355,8 @@ describe('UploadManager', () => {
360
355
  nodeRevisionDraft.nodeRevisionUid,
361
356
  expect.anything(),
362
357
  );
363
- expect(nodesService.notifyChildCreated).toHaveBeenCalledWith('parentUid');
358
+ expect(nodesService.notifyNodeChanged).toHaveBeenCalledWith('newNode:nodeUid');
359
+ expect(nodesService.notifyChildCreated).not.toHaveBeenCalled();
364
360
  });
365
361
 
366
362
  it('should commit node draft', async () => {
@@ -373,7 +369,7 @@ describe('UploadManager', () => {
373
369
  hash: 'newNode:hash',
374
370
  },
375
371
  };
376
- await manager.commitDraft(nodeRevisionDraftWithNewNodeInfo as any, manifest, metadata, extendedAttributes);
372
+ await manager.commitDraft(nodeRevisionDraftWithNewNodeInfo as any, manifest, extendedAttributes);
377
373
 
378
374
  expect(cryptoService.commitFile).toHaveBeenCalledWith(
379
375
  nodeRevisionDraft.nodeKeys,
@@ -385,6 +381,7 @@ describe('UploadManager', () => {
385
381
  expect.anything(),
386
382
  );
387
383
  expect(nodesService.notifyChildCreated).toHaveBeenCalledWith('parentUid');
384
+ expect(nodesService.notifyNodeChanged).not.toHaveBeenCalled();
388
385
  });
389
386
  });
390
387
  });
@@ -260,7 +260,6 @@ export class UploadManager {
260
260
  async commitDraft(
261
261
  nodeRevisionDraft: NodeRevisionDraft,
262
262
  manifest: Uint8Array,
263
- _metadata: UploadMetadata,
264
263
  extendedAttributes: {
265
264
  modificationTime?: Date;
266
265
  size?: number;
@@ -277,9 +276,13 @@ export class UploadManager {
277
276
  generatedExtendedAttributes,
278
277
  );
279
278
  await this.apiService.commitDraftRevision(nodeRevisionDraft.nodeRevisionUid, nodeCommitCrypto);
280
- const node = await this.nodesService.getNode(nodeRevisionDraft.nodeUid);
281
- if (node.parentUid) {
282
- await this.nodesService.notifyChildCreated(node.parentUid);
279
+
280
+ // If new revision to existing node was created, invalidate the node.
281
+ // Otherwise notify about the new child in the parent.
282
+ if (nodeRevisionDraft.newNodeInfo) {
283
+ await this.nodesService.notifyChildCreated(nodeRevisionDraft.newNodeInfo.parentUid);
284
+ } else {
285
+ await this.nodesService.notifyNodeChanged(nodeRevisionDraft.nodeUid);
283
286
  }
284
287
  }
285
288
  }
@@ -147,7 +147,7 @@ describe('StreamUploader', () => {
147
147
 
148
148
  const numberOfExpectedBlocks = Math.ceil(metadata.expectedSize / FILE_CHUNK_SIZE);
149
149
  expect(uploadManager.commitDraft).toHaveBeenCalledTimes(1);
150
- expect(uploadManager.commitDraft).toHaveBeenCalledWith(revisionDraft, expect.anything(), metadata, {
150
+ expect(uploadManager.commitDraft).toHaveBeenCalledWith(revisionDraft, expect.anything(), {
151
151
  size: metadata.expectedSize,
152
152
  blockSizes: metadata.expectedSize
153
153
  ? [
@@ -217,7 +217,7 @@ export class StreamUploader {
217
217
  blockSizes: uploadedBlocks.map((block) => block.originalSize),
218
218
  digests: this.digests.digests(),
219
219
  };
220
- await this.uploadManager.commitDraft(this.revisionDraft, this.manifest, this.metadata, extendedAttributes);
220
+ await this.uploadManager.commitDraft(this.revisionDraft, this.manifest, extendedAttributes);
221
221
  }
222
222
 
223
223
  private async encryptThumbnails(thumbnails: Thumbnail[]) {
@@ -155,8 +155,8 @@ export class ProtonDriveClient {
155
155
  );
156
156
  // These are used to keep the internal cache up to date
157
157
  const cacheEventListeners: DriveListener[] = [
158
- this.nodes.eventHandler.updateNodesCacheOnEvent,
159
- this.sharing.eventHandler.handleDriveEvent,
158
+ this.nodes.eventHandler.updateNodesCacheOnEvent.bind(this.nodes.eventHandler),
159
+ this.sharing.eventHandler.handleDriveEvent.bind(this.sharing.eventHandler),
160
160
  ];
161
161
  this.events = new DriveEventsService(
162
162
  telemetry,
@@ -29,6 +29,7 @@ type InternalPartialNode = Pick<
29
29
  | 'totalStorageSize'
30
30
  | 'errors'
31
31
  | 'shareId'
32
+ | 'treeEventScopeId'
32
33
  >;
33
34
 
34
35
  type NodeUid = string | { uid: string } | Result<{ uid: string }, { uid: string }>;
@@ -92,6 +93,7 @@ export function convertInternalNode(node: InternalPartialNode): PublicMaybeNode
92
93
  totalStorageSize: node.totalStorageSize,
93
94
  folder: node.folder,
94
95
  deprecatedShareId: node.shareId,
96
+ treeEventScopeId: node.treeEventScopeId,
95
97
  };
96
98
 
97
99
  const name = node.name;