@protontech/drive-sdk 0.6.0 → 0.6.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 (128) hide show
  1. package/dist/diagnostic/diagnostic.d.ts +7 -4
  2. package/dist/diagnostic/diagnostic.js +16 -8
  3. package/dist/diagnostic/diagnostic.js.map +1 -1
  4. package/dist/diagnostic/index.d.ts +1 -1
  5. package/dist/diagnostic/index.js +9 -1
  6. package/dist/diagnostic/index.js.map +1 -1
  7. package/dist/diagnostic/interface.d.ts +24 -9
  8. package/dist/diagnostic/nodeUtils.d.ts +13 -0
  9. package/dist/diagnostic/nodeUtils.js +90 -0
  10. package/dist/diagnostic/nodeUtils.js.map +1 -0
  11. package/dist/diagnostic/sdkDiagnosticBase.d.ts +36 -0
  12. package/dist/diagnostic/sdkDiagnosticBase.js +305 -0
  13. package/dist/diagnostic/sdkDiagnosticBase.js.map +1 -0
  14. package/dist/diagnostic/sdkDiagnosticMain.d.ts +16 -0
  15. package/dist/diagnostic/sdkDiagnosticMain.js +79 -0
  16. package/dist/diagnostic/sdkDiagnosticMain.js.map +1 -0
  17. package/dist/diagnostic/sdkDiagnosticPhotos.d.ts +13 -0
  18. package/dist/diagnostic/sdkDiagnosticPhotos.js +65 -0
  19. package/dist/diagnostic/sdkDiagnosticPhotos.js.map +1 -0
  20. package/dist/internal/devices/interface.d.ts +1 -1
  21. package/dist/internal/devices/manager.js +1 -1
  22. package/dist/internal/devices/manager.js.map +1 -1
  23. package/dist/internal/devices/manager.test.js +3 -3
  24. package/dist/internal/devices/manager.test.js.map +1 -1
  25. package/dist/internal/errors.d.ts +5 -0
  26. package/dist/internal/errors.js +23 -0
  27. package/dist/internal/errors.js.map +1 -1
  28. package/dist/internal/errors.test.js +53 -2
  29. package/dist/internal/errors.test.js.map +1 -1
  30. package/dist/internal/nodes/cryptoReporter.js +3 -0
  31. package/dist/internal/nodes/cryptoReporter.js.map +1 -1
  32. package/dist/internal/nodes/index.test.js +1 -1
  33. package/dist/internal/nodes/index.test.js.map +1 -1
  34. package/dist/internal/nodes/interface.d.ts +1 -1
  35. package/dist/internal/nodes/nodesAccess.d.ts +1 -1
  36. package/dist/internal/nodes/nodesAccess.js +4 -4
  37. package/dist/internal/nodes/nodesAccess.js.map +1 -1
  38. package/dist/internal/nodes/nodesAccess.test.js +2 -2
  39. package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
  40. package/dist/internal/photos/albums.js +1 -1
  41. package/dist/internal/photos/albums.js.map +1 -1
  42. package/dist/internal/photos/apiService.d.ts +6 -0
  43. package/dist/internal/photos/apiService.js +16 -0
  44. package/dist/internal/photos/apiService.js.map +1 -1
  45. package/dist/internal/photos/index.d.ts +1 -1
  46. package/dist/internal/photos/index.js +2 -2
  47. package/dist/internal/photos/index.js.map +1 -1
  48. package/dist/internal/photos/interface.d.ts +4 -1
  49. package/dist/internal/photos/shares.d.ts +1 -1
  50. package/dist/internal/photos/shares.js +3 -3
  51. package/dist/internal/photos/shares.js.map +1 -1
  52. package/dist/internal/photos/timeline.d.ts +8 -1
  53. package/dist/internal/photos/timeline.js +36 -2
  54. package/dist/internal/photos/timeline.js.map +1 -1
  55. package/dist/internal/photos/timeline.test.d.ts +1 -0
  56. package/dist/internal/photos/timeline.test.js +99 -0
  57. package/dist/internal/photos/timeline.test.js.map +1 -0
  58. package/dist/internal/shares/cryptoService.js +3 -0
  59. package/dist/internal/shares/cryptoService.js.map +1 -1
  60. package/dist/internal/shares/manager.d.ts +1 -1
  61. package/dist/internal/shares/manager.js +4 -4
  62. package/dist/internal/shares/manager.js.map +1 -1
  63. package/dist/internal/shares/manager.test.js +7 -7
  64. package/dist/internal/shares/manager.test.js.map +1 -1
  65. package/dist/internal/sharing/interface.d.ts +1 -1
  66. package/dist/internal/sharing/sharingAccess.js +1 -1
  67. package/dist/internal/sharing/sharingAccess.js.map +1 -1
  68. package/dist/internal/sharing/sharingAccess.test.js +1 -1
  69. package/dist/internal/sharing/sharingAccess.test.js.map +1 -1
  70. package/dist/internal/sharing/sharingManagement.js +32 -14
  71. package/dist/internal/sharing/sharingManagement.js.map +1 -1
  72. package/dist/internal/sharing/sharingManagement.test.js +46 -1
  73. package/dist/internal/sharing/sharingManagement.test.js.map +1 -1
  74. package/dist/internal/sharingPublic/cryptoReporter.js +3 -0
  75. package/dist/internal/sharingPublic/cryptoReporter.js.map +1 -1
  76. package/dist/internal/sharingPublic/index.d.ts +3 -0
  77. package/dist/internal/sharingPublic/index.js +3 -0
  78. package/dist/internal/sharingPublic/index.js.map +1 -1
  79. package/dist/internal/sharingPublic/shares.d.ts +1 -1
  80. package/dist/internal/sharingPublic/shares.js +1 -2
  81. package/dist/internal/sharingPublic/shares.js.map +1 -1
  82. package/dist/protonDrivePhotosClient.d.ts +19 -0
  83. package/dist/protonDrivePhotosClient.js +23 -1
  84. package/dist/protonDrivePhotosClient.js.map +1 -1
  85. package/dist/protonDrivePublicLinkClient.d.ts +33 -1
  86. package/dist/protonDrivePublicLinkClient.js +51 -2
  87. package/dist/protonDrivePublicLinkClient.js.map +1 -1
  88. package/package.json +1 -1
  89. package/src/diagnostic/diagnostic.ts +27 -8
  90. package/src/diagnostic/index.ts +17 -2
  91. package/src/diagnostic/interface.ts +35 -9
  92. package/src/diagnostic/nodeUtils.ts +100 -0
  93. package/src/diagnostic/{sdkDiagnostic.ts → sdkDiagnosticBase.ts} +204 -204
  94. package/src/diagnostic/sdkDiagnosticMain.ts +95 -0
  95. package/src/diagnostic/sdkDiagnosticPhotos.ts +70 -0
  96. package/src/internal/devices/interface.ts +1 -1
  97. package/src/internal/devices/manager.test.ts +3 -3
  98. package/src/internal/devices/manager.ts +1 -1
  99. package/src/internal/errors.test.ts +62 -1
  100. package/src/internal/errors.ts +27 -0
  101. package/src/internal/nodes/cryptoReporter.ts +6 -5
  102. package/src/internal/nodes/index.test.ts +1 -1
  103. package/src/internal/nodes/interface.ts +1 -1
  104. package/src/internal/nodes/nodesAccess.test.ts +2 -2
  105. package/src/internal/nodes/nodesAccess.ts +5 -5
  106. package/src/internal/photos/albums.ts +1 -1
  107. package/src/internal/photos/apiService.ts +40 -0
  108. package/src/internal/photos/index.ts +9 -1
  109. package/src/internal/photos/interface.ts +4 -1
  110. package/src/internal/photos/shares.ts +3 -3
  111. package/src/internal/photos/timeline.test.ts +116 -0
  112. package/src/internal/photos/timeline.ts +47 -2
  113. package/src/internal/shares/cryptoService.ts +5 -1
  114. package/src/internal/shares/manager.test.ts +7 -7
  115. package/src/internal/shares/manager.ts +4 -4
  116. package/src/internal/sharing/interface.ts +1 -1
  117. package/src/internal/sharing/sharingAccess.test.ts +1 -1
  118. package/src/internal/sharing/sharingAccess.ts +1 -1
  119. package/src/internal/sharing/sharingManagement.test.ts +59 -1
  120. package/src/internal/sharing/sharingManagement.ts +33 -14
  121. package/src/internal/sharingPublic/cryptoReporter.ts +5 -1
  122. package/src/internal/sharingPublic/index.ts +3 -0
  123. package/src/internal/sharingPublic/shares.ts +1 -2
  124. package/src/protonDrivePhotosClient.ts +24 -1
  125. package/src/protonDrivePublicLinkClient.ts +77 -2
  126. package/dist/diagnostic/sdkDiagnostic.d.ts +0 -23
  127. package/dist/diagnostic/sdkDiagnostic.js +0 -320
  128. package/dist/diagnostic/sdkDiagnostic.js.map +0 -1
@@ -46,7 +46,7 @@ export class SharesManager {
46
46
  *
47
47
  * If the default volume or My files section doesn't exist, it creates it.
48
48
  */
49
- async getOwnVolumeIDs(): Promise<VolumeShareNodeIDs> {
49
+ async getRootIDs(): Promise<VolumeShareNodeIDs> {
50
50
  if (this.myFilesIds) {
51
51
  return this.myFilesIds;
52
52
  }
@@ -140,7 +140,7 @@ export class SharesManager {
140
140
  addressKey: PrivateKey;
141
141
  addressKeyId: string;
142
142
  }> {
143
- const { volumeId } = await this.getOwnVolumeIDs();
143
+ const { volumeId } = await this.getRootIDs();
144
144
 
145
145
  try {
146
146
  const { addressId } = await this.cache.getVolume(volumeId);
@@ -196,11 +196,11 @@ export class SharesManager {
196
196
  }
197
197
 
198
198
  async isOwnVolume(volumeId: string): Promise<boolean> {
199
- return (await this.getOwnVolumeIDs()).volumeId === volumeId;
199
+ return (await this.getRootIDs()).volumeId === volumeId;
200
200
  }
201
201
 
202
202
  async getVolumeMetricContext(volumeId: string): Promise<MetricVolumeType> {
203
- const { volumeId: myVolumeId } = await this.getOwnVolumeIDs();
203
+ const { volumeId: myVolumeId } = await this.getRootIDs();
204
204
 
205
205
  // SDK doesn't support public sharing yet, also public sharing
206
206
  // doesn't use a volume but shareURL, thus we can simplify and
@@ -142,7 +142,7 @@ export interface PublicLinkWithCreatorEmail extends PublicLink {
142
142
  * Interface describing the dependencies to the shares module.
143
143
  */
144
144
  export interface SharesService {
145
- getOwnVolumeIDs(): Promise<{ volumeId: string }>;
145
+ getRootIDs(): Promise<{ volumeId: string }>;
146
146
  loadEncryptedShare(shareId: string): Promise<EncryptedShare>;
147
147
  getMyFilesShareMemberEmailKey(): Promise<{
148
148
  email: string;
@@ -93,7 +93,7 @@ describe('SharingAccess', () => {
93
93
 
94
94
  // @ts-expect-error No need to implement all methods for mocking
95
95
  sharesService = {
96
- getOwnVolumeIDs: jest.fn().mockResolvedValue({ volumeId: 'volumeId' }),
96
+ getRootIDs: jest.fn().mockResolvedValue({ volumeId: 'volumeId' }),
97
97
  loadEncryptedShare: jest.fn().mockResolvedValue({
98
98
  id: 'shareId',
99
99
  membership: { memberUid: 'memberUid' },
@@ -40,7 +40,7 @@ export class SharingAccess {
40
40
  const nodeUids = await this.cache.getSharedByMeNodeUids();
41
41
  yield* this.iterateSharedNodesFromCache(nodeUids, signal);
42
42
  } catch {
43
- const { volumeId } = await this.sharesService.getOwnVolumeIDs();
43
+ const { volumeId } = await this.sharesService.getRootIDs();
44
44
  const nodeUidsIterator = this.apiService.iterateSharedNodeUids(volumeId, signal);
45
45
  yield* this.iterateSharedNodesFromAPI(
46
46
  nodeUidsIterator,
@@ -1,5 +1,6 @@
1
1
  import { getMockLogger } from '../../tests/logger';
2
2
  import {
3
+ Logger,
3
4
  Member,
4
5
  MemberRole,
5
6
  NonProtonInvitation,
@@ -14,8 +15,11 @@ import { SharingCache } from './cache';
14
15
  import { SharingCryptoService } from './cryptoService';
15
16
  import { SharesService, NodesService } from './interface';
16
17
  import { SharingManagement } from './sharingManagement';
18
+ import { ValidationError } from '../../errors';
19
+ import { ErrorCode } from '../apiService';
17
20
 
18
21
  describe('SharingManagement', () => {
22
+ let logger: Logger;
19
23
  let apiService: SharingAPIService;
20
24
  let cache: SharingCache;
21
25
  let cryptoService: SharingCryptoService;
@@ -26,6 +30,8 @@ describe('SharingManagement', () => {
26
30
  let sharingManagement: SharingManagement;
27
31
 
28
32
  beforeEach(() => {
33
+ logger = getMockLogger();
34
+
29
35
  // @ts-expect-error No need to implement all methods for mocking
30
36
  apiService = {
31
37
  createStandardShare: jest.fn().mockReturnValue('newShareId'),
@@ -110,7 +116,7 @@ describe('SharingManagement', () => {
110
116
  };
111
117
 
112
118
  sharingManagement = new SharingManagement(
113
- getMockLogger(),
119
+ logger,
114
120
  apiService,
115
121
  cache,
116
122
  cryptoService,
@@ -225,6 +231,58 @@ describe('SharingManagement', () => {
225
231
  expect(nodesService.notifyNodeChanged).toHaveBeenCalledWith(nodeUid);
226
232
  expect(cache.addSharedByMeNodeUid).toHaveBeenCalledWith(nodeUid);
227
233
  });
234
+
235
+ it('should refresh node info if share already exists', async () => {
236
+ nodesService.getNode = jest
237
+ .fn()
238
+ .mockImplementationOnce((nodeUid) => ({
239
+ nodeUid,
240
+ parentUid: 'parentUid',
241
+ name: { ok: true, value: 'name' },
242
+ }))
243
+ .mockImplementation((nodeUid) => ({
244
+ nodeUid,
245
+ shareId: 'shareId',
246
+ parentUid: 'parentUid',
247
+ name: { ok: true, value: 'name' },
248
+ }));
249
+ apiService.createStandardShare = jest
250
+ .fn()
251
+ .mockRejectedValue(new ValidationError('Share already exists', ErrorCode.ALREADY_EXISTS));
252
+
253
+ const sharingInfo = await sharingManagement.shareNode(nodeUid, { users: ['email'] });
254
+
255
+ expect(sharingInfo).toEqual({
256
+ protonInvitations: [
257
+ {
258
+ uid: 'created-invitation',
259
+ addedByEmail: { ok: true, value: 'volume-email' },
260
+ inviteeEmail: 'email',
261
+ role: 'viewer',
262
+ },
263
+ ],
264
+ nonProtonInvitations: [],
265
+ members: [],
266
+ publicLink: undefined,
267
+ });
268
+
269
+ expect(nodesService.notifyNodeChanged).toHaveBeenCalledWith(nodeUid);
270
+ expect(logger.debug).toHaveBeenCalledWith(
271
+ 'Share already exists for node volumeId~nodeUid, refreshing node',
272
+ );
273
+ expect(apiService.inviteProtonUser).toHaveBeenCalledWith(
274
+ 'shareId',
275
+ {
276
+ addedByEmail: 'volume-email',
277
+ inviteeEmail: 'email',
278
+ role: 'viewer',
279
+ },
280
+ {
281
+ message: undefined,
282
+ nodeName: undefined,
283
+ },
284
+ );
285
+ });
228
286
  });
229
287
 
230
288
  describe('shareNode with share re-use', () => {
@@ -15,6 +15,7 @@ import {
15
15
  ProtonDriveAccount,
16
16
  SharePublicLinkSettingsObject,
17
17
  } from '../../interface';
18
+ import { ErrorCode } from '../apiService';
18
19
  import { splitNodeUid } from '../uids';
19
20
  import { getErrorMessage } from '../errors';
20
21
  import { SharingAPIService } from './apiService';
@@ -147,22 +148,40 @@ export class SharingManagement {
147
148
  throw new ValidationError(c('Error').t`Expiration date cannot be in the past`);
148
149
  }
149
150
 
150
- let contextShareAddress: ContextShareAddress;
151
+ let contextShareAddress: ContextShareAddress | undefined;
151
152
  let currentSharing = await this.getInternalSharingInfo(nodeUid);
152
- if (currentSharing) {
153
- contextShareAddress = await this.nodesService.getRootNodeEmailKey(nodeUid);
154
- } else {
153
+ if (!currentSharing) {
155
154
  const node = await this.nodesService.getNode(nodeUid);
156
- const result = await this.createShare(nodeUid);
157
- currentSharing = {
158
- share: result.share,
159
- nodeName: node.name.ok ? node.name.value : node.name.error.name,
160
- protonInvitations: [],
161
- nonProtonInvitations: [],
162
- members: [],
163
- publicLink: undefined,
164
- };
165
- contextShareAddress = result.contextShareAddress;
155
+ try {
156
+ const result = await this.createShare(nodeUid);
157
+ currentSharing = {
158
+ share: result.share,
159
+ nodeName: node.name.ok ? node.name.value : node.name.error.name,
160
+ protonInvitations: [],
161
+ nonProtonInvitations: [],
162
+ members: [],
163
+ publicLink: undefined,
164
+ };
165
+ contextShareAddress = result.contextShareAddress;
166
+ } catch (error: unknown) {
167
+ // If the share already exists, notify that the node has
168
+ // changed to force refresh and get the latest sharing info
169
+ // again.
170
+ if (error instanceof ValidationError && error.code === ErrorCode.ALREADY_EXISTS) {
171
+ this.logger.debug(`Share already exists for node ${nodeUid}, refreshing node`);
172
+ await this.nodesService.notifyNodeChanged(nodeUid);
173
+ currentSharing = await this.getInternalSharingInfo(nodeUid);
174
+ } else {
175
+ throw error;
176
+ }
177
+ }
178
+ }
179
+
180
+ if (!currentSharing) {
181
+ throw new ValidationError(c('Error').t`Failed to get sharing info for node ${nodeUid}`);
182
+ }
183
+ if (!contextShareAddress) {
184
+ contextShareAddress = await this.nodesService.getRootNodeEmailKey(nodeUid);
166
185
  }
167
186
 
168
187
  const emailOptions: EmailOptions = {
@@ -1,7 +1,7 @@
1
1
  import { c } from 'ttag';
2
2
 
3
3
  import { VERIFICATION_STATUS } from '../../crypto';
4
- import { getVerificationMessage } from '../errors';
4
+ import { getVerificationMessage, isNotApplicationError } from '../errors';
5
5
  import {
6
6
  resultOk,
7
7
  resultError,
@@ -49,6 +49,10 @@ export class SharingPublicCryptoReporter {
49
49
  field: MetricsDecryptionErrorField,
50
50
  error: unknown,
51
51
  ) {
52
+ if (isNotApplicationError(error)) {
53
+ return;
54
+ }
55
+
52
56
  const fromBefore2024 = node.creationTime < new Date('2024-01-01');
53
57
 
54
58
  this.logger.error(
@@ -10,6 +10,7 @@ import { NodeAPIService } from '../nodes/apiService';
10
10
  import { NodesCache } from '../nodes/cache';
11
11
  import { NodesCryptoCache } from '../nodes/cryptoCache';
12
12
  import { NodesCryptoService } from '../nodes/cryptoService';
13
+ import { NodesManagement } from '../nodes/nodesManagement';
13
14
  import { NodesRevisons } from '../nodes/nodesRevisions';
14
15
  import { SharingPublicCryptoReporter } from './cryptoReporter';
15
16
  import { SharingPublicNodesAccess } from './nodes';
@@ -96,10 +97,12 @@ export function initSharingPublicNodesModule(
96
97
  publicShareKey,
97
98
  publicRootNodeUid,
98
99
  );
100
+ const nodesManagement = new NodesManagement(api, cryptoCache, cryptoService, nodesAccess);
99
101
  const nodesRevisions = new NodesRevisons(telemetry.getLogger('nodes'), api, cryptoService, nodesAccess);
100
102
 
101
103
  return {
102
104
  access: nodesAccess,
105
+ management: nodesManagement,
103
106
  revisions: nodesRevisions,
104
107
  };
105
108
  }
@@ -19,8 +19,7 @@ export class SharingPublicSharesManager {
19
19
  this.publicRootNodeUid = publicRootNodeUid;
20
20
  }
21
21
 
22
- // TODO: Rename to getRootIDs everywhere.
23
- async getOwnVolumeIDs(): Promise<{ volumeId: string; rootNodeId: string; rootNodeUid: string }> {
22
+ async getRootIDs(): Promise<{ volumeId: string; rootNodeId: string; rootNodeUid: string }> {
24
23
  const { volumeId, nodeId: rootNodeId } = splitNodeUid(this.publicRootNodeUid);
25
24
  return { volumeId, rootNodeId, rootNodeUid: this.publicRootNodeUid };
26
25
  }
@@ -117,7 +117,7 @@ export class ProtonDrivePhotosClient {
117
117
  this.photoShares,
118
118
  fullConfig.clientUid,
119
119
  );
120
- this.photos = initPhotosModule(apiService, this.photoShares, this.nodes.access);
120
+ this.photos = initPhotosModule(telemetry, apiService, cryptoModule, this.photoShares, this.nodes.access);
121
121
  this.sharing = initSharingModule(
122
122
  telemetry,
123
123
  apiService,
@@ -454,6 +454,29 @@ export class ProtonDrivePhotosClient {
454
454
  return this.upload.getFileUploader(getUid(parentFolderUid), name, metadata, signal);
455
455
  }
456
456
 
457
+ /**
458
+ * Check if the photo is a duplicate.
459
+ *
460
+ * For given photo name, find existing photos with the same name
461
+ * in the timeline and check if the photo content is also the same.
462
+ * Only the same name is not considered as duplicate photo because
463
+ * it is expected that there are photos with the same name (e.g.,
464
+ * date as a name from multiple cameras, or rolling number).
465
+ *
466
+ * The function accepts a callback to generate the SHA1 and it is
467
+ * called only when there is any matching node name hash to avoid
468
+ * computation for every node if its not necessary.
469
+ *
470
+ * @param name - The name of the photo to check for duplicates.
471
+ * @param generateSha1 - A callback to generate the hex string representation of the SHA1 of the photo content.
472
+ * @param signal - An optional abort signal to cancel the operation.
473
+ * @returns True if the photo already exists in the timeline, false otherwise.
474
+ */
475
+ async isDuplicatePhoto(name: string, generateSha1: () => Promise<string>, signal?: AbortSignal): Promise<boolean> {
476
+ this.logger.info(`Checking if photo is a duplicate`);
477
+ return this.photos.timeline.isDuplicatePhoto(name, generateSha1, signal);
478
+ }
479
+
457
480
  /**
458
481
  * Iterates the albums.
459
482
  *
@@ -15,6 +15,9 @@ import {
15
15
  FileDownloader,
16
16
  ThumbnailType,
17
17
  ThumbnailResult,
18
+ UploadMetadata,
19
+ FileUploader,
20
+ NodeResult,
18
21
  } from './interface';
19
22
  import { Telemetry } from './telemetry';
20
23
  import {
@@ -28,6 +31,7 @@ import { DriveAPIService } from './internal/apiService';
28
31
  import { initDownloadModule } from './internal/download';
29
32
  import { SDKEvents } from './internal/sdkEvents';
30
33
  import { initSharingPublicModule } from './internal/sharingPublic';
34
+ import { initUploadModule } from './internal/upload';
31
35
 
32
36
  /**
33
37
  * ProtonDrivePublicLinkClient is the interface for the public link client.
@@ -47,6 +51,7 @@ export class ProtonDrivePublicLinkClient {
47
51
  private sdkEvents: SDKEvents;
48
52
  private sharingPublic: ReturnType<typeof initSharingPublicModule>;
49
53
  private download: ReturnType<typeof initDownloadModule>;
54
+ private upload: ReturnType<typeof initUploadModule>;
50
55
 
51
56
  public experimental: {
52
57
  /**
@@ -91,7 +96,7 @@ export class ProtonDrivePublicLinkClient {
91
96
  if (!telemetry) {
92
97
  telemetry = new Telemetry();
93
98
  }
94
- this.logger = telemetry.getLogger('interface');
99
+ this.logger = telemetry.getLogger('publicLink-interface');
95
100
 
96
101
  // Use only in memory cache for public link as there are no events to keep it up to date if persisted.
97
102
  const entitiesCache = new MemoryCache<string>();
@@ -129,6 +134,14 @@ export class ProtonDrivePublicLinkClient {
129
134
  this.sharingPublic.nodes.access,
130
135
  this.sharingPublic.nodes.revisions,
131
136
  );
137
+ this.upload = initUploadModule(
138
+ telemetry,
139
+ apiService,
140
+ cryptoModule,
141
+ this.sharingPublic.shares,
142
+ this.sharingPublic.nodes.access,
143
+ fullConfig.clientUid,
144
+ );
132
145
 
133
146
  this.experimental = {
134
147
  getNodeUrl: async (nodeUid: NodeOrUid) => {
@@ -151,7 +164,7 @@ export class ProtonDrivePublicLinkClient {
151
164
  */
152
165
  async getRootNode(): Promise<MaybeNode> {
153
166
  this.logger.info(`Getting root node`);
154
- const { rootNodeUid } = await this.sharingPublic.shares.getOwnVolumeIDs();
167
+ const { rootNodeUid } = await this.sharingPublic.shares.getRootIDs();
155
168
  return convertInternalNodePromise(this.sharingPublic.nodes.access.getNode(rootNodeUid));
156
169
  }
157
170
 
@@ -193,6 +206,38 @@ export class ProtonDrivePublicLinkClient {
193
206
  return convertInternalNodePromise(this.sharingPublic.nodes.access.getNode(getUid(nodeUid)));
194
207
  }
195
208
 
209
+ /**
210
+ * Rename the node.
211
+ *
212
+ * See `ProtonDriveClient.renameNode` for more information.
213
+ */
214
+ async renameNode(nodeUid: NodeOrUid, newName: string): Promise<MaybeNode> {
215
+ this.logger.info(`Renaming node ${getUid(nodeUid)}`);
216
+ return convertInternalNodePromise(this.sharingPublic.nodes.management.renameNode(getUid(nodeUid), newName));
217
+ }
218
+
219
+ /**
220
+ * Delete the nodes permanently.
221
+ *
222
+ * See `ProtonDriveClient.deleteNodes` for more information.
223
+ */
224
+ async *deleteNodes(nodeUids: NodeOrUid[], signal?: AbortSignal): AsyncGenerator<NodeResult> {
225
+ this.logger.info(`Deleting ${nodeUids.length} nodes`);
226
+ yield* this.sharingPublic.nodes.management.deleteNodes(getUids(nodeUids), signal);
227
+ }
228
+
229
+ /**
230
+ * Create a new folder.
231
+ *
232
+ * See `ProtonDriveClient.createFolder` for more information.
233
+ */
234
+ async createFolder(parentNodeUid: NodeOrUid, name: string, modificationTime?: Date): Promise<MaybeNode> {
235
+ this.logger.info(`Creating folder in ${getUid(parentNodeUid)}`);
236
+ return convertInternalNodePromise(
237
+ this.sharingPublic.nodes.management.createFolder(getUid(parentNodeUid), name, modificationTime),
238
+ );
239
+ }
240
+
196
241
  /**
197
242
  * Get the file downloader to download the node content.
198
243
  *
@@ -216,4 +261,34 @@ export class ProtonDrivePublicLinkClient {
216
261
  this.logger.info(`Iterating ${nodeUids.length} thumbnails`);
217
262
  yield* this.download.iterateThumbnails(getUids(nodeUids), thumbnailType, signal);
218
263
  }
264
+
265
+ /**
266
+ * Get the file uploader to upload a new file. For uploading a new
267
+ * revision, use `getFileRevisionUploader` instead.
268
+ *
269
+ * See `ProtonDriveClient.getFileUploader` for more information.
270
+ */
271
+ async getFileUploader(
272
+ parentFolderUid: NodeOrUid,
273
+ name: string,
274
+ metadata: UploadMetadata,
275
+ signal?: AbortSignal,
276
+ ): Promise<FileUploader> {
277
+ this.logger.info(`Getting file uploader for parent ${getUid(parentFolderUid)}`);
278
+ return this.upload.getFileUploader(getUid(parentFolderUid), name, metadata, signal);
279
+ }
280
+
281
+ /**
282
+ * Same as `getFileUploader`, but for a uploading new revision of the file.
283
+ *
284
+ * See `ProtonDriveClient.getFileRevisionUploader` for more information.
285
+ */
286
+ async getFileRevisionUploader(
287
+ nodeUid: NodeOrUid,
288
+ metadata: UploadMetadata,
289
+ signal?: AbortSignal,
290
+ ): Promise<FileUploader> {
291
+ this.logger.info(`Getting file revision uploader for ${getUid(nodeUid)}`);
292
+ return this.upload.getFileRevisionUploader(getUid(nodeUid), metadata, signal);
293
+ }
219
294
  }
@@ -1,23 +0,0 @@
1
- import { MaybeNode } from '../interface';
2
- import { ProtonDriveClient } from '../protonDriveClient';
3
- import { DiagnosticOptions, DiagnosticResult } from './interface';
4
- /**
5
- * Diagnostic tool that uses SDK to traverse the node tree and verify
6
- * the integrity of the node tree.
7
- *
8
- * It produces only events that can be read by direct SDK invocation.
9
- * To get the full diagnostic, use {@link FullSDKDiagnostic}.
10
- */
11
- export declare class SDKDiagnostic {
12
- private protonDriveClient;
13
- constructor(protonDriveClient: ProtonDriveClient);
14
- verifyMyFiles(options?: DiagnosticOptions): AsyncGenerator<DiagnosticResult>;
15
- verifyNodeTree(node: MaybeNode, options?: DiagnosticOptions): AsyncGenerator<DiagnosticResult>;
16
- private verifyNode;
17
- private verifyAuthor;
18
- private verifyFileExtendedAttributes;
19
- private verifyContent;
20
- private verifyThumbnails;
21
- private verifyNodeChildren;
22
- private verifyExpectedNodeChildren;
23
- }