@protontech/drive-sdk 0.14.0 → 0.14.2

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 (66) hide show
  1. package/dist/internal/batchLoading.d.ts +2 -0
  2. package/dist/internal/batchLoading.js +18 -5
  3. package/dist/internal/batchLoading.js.map +1 -1
  4. package/dist/internal/batchLoading.test.js +92 -0
  5. package/dist/internal/batchLoading.test.js.map +1 -1
  6. package/dist/internal/nodes/nodesAccess.js +1 -1
  7. package/dist/internal/nodes/nodesAccess.js.map +1 -1
  8. package/dist/internal/nodes/nodesAccess.test.js +3 -2
  9. package/dist/internal/nodes/nodesAccess.test.js.map +1 -1
  10. package/dist/internal/photos/index.js +3 -1
  11. package/dist/internal/photos/index.js.map +1 -1
  12. package/dist/internal/photos/upload.d.ts +1 -1
  13. package/dist/internal/photos/upload.js +2 -2
  14. package/dist/internal/photos/upload.js.map +1 -1
  15. package/dist/internal/sharing/events.d.ts +4 -2
  16. package/dist/internal/sharing/events.js +40 -9
  17. package/dist/internal/sharing/events.js.map +1 -1
  18. package/dist/internal/sharing/events.test.js +30 -2
  19. package/dist/internal/sharing/events.test.js.map +1 -1
  20. package/dist/internal/sharing/index.js +1 -1
  21. package/dist/internal/sharing/index.js.map +1 -1
  22. package/dist/internal/sharingPublic/session/index.d.ts +1 -0
  23. package/dist/internal/sharingPublic/session/index.js +3 -1
  24. package/dist/internal/sharingPublic/session/index.js.map +1 -1
  25. package/dist/internal/sharingPublic/session/manager.d.ts +2 -0
  26. package/dist/internal/sharingPublic/session/manager.js +1 -0
  27. package/dist/internal/sharingPublic/session/manager.js.map +1 -1
  28. package/dist/internal/upload/fileUploader.d.ts +19 -3
  29. package/dist/internal/upload/fileUploader.js +31 -5
  30. package/dist/internal/upload/fileUploader.js.map +1 -1
  31. package/dist/internal/upload/fileUploader.test.js +1 -1
  32. package/dist/internal/upload/fileUploader.test.js.map +1 -1
  33. package/dist/internal/upload/index.js +4 -11
  34. package/dist/internal/upload/index.js.map +1 -1
  35. package/dist/internal/upload/index.test.js +104 -45
  36. package/dist/internal/upload/index.test.js.map +1 -1
  37. package/dist/internal/upload/smallFileUploader.d.ts +14 -14
  38. package/dist/internal/upload/smallFileUploader.js +38 -20
  39. package/dist/internal/upload/smallFileUploader.js.map +1 -1
  40. package/dist/internal/upload/smallFileUploader.test.js +35 -36
  41. package/dist/internal/upload/smallFileUploader.test.js.map +1 -1
  42. package/dist/protonDriveClient.js +2 -1
  43. package/dist/protonDriveClient.js.map +1 -1
  44. package/dist/protonDrivePublicLinkClient.d.ts +15 -1
  45. package/dist/protonDrivePublicLinkClient.js +7 -1
  46. package/dist/protonDrivePublicLinkClient.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/internal/batchLoading.test.ts +104 -0
  49. package/src/internal/batchLoading.ts +21 -5
  50. package/src/internal/nodes/nodesAccess.test.ts +4 -3
  51. package/src/internal/nodes/nodesAccess.ts +1 -1
  52. package/src/internal/photos/index.ts +2 -0
  53. package/src/internal/photos/upload.ts +13 -1
  54. package/src/internal/sharing/events.test.ts +35 -2
  55. package/src/internal/sharing/events.ts +47 -10
  56. package/src/internal/sharing/index.ts +1 -0
  57. package/src/internal/sharingPublic/session/index.ts +1 -0
  58. package/src/internal/sharingPublic/session/manager.ts +2 -0
  59. package/src/internal/upload/fileUploader.test.ts +1 -0
  60. package/src/internal/upload/fileUploader.ts +60 -2
  61. package/src/internal/upload/index.test.ts +121 -63
  62. package/src/internal/upload/index.ts +4 -30
  63. package/src/internal/upload/smallFileUploader.test.ts +33 -40
  64. package/src/internal/upload/smallFileUploader.ts +47 -36
  65. package/src/protonDriveClient.ts +2 -1
  66. package/src/protonDrivePublicLinkClient.ts +23 -2
@@ -6,9 +6,10 @@ import { UploadAPIService } from './apiService';
6
6
  import { UploadCryptoService } from './cryptoService';
7
7
  import { UploadManager } from './manager';
8
8
  import { NodeCrypto } from './interface';
9
+ import { mergeUint8Arrays } from '../utils';
9
10
 
10
- const MOCK_BLOCK_HASH = new Uint8Array(32).fill(1);
11
- const MOCK_VERIFICATION_TOKEN = new Uint8Array(16).fill(2);
11
+ const MOCK_BLOCK_HASH = new Uint8Array(32).fill(4);
12
+ const MOCK_VERIFICATION_TOKEN = new Uint8Array(16).fill(5);
12
13
 
13
14
  function createStream(bytes: number[]): ReadableStream<Uint8Array> {
14
15
  return new ReadableStream({
@@ -108,7 +109,7 @@ describe('SmallFileUploader', () => {
108
109
  encryptedData: new Uint8Array(thumbnail.thumbnail),
109
110
  originalSize: thumbnail.thumbnail.length,
110
111
  encryptedSize: thumbnail.thumbnail.length + 100,
111
- hash: 'thumbnailHash',
112
+ hashPromise: Promise.resolve(new Uint8Array(32).fill(thumbnail.type)),
112
113
  })),
113
114
  encryptBlock: jest.fn().mockImplementation(mockEncryptBlock),
114
115
  verifyBlock: jest.fn().mockResolvedValue({ verificationToken: MOCK_VERIFICATION_TOKEN }),
@@ -138,7 +139,6 @@ describe('SmallFileUploader', () => {
138
139
  function createUploader() {
139
140
  return new SmallFileUploader(
140
141
  telemetry,
141
- apiService,
142
142
  cryptoService,
143
143
  uploadManager,
144
144
  metadata,
@@ -157,24 +157,13 @@ describe('SmallFileUploader', () => {
157
157
  const uploader = createUploader();
158
158
  const stream = createStream([1, 2, 3]);
159
159
 
160
- const controller = await uploader.uploadFromStream(stream, thumbnails, onProgress);
161
- const result = await controller.completion();
160
+ const result = await uploader.upload(stream, thumbnails, onProgress);
162
161
 
163
162
  expect(uploadManager.generateNewFileCrypto).toHaveBeenCalledWith(parentFolderUid, name);
164
163
  expect(uploadManager.uploadFile).toHaveBeenCalledTimes(1);
165
164
  expect(result).toEqual({ nodeUid: 'nodeUid', nodeRevisionUid: 'nodeRevisionUid' });
166
165
  expect(onProgress).toHaveBeenCalledWith(metadata.expectedSize);
167
166
  });
168
-
169
- it('should throw if upload already started', async () => {
170
- const uploader = createUploader();
171
- const stream = createStream([1, 2, 3]);
172
-
173
- await uploader.uploadFromStream(stream, thumbnails, onProgress);
174
- await expect(uploader.uploadFromStream(stream, thumbnails, onProgress)).rejects.toThrow(
175
- 'Upload already started',
176
- );
177
- });
178
167
  });
179
168
 
180
169
  describe('buildPayloads (via upload flow)', () => {
@@ -186,8 +175,7 @@ describe('SmallFileUploader', () => {
186
175
  { type: ThumbnailType.Type2, thumbnail: new Uint8Array([30, 40, 50]) },
187
176
  ];
188
177
 
189
- await uploader.uploadFromStream(stream, thumbnails, undefined);
190
- await (uploader as any).controller.completion();
178
+ await uploader.upload(stream, thumbnails, undefined);
191
179
 
192
180
  expect(uploadManager.uploadFile).toHaveBeenCalledWith(
193
181
  parentFolderUid,
@@ -203,8 +191,16 @@ describe('SmallFileUploader', () => {
203
191
  verificationToken: MOCK_VERIFICATION_TOKEN,
204
192
  }),
205
193
  [
206
- { type: ThumbnailType.Type1, encryptedData: expect.any(Uint8Array) },
207
- { type: ThumbnailType.Type2, encryptedData: expect.any(Uint8Array) },
194
+ {
195
+ type: ThumbnailType.Type1,
196
+ encryptedData: expect.any(Uint8Array),
197
+ blockHash: new Uint8Array(32).fill(ThumbnailType.Type1),
198
+ },
199
+ {
200
+ type: ThumbnailType.Type2,
201
+ encryptedData: expect.any(Uint8Array),
202
+ blockHash: new Uint8Array(32).fill(ThumbnailType.Type2),
203
+ },
208
204
  ],
209
205
  );
210
206
 
@@ -212,7 +208,11 @@ describe('SmallFileUploader', () => {
212
208
  expect(cryptoService.encryptThumbnail).toHaveBeenCalledTimes(2);
213
209
  expect(cryptoService.commitFile).toHaveBeenCalledWith(
214
210
  expect.anything(),
215
- MOCK_BLOCK_HASH,
211
+ mergeUint8Arrays([
212
+ new Uint8Array(32).fill(ThumbnailType.Type1),
213
+ new Uint8Array(32).fill(ThumbnailType.Type2),
214
+ MOCK_BLOCK_HASH,
215
+ ]),
216
216
  expect.any(String),
217
217
  );
218
218
  });
@@ -223,8 +223,7 @@ describe('SmallFileUploader', () => {
223
223
  metadata.expectedSize = content.length;
224
224
  const stream = createStream(content);
225
225
 
226
- await uploader.uploadFromStream(stream, [], undefined);
227
- await (uploader as any).controller.completion();
226
+ await uploader.upload(stream, [], undefined);
228
227
 
229
228
  expect(cryptoService.encryptBlock).toHaveBeenCalledWith(
230
229
  expect.any(Function),
@@ -241,8 +240,7 @@ describe('SmallFileUploader', () => {
241
240
  ];
242
241
  const stream = createStream([1, 2, 3]);
243
242
 
244
- await uploader.uploadFromStream(stream, thumbnails, undefined);
245
- await (uploader as any).controller.completion();
243
+ await uploader.upload(stream, thumbnails, undefined);
246
244
 
247
245
  expect(cryptoService.encryptThumbnail).toHaveBeenCalledWith(
248
246
  expect.objectContaining({
@@ -259,8 +257,7 @@ describe('SmallFileUploader', () => {
259
257
  const uploader = createUploader();
260
258
  const stream = createStream([1, 2, 3]);
261
259
 
262
- await uploader.uploadFromStream(stream, [], undefined);
263
- await (uploader as any).controller.completion();
260
+ await uploader.upload(stream, [], undefined);
264
261
 
265
262
  const [nodeKeys, manifest, extendedAttributes] = (cryptoService.commitFile as jest.Mock).mock.calls[0];
266
263
  expect(manifest).toEqual(MOCK_BLOCK_HASH);
@@ -275,10 +272,10 @@ describe('SmallFileUploader', () => {
275
272
  metadata.expectedSize = 5;
276
273
  const stream = createStream([1, 2, 3]); // only 3 bytes
277
274
 
278
- const controller = await uploader.uploadFromStream(stream, [], undefined);
275
+ const promise = uploader.upload(stream, [], undefined);
279
276
 
280
- await expect(controller.completion()).rejects.toThrow(IntegrityError);
281
- await expect(controller.completion()).rejects.toMatchObject({
277
+ await expect(promise).rejects.toThrow(IntegrityError);
278
+ await expect(promise).rejects.toMatchObject({
282
279
  debug: { actual: 3, expected: 5 },
283
280
  });
284
281
  });
@@ -288,10 +285,10 @@ describe('SmallFileUploader', () => {
288
285
  metadata.expectedSha1 = 'a'.repeat(40); // wrong sha1
289
286
  const stream = createStream([1, 2, 3]);
290
287
 
291
- const controller = await uploader.uploadFromStream(stream, [], undefined);
288
+ const promise = uploader.upload(stream, [], undefined);
292
289
 
293
- await expect(controller.completion()).rejects.toThrow(IntegrityError);
294
- await expect(controller.completion()).rejects.toMatchObject({
290
+ await expect(promise).rejects.toThrow(IntegrityError);
291
+ await expect(promise).rejects.toMatchObject({
295
292
  debug: expect.objectContaining({
296
293
  expectedSha1: 'a'.repeat(40),
297
294
  }),
@@ -306,8 +303,7 @@ describe('SmallFileUploader', () => {
306
303
  const stream = createStream([]);
307
304
  const onProgress = jest.fn();
308
305
 
309
- const controller = await uploader.uploadFromStream(stream, [], onProgress);
310
- const result = await controller.completion();
306
+ const result = await uploader.upload(stream, [], onProgress);
311
307
 
312
308
  expect(result).toEqual({ nodeUid: 'nodeUid', nodeRevisionUid: 'nodeRevisionUid' });
313
309
  expect(cryptoService.encryptBlock).not.toHaveBeenCalled();
@@ -430,7 +426,6 @@ describe('SmallFileRevisionUploader', () => {
430
426
  function createUploader() {
431
427
  return new SmallFileRevisionUploader(
432
428
  telemetry,
433
- apiService,
434
429
  cryptoService,
435
430
  uploadManager,
436
431
  metadata,
@@ -444,8 +439,7 @@ describe('SmallFileRevisionUploader', () => {
444
439
  const uploader = createUploader();
445
440
  const stream = createStream([1, 2, 3]);
446
441
 
447
- const controller = await uploader.uploadFromStream(stream, [], undefined);
448
- const result = await controller.completion();
442
+ const result = await uploader.upload(stream, [], undefined);
449
443
 
450
444
  expect(result).toEqual({ nodeUid: 'nodeUid', nodeRevisionUid: 'nodeRevisionUid' });
451
445
  expect(cryptoService.encryptBlock).toHaveBeenCalledWith(expect.any(Function), expect.anything(), Uint8Array.from([1, 2, 3]), 0);
@@ -471,8 +465,7 @@ describe('SmallFileRevisionUploader', () => {
471
465
  const uploader = createUploader();
472
466
  const stream = createStream([]);
473
467
 
474
- const controller = await uploader.uploadFromStream(stream, [], undefined);
475
- const result = await controller.completion();
468
+ const result = await uploader.upload(stream, [], undefined);
476
469
 
477
470
  expect(result).toEqual({ nodeUid: 'nodeUid', nodeRevisionUid: 'nodeRevisionUid' });
478
471
  expect(cryptoService.encryptBlock).not.toHaveBeenCalled();
@@ -3,12 +3,11 @@ import { AbortError, IntegrityError } from '../../errors';
3
3
  import { Logger, Thumbnail, ThumbnailType, UploadMetadata } from '../../interface';
4
4
  import { getErrorMessage } from '../errors';
5
5
  import { generateFileExtendedAttributes } from '../nodes';
6
- import { UploadAPIService } from './apiService';
7
- import { BlockVerifier, verifyBlockWithContentKey } from './blockVerifier';
6
+ import { mergeUint8Arrays } from '../utils';
7
+ import { verifyBlockWithContentKey } from './blockVerifier';
8
8
  import { UploadCryptoService } from './cryptoService';
9
9
  import { UploadDigests } from './digests';
10
- import { Uploader } from './fileUploader';
11
- import { NodeRevisionDraft, NodeCrypto } from './interface';
10
+ import { NodeCrypto } from './interface';
12
11
  import { UploadManager } from './manager';
13
12
  import { readStreamToUint8Array } from './streamReader';
14
13
  import { MAX_BLOCK_ENCRYPTION_RETRIES } from './streamUploader';
@@ -25,34 +24,23 @@ export type NodeKeys = {
25
24
  * Base uploader for small file and small revision uploads.
26
25
  * Shares the single-request flow: read content, get node crypto, encrypt, then call API.
27
26
  */
28
- abstract class SmallUploader extends Uploader {
27
+ abstract class SmallUploader {
29
28
  protected logger: Logger;
29
+ protected abortController: AbortController;
30
30
 
31
31
  constructor(
32
- telemetry: UploadTelemetry,
33
- apiService: UploadAPIService,
34
- cryptoService: UploadCryptoService,
35
- manager: UploadManager,
36
- metadata: UploadMetadata,
37
- onFinish: () => void,
38
- signal: AbortSignal | undefined,
32
+ protected telemetry: UploadTelemetry,
33
+ protected cryptoService: UploadCryptoService,
34
+ protected manager: UploadManager,
35
+ protected metadata: UploadMetadata,
36
+ protected onFinish: () => void,
37
+ protected signal: AbortSignal | undefined,
39
38
  ) {
40
- super(telemetry, apiService, cryptoService, manager, metadata, onFinish, signal);
41
39
  this.logger = telemetry.getLoggerForSmallUpload();
42
- }
43
- protected async createRevisionDraft(): Promise<{
44
- revisionDraft: NodeRevisionDraft;
45
- blockVerifier: BlockVerifier;
46
- }> {
47
- throw new Error('Small upload does not use revision draft');
40
+ this.abortController = new AbortController();
48
41
  }
49
42
 
50
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
51
- protected async deleteRevisionDraft(revisionDraft: NodeRevisionDraft): Promise<void> {
52
- throw new Error('Small upload does not use revision draft');
53
- }
54
-
55
- protected async startUpload(
43
+ async upload(
56
44
  stream: ReadableStream,
57
45
  thumbnails: Thumbnail[],
58
46
  onProgress?: (uploadedBytes: number) => void,
@@ -105,7 +93,8 @@ abstract class SmallUploader extends Uploader {
105
93
  this.encryptThumbnails(nodeKeys, thumbnails),
106
94
  this.encryptContentBlock(nodeKeys, content.data),
107
95
  ]);
108
- const commitPayload = await this.encryptCommitPayload(nodeKeys, content.sha1, encryptedBlock);
96
+ const manifest = await this.getManifest(encryptedBlock, encryptedThumbnails);
97
+ const commitPayload = await this.encryptCommitPayload(nodeKeys, content.sha1, manifest);
109
98
 
110
99
  return {
111
100
  commitPayload,
@@ -147,12 +136,22 @@ abstract class SmallUploader extends Uploader {
147
136
  private async encryptThumbnails(
148
137
  nodeKeys: NodeKeys,
149
138
  thumbnails: Thumbnail[],
150
- ): Promise<{ type: ThumbnailType; encryptedData: Uint8Array<ArrayBuffer> }[]> {
139
+ ): Promise<
140
+ {
141
+ type: ThumbnailType;
142
+ encryptedData: Uint8Array<ArrayBuffer>;
143
+ blockHash: Uint8Array<ArrayBuffer>;
144
+ }[]
145
+ > {
151
146
  const result = [];
152
147
  for (const thumbnail of thumbnails) {
153
148
  this.logger.debug(`Encrypting thumbnail ${thumbnail.type}`);
154
149
  const enc = await this.cryptoService.encryptThumbnail(nodeKeys, thumbnail);
155
- result.push({ type: thumbnail.type, encryptedData: enc.encryptedData });
150
+ result.push({
151
+ type: thumbnail.type,
152
+ encryptedData: enc.encryptedData,
153
+ blockHash: await enc.hashPromise,
154
+ });
156
155
  }
157
156
  return result;
158
157
  }
@@ -228,21 +227,35 @@ abstract class SmallUploader extends Uploader {
228
227
  };
229
228
  }
230
229
 
231
- private async encryptCommitPayload(
232
- nodeKeys: NodeKeys,
233
- contentSha1: string,
230
+ private async getManifest(
234
231
  encryptedBlock:
235
232
  | {
236
233
  blockHash: Uint8Array<ArrayBuffer>;
237
234
  }
238
235
  | undefined,
236
+ encryptedThumbnails: {
237
+ type: ThumbnailType;
238
+ blockHash: Uint8Array<ArrayBuffer>;
239
+ }[],
240
+ ): Promise<Uint8Array<ArrayBuffer>> {
241
+ encryptedThumbnails.sort((a, b) => a.type - b.type);
242
+ const hashes = [
243
+ ...(await Promise.all(encryptedThumbnails.map(({ blockHash }) => blockHash))),
244
+ ...(encryptedBlock ? [encryptedBlock.blockHash] : []),
245
+ ];
246
+ return mergeUint8Arrays(hashes);
247
+ }
248
+
249
+ private async encryptCommitPayload(
250
+ nodeKeys: NodeKeys,
251
+ contentSha1: string,
252
+ manifest: Uint8Array<ArrayBuffer>,
239
253
  ): Promise<{
240
254
  armoredManifestSignature: string;
241
255
  armoredExtendedAttributes: string;
242
256
  }> {
243
257
  this.logger.debug(`Preparing commit payload`);
244
258
 
245
- const manifest = encryptedBlock ? encryptedBlock.blockHash : new Uint8Array(0);
246
259
  const extendedAttributes = generateFileExtendedAttributes(
247
260
  {
248
261
  modificationTime: this.metadata.modificationTime,
@@ -266,7 +279,6 @@ abstract class SmallUploader extends Uploader {
266
279
  export class SmallFileUploader extends SmallUploader {
267
280
  constructor(
268
281
  telemetry: UploadTelemetry,
269
- apiService: UploadAPIService,
270
282
  cryptoService: UploadCryptoService,
271
283
  manager: UploadManager,
272
284
  metadata: UploadMetadata,
@@ -275,7 +287,7 @@ export class SmallFileUploader extends SmallUploader {
275
287
  private parentFolderUid: string,
276
288
  private name: string,
277
289
  ) {
278
- super(telemetry, apiService, cryptoService, manager, metadata, onFinish, signal);
290
+ super(telemetry, cryptoService, manager, metadata, onFinish, signal);
279
291
  this.parentFolderUid = parentFolderUid;
280
292
  this.name = name;
281
293
  }
@@ -317,7 +329,6 @@ export class SmallFileUploader extends SmallUploader {
317
329
  export class SmallFileRevisionUploader extends SmallUploader {
318
330
  constructor(
319
331
  telemetry: UploadTelemetry,
320
- apiService: UploadAPIService,
321
332
  cryptoService: UploadCryptoService,
322
333
  manager: UploadManager,
323
334
  metadata: UploadMetadata,
@@ -325,7 +336,7 @@ export class SmallFileRevisionUploader extends SmallUploader {
325
336
  signal: AbortSignal | undefined,
326
337
  private nodeUid: string,
327
338
  ) {
328
- super(telemetry, apiService, cryptoService, manager, metadata, onFinish, signal);
339
+ super(telemetry, cryptoService, manager, metadata, onFinish, signal);
329
340
  this.nodeUid = nodeUid;
330
341
  }
331
342
 
@@ -232,7 +232,7 @@ export class ProtonDriveClient {
232
232
  const { token, password: urlPassword } = getTokenAndPasswordFromUrl(url);
233
233
  this.logger.info(`Authenticating public link token ${token}`);
234
234
 
235
- const { httpClient, shareKey, rootUid, publicRole } = await this.publicSessionManager.auth(
235
+ const { httpClient, shareKey, rootUid, publicRole, session } = await this.publicSessionManager.auth(
236
236
  token,
237
237
  urlPassword,
238
238
  customPassword,
@@ -250,6 +250,7 @@ export class ProtonDriveClient {
250
250
  publicRootNodeUid: rootUid,
251
251
  isAnonymousContext,
252
252
  publicRole,
253
+ session,
253
254
  });
254
255
  },
255
256
  };
@@ -33,6 +33,7 @@ import {
33
33
  import { initDownloadModule } from './internal/download';
34
34
  import { SDKEvents } from './internal/sdkEvents';
35
35
  import { initSharingPublicModule, UnauthDriveAPIService } from './internal/sharingPublic';
36
+ import { SharingPublicLinkSession } from './internal/sharingPublic/session';
36
37
  import { initUploadModule } from './internal/upload';
37
38
  import { NullFeatureFlagProvider } from './featureFlags';
38
39
  import { NodesSecurityScanResult } from './internal/sharingPublic/nodesSecurity';
@@ -56,6 +57,7 @@ export class ProtonDrivePublicLinkClient {
56
57
  private sharingPublic: ReturnType<typeof initSharingPublicModule>;
57
58
  private download: ReturnType<typeof initDownloadModule>;
58
59
  private upload: ReturnType<typeof initUploadModule>;
60
+ private session: SharingPublicLinkSession;
59
61
 
60
62
  public experimental: {
61
63
  /**
@@ -86,6 +88,14 @@ export class ProtonDrivePublicLinkClient {
86
88
  * Experimental feature to create a document (Proton Docs or Proton Sheets) in the public link.
87
89
  */
88
90
  createDocument: (parentNodeUid: NodeOrUid, documentName: string, documentType: 1 | 2) => Promise<MaybeNode>;
91
+ /**
92
+ * Experimental feature to get the session info for the public link.
93
+ *
94
+ * This helper is used to set the session for metrics requests.
95
+ * Returns the session UID and access token that were obtained during
96
+ * authentication.
97
+ */
98
+ getSessionInfo: () => { uid: string; accessToken: string | undefined };
89
99
  };
90
100
 
91
101
  constructor({
@@ -102,6 +112,7 @@ export class ProtonDrivePublicLinkClient {
102
112
  publicRootNodeUid,
103
113
  isAnonymousContext,
104
114
  publicRole,
115
+ session,
105
116
  }: {
106
117
  httpClient: ProtonDriveHTTPClient;
107
118
  account: ProtonDriveAccount;
@@ -116,6 +127,7 @@ export class ProtonDrivePublicLinkClient {
116
127
  publicRootNodeUid: string;
117
128
  isAnonymousContext: boolean;
118
129
  publicRole: MemberRole;
130
+ session: SharingPublicLinkSession;
119
131
  }) {
120
132
  if (!telemetry) {
121
133
  telemetry = new Telemetry();
@@ -124,6 +136,7 @@ export class ProtonDrivePublicLinkClient {
124
136
  featureFlagProvider = new NullFeatureFlagProvider();
125
137
  }
126
138
  this.logger = telemetry.getLogger('publicLink-interface');
139
+ this.session = session;
127
140
 
128
141
  // Use only in memory cache for public link as there are no events to keep it up to date if persisted.
129
142
  const entitiesCache = new MemoryCache<string>();
@@ -197,7 +210,7 @@ export class ProtonDrivePublicLinkClient {
197
210
  if (!keys.passphrase) {
198
211
  throw new Error('Node does not have a passphrase');
199
212
  }
200
- return keys.passphrase
213
+ return keys.passphrase;
201
214
  },
202
215
  scanHashes: async (hashes: string[]): Promise<NodesSecurityScanResult> => {
203
216
  this.logger.debug(`Scanning ${hashes.length} hashes`);
@@ -210,9 +223,17 @@ export class ProtonDrivePublicLinkClient {
210
223
  ): Promise<MaybeNode> => {
211
224
  this.logger.debug(`Creating document in ${getUid(parentNodeUid)}`);
212
225
  return convertInternalNodePromise(
213
- this.sharingPublic.nodes.management.createDocument(getUid(parentNodeUid), documentName, documentType),
226
+ this.sharingPublic.nodes.management.createDocument(
227
+ getUid(parentNodeUid),
228
+ documentName,
229
+ documentType,
230
+ ),
214
231
  );
215
232
  },
233
+ getSessionInfo: (): { uid: string; accessToken: string | undefined } => {
234
+ this.logger.debug(`Getting session info`);
235
+ return this.session.session;
236
+ },
216
237
  };
217
238
  }
218
239