@protontech/drive-sdk 0.4.1 → 0.5.1

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 (197) hide show
  1. package/dist/diagnostic/{sdkDiagnosticFull.d.ts → diagnostic.d.ts} +5 -4
  2. package/dist/diagnostic/{sdkDiagnosticFull.js → diagnostic.js} +13 -10
  3. package/dist/diagnostic/diagnostic.js.map +1 -0
  4. package/dist/diagnostic/index.js +2 -4
  5. package/dist/diagnostic/index.js.map +1 -1
  6. package/dist/diagnostic/interface.d.ts +22 -1
  7. package/dist/diagnostic/sdkDiagnostic.d.ts +3 -2
  8. package/dist/diagnostic/sdkDiagnostic.js +80 -8
  9. package/dist/diagnostic/sdkDiagnostic.js.map +1 -1
  10. package/dist/interface/download.d.ts +4 -4
  11. package/dist/interface/index.d.ts +1 -1
  12. package/dist/interface/index.js.map +1 -1
  13. package/dist/interface/nodes.d.ts +9 -0
  14. package/dist/interface/telemetry.d.ts +4 -1
  15. package/dist/interface/telemetry.js.map +1 -1
  16. package/dist/interface/upload.d.ts +6 -3
  17. package/dist/internal/apiService/apiService.d.ts +3 -0
  18. package/dist/internal/apiService/apiService.js +25 -2
  19. package/dist/internal/apiService/apiService.js.map +1 -1
  20. package/dist/internal/apiService/apiService.test.js +38 -0
  21. package/dist/internal/apiService/apiService.test.js.map +1 -1
  22. package/dist/internal/apiService/driveTypes.d.ts +2595 -2397
  23. package/dist/internal/apiService/errors.js +3 -0
  24. package/dist/internal/apiService/errors.js.map +1 -1
  25. package/dist/internal/apiService/errors.test.js +15 -7
  26. package/dist/internal/apiService/errors.test.js.map +1 -1
  27. package/dist/internal/asyncIteratorMap.d.ts +1 -1
  28. package/dist/internal/asyncIteratorMap.js +6 -1
  29. package/dist/internal/asyncIteratorMap.js.map +1 -1
  30. package/dist/internal/asyncIteratorMap.test.js +9 -0
  31. package/dist/internal/asyncIteratorMap.test.js.map +1 -1
  32. package/dist/internal/download/controller.d.ts +2 -0
  33. package/dist/internal/download/controller.js +15 -1
  34. package/dist/internal/download/controller.js.map +1 -1
  35. package/dist/internal/download/fileDownloader.d.ts +3 -3
  36. package/dist/internal/download/fileDownloader.js +11 -6
  37. package/dist/internal/download/fileDownloader.js.map +1 -1
  38. package/dist/internal/download/fileDownloader.test.js +8 -8
  39. package/dist/internal/download/fileDownloader.test.js.map +1 -1
  40. package/dist/internal/nodes/apiService.d.ts +6 -1
  41. package/dist/internal/nodes/apiService.js +71 -44
  42. package/dist/internal/nodes/apiService.js.map +1 -1
  43. package/dist/internal/nodes/apiService.test.js +204 -15
  44. package/dist/internal/nodes/apiService.test.js.map +1 -1
  45. package/dist/internal/nodes/debouncer.d.ts +24 -0
  46. package/dist/internal/nodes/debouncer.js +92 -0
  47. package/dist/internal/nodes/debouncer.js.map +1 -0
  48. package/dist/internal/nodes/debouncer.test.d.ts +1 -0
  49. package/dist/internal/nodes/debouncer.test.js +108 -0
  50. package/dist/internal/nodes/debouncer.test.js.map +1 -0
  51. package/dist/internal/nodes/extendedAttributes.js +2 -2
  52. package/dist/internal/nodes/extendedAttributes.js.map +1 -1
  53. package/dist/internal/nodes/index.js +1 -1
  54. package/dist/internal/nodes/index.js.map +1 -1
  55. package/dist/internal/nodes/nodesAccess.d.ts +6 -4
  56. package/dist/internal/nodes/nodesAccess.js +29 -9
  57. package/dist/internal/nodes/nodesAccess.js.map +1 -1
  58. package/dist/internal/nodes/nodesAccess.test.js +19 -7
  59. package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
  60. package/dist/internal/nodes/nodesManagement.d.ts +2 -2
  61. package/dist/internal/nodes/nodesManagement.js +5 -3
  62. package/dist/internal/nodes/nodesManagement.js.map +1 -1
  63. package/dist/internal/nodes/nodesManagement.test.js +3 -1
  64. package/dist/internal/nodes/nodesManagement.test.js.map +1 -1
  65. package/dist/internal/photos/apiService.js +9 -20
  66. package/dist/internal/photos/apiService.js.map +1 -1
  67. package/dist/internal/photos/upload.d.ts +2 -1
  68. package/dist/internal/photos/upload.js +9 -3
  69. package/dist/internal/photos/upload.js.map +1 -1
  70. package/dist/internal/sharing/apiService.d.ts +1 -1
  71. package/dist/internal/sharing/apiService.js +2 -2
  72. package/dist/internal/sharing/apiService.js.map +1 -1
  73. package/dist/internal/sharing/sharingManagement.d.ts +4 -1
  74. package/dist/internal/sharing/sharingManagement.js +7 -4
  75. package/dist/internal/sharing/sharingManagement.js.map +1 -1
  76. package/dist/internal/sharingPublic/apiService.d.ts +8 -10
  77. package/dist/internal/sharingPublic/apiService.js +9 -125
  78. package/dist/internal/sharingPublic/apiService.js.map +1 -1
  79. package/dist/internal/sharingPublic/cryptoReporter.d.ts +16 -0
  80. package/dist/internal/sharingPublic/{cryptoService.js → cryptoReporter.js} +3 -16
  81. package/dist/internal/sharingPublic/cryptoReporter.js.map +1 -0
  82. package/dist/internal/sharingPublic/index.d.ts +22 -4
  83. package/dist/internal/sharingPublic/index.js +37 -12
  84. package/dist/internal/sharingPublic/index.js.map +1 -1
  85. package/dist/internal/sharingPublic/nodes.d.ts +18 -0
  86. package/dist/internal/sharingPublic/nodes.js +46 -0
  87. package/dist/internal/sharingPublic/nodes.js.map +1 -0
  88. package/dist/internal/sharingPublic/session/apiService.d.ts +7 -5
  89. package/dist/internal/sharingPublic/session/apiService.js +25 -4
  90. package/dist/internal/sharingPublic/session/apiService.js.map +1 -1
  91. package/dist/internal/sharingPublic/session/interface.d.ts +17 -0
  92. package/dist/internal/sharingPublic/session/manager.d.ts +12 -4
  93. package/dist/internal/sharingPublic/session/manager.js +14 -4
  94. package/dist/internal/sharingPublic/session/manager.js.map +1 -1
  95. package/dist/internal/sharingPublic/session/session.d.ts +7 -4
  96. package/dist/internal/sharingPublic/session/session.js +7 -3
  97. package/dist/internal/sharingPublic/session/session.js.map +1 -1
  98. package/dist/internal/sharingPublic/session/url.test.js +3 -3
  99. package/dist/internal/sharingPublic/shares.d.ts +27 -0
  100. package/dist/internal/sharingPublic/shares.js +46 -0
  101. package/dist/internal/sharingPublic/shares.js.map +1 -0
  102. package/dist/internal/upload/apiService.js +10 -1
  103. package/dist/internal/upload/apiService.js.map +1 -1
  104. package/dist/internal/upload/controller.d.ts +11 -3
  105. package/dist/internal/upload/controller.js +16 -2
  106. package/dist/internal/upload/controller.js.map +1 -1
  107. package/dist/internal/upload/fileUploader.d.ts +6 -3
  108. package/dist/internal/upload/fileUploader.js +4 -4
  109. package/dist/internal/upload/fileUploader.js.map +1 -1
  110. package/dist/internal/upload/fileUploader.test.js +23 -11
  111. package/dist/internal/upload/fileUploader.test.js.map +1 -1
  112. package/dist/internal/upload/streamUploader.d.ts +9 -4
  113. package/dist/internal/upload/streamUploader.js +67 -20
  114. package/dist/internal/upload/streamUploader.js.map +1 -1
  115. package/dist/internal/upload/streamUploader.test.js +43 -13
  116. package/dist/internal/upload/streamUploader.test.js.map +1 -1
  117. package/dist/protonDriveClient.d.ts +11 -6
  118. package/dist/protonDriveClient.js +11 -10
  119. package/dist/protonDriveClient.js.map +1 -1
  120. package/dist/protonDrivePublicLinkClient.d.ts +34 -6
  121. package/dist/protonDrivePublicLinkClient.js +52 -9
  122. package/dist/protonDrivePublicLinkClient.js.map +1 -1
  123. package/dist/tests/telemetry.d.ts +4 -2
  124. package/dist/tests/telemetry.js +3 -1
  125. package/dist/tests/telemetry.js.map +1 -1
  126. package/dist/transformers.d.ts +3 -2
  127. package/dist/transformers.js +6 -0
  128. package/dist/transformers.js.map +1 -1
  129. package/package.json +1 -1
  130. package/src/diagnostic/{sdkDiagnosticFull.ts → diagnostic.ts} +10 -6
  131. package/src/diagnostic/index.ts +3 -5
  132. package/src/diagnostic/interface.ts +39 -0
  133. package/src/diagnostic/sdkDiagnostic.ts +111 -10
  134. package/src/interface/download.ts +4 -4
  135. package/src/interface/index.ts +1 -0
  136. package/src/interface/nodes.ts +3 -0
  137. package/src/interface/telemetry.ts +5 -0
  138. package/src/interface/upload.ts +3 -3
  139. package/src/internal/apiService/apiService.test.ts +50 -0
  140. package/src/internal/apiService/apiService.ts +33 -2
  141. package/src/internal/apiService/driveTypes.ts +2713 -2561
  142. package/src/internal/apiService/errors.test.ts +10 -0
  143. package/src/internal/apiService/errors.ts +5 -1
  144. package/src/internal/asyncIteratorMap.test.ts +12 -0
  145. package/src/internal/asyncIteratorMap.ts +8 -0
  146. package/src/internal/download/controller.ts +13 -1
  147. package/src/internal/download/fileDownloader.test.ts +8 -8
  148. package/src/internal/download/fileDownloader.ts +13 -6
  149. package/src/internal/nodes/apiService.test.ts +261 -14
  150. package/src/internal/nodes/apiService.ts +99 -65
  151. package/src/internal/nodes/debouncer.test.ts +141 -0
  152. package/src/internal/nodes/debouncer.ts +109 -0
  153. package/src/internal/nodes/extendedAttributes.ts +2 -2
  154. package/src/internal/nodes/index.ts +1 -8
  155. package/src/internal/nodes/nodesAccess.test.ts +19 -7
  156. package/src/internal/nodes/nodesAccess.ts +44 -9
  157. package/src/internal/nodes/nodesManagement.test.ts +3 -1
  158. package/src/internal/nodes/nodesManagement.ts +11 -5
  159. package/src/internal/photos/apiService.ts +12 -29
  160. package/src/internal/photos/upload.ts +22 -1
  161. package/src/internal/sharing/apiService.ts +2 -2
  162. package/src/internal/sharing/sharingManagement.ts +7 -4
  163. package/src/internal/sharingPublic/apiService.ts +23 -160
  164. package/src/internal/sharingPublic/{cryptoService.ts → cryptoReporter.ts} +2 -27
  165. package/src/internal/sharingPublic/index.ts +76 -13
  166. package/src/internal/sharingPublic/nodes.ts +59 -0
  167. package/src/internal/sharingPublic/session/apiService.ts +32 -10
  168. package/src/internal/sharingPublic/session/interface.ts +20 -0
  169. package/src/internal/sharingPublic/session/manager.ts +31 -8
  170. package/src/internal/sharingPublic/session/session.ts +12 -7
  171. package/src/internal/sharingPublic/session/url.test.ts +3 -3
  172. package/src/internal/sharingPublic/shares.ts +50 -0
  173. package/src/internal/upload/apiService.ts +12 -1
  174. package/src/internal/upload/controller.ts +16 -4
  175. package/src/internal/upload/fileUploader.test.ts +25 -11
  176. package/src/internal/upload/fileUploader.ts +6 -5
  177. package/src/internal/upload/streamUploader.test.ts +56 -12
  178. package/src/internal/upload/streamUploader.ts +78 -20
  179. package/src/protonDriveClient.ts +29 -11
  180. package/src/protonDrivePublicLinkClient.ts +100 -16
  181. package/src/tests/telemetry.ts +6 -3
  182. package/src/transformers.ts +8 -0
  183. package/dist/diagnostic/sdkDiagnosticFull.js.map +0 -1
  184. package/dist/internal/sharingPublic/cryptoCache.d.ts +0 -19
  185. package/dist/internal/sharingPublic/cryptoCache.js +0 -72
  186. package/dist/internal/sharingPublic/cryptoCache.js.map +0 -1
  187. package/dist/internal/sharingPublic/cryptoService.d.ts +0 -9
  188. package/dist/internal/sharingPublic/cryptoService.js.map +0 -1
  189. package/dist/internal/sharingPublic/interface.d.ts +0 -6
  190. package/dist/internal/sharingPublic/interface.js +0 -3
  191. package/dist/internal/sharingPublic/interface.js.map +0 -1
  192. package/dist/internal/sharingPublic/manager.d.ts +0 -19
  193. package/dist/internal/sharingPublic/manager.js +0 -81
  194. package/dist/internal/sharingPublic/manager.js.map +0 -1
  195. package/src/internal/sharingPublic/cryptoCache.ts +0 -79
  196. package/src/internal/sharingPublic/interface.ts +0 -14
  197. package/src/internal/sharingPublic/manager.ts +0 -86
@@ -43,10 +43,10 @@ class Uploader {
43
43
  });
44
44
  }
45
45
 
46
- this.controller = new UploadController();
46
+ this.controller = new UploadController(this.abortController.signal);
47
47
  }
48
48
 
49
- async writeFile(
49
+ async uploadFromFile(
50
50
  fileObject: File,
51
51
  thumbnails: Thumbnail[],
52
52
  onProgress?: (uploadedBytes: number) => void,
@@ -67,7 +67,7 @@ class Uploader {
67
67
  return this.controller;
68
68
  }
69
69
 
70
- async writeStream(
70
+ async uploadFromStream(
71
71
  stream: ReadableStream,
72
72
  thumbnails: Thumbnail[],
73
73
  onProgress?: (uploadedBytes: number) => void,
@@ -83,7 +83,7 @@ class Uploader {
83
83
  stream: ReadableStream,
84
84
  thumbnails: Thumbnail[],
85
85
  onProgress?: (uploadedBytes: number) => void,
86
- ): Promise<string> {
86
+ ): Promise<{ nodeRevisionUid: string, nodeUid: string }> {
87
87
  const uploader = await this.initStreamUploader();
88
88
  return uploader.start(stream, thumbnails, onProgress);
89
89
  }
@@ -119,7 +119,8 @@ class Uploader {
119
119
  revisionDraft,
120
120
  this.metadata,
121
121
  onFinish,
122
- this.signal,
122
+ this.controller,
123
+ this.abortController,
123
124
  );
124
125
  }
125
126
 
@@ -108,6 +108,7 @@ describe('StreamUploader', () => {
108
108
 
109
109
  revisionDraft = {
110
110
  nodeRevisionUid: 'revisionUid',
111
+ nodeUid: 'nodeUid',
111
112
  nodeKeys: {
112
113
  signatureAddress: { addressId: 'addressId' },
113
114
  },
@@ -131,7 +132,8 @@ describe('StreamUploader', () => {
131
132
  revisionDraft,
132
133
  metadata,
133
134
  onFinish,
134
- abortController.signal,
135
+ controller,
136
+ abortController,
135
137
  );
136
138
  });
137
139
 
@@ -143,7 +145,12 @@ describe('StreamUploader', () => {
143
145
  let stream: ReadableStream<Uint8Array>;
144
146
 
145
147
  const verifySuccess = async () => {
146
- await uploader.start(stream, thumbnails, onProgress);
148
+ const result = await uploader.start(stream, thumbnails, onProgress);
149
+
150
+ expect(result).toEqual({
151
+ nodeRevisionUid: 'revisionUid',
152
+ nodeUid: 'nodeUid',
153
+ });
147
154
 
148
155
  const numberOfExpectedBlocks = Math.ceil(metadata.expectedSize / FILE_CHUNK_SIZE);
149
156
  expect(uploadManager.commitDraft).toHaveBeenCalledTimes(1);
@@ -251,6 +258,8 @@ describe('StreamUploader', () => {
251
258
  revisionDraft,
252
259
  metadata,
253
260
  onFinish,
261
+ controller,
262
+ abortController,
254
263
  );
255
264
 
256
265
  await verifySuccess();
@@ -278,6 +287,8 @@ describe('StreamUploader', () => {
278
287
  revisionDraft,
279
288
  metadata,
280
289
  onFinish,
290
+ controller,
291
+ abortController,
281
292
  );
282
293
 
283
294
  await verifySuccess();
@@ -422,14 +433,6 @@ describe('StreamUploader', () => {
422
433
  await verifyOnProgress([1024, 4 * 1024 * 1024, 2 * 1024 * 1024, 4 * 1024 * 1024]);
423
434
  });
424
435
 
425
- it('should handle abortion', async () => {
426
- const error = new Error('Aborted');
427
- const promise = uploader.start(stream, thumbnails, onProgress);
428
- abortController.abort(error);
429
- await promise;
430
- expect(apiService.uploadBlock.mock.calls[0][4]?.aborted).toBe(true);
431
- });
432
-
433
436
  describe('verifyIntegrity', () => {
434
437
  it('should report block verification error', async () => {
435
438
  blockVerifier.verifyBlock = jest.fn().mockRejectedValue(new IntegrityError('Block verification error'));
@@ -459,9 +462,10 @@ describe('StreamUploader', () => {
459
462
  {
460
463
  // Fake expected size to break verification
461
464
  expectedSize: 1 * 1024 * 1024 + 1024,
462
- mediaType: '',
463
- },
465
+ } as UploadMetadata,
464
466
  onFinish,
467
+ controller,
468
+ abortController,
465
469
  );
466
470
 
467
471
  await verifyFailure(
@@ -486,4 +490,44 @@ describe('StreamUploader', () => {
486
490
  });
487
491
  });
488
492
  });
493
+
494
+ describe('abort', () => {
495
+ const thumbnails: Thumbnail[] = [];
496
+ let stream: ReadableStream<Uint8Array>;
497
+ let streamController: ReadableStreamDefaultController<Uint8Array>;
498
+
499
+ beforeEach(() => {
500
+ stream = new ReadableStream({
501
+ start(controller) {
502
+ streamController = controller;
503
+ },
504
+ });
505
+ });
506
+
507
+ it('should abort at the start', async () => {
508
+ const promise = uploader.start(stream, thumbnails);
509
+ abortController.abort();
510
+ await expect(promise).rejects.toThrow('Operation aborted');
511
+ });
512
+
513
+ it('should abort when encrypting blocks', async () => {
514
+ const promise = uploader.start(stream, thumbnails);
515
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
516
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
517
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
518
+ abortController.abort();
519
+ await expect(promise).rejects.toThrow('Operation aborted');
520
+ });
521
+
522
+ it('should abort when uploading block', async () => {
523
+ apiService.uploadBlock = jest.fn().mockImplementation(async function () {
524
+ abortController.abort();
525
+ });
526
+
527
+ const promise = uploader.start(stream, thumbnails);
528
+ streamController.enqueue(new Uint8Array(FILE_CHUNK_SIZE));
529
+
530
+ await expect(promise).rejects.toThrow('Operation aborted');
531
+ });
532
+ });
489
533
  });
@@ -1,7 +1,7 @@
1
1
  import { c } from 'ttag';
2
2
 
3
3
  import { Thumbnail, Logger, ThumbnailType, UploadMetadata } from '../../interface';
4
- import { IntegrityError } from '../../errors';
4
+ import { AbortError, IntegrityError } from '../../errors';
5
5
  import { LoggerWithPrefix } from '../../telemetry';
6
6
  import { APIHTTPError, HTTPErrorCode, NotFoundAPIError } from '../apiService';
7
7
  import { getErrorMessage } from '../errors';
@@ -59,7 +59,6 @@ export class StreamUploader {
59
59
 
60
60
  protected digests: UploadDigests;
61
61
  protected controller: UploadController;
62
- protected abortController: AbortController;
63
62
 
64
63
  protected encryptedThumbnails = new Map<ThumbnailType, EncryptedThumbnail>();
65
64
  protected encryptedBlocks = new Map<number, EncryptedBlock>();
@@ -75,6 +74,9 @@ export class StreamUploader {
75
74
  protected uploadedThumbnails: ({ type: ThumbnailType } & EncryptedBlockMetadata)[] = [];
76
75
  protected uploadedBlocks: ({ index: number } & EncryptedBlockMetadata)[] = [];
77
76
 
77
+ // Error of the whole upload - either encryption or upload error.
78
+ protected error: unknown | undefined;
79
+
78
80
  constructor(
79
81
  protected telemetry: UploadTelemetry,
80
82
  protected apiService: UploadAPIService,
@@ -84,7 +86,8 @@ export class StreamUploader {
84
86
  protected revisionDraft: NodeRevisionDraft,
85
87
  protected metadata: UploadMetadata,
86
88
  protected onFinish: (failure: boolean) => Promise<void>,
87
- protected signal?: AbortSignal,
89
+ protected uploadController: UploadController,
90
+ protected abortController: AbortController,
88
91
  ) {
89
92
  this.telemetry = telemetry;
90
93
  this.logger = telemetry.getLoggerForRevision(revisionDraft.nodeRevisionUid);
@@ -95,23 +98,16 @@ export class StreamUploader {
95
98
  this.metadata = metadata;
96
99
  this.onFinish = onFinish;
97
100
 
98
- this.signal = signal;
99
- this.abortController = new AbortController();
100
- if (signal) {
101
- signal.addEventListener('abort', () => {
102
- this.abortController.abort();
103
- });
104
- }
105
-
106
101
  this.digests = new UploadDigests();
107
- this.controller = new UploadController();
102
+ this.controller = uploadController;
103
+ this.abortController = abortController;
108
104
  }
109
105
 
110
106
  async start(
111
107
  stream: ReadableStream,
112
108
  thumbnails: Thumbnail[],
113
109
  onProgress?: (uploadedBytes: number) => void,
114
- ): Promise<string> {
110
+ ): Promise<{ nodeRevisionUid: string; nodeUid: string }> {
115
111
  let failure = false;
116
112
 
117
113
  // File progress is tracked for telemetry - to track at what
@@ -154,7 +150,10 @@ export class StreamUploader {
154
150
  await this.onFinish(failure);
155
151
  }
156
152
 
157
- return this.revisionDraft.nodeRevisionUid;
153
+ return {
154
+ nodeRevisionUid: this.revisionDraft.nodeRevisionUid,
155
+ nodeUid: this.revisionDraft.nodeUid,
156
+ };
158
157
  }
159
158
 
160
159
  private async encryptAndUploadBlocks(
@@ -178,8 +177,8 @@ export class StreamUploader {
178
177
  void this.abortUpload(error);
179
178
  });
180
179
 
181
- while (!encryptionError) {
182
- await this.controller.waitIfPaused();
180
+ while (!this.isUploadAborted) {
181
+ await this.controller.waitWhilePaused();
183
182
  await this.waitForUploadCapacityAndBufferedBlocks();
184
183
 
185
184
  if (this.isEncryptionFullyFinished) {
@@ -193,6 +192,17 @@ export class StreamUploader {
193
192
  }
194
193
  }
195
194
 
195
+ // If the upload was aborted due to encryption or upload error, throw
196
+ // the original error (it is failing upload).
197
+ // If the upload was aborted due to abort signal, throw AbortError
198
+ // (it is aborted by the user).
199
+ if (this.error) {
200
+ throw this.error;
201
+ }
202
+ if (this.abortController.signal.aborted) {
203
+ throw new AbortError();
204
+ }
205
+
196
206
  this.logger.debug(`All blocks uploading, waiting for them to finish`);
197
207
  // Technically this is finished as while-block above will break
198
208
  // when encryption is finished. But in case of error there could
@@ -228,6 +238,10 @@ export class StreamUploader {
228
238
  }
229
239
 
230
240
  for (const thumbnail of thumbnails) {
241
+ if (this.isUploadAborted) {
242
+ break;
243
+ }
244
+
231
245
  this.logger.debug(`Encrypting thumbnail ${thumbnail.type}`);
232
246
  const encryptedThumbnail = await this.cryptoService.encryptThumbnail(
233
247
  this.revisionDraft.nodeKeys,
@@ -246,9 +260,13 @@ export class StreamUploader {
246
260
 
247
261
  this.digests.update(block);
248
262
 
249
- await this.controller.waitIfPaused();
263
+ await this.controller.waitWhilePaused();
250
264
  await this.waitForBufferCapacity();
251
265
 
266
+ if (this.isUploadAborted) {
267
+ break;
268
+ }
269
+
252
270
  this.logger.debug(`Encrypting block ${index}`);
253
271
  let attempt = 0;
254
272
  let integrityError = false;
@@ -267,6 +285,11 @@ export class StreamUploader {
267
285
  void this.telemetry.logBlockVerificationError(true);
268
286
  }
269
287
  } catch (error: unknown) {
288
+ // Do not retry or report anything if the upload was aborted.
289
+ if (error instanceof AbortError) {
290
+ throw error;
291
+ }
292
+
270
293
  if (error instanceof IntegrityError) {
271
294
  integrityError = true;
272
295
  }
@@ -394,6 +417,11 @@ export class StreamUploader {
394
417
  });
395
418
  break;
396
419
  } catch (error: unknown) {
420
+ // Do not retry or report anything if the upload was aborted.
421
+ if (error instanceof AbortError) {
422
+ throw error;
423
+ }
424
+
397
425
  if (blockProgress !== 0) {
398
426
  onProgress?.(-blockProgress);
399
427
  blockProgress = 0;
@@ -456,6 +484,11 @@ export class StreamUploader {
456
484
  });
457
485
  break;
458
486
  } catch (error: unknown) {
487
+ // Do not retry or report anything if the upload was aborted.
488
+ if (error instanceof AbortError) {
489
+ throw error;
490
+ }
491
+
459
492
  if (blockProgress !== 0) {
460
493
  onProgress?.(-blockProgress);
461
494
  blockProgress = 0;
@@ -505,7 +538,17 @@ export class StreamUploader {
505
538
 
506
539
  private async waitForBufferCapacity() {
507
540
  if (this.encryptedBlocks.size >= MAX_BUFFERED_BLOCKS) {
508
- await waitForCondition(() => this.encryptedBlocks.size < MAX_BUFFERED_BLOCKS);
541
+ try {
542
+ await waitForCondition(
543
+ () => this.encryptedBlocks.size < MAX_BUFFERED_BLOCKS,
544
+ this.abortController.signal,
545
+ );
546
+ } catch (error: unknown) {
547
+ if (error instanceof AbortError) {
548
+ return;
549
+ }
550
+ throw error;
551
+ }
509
552
  }
510
553
  }
511
554
 
@@ -513,7 +556,17 @@ export class StreamUploader {
513
556
  while (this.ongoingUploads.size >= MAX_UPLOADING_BLOCKS) {
514
557
  await Promise.race(this.ongoingUploads.values().map(({ uploadPromise }) => uploadPromise));
515
558
  }
516
- await waitForCondition(() => this.encryptedBlocks.size > 0 || this.encryptionFinished);
559
+ try {
560
+ await waitForCondition(
561
+ () => this.encryptedBlocks.size > 0 || this.encryptionFinished,
562
+ this.abortController.signal,
563
+ );
564
+ } catch (error: unknown) {
565
+ if (error instanceof AbortError) {
566
+ return;
567
+ }
568
+ throw error;
569
+ }
517
570
  }
518
571
 
519
572
  protected verifyIntegrity(thumbnails: Thumbnail[]) {
@@ -568,9 +621,14 @@ export class StreamUploader {
568
621
  }
569
622
 
570
623
  private async abortUpload(error: unknown) {
571
- if (this.abortController.signal.aborted || this.signal?.aborted) {
624
+ if (this.isUploadAborted) {
572
625
  return;
573
626
  }
627
+ this.error = error;
574
628
  this.abortController.abort(error);
575
629
  }
630
+
631
+ private get isUploadAborted(): boolean {
632
+ return !!this.error || this.abortController.signal.aborted;
633
+ }
576
634
  }
@@ -7,6 +7,7 @@ import {
7
7
  MaybeNode,
8
8
  MaybeMissingNode,
9
9
  NodeResult,
10
+ NodeResultWithNewUid,
10
11
  Revision,
11
12
  RevisionOrUid,
12
13
  ShareNodeSettings,
@@ -28,6 +29,7 @@ import {
28
29
  ThumbnailResult,
29
30
  SDKEvent,
30
31
  NodeType,
32
+ MemberRole,
31
33
  } from './interface';
32
34
  import {
33
35
  getUid,
@@ -36,6 +38,7 @@ import {
36
38
  convertInternalNodeIterator,
37
39
  convertInternalMissingNodeIterator,
38
40
  convertInternalNode,
41
+ convertInternalRevisionIterator,
39
42
  } from './transformers';
40
43
  import { Telemetry } from './telemetry';
41
44
  import { DriveAPIService } from './internal/apiService';
@@ -68,7 +71,7 @@ export class ProtonDriveClient {
68
71
  private download: ReturnType<typeof initDownloadModule>;
69
72
  private upload: ReturnType<typeof initUploadModule>;
70
73
  private devices: ReturnType<typeof initDevicesModule>;
71
- private sessionManager: SharingPublicSessionManager;
74
+ private publicSessionManager: SharingPublicSessionManager;
72
75
 
73
76
  public experimental: {
74
77
  /**
@@ -93,6 +96,11 @@ export class ProtonDriveClient {
93
96
  isCustomPasswordProtected: boolean;
94
97
  isLegacy: boolean;
95
98
  vendorType: number;
99
+ directAccess?: {
100
+ nodeUid: string;
101
+ directRole: MemberRole;
102
+ publicRole: MemberRole;
103
+ };
96
104
  }>;
97
105
  /**
98
106
  * Experimental feature to authenticate a public link and
@@ -184,7 +192,13 @@ export class ProtonDriveClient {
184
192
  latestEventIdProvider,
185
193
  );
186
194
 
187
- this.sessionManager = new SharingPublicSessionManager(httpClient, apiService, srpModule);
195
+ this.publicSessionManager = new SharingPublicSessionManager(
196
+ telemetry,
197
+ httpClient,
198
+ cryptoModule,
199
+ srpModule,
200
+ apiService,
201
+ );
188
202
 
189
203
  this.experimental = {
190
204
  getNodeUrl: async (nodeUid: NodeOrUid) => {
@@ -201,21 +215,25 @@ export class ProtonDriveClient {
201
215
  },
202
216
  getPublicLinkInfo: async (url: string) => {
203
217
  this.logger.info(`Getting info for public link ${url}`);
204
- return this.sessionManager.getInfo(url);
218
+ return this.publicSessionManager.getInfo(url);
205
219
  },
206
220
  authPublicLink: async (url: string, customPassword?: string) => {
207
221
  this.logger.info(`Authenticating public link ${url}`);
208
- const { httpClient, token, password } = await this.sessionManager.auth(url, customPassword);
222
+ const { httpClient, token, shareKey, rootUid } = await this.publicSessionManager.auth(
223
+ url,
224
+ customPassword,
225
+ );
209
226
  return new ProtonDrivePublicLinkClient({
210
227
  httpClient,
211
- cryptoCache,
212
228
  account,
213
229
  openPGPCryptoModule,
214
230
  srpModule,
215
231
  config,
216
232
  telemetry,
233
+ url,
217
234
  token,
218
- password,
235
+ publicShareKey: shareKey,
236
+ publicRootNodeUid: rootUid,
219
237
  });
220
238
  },
221
239
  };
@@ -408,7 +426,7 @@ export class ProtonDriveClient {
408
426
  nodeUids: NodeOrUid[],
409
427
  newParentNodeUid: NodeOrUid,
410
428
  signal?: AbortSignal,
411
- ): AsyncGenerator<NodeResult> {
429
+ ): AsyncGenerator<NodeResultWithNewUid> {
412
430
  this.logger.info(`Copying ${nodeUids.length} nodes to ${getUid(newParentNodeUid)}`);
413
431
  yield* this.nodes.management.copyNodes(getUids(nodeUids), getUid(newParentNodeUid), signal);
414
432
  }
@@ -507,7 +525,7 @@ export class ProtonDriveClient {
507
525
  */
508
526
  async *iterateRevisions(nodeUid: NodeOrUid, signal?: AbortSignal): AsyncGenerator<Revision> {
509
527
  this.logger.info(`Iterating revisions of ${getUid(nodeUid)}`);
510
- yield* this.nodes.revisions.iterateRevisions(getUid(nodeUid), signal);
528
+ yield* convertInternalRevisionIterator(this.nodes.revisions.iterateRevisions(getUid(nodeUid), signal));
511
529
  }
512
530
 
513
531
  /**
@@ -726,7 +744,7 @@ export class ProtonDriveClient {
726
744
  * ```typescript
727
745
  * const downloader = await client.getFileDownloader(nodeUid, signal);
728
746
  * const claimedSize = fileDownloader.getClaimedSizeInBytes();
729
- * const downloadController = fileDownloader.writeToStream(stream, (downloadedBytes) => { ... });
747
+ * const downloadController = fileDownloader.downloadToStream(stream, (downloadedBytes) => { ... });
730
748
  *
731
749
  * signalController.abort(); // to cancel
732
750
  * downloadController.pause(); // to pause
@@ -786,12 +804,12 @@ export class ProtonDriveClient {
786
804
  *
787
805
  * ```typescript
788
806
  * const uploader = await client.getFileUploader(parentFolderUid, name, metadata, signal);
789
- * const uploadController = await uploader.writeStream(stream, thumbnails, (uploadedBytes) => { ... });
807
+ * const uploadController = await uploader.uploadFromStream(stream, thumbnails, (uploadedBytes) => { ... });
790
808
  *
791
809
  * signalController.abort(); // to cancel
792
810
  * uploadController.pause(); // to pause
793
811
  * uploadController.resume(); // to resume
794
- * const nodeUid = await uploadController.completion(); // to await completion
812
+ * const { nodeUid, nodeRevisionUid } = await uploadController.completion(); // to await completion
795
813
  * ```
796
814
  */
797
815
  async getFileUploader(