@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
@@ -3,16 +3,15 @@ import { DriveAPIService } from "../apiService";
3
3
  import { DriveCrypto } from "../../crypto";
4
4
  import { UploadAPIService } from "./apiService";
5
5
  import { UploadCryptoService } from "./cryptoService";
6
+ import { FileUploader, FileRevisionUploader } from "./fileUploader";
7
+ import { NodesService, SharesService } from "./interface";
8
+ import { UploadManager } from "./manager";
6
9
  import { UploadQueue } from "./queue";
7
- import { NodesService, NodesEvents, SharesService } from "./interface";
8
- import { Fileuploader } from "./fileUploader";
9
10
  import { UploadTelemetry } from "./telemetry";
10
- import { UploadManager } from "./manager";
11
- import { BlockVerifier } from "./blockVerifier";
12
11
 
13
12
  /**
14
13
  * Provides facade for the upload module.
15
- *
14
+ *
16
15
  * The upload module is responsible for handling file uploads, including
17
16
  * metadata generation, content upload, API communication, encryption,
18
17
  * and verifications.
@@ -23,95 +22,72 @@ export function initUploadModule(
23
22
  driveCrypto: DriveCrypto,
24
23
  sharesService: SharesService,
25
24
  nodesService: NodesService,
26
- nodesEvents: NodesEvents,
25
+ clientUid?: string,
27
26
  ) {
28
- const api = new UploadAPIService(apiService);
27
+ const api = new UploadAPIService(apiService, clientUid);
29
28
  const cryptoService = new UploadCryptoService(driveCrypto, nodesService);
30
29
 
31
30
  const uploadTelemetry = new UploadTelemetry(telemetry, sharesService);
32
- const manager = new UploadManager(telemetry, api, cryptoService, nodesService, nodesEvents);
31
+ const manager = new UploadManager(telemetry, api, cryptoService, nodesService, clientUid);
33
32
 
34
33
  const queue = new UploadQueue();
35
34
 
35
+ /**
36
+ * Returns a FileUploader instance that can be used to upload a file to
37
+ * a parent folder.
38
+ *
39
+ * This operation does not call the API, it only returns a FileUploader
40
+ * instance when the upload queue has capacity.
41
+ */
36
42
  async function getFileUploader(
37
43
  parentFolderUid: string,
38
44
  name: string,
39
45
  metadata: UploadMetadata,
40
46
  signal?: AbortSignal,
41
- ): Promise<Fileuploader> {
47
+ ): Promise<FileUploader> {
42
48
  await queue.waitForCapacity(signal);
43
49
 
44
- let revisionDraft, blockVerifier;
45
- try {
46
- revisionDraft = await manager.createDraftNode(parentFolderUid, name, metadata);
47
-
48
- blockVerifier = new BlockVerifier(api, cryptoService, revisionDraft.nodeKeys.key, revisionDraft.nodeRevisionUid);
49
- await blockVerifier.loadVerificationData();
50
- } catch (error: unknown) {
51
- queue.releaseCapacity();
52
- if (revisionDraft) {
53
- await manager.deleteDraftNode(revisionDraft.nodeUid);
54
- }
55
- void uploadTelemetry.uploadInitFailed(parentFolderUid, error, metadata.expectedSize);
56
- throw error;
57
- }
58
-
59
- const onFinish = async (failure: boolean) => {
50
+ const onFinish = () => {
60
51
  queue.releaseCapacity();
61
- if (failure) {
62
- await manager.deleteDraftNode(revisionDraft.nodeUid);
63
- }
64
52
  }
65
53
 
66
- return new Fileuploader(
54
+ return new FileUploader(
67
55
  uploadTelemetry,
68
56
  api,
69
57
  cryptoService,
70
58
  manager,
71
- blockVerifier,
72
- revisionDraft,
59
+ parentFolderUid,
60
+ name,
73
61
  metadata,
74
62
  onFinish,
75
63
  signal,
76
64
  );
77
65
  }
78
66
 
67
+ /**
68
+ * Returns a FileUploader instance that can be used to upload a new
69
+ * revision of a file.
70
+ *
71
+ * This operation does not call the API, it only returns a
72
+ * FileRevisionUploader instance when the upload queue has capacity.
73
+ */
79
74
  async function getFileRevisionUploader(
80
75
  nodeUid: string,
81
76
  metadata: UploadMetadata,
82
77
  signal?: AbortSignal,
83
- ): Promise<Fileuploader> {
78
+ ): Promise<FileRevisionUploader> {
84
79
  await queue.waitForCapacity(signal);
85
80
 
86
- let revisionDraft, blockVerifier;
87
- try {
88
- revisionDraft = await manager.createDraftRevision(nodeUid, metadata);
89
-
90
- blockVerifier = new BlockVerifier(api, cryptoService, revisionDraft.nodeKeys.key, revisionDraft.nodeRevisionUid);
91
- await blockVerifier.loadVerificationData();
92
- } catch (error: unknown) {
93
- queue.releaseCapacity();
94
- if (revisionDraft) {
95
- await manager.deleteDraftRevision(revisionDraft.nodeRevisionUid);
96
- }
97
- void uploadTelemetry.uploadInitFailed(nodeUid, error, metadata.expectedSize);
98
- throw error;
99
- }
100
-
101
- const onFinish = async (failure: boolean) => {
81
+ const onFinish = () => {
102
82
  queue.releaseCapacity();
103
- if (failure) {
104
- await manager.deleteDraftNode(revisionDraft.nodeUid);
105
- }
106
83
  }
107
84
 
108
- return new Fileuploader(
85
+ return new FileRevisionUploader(
109
86
  uploadTelemetry,
110
87
  api,
111
88
  cryptoService,
112
89
  manager,
113
- blockVerifier,
114
- revisionDraft,
90
+ nodeUid,
115
91
  metadata,
116
92
  onFinish,
117
93
  signal,
@@ -105,6 +105,7 @@ export interface NodesService {
105
105
  addressKey: PrivateKey,
106
106
  addressKeyId: string,
107
107
  }>,
108
+ notifyChildCreated(nodeUid: string): Promise<void>;
108
109
  }
109
110
 
110
111
  /**
@@ -117,6 +118,7 @@ export interface NodesEvents {
117
118
 
118
119
  export interface NodesServiceNode {
119
120
  uid: string,
121
+ parentUid?: string,
120
122
  activeRevision?: Result<Revision, Error>,
121
123
  }
122
124
 
@@ -1,10 +1,10 @@
1
1
  import { ValidationError } from "../../errors";
2
- import { NodeType, ProtonDriveTelemetry, RevisionState, UploadMetadata } from "../../interface";
2
+ import { ProtonDriveTelemetry, UploadMetadata } from "../../interface";
3
3
  import { getMockTelemetry } from "../../tests/telemetry";
4
4
  import { ErrorCode } from "../apiService";
5
5
  import { UploadAPIService } from "./apiService";
6
6
  import { UploadCryptoService } from "./cryptoService";
7
- import { NodesService, NodesEvents } from "./interface";
7
+ import { NodesService } from "./interface";
8
8
  import { UploadManager } from './manager';
9
9
 
10
10
  describe("UploadManager", () => {
@@ -12,10 +12,11 @@ describe("UploadManager", () => {
12
12
  let apiService: UploadAPIService;
13
13
  let cryptoService: UploadCryptoService;
14
14
  let nodesService: NodesService;
15
- let nodesEvents: NodesEvents;
16
15
 
17
16
  let manager: UploadManager;
18
17
 
18
+ const clientUid = 'clientUid';
19
+
19
20
  beforeEach(() => {
20
21
  telemetry = getMockTelemetry();
21
22
  // @ts-expect-error No need to implement all methods for mocking
@@ -73,8 +74,12 @@ describe("UploadManager", () => {
73
74
  armoredExtendedAttributes: "newNode:armoredExtendedAttributes",
74
75
  }),
75
76
  }
76
- // @ts-expect-error No need to implement all methods for mocking
77
77
  nodesService = {
78
+ getNode: jest.fn(async (nodeUid: string) => ({
79
+ uid: nodeUid,
80
+ parentUid: 'parentUid',
81
+
82
+ })),
78
83
  getNodeKeys: jest.fn().mockResolvedValue({
79
84
  hashKey: 'parentNode:hashKey',
80
85
  key: 'parentNode:nodekey',
@@ -83,13 +88,10 @@ describe("UploadManager", () => {
83
88
  email: "signatureEmail",
84
89
  addressId: "addressId",
85
90
  }),
86
- }
87
- nodesEvents = {
88
- nodeCreated: jest.fn(),
89
- nodeUpdated: jest.fn(),
91
+ notifyChildCreated: jest.fn(async (nodeUid: string) => { return }),
90
92
  }
91
93
 
92
- manager = new UploadManager(telemetry, apiService, cryptoService, nodesService, nodesEvents);
94
+ manager = new UploadManager(telemetry, apiService, cryptoService, nodesService, clientUid);
93
95
  });
94
96
 
95
97
  describe("createDraftNode", () => {
@@ -135,14 +137,18 @@ describe("UploadManager", () => {
135
137
  armoredContentKeyPacketSignature: "newNode:armoredContentKeyPacketSignature",
136
138
  signatureEmail: "signatureEmail",
137
139
  });
138
- expect(apiService.checkAvailableHashes).not.toHaveBeenCalled();
139
140
  });
140
141
 
141
- it("should handle existing draft by deleting and trying again", async () => {
142
- let hashChecked = false;
142
+ it("should delete existing draft and trying again", async () => {
143
+ let firstCall = true;
143
144
  apiService.createDraft = jest.fn().mockImplementation(() => {
144
- if (!hashChecked) {
145
- throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS);
145
+ if (firstCall) {
146
+ firstCall = false;
147
+ throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS, {
148
+ ConflictLinkID: "existingLinkId",
149
+ ConflictDraftRevisionID: "existingDraftRevisionId",
150
+ ConflictDraftClientUID: clientUid,
151
+ });
146
152
  }
147
153
  return {
148
154
  nodeUid: "newNode:nodeUid",
@@ -150,27 +156,8 @@ describe("UploadManager", () => {
150
156
  };
151
157
  });
152
158
 
153
- apiService.checkAvailableHashes = jest.fn().mockImplementation(() => {
154
- if (!hashChecked) {
155
- hashChecked = true;
156
- return {
157
- availalbleHashes: ["name1Hash"],
158
- pendingHashes: [{
159
- hash: "newNode:hash",
160
- nodeUid: "nodeUidToDelete"
161
- }],
162
- }
163
- }
164
- return {
165
- availalbleHashes: ["name1Hash"],
166
- pendingHashes: [],
167
- }
168
- });
169
-
170
- const result = await manager.createDraftNode("parentUid", "name", {} as UploadMetadata);
159
+ const result = await manager.createDraftNode("volumeId~parentUid", "name", {} as UploadMetadata);
171
160
 
172
- expect(apiService.checkAvailableHashes).toHaveBeenCalledTimes(1);
173
- expect(apiService.deleteDraft).toHaveBeenCalledTimes(1);
174
161
  expect(result).toEqual({
175
162
  nodeUid: "newNode:nodeUid",
176
163
  nodeRevisionUid: "newNode:nodeRevisionUid",
@@ -182,60 +169,57 @@ describe("UploadManager", () => {
182
169
  },
183
170
  },
184
171
  newNodeInfo: {
185
- parentUid: "parentUid",
172
+ parentUid: "volumeId~parentUid",
186
173
  name: "name",
187
174
  encryptedName: "newNode:encryptedName",
188
175
  hash: "newNode:hash",
189
176
  },
190
177
  });
191
- expect(apiService.deleteDraft).toHaveBeenCalledWith("nodeUidToDelete");
178
+ expect(apiService.deleteDraft).toHaveBeenCalledTimes(1);
179
+ expect(apiService.deleteDraft).toHaveBeenCalledWith("volumeId~existingLinkId");
192
180
  });
193
181
 
194
- it("should handle error when deleting existing draft", async () => {
195
- let hashChecked = false;
182
+ it("should not delete existing draft if client UID does not match", async () => {
183
+ let firstCall = true;
196
184
  apiService.createDraft = jest.fn().mockImplementation(() => {
197
- if (!hashChecked) {
198
- throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS);
185
+ if (firstCall) {
186
+ firstCall = false;
187
+ throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS, {
188
+ ConflictLinkID: "existingLinkId",
189
+ ConflictDraftRevisionID: "existingDraftRevisionId",
190
+ ConflictDraftClientUID: "anotherClientUid",
191
+ });
199
192
  }
200
193
  return {
201
194
  nodeUid: "newNode:nodeUid",
202
195
  nodeRevisionUid: "newNode:nodeRevisionUid",
203
196
  };
204
197
  });
205
- apiService.deleteDraft = jest.fn().mockImplementation(() => {
206
- throw new Error("Failed to delete draft");
207
- });
208
198
 
209
- apiService.checkAvailableHashes = jest.fn().mockImplementation(() => {
210
- if (!hashChecked) {
211
- hashChecked = true;
212
- return {
213
- availalbleHashes: ["name1Hash"],
214
- pendingHashes: [{
215
- hash: "newNode:hash",
216
- nodeUid: "nodeUidToDelete"
217
- }],
218
- }
219
- }
220
- return {
221
- availalbleHashes: ["name1Hash"],
222
- pendingHashes: [],
223
- }
224
- });
199
+ const promise = manager.createDraftNode("volumeId~parentUid", "name", {} as UploadMetadata);
225
200
 
226
- const result = manager.createDraftNode("parentUid", "name", {} as UploadMetadata);
227
-
228
- await expect(result).rejects.toThrow("Draft already exists");
229
- expect(apiService.checkAvailableHashes).toHaveBeenCalledTimes(1);
230
- expect(apiService.deleteDraft).toHaveBeenCalledTimes(1);
201
+ try {
202
+ await promise;
203
+ } catch (error: any) {
204
+ expect(error.message).toBe("Draft already exists");
205
+ expect(error.ongoingUploadByOtherClient).toBe(true);
206
+ }
207
+ expect(apiService.deleteDraft).not.toHaveBeenCalled();
231
208
  });
232
209
 
233
- it("should handle existing name by providing available name", async () => {
234
- let count = 0;
210
+ it("should not delete existing draft if client UID is not set", async () => {
211
+ const clientUid = undefined;
212
+ manager = new UploadManager(telemetry, apiService, cryptoService, nodesService, clientUid);
213
+
214
+ let firstCall = true;
235
215
  apiService.createDraft = jest.fn().mockImplementation(() => {
236
- if (count === 0) {
237
- count++;
238
- throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS);
216
+ if (firstCall) {
217
+ firstCall = false;
218
+ throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS, {
219
+ ConflictLinkID: "existingLinkId",
220
+ ConflictDraftRevisionID: "existingDraftRevisionId",
221
+ ConflictDraftClientUID: clientUid,
222
+ });
239
223
  }
240
224
  return {
241
225
  nodeUid: "newNode:nodeUid",
@@ -243,33 +227,69 @@ describe("UploadManager", () => {
243
227
  };
244
228
  });
245
229
 
246
- const result = manager.createDraftNode("parentUid", "name", {} as UploadMetadata);
247
-
248
- await expect(result).rejects.toThrow("Draft already exists");
249
- expect(apiService.checkAvailableHashes).toHaveBeenCalledTimes(1);
230
+ const promise = manager.createDraftNode("volumeId~parentUid", "name", {} as UploadMetadata);
250
231
 
251
232
  try {
252
- await result;
233
+ await promise;
253
234
  } catch (error: any) {
254
- expect(error.availableName).toBe("name1");
235
+ expect(error.message).toBe("Draft already exists");
236
+ expect(error.ongoingUploadByOtherClient).toBe(true);
255
237
  }
238
+ expect(apiService.deleteDraft).not.toHaveBeenCalled();
256
239
  });
257
240
 
258
- it("should handle existing name by providing available name when there is too many conflicts", async () => {
259
- let hashChecked = false;
241
+ it("should handle error when deleting existing draft", async () => {
242
+ let firstCall = true;
260
243
  apiService.createDraft = jest.fn().mockImplementation(() => {
261
- if (!hashChecked) {
262
- throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS);
244
+ if (firstCall) {
245
+ firstCall = false;
246
+ throw new ValidationError("Draft already exists", ErrorCode.ALREADY_EXISTS, {
247
+ ConflictLinkID: "existingLinkId",
248
+ ConflictDraftRevisionID: "existingDraftRevisionId",
249
+ ConflictDraftClientUID: clientUid,
250
+ });
263
251
  }
264
252
  return {
265
253
  nodeUid: "newNode:nodeUid",
266
254
  nodeRevisionUid: "newNode:nodeRevisionUid",
267
255
  };
268
256
  });
257
+ apiService.deleteDraft = jest.fn().mockImplementation(() => {
258
+ throw new Error("Failed to delete draft");
259
+ });
260
+
261
+ const result = manager.createDraftNode("volumeId~parentUid", "name", {} as UploadMetadata);
269
262
 
263
+ try {
264
+ await result;
265
+ } catch (error: any) {
266
+ expect(error.message).toBe("Draft already exists");
267
+ expect(error.existingNodeUid).toBe("volumeId~existingLinkId");
268
+ }
269
+ expect(apiService.deleteDraft).toHaveBeenCalledTimes(1);
270
+ });
271
+ });
272
+
273
+ describe("findAvailableName", () => {
274
+ it("should find available name", async () => {
270
275
  apiService.checkAvailableHashes = jest.fn().mockImplementation(() => {
271
- if (!hashChecked) {
272
- hashChecked = true;
276
+ return {
277
+ availalbleHashes: ["name3Hash"],
278
+ pendingHashes: [],
279
+ }
280
+ });
281
+
282
+ const result = await manager.findAvailableName("parentUid", "name");
283
+ expect(result).toBe("name3");
284
+ expect(apiService.checkAvailableHashes).toHaveBeenCalledTimes(1);
285
+ expect(apiService.checkAvailableHashes).toHaveBeenCalledWith("parentUid", ["name1Hash", "name2Hash", "name3Hash"]);
286
+ });
287
+
288
+ it("should find available name with multiple pages", async () => {
289
+ let firstCall = false;
290
+ apiService.checkAvailableHashes = jest.fn().mockImplementation(() => {
291
+ if (!firstCall) {
292
+ firstCall = true;
273
293
  return {
274
294
  // First page has no available hashes
275
295
  availalbleHashes: [],
@@ -282,16 +302,10 @@ describe("UploadManager", () => {
282
302
  }
283
303
  });
284
304
 
285
- const result = manager.createDraftNode("parentUid", "name", {} as UploadMetadata);
286
-
287
- await expect(result).rejects.toThrow("Draft already exists");
305
+ const result = await manager.findAvailableName("parentUid", "name");
306
+ expect(result).toBe("name3");
288
307
  expect(apiService.checkAvailableHashes).toHaveBeenCalledTimes(2);
289
-
290
- try {
291
- await result;
292
- } catch (error: any) {
293
- expect(error.availableName).toBe("name3");
294
- }
308
+ expect(apiService.checkAvailableHashes).toHaveBeenCalledWith("parentUid", ["name1Hash", "name2Hash", "name3Hash"]);
295
309
  });
296
310
  });
297
311
 
@@ -300,7 +314,7 @@ describe("UploadManager", () => {
300
314
  nodeUid: "newNode:nodeUid",
301
315
  nodeRevisionUid: "newNode:nodeRevisionUid",
302
316
  nodeKeys: {
303
- key: {_idx: 32321},
317
+ key: { _idx: 32321 },
304
318
  contentKeyPacketSessionKey: "newNode:contentKeyPacketSessionKey",
305
319
  signatureAddress: {
306
320
  email: "signatureEmail",
@@ -327,29 +341,11 @@ describe("UploadManager", () => {
327
341
  manifest,
328
342
  metadata,
329
343
  extendedAttributes,
330
- 1234567,
331
344
  );
332
345
 
333
346
  expect(cryptoService.commitFile).toHaveBeenCalledWith(nodeRevisionDraft.nodeKeys, manifest, expect.anything());
334
347
  expect(apiService.commitDraftRevision).toHaveBeenCalledWith(nodeRevisionDraft.nodeRevisionUid, expect.anything());
335
- expect(nodesEvents.nodeUpdated).toHaveBeenCalledWith({
336
- uid: "newNode:nodeUid",
337
- activeRevision: {
338
- ok: true,
339
- value: {
340
- uid: "newNode:nodeRevisionUid",
341
- state: RevisionState.Active,
342
- creationTime: expect.any(Date),
343
- contentAuthor: { ok: true, value: "signatureEmail" },
344
- storageSize: 1234567,
345
- claimedSize: 123456,
346
- claimedModificationTime: extendedAttributes.modificationTime,
347
- claimedDigests: {
348
- sha1: "sha1",
349
- },
350
- },
351
- },
352
- });
348
+ expect(nodesService.notifyChildCreated).toHaveBeenCalledWith("parentUid");
353
349
  })
354
350
 
355
351
  it("should commit node draft", async () => {
@@ -367,24 +363,11 @@ describe("UploadManager", () => {
367
363
  manifest,
368
364
  metadata,
369
365
  extendedAttributes,
370
- 1234567,
371
366
  );
372
367
 
373
368
  expect(cryptoService.commitFile).toHaveBeenCalledWith(nodeRevisionDraft.nodeKeys, manifest, expect.anything());
374
369
  expect(apiService.commitDraftRevision).toHaveBeenCalledWith(nodeRevisionDraft.nodeRevisionUid, expect.anything());
375
- expect(nodesEvents.nodeCreated).toHaveBeenCalledWith(expect.objectContaining({
376
- uid: "newNode:nodeUid",
377
- parentUid: "parentUid",
378
- type: NodeType.File,
379
- totalStorageSize: 1234567,
380
- activeRevision: {
381
- ok: true,
382
- value: expect.objectContaining({
383
- uid: "newNode:nodeRevisionUid",
384
- storageSize: 1234567,
385
- }),
386
- },
387
- }));
370
+ expect(nodesService.notifyChildCreated).toHaveBeenCalledWith("parentUid");
388
371
  });
389
372
  });
390
373
  });