@cooperation/vc-storage 1.0.33 → 1.0.40

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.
@@ -2,21 +2,25 @@
2
2
  * @class GoogleDriveStorage
3
3
  * @description Class to interact with Google Drive API
4
4
  * @param accessToken - Access token to authenticate with Google Drive API
5
- * @method createFolder - Create a new folder in Google Drive
6
- * @method save - Save data to Google Drive
7
- * @method addCommentToFile - Add a comment to a file in Google Drive
8
- * @method addCommenterRoleToFile - Add commenter role to a file in Google Drive
5
+ * @method saveFile - Save a file to Google Drive
9
6
  * @method retrieve - Retrieve a file from Google Drive
10
- * @method findFolders - Find folders in Google Drive
11
- * @method findLastFile - Find the last file in a folder
12
- * @method getAllVCs - Get all verifiable credentials from Google Drive
13
- * @method getAllSessions - Get all sessions from Google Drive
7
+ * @method createFolder - Create a new folder in Google Drive
8
+ * @method getOrCreateMediaFolder - Get the ID of the MEDIAs folder
9
+ * @method uploadBinaryFile - Upload a binary file to Google Drive
10
+ * @method updateFileData - Update the data of a file
11
+ * @method updateRelationsFile - Update the relations file
14
12
  * @method delete - Delete a file from Google Drive
13
+ * @method checkEmailExists - Check if an email VC exists and return its content
14
+ * @method findFolders - Find folders in Google Drive
15
+ * @method findFolderFiles - Find files in a folder
15
16
  */
16
17
  export class GoogleDriveStorage {
17
18
  accessToken;
18
- folderCache = {};
19
- fileIdsCache = null;
19
+ static folderCache = {};
20
+ static fileIdsCache = null;
21
+ constructor(accessToken) {
22
+ this.accessToken = accessToken;
23
+ }
20
24
  async updateFileIdsJson(newFileId) {
21
25
  const constructUrl = () => {
22
26
  const baseUrl = 'https://www.googleapis.com/drive/v3/files';
@@ -29,28 +33,28 @@ export class GoogleDriveStorage {
29
33
  };
30
34
  try {
31
35
  // ✅ Fetch `file_ids.json` ID once per session (cached)
32
- if (!this.fileIdsCache) {
36
+ if (!GoogleDriveStorage.fileIdsCache) {
33
37
  const existingFile = await this.fetcher({
34
38
  method: 'GET',
35
39
  headers: {},
36
40
  url: constructUrl(),
37
41
  });
38
42
  if (existingFile.files.length > 0) {
39
- this.fileIdsCache = existingFile.files[0].id;
43
+ GoogleDriveStorage.fileIdsCache = existingFile.files[0].id;
40
44
  }
41
45
  else {
42
46
  console.log('No existing file_ids.json found, creating a new one.');
43
- this.fileIdsCache = null;
47
+ GoogleDriveStorage.fileIdsCache = null;
44
48
  }
45
49
  }
46
50
  let existingFileIds = [];
47
51
  // ✅ Fetch existing file IDs **only if `file_ids.json` exists**
48
- if (this.fileIdsCache) {
52
+ if (GoogleDriveStorage.fileIdsCache) {
49
53
  try {
50
54
  const fileContent = await this.fetcher({
51
55
  method: 'GET',
52
56
  headers: {},
53
- url: `https://www.googleapis.com/drive/v3/files/${this.fileIdsCache}?alt=media`,
57
+ url: `https://www.googleapis.com/drive/v3/files/${GoogleDriveStorage.fileIdsCache}?alt=media`,
54
58
  });
55
59
  existingFileIds = fileContent;
56
60
  }
@@ -60,16 +64,13 @@ export class GoogleDriveStorage {
60
64
  }
61
65
  // ✅ Append the new file ID to the list
62
66
  existingFileIds.push(newFileId);
63
- console.log('File ID saved to appDataFolder.', this.fileIdsCache);
67
+ console.log('File ID saved to appDataFolder.', GoogleDriveStorage.fileIdsCache);
64
68
  }
65
69
  catch (error) {
66
70
  console.error('Error updating file_ids.json:', error.message);
67
71
  throw error;
68
72
  }
69
73
  }
70
- constructor(accessToken) {
71
- this.accessToken = accessToken;
72
- }
73
74
  async fetcher({ method, headers, body, url }) {
74
75
  try {
75
76
  const res = await fetch(url, {
@@ -120,6 +121,43 @@ export class GoogleDriveStorage {
120
121
  });
121
122
  return result.files || [];
122
123
  }
124
+ async getOrCreateMediaFolder() {
125
+ if (GoogleDriveStorage.folderCache['MEDIAs']) {
126
+ return GoogleDriveStorage.folderCache['MEDIAs'];
127
+ }
128
+ const rootFolders = await this.findFolders();
129
+ let credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
130
+ if (!credentialsFolder) {
131
+ credentialsFolder = await this.createFolder({ folderName: 'Credentials', parentFolderId: 'root' });
132
+ }
133
+ const subfolders = await this.findFolders(credentialsFolder.id);
134
+ let mediasFolder = subfolders.find((f) => f.name === 'MEDIAs');
135
+ if (!mediasFolder) {
136
+ mediasFolder = await this.createFolder({ folderName: 'MEDIAs', parentFolderId: credentialsFolder.id });
137
+ }
138
+ GoogleDriveStorage.folderCache['MEDIAs'] = mediasFolder.id;
139
+ return mediasFolder.id;
140
+ }
141
+ async findFolderFiles(folderId) {
142
+ if (!folderId)
143
+ throw new Error('Folder ID is required');
144
+ const files = await this.searchFiles(`'${folderId}' in parents`);
145
+ if (files.length === 0) {
146
+ console.log('No files found in the folder.');
147
+ return [];
148
+ }
149
+ const filesWithContent = await Promise.all(files.map(async (file) => {
150
+ try {
151
+ const content = await this.getFileContent(file.id);
152
+ return { ...file, content };
153
+ }
154
+ catch (error) {
155
+ console.error(`Error fetching content for file "${file.name}" (ID: ${file.id}):`, error);
156
+ return { ...file, content: null };
157
+ }
158
+ }));
159
+ return filesWithContent;
160
+ }
123
161
  async createFolder({ folderName, parentFolderId }) {
124
162
  if (!parentFolderId) {
125
163
  throw new Error(`Parent folder ID must be provided when creating folder "${folderName}".`);
@@ -143,42 +181,29 @@ export class GoogleDriveStorage {
143
181
  body: JSON.stringify({ role: 'reader', type: 'anyone' }),
144
182
  });
145
183
  // Invalidate cache for this parent folder
146
- if (this.folderCache[parentFolderId]) {
147
- delete this.folderCache[parentFolderId];
184
+ if (GoogleDriveStorage.folderCache[parentFolderId]) {
185
+ delete GoogleDriveStorage.folderCache[parentFolderId];
148
186
  }
149
187
  // Also clear 'root' cache if parent is root
150
- if (parentFolderId === 'root' && this.folderCache['root']) {
151
- delete this.folderCache['root'];
188
+ if (parentFolderId === 'root' && GoogleDriveStorage.folderCache['root']) {
189
+ delete GoogleDriveStorage.folderCache['root'];
152
190
  }
153
191
  return folder;
154
192
  }
193
+ /**
194
+ * Get the ID of the MEDIAs folder (public wrapper for getOrCreateMediaFolder)
195
+ * @returns The folder ID for the MEDIAs folder
196
+ */
155
197
  async getMediaFolderId() {
156
- if (this.folderCache['MEDIAs']) {
157
- return this.folderCache['MEDIAs'];
158
- }
159
- const rootFolders = await this.findFolders();
160
- let credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
161
- if (!credentialsFolder) {
162
- credentialsFolder = await this.createFolder({ folderName: 'Credentials', parentFolderId: 'root' });
163
- }
164
- const credentialsFolderId = credentialsFolder.id;
165
- const subfolders = await this.findFolders(credentialsFolder.id);
166
- let mediasFolder = subfolders.find((f) => f.name === 'MEDIAs');
167
- if (!mediasFolder) {
168
- mediasFolder = await this.createFolder({ folderName: 'MEDIAs', parentFolderId: credentialsFolderId });
169
- }
170
- const mediasFolderId = mediasFolder.id;
171
- this.folderCache['MEDIAs'] = mediasFolderId;
172
- return mediasFolderId;
198
+ return await this.getOrCreateMediaFolder();
173
199
  }
174
200
  async uploadBinaryFile({ file }) {
175
201
  try {
176
- const accessToken = this.accessToken; // Ensure access token is available
202
+ const accessToken = this.accessToken;
177
203
  if (!accessToken) {
178
204
  throw new Error('Missing Google OAuth access token.');
179
205
  }
180
- const folderId = await this.getMediaFolderId(); // Ensure folderId is correct
181
- // ✅ Correct metadata for Google Drive API
206
+ const folderId = await this.getOrCreateMediaFolder();
182
207
  const metadata = {
183
208
  name: file.name,
184
209
  mimeType: file.type,
@@ -209,14 +234,20 @@ export class GoogleDriveStorage {
209
234
  throw error;
210
235
  }
211
236
  }
212
- async saveFile({ data, folderId }) {
237
+ async saveFile({ data, folderId, fileId }) {
213
238
  console.log('🚀 ~ GoogleDriveStorage ~ saveFile ~ data:', data);
214
239
  try {
240
+ // If fileId is provided, update the existing file instead of creating a new one
241
+ if (fileId) {
242
+ console.log(`Updating existing file with ID: ${fileId}`);
243
+ return await this.updateFileContent({ fileId, data });
244
+ }
245
+ // For new files, folderId is required
215
246
  if (!folderId) {
216
- throw new Error('Folder ID is required to save a file.');
247
+ throw new Error('Folder ID is required to save a new file.');
217
248
  }
218
249
  const fileMetadata = {
219
- name: data.fileName || data.name + '.json' || data.credentialSubject.person.name.formattedName + '.json' || 'Untitled file.json',
250
+ name: data.fileName || data.name + '.json' || data.credentialSubject?.person?.name?.formattedName + '.json' || 'Untitled file.json',
220
251
  parents: [folderId],
221
252
  mimeType: data.mimeType || 'application/json',
222
253
  };
@@ -248,11 +279,6 @@ export class GoogleDriveStorage {
248
279
  throw error;
249
280
  }
250
281
  }
251
- /**
252
- * Get file from google drive by id
253
- * @param id
254
- * @returns file content
255
- */
256
282
  async retrieve(id) {
257
283
  const dataUrl = `https://www.googleapis.com/drive/v3/files/${id}?alt=media`;
258
284
  try {
@@ -293,63 +319,53 @@ export class GoogleDriveStorage {
293
319
  return null;
294
320
  }
295
321
  }
296
- /**
297
- * Get folder by folderId, if folderId == null you will have them all
298
- * @param folderId [Optional]
299
- * @returns
300
- */
301
322
  async findFolders(folderId) {
302
323
  const cacheKey = folderId || 'root';
303
- if (this.folderCache[cacheKey]) {
304
- return this.folderCache[cacheKey];
324
+ if (GoogleDriveStorage.folderCache[cacheKey]) {
325
+ return GoogleDriveStorage.folderCache[cacheKey];
305
326
  }
306
327
  const query = folderId
307
328
  ? `'${folderId}' in parents and mimeType='application/vnd.google-apps.folder'`
308
329
  : `'root' in parents and mimeType='application/vnd.google-apps.folder'`;
309
330
  const folders = await this.searchFiles(query);
310
- this.folderCache[cacheKey] = folders;
331
+ GoogleDriveStorage.folderCache[cacheKey] = folders;
311
332
  return folders;
312
333
  }
313
- /**
314
- * Get all files content for the specified type ('KEYPAIRs' | 'VCs' | 'SESSIONs' | 'DIDs' | 'RECOMMENDATIONs')
315
- * @param type
316
- * @returns
317
- */
318
334
  async getAllFilesByType(type) {
319
335
  try {
320
- if (!this.folderCache['Credentials']) {
336
+ if (!GoogleDriveStorage.folderCache['Credentials']) {
321
337
  const rootFolders = await this.findFolders();
322
- this.folderCache['Credentials'] = rootFolders;
338
+ GoogleDriveStorage.folderCache['Credentials'] = rootFolders;
323
339
  }
324
- const credentialsFolder = this.folderCache['Credentials'].find((f) => f.name === 'Credentials');
340
+ const credentialsFolder = GoogleDriveStorage.folderCache['Credentials'].find((f) => f.name === 'Credentials');
325
341
  if (!credentialsFolder) {
326
342
  console.error('Credentials folder not found.');
327
343
  return [];
328
344
  }
329
345
  if (type === 'VCs') {
330
- if (!this.folderCache['VCs']) {
346
+ if (!GoogleDriveStorage.folderCache['VCs']) {
331
347
  const vcSubfolder = await this.findFolders(credentialsFolder.id);
332
348
  const vcsFolder = vcSubfolder.find((f) => f.name === 'VCs');
333
349
  const vcSubFolders = await this.findFolders(vcsFolder.id);
334
- this.folderCache['VCs'] = vcSubFolders.filter((folder) => folder.name.startsWith('VC-'));
350
+ GoogleDriveStorage.folderCache['VCs'] = vcSubFolders.filter((folder) => folder.name.startsWith('VC-'));
335
351
  }
336
- const vcSubfolders = this.folderCache['VCs'];
352
+ const vcSubfolders = GoogleDriveStorage.folderCache['VCs'];
337
353
  if (!vcSubfolders.length) {
338
354
  console.error(`No subfolders found for type: ${type}`);
339
355
  return [];
340
356
  }
341
- const allFilesNested = await Promise.all(vcSubfolders.map(async (folder) => await this.findFilesUnderFolder(folder.id)));
357
+ const allFilesNested = await Promise.all(vcSubfolders.map(async (folder) => await this.findFolderFiles(folder.id)));
342
358
  const allVcJsonFiles = allFilesNested.flat().filter((file) => file.mimeType === 'application/json');
343
359
  const fileContentsResults = await Promise.allSettled(allVcJsonFiles.map((file) => this.retrieve(file.id)));
344
360
  const validFileContents = fileContentsResults.filter((result) => result.status === 'fulfilled').map((result) => result.value);
345
361
  return validFileContents.filter((file) => file.data.fileName !== 'RELATIONS');
346
362
  }
347
- if (!this.folderCache[type]) {
363
+ if (!GoogleDriveStorage.folderCache[type]) {
348
364
  const subfolders = await this.findFolders(credentialsFolder.id);
349
365
  const targetFolder = subfolders.find((f) => f.name === type);
350
- this.folderCache[type] = targetFolder ? targetFolder.id : null;
366
+ GoogleDriveStorage.folderCache[type] = targetFolder ? targetFolder.id : null;
351
367
  }
352
- const targetFolderId = this.folderCache[type];
368
+ const targetFolderId = GoogleDriveStorage.folderCache[type];
353
369
  if (!targetFolderId) {
354
370
  console.error(`Folder for type ${type} not found.`);
355
371
  return [];
@@ -369,70 +385,52 @@ export class GoogleDriveStorage {
369
385
  return [];
370
386
  }
371
387
  }
372
- /**
373
- * Update the name of a file in Google Drive
374
- * @param fileId - The ID of the file to update
375
- * @param newFileName - The new name for the file
376
- * @returns The updated file metadata, including the new name
377
- */
378
- async updateFileName(fileId, newFileName) {
388
+ async updateFileData(fileId, data) {
379
389
  try {
380
- const metadata = { name: newFileName };
390
+ const updateUrl = `https://www.googleapis.com/drive/v3/files/${fileId}`;
381
391
  const updatedFile = await this.fetcher({
382
392
  method: 'PATCH',
383
393
  headers: { 'Content-Type': 'application/json' },
384
- body: JSON.stringify(metadata),
385
- url: `https://www.googleapis.com/drive/v3/files/${fileId}`,
394
+ body: JSON.stringify({ name: data.fileName }),
395
+ url: updateUrl,
386
396
  });
387
- console.log('File name updated successfully:', updatedFile.name);
397
+ console.log('File renamed successfully:', updatedFile);
388
398
  return updatedFile;
389
399
  }
390
400
  catch (error) {
391
- console.error('Error updating file name:', error.message);
392
401
  throw error;
393
402
  }
394
403
  }
395
- async findFileByName(name) {
396
- const rootFolders = await this.findFolders();
397
- const credentialsFolderId = rootFolders.find((f) => f.name === 'Credentials')?.id;
398
- if (!credentialsFolderId)
399
- throw new Error('Credentials folder not found');
400
- const files = await this.searchFiles(`'${credentialsFolderId}' in parents and name='${name}'`);
401
- return files[0];
402
- }
403
- async findFilesUnderFolder(folderId) {
404
- if (!folderId)
405
- throw new Error('Folder ID is required');
406
- const files = await this.searchFiles(`'${folderId}' in parents`);
407
- if (files.length === 0) {
408
- console.log('No files found in the folder.');
409
- return [];
410
- }
411
- const filesWithContent = await Promise.all(files.map(async (file) => {
412
- try {
413
- const content = await this.getFileContent(file.id);
414
- return { ...file, content };
415
- }
416
- catch (error) {
417
- console.error(`Error fetching content for file "${file.name}" (ID: ${file.id}):`, error);
418
- return { ...file, content: null };
419
- }
420
- }));
421
- return filesWithContent;
422
- }
423
- async updateFileData(fileId, data) {
404
+ /**
405
+ * Update the content of an existing file in Google Drive
406
+ * @param fileId - The ID of the file to update
407
+ * @param data - The new content for the file
408
+ * @returns The updated file metadata
409
+ */
410
+ async updateFileContent({ fileId, data }) {
424
411
  try {
425
- const updateUrl = `https://www.googleapis.com/drive/v3/files/${fileId}`;
426
- const updatedFile = await this.fetcher({
412
+ if (!fileId) {
413
+ throw new Error('File ID is required to update a file.');
414
+ }
415
+ // Convert data to JSON blob
416
+ const fileBlob = new Blob([JSON.stringify(data)], { type: 'application/json' });
417
+ // Update the file content using media upload
418
+ // Note: When using uploadType=media, the response is the updated file resource
419
+ const response = await this.fetcher({
427
420
  method: 'PATCH',
428
- headers: { 'Content-Type': 'application/json' },
429
- body: JSON.stringify({ name: data.fileName }),
430
- url: updateUrl,
421
+ headers: {
422
+ 'Content-Type': 'application/json'
423
+ },
424
+ body: fileBlob,
425
+ url: `https://www.googleapis.com/upload/drive/v3/files/${fileId}?uploadType=media`,
431
426
  });
432
- console.log('✅ File renamed successfully:', updatedFile);
433
- return updatedFile;
427
+ console.log(`✅ File content updated successfully: ${fileId}`);
428
+ // Return a consistent response format with id and data
429
+ // The response from media upload might be the file metadata or empty
430
+ return { id: fileId, data, ...response };
434
431
  }
435
432
  catch (error) {
433
+ console.error('Error updating file content:', error);
436
434
  throw error;
437
435
  }
438
436
  }
@@ -460,12 +458,10 @@ export class GoogleDriveStorage {
460
458
  return updateResponse;
461
459
  }
462
460
  async createRelationsFile({ vcFolderId }) {
463
- const files = await this.findFilesUnderFolder(vcFolderId);
461
+ const files = await this.findFolderFiles(vcFolderId);
464
462
  const vcFile = files.find((file) => file.name === 'VC');
465
463
  const vcContent = await this.getFileContent(vcFile.id);
466
- console.log('🚀 ~ GoogleDriveStorage ~ createRelationsFile ~ vcContent:', vcContent);
467
464
  const subject = JSON.parse(vcContent.body).credentialSubject;
468
- console.log('🚀 ~ GoogleDriveStorage ~ createRelationsFile ~ subject:', subject);
469
465
  const relationsFile = await this.saveFile({
470
466
  data: {
471
467
  fileName: 'RELATIONS',
@@ -483,66 +479,6 @@ export class GoogleDriveStorage {
483
479
  await this.updateFileIdsJson(relationsFile.id);
484
480
  return relationsFile;
485
481
  }
486
- async updateResumeRelation({ authorFolderId, draftFileId, signedFileId, }) {
487
- try {
488
- const relationFileName = 'relations.json';
489
- // Step 1: Check if `relations.json` exists in RESUMES_AUTHOR/
490
- const existingRelationFiles = await this.searchFiles(`name='${relationFileName}' and '${authorFolderId}' in parents`);
491
- let relationFileId = null;
492
- let existingRelations = {};
493
- if (existingRelationFiles.length > 0) {
494
- relationFileId = existingRelationFiles[0].id;
495
- existingRelations = await this.getFileContent(relationFileId);
496
- }
497
- else {
498
- console.log('relations.json does not exist. Will create a new one.');
499
- }
500
- // Step 2: Update relations object
501
- existingRelations[draftFileId] = signedFileId;
502
- // Step 3: Create or update the file on Drive
503
- const fileBlob = new Blob([JSON.stringify(existingRelations, null, 2)], {
504
- type: 'application/json',
505
- });
506
- const formData = new FormData();
507
- const metadata = {
508
- name: relationFileName,
509
- parents: [authorFolderId],
510
- mimeType: 'application/json',
511
- };
512
- formData.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));
513
- formData.append('file', fileBlob);
514
- let uploadedFile;
515
- if (relationFileId) {
516
- // Update existing file
517
- uploadedFile = await this.fetcher({
518
- method: 'PATCH',
519
- headers: {},
520
- body: formData,
521
- url: `https://www.googleapis.com/upload/drive/v3/files/${relationFileId}?uploadType=multipart&fields=id,parents`,
522
- });
523
- }
524
- else {
525
- // Create new file
526
- uploadedFile = await this.fetcher({
527
- method: 'POST',
528
- headers: {},
529
- body: formData,
530
- url: `https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,parents`,
531
- });
532
- }
533
- console.log(`✅ Resume relation updated. File ID: ${uploadedFile.id}`);
534
- return uploadedFile;
535
- }
536
- catch (error) {
537
- console.error('❌ Failed to update resume relation:', error);
538
- throw error;
539
- }
540
- }
541
- /**
542
- * Delete file by id
543
- * @param id
544
- * @returns
545
- */
546
482
  async delete(id) {
547
483
  try {
548
484
  const response = await this.fetcher({
@@ -558,94 +494,6 @@ export class GoogleDriveStorage {
558
494
  return null;
559
495
  }
560
496
  }
561
- async update(fileId, data) {
562
- const metadata = {
563
- name: data.fileName || 'resume.json',
564
- mimeType: 'application/json',
565
- };
566
- const uploadUrl = `https://www.googleapis.com/upload/drive/v3/files/${fileId}?uploadType=multipart`;
567
- const formData = new FormData();
568
- formData.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));
569
- formData.append('file', new Blob([JSON.stringify(data.body)], { type: 'application/json' }));
570
- try {
571
- const response = await this.fetcher({
572
- method: 'PATCH',
573
- headers: {},
574
- body: formData,
575
- url: `${uploadUrl}&fields=id,name,mimeType`,
576
- });
577
- console.log('✅ File updated successfully:', response);
578
- return response;
579
- }
580
- catch (error) {
581
- console.error('❌ Error updating Google Drive file:', error);
582
- throw error;
583
- }
584
- }
585
- async getFileIdsFromAppDataFolder() {
586
- try {
587
- const constructUrl = () => {
588
- const baseUrl = 'https://www.googleapis.com/drive/v3/files';
589
- const queryParams = new URLSearchParams({
590
- spaces: 'appDataFolder',
591
- q: "name='file_ids.json'",
592
- fields: 'files(id)',
593
- });
594
- return `${baseUrl}?${queryParams.toString()}`;
595
- };
596
- // Step 1: Search for the file_ids.json file in the appDataFolder
597
- const response = await this.fetcher({
598
- method: 'GET',
599
- headers: {},
600
- url: constructUrl(),
601
- });
602
- console.log(': GoogleDriveStorage getFileIdsFromAppDataFolder response', response);
603
- // Step 2: Check if the file exists
604
- if (!response.files || response.files.length === 0) {
605
- console.log('No file_ids.json found in appDataFolder.');
606
- return [];
607
- }
608
- // Step 3: Get the file ID of file_ids.json
609
- const fileId = response.files[0].id;
610
- console.log(': GoogleDriveStorage getFileIdsFromAppDataFolder fileId', fileId);
611
- // Step 4: Fetch the content of file_ids.json
612
- const fileContent = await this.fetcher({
613
- method: 'GET',
614
- headers: {},
615
- url: `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`,
616
- });
617
- console.log(': GoogleDriveStorage getFileIdsFromAppDataFolder fileContent', fileContent);
618
- // Step 5: Parse the file content (array of file IDs)
619
- const fileIds = fileContent;
620
- console.log(': GoogleDriveStorage getFileIdsFromAppDataFolder fileIds', fileIds);
621
- return fileIds;
622
- }
623
- catch (error) {
624
- console.error('Error fetching file IDs from appDataFolder:', error.message);
625
- return [];
626
- }
627
- }
628
- async getAllFilesData() {
629
- try {
630
- // Step 1: Get the file IDs from appDataFolder
631
- const fileIds = await this.getFileIdsFromAppDataFolder();
632
- if (fileIds.length === 0) {
633
- console.log('No files found.');
634
- return [];
635
- }
636
- // Step 2: Return the array of file IDs
637
- return fileIds;
638
- }
639
- catch (error) {
640
- console.error('Error fetching all files data:', error.message);
641
- return [];
642
- }
643
- }
644
- /**
645
- * Check if an email VC exists and return its content
646
- * @param email - The email address to check
647
- * @returns {Promise<{data: any, id: string} | null>} - The email VC content and ID if exists, null otherwise
648
- */
649
497
  async checkEmailExists(email) {
650
498
  try {
651
499
  // Get root folders
@@ -61,15 +61,27 @@ export class StorageHandler {
61
61
  if (!folder) {
62
62
  throw new Error(`${folderName} folder not found`);
63
63
  }
64
- return this.storage.findFilesUnderFolder(folder.id);
64
+ return this.storage.findFolderFiles(folder.id);
65
65
  }
66
66
  }
67
67
  export class Resume extends StorageHandler {
68
68
  constructor(storage) {
69
69
  super(storage);
70
70
  }
71
- async saveResume({ resume, type }) {
71
+ async saveResume({ resume, type, id }) {
72
72
  try {
73
+ // If an ID is provided, update the existing resume
74
+ if (id) {
75
+ console.log(`🔄 Updating existing ${type} resume with ID: ${id}`);
76
+ // Update the file content directly
77
+ const updatedResume = await this.storage.updateFileContent({
78
+ fileId: id,
79
+ data: resume
80
+ });
81
+ // Return the updated resume with its ID
82
+ return { ...updatedResume, id };
83
+ }
84
+ // For new resumes, create folders and save as before
73
85
  let rootFolder = await this.getOrCreateFolder(resumeFolderTypes.root, 'root');
74
86
  console.log('🚀 ~ Resume ~ saveResume ~ rootFolder:', rootFolder);
75
87
  // Get or create the subfolder
@@ -106,7 +118,7 @@ export class Resume extends StorageHandler {
106
118
  // Find or create the signed resumes folder
107
119
  const signedFolder = await this.getOrCreateFolder(resumeFolderTypes.signed, rootFolder.id);
108
120
  // Retrieve all files from the signed folder
109
- const files = await this.storage.findFilesUnderFolder(signedFolder.id);
121
+ const files = await this.storage.findFolderFiles(signedFolder.id);
110
122
  return files;
111
123
  }
112
124
  catch (error) {
@@ -120,7 +132,7 @@ export class Resume extends StorageHandler {
120
132
  // Find or create the non-signed resumes folder
121
133
  const nonSignedFolder = await this.getOrCreateFolder(resumeFolderTypes.nonSigned, rootFolder.id);
122
134
  // Retrieve all files from the non-signed folder
123
- const files = await this.storage.findFilesUnderFolder(nonSignedFolder.id);
135
+ const files = await this.storage.findFolderFiles(nonSignedFolder.id);
124
136
  return files;
125
137
  }
126
138
  catch (error) {