@protontech/drive-sdk 0.0.10
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/README.md +17 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.js +6 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/interface.d.ts +105 -0
- package/dist/cache/interface.js +3 -0
- package/dist/cache/interface.js.map +1 -0
- package/dist/cache/memoryCache.d.ts +18 -0
- package/dist/cache/memoryCache.js +78 -0
- package/dist/cache/memoryCache.js.map +1 -0
- package/dist/cache/memoryCache.test.d.ts +1 -0
- package/dist/cache/memoryCache.test.js +121 -0
- package/dist/cache/memoryCache.test.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto/driveCrypto.d.ts +209 -0
- package/dist/crypto/driveCrypto.js +364 -0
- package/dist/crypto/driveCrypto.js.map +1 -0
- package/dist/crypto/driveCrypto.test.d.ts +1 -0
- package/dist/crypto/driveCrypto.test.js +42 -0
- package/dist/crypto/driveCrypto.test.js.map +1 -0
- package/dist/crypto/hmac.d.ts +22 -0
- package/dist/crypto/hmac.js +44 -0
- package/dist/crypto/hmac.js.map +1 -0
- package/dist/crypto/index.d.ts +6 -0
- package/dist/crypto/index.js +13 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/interface.d.ts +125 -0
- package/dist/crypto/interface.js +10 -0
- package/dist/crypto/interface.js.map +1 -0
- package/dist/crypto/openPGPCrypto.d.ts +145 -0
- package/dist/crypto/openPGPCrypto.js +250 -0
- package/dist/crypto/openPGPCrypto.js.map +1 -0
- package/dist/crypto/utils.d.ts +2 -0
- package/dist/crypto/utils.js +35 -0
- package/dist/crypto/utils.js.map +1 -0
- package/dist/errors.d.ts +138 -0
- package/dist/errors.js +163 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/interface/account.d.ts +36 -0
- package/dist/interface/account.js +3 -0
- package/dist/interface/account.js.map +1 -0
- package/dist/interface/author.d.ts +26 -0
- package/dist/interface/author.js +3 -0
- package/dist/interface/author.js.map +1 -0
- package/dist/interface/devices.d.ts +18 -0
- package/dist/interface/devices.js +10 -0
- package/dist/interface/devices.js.map +1 -0
- package/dist/interface/download.d.ts +29 -0
- package/dist/interface/download.js +3 -0
- package/dist/interface/download.js.map +1 -0
- package/dist/interface/events.d.ts +26 -0
- package/dist/interface/events.js +11 -0
- package/dist/interface/events.js.map +1 -0
- package/dist/interface/httpClient.d.ts +38 -0
- package/dist/interface/httpClient.js +3 -0
- package/dist/interface/httpClient.js.map +1 -0
- package/dist/interface/index.d.ts +43 -0
- package/dist/interface/index.js +22 -0
- package/dist/interface/index.js.map +1 -0
- package/dist/interface/nodes.d.ts +161 -0
- package/dist/interface/nodes.js +21 -0
- package/dist/interface/nodes.js.map +1 -0
- package/dist/interface/result.d.ts +9 -0
- package/dist/interface/result.js +11 -0
- package/dist/interface/result.js.map +1 -0
- package/dist/interface/sharing.d.ts +73 -0
- package/dist/interface/sharing.js +9 -0
- package/dist/interface/sharing.js.map +1 -0
- package/dist/interface/telemetry.d.ts +61 -0
- package/dist/interface/telemetry.js +18 -0
- package/dist/interface/telemetry.js.map +1 -0
- package/dist/interface/thumbnail.d.ts +17 -0
- package/dist/interface/thumbnail.js +9 -0
- package/dist/interface/thumbnail.js.map +1 -0
- package/dist/interface/upload.d.ts +16 -0
- package/dist/interface/upload.js +3 -0
- package/dist/interface/upload.js.map +1 -0
- package/dist/internal/apiService/apiService.d.ts +51 -0
- package/dist/internal/apiService/apiService.js +305 -0
- package/dist/internal/apiService/apiService.js.map +1 -0
- package/dist/internal/apiService/apiService.test.d.ts +1 -0
- package/dist/internal/apiService/apiService.test.js +237 -0
- package/dist/internal/apiService/apiService.test.js.map +1 -0
- package/dist/internal/apiService/coreTypes.d.ts +24438 -0
- package/dist/internal/apiService/coreTypes.js +7 -0
- package/dist/internal/apiService/coreTypes.js.map +1 -0
- package/dist/internal/apiService/driveTypes.d.ts +11840 -0
- package/dist/internal/apiService/driveTypes.js +7 -0
- package/dist/internal/apiService/driveTypes.js.map +1 -0
- package/dist/internal/apiService/errorCodes.d.ts +30 -0
- package/dist/internal/apiService/errorCodes.js +11 -0
- package/dist/internal/apiService/errorCodes.js.map +1 -0
- package/dist/internal/apiService/errors.d.ts +19 -0
- package/dist/internal/apiService/errors.js +76 -0
- package/dist/internal/apiService/errors.js.map +1 -0
- package/dist/internal/apiService/errors.test.d.ts +1 -0
- package/dist/internal/apiService/errors.test.js +69 -0
- package/dist/internal/apiService/errors.test.js.map +1 -0
- package/dist/internal/apiService/index.d.ts +7 -0
- package/dist/internal/apiService/index.js +30 -0
- package/dist/internal/apiService/index.js.map +1 -0
- package/dist/internal/apiService/observerStream.d.ts +3 -0
- package/dist/internal/apiService/observerStream.js +15 -0
- package/dist/internal/apiService/observerStream.js.map +1 -0
- package/dist/internal/apiService/transformers.d.ts +4 -0
- package/dist/internal/apiService/transformers.js +48 -0
- package/dist/internal/apiService/transformers.js.map +1 -0
- package/dist/internal/batchLoading.d.ts +34 -0
- package/dist/internal/batchLoading.js +68 -0
- package/dist/internal/batchLoading.js.map +1 -0
- package/dist/internal/batchLoading.test.d.ts +1 -0
- package/dist/internal/batchLoading.test.js +50 -0
- package/dist/internal/batchLoading.test.js.map +1 -0
- package/dist/internal/devices/apiService.d.ts +38 -0
- package/dist/internal/devices/apiService.js +105 -0
- package/dist/internal/devices/apiService.js.map +1 -0
- package/dist/internal/devices/cryptoService.d.ts +30 -0
- package/dist/internal/devices/cryptoService.js +47 -0
- package/dist/internal/devices/cryptoService.js.map +1 -0
- package/dist/internal/devices/index.d.ts +15 -0
- package/dist/internal/devices/index.js +22 -0
- package/dist/internal/devices/index.js.map +1 -0
- package/dist/internal/devices/interface.d.ts +31 -0
- package/dist/internal/devices/interface.js +3 -0
- package/dist/internal/devices/interface.js.map +1 -0
- package/dist/internal/devices/manager.d.ts +18 -0
- package/dist/internal/devices/manager.js +103 -0
- package/dist/internal/devices/manager.js.map +1 -0
- package/dist/internal/devices/manager.test.d.ts +1 -0
- package/dist/internal/devices/manager.test.js +100 -0
- package/dist/internal/devices/manager.test.js.map +1 -0
- package/dist/internal/download/apiService.d.ts +27 -0
- package/dist/internal/download/apiService.js +110 -0
- package/dist/internal/download/apiService.js.map +1 -0
- package/dist/internal/download/controller.d.ts +8 -0
- package/dist/internal/download/controller.js +22 -0
- package/dist/internal/download/controller.js.map +1 -0
- package/dist/internal/download/cryptoService.d.ts +17 -0
- package/dist/internal/download/cryptoService.js +82 -0
- package/dist/internal/download/cryptoService.js.map +1 -0
- package/dist/internal/download/fileDownloader.d.ts +33 -0
- package/dist/internal/download/fileDownloader.js +226 -0
- package/dist/internal/download/fileDownloader.js.map +1 -0
- package/dist/internal/download/fileDownloader.test.d.ts +1 -0
- package/dist/internal/download/fileDownloader.test.js +324 -0
- package/dist/internal/download/fileDownloader.test.js.map +1 -0
- package/dist/internal/download/index.d.ts +10 -0
- package/dist/internal/download/index.js +82 -0
- package/dist/internal/download/index.js.map +1 -0
- package/dist/internal/download/interface.d.ts +35 -0
- package/dist/internal/download/interface.js +3 -0
- package/dist/internal/download/interface.js.map +1 -0
- package/dist/internal/download/queue.d.ts +5 -0
- package/dist/internal/download/queue.js +31 -0
- package/dist/internal/download/queue.js.map +1 -0
- package/dist/internal/download/telemetry.d.ts +14 -0
- package/dist/internal/download/telemetry.js +106 -0
- package/dist/internal/download/telemetry.js.map +1 -0
- package/dist/internal/download/telemetry.test.d.ts +1 -0
- package/dist/internal/download/telemetry.test.js +111 -0
- package/dist/internal/download/telemetry.test.js.map +1 -0
- package/dist/internal/download/thumbnailDownloader.d.ts +19 -0
- package/dist/internal/download/thumbnailDownloader.js +198 -0
- package/dist/internal/download/thumbnailDownloader.js.map +1 -0
- package/dist/internal/download/thumbnailDownloader.test.d.ts +1 -0
- package/dist/internal/download/thumbnailDownloader.test.js +179 -0
- package/dist/internal/download/thumbnailDownloader.test.js.map +1 -0
- package/dist/internal/errors.d.ts +6 -0
- package/dist/internal/errors.js +28 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/internal/errors.test.d.ts +1 -0
- package/dist/internal/errors.test.js +22 -0
- package/dist/internal/errors.test.js.map +1 -0
- package/dist/internal/events/apiService.d.ts +18 -0
- package/dist/internal/events/apiService.js +81 -0
- package/dist/internal/events/apiService.js.map +1 -0
- package/dist/internal/events/cache.d.ts +28 -0
- package/dist/internal/events/cache.js +67 -0
- package/dist/internal/events/cache.js.map +1 -0
- package/dist/internal/events/cache.test.d.ts +1 -0
- package/dist/internal/events/cache.test.js +43 -0
- package/dist/internal/events/cache.test.js.map +1 -0
- package/dist/internal/events/coreEventManager.d.ts +25 -0
- package/dist/internal/events/coreEventManager.js +63 -0
- package/dist/internal/events/coreEventManager.js.map +1 -0
- package/dist/internal/events/eventManager.d.ts +62 -0
- package/dist/internal/events/eventManager.js +159 -0
- package/dist/internal/events/eventManager.js.map +1 -0
- package/dist/internal/events/eventManager.test.d.ts +1 -0
- package/dist/internal/events/eventManager.test.js +120 -0
- package/dist/internal/events/eventManager.test.js.map +1 -0
- package/dist/internal/events/index.d.ts +50 -0
- package/dist/internal/events/index.js +117 -0
- package/dist/internal/events/index.js.map +1 -0
- package/dist/internal/events/interface.d.ts +47 -0
- package/dist/internal/events/interface.js +12 -0
- package/dist/internal/events/interface.js.map +1 -0
- package/dist/internal/events/volumeEventManager.d.ts +27 -0
- package/dist/internal/events/volumeEventManager.js +69 -0
- package/dist/internal/events/volumeEventManager.js.map +1 -0
- package/dist/internal/nodes/apiService.d.ts +54 -0
- package/dist/internal/nodes/apiService.js +308 -0
- package/dist/internal/nodes/apiService.js.map +1 -0
- package/dist/internal/nodes/apiService.test.d.ts +1 -0
- package/dist/internal/nodes/apiService.test.js +344 -0
- package/dist/internal/nodes/apiService.test.js.map +1 -0
- package/dist/internal/nodes/cache.d.ts +57 -0
- package/dist/internal/nodes/cache.js +226 -0
- package/dist/internal/nodes/cache.js.map +1 -0
- package/dist/internal/nodes/cache.test.d.ts +1 -0
- package/dist/internal/nodes/cache.test.js +160 -0
- package/dist/internal/nodes/cache.test.js.map +1 -0
- package/dist/internal/nodes/cryptoCache.d.ts +16 -0
- package/dist/internal/nodes/cryptoCache.js +50 -0
- package/dist/internal/nodes/cryptoCache.js.map +1 -0
- package/dist/internal/nodes/cryptoCache.test.d.ts +1 -0
- package/dist/internal/nodes/cryptoCache.test.js +79 -0
- package/dist/internal/nodes/cryptoCache.test.js.map +1 -0
- package/dist/internal/nodes/cryptoService.d.ts +75 -0
- package/dist/internal/nodes/cryptoService.js +409 -0
- package/dist/internal/nodes/cryptoService.js.map +1 -0
- package/dist/internal/nodes/cryptoService.test.d.ts +1 -0
- package/dist/internal/nodes/cryptoService.test.js +698 -0
- package/dist/internal/nodes/cryptoService.test.js.map +1 -0
- package/dist/internal/nodes/events.d.ts +91 -0
- package/dist/internal/nodes/events.js +243 -0
- package/dist/internal/nodes/events.js.map +1 -0
- package/dist/internal/nodes/events.test.d.ts +1 -0
- package/dist/internal/nodes/events.test.js +318 -0
- package/dist/internal/nodes/events.test.js.map +1 -0
- package/dist/internal/nodes/extendedAttributes.d.ts +23 -0
- package/dist/internal/nodes/extendedAttributes.js +117 -0
- package/dist/internal/nodes/extendedAttributes.js.map +1 -0
- package/dist/internal/nodes/extendedAttributes.test.d.ts +1 -0
- package/dist/internal/nodes/extendedAttributes.test.js +176 -0
- package/dist/internal/nodes/extendedAttributes.test.js.map +1 -0
- package/dist/internal/nodes/index.d.ts +26 -0
- package/dist/internal/nodes/index.js +40 -0
- package/dist/internal/nodes/index.js.map +1 -0
- package/dist/internal/nodes/index.test.d.ts +1 -0
- package/dist/internal/nodes/index.test.js +112 -0
- package/dist/internal/nodes/index.test.js.map +1 -0
- package/dist/internal/nodes/interface.d.ts +135 -0
- package/dist/internal/nodes/interface.js +3 -0
- package/dist/internal/nodes/interface.js.map +1 -0
- package/dist/internal/nodes/mediaTypes.d.ts +2 -0
- package/dist/internal/nodes/mediaTypes.js +13 -0
- package/dist/internal/nodes/mediaTypes.js.map +1 -0
- package/dist/internal/nodes/nodesAccess.d.ts +49 -0
- package/dist/internal/nodes/nodesAccess.js +332 -0
- package/dist/internal/nodes/nodesAccess.js.map +1 -0
- package/dist/internal/nodes/nodesAccess.test.d.ts +1 -0
- package/dist/internal/nodes/nodesAccess.test.js +487 -0
- package/dist/internal/nodes/nodesAccess.test.js.map +1 -0
- package/dist/internal/nodes/nodesManagement.d.ts +33 -0
- package/dist/internal/nodes/nodesManagement.js +222 -0
- package/dist/internal/nodes/nodesManagement.js.map +1 -0
- package/dist/internal/nodes/nodesManagement.test.d.ts +1 -0
- package/dist/internal/nodes/nodesManagement.test.js +178 -0
- package/dist/internal/nodes/nodesManagement.test.js.map +1 -0
- package/dist/internal/nodes/nodesRevisions.d.ts +18 -0
- package/dist/internal/nodes/nodesRevisions.js +55 -0
- package/dist/internal/nodes/nodesRevisions.js.map +1 -0
- package/dist/internal/nodes/validations.d.ts +4 -0
- package/dist/internal/nodes/validations.js +21 -0
- package/dist/internal/nodes/validations.js.map +1 -0
- package/dist/internal/photos/albums.d.ts +13 -0
- package/dist/internal/photos/albums.js +30 -0
- package/dist/internal/photos/albums.js.map +1 -0
- package/dist/internal/photos/apiService.d.ts +8 -0
- package/dist/internal/photos/apiService.js +18 -0
- package/dist/internal/photos/apiService.js.map +1 -0
- package/dist/internal/photos/cache.d.ts +6 -0
- package/dist/internal/photos/cache.js +15 -0
- package/dist/internal/photos/cache.js.map +1 -0
- package/dist/internal/photos/index.d.ts +9 -0
- package/dist/internal/photos/index.js +18 -0
- package/dist/internal/photos/index.js.map +1 -0
- package/dist/internal/photos/interface.d.ts +6 -0
- package/dist/internal/photos/interface.js +3 -0
- package/dist/internal/photos/interface.js.map +1 -0
- package/dist/internal/photos/photosTimeline.d.ts +10 -0
- package/dist/internal/photos/photosTimeline.js +20 -0
- package/dist/internal/photos/photosTimeline.js.map +1 -0
- package/dist/internal/sdkEvents.d.ts +12 -0
- package/dist/internal/sdkEvents.js +44 -0
- package/dist/internal/sdkEvents.js.map +1 -0
- package/dist/internal/sdkEvents.test.d.ts +1 -0
- package/dist/internal/sdkEvents.test.js +45 -0
- package/dist/internal/sdkEvents.test.js.map +1 -0
- package/dist/internal/shares/apiService.d.ts +51 -0
- package/dist/internal/shares/apiService.js +128 -0
- package/dist/internal/shares/apiService.js.map +1 -0
- package/dist/internal/shares/cache.d.ts +15 -0
- package/dist/internal/shares/cache.js +63 -0
- package/dist/internal/shares/cache.js.map +1 -0
- package/dist/internal/shares/cache.test.d.ts +1 -0
- package/dist/internal/shares/cache.test.js +54 -0
- package/dist/internal/shares/cache.test.js.map +1 -0
- package/dist/internal/shares/cryptoCache.d.ts +20 -0
- package/dist/internal/shares/cryptoCache.js +35 -0
- package/dist/internal/shares/cryptoCache.js.map +1 -0
- package/dist/internal/shares/cryptoCache.test.d.ts +1 -0
- package/dist/internal/shares/cryptoCache.test.js +58 -0
- package/dist/internal/shares/cryptoCache.test.js.map +1 -0
- package/dist/internal/shares/cryptoService.d.ts +42 -0
- package/dist/internal/shares/cryptoService.js +126 -0
- package/dist/internal/shares/cryptoService.js.map +1 -0
- package/dist/internal/shares/cryptoService.test.d.ts +1 -0
- package/dist/internal/shares/cryptoService.test.js +120 -0
- package/dist/internal/shares/cryptoService.test.js.map +1 -0
- package/dist/internal/shares/index.d.ts +15 -0
- package/dist/internal/shares/index.js +26 -0
- package/dist/internal/shares/index.js.map +1 -0
- package/dist/internal/shares/interface.d.ts +94 -0
- package/dist/internal/shares/interface.js +11 -0
- package/dist/internal/shares/interface.js.map +1 -0
- package/dist/internal/shares/manager.d.ts +68 -0
- package/dist/internal/shares/manager.js +186 -0
- package/dist/internal/shares/manager.js.map +1 -0
- package/dist/internal/shares/manager.test.d.ts +1 -0
- package/dist/internal/shares/manager.test.js +176 -0
- package/dist/internal/shares/manager.test.js.map +1 -0
- package/dist/internal/sharing/apiService.d.ts +80 -0
- package/dist/internal/sharing/apiService.js +325 -0
- package/dist/internal/sharing/apiService.js.map +1 -0
- package/dist/internal/sharing/cache.d.ts +37 -0
- package/dist/internal/sharing/cache.js +105 -0
- package/dist/internal/sharing/cache.js.map +1 -0
- package/dist/internal/sharing/cache.test.d.ts +1 -0
- package/dist/internal/sharing/cache.test.js +82 -0
- package/dist/internal/sharing/cache.test.js.map +1 -0
- package/dist/internal/sharing/cryptoService.d.ts +112 -0
- package/dist/internal/sharing/cryptoService.js +269 -0
- package/dist/internal/sharing/cryptoService.js.map +1 -0
- package/dist/internal/sharing/events.d.ts +57 -0
- package/dist/internal/sharing/events.js +153 -0
- package/dist/internal/sharing/events.js.map +1 -0
- package/dist/internal/sharing/events.test.d.ts +1 -0
- package/dist/internal/sharing/events.test.js +246 -0
- package/dist/internal/sharing/events.test.js.map +1 -0
- package/dist/internal/sharing/index.d.ts +20 -0
- package/dist/internal/sharing/index.js +30 -0
- package/dist/internal/sharing/index.js.map +1 -0
- package/dist/internal/sharing/interface.d.ts +169 -0
- package/dist/internal/sharing/interface.js +9 -0
- package/dist/internal/sharing/interface.js.map +1 -0
- package/dist/internal/sharing/sharingAccess.d.ts +32 -0
- package/dist/internal/sharing/sharingAccess.js +119 -0
- package/dist/internal/sharing/sharingAccess.js.map +1 -0
- package/dist/internal/sharing/sharingAccess.test.d.ts +1 -0
- package/dist/internal/sharing/sharingAccess.test.js +84 -0
- package/dist/internal/sharing/sharingAccess.test.js.map +1 -0
- package/dist/internal/sharing/sharingManagement.d.ts +43 -0
- package/dist/internal/sharing/sharingManagement.js +439 -0
- package/dist/internal/sharing/sharingManagement.js.map +1 -0
- package/dist/internal/sharing/sharingManagement.test.d.ts +1 -0
- package/dist/internal/sharing/sharingManagement.test.js +788 -0
- package/dist/internal/sharing/sharingManagement.test.js.map +1 -0
- package/dist/internal/uids.d.ts +38 -0
- package/dist/internal/uids.js +85 -0
- package/dist/internal/uids.js.map +1 -0
- package/dist/internal/upload/apiService.d.ts +65 -0
- package/dist/internal/upload/apiService.js +137 -0
- package/dist/internal/upload/apiService.js.map +1 -0
- package/dist/internal/upload/blockVerifier.d.ts +16 -0
- package/dist/internal/upload/blockVerifier.js +33 -0
- package/dist/internal/upload/blockVerifier.js.map +1 -0
- package/dist/internal/upload/chunkStreamReader.d.ts +13 -0
- package/dist/internal/upload/chunkStreamReader.js +46 -0
- package/dist/internal/upload/chunkStreamReader.js.map +1 -0
- package/dist/internal/upload/chunkStreamReader.test.d.ts +1 -0
- package/dist/internal/upload/chunkStreamReader.test.js +75 -0
- package/dist/internal/upload/chunkStreamReader.test.js.map +1 -0
- package/dist/internal/upload/controller.d.ts +8 -0
- package/dist/internal/upload/controller.js +25 -0
- package/dist/internal/upload/controller.js.map +1 -0
- package/dist/internal/upload/cryptoService.d.ts +29 -0
- package/dist/internal/upload/cryptoService.js +104 -0
- package/dist/internal/upload/cryptoService.js.map +1 -0
- package/dist/internal/upload/digests.d.ts +8 -0
- package/dist/internal/upload/digests.js +22 -0
- package/dist/internal/upload/digests.js.map +1 -0
- package/dist/internal/upload/fileUploader.d.ts +65 -0
- package/dist/internal/upload/fileUploader.js +463 -0
- package/dist/internal/upload/fileUploader.js.map +1 -0
- package/dist/internal/upload/fileUploader.test.d.ts +1 -0
- package/dist/internal/upload/fileUploader.test.js +393 -0
- package/dist/internal/upload/fileUploader.test.js.map +1 -0
- package/dist/internal/upload/index.d.ts +16 -0
- package/dist/internal/upload/index.js +77 -0
- package/dist/internal/upload/index.js.map +1 -0
- package/dist/internal/upload/interface.d.ts +117 -0
- package/dist/internal/upload/interface.js +3 -0
- package/dist/internal/upload/interface.js.map +1 -0
- package/dist/internal/upload/manager.d.ts +31 -0
- package/dist/internal/upload/manager.js +250 -0
- package/dist/internal/upload/manager.js.map +1 -0
- package/dist/internal/upload/manager.test.d.ts +1 -0
- package/dist/internal/upload/manager.test.js +349 -0
- package/dist/internal/upload/manager.test.js.map +1 -0
- package/dist/internal/upload/queue.d.ts +5 -0
- package/dist/internal/upload/queue.js +32 -0
- package/dist/internal/upload/queue.js.map +1 -0
- package/dist/internal/upload/telemetry.d.ts +15 -0
- package/dist/internal/upload/telemetry.js +111 -0
- package/dist/internal/upload/telemetry.js.map +1 -0
- package/dist/internal/upload/telemetry.test.d.ts +1 -0
- package/dist/internal/upload/telemetry.test.js +107 -0
- package/dist/internal/upload/telemetry.test.js.map +1 -0
- package/dist/internal/utils.d.ts +1 -0
- package/dist/internal/utils.js +13 -0
- package/dist/internal/utils.js.map +1 -0
- package/dist/internal/wait.d.ts +3 -0
- package/dist/internal/wait.js +28 -0
- package/dist/internal/wait.js.map +1 -0
- package/dist/internal/wait.test.d.ts +1 -0
- package/dist/internal/wait.test.js +21 -0
- package/dist/internal/wait.test.js.map +1 -0
- package/dist/protonDriveClient.d.ts +593 -0
- package/dist/protonDriveClient.js +768 -0
- package/dist/protonDriveClient.js.map +1 -0
- package/dist/protonDrivePhotosClient.d.ts +16 -0
- package/dist/protonDrivePhotosClient.js +46 -0
- package/dist/protonDrivePhotosClient.js.map +1 -0
- package/dist/telemetry.d.ts +187 -0
- package/dist/telemetry.js +297 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tests/logger.d.ts +2 -0
- package/dist/tests/logger.js +12 -0
- package/dist/tests/logger.js.map +1 -0
- package/dist/tests/telemetry.d.ts +2 -0
- package/dist/tests/telemetry.js +11 -0
- package/dist/tests/telemetry.js.map +1 -0
- package/dist/transformers.d.ts +17 -0
- package/dist/transformers.js +77 -0
- package/dist/transformers.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/package.json +49 -0
- package/src/cache/index.ts +2 -0
- package/src/cache/interface.ts +104 -0
- package/src/cache/memoryCache.test.ts +150 -0
- package/src/cache/memoryCache.ts +85 -0
- package/src/config.ts +9 -0
- package/src/crypto/driveCrypto.test.ts +45 -0
- package/src/crypto/driveCrypto.ts +696 -0
- package/src/crypto/hmac.ts +46 -0
- package/src/crypto/index.ts +6 -0
- package/src/crypto/interface.ts +230 -0
- package/src/crypto/openPGPCrypto.ts +398 -0
- package/src/crypto/utils.ts +40 -0
- package/src/errors.ts +168 -0
- package/src/index.ts +30 -0
- package/src/interface/account.ts +38 -0
- package/src/interface/author.ts +29 -0
- package/src/interface/devices.ts +21 -0
- package/src/interface/download.ts +32 -0
- package/src/interface/events.ts +30 -0
- package/src/interface/httpClient.ts +42 -0
- package/src/interface/index.ts +46 -0
- package/src/interface/nodes.ts +168 -0
- package/src/interface/result.ts +11 -0
- package/src/interface/sharing.ts +87 -0
- package/src/interface/telemetry.ts +107 -0
- package/src/interface/thumbnail.ts +14 -0
- package/src/interface/upload.ts +19 -0
- package/src/internal/apiService/apiService.test.ts +285 -0
- package/src/internal/apiService/apiService.ts +353 -0
- package/src/internal/apiService/coreTypes.ts +24439 -0
- package/src/internal/apiService/driveTypes.ts +11841 -0
- package/src/internal/apiService/errorCodes.ts +38 -0
- package/src/internal/apiService/errors.test.ts +63 -0
- package/src/internal/apiService/errors.ts +91 -0
- package/src/internal/apiService/index.ts +7 -0
- package/src/internal/apiService/observerStream.ts +10 -0
- package/src/internal/apiService/transformers.ts +45 -0
- package/src/internal/batchLoading.test.ts +58 -0
- package/src/internal/batchLoading.ts +74 -0
- package/src/internal/devices/apiService.ts +142 -0
- package/src/internal/devices/cryptoService.ts +65 -0
- package/src/internal/devices/index.ts +31 -0
- package/src/internal/devices/interface.ts +28 -0
- package/src/internal/devices/manager.test.ts +129 -0
- package/src/internal/devices/manager.ts +113 -0
- package/src/internal/download/apiService.ts +145 -0
- package/src/internal/download/controller.ts +22 -0
- package/src/internal/download/cryptoService.ts +96 -0
- package/src/internal/download/fileDownloader.test.ts +381 -0
- package/src/internal/download/fileDownloader.ts +266 -0
- package/src/internal/download/index.ts +122 -0
- package/src/internal/download/interface.ts +38 -0
- package/src/internal/download/queue.ts +30 -0
- package/src/internal/download/telemetry.test.ts +134 -0
- package/src/internal/download/telemetry.ts +115 -0
- package/src/internal/download/thumbnailDownloader.test.ts +226 -0
- package/src/internal/download/thumbnailDownloader.ts +250 -0
- package/src/internal/errors.test.ts +21 -0
- package/src/internal/errors.ts +28 -0
- package/src/internal/events/apiService.ts +87 -0
- package/src/internal/events/cache.test.ts +47 -0
- package/src/internal/events/cache.ts +80 -0
- package/src/internal/events/coreEventManager.ts +69 -0
- package/src/internal/events/eventManager.test.ts +139 -0
- package/src/internal/events/eventManager.ts +168 -0
- package/src/internal/events/index.ts +131 -0
- package/src/internal/events/interface.ts +51 -0
- package/src/internal/events/volumeEventManager.ts +74 -0
- package/src/internal/nodes/apiService.test.ts +394 -0
- package/src/internal/nodes/apiService.ts +455 -0
- package/src/internal/nodes/cache.test.ts +197 -0
- package/src/internal/nodes/cache.ts +240 -0
- package/src/internal/nodes/cryptoCache.test.ts +92 -0
- package/src/internal/nodes/cryptoCache.ts +47 -0
- package/src/internal/nodes/cryptoService.test.ts +814 -0
- package/src/internal/nodes/cryptoService.ts +550 -0
- package/src/internal/nodes/events.test.ts +383 -0
- package/src/internal/nodes/events.ts +271 -0
- package/src/internal/nodes/extendedAttributes.test.ts +177 -0
- package/src/internal/nodes/extendedAttributes.ts +180 -0
- package/src/internal/nodes/index.test.ts +135 -0
- package/src/internal/nodes/index.ts +52 -0
- package/src/internal/nodes/interface.ts +152 -0
- package/src/internal/nodes/mediaTypes.ts +10 -0
- package/src/internal/nodes/nodesAccess.test.ts +555 -0
- package/src/internal/nodes/nodesAccess.ts +360 -0
- package/src/internal/nodes/nodesManagement.test.ts +221 -0
- package/src/internal/nodes/nodesManagement.ts +272 -0
- package/src/internal/nodes/nodesRevisions.ts +58 -0
- package/src/internal/nodes/validations.ts +26 -0
- package/src/internal/photos/albums.ts +29 -0
- package/src/internal/photos/apiService.ts +16 -0
- package/src/internal/photos/cache.ts +11 -0
- package/src/internal/photos/index.ts +23 -0
- package/src/internal/photos/interface.ts +7 -0
- package/src/internal/photos/photosTimeline.ts +18 -0
- package/src/internal/sdkEvents.test.ts +55 -0
- package/src/internal/sdkEvents.ts +52 -0
- package/src/internal/shares/apiService.ts +176 -0
- package/src/internal/shares/cache.test.ts +58 -0
- package/src/internal/shares/cache.ts +64 -0
- package/src/internal/shares/cryptoCache.test.ts +70 -0
- package/src/internal/shares/cryptoCache.ts +35 -0
- package/src/internal/shares/cryptoService.test.ts +137 -0
- package/src/internal/shares/cryptoService.ts +143 -0
- package/src/internal/shares/index.ts +35 -0
- package/src/internal/shares/interface.ts +104 -0
- package/src/internal/shares/manager.test.ts +210 -0
- package/src/internal/shares/manager.ts +213 -0
- package/src/internal/sharing/apiService.ts +483 -0
- package/src/internal/sharing/cache.test.ts +99 -0
- package/src/internal/sharing/cache.ts +109 -0
- package/src/internal/sharing/cryptoService.ts +378 -0
- package/src/internal/sharing/events.test.ts +268 -0
- package/src/internal/sharing/events.ts +166 -0
- package/src/internal/sharing/index.ts +43 -0
- package/src/internal/sharing/interface.ts +177 -0
- package/src/internal/sharing/sharingAccess.test.ts +102 -0
- package/src/internal/sharing/sharingAccess.ts +133 -0
- package/src/internal/sharing/sharingManagement.test.ts +895 -0
- package/src/internal/sharing/sharingManagement.ts +521 -0
- package/src/internal/uids.ts +83 -0
- package/src/internal/upload/apiService.ts +243 -0
- package/src/internal/upload/blockVerifier.ts +40 -0
- package/src/internal/upload/chunkStreamReader.test.ts +89 -0
- package/src/internal/upload/chunkStreamReader.ts +49 -0
- package/src/internal/upload/controller.ts +25 -0
- package/src/internal/upload/cryptoService.ts +162 -0
- package/src/internal/upload/digests.ts +18 -0
- package/src/internal/upload/fileUploader.test.ts +513 -0
- package/src/internal/upload/fileUploader.ts +576 -0
- package/src/internal/upload/index.ts +126 -0
- package/src/internal/upload/interface.ts +128 -0
- package/src/internal/upload/manager.test.ts +390 -0
- package/src/internal/upload/manager.ts +320 -0
- package/src/internal/upload/queue.ts +31 -0
- package/src/internal/upload/telemetry.test.ts +129 -0
- package/src/internal/upload/telemetry.ts +121 -0
- package/src/internal/utils.ts +9 -0
- package/src/internal/wait.test.ts +21 -0
- package/src/internal/wait.ts +26 -0
- package/src/protonDriveClient.ts +861 -0
- package/src/protonDrivePhotosClient.ts +56 -0
- package/src/telemetry.ts +346 -0
- package/src/tests/logger.ts +10 -0
- package/src/tests/telemetry.ts +9 -0
- package/src/transformers.ts +98 -0
- package/src/version.ts +4 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { c } from 'ttag';
|
|
2
|
+
|
|
3
|
+
import { DriveCrypto } from "../../crypto";
|
|
4
|
+
import { ValidationError } from "../../errors";
|
|
5
|
+
import { ProtonDriveAccount, ProtonDriveTelemetry, NodeType, ThumbnailType, ThumbnailResult } from "../../interface";
|
|
6
|
+
import { DriveAPIService } from "../apiService";
|
|
7
|
+
import { DownloadAPIService } from "./apiService";
|
|
8
|
+
import { DownloadCryptoService } from "./cryptoService";
|
|
9
|
+
import { NodesService, RevisionsService, SharesService } from "./interface";
|
|
10
|
+
import { FileDownloader } from "./fileDownloader";
|
|
11
|
+
import { DownloadQueue } from "./queue";
|
|
12
|
+
import { DownloadTelemetry } from "./telemetry";
|
|
13
|
+
import { makeNodeUidFromRevisionUid } from "../uids";
|
|
14
|
+
import { ThumbnailDownloader } from './thumbnailDownloader';
|
|
15
|
+
|
|
16
|
+
export function initDownloadModule(
|
|
17
|
+
telemetry: ProtonDriveTelemetry,
|
|
18
|
+
apiService: DriveAPIService,
|
|
19
|
+
driveCrypto: DriveCrypto,
|
|
20
|
+
account: ProtonDriveAccount,
|
|
21
|
+
sharesService: SharesService,
|
|
22
|
+
nodesService: NodesService,
|
|
23
|
+
revisionsService: RevisionsService,
|
|
24
|
+
) {
|
|
25
|
+
const queue = new DownloadQueue();
|
|
26
|
+
const api = new DownloadAPIService(apiService);
|
|
27
|
+
const cryptoService = new DownloadCryptoService(driveCrypto, account);
|
|
28
|
+
const downloadTelemetry = new DownloadTelemetry(telemetry, sharesService);
|
|
29
|
+
|
|
30
|
+
async function getFileDownloader(nodeUid: string, signal?: AbortSignal): Promise<FileDownloader> {
|
|
31
|
+
await queue.waitForCapacity(signal);
|
|
32
|
+
|
|
33
|
+
let node, nodeKey;
|
|
34
|
+
try {
|
|
35
|
+
node = await nodesService.getNode(nodeUid);
|
|
36
|
+
nodeKey = await nodesService.getNodeKeys(nodeUid);
|
|
37
|
+
|
|
38
|
+
if (node.type === NodeType.Folder) {
|
|
39
|
+
throw new ValidationError(c("Error").t`Cannot download a folder`);
|
|
40
|
+
}
|
|
41
|
+
if (!nodeKey.contentKeyPacketSessionKey) {
|
|
42
|
+
throw new ValidationError(c("Error").t`File has no content key`);
|
|
43
|
+
}
|
|
44
|
+
if (!node.activeRevision?.ok || !node.activeRevision.value) {
|
|
45
|
+
throw new ValidationError(c("Error").t`File has no active revision`);
|
|
46
|
+
}
|
|
47
|
+
} catch (error: unknown) {
|
|
48
|
+
queue.releaseCapacity();
|
|
49
|
+
void downloadTelemetry.downloadInitFailed(nodeUid, error);
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const onFinish = () => queue.releaseCapacity();
|
|
54
|
+
|
|
55
|
+
return new FileDownloader(
|
|
56
|
+
downloadTelemetry,
|
|
57
|
+
api,
|
|
58
|
+
cryptoService,
|
|
59
|
+
{
|
|
60
|
+
key: nodeKey.key,
|
|
61
|
+
contentKeyPacketSessionKey: nodeKey.contentKeyPacketSessionKey,
|
|
62
|
+
},
|
|
63
|
+
node.activeRevision.value,
|
|
64
|
+
signal,
|
|
65
|
+
onFinish,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getFileRevisionDownloader(nodeRevisionUid: string, signal?: AbortSignal): Promise<FileDownloader> {
|
|
70
|
+
await queue.waitForCapacity(signal);
|
|
71
|
+
|
|
72
|
+
const nodeUid = makeNodeUidFromRevisionUid(nodeRevisionUid);
|
|
73
|
+
|
|
74
|
+
let node, nodeKey, revision;
|
|
75
|
+
try {
|
|
76
|
+
node = await nodesService.getNode(nodeUid);
|
|
77
|
+
nodeKey = await nodesService.getNodeKeys(nodeUid);
|
|
78
|
+
revision = await revisionsService.getRevision(nodeRevisionUid);
|
|
79
|
+
|
|
80
|
+
if (node.type === NodeType.Folder) {
|
|
81
|
+
throw new ValidationError(c("Error").t`Cannot download a folder`);
|
|
82
|
+
}
|
|
83
|
+
if (!nodeKey.contentKeyPacketSessionKey) {
|
|
84
|
+
throw new ValidationError(c("Error").t`File has no content key`);
|
|
85
|
+
}
|
|
86
|
+
} catch (error: unknown) {
|
|
87
|
+
queue.releaseCapacity();
|
|
88
|
+
void downloadTelemetry.downloadInitFailed(nodeUid, error);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const onFinish = () => queue.releaseCapacity();
|
|
93
|
+
|
|
94
|
+
return new FileDownloader(
|
|
95
|
+
downloadTelemetry,
|
|
96
|
+
api,
|
|
97
|
+
cryptoService,
|
|
98
|
+
{
|
|
99
|
+
key: nodeKey.key,
|
|
100
|
+
contentKeyPacketSessionKey: nodeKey.contentKeyPacketSessionKey,
|
|
101
|
+
},
|
|
102
|
+
revision,
|
|
103
|
+
signal,
|
|
104
|
+
onFinish,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function *iterateThumbnails(
|
|
109
|
+
nodeUids: string[],
|
|
110
|
+
thumbnailType?: ThumbnailType,
|
|
111
|
+
signal?: AbortSignal,
|
|
112
|
+
): AsyncGenerator<ThumbnailResult> {
|
|
113
|
+
const thumbnailDownloader = new ThumbnailDownloader(telemetry, nodesService, api, cryptoService);
|
|
114
|
+
yield* thumbnailDownloader.iterateThumbnails(nodeUids, thumbnailType, signal);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
getFileDownloader,
|
|
119
|
+
getFileRevisionDownloader,
|
|
120
|
+
iterateThumbnails,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PrivateKey, PublicKey, SessionKey } from "../../crypto";
|
|
2
|
+
import { NodeType, Result, Revision, MissingNode, MetricContext } from "../../interface";
|
|
3
|
+
import { DecryptedNode } from "../nodes";
|
|
4
|
+
|
|
5
|
+
export type BlockMetadata = {
|
|
6
|
+
index: number,
|
|
7
|
+
bareUrl: string,
|
|
8
|
+
token: string,
|
|
9
|
+
base64sha256Hash: string,
|
|
10
|
+
signatureEmail?: string,
|
|
11
|
+
armoredSignature?: string,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type RevisionKeys = {
|
|
15
|
+
key: PrivateKey,
|
|
16
|
+
contentKeyPacketSessionKey: SessionKey,
|
|
17
|
+
verificationKeys?: PublicKey[],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SharesService {
|
|
21
|
+
getVolumeMetricContext(volumeId: string): Promise<MetricContext>,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface NodesService {
|
|
25
|
+
getNode(nodeUid: string): Promise<NodesServiceNode>,
|
|
26
|
+
getNodeKeys(nodeUid: string): Promise<{ key: PrivateKey, contentKeyPacketSessionKey?: SessionKey; }>,
|
|
27
|
+
iterateNodes(nodeUids: string[], signal?: AbortSignal): AsyncGenerator<DecryptedNode | MissingNode>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface NodesServiceNode {
|
|
31
|
+
uid: string,
|
|
32
|
+
type: NodeType,
|
|
33
|
+
activeRevision?: Result<Revision, Error>,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface RevisionsService {
|
|
37
|
+
getRevision(nodeRevisionUid: string): Promise<Revision>,
|
|
38
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { waitForCondition } from '../wait';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A queue that limits the number of concurrent downloads.
|
|
5
|
+
*
|
|
6
|
+
* This is used to limit the number of concurrent downloads to avoid
|
|
7
|
+
* overloading the server, or get rate limited.
|
|
8
|
+
*
|
|
9
|
+
* Each file download consumes memory and is limited by the number of
|
|
10
|
+
* concurrent block downloads for each file.
|
|
11
|
+
*
|
|
12
|
+
* This queue is straitforward and does not have any priority mechanism
|
|
13
|
+
* or other features, such as limiting total number of blocks being
|
|
14
|
+
* downloaded. That is something we want to add in the future to be
|
|
15
|
+
* more performant for many small file downloads.
|
|
16
|
+
*/
|
|
17
|
+
const MAX_CONCURRENT_DOWNLOADS = 5;
|
|
18
|
+
|
|
19
|
+
export class DownloadQueue {
|
|
20
|
+
private capacity = 0;
|
|
21
|
+
|
|
22
|
+
async waitForCapacity(signal?: AbortSignal) {
|
|
23
|
+
await waitForCondition(() => this.capacity < MAX_CONCURRENT_DOWNLOADS, signal);
|
|
24
|
+
this.capacity++;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
releaseCapacity() {
|
|
28
|
+
this.capacity--;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { RateLimitedError, ValidationError, DecryptionError, IntegrityError } from '../../errors';
|
|
2
|
+
import { ProtonDriveTelemetry } from '../../interface';
|
|
3
|
+
import { APIHTTPError } from '../apiService';
|
|
4
|
+
import { SharesService } from './interface';
|
|
5
|
+
import { DownloadTelemetry } from './telemetry';
|
|
6
|
+
|
|
7
|
+
describe('DownloadTelemetry', () => {
|
|
8
|
+
let mockTelemetry: jest.Mocked<ProtonDriveTelemetry>;
|
|
9
|
+
let sharesService: jest.Mocked<SharesService>;
|
|
10
|
+
let downloadTelemetry: DownloadTelemetry;
|
|
11
|
+
|
|
12
|
+
const nodeUid = 'volumeId~nodeId';
|
|
13
|
+
const revisionUid = 'volumeId~nodeId~revisionId';
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
mockTelemetry = {
|
|
17
|
+
logEvent: jest.fn(),
|
|
18
|
+
getLogger: jest.fn().mockReturnValue({
|
|
19
|
+
info: jest.fn(),
|
|
20
|
+
warn: jest.fn(),
|
|
21
|
+
error: jest.fn(),
|
|
22
|
+
debug: jest.fn(),
|
|
23
|
+
}),
|
|
24
|
+
} as unknown as jest.Mocked<ProtonDriveTelemetry>;
|
|
25
|
+
|
|
26
|
+
sharesService = {
|
|
27
|
+
getVolumeMetricContext: jest.fn().mockResolvedValue('own_volume'),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
downloadTelemetry = new DownloadTelemetry(mockTelemetry, sharesService);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should log failure during init (excludes file size)', async () => {
|
|
34
|
+
await downloadTelemetry.downloadInitFailed(nodeUid, new Error('Failed'));
|
|
35
|
+
|
|
36
|
+
expect(mockTelemetry.logEvent).toHaveBeenCalledWith({
|
|
37
|
+
eventName: "download",
|
|
38
|
+
context: "own_volume",
|
|
39
|
+
downloadedSize: 0,
|
|
40
|
+
error: "unknown",
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should log failure download', async () => {
|
|
45
|
+
await downloadTelemetry.downloadFailed(revisionUid, new Error('Failed'), 123, 456);
|
|
46
|
+
|
|
47
|
+
expect(mockTelemetry.logEvent).toHaveBeenCalledWith({
|
|
48
|
+
eventName: "download",
|
|
49
|
+
context: "own_volume",
|
|
50
|
+
downloadedSize: 123,
|
|
51
|
+
claimedFileSize: 456,
|
|
52
|
+
error: "unknown",
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should log successful download (excludes error)', async () => {
|
|
57
|
+
await downloadTelemetry.downloadFinished(revisionUid, 500);
|
|
58
|
+
|
|
59
|
+
expect(mockTelemetry.logEvent).toHaveBeenCalledWith({
|
|
60
|
+
eventName: "download",
|
|
61
|
+
context: "own_volume",
|
|
62
|
+
downloadedSize: 500,
|
|
63
|
+
claimedFileSize: 500,
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('detect error category', () => {
|
|
68
|
+
const verifyErrorCategory = (error: string) => {
|
|
69
|
+
expect(mockTelemetry.logEvent).toHaveBeenCalledWith(
|
|
70
|
+
expect.objectContaining({
|
|
71
|
+
error,
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
it('should ignore ValidationError', async () => {
|
|
77
|
+
const error = new ValidationError('Validation error');
|
|
78
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
79
|
+
expect(mockTelemetry.logEvent).not.toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should ignore AbortError', async () => {
|
|
83
|
+
const error = new Error('Aborted');
|
|
84
|
+
error.name = 'AbortError';
|
|
85
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
86
|
+
|
|
87
|
+
expect(mockTelemetry.logEvent).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should detect "rate_limited" error for RateLimitedError', async () => {
|
|
91
|
+
const error = new RateLimitedError('Rate limited');
|
|
92
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
93
|
+
verifyErrorCategory('rate_limited');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should detect "decryption_error" for DecryptionError', async () => {
|
|
97
|
+
const error = new DecryptionError('Decryption failed');
|
|
98
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
99
|
+
verifyErrorCategory('decryption_error');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should detect "integrity_error" for IntegrityError', async () => {
|
|
103
|
+
const error = new IntegrityError('Integrity check failed');
|
|
104
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
105
|
+
verifyErrorCategory('integrity_error');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should detect "4xx" error for APIHTTPError with 4xx status code', async () => {
|
|
109
|
+
const error = new APIHTTPError('Client error', 404);
|
|
110
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
111
|
+
verifyErrorCategory('4xx');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should detect "5xx" error for APIHTTPError with 5xx status code', async () => {
|
|
115
|
+
const error = new APIHTTPError('Server error', 500);
|
|
116
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
117
|
+
verifyErrorCategory('5xx');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should detect "server_error" for TimeoutError', async () => {
|
|
121
|
+
const error = new Error('Timeout');
|
|
122
|
+
error.name = 'TimeoutError';
|
|
123
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
124
|
+
verifyErrorCategory('server_error');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should detect "network_error" for NetworkError', async () => {
|
|
128
|
+
const error = new Error('Network error');
|
|
129
|
+
error.name = 'NetworkError';
|
|
130
|
+
await downloadTelemetry.downloadFailed(revisionUid, error, 100, 200);
|
|
131
|
+
verifyErrorCategory('network_error');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { RateLimitedError, ValidationError, DecryptionError, IntegrityError } from "../../errors";
|
|
2
|
+
import { ProtonDriveTelemetry, MetricsDownloadErrorType, Logger } from "../../interface";
|
|
3
|
+
import { LoggerWithPrefix } from "../../telemetry";
|
|
4
|
+
import { APIHTTPError } from '../apiService';
|
|
5
|
+
import { splitNodeRevisionUid, splitNodeUid } from "../uids";
|
|
6
|
+
import { SharesService } from "./interface";
|
|
7
|
+
|
|
8
|
+
export class DownloadTelemetry {
|
|
9
|
+
private logger: Logger;
|
|
10
|
+
|
|
11
|
+
constructor(private telemetry: ProtonDriveTelemetry, private sharesService: SharesService) {
|
|
12
|
+
this.telemetry = telemetry;
|
|
13
|
+
this.logger = this.telemetry.getLogger("download");
|
|
14
|
+
this.sharesService = sharesService;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getLoggerForRevision(revisionUid: string) {
|
|
18
|
+
return new LoggerWithPrefix(this.logger, `revision ${revisionUid}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async downloadInitFailed(nodeUid: string, error: unknown) {
|
|
22
|
+
const { volumeId } = splitNodeUid(nodeUid);
|
|
23
|
+
const errorCategory = getErrorCategory(error);
|
|
24
|
+
|
|
25
|
+
// No error category means ignored error from telemetry.
|
|
26
|
+
// For example, aborted request.
|
|
27
|
+
if (!errorCategory) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await this.sendTelemetry(volumeId, {
|
|
32
|
+
downloadedSize: 0,
|
|
33
|
+
error: errorCategory,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async downloadFailed(revisionUid: string, error: unknown, downloadedSize: number, claimedFileSize?: number) {
|
|
38
|
+
const { volumeId } = splitNodeRevisionUid(revisionUid);
|
|
39
|
+
const errorCategory = getErrorCategory(error);
|
|
40
|
+
|
|
41
|
+
// No error category means ignored error from telemetry.
|
|
42
|
+
// For example, aborted request.
|
|
43
|
+
if (!errorCategory) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await this.sendTelemetry(volumeId, {
|
|
48
|
+
downloadedSize,
|
|
49
|
+
claimedFileSize,
|
|
50
|
+
error: errorCategory,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async downloadFinished(revisionUid: string, downloadedSize: number) {
|
|
55
|
+
const { volumeId } = splitNodeRevisionUid(revisionUid);
|
|
56
|
+
await this.sendTelemetry(volumeId, {
|
|
57
|
+
downloadedSize,
|
|
58
|
+
claimedFileSize: downloadedSize,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private async sendTelemetry(volumeId: string, options: {
|
|
63
|
+
downloadedSize: number,
|
|
64
|
+
claimedFileSize?: number,
|
|
65
|
+
error?: MetricsDownloadErrorType,
|
|
66
|
+
}) {
|
|
67
|
+
let context;
|
|
68
|
+
try {
|
|
69
|
+
context = await this.sharesService.getVolumeMetricContext(volumeId);
|
|
70
|
+
} catch (error: unknown) {
|
|
71
|
+
this.logger.error('Failed to get metric context', error);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.telemetry.logEvent({
|
|
75
|
+
eventName: 'download',
|
|
76
|
+
context,
|
|
77
|
+
...options,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getErrorCategory(error: unknown): MetricsDownloadErrorType | undefined {
|
|
83
|
+
if (error instanceof ValidationError) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
if (error instanceof RateLimitedError) {
|
|
87
|
+
return 'rate_limited';
|
|
88
|
+
}
|
|
89
|
+
if (error instanceof DecryptionError) {
|
|
90
|
+
return 'decryption_error';
|
|
91
|
+
}
|
|
92
|
+
if (error instanceof IntegrityError) {
|
|
93
|
+
return 'integrity_error';
|
|
94
|
+
}
|
|
95
|
+
if (error instanceof APIHTTPError) {
|
|
96
|
+
if (error.statusCode >= 400 && error.statusCode < 500) {
|
|
97
|
+
return '4xx';
|
|
98
|
+
}
|
|
99
|
+
if (error.statusCode >= 500) {
|
|
100
|
+
return '5xx';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (error instanceof Error) {
|
|
104
|
+
if (error.name === 'TimeoutError') {
|
|
105
|
+
return 'server_error';
|
|
106
|
+
}
|
|
107
|
+
if (error.name === 'OfflineError' || error.name === 'NetworkError' || error.message?.toLowerCase() === 'network error') {
|
|
108
|
+
return 'network_error';
|
|
109
|
+
}
|
|
110
|
+
if (error.name === 'AbortError') {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return 'unknown';
|
|
115
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { ProtonDriveTelemetry } from '../../interface';
|
|
2
|
+
import { getMockTelemetry } from "../../tests/telemetry";
|
|
3
|
+
import { ThumbnailDownloader } from './thumbnailDownloader';
|
|
4
|
+
import { DownloadAPIService } from './apiService';
|
|
5
|
+
import { DownloadCryptoService } from './cryptoService';
|
|
6
|
+
import { NodesService } from './interface';
|
|
7
|
+
|
|
8
|
+
describe('ThumbnailDownloader', () => {
|
|
9
|
+
let telemetry: ProtonDriveTelemetry;
|
|
10
|
+
let nodesService: NodesService;
|
|
11
|
+
let apiService: DownloadAPIService;
|
|
12
|
+
let cryptoService: DownloadCryptoService;
|
|
13
|
+
let downloader: ThumbnailDownloader;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
telemetry = getMockTelemetry();
|
|
17
|
+
|
|
18
|
+
// @ts-expect-error No need to implement all methods for mocking
|
|
19
|
+
nodesService = {
|
|
20
|
+
iterateNodes: jest.fn().mockImplementation(async function* (nodeUids: string[]) {
|
|
21
|
+
for (const nodeUid of nodeUids) {
|
|
22
|
+
yield {
|
|
23
|
+
uid: nodeUid,
|
|
24
|
+
type: 'file',
|
|
25
|
+
activeRevision: {
|
|
26
|
+
ok: true,
|
|
27
|
+
value: {
|
|
28
|
+
thumbnails: [{ type: 1, uid: `thumb-${nodeUid}` }],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}),
|
|
34
|
+
getNodeKeys: jest.fn().mockReturnValue({
|
|
35
|
+
contentKeyPacketSessionKey: 'contentKeyPacketSessionKey',
|
|
36
|
+
}),
|
|
37
|
+
} as NodesService;
|
|
38
|
+
|
|
39
|
+
// @ts-expect-error No need to implement all methods for mocking
|
|
40
|
+
apiService = {
|
|
41
|
+
iterateThumbnails: jest.fn().mockImplementation(async function* (thumbnailUids: string[]) {
|
|
42
|
+
for (const thumbnailUid of thumbnailUids) {
|
|
43
|
+
yield {
|
|
44
|
+
uid: thumbnailUid,
|
|
45
|
+
ok: true,
|
|
46
|
+
bareUrl: `url-${thumbnailUid}`,
|
|
47
|
+
token: `token-${thumbnailUid}`,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}),
|
|
51
|
+
downloadBlock: jest.fn().mockResolvedValue(new Uint8Array([1, 2, 3])),
|
|
52
|
+
} as DownloadAPIService;
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error No need to implement all methods for mocking
|
|
55
|
+
cryptoService = {
|
|
56
|
+
decryptThumbnail: jest.fn().mockImplementation(async (thumbnail: Uint8Array) => thumbnail),
|
|
57
|
+
} as DownloadCryptoService;
|
|
58
|
+
|
|
59
|
+
downloader = new ThumbnailDownloader(telemetry, nodesService, apiService, cryptoService);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should handle all success cases', async () => {
|
|
63
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1', 'node2', 'node3']));
|
|
64
|
+
|
|
65
|
+
expect(results).toEqual([
|
|
66
|
+
{ nodeUid: 'node1', ok: true, thumbnail: new Uint8Array([1, 2, 3]) },
|
|
67
|
+
{ nodeUid: 'node2', ok: true, thumbnail: new Uint8Array([1, 2, 3]) },
|
|
68
|
+
{ nodeUid: 'node3', ok: true, thumbnail: new Uint8Array([1, 2, 3]) },
|
|
69
|
+
]);
|
|
70
|
+
expect(nodesService.iterateNodes).toHaveBeenCalledWith(['node1', 'node2', 'node3'], undefined);
|
|
71
|
+
expect(apiService.iterateThumbnails).toHaveBeenCalledWith(['thumb-node1', 'thumb-node2', 'thumb-node3'], undefined);
|
|
72
|
+
expect(nodesService.getNodeKeys).toHaveBeenCalledTimes(3);
|
|
73
|
+
expect(apiService.downloadBlock).toHaveBeenCalledTimes(3);
|
|
74
|
+
expect(cryptoService.decryptThumbnail).toHaveBeenCalledTimes(3);
|
|
75
|
+
expect(cryptoService.decryptThumbnail).toHaveBeenCalledWith(new Uint8Array([1, 2, 3]), 'contentKeyPacketSessionKey');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should handle no requested node', async () => {
|
|
79
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails([]));
|
|
80
|
+
|
|
81
|
+
expect(results).toEqual([]);
|
|
82
|
+
expect(nodesService.iterateNodes).not.toHaveBeenCalled();
|
|
83
|
+
expect(apiService.iterateThumbnails).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should handle failure when requesting nodes', async () => {
|
|
87
|
+
nodesService.iterateNodes = jest.fn().mockImplementation(() => {
|
|
88
|
+
throw new Error('Failed to fetch nodes');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const results = Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
92
|
+
await expect(results).rejects.toThrow('Failed to fetch nodes');
|
|
93
|
+
expect(apiService.iterateThumbnails).not.toHaveBeenCalled();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should handle missing node', async () => {
|
|
97
|
+
nodesService.iterateNodes = jest.fn().mockImplementation(async function* () {
|
|
98
|
+
yield { missingUid: 'node1' };
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
102
|
+
|
|
103
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Node not found' }]);
|
|
104
|
+
expect(apiService.iterateThumbnails).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should handle node that is not a file', async () => {
|
|
108
|
+
nodesService.iterateNodes = jest.fn().mockImplementation(async function* () {
|
|
109
|
+
yield { uid: 'node1', type: 'folder' };
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
113
|
+
|
|
114
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Node is not a file' }]);
|
|
115
|
+
expect(apiService.iterateThumbnails).not.toHaveBeenCalled();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
it('should handle node without requested thumbnail', async () => {
|
|
120
|
+
nodesService.iterateNodes = jest.fn().mockImplementation(async function* () {
|
|
121
|
+
yield { uid: 'node1', type: 'file', activeRevision: { ok: true, value: { thumbnails: [] } } };
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
125
|
+
|
|
126
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Node has no thumbnail' }]);
|
|
127
|
+
expect(apiService.iterateThumbnails).not.toHaveBeenCalled();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should handle API failure to provide token for thumbnail', async () => {
|
|
131
|
+
apiService.iterateThumbnails = jest.fn().mockImplementation(async function* () {
|
|
132
|
+
yield { uid: 'thumb-node1', ok: false, error: 'Failed to fetch token' };
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
136
|
+
|
|
137
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Failed to fetch token' }]);
|
|
138
|
+
expect(apiService.downloadBlock).not.toHaveBeenCalled();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should handle API providing unexpected thumbnail', async () => {
|
|
142
|
+
apiService.iterateThumbnails = jest.fn().mockImplementation(async function* () {
|
|
143
|
+
yield { uid: 'thumb-unexpected', ok: true, thumbnail: new Uint8Array([1, 2, 3]) };
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
147
|
+
|
|
148
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Thumbnail not found' }]);
|
|
149
|
+
expect(apiService.downloadBlock).not.toHaveBeenCalled();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should handle failure when downloading block', async () => {
|
|
153
|
+
apiService.downloadBlock = jest.fn().mockRejectedValue(new Error('Failed to download thumbnail'));
|
|
154
|
+
|
|
155
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
156
|
+
|
|
157
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Failed to download thumbnail' }]);
|
|
158
|
+
expect(apiService.downloadBlock).toHaveBeenCalledTimes(3);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should handle one-off failure when downloading block', async () => {
|
|
162
|
+
let callCount = 0;
|
|
163
|
+
apiService.downloadBlock = jest.fn().mockImplementation(() => {
|
|
164
|
+
callCount++;
|
|
165
|
+
if (callCount === 1) {
|
|
166
|
+
return Promise.reject(new Error('Failed to download block'));
|
|
167
|
+
}
|
|
168
|
+
return Promise.resolve(new Uint8Array([1, 2, 3]));
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
172
|
+
|
|
173
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: true, thumbnail: new Uint8Array([1, 2, 3]) }]);
|
|
174
|
+
expect(apiService.downloadBlock).toHaveBeenCalledTimes(2);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should handle failure when getting node keys', async () => {
|
|
178
|
+
nodesService.getNodeKeys = jest.fn().mockRejectedValue(new Error('Failed to get node keys'));
|
|
179
|
+
|
|
180
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
181
|
+
|
|
182
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Failed to get node keys' }]);
|
|
183
|
+
expect(apiService.downloadBlock).toHaveBeenCalledTimes(3);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should handle one-off failure when getting node keys', async () => {
|
|
187
|
+
let callCount = 0;
|
|
188
|
+
nodesService.getNodeKeys = jest.fn().mockImplementation(() => {
|
|
189
|
+
callCount++;
|
|
190
|
+
if (callCount === 1) {
|
|
191
|
+
return Promise.reject(new Error('Failed to get node keys'));
|
|
192
|
+
}
|
|
193
|
+
return Promise.resolve({ contentKeyPacketSessionKey: 'contentKeyPacketSessionKey' });
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
197
|
+
|
|
198
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: true, thumbnail: new Uint8Array([1, 2, 3]) }]);
|
|
199
|
+
expect(apiService.downloadBlock).toHaveBeenCalledTimes(2);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should handle failure when decrypting block', async () => {
|
|
203
|
+
cryptoService.decryptThumbnail = jest.fn().mockRejectedValue(new Error('Failed to decrypt thumbnail'));
|
|
204
|
+
|
|
205
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
206
|
+
|
|
207
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: false, error: 'Failed to decrypt thumbnail' }]);
|
|
208
|
+
expect(apiService.downloadBlock).toHaveBeenCalledTimes(3);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should handle one-off failure when decrypting block', async () => {
|
|
212
|
+
let callCount = 0;
|
|
213
|
+
cryptoService.decryptThumbnail = jest.fn().mockImplementation(() => {
|
|
214
|
+
callCount++;
|
|
215
|
+
if (callCount === 1) {
|
|
216
|
+
return Promise.reject(new Error('Failed to decrypt thumbnail'));
|
|
217
|
+
}
|
|
218
|
+
return Promise.resolve(new Uint8Array([1, 2, 3]));
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const results = await Array.fromAsync(downloader.iterateThumbnails(['node1']));
|
|
222
|
+
|
|
223
|
+
expect(results).toEqual([{ nodeUid: 'node1', ok: true, thumbnail: new Uint8Array([1, 2, 3]) }]);
|
|
224
|
+
expect(apiService.downloadBlock).toHaveBeenCalledTimes(2);
|
|
225
|
+
});
|
|
226
|
+
});
|