@protontech/drive-sdk 0.0.13 → 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.
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.js +3 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/memoryCache.d.ts +1 -1
- package/dist/cache/nullCache.d.ts +14 -0
- package/dist/cache/nullCache.js +37 -0
- package/dist/cache/nullCache.js.map +1 -0
- package/dist/config.d.ts +16 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/crypto/openPGPCrypto.js +2 -0
- package/dist/crypto/openPGPCrypto.js.map +1 -1
- package/dist/diagnostic/eventsGenerator.d.ts +14 -0
- package/dist/diagnostic/eventsGenerator.js +49 -0
- package/dist/diagnostic/eventsGenerator.js.map +1 -0
- package/dist/diagnostic/httpClient.d.ts +16 -0
- package/dist/diagnostic/httpClient.js +81 -0
- package/dist/diagnostic/httpClient.js.map +1 -0
- package/dist/diagnostic/index.d.ts +10 -0
- package/dist/diagnostic/index.js +35 -0
- package/dist/diagnostic/index.js.map +1 -0
- package/dist/diagnostic/integrityVerificationStream.d.ts +21 -0
- package/dist/diagnostic/integrityVerificationStream.js +56 -0
- package/dist/diagnostic/integrityVerificationStream.js.map +1 -0
- package/dist/diagnostic/interface.d.ts +102 -0
- package/dist/diagnostic/interface.js +3 -0
- package/dist/diagnostic/interface.js.map +1 -0
- package/dist/diagnostic/sdkDiagnostic.d.ts +22 -0
- package/dist/diagnostic/sdkDiagnostic.js +216 -0
- package/dist/diagnostic/sdkDiagnostic.js.map +1 -0
- package/dist/diagnostic/sdkDiagnosticFull.d.ts +18 -0
- package/dist/diagnostic/sdkDiagnosticFull.js +35 -0
- package/dist/diagnostic/sdkDiagnosticFull.js.map +1 -0
- package/dist/diagnostic/telemetry.d.ts +25 -0
- package/dist/diagnostic/telemetry.js +70 -0
- package/dist/diagnostic/telemetry.js.map +1 -0
- package/dist/diagnostic/zipGenerators.d.ts +9 -0
- package/dist/diagnostic/zipGenerators.js +64 -0
- package/dist/diagnostic/zipGenerators.js.map +1 -0
- package/dist/diagnostic/zipGenerators.test.js +144 -0
- package/dist/diagnostic/zipGenerators.test.js.map +1 -0
- package/dist/errors.d.ts +2 -1
- package/dist/errors.js +3 -1
- package/dist/errors.js.map +1 -1
- package/dist/interface/config.d.ts +26 -0
- package/dist/interface/config.js +3 -0
- package/dist/interface/config.js.map +1 -0
- package/dist/interface/download.d.ts +2 -2
- package/dist/interface/events.d.ts +60 -20
- package/dist/interface/events.js +11 -1
- package/dist/interface/events.js.map +1 -1
- package/dist/interface/httpClient.d.ts +0 -14
- package/dist/interface/index.d.ts +8 -4
- package/dist/interface/index.js +2 -1
- package/dist/interface/index.js.map +1 -1
- package/dist/interface/nodes.d.ts +9 -0
- package/dist/interface/nodes.js.map +1 -1
- package/dist/interface/sharing.d.ts +1 -0
- package/dist/interface/upload.d.ts +6 -0
- package/dist/internal/download/apiService.js +32 -31
- package/dist/internal/download/apiService.js.map +1 -1
- package/dist/internal/download/fileDownloader.d.ts +2 -2
- package/dist/internal/download/fileDownloader.js.map +1 -1
- package/dist/internal/events/apiService.d.ts +4 -6
- package/dist/internal/events/apiService.js +15 -22
- package/dist/internal/events/apiService.js.map +1 -1
- package/dist/internal/events/coreEventManager.d.ts +7 -10
- package/dist/internal/events/coreEventManager.js +19 -36
- package/dist/internal/events/coreEventManager.js.map +1 -1
- package/dist/internal/events/coreEventManager.test.js +87 -0
- package/dist/internal/events/coreEventManager.test.js.map +1 -0
- package/dist/internal/events/eventManager.d.ts +11 -36
- package/dist/internal/events/eventManager.js +59 -105
- package/dist/internal/events/eventManager.js.map +1 -1
- package/dist/internal/events/eventManager.test.js +167 -82
- package/dist/internal/events/eventManager.test.js.map +1 -1
- package/dist/internal/events/index.d.ts +13 -33
- package/dist/internal/events/index.js +56 -72
- package/dist/internal/events/index.js.map +1 -1
- package/dist/internal/events/interface.d.ts +59 -14
- package/dist/internal/events/interface.js +13 -3
- package/dist/internal/events/interface.js.map +1 -1
- package/dist/internal/events/volumeEventManager.d.ts +7 -17
- package/dist/internal/events/volumeEventManager.js +58 -45
- package/dist/internal/events/volumeEventManager.js.map +1 -1
- package/dist/internal/events/volumeEventManager.test.d.ts +1 -0
- package/dist/internal/events/volumeEventManager.test.js +203 -0
- package/dist/internal/events/volumeEventManager.test.js.map +1 -0
- package/dist/internal/nodes/cache.d.ts +10 -1
- package/dist/internal/nodes/cache.js +17 -0
- package/dist/internal/nodes/cache.js.map +1 -1
- package/dist/internal/nodes/cryptoService.d.ts +1 -1
- package/dist/internal/nodes/cryptoService.js.map +1 -1
- package/dist/internal/nodes/events.d.ts +7 -83
- package/dist/internal/nodes/events.js +43 -217
- package/dist/internal/nodes/events.js.map +1 -1
- package/dist/internal/nodes/events.test.js +27 -277
- package/dist/internal/nodes/events.test.js.map +1 -1
- package/dist/internal/nodes/index.d.ts +3 -4
- package/dist/internal/nodes/index.js +5 -5
- package/dist/internal/nodes/index.js.map +1 -1
- package/dist/internal/nodes/nodesAccess.d.ts +15 -0
- package/dist/internal/nodes/nodesAccess.js +37 -0
- package/dist/internal/nodes/nodesAccess.js.map +1 -1
- package/dist/internal/nodes/nodesAccess.test.js +131 -93
- package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.d.ts +1 -3
- package/dist/internal/nodes/nodesManagement.js +12 -26
- package/dist/internal/nodes/nodesManagement.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.test.js +35 -14
- package/dist/internal/nodes/nodesManagement.test.js.map +1 -1
- package/dist/internal/shares/cache.d.ts +2 -0
- package/dist/internal/shares/cache.js +2 -0
- package/dist/internal/shares/cache.js.map +1 -1
- package/dist/internal/shares/manager.d.ts +1 -0
- package/dist/internal/shares/manager.js +3 -0
- package/dist/internal/shares/manager.js.map +1 -1
- package/dist/internal/sharing/apiService.js +1 -0
- package/dist/internal/sharing/apiService.js.map +1 -1
- package/dist/internal/sharing/cryptoService.js +1 -0
- package/dist/internal/sharing/cryptoService.js.map +1 -1
- package/dist/internal/sharing/events.d.ts +23 -55
- package/dist/internal/sharing/events.js +46 -138
- package/dist/internal/sharing/events.js.map +1 -1
- package/dist/internal/sharing/events.test.js +77 -180
- package/dist/internal/sharing/events.test.js.map +1 -1
- package/dist/internal/sharing/index.d.ts +4 -5
- package/dist/internal/sharing/index.js +5 -5
- package/dist/internal/sharing/index.js.map +1 -1
- package/dist/internal/sharing/interface.d.ts +3 -0
- package/dist/internal/sharing/sharingManagement.d.ts +2 -3
- package/dist/internal/sharing/sharingManagement.js +7 -9
- package/dist/internal/sharing/sharingManagement.js.map +1 -1
- package/dist/internal/sharing/sharingManagement.test.js +9 -39
- package/dist/internal/sharing/sharingManagement.test.js.map +1 -1
- package/dist/internal/upload/apiService.d.ts +2 -3
- package/dist/internal/upload/apiService.js +7 -4
- package/dist/internal/upload/apiService.js.map +1 -1
- package/dist/internal/upload/index.d.ts +2 -2
- package/dist/internal/upload/index.js +3 -3
- package/dist/internal/upload/index.js.map +1 -1
- package/dist/internal/upload/interface.d.ts +2 -0
- package/dist/internal/upload/manager.d.ts +5 -5
- package/dist/internal/upload/manager.js +19 -50
- package/dist/internal/upload/manager.js.map +1 -1
- package/dist/internal/upload/manager.test.js +68 -44
- package/dist/internal/upload/manager.test.js.map +1 -1
- package/dist/internal/upload/streamUploader.js +1 -2
- package/dist/internal/upload/streamUploader.js.map +1 -1
- package/dist/internal/upload/streamUploader.test.js +1 -1
- package/dist/internal/upload/streamUploader.test.js.map +1 -1
- package/dist/protonDriveClient.d.ts +19 -162
- package/dist/protonDriveClient.js +26 -190
- package/dist/protonDriveClient.js.map +1 -1
- package/dist/protonDrivePhotosClient.js +3 -2
- package/dist/protonDrivePhotosClient.js.map +1 -1
- package/package.json +3 -3
- package/src/cache/index.ts +1 -0
- package/src/cache/memoryCache.ts +1 -1
- package/src/cache/nullCache.ts +38 -0
- package/src/config.ts +17 -2
- package/src/crypto/openPGPCrypto.ts +2 -0
- package/src/diagnostic/eventsGenerator.ts +48 -0
- package/src/diagnostic/httpClient.ts +80 -0
- package/src/diagnostic/index.ts +38 -0
- package/src/diagnostic/integrityVerificationStream.ts +56 -0
- package/src/diagnostic/interface.ts +158 -0
- package/src/diagnostic/sdkDiagnostic.ts +238 -0
- package/src/diagnostic/sdkDiagnosticFull.ts +40 -0
- package/src/diagnostic/telemetry.ts +71 -0
- package/src/diagnostic/zipGenerators.test.ts +177 -0
- package/src/diagnostic/zipGenerators.ts +70 -0
- package/src/errors.ts +4 -1
- package/src/interface/config.ts +28 -0
- package/src/interface/download.ts +2 -2
- package/src/interface/events.ts +66 -21
- package/src/interface/httpClient.ts +0 -16
- package/src/interface/index.ts +8 -4
- package/src/interface/nodes.ts +21 -12
- package/src/interface/sharing.ts +1 -0
- package/src/interface/upload.ts +6 -0
- package/src/internal/download/apiService.ts +11 -8
- package/src/internal/download/fileDownloader.ts +2 -2
- package/src/internal/events/apiService.ts +25 -28
- package/src/internal/events/coreEventManager.test.ts +101 -0
- package/src/internal/events/coreEventManager.ts +20 -45
- package/src/internal/events/eventManager.test.ts +201 -88
- package/src/internal/events/eventManager.ts +69 -115
- package/src/internal/events/index.ts +54 -84
- package/src/internal/events/interface.ts +70 -15
- package/src/internal/events/volumeEventManager.test.ts +243 -0
- package/src/internal/events/volumeEventManager.ts +55 -53
- package/src/internal/nodes/cache.ts +20 -2
- package/src/internal/nodes/cryptoService.ts +1 -1
- package/src/internal/nodes/events.test.ts +29 -335
- package/src/internal/nodes/events.ts +45 -253
- package/src/internal/nodes/index.ts +6 -8
- package/src/internal/nodes/interface.ts +2 -2
- package/src/internal/nodes/nodesAccess.test.ts +132 -91
- package/src/internal/nodes/nodesAccess.ts +40 -1
- package/src/internal/nodes/nodesManagement.test.ts +39 -15
- package/src/internal/nodes/nodesManagement.ts +12 -30
- package/src/internal/shares/cache.ts +4 -2
- package/src/internal/shares/manager.ts +9 -5
- package/src/internal/sharing/apiService.ts +1 -0
- package/src/internal/sharing/cache.ts +1 -1
- package/src/internal/sharing/cryptoService.ts +1 -0
- package/src/internal/sharing/events.test.ts +89 -195
- package/src/internal/sharing/events.ts +42 -156
- package/src/internal/sharing/index.ts +6 -9
- package/src/internal/sharing/interface.ts +6 -2
- package/src/internal/sharing/sharingManagement.test.ts +10 -40
- package/src/internal/sharing/sharingManagement.ts +7 -11
- package/src/internal/upload/apiService.ts +5 -6
- package/src/internal/upload/index.ts +5 -5
- package/src/internal/upload/interface.ts +2 -0
- package/src/internal/upload/manager.test.ts +75 -45
- package/src/internal/upload/manager.ts +24 -54
- package/src/internal/upload/streamUploader.test.ts +0 -1
- package/src/internal/upload/streamUploader.ts +0 -2
- package/src/protonDriveClient.ts +75 -244
- package/src/protonDrivePhotosClient.ts +4 -3
- package/dist/internal/events/cache.d.ts +0 -28
- package/dist/internal/events/cache.js +0 -67
- package/dist/internal/events/cache.js.map +0 -1
- package/dist/internal/events/cache.test.js +0 -43
- package/dist/internal/events/cache.test.js.map +0 -1
- package/dist/internal/nodes/index.test.js +0 -114
- package/dist/internal/nodes/index.test.js.map +0 -1
- package/src/internal/events/cache.test.ts +0 -47
- package/src/internal/events/cache.ts +0 -80
- package/src/internal/nodes/index.test.ts +0 -137
- /package/dist/{internal/events/cache.test.d.ts → diagnostic/zipGenerators.test.d.ts} +0 -0
- /package/dist/internal/{nodes/index.test.d.ts → events/coreEventManager.test.d.ts} +0 -0
|
@@ -22,7 +22,7 @@ describe('nodesAccess', () => {
|
|
|
22
22
|
apiService = {
|
|
23
23
|
getNode: jest.fn(),
|
|
24
24
|
iterateNodes: jest.fn().mockImplementation(async function* (uids: string[]) {
|
|
25
|
-
yield* uids.map((uid => ({ uid, parentUid: '
|
|
25
|
+
yield* uids.map((uid => ({ uid, parentUid: 'volumeId~parentNodeId' } as EncryptedNode)));
|
|
26
26
|
}),
|
|
27
27
|
iterateChildrenNodeUids: jest.fn(),
|
|
28
28
|
}
|
|
@@ -55,49 +55,51 @@ describe('nodesAccess', () => {
|
|
|
55
55
|
|
|
56
56
|
describe('getNode', () => {
|
|
57
57
|
it('should get node from cache', async () => {
|
|
58
|
-
const node = { uid: 'nodeId', isStale: false } as DecryptedNode;
|
|
58
|
+
const node = { uid: 'volumeId~nodeId', isStale: false } as DecryptedNode;
|
|
59
59
|
cache.getNode = jest.fn(() => Promise.resolve(node));
|
|
60
60
|
|
|
61
|
-
const result = await access.getNode('nodeId');
|
|
61
|
+
const result = await access.getNode('volumeId~nodeId');
|
|
62
62
|
expect(result).toBe(node);
|
|
63
63
|
expect(apiService.getNode).not.toHaveBeenCalled();
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
it('should get node from API when
|
|
67
|
-
const encryptedNode = { uid: 'nodeId', parentUid: '
|
|
68
|
-
const decryptedUnparsedNode = { uid: 'nodeId', parentUid: '
|
|
66
|
+
it('should get node from API when cache is stale', async () => {
|
|
67
|
+
const encryptedNode = { uid: 'volumeId~nodeId', parentUid: 'volumeId~parentNodeid' } as EncryptedNode;
|
|
68
|
+
const decryptedUnparsedNode = { uid: 'volumeId~nodeId', parentUid: 'volumeId~parentNodeid', name: { ok: true, value: 'name' } } as DecryptedUnparsedNode;
|
|
69
69
|
const decryptedNode = {
|
|
70
70
|
...decryptedUnparsedNode,
|
|
71
71
|
name: { ok: true, value: 'name' },
|
|
72
72
|
isStale: false,
|
|
73
73
|
activeRevision: undefined,
|
|
74
74
|
folder: undefined,
|
|
75
|
+
treeEventScopeId: "volumeId",
|
|
75
76
|
} as DecryptedNode;
|
|
76
77
|
const decryptedKeys = { key: 'key' } as any as DecryptedNodeKeys;
|
|
77
78
|
|
|
78
|
-
cache.getNode = jest.fn(() => Promise.resolve({ uid: 'nodeId', isStale: true } as DecryptedNode));
|
|
79
|
+
cache.getNode = jest.fn(() => Promise.resolve({ uid: 'volumeId~nodeId', isStale: true } as DecryptedNode));
|
|
79
80
|
apiService.getNode = jest.fn(() => Promise.resolve(encryptedNode));
|
|
80
81
|
cryptoCache.getNodeKeys = jest.fn(() => Promise.resolve({ key: 'parentKey' } as any as DecryptedNodeKeys));
|
|
81
82
|
cryptoService.decryptNode = jest.fn(() => Promise.resolve({ node: decryptedUnparsedNode, keys: decryptedKeys }));
|
|
82
83
|
|
|
83
|
-
const result = await access.getNode('nodeId');
|
|
84
|
+
const result = await access.getNode('volumeId~nodeId');
|
|
84
85
|
expect(result).toEqual(decryptedNode);
|
|
85
|
-
expect(apiService.getNode).toHaveBeenCalledWith('nodeId', 'volumeId');
|
|
86
|
-
expect(cryptoCache.getNodeKeys).toHaveBeenCalledWith('
|
|
86
|
+
expect(apiService.getNode).toHaveBeenCalledWith('volumeId~nodeId', 'volumeId');
|
|
87
|
+
expect(cryptoCache.getNodeKeys).toHaveBeenCalledWith('volumeId~parentNodeid');
|
|
87
88
|
expect(cryptoService.decryptNode).toHaveBeenCalledWith(encryptedNode, 'parentKey');
|
|
88
89
|
expect(cache.setNode).toHaveBeenCalledWith(decryptedNode);
|
|
89
|
-
expect(cryptoCache.setNodeKeys).toHaveBeenCalledWith('nodeId', decryptedKeys);
|
|
90
|
+
expect(cryptoCache.setNodeKeys).toHaveBeenCalledWith('volumeId~nodeId', decryptedKeys);
|
|
90
91
|
});
|
|
91
92
|
|
|
92
93
|
it('should get node from API missing cache', async () => {
|
|
93
|
-
const encryptedNode = { uid: 'nodeId', parentUid: '
|
|
94
|
-
const decryptedUnparsedNode = { uid: 'nodeId', parentUid: '
|
|
94
|
+
const encryptedNode = { uid: 'volumeId~nodeId', parentUid: 'volumeId~parentNodeid' } as EncryptedNode;
|
|
95
|
+
const decryptedUnparsedNode = { uid: 'volumeId~nodeId', parentUid: 'volumeId~parentNodeid', name: { ok: true, value: 'name' } } as DecryptedUnparsedNode;
|
|
95
96
|
const decryptedNode = {
|
|
96
97
|
...decryptedUnparsedNode,
|
|
97
98
|
name: { ok: true, value: 'name' },
|
|
98
99
|
isStale: false,
|
|
99
100
|
activeRevision: undefined,
|
|
100
101
|
folder: undefined,
|
|
102
|
+
treeEventScopeId: 'volumeId',
|
|
101
103
|
} as DecryptedNode;
|
|
102
104
|
const decryptedKeys = { key: 'key' } as any as DecryptedNodeKeys;
|
|
103
105
|
|
|
@@ -106,21 +108,22 @@ describe('nodesAccess', () => {
|
|
|
106
108
|
cryptoCache.getNodeKeys = jest.fn(() => Promise.resolve({ key: 'parentKey' } as any as DecryptedNodeKeys));
|
|
107
109
|
cryptoService.decryptNode = jest.fn(() => Promise.resolve({ node: decryptedUnparsedNode, keys: decryptedKeys }));
|
|
108
110
|
|
|
109
|
-
const result = await access.getNode('nodeId');
|
|
111
|
+
const result = await access.getNode('volumeId~nodeId');
|
|
110
112
|
expect(result).toEqual(decryptedNode);
|
|
111
|
-
expect(apiService.getNode).toHaveBeenCalledWith('nodeId', 'volumeId');
|
|
112
|
-
expect(cryptoCache.getNodeKeys).toHaveBeenCalledWith('
|
|
113
|
+
expect(apiService.getNode).toHaveBeenCalledWith('volumeId~nodeId', 'volumeId');
|
|
114
|
+
expect(cryptoCache.getNodeKeys).toHaveBeenCalledWith('volumeId~parentNodeid');
|
|
113
115
|
expect(cryptoService.decryptNode).toHaveBeenCalledWith(encryptedNode, 'parentKey');
|
|
114
116
|
expect(cache.setNode).toHaveBeenCalledWith(decryptedNode);
|
|
115
|
-
expect(cryptoCache.setNodeKeys).toHaveBeenCalledWith('nodeId', decryptedKeys);
|
|
117
|
+
expect(cryptoCache.setNodeKeys).toHaveBeenCalledWith('volumeId~nodeId', decryptedKeys);
|
|
116
118
|
});
|
|
117
119
|
|
|
118
120
|
it('should validate node name', async () => {
|
|
119
|
-
const encryptedNode = { uid: 'nodeId', parentUid: '
|
|
120
|
-
const decryptedUnparsedNode = { uid: 'nodeId', parentUid: '
|
|
121
|
+
const encryptedNode = { uid: 'volumeId~nodeId', parentUid: 'volumeId~parentNodeid' } as EncryptedNode;
|
|
122
|
+
const decryptedUnparsedNode = { uid: 'volumeId~nodeId', parentUid: 'volumeId~parentNodeid', name: { ok: true, value: 'foo/bar' } } as DecryptedUnparsedNode;
|
|
121
123
|
const decryptedNode = {
|
|
122
124
|
...decryptedUnparsedNode,
|
|
123
125
|
name: { ok: false, error: { name: 'foo/bar', error: "Name must not contain the character '/'" } },
|
|
126
|
+
treeEventScopeId: 'volumeId',
|
|
124
127
|
} as DecryptedNode;
|
|
125
128
|
const decryptedKeys = { key: 'key' } as any as DecryptedNodeKeys;
|
|
126
129
|
|
|
@@ -129,7 +132,7 @@ describe('nodesAccess', () => {
|
|
|
129
132
|
cryptoCache.getNodeKeys = jest.fn(() => Promise.resolve({ key: 'parentKey' } as any as DecryptedNodeKeys));
|
|
130
133
|
cryptoService.decryptNode = jest.fn(() => Promise.resolve({ node: decryptedUnparsedNode, keys: decryptedKeys }));
|
|
131
134
|
|
|
132
|
-
const result = await access.getNode('nodeId');
|
|
135
|
+
const result = await access.getNode('volumeId~nodeId');
|
|
133
136
|
expect(result).toMatchObject(decryptedNode);
|
|
134
137
|
});
|
|
135
138
|
});
|
|
@@ -144,11 +147,11 @@ describe('nodesAccess', () => {
|
|
|
144
147
|
});
|
|
145
148
|
|
|
146
149
|
describe('iterateChildren', () => {
|
|
147
|
-
const parentNode = { uid: '
|
|
148
|
-
const node1 = { uid: 'node1', isStale: false } as DecryptedNode;
|
|
149
|
-
const node2 = { uid: 'node2', isStale: false } as DecryptedNode;
|
|
150
|
-
const node3 = { uid: 'node3', isStale: false } as DecryptedNode;
|
|
151
|
-
const node4 = { uid: 'node4', isStale: false } as DecryptedNode;
|
|
150
|
+
const parentNode = { uid: 'volumeId~parentNodeid', isStale: false } as DecryptedNode;
|
|
151
|
+
const node1 = { uid: 'volumeId~node1', isStale: false } as DecryptedNode;
|
|
152
|
+
const node2 = { uid: 'volumeId~node2', isStale: false } as DecryptedNode;
|
|
153
|
+
const node3 = { uid: 'volumeId~node3', isStale: false } as DecryptedNode;
|
|
154
|
+
const node4 = { uid: 'volumeId~node4', isStale: false } as DecryptedNode;
|
|
152
155
|
|
|
153
156
|
beforeEach(() => {
|
|
154
157
|
cache.getNode = jest.fn().mockResolvedValue(parentNode);
|
|
@@ -163,7 +166,7 @@ describe('nodesAccess', () => {
|
|
|
163
166
|
yield { ok: true, node: node4 };
|
|
164
167
|
});
|
|
165
168
|
|
|
166
|
-
const result = await Array.fromAsync(access.iterateFolderChildren('
|
|
169
|
+
const result = await Array.fromAsync(access.iterateFolderChildren('volumeId~parentNodeid'));
|
|
167
170
|
expect(result).toMatchObject([node1, node2, node3, node4]);
|
|
168
171
|
expect(apiService.iterateChildrenNodeUids).not.toHaveBeenCalled();
|
|
169
172
|
expect(apiService.iterateNodes).not.toHaveBeenCalled();
|
|
@@ -178,9 +181,9 @@ describe('nodesAccess', () => {
|
|
|
178
181
|
yield { ok: true, uid: node4.uid, node: node4 };
|
|
179
182
|
});
|
|
180
183
|
|
|
181
|
-
const result = await Array.fromAsync(access.iterateFolderChildren('
|
|
184
|
+
const result = await Array.fromAsync(access.iterateFolderChildren('volumeId~parentNodeid'));
|
|
182
185
|
expect(result).toMatchObject([node1, node4, node2, node3]);
|
|
183
|
-
expect(apiService.iterateNodes).toHaveBeenCalledWith([
|
|
186
|
+
expect(apiService.iterateNodes).toHaveBeenCalledWith([node2.uid, node3.uid], 'volumeId', undefined);
|
|
184
187
|
expect(cryptoService.decryptNode).toHaveBeenCalledTimes(2);
|
|
185
188
|
expect(cache.setNode).toHaveBeenCalledTimes(2);
|
|
186
189
|
expect(cryptoCache.setNodeKeys).toHaveBeenCalledTimes(2);
|
|
@@ -188,26 +191,26 @@ describe('nodesAccess', () => {
|
|
|
188
191
|
|
|
189
192
|
it('should load children uids and serve nodes from cache', async () => {
|
|
190
193
|
apiService.iterateChildrenNodeUids = jest.fn().mockImplementation(async function* () {
|
|
191
|
-
yield
|
|
192
|
-
yield
|
|
193
|
-
yield
|
|
194
|
-
yield
|
|
194
|
+
yield node1.uid;
|
|
195
|
+
yield node2.uid;
|
|
196
|
+
yield node3.uid;
|
|
197
|
+
yield node4.uid;
|
|
195
198
|
});
|
|
196
199
|
cache.getNode = jest.fn().mockImplementation((uid: string) => ({ uid, isStale: false }));
|
|
197
200
|
|
|
198
|
-
const result = await Array.fromAsync(access.iterateFolderChildren('
|
|
201
|
+
const result = await Array.fromAsync(access.iterateFolderChildren('volumeId~parentNodeid'));
|
|
199
202
|
expect(result).toMatchObject([node1, node2, node3, node4]);
|
|
200
|
-
expect(apiService.iterateChildrenNodeUids).toHaveBeenCalledWith('
|
|
203
|
+
expect(apiService.iterateChildrenNodeUids).toHaveBeenCalledWith('volumeId~parentNodeid', undefined);
|
|
201
204
|
expect(apiService.iterateNodes).not.toHaveBeenCalled();
|
|
202
|
-
expect(cache.setFolderChildrenLoaded).toHaveBeenCalledWith('
|
|
205
|
+
expect(cache.setFolderChildrenLoaded).toHaveBeenCalledWith('volumeId~parentNodeid');
|
|
203
206
|
});
|
|
204
207
|
|
|
205
208
|
it('should load from API', async () => {
|
|
206
209
|
apiService.iterateChildrenNodeUids = jest.fn().mockImplementation(async function* () {
|
|
207
|
-
yield
|
|
208
|
-
yield
|
|
209
|
-
yield
|
|
210
|
-
yield
|
|
210
|
+
yield node1.uid;
|
|
211
|
+
yield node2.uid;
|
|
212
|
+
yield node3.uid;
|
|
213
|
+
yield node4.uid;
|
|
211
214
|
});
|
|
212
215
|
cache.getNode = jest.fn().mockImplementation((uid: string) => {
|
|
213
216
|
if (uid === parentNode.uid) {
|
|
@@ -216,21 +219,21 @@ describe('nodesAccess', () => {
|
|
|
216
219
|
throw new Error('Entity not found');
|
|
217
220
|
});
|
|
218
221
|
|
|
219
|
-
const result = await Array.fromAsync(access.iterateFolderChildren('
|
|
222
|
+
const result = await Array.fromAsync(access.iterateFolderChildren('volumeId~parentNodeid'));
|
|
220
223
|
expect(result).toMatchObject([node1, node2, node3, node4]);
|
|
221
|
-
expect(apiService.iterateChildrenNodeUids).toHaveBeenCalledWith('
|
|
222
|
-
expect(apiService.iterateNodes).toHaveBeenCalledWith(['node1', 'node2', 'node3', 'node4'], 'volumeId', undefined);
|
|
224
|
+
expect(apiService.iterateChildrenNodeUids).toHaveBeenCalledWith('volumeId~parentNodeid', undefined);
|
|
225
|
+
expect(apiService.iterateNodes).toHaveBeenCalledWith(['volumeId~node1', 'volumeId~node2', 'volumeId~node3', 'volumeId~node4'], 'volumeId', undefined);
|
|
223
226
|
expect(cryptoService.decryptNode).toHaveBeenCalledTimes(4);
|
|
224
227
|
expect(cache.setNode).toHaveBeenCalledTimes(4);
|
|
225
228
|
expect(cryptoCache.setNodeKeys).toHaveBeenCalledTimes(4);
|
|
226
|
-
expect(cache.setFolderChildrenLoaded).toHaveBeenCalledWith('
|
|
229
|
+
expect(cache.setFolderChildrenLoaded).toHaveBeenCalledWith('volumeId~parentNodeid');
|
|
227
230
|
});
|
|
228
231
|
|
|
229
232
|
it('should remove from cache if missing on API', async () => {
|
|
230
233
|
apiService.iterateChildrenNodeUids = jest.fn().mockImplementation(async function* () {
|
|
231
|
-
yield
|
|
232
|
-
yield
|
|
233
|
-
yield
|
|
234
|
+
yield node1.uid;
|
|
235
|
+
yield node2.uid;
|
|
236
|
+
yield node3.uid;
|
|
234
237
|
});
|
|
235
238
|
cache.getNode = jest.fn().mockImplementation((uid: string) => {
|
|
236
239
|
if (uid === parentNode.uid) {
|
|
@@ -243,16 +246,16 @@ describe('nodesAccess', () => {
|
|
|
243
246
|
yield* uids.slice(1).map((uid) => ({ uid, parentUid: parentNode.uid } as EncryptedNode));
|
|
244
247
|
});
|
|
245
248
|
|
|
246
|
-
const result = await Array.fromAsync(access.iterateFolderChildren('
|
|
249
|
+
const result = await Array.fromAsync(access.iterateFolderChildren('volumeId~parentNodeid'));
|
|
247
250
|
expect(result).toMatchObject([node2, node3]);
|
|
248
|
-
expect(cache.removeNodes).toHaveBeenCalledWith([
|
|
251
|
+
expect(cache.removeNodes).toHaveBeenCalledWith([node1.uid]);
|
|
249
252
|
});
|
|
250
253
|
|
|
251
254
|
it('should yield all decryptable children before throwing error', async () => {
|
|
252
255
|
apiService.iterateChildrenNodeUids = jest.fn().mockImplementation(async function* () {
|
|
253
|
-
yield 'node1';
|
|
254
|
-
yield 'node2';
|
|
255
|
-
yield 'node3';
|
|
256
|
+
yield 'volumeId~node1';
|
|
257
|
+
yield 'volumeId~node2';
|
|
258
|
+
yield 'volumeId~node3';
|
|
256
259
|
});
|
|
257
260
|
cache.getNode = jest.fn().mockImplementation((uid: string) => {
|
|
258
261
|
if (uid === parentNode.uid) {
|
|
@@ -261,7 +264,7 @@ describe('nodesAccess', () => {
|
|
|
261
264
|
throw new Error('Entity not found');
|
|
262
265
|
});
|
|
263
266
|
cryptoService.decryptNode = jest.fn().mockImplementation((encryptedNode: EncryptedNode) => {
|
|
264
|
-
if (encryptedNode.uid === 'node2') {
|
|
267
|
+
if (encryptedNode.uid === 'volumeId~node2') {
|
|
265
268
|
throw new DecryptionError('Decryption failed');
|
|
266
269
|
}
|
|
267
270
|
return Promise.resolve({
|
|
@@ -270,11 +273,11 @@ describe('nodesAccess', () => {
|
|
|
270
273
|
});
|
|
271
274
|
});
|
|
272
275
|
|
|
273
|
-
const generator = access.iterateFolderChildren('
|
|
276
|
+
const generator = access.iterateFolderChildren('volumeId~parentNodeid');
|
|
274
277
|
const node1 = await generator.next();
|
|
275
|
-
expect(node1.value).toMatchObject({ uid: 'node1' });
|
|
278
|
+
expect(node1.value).toMatchObject({ uid: 'volumeId~node1' });
|
|
276
279
|
const node2 = await generator.next();
|
|
277
|
-
expect(node2.value).toMatchObject({ uid: 'node3' });
|
|
280
|
+
expect(node2.value).toMatchObject({ uid: 'volumeId~node3' });
|
|
278
281
|
const node3 = generator.next();
|
|
279
282
|
await expect(node3).rejects.toThrow('Failed to decrypt some nodes');
|
|
280
283
|
try {
|
|
@@ -289,10 +292,10 @@ describe('nodesAccess', () => {
|
|
|
289
292
|
|
|
290
293
|
describe('iterateTrashedNodes', () => {
|
|
291
294
|
const volumeId = 'volumeId';
|
|
292
|
-
const node1 = { uid: 'node1', isStale: false } as DecryptedNode;
|
|
293
|
-
const node2 = { uid: 'node2', isStale: false } as DecryptedNode;
|
|
294
|
-
const node3 = { uid: 'node3', isStale: false } as DecryptedNode;
|
|
295
|
-
const node4 = { uid: 'node4', isStale: false } as DecryptedNode;
|
|
295
|
+
const node1 = { uid: 'volumeId~node1', isStale: false } as DecryptedNode;
|
|
296
|
+
const node2 = { uid: 'volumeId~node2', isStale: false } as DecryptedNode;
|
|
297
|
+
const node3 = { uid: 'volumeId~node3', isStale: false } as DecryptedNode;
|
|
298
|
+
const node4 = { uid: 'volumeId~node4', isStale: false } as DecryptedNode;
|
|
296
299
|
|
|
297
300
|
beforeEach(() => {
|
|
298
301
|
shareService.getMyFilesIDs = jest.fn().mockResolvedValue({ volumeId });
|
|
@@ -321,7 +324,7 @@ describe('nodesAccess', () => {
|
|
|
321
324
|
const result = await Array.fromAsync(access.iterateTrashedNodes());
|
|
322
325
|
expect(result).toMatchObject([node1, node2, node3, node4]);
|
|
323
326
|
expect(apiService.iterateTrashedNodeUids).toHaveBeenCalledWith(volumeId, undefined);
|
|
324
|
-
expect(apiService.iterateNodes).toHaveBeenCalledWith(['node1', 'node2', 'node3', 'node4'], volumeId, undefined);
|
|
327
|
+
expect(apiService.iterateNodes).toHaveBeenCalledWith(['volumeId~node1', 'volumeId~node2', 'volumeId~node3', 'volumeId~node4'], volumeId, undefined);
|
|
325
328
|
expect(cryptoService.decryptNode).toHaveBeenCalledTimes(4);
|
|
326
329
|
expect(cache.setNode).toHaveBeenCalledTimes(4);
|
|
327
330
|
expect(cryptoCache.setNodeKeys).toHaveBeenCalledTimes(4);
|
|
@@ -333,20 +336,20 @@ describe('nodesAccess', () => {
|
|
|
333
336
|
});
|
|
334
337
|
apiService.iterateNodes = jest.fn().mockImplementation(async function* (uids: string[]) {
|
|
335
338
|
// Skip first node - make it missing.
|
|
336
|
-
yield* uids.slice(1).map((uid) => ({ uid, parentUid: '
|
|
339
|
+
yield* uids.slice(1).map((uid) => ({ uid, parentUid: 'volumeId~parentNodeid' } as EncryptedNode));
|
|
337
340
|
});
|
|
338
341
|
|
|
339
342
|
const result = await Array.fromAsync(access.iterateTrashedNodes());
|
|
340
343
|
expect(result).toMatchObject([node2, node3, node4]);
|
|
341
|
-
expect(cache.removeNodes).toHaveBeenCalledWith(['node1']);
|
|
344
|
+
expect(cache.removeNodes).toHaveBeenCalledWith(['volumeId~node1']);
|
|
342
345
|
});
|
|
343
346
|
});
|
|
344
347
|
|
|
345
348
|
describe('iterateNodes', () => {
|
|
346
|
-
const node1 = { uid: 'node1', isStale: false } as DecryptedNode;
|
|
347
|
-
const node2 = { uid: 'node2', isStale: false } as DecryptedNode;
|
|
348
|
-
const node3 = { uid: 'node3', isStale: false } as DecryptedNode;
|
|
349
|
-
const node4 = { uid: 'node4', isStale: false } as DecryptedNode;
|
|
349
|
+
const node1 = { uid: 'volumeId~node1', isStale: false, treeEventScopeId: 'volumeId' } as DecryptedNode;
|
|
350
|
+
const node2 = { uid: 'volumeId~node2', isStale: false, treeEventScopeId: 'volumeId' } as DecryptedNode;
|
|
351
|
+
const node3 = { uid: 'volumeId~node3', isStale: false, treeEventScopeId: 'volumeId' } as DecryptedNode;
|
|
352
|
+
const node4 = { uid: 'volume~node4', isStale: false, treeEventScopeId: 'volumeId' } as DecryptedNode;
|
|
350
353
|
|
|
351
354
|
it('should serve fully from cache', async () => {
|
|
352
355
|
cache.iterateNodes = jest.fn().mockImplementation(async function* () {
|
|
@@ -356,7 +359,7 @@ describe('nodesAccess', () => {
|
|
|
356
359
|
yield { ok: true, node: node4 };
|
|
357
360
|
});
|
|
358
361
|
|
|
359
|
-
const result = await Array.fromAsync(access.iterateNodes(['node1', 'node2', 'node3', 'node4']));
|
|
362
|
+
const result = await Array.fromAsync(access.iterateNodes(['volumeId~node1', 'volumeId~node2', 'volumeId~node3', 'volumeId~node4']));
|
|
360
363
|
expect(result).toMatchObject([node1, node2, node3, node4]);
|
|
361
364
|
expect(apiService.iterateNodes).not.toHaveBeenCalled();
|
|
362
365
|
});
|
|
@@ -364,52 +367,55 @@ describe('nodesAccess', () => {
|
|
|
364
367
|
it('should load from API', async () => {
|
|
365
368
|
cache.iterateNodes = jest.fn().mockImplementation(async function* () {
|
|
366
369
|
yield { ok: true, node: node1 };
|
|
367
|
-
yield { ok: false, uid: 'node2' };
|
|
368
|
-
yield { ok: false, uid: 'node3' };
|
|
370
|
+
yield { ok: false, uid: 'volumeId~node2' };
|
|
371
|
+
yield { ok: false, uid: 'volumeId~node3' };
|
|
369
372
|
yield { ok: true, node: node4 };
|
|
370
373
|
});
|
|
371
374
|
|
|
372
|
-
const result = await Array.fromAsync(access.iterateNodes(['node1', 'node2', 'node3', 'node4']));
|
|
375
|
+
const result = await Array.fromAsync(access.iterateNodes(['volumeId~node1', 'volumeId~node2', 'volumeId~node3', 'volumeId~node4']));
|
|
373
376
|
expect(result).toMatchObject([node1, node4, node2, node3]);
|
|
374
|
-
expect(apiService.iterateNodes).toHaveBeenCalledWith(['node2', 'node3'], 'volumeId', undefined);
|
|
377
|
+
expect(apiService.iterateNodes).toHaveBeenCalledWith(['volumeId~node2', 'volumeId~node3'], 'volumeId', undefined);
|
|
375
378
|
});
|
|
376
379
|
|
|
377
380
|
it('should remove from cache if missing on API and return back to caller', async () => {
|
|
378
381
|
cache.iterateNodes = jest.fn().mockImplementation(async function* () {
|
|
379
|
-
yield { ok: false, uid: 'node1' };
|
|
380
|
-
yield { ok: false, uid: 'node2' };
|
|
381
|
-
yield { ok: false, uid: 'node3' };
|
|
382
|
+
yield { ok: false, uid: 'volumeId~node1' };
|
|
383
|
+
yield { ok: false, uid: 'volumeId~node2' };
|
|
384
|
+
yield { ok: false, uid: 'volumeId~node3' };
|
|
382
385
|
});
|
|
383
386
|
apiService.iterateNodes = jest.fn().mockImplementation(async function* (uids: string[]) {
|
|
384
387
|
// Skip first node - make it missing.
|
|
385
|
-
yield* uids.slice(1).map((uid) => ({ uid, parentUid: '
|
|
388
|
+
yield* uids.slice(1).map((uid) => ({ uid, parentUid: 'volumeId~parentNodeid' } as EncryptedNode));
|
|
386
389
|
});
|
|
387
390
|
|
|
388
|
-
const result = await Array.fromAsync(access.iterateNodes(['node1', 'node2', 'node3']));
|
|
389
|
-
expect(result).toMatchObject([node2, node3, {missingUid: 'node1'}]);
|
|
390
|
-
expect(cache.removeNodes).toHaveBeenCalledWith(['node1']);
|
|
391
|
+
const result = await Array.fromAsync(access.iterateNodes(['volumeId~node1', 'volumeId~node2', 'volumeId~node3']));
|
|
392
|
+
expect(result).toMatchObject([node2, node3, {missingUid: 'volumeId~node1'}]);
|
|
393
|
+
expect(cache.removeNodes).toHaveBeenCalledWith(['volumeId~node1']);
|
|
391
394
|
});
|
|
392
395
|
|
|
393
396
|
it('should return degraded node if parent cannot be decrypted', async () => {
|
|
394
397
|
cache.iterateNodes = jest.fn().mockImplementation(async function* () {
|
|
395
|
-
yield { ok: false, uid: 'node1' };
|
|
396
|
-
yield { ok: false, uid: 'node2' };
|
|
397
|
-
yield { ok: false, uid: 'node3' };
|
|
398
|
+
yield { ok: false, uid: 'volumeId~node1' };
|
|
399
|
+
yield { ok: false, uid: 'volumeId~node2' };
|
|
400
|
+
yield { ok: false, uid: 'volumeId~node3' };
|
|
398
401
|
});
|
|
399
402
|
const encryptedCrypto = {
|
|
400
403
|
signatureEmail: 'signatureEmail',
|
|
401
404
|
nameSignatureEmail: 'nameSignatureEmail',
|
|
402
405
|
};
|
|
403
406
|
apiService.iterateNodes = jest.fn().mockImplementation(async function* (uids: string[]) {
|
|
404
|
-
yield* uids.map((uid) =>
|
|
407
|
+
yield* uids.map((uid) => {
|
|
408
|
+
const parentUid = uid.replace('node', 'parentOfNode');
|
|
409
|
+
return {
|
|
405
410
|
uid,
|
|
406
|
-
parentUid
|
|
411
|
+
parentUid,
|
|
407
412
|
encryptedCrypto,
|
|
408
|
-
|
|
413
|
+
} as EncryptedNode
|
|
414
|
+
});
|
|
409
415
|
});
|
|
410
416
|
const decryptionError = new DecryptionError('Parent cannot be decrypted');
|
|
411
417
|
jest.spyOn(access, 'getParentKeys').mockImplementation(async ({ parentUid }) => {
|
|
412
|
-
if (parentUid === '
|
|
418
|
+
if (parentUid === 'volumeId~parentOfNode1') {
|
|
413
419
|
throw decryptionError;
|
|
414
420
|
}
|
|
415
421
|
return {
|
|
@@ -417,12 +423,12 @@ describe('nodesAccess', () => {
|
|
|
417
423
|
} as any;
|
|
418
424
|
} );
|
|
419
425
|
|
|
420
|
-
const result = await Array.fromAsync(access.iterateNodes(['node1', 'node2', 'node3']));
|
|
426
|
+
const result = await Array.fromAsync(access.iterateNodes(['volumeId~node1', 'volumeId~node2', 'volumeId~node3']));
|
|
421
427
|
expect(result).toEqual([
|
|
422
428
|
{
|
|
423
429
|
...node1,
|
|
424
430
|
encryptedCrypto,
|
|
425
|
-
parentUid: '
|
|
431
|
+
parentUid: 'volumeId~parentOfNode1',
|
|
426
432
|
name: { ok: false, error: decryptionError },
|
|
427
433
|
keyAuthor: { ok: false, error: { claimedAuthor: 'signatureEmail', error: decryptionError.message } },
|
|
428
434
|
nameAuthor: { ok: false, error: { claimedAuthor: 'nameSignatureEmail', error: decryptionError.message } },
|
|
@@ -457,7 +463,7 @@ describe('nodesAccess', () => {
|
|
|
457
463
|
it('should get node parent keys', async () => {
|
|
458
464
|
cryptoCache.getNodeKeys = jest.fn(() => Promise.resolve({ key: 'parentKey' } as any as DecryptedNodeKeys));
|
|
459
465
|
|
|
460
|
-
const result = await access.getParentKeys({ shareId: undefined, parentUid: '
|
|
466
|
+
const result = await access.getParentKeys({ shareId: undefined, parentUid: 'volumeId~parentNodeid' });
|
|
461
467
|
expect(result).toEqual({ key: 'parentKey' });
|
|
462
468
|
expect(shareService.getSharePrivateKey).not.toHaveBeenCalled();
|
|
463
469
|
});
|
|
@@ -465,7 +471,7 @@ describe('nodesAccess', () => {
|
|
|
465
471
|
it('should get node parent keys even if share is set', async () => {
|
|
466
472
|
cryptoCache.getNodeKeys = jest.fn(() => Promise.resolve({ key: 'parentKey' } as any as DecryptedNodeKeys));
|
|
467
473
|
|
|
468
|
-
const result = await access.getParentKeys({ shareId: 'shareId', parentUid: '
|
|
474
|
+
const result = await access.getParentKeys({ shareId: 'shareId', parentUid: 'volume1~parentNodeid' });
|
|
469
475
|
expect(result).toEqual({ key: 'parentKey' });
|
|
470
476
|
expect(shareService.getSharePrivateKey).not.toHaveBeenCalled();
|
|
471
477
|
});
|
|
@@ -477,7 +483,7 @@ describe('nodesAccess', () => {
|
|
|
477
483
|
apiService.getNode = jest.fn(() => Promise.reject(new Error('API called')));
|
|
478
484
|
|
|
479
485
|
try {
|
|
480
|
-
await access.getNodeKeys('nodeId');
|
|
486
|
+
await access.getNodeKeys('volumeId~nodeId');
|
|
481
487
|
throw new Error('Expected error');
|
|
482
488
|
} catch (error: unknown) {
|
|
483
489
|
expect(`${error}`).toBe('Error: API called');
|
|
@@ -490,7 +496,7 @@ describe('nodesAccess', () => {
|
|
|
490
496
|
const nodeUid = 'nodeUid';
|
|
491
497
|
const node = {
|
|
492
498
|
uid: nodeUid,
|
|
493
|
-
parentUid: '
|
|
499
|
+
parentUid: 'volume1~parentNodeid',
|
|
494
500
|
encryptedName: 'encryptedName',
|
|
495
501
|
} as DecryptedNode;
|
|
496
502
|
|
|
@@ -553,4 +559,39 @@ describe('nodesAccess', () => {
|
|
|
553
559
|
expect(result).toBe('https://drive.proton.me/shareId/folder/nodeId');
|
|
554
560
|
});
|
|
555
561
|
});
|
|
562
|
+
|
|
563
|
+
describe('notifyNodeChanged', () => {
|
|
564
|
+
it('should mark node as stale', async () => {
|
|
565
|
+
const node = { uid: 'volumeId~nodeId', isStale: false } as DecryptedNode;
|
|
566
|
+
cache.getNode = jest.fn(() => Promise.resolve(node));
|
|
567
|
+
cache.setNode = jest.fn();
|
|
568
|
+
await access.notifyNodeChanged(node.uid);
|
|
569
|
+
expect(cache.getNode).toHaveBeenCalledWith(node.uid);
|
|
570
|
+
expect(cache.setNode).toHaveBeenCalledWith({...node, isStale: true});
|
|
571
|
+
});
|
|
572
|
+
it('should update parent if needed', async () => {
|
|
573
|
+
const node = { uid: 'volumeId~nodeId', parentUid: 'v1~pn1', isStale: false } as DecryptedNode;
|
|
574
|
+
cache.getNode = jest.fn(() => Promise.resolve(node));
|
|
575
|
+
cache.setNode = jest.fn();
|
|
576
|
+
await access.notifyNodeChanged(node.uid, 'v1~pn2');
|
|
577
|
+
expect(cache.getNode).toHaveBeenCalledWith(node.uid);
|
|
578
|
+
expect(cache.setNode).toHaveBeenCalledWith({...node, parentUid: 'v1~pn2', isStale: true});
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
describe('notifyChildCreated', () => {
|
|
583
|
+
it('should reset parent listing', async () => {
|
|
584
|
+
const nodeUid = 'VolumeId1~NodeId1';
|
|
585
|
+
cache.resetFolderChildrenLoaded = jest.fn();
|
|
586
|
+
await access.notifyChildCreated(nodeUid);
|
|
587
|
+
expect(cache.resetFolderChildrenLoaded).toHaveBeenCalledWith(nodeUid);
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
describe('notifyNodeDeleted', () => {
|
|
592
|
+
it('should reset parent listing', async () => {
|
|
593
|
+
await access.notifyNodeDeleted('v1~n1');
|
|
594
|
+
expect(cache.removeNodes).toHaveBeenCalledWith(['v1~n1']);
|
|
595
|
+
});
|
|
596
|
+
});
|
|
556
597
|
});
|
|
@@ -28,7 +28,7 @@ const DECRYPTION_CONCURRENCY = 15;
|
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Provides access to node metadata.
|
|
31
|
-
*
|
|
31
|
+
*
|
|
32
32
|
* The node access module is responsible for fetching, decrypting and caching
|
|
33
33
|
* nodes metadata.
|
|
34
34
|
*/
|
|
@@ -140,6 +140,42 @@ export class NodesAccess {
|
|
|
140
140
|
yield* batchLoading.loadRest();
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Call to invalidate the folder listing cache. This should be refactored into a clean
|
|
145
|
+
* cache layer once the cache is split off.
|
|
146
|
+
*/
|
|
147
|
+
async notifyChildCreated(nodeUid: string): Promise<void> {
|
|
148
|
+
await this.cache.resetFolderChildrenLoaded(nodeUid);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Call to invalidate the node cache when a node changes. Parent can be set after a move
|
|
153
|
+
* to ensure parent listing of new parent is up to date if cached.
|
|
154
|
+
* This should be refactored into a clean cache layer once the cache is split off.
|
|
155
|
+
*/
|
|
156
|
+
async notifyNodeChanged(nodeUid: string, newParentUid?: string): Promise<void> {
|
|
157
|
+
try {
|
|
158
|
+
const node = await this.cache.getNode(nodeUid);
|
|
159
|
+
if (node.isStale && newParentUid === null) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
node.isStale = true;
|
|
163
|
+
if (newParentUid) {
|
|
164
|
+
node.parentUid = newParentUid;
|
|
165
|
+
}
|
|
166
|
+
await this.cache.setNode(node);
|
|
167
|
+
} catch (error: unknown) {
|
|
168
|
+
this.logger.warn(`Failed to set node ${nodeUid} as stale after sharing: ${error}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Call to remove a node from cache. This should be refactored when the cache is split off.
|
|
174
|
+
*/
|
|
175
|
+
async notifyNodeDeleted(nodeUid: string): Promise<void> {
|
|
176
|
+
await this.cache.removeNodes([nodeUid]);
|
|
177
|
+
}
|
|
178
|
+
|
|
143
179
|
private async loadNode(nodeUid: string): Promise<{ node: DecryptedNode, keys?: DecryptedNodeKeys }> {
|
|
144
180
|
const { volumeId: ownVolumeId } = await this.shareService.getMyFilesIDs();
|
|
145
181
|
const encryptedNode = await this.apiService.getNode(nodeUid, ownVolumeId);
|
|
@@ -217,6 +253,7 @@ export class NodesAccess {
|
|
|
217
253
|
error: getErrorMessage(error),
|
|
218
254
|
}),
|
|
219
255
|
errors: [error],
|
|
256
|
+
treeEventScopeId: splitNodeUid(encryptedNode.uid).volumeId,
|
|
220
257
|
},
|
|
221
258
|
};
|
|
222
259
|
}
|
|
@@ -272,6 +309,7 @@ export class NodesAccess {
|
|
|
272
309
|
...extendedAttributes,
|
|
273
310
|
}),
|
|
274
311
|
folder: undefined,
|
|
312
|
+
treeEventScopeId: splitNodeUid(unparsedNode.uid).volumeId,
|
|
275
313
|
}
|
|
276
314
|
}
|
|
277
315
|
|
|
@@ -286,6 +324,7 @@ export class NodesAccess {
|
|
|
286
324
|
folder: extendedAttributes ? {
|
|
287
325
|
...extendedAttributes,
|
|
288
326
|
} : undefined,
|
|
327
|
+
treeEventScopeId: splitNodeUid(unparsedNode.uid).volumeId,
|
|
289
328
|
}
|
|
290
329
|
}
|
|
291
330
|
|