@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.
- package/dist/diagnostic/{sdkDiagnosticFull.d.ts → diagnostic.d.ts} +5 -4
- package/dist/diagnostic/{sdkDiagnosticFull.js → diagnostic.js} +13 -10
- package/dist/diagnostic/diagnostic.js.map +1 -0
- package/dist/diagnostic/index.js +2 -4
- package/dist/diagnostic/index.js.map +1 -1
- package/dist/diagnostic/interface.d.ts +22 -1
- package/dist/diagnostic/sdkDiagnostic.d.ts +3 -2
- package/dist/diagnostic/sdkDiagnostic.js +80 -8
- package/dist/diagnostic/sdkDiagnostic.js.map +1 -1
- package/dist/interface/download.d.ts +4 -4
- package/dist/interface/index.d.ts +1 -1
- package/dist/interface/index.js.map +1 -1
- package/dist/interface/nodes.d.ts +9 -0
- package/dist/interface/telemetry.d.ts +4 -1
- package/dist/interface/telemetry.js.map +1 -1
- package/dist/interface/upload.d.ts +6 -3
- package/dist/internal/apiService/apiService.d.ts +3 -0
- package/dist/internal/apiService/apiService.js +25 -2
- package/dist/internal/apiService/apiService.js.map +1 -1
- package/dist/internal/apiService/apiService.test.js +38 -0
- package/dist/internal/apiService/apiService.test.js.map +1 -1
- package/dist/internal/apiService/driveTypes.d.ts +2595 -2397
- package/dist/internal/apiService/errors.js +3 -0
- package/dist/internal/apiService/errors.js.map +1 -1
- package/dist/internal/apiService/errors.test.js +15 -7
- package/dist/internal/apiService/errors.test.js.map +1 -1
- package/dist/internal/asyncIteratorMap.d.ts +1 -1
- package/dist/internal/asyncIteratorMap.js +6 -1
- package/dist/internal/asyncIteratorMap.js.map +1 -1
- package/dist/internal/asyncIteratorMap.test.js +9 -0
- package/dist/internal/asyncIteratorMap.test.js.map +1 -1
- package/dist/internal/download/controller.d.ts +2 -0
- package/dist/internal/download/controller.js +15 -1
- package/dist/internal/download/controller.js.map +1 -1
- package/dist/internal/download/fileDownloader.d.ts +3 -3
- package/dist/internal/download/fileDownloader.js +11 -6
- package/dist/internal/download/fileDownloader.js.map +1 -1
- package/dist/internal/download/fileDownloader.test.js +8 -8
- package/dist/internal/download/fileDownloader.test.js.map +1 -1
- package/dist/internal/nodes/apiService.d.ts +6 -1
- package/dist/internal/nodes/apiService.js +71 -44
- package/dist/internal/nodes/apiService.js.map +1 -1
- package/dist/internal/nodes/apiService.test.js +204 -15
- package/dist/internal/nodes/apiService.test.js.map +1 -1
- package/dist/internal/nodes/debouncer.d.ts +24 -0
- package/dist/internal/nodes/debouncer.js +92 -0
- package/dist/internal/nodes/debouncer.js.map +1 -0
- package/dist/internal/nodes/debouncer.test.d.ts +1 -0
- package/dist/internal/nodes/debouncer.test.js +108 -0
- package/dist/internal/nodes/debouncer.test.js.map +1 -0
- package/dist/internal/nodes/extendedAttributes.js +2 -2
- package/dist/internal/nodes/extendedAttributes.js.map +1 -1
- package/dist/internal/nodes/index.js +1 -1
- package/dist/internal/nodes/index.js.map +1 -1
- package/dist/internal/nodes/nodesAccess.d.ts +6 -4
- package/dist/internal/nodes/nodesAccess.js +29 -9
- package/dist/internal/nodes/nodesAccess.js.map +1 -1
- package/dist/internal/nodes/nodesAccess.test.js +19 -7
- package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.d.ts +2 -2
- package/dist/internal/nodes/nodesManagement.js +5 -3
- package/dist/internal/nodes/nodesManagement.js.map +1 -1
- package/dist/internal/nodes/nodesManagement.test.js +3 -1
- package/dist/internal/nodes/nodesManagement.test.js.map +1 -1
- package/dist/internal/photos/apiService.js +9 -20
- package/dist/internal/photos/apiService.js.map +1 -1
- package/dist/internal/photos/upload.d.ts +2 -1
- package/dist/internal/photos/upload.js +9 -3
- package/dist/internal/photos/upload.js.map +1 -1
- package/dist/internal/sharing/apiService.d.ts +1 -1
- package/dist/internal/sharing/apiService.js +2 -2
- package/dist/internal/sharing/apiService.js.map +1 -1
- package/dist/internal/sharing/sharingManagement.d.ts +4 -1
- package/dist/internal/sharing/sharingManagement.js +7 -4
- package/dist/internal/sharing/sharingManagement.js.map +1 -1
- package/dist/internal/sharingPublic/apiService.d.ts +8 -10
- package/dist/internal/sharingPublic/apiService.js +9 -125
- package/dist/internal/sharingPublic/apiService.js.map +1 -1
- package/dist/internal/sharingPublic/cryptoReporter.d.ts +16 -0
- package/dist/internal/sharingPublic/{cryptoService.js → cryptoReporter.js} +3 -16
- package/dist/internal/sharingPublic/cryptoReporter.js.map +1 -0
- package/dist/internal/sharingPublic/index.d.ts +22 -4
- package/dist/internal/sharingPublic/index.js +37 -12
- package/dist/internal/sharingPublic/index.js.map +1 -1
- package/dist/internal/sharingPublic/nodes.d.ts +18 -0
- package/dist/internal/sharingPublic/nodes.js +46 -0
- package/dist/internal/sharingPublic/nodes.js.map +1 -0
- package/dist/internal/sharingPublic/session/apiService.d.ts +7 -5
- package/dist/internal/sharingPublic/session/apiService.js +25 -4
- package/dist/internal/sharingPublic/session/apiService.js.map +1 -1
- package/dist/internal/sharingPublic/session/interface.d.ts +17 -0
- package/dist/internal/sharingPublic/session/manager.d.ts +12 -4
- package/dist/internal/sharingPublic/session/manager.js +14 -4
- package/dist/internal/sharingPublic/session/manager.js.map +1 -1
- package/dist/internal/sharingPublic/session/session.d.ts +7 -4
- package/dist/internal/sharingPublic/session/session.js +7 -3
- package/dist/internal/sharingPublic/session/session.js.map +1 -1
- package/dist/internal/sharingPublic/session/url.test.js +3 -3
- package/dist/internal/sharingPublic/shares.d.ts +27 -0
- package/dist/internal/sharingPublic/shares.js +46 -0
- package/dist/internal/sharingPublic/shares.js.map +1 -0
- package/dist/internal/upload/apiService.js +10 -1
- package/dist/internal/upload/apiService.js.map +1 -1
- package/dist/internal/upload/controller.d.ts +11 -3
- package/dist/internal/upload/controller.js +16 -2
- package/dist/internal/upload/controller.js.map +1 -1
- package/dist/internal/upload/fileUploader.d.ts +6 -3
- package/dist/internal/upload/fileUploader.js +4 -4
- package/dist/internal/upload/fileUploader.js.map +1 -1
- package/dist/internal/upload/fileUploader.test.js +23 -11
- package/dist/internal/upload/fileUploader.test.js.map +1 -1
- package/dist/internal/upload/streamUploader.d.ts +9 -4
- package/dist/internal/upload/streamUploader.js +67 -20
- package/dist/internal/upload/streamUploader.js.map +1 -1
- package/dist/internal/upload/streamUploader.test.js +43 -13
- package/dist/internal/upload/streamUploader.test.js.map +1 -1
- package/dist/protonDriveClient.d.ts +11 -6
- package/dist/protonDriveClient.js +11 -10
- package/dist/protonDriveClient.js.map +1 -1
- package/dist/protonDrivePublicLinkClient.d.ts +34 -6
- package/dist/protonDrivePublicLinkClient.js +52 -9
- package/dist/protonDrivePublicLinkClient.js.map +1 -1
- package/dist/tests/telemetry.d.ts +4 -2
- package/dist/tests/telemetry.js +3 -1
- package/dist/tests/telemetry.js.map +1 -1
- package/dist/transformers.d.ts +3 -2
- package/dist/transformers.js +6 -0
- package/dist/transformers.js.map +1 -1
- package/package.json +1 -1
- package/src/diagnostic/{sdkDiagnosticFull.ts → diagnostic.ts} +10 -6
- package/src/diagnostic/index.ts +3 -5
- package/src/diagnostic/interface.ts +39 -0
- package/src/diagnostic/sdkDiagnostic.ts +111 -10
- package/src/interface/download.ts +4 -4
- package/src/interface/index.ts +1 -0
- package/src/interface/nodes.ts +3 -0
- package/src/interface/telemetry.ts +5 -0
- package/src/interface/upload.ts +3 -3
- package/src/internal/apiService/apiService.test.ts +50 -0
- package/src/internal/apiService/apiService.ts +33 -2
- package/src/internal/apiService/driveTypes.ts +2713 -2561
- package/src/internal/apiService/errors.test.ts +10 -0
- package/src/internal/apiService/errors.ts +5 -1
- package/src/internal/asyncIteratorMap.test.ts +12 -0
- package/src/internal/asyncIteratorMap.ts +8 -0
- package/src/internal/download/controller.ts +13 -1
- package/src/internal/download/fileDownloader.test.ts +8 -8
- package/src/internal/download/fileDownloader.ts +13 -6
- package/src/internal/nodes/apiService.test.ts +261 -14
- package/src/internal/nodes/apiService.ts +99 -65
- package/src/internal/nodes/debouncer.test.ts +141 -0
- package/src/internal/nodes/debouncer.ts +109 -0
- package/src/internal/nodes/extendedAttributes.ts +2 -2
- package/src/internal/nodes/index.ts +1 -8
- package/src/internal/nodes/nodesAccess.test.ts +19 -7
- package/src/internal/nodes/nodesAccess.ts +44 -9
- package/src/internal/nodes/nodesManagement.test.ts +3 -1
- package/src/internal/nodes/nodesManagement.ts +11 -5
- package/src/internal/photos/apiService.ts +12 -29
- package/src/internal/photos/upload.ts +22 -1
- package/src/internal/sharing/apiService.ts +2 -2
- package/src/internal/sharing/sharingManagement.ts +7 -4
- package/src/internal/sharingPublic/apiService.ts +23 -160
- package/src/internal/sharingPublic/{cryptoService.ts → cryptoReporter.ts} +2 -27
- package/src/internal/sharingPublic/index.ts +76 -13
- package/src/internal/sharingPublic/nodes.ts +59 -0
- package/src/internal/sharingPublic/session/apiService.ts +32 -10
- package/src/internal/sharingPublic/session/interface.ts +20 -0
- package/src/internal/sharingPublic/session/manager.ts +31 -8
- package/src/internal/sharingPublic/session/session.ts +12 -7
- package/src/internal/sharingPublic/session/url.test.ts +3 -3
- package/src/internal/sharingPublic/shares.ts +50 -0
- package/src/internal/upload/apiService.ts +12 -1
- package/src/internal/upload/controller.ts +16 -4
- package/src/internal/upload/fileUploader.test.ts +25 -11
- package/src/internal/upload/fileUploader.ts +6 -5
- package/src/internal/upload/streamUploader.test.ts +56 -12
- package/src/internal/upload/streamUploader.ts +78 -20
- package/src/protonDriveClient.ts +29 -11
- package/src/protonDrivePublicLinkClient.ts +100 -16
- package/src/tests/telemetry.ts +6 -3
- package/src/transformers.ts +8 -0
- package/dist/diagnostic/sdkDiagnosticFull.js.map +0 -1
- package/dist/internal/sharingPublic/cryptoCache.d.ts +0 -19
- package/dist/internal/sharingPublic/cryptoCache.js +0 -72
- package/dist/internal/sharingPublic/cryptoCache.js.map +0 -1
- package/dist/internal/sharingPublic/cryptoService.d.ts +0 -9
- package/dist/internal/sharingPublic/cryptoService.js.map +0 -1
- package/dist/internal/sharingPublic/interface.d.ts +0 -6
- package/dist/internal/sharingPublic/interface.js +0 -3
- package/dist/internal/sharingPublic/interface.js.map +0 -1
- package/dist/internal/sharingPublic/manager.d.ts +0 -19
- package/dist/internal/sharingPublic/manager.js +0 -81
- package/dist/internal/sharingPublic/manager.js.map +0 -1
- package/src/internal/sharingPublic/cryptoCache.ts +0 -79
- package/src/internal/sharingPublic/interface.ts +0 -14
- 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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 (!
|
|
182
|
-
await this.controller.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
}
|
package/src/protonDriveClient.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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<
|
|
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.
|
|
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.
|
|
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(
|