@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
@@ -1,6 +1,5 @@
1
- import { Thumbnail, ThumbnailType, UploadMetadata } from '../../interface';
2
- import { APIHTTPError, HTTPErrorCode } from '../apiService';
3
- import { FILE_CHUNK_SIZE, Fileuploader } from './fileUploader';
1
+ import { Thumbnail, UploadMetadata } from '../../interface';
2
+ import { FileUploader } from './fileUploader';
4
3
  import { UploadTelemetry } from './telemetry';
5
4
  import { UploadAPIService } from './apiService';
6
5
  import { UploadCryptoService } from './cryptoService';
@@ -8,7 +7,6 @@ import { UploadController } from './controller';
8
7
  import { BlockVerifier } from './blockVerifier';
9
8
  import { NodeRevisionDraft } from './interface';
10
9
  import { UploadManager } from './manager';
11
- import { IntegrityError } from '../../errors';
12
10
 
13
11
  const BLOCK_ENCRYPTION_OVERHEAD = 10000;
14
12
 
@@ -41,7 +39,9 @@ describe('FileUploader', () => {
41
39
  let onFinish: () => Promise<void>;
42
40
  let abortController: AbortController;
43
41
 
44
- let uploader: Fileuploader;
42
+ let uploader: FileUploader;
43
+
44
+ let startUploadSpy: jest.SpyInstance;
45
45
 
46
46
  beforeEach(() => {
47
47
  // @ts-expect-error No need to implement all methods for mocking
@@ -103,411 +103,81 @@ describe('FileUploader', () => {
103
103
  },
104
104
  } as NodeRevisionDraft;
105
105
 
106
- metadata = {
107
- // 3 blocks: 4 + 4 + 2 MB
108
- expectedSize: 10 * 1024 * 1024,
109
- } as UploadMetadata;
106
+ metadata = {} as UploadMetadata;
110
107
 
111
108
  controller = new UploadController();
112
109
  onFinish = jest.fn();
113
110
  abortController = new AbortController();
114
111
 
115
- uploader = new Fileuploader(
112
+ uploader = new FileUploader(
116
113
  telemetry,
117
114
  apiService,
118
115
  cryptoService,
119
116
  uploadManager,
120
- blockVerifier,
121
- revisionDraft,
117
+ 'parentFolderUid',
118
+ 'name',
122
119
  metadata,
123
120
  onFinish,
124
121
  abortController.signal,
125
122
  );
126
- });
127
-
128
- describe('writeFile', () => {
129
- it('should set modification time if not set', () => {
130
- // @ts-expect-error Ignore mocking File
131
- const file = {
132
- lastModified: 123456789,
133
- stream: jest.fn().mockReturnValue('stream'),
134
- } as File;
135
- const thumbnails: Thumbnail[] = [];
136
- const onProgress = jest.fn();
137
-
138
- const writeStreamSpy = jest.spyOn(uploader, 'writeStream').mockReturnValue(controller);
139
-
140
- uploader.writeFile(file, thumbnails, onProgress);
141
-
142
- expect(metadata.modificationTime).toEqual(new Date(123456789));
143
- expect(writeStreamSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
144
- });
145
- });
146
-
147
- describe('writeStream', () => {
148
- let uploadStreamSpy: jest.SpyInstance;
149
- beforeEach(() => {
150
- uploadStreamSpy = jest.spyOn(uploader as any, 'uploadStream').mockResolvedValue('revisionUid');
151
- });
152
-
153
- it('should throw an error if upload already started', () => {
154
- uploader.writeStream(new ReadableStream(), [], jest.fn());
155
-
156
- expect(() => {
157
- uploader.writeStream(new ReadableStream(), [], jest.fn());
158
- }).toThrow('Upload already started');
159
- });
160
-
161
- it('should start the upload process', async () => {
162
- const stream = new ReadableStream();
163
- const thumbnails: Thumbnail[] = [];
164
- const onProgress = jest.fn();
165
123
 
166
- uploader.writeStream(stream, thumbnails, onProgress);
167
- expect(uploadStreamSpy).toHaveBeenCalledWith(stream, thumbnails, onProgress);
168
- });
124
+ startUploadSpy = jest.spyOn(uploader as any, 'startUpload').mockReturnValue(Promise.resolve('revisionUid'));
169
125
  });
170
126
 
171
- describe('uploadStream', () => {
172
- let thumbnails: Thumbnail[];
173
- let thumbnailSize: number;
174
-
175
- let onProgress: (uploadedBytes: number) => void;
176
- let stream: ReadableStream<Uint8Array>;
177
-
178
- const verifySuccess = async () => {
179
- const controller = uploader.writeStream(stream, thumbnails, onProgress);
180
- await controller.completion();
181
-
182
- const numberOfExpectedBlocks = Math.ceil(metadata.expectedSize / FILE_CHUNK_SIZE);
183
- expect(uploadManager.commitDraft).toHaveBeenCalledTimes(1);
184
- expect(uploadManager.commitDraft).toHaveBeenCalledWith(
185
- revisionDraft,
186
- expect.anything(),
187
- metadata,
188
- {
189
- size: metadata.expectedSize,
190
- blockSizes: metadata.expectedSize ? [
191
- ...Array(numberOfExpectedBlocks - 1).fill(FILE_CHUNK_SIZE),
192
- metadata.expectedSize % FILE_CHUNK_SIZE
193
- ] : [],
194
- modificationTime: undefined,
195
- digests: {
196
- sha1: expect.anything(),
197
- }
198
- },
199
- metadata.expectedSize + numberOfExpectedBlocks * BLOCK_ENCRYPTION_OVERHEAD,
200
- );
201
- expect(telemetry.uploadFinished).toHaveBeenCalledTimes(1);
202
- expect(telemetry.uploadFinished).toHaveBeenCalledWith('revisionUid', metadata.expectedSize + thumbnailSize);
203
- expect(telemetry.uploadFailed).not.toHaveBeenCalled();
204
- expect(onFinish).toHaveBeenCalledTimes(1);
205
- expect(onFinish).toHaveBeenCalledWith(false);
206
- };
207
-
208
- const verifyFailure = async (error: string, uploadedBytes: number | undefined, expectedSize = metadata.expectedSize) => {
209
- const controller = uploader.writeStream(stream, thumbnails, onProgress);
210
- await expect(controller.completion()).rejects.toThrow(error);
211
-
212
- expect(telemetry.uploadFinished).not.toHaveBeenCalled();
213
- expect(telemetry.uploadFailed).toHaveBeenCalledTimes(1);
214
- expect(telemetry.uploadFailed).toHaveBeenCalledWith(
215
- 'revisionUid',
216
- new Error(error),
217
- uploadedBytes === undefined ? expect.anything() : uploadedBytes,
218
- expectedSize,
219
- );
220
- expect(onFinish).toHaveBeenCalledTimes(1);
221
- expect(onFinish).toHaveBeenCalledWith(true);
222
- };
223
-
224
- const verifyOnProgress = async (uploadedBytes: number[]) => {
225
- expect(onProgress).toHaveBeenCalledTimes(uploadedBytes.length);
226
- for (let i = 0; i < uploadedBytes.length; i++) {
227
- expect(onProgress).toHaveBeenNthCalledWith(i + 1, uploadedBytes[i]);
228
- }
229
- };
230
-
231
- beforeEach(() => {
232
- onProgress = jest.fn();
233
- thumbnails = [
234
- {
235
- type: ThumbnailType.Type1,
236
- thumbnail: new Uint8Array(1024),
237
- }
238
- ];
239
- thumbnailSize = thumbnails.reduce((acc, thumbnail) => acc + thumbnail.thumbnail.length, 0);
240
- stream = new ReadableStream({
241
- start(controller) {
242
- const chunkSize = 1024;
243
- const chunkCount = metadata.expectedSize / chunkSize;
244
- for (let i = 1; i <= chunkCount; i++) {
245
- controller.enqueue(new Uint8Array(chunkSize));
246
- }
247
- controller.close();
248
- },
249
- });
250
- });
251
-
252
- it("should upload successfully", async () => {
253
- await verifySuccess();
254
- expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(1);
255
- expect(apiService.uploadBlock).toHaveBeenCalledTimes(4); // 3 blocks + 1 thumbnail
256
- expect(blockVerifier.verifyBlock).toHaveBeenCalledTimes(3); // 3 blocks
257
- expect(telemetry.logBlockVerificationError).not.toHaveBeenCalled();
258
- await verifyOnProgress([thumbnailSize, 4 * 1024 * 1024, 4 * 1024 * 1024, 2 * 1024 * 1024]);
259
- });
260
-
261
- it("should upload successfully empty file without thumbnail", async () => {
262
- metadata = {
263
- expectedSize: 0,
264
- } as UploadMetadata;
265
- stream = new ReadableStream({
266
- start(controller) {
267
- controller.close();
268
- },
269
- });
270
- thumbnails = [];
271
- thumbnailSize = 0;
272
- uploader = new Fileuploader(
273
- telemetry,
274
- apiService,
275
- cryptoService,
276
- uploadManager,
277
- blockVerifier,
278
- revisionDraft,
279
- metadata,
280
- onFinish,
281
- );
282
-
283
- await verifySuccess();
284
- expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(0);
285
- expect(apiService.uploadBlock).toHaveBeenCalledTimes(0);
286
- expect(blockVerifier.verifyBlock).toHaveBeenCalledTimes(0);
287
- await verifyOnProgress([]);
288
- });
289
-
290
- it("should upload successfully empty file with thumbnail", async () => {
291
- metadata = {
292
- expectedSize: 0,
293
- } as UploadMetadata;
294
- stream = new ReadableStream({
295
- start(controller) {
296
- controller.close();
297
- },
298
- });
299
- uploader = new Fileuploader(
300
- telemetry,
301
- apiService,
302
- cryptoService,
303
- uploadManager,
304
- blockVerifier,
305
- revisionDraft,
306
- metadata,
307
- onFinish,
308
- );
309
-
310
- await verifySuccess();
311
- expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(1);
312
- expect(apiService.uploadBlock).toHaveBeenCalledTimes(1);
313
- expect(blockVerifier.verifyBlock).toHaveBeenCalledTimes(0);
314
- await verifyOnProgress([thumbnailSize]);
315
- });
316
-
317
- it('should handle failure when encrypting thumbnails', async () => {
318
- cryptoService.encryptThumbnail = jest.fn().mockImplementation(async function () {
319
- throw new Error('Failed to encrypt thumbnail');
320
- });
321
-
322
- await verifyFailure('Failed to encrypt thumbnail', 0);
323
- expect(cryptoService.encryptThumbnail).toHaveBeenCalledTimes(1);
324
- });
325
-
326
- it('should handle failure when encrypting block', async () => {
327
- cryptoService.encryptBlock = jest.fn().mockImplementation(async function () {
328
- throw new Error('Failed to encrypt block');
329
- });
330
-
331
- // Encrypting thumbnails is before blocks, thus it can be uploaded before failure.
332
- await verifyFailure('Failed to encrypt block', 1024);
333
- // 1 block + 1 retry, others are skipped
334
- expect(cryptoService.encryptBlock).toHaveBeenCalledTimes(2);
335
- });
336
-
337
- it('should handle one time-off failure when encrypting block', async () => {
338
- let count = 0;
339
- cryptoService.encryptBlock = jest.fn().mockImplementation(async function (verifyBlock, keys, block, index) {
340
- if (count === 0) {
341
- count++;
342
- throw new Error('Failed to encrypt block');
343
- }
344
- return mockEncryptBlock(verifyBlock, keys, block, index);
345
- });
346
-
347
- await verifySuccess();
348
- // 1 block + 1 retry + 2 other blocks without retry
349
- expect(cryptoService.encryptBlock).toHaveBeenCalledTimes(4);
350
- await verifyOnProgress([thumbnailSize, 4 * 1024 * 1024, 4 * 1024 * 1024, 2 * 1024 * 1024]);
351
- });
352
-
353
- it('should handle failure when requesting tokens', async () => {
354
- apiService.requestBlockUpload = jest.fn().mockImplementation(async function () {
355
- throw new Error('Failed to request tokens');
356
- });
357
-
358
- await verifyFailure('Failed to request tokens', 0);
359
- });
127
+ describe('writeFile', () => {
128
+ // @ts-expect-error Ignore mocking File
129
+ const file = {
130
+ type: 'image/png',
131
+ size: 1000,
132
+ lastModified: 123456789,
133
+ stream: jest.fn().mockReturnValue('stream'),
134
+ } as File;
135
+ const thumbnails: Thumbnail[] = [];
136
+ const onProgress = jest.fn();
360
137
 
361
- it('should handle failure when uploading thumbnail', async () => {
362
- apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
363
- if (token === 'token/thumbnail:1') {
364
- throw new Error('Failed to upload thumbnail');
365
- }
366
- return mockUploadBlock(bareUrl, token, block, onProgress);
367
- });
138
+ it('should set media type if not set', async () => {
139
+ await uploader.writeFile(file, thumbnails, onProgress);
368
140
 
369
- // 10 MB uploaded as blocks still uploaded
370
- await verifyFailure('Failed to upload thumbnail', 10 * 1024 * 1024);
141
+ expect(metadata.mediaType).toEqual('image/png');
142
+ expect(startUploadSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
371
143
  });
372
144
 
373
- it('should handle one time-off failure when uploading thubmnail', async () => {
374
- let count = 0;
375
- apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
376
- if (token === 'token/thumbnail:1' && count === 0) {
377
- count++;
378
- throw new Error('Failed to upload thumbnail');
379
- }
380
- return mockUploadBlock(bareUrl, token, block, onProgress);
381
- });
145
+ it('should set expected size if not set', async () => {
146
+ await uploader.writeFile(file, thumbnails, onProgress);
382
147
 
383
- await verifySuccess();
384
- expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(1);
385
- // 3 blocks + 1 retry + 1 thumbnail
386
- expect(apiService.uploadBlock).toHaveBeenCalledTimes(5);
387
- await verifyOnProgress([4 * 1024 * 1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 1024]);
148
+ expect(metadata.expectedSize).toEqual(file.size);
149
+ expect(startUploadSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
388
150
  });
389
151
 
390
- it('should handle failure when uploading block', async () => {
391
- apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
392
- if (token === 'token/block:3') {
393
- throw new Error('Failed to upload block');
394
- }
395
- return mockUploadBlock(bareUrl, token, block, onProgress);
396
- });
152
+ it('should set modification time if not set', async () => {
153
+ await uploader.writeFile(file, thumbnails, onProgress);
397
154
 
398
- // ~8 MB uploaded as 2 first blocks + 1 thumbnail still uploaded
399
- await verifyFailure('Failed to upload block', 8 * 1024 * 1024 + 1024);
155
+ expect(metadata.modificationTime).toEqual(new Date(123456789));
156
+ expect(startUploadSpy).toHaveBeenCalledWith('stream', thumbnails, onProgress);
400
157
  });
401
158
 
402
- it('should handle one time-off failure when uploading block', async () => {
403
- let count = 0;
404
- apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
405
- if (token === 'token/block:2' && count === 0) {
406
- count++;
407
- throw new Error('Failed to upload block');
408
- }
409
- return mockUploadBlock(bareUrl, token, block, onProgress);
410
- });
159
+ it('should throw an error if upload already started', async () => {
160
+ await uploader.writeFile(file, thumbnails, onProgress);
411
161
 
412
- await verifySuccess();
413
- expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(1);
414
- // 3 blocks + 1 retry + 1 thumbnail
415
- expect(apiService.uploadBlock).toHaveBeenCalledTimes(5);
416
- await verifyOnProgress([1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024]);
162
+ await expect(uploader.writeFile(file, thumbnails, onProgress)).rejects.toThrow('Upload already started');
417
163
  });
164
+ });
418
165
 
419
- it('should handle expired token when uploading block', async () => {
420
- let count = 0;
421
- apiService.uploadBlock = jest.fn().mockImplementation(async function (bareUrl, token, block, onProgress) {
422
- if (token === 'token/block:2' && count === 0) {
423
- count++;
424
- throw new APIHTTPError('Expired token', HTTPErrorCode.NOT_FOUND);
425
- }
426
- return mockUploadBlock(bareUrl, token, block, onProgress);
427
- });
166
+ describe('writeStream', () => {
167
+ const stream = new ReadableStream();
168
+ const thumbnails: Thumbnail[] = [];
169
+ const onProgress = jest.fn();
428
170
 
429
- await verifySuccess();
430
- // 1 for first try + 1 for retry
431
- expect(apiService.requestBlockUpload).toHaveBeenCalledTimes(2);
432
- expect(apiService.requestBlockUpload).toHaveBeenCalledWith(
433
- revisionDraft.nodeRevisionUid,
434
- revisionDraft.nodeKeys.signatureAddress.addressId,
435
- {
436
- contentBlocks: [
437
- {
438
- index: 2,
439
- encryptedSize: 4 * 1024 * 1024 + 10000,
440
- hash: 'blockHash',
441
- armoredSignature: 'signature',
442
- verificationToken: 'verificationToken',
443
- }
444
- ],
445
- },
446
- );
447
- // 3 blocks + 1 retry + 1 thumbnail
448
- expect(apiService.uploadBlock).toHaveBeenCalledTimes(5);
449
- await verifyOnProgress([1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024]);
450
- });
171
+ it('should start the upload process', async () => {
172
+ await uploader.writeStream(stream, thumbnails, onProgress);
451
173
 
452
- it('should handle abortion', async () => {
453
- const error = new Error('Aborted');
454
- const controller = uploader.writeStream(stream, thumbnails, onProgress);
455
- abortController.abort(error);
456
- await controller.completion();
457
- expect(apiService.uploadBlock.mock.calls[0][4]?.aborted).toBe(true);
174
+ expect(startUploadSpy).toHaveBeenCalledWith(stream, thumbnails, onProgress);
458
175
  });
459
176
 
460
- describe('verifyIntegrity', () => {
461
- it('should report block verification error', async () => {
462
- blockVerifier.verifyBlock = jest.fn().mockRejectedValue(new IntegrityError('Block verification error'));
463
- await verifyFailure('Block verification error', 1024);
464
- expect(telemetry.logBlockVerificationError).toHaveBeenCalledWith(false);
465
- });
466
-
467
- it('should report block verification error when retry helped', async () => {
468
- blockVerifier.verifyBlock = jest.fn().mockRejectedValueOnce(new IntegrityError('Block verification error')).mockResolvedValue({
469
- verificationToken: new Uint8Array(),
470
- });
471
- await verifySuccess();
472
- expect(telemetry.logBlockVerificationError).toHaveBeenCalledWith(true);
473
- });
474
-
475
- it('should throw an error if block count does not match', async () => {
476
- uploader = new Fileuploader(
477
- telemetry,
478
- apiService,
479
- cryptoService,
480
- uploadManager,
481
- blockVerifier,
482
- revisionDraft,
483
- {
484
- // Fake expected size to break verification
485
- expectedSize: 1 * 1024 * 1024 + 1024,
486
- mediaType: '',
487
- },
488
- onFinish,
489
- );
490
-
491
- await verifyFailure(
492
- 'Some file parts failed to upload',
493
- 10 * 1024 * 1024 + 1024,
494
- 1 * 1024 * 1024 + 1024,
495
- );
496
- });
497
-
498
- it('should throw an error if file size does not match', async () => {
499
- cryptoService.encryptBlock = jest.fn().mockImplementation(async (_, __, block, index) => ({
500
- index,
501
- encryptedData: block,
502
- armoredSignature: 'signature',
503
- verificationToken: 'verificationToken',
504
- originalSize: 0, // Fake original size to break verification
505
- encryptedSize: block.length + 10000,
506
- hash: 'blockHash',
507
- }));
177
+ it('should throw an error if upload already started', async () => {
178
+ await uploader.writeStream(stream, thumbnails, onProgress);
508
179
 
509
- await verifyFailure('Some file bytes failed to upload', 10 * 1024 * 1024 + 1024);
510
- });
180
+ await expect(uploader.writeStream(stream, thumbnails, onProgress)).rejects.toThrow('Upload already started');
511
181
  });
512
182
  });
513
183
  });