@cooperation/vc-storage 1.0.13 → 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,3 +2,4 @@ export * from './models/GoogleDriveStorage.js';
2
2
  export * from './models/CredentialEngine.js';
3
3
  export * from './utils/google.js';
4
4
  export * from './utils/presentation.js';
5
+ export * from './models/Resume.js';
@@ -51,6 +51,22 @@ export class GoogleDriveStorage {
51
51
  throw error;
52
52
  }
53
53
  }
54
+ async getFileContent(fileId) {
55
+ const url = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`;
56
+ try {
57
+ const response = await this.fetcher({
58
+ method: 'GET',
59
+ headers: {}, // Add additional headers if required
60
+ url,
61
+ });
62
+ console.log(`Content fetched for file ID: ${fileId}`);
63
+ return response; // This could be text, JSON, or binary, depending on the file type
64
+ }
65
+ catch (error) {
66
+ console.error(`Error fetching content for file ID: ${fileId}:`, error.message);
67
+ throw new Error(`Failed to fetch content for file ID: ${fileId}`);
68
+ }
69
+ }
54
70
  async searchFiles(query) {
55
71
  const result = await this.fetcher({
56
72
  method: 'GET',
@@ -63,11 +79,14 @@ export class GoogleDriveStorage {
63
79
  }
64
80
  return result.files;
65
81
  }
66
- async createFolder(folderName, parentFolderId) {
82
+ async createFolder({ folderName, parentFolderId }) {
83
+ if (!parentFolderId) {
84
+ throw new Error(`Parent folder ID must be provided when creating folder "${folderName}".`);
85
+ }
67
86
  const metadata = {
68
87
  name: folderName,
69
88
  mimeType: 'application/vnd.google-apps.folder',
70
- parents: parentFolderId ? [parentFolderId] : [],
89
+ parents: [parentFolderId], // Explicitly associate with the parent folder
71
90
  };
72
91
  const folder = await this.fetcher({
73
92
  method: 'POST',
@@ -75,22 +94,35 @@ export class GoogleDriveStorage {
75
94
  body: JSON.stringify(metadata),
76
95
  url: 'https://www.googleapis.com/drive/v3/files',
77
96
  });
78
- console.log('Folder ID:', folder.id);
79
- return folder.id;
97
+ console.log(`Folder created: "${folderName}" with ID: ${folder.id}, Parent: ${parentFolderId}`);
98
+ return folder;
80
99
  }
81
100
  async saveFile({ data, folderId }) {
82
101
  try {
102
+ if (!folderId) {
103
+ throw new Error('Folder ID is required to save a file.');
104
+ }
83
105
  // Define file metadata, ensure correct folder is assigned
84
106
  const fileMetadata = {
85
107
  name: data.fileName,
86
108
  parents: [folderId], // Specify the folder ID
87
- mimeType: data.mimeType,
109
+ mimeType: data.mimeType || 'application/json',
88
110
  };
111
+ // make sure the parentId is not in trash
112
+ const folder = await this.fetcher({
113
+ method: 'GET',
114
+ headers: {},
115
+ url: `https://www.googleapis.com/drive/v3/files/${folderId}?fields=trashed`,
116
+ });
117
+ if (folder.trashed) {
118
+ throw new Error('Parent folder is in trash');
119
+ }
89
120
  let uploadUrl = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart';
90
121
  const formData = new FormData();
91
122
  formData.append('metadata', new Blob([JSON.stringify(fileMetadata)], { type: 'application/json' }));
92
123
  formData.append('file', new Blob([data.body], { type: fileMetadata.mimeType })); // Set file data and MIME type
93
124
  // Upload file to Google Drive
125
+ console.log('Uploading file...');
94
126
  const file = await this.fetcher({
95
127
  method: 'POST',
96
128
  headers: {},
@@ -109,8 +141,6 @@ export class GoogleDriveStorage {
109
141
  headers: {},
110
142
  body: JSON.stringify(permissionData),
111
143
  });
112
- console.log('Permission set to public for file:', file.id);
113
- console.log('Parent folder IDs:', file.parents);
114
144
  return file;
115
145
  }
116
146
  catch (error) {
@@ -283,18 +313,6 @@ export class GoogleDriveStorage {
283
313
  return await this.retrieve(file.id);
284
314
  }));
285
315
  }));
286
- // for (const folder of vcSubfolders) {
287
- // const files = await this.findFilesUnderFolder(folder.id);
288
- // // Fetch the content of each file
289
- // for (const file of files) {
290
- // try {
291
- // const content = await this.retrieve(file.id);
292
- // fileContents.push(content);
293
- // } catch (error) {
294
- // console.error(`Error retrieving content for file ${file.id}:`, error);
295
- // }
296
- // }
297
- // }
298
316
  return fileContents;
299
317
  }
300
318
  // Step 3: Generic handling for other types
@@ -358,8 +376,24 @@ export class GoogleDriveStorage {
358
376
  if (!folderId)
359
377
  throw new Error('Folder ID is required');
360
378
  console.log('🚀 ~ GoogleDriveStorage ~ findFilesUnderFolder ~ folderId', folderId);
379
+ // Fetch files under the folder
361
380
  const files = await this.searchFiles(`'${folderId}' in parents`);
362
- return files;
381
+ if (files.length === 0) {
382
+ console.log('No files found in the folder.');
383
+ return [];
384
+ }
385
+ // Fetch content for each file
386
+ const filesWithContent = await Promise.all(files.map(async (file) => {
387
+ try {
388
+ const content = await this.getFileContent(file.id);
389
+ return { ...file, content }; // Merge file metadata with its content
390
+ }
391
+ catch (error) {
392
+ console.error(`Error fetching content for file "${file.name}" (ID: ${file.id}):`, error);
393
+ return { ...file, content: null }; // Handle errors gracefully
394
+ }
395
+ }));
396
+ return filesWithContent;
363
397
  }
364
398
  async updateFileData(fileId, data) {
365
399
  const fileMetadata = {
@@ -0,0 +1,134 @@
1
+ export const resumeFolderTypes = {
2
+ root: 'RESUMES_AUTHOR',
3
+ nonSigned: 'NON_SIGNED_RESUMES',
4
+ signed: 'SIGNED_RESUMES',
5
+ };
6
+ export class StorageHandler {
7
+ storage;
8
+ constructor(storage) {
9
+ this.storage = storage;
10
+ }
11
+ async getOrCreateFolder(folderName, parentId) {
12
+ console.log(`Searching for folder: "${folderName}", Parent ID: ${parentId}`);
13
+ const folders = await this.storage.findFolders(parentId); // Fetch all child folders of the parent
14
+ let folder = folders.find((folder) => {
15
+ console.log('🚀 ~ StorageHandler ~ getOrCreateFolder ~ folder:', folder);
16
+ return folder.name === folderName;
17
+ });
18
+ if (folder && folder.name === 'RESUMES_AUTHOR') {
19
+ console.log('🚀 ~ StorageHandler ~ getOrCreateFolder ~ folder:', folder);
20
+ }
21
+ if (!folder) {
22
+ console.log(`Folder "${folderName}" not found. Creating under parent: ${parentId}`);
23
+ folder = await this.storage.createFolder({
24
+ folderName,
25
+ parentFolderId: parentId,
26
+ });
27
+ }
28
+ console.log(`Resolved folder: "${folderName}" with ID: ${folder.id}`);
29
+ return folder;
30
+ }
31
+ async findFilesInFolder(folderName) {
32
+ const folders = await this.storage.findFolders();
33
+ const folder = folders.find((folder) => folder.name === folderName);
34
+ if (!folder) {
35
+ throw new Error(`${folderName} folder not found`);
36
+ }
37
+ return this.storage.findFilesUnderFolder(folder.id);
38
+ }
39
+ }
40
+ export class Resume extends StorageHandler {
41
+ constructor(storage) {
42
+ super(storage);
43
+ }
44
+ signResume({ resume }) {
45
+ // genetrate unsingned resume
46
+ // sign resume
47
+ }
48
+ async saveResume({ resume, type }) {
49
+ try {
50
+ // Get or create the root folder
51
+ console.log('Checking for root folder...');
52
+ const rootFolders = await this.storage.findFolders();
53
+ let rootFolder = rootFolders.find((folder) => folder.name === resumeFolderTypes.root);
54
+ if (!rootFolder) {
55
+ console.log('Root folder not found. Creating...');
56
+ rootFolder = await this.storage.createFolder({ folderName: resumeFolderTypes.root, parentFolderId: 'root' });
57
+ }
58
+ console.log('🚀 Root folder resolved:', rootFolder);
59
+ // Get or create the subfolder
60
+ const subFolderName = type === 'sign' ? resumeFolderTypes.signed : resumeFolderTypes.nonSigned;
61
+ const subFolder = await this.getOrCreateFolder(subFolderName, rootFolder.id);
62
+ console.log(`🚀 Subfolder resolved for type "${type}":`, subFolder);
63
+ // Save the file in the subfolder
64
+ console.log(`Saving file in subfolder "${subFolderName}"...`);
65
+ const savedResume = await this.storage.saveFile({
66
+ folderId: subFolder.id, // Ensure this points to the subfolder
67
+ data: resume,
68
+ });
69
+ console.log(`🚀 File saved in folder "${subFolderName}" (ID: ${subFolder.id}):`, savedResume);
70
+ return savedResume;
71
+ }
72
+ catch (error) {
73
+ throw new Error(`Error while saving ${type} resume: ${error.message}`);
74
+ }
75
+ }
76
+ async find() {
77
+ try {
78
+ const signedResumes = await this.getSignedResumes();
79
+ const nonSignedResumes = await this.getNonSignedResumes();
80
+ return {
81
+ signed: signedResumes,
82
+ nonSigned: nonSignedResumes,
83
+ };
84
+ }
85
+ catch (error) {
86
+ throw new Error('Error while fetching resume: ' + error.message);
87
+ }
88
+ }
89
+ async getSignedResumes() {
90
+ try {
91
+ // Find the root folder first
92
+ const rootFolder = await this.findRootFolder();
93
+ // Find or create the signed resumes folder
94
+ const signedFolder = await this.getOrCreateFolder(resumeFolderTypes.signed, rootFolder.id);
95
+ // Retrieve all files from the signed folder
96
+ const files = await this.storage.findFilesUnderFolder(signedFolder.id);
97
+ console.log(`Files found in "SIGNED_RESUMES":`, files);
98
+ return files;
99
+ }
100
+ catch (error) {
101
+ throw new Error('Error while fetching signed resumes: ' + error.message);
102
+ }
103
+ }
104
+ async getNonSignedResumes() {
105
+ try {
106
+ // Find the root folder first
107
+ const rootFolder = await this.findRootFolder();
108
+ console.log('🚀 ~ Resume ~ getNonSignedResumes ~ rootFolder:', rootFolder);
109
+ // Find or create the non-signed resumes folder
110
+ const nonSignedFolder = await this.getOrCreateFolder(resumeFolderTypes.nonSigned, rootFolder.id);
111
+ console.log('🚀 ~ Resume ~ getNonSignedResumes ~ nonSignedFolder:', nonSignedFolder);
112
+ // Retrieve all files from the non-signed folder
113
+ const files = await this.storage.findFilesUnderFolder(nonSignedFolder.id);
114
+ console.log(`Files found in "NON_SIGNED_RESUMES":`, files);
115
+ return files;
116
+ }
117
+ catch (error) {
118
+ throw new Error('Error while fetching non-signed resumes: ' + error.message);
119
+ }
120
+ }
121
+ async findRootFolder() {
122
+ console.log('Searching for the root folder...');
123
+ const rootFolders = await this.storage.findFolders(); // Fetch all root-level folders
124
+ const rootFolder = rootFolders.find((folder) => folder.name === resumeFolderTypes.root);
125
+ if (!rootFolder) {
126
+ throw new Error(`Root folder "${resumeFolderTypes.root}" not found in the root directory.`);
127
+ }
128
+ console.log('Root folder found:', rootFolder);
129
+ return rootFolder;
130
+ }
131
+ generarteUnsignedResume() { }
132
+ isResumeFolderExist() { }
133
+ }
134
+ export default Resume;
@@ -2,3 +2,4 @@ export * from './models/GoogleDriveStorage.js';
2
2
  export * from './models/CredentialEngine.js';
3
3
  export * from './utils/google.js';
4
4
  export * from './utils/presentation.js';
5
+ export * from './models/Resume.js';
@@ -1,4 +1,4 @@
1
- import { DataToSaveI, FilesType } from '../../types';
1
+ import { DataToSaveI } from '../../types';
2
2
  interface FileContent {
3
3
  name: string;
4
4
  content: any;
@@ -23,10 +23,19 @@ export declare class GoogleDriveStorage {
23
23
  private accessToken;
24
24
  constructor(accessToken: string);
25
25
  private fetcher;
26
+ private getFileContent;
26
27
  private searchFiles;
27
- createFolder(folderName: string, parentFolderId?: string): Promise<string>;
28
+ createFolder({ folderName, parentFolderId }: {
29
+ folderName: string;
30
+ parentFolderId: string;
31
+ }): Promise<{
32
+ id: string;
33
+ name: string;
34
+ mimeType: string;
35
+ parents: string[];
36
+ }>;
28
37
  saveFile({ data, folderId }: {
29
- data: DataToSaveI;
38
+ data: any;
30
39
  folderId: string;
31
40
  }): Promise<any>;
32
41
  /**
@@ -64,7 +73,7 @@ export declare class GoogleDriveStorage {
64
73
  * @returns The updated file metadata, including the new name
65
74
  */
66
75
  updateFileName(fileId: string, newFileName: string): Promise<any>;
67
- findFileByName(name: FilesType): Promise<any>;
76
+ findFileByName(name: string): Promise<any>;
68
77
  findFilesUnderFolder(folderId: string): Promise<any[]>;
69
78
  updateFileData(fileId: string, data: DataToSaveI): Promise<any>;
70
79
  getFileParents(fileId: string): Promise<any>;
@@ -0,0 +1,32 @@
1
+ import { GoogleDriveStorage } from './GoogleDriveStorage';
2
+ export declare const resumeFolderTypes: {
3
+ root: string;
4
+ nonSigned: string;
5
+ signed: string;
6
+ };
7
+ export declare class StorageHandler {
8
+ protected storage: GoogleDriveStorage;
9
+ constructor(storage: GoogleDriveStorage);
10
+ protected getOrCreateFolder(folderName: string, parentId: string): Promise<any>;
11
+ protected findFilesInFolder(folderName: string): Promise<any[]>;
12
+ }
13
+ export declare class Resume extends StorageHandler {
14
+ constructor(storage: GoogleDriveStorage);
15
+ signResume({ resume }: {
16
+ resume: any;
17
+ }): void;
18
+ saveResume({ resume, type }: {
19
+ resume: any;
20
+ type: 'sign' | 'unsigned';
21
+ }): Promise<any>;
22
+ find(): Promise<{
23
+ signed: any[];
24
+ nonSigned: any[];
25
+ }>;
26
+ getSignedResumes(): Promise<any[]>;
27
+ getNonSignedResumes(): Promise<any[]>;
28
+ private findRootFolder;
29
+ private generarteUnsignedResume;
30
+ private isResumeFolderExist;
31
+ }
32
+ export default Resume;
@@ -1,6 +1,6 @@
1
1
  import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-key-2020';
2
- import crypto from 'crypto';
3
2
  import { v4 as uuidv4 } from 'uuid';
3
+ import CryptoJS from 'crypto-js';
4
4
  /**
5
5
  * Utility function to generate a hashed ID for a credential.
6
6
  * Excludes the `id` field when hashing.
@@ -11,7 +11,7 @@ function generateHashedId(credential) {
11
11
  // Exclude the `id` field from the hash
12
12
  const credentialWithoutId = { ...credential, id: undefined };
13
13
  const serialized = JSON.stringify(credentialWithoutId);
14
- return crypto.createHash('sha256').update(serialized).digest('hex');
14
+ return CryptoJS.SHA256(serialized).toString(CryptoJS.enc.Hex);
15
15
  }
16
16
  /**
17
17
  * Create a DID document using the provided key pair.
@@ -34,26 +34,22 @@ export async function saveToGoogleDrive({ storage, data, type }) {
34
34
  let credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
35
35
  let credentialsFolderId;
36
36
  if (!credentialsFolder) {
37
- credentialsFolderId = await storage.createFolder('Credentials');
38
- }
39
- else {
40
- credentialsFolderId = credentialsFolder.id;
37
+ credentialsFolder = await storage.createFolder({ folderName: 'Credentials', parentFolderId: 'root' });
41
38
  }
39
+ credentialsFolderId = credentialsFolder.id;
42
40
  // Get subfolders within the "Credentials" folder
43
41
  const subfolders = await storage.findFolders(credentialsFolderId);
44
42
  // Find or create the specific subfolder (DIDs or VCs)
45
43
  let typeFolder = subfolders.find((f) => f.name === `${type}s`);
46
44
  let typeFolderId;
47
45
  if (!typeFolder) {
48
- typeFolderId = await storage.createFolder(`${type}s`, credentialsFolderId);
49
- }
50
- else {
51
- typeFolderId = typeFolder.id;
46
+ typeFolder = await storage.createFolder({ folderName: `${type}s`, parentFolderId: credentialsFolderId });
52
47
  }
48
+ typeFolderId = typeFolder.id;
53
49
  if (type === 'VC') {
54
50
  // save the data in Credentials/VCs/VC-timestamp/vc.json
55
- const vcFolderId = await storage.createFolder(`${fileData.fileName}-${Date.now()}`, typeFolderId);
56
- const file = await storage.saveFile({ data: fileData, folderId: vcFolderId });
51
+ const vcFolder = await storage.createFolder({ folderName: `${fileData.fileName}-${Date.now()}`, parentFolderId: typeFolderId });
52
+ const file = await storage.saveFile({ data: fileData, folderId: vcFolder.id });
57
53
  console.log(`File uploaded: ${file?.id} under ${fileData.fileName} folder in VCs folder`);
58
54
  return file;
59
55
  }
@@ -78,22 +74,17 @@ export async function uploadImageToGoogleDrive(storage, imageFile) {
78
74
  try {
79
75
  const rootFolders = await storage.findFolders();
80
76
  let credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
81
- let credentialsFolderId;
82
77
  if (!credentialsFolder) {
83
- credentialsFolderId = await storage.createFolder('Credentials');
78
+ console.log('Credentials folder not found. Creating...');
79
+ credentialsFolder = await storage.createFolder({ folderName: 'Credentials', parentFolderId: 'root' });
84
80
  }
85
- else {
86
- credentialsFolderId = credentialsFolder.id;
87
- }
88
- const subfolders = await storage.findFolders(credentialsFolderId);
81
+ const credentialsFolderId = credentialsFolder.id;
82
+ const subfolders = await storage.findFolders(credentialsFolder.id);
89
83
  let mediasFolder = subfolders.find((f) => f.name === 'MEDIAs');
90
- let mediasFolderId;
91
84
  if (!mediasFolder) {
92
- mediasFolderId = await storage.createFolder('MEDIAs', credentialsFolderId);
93
- }
94
- else {
95
- mediasFolderId = mediasFolder.id;
85
+ mediasFolder = await storage.createFolder({ folderName: 'MEDIAs', parentFolderId: credentialsFolderId });
96
86
  }
87
+ const mediasFolderId = mediasFolder.id;
97
88
  // Prepare the image file data
98
89
  const imageData = {
99
90
  fileName: imageFile.name,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cooperation/vc-storage",
3
3
  "type": "module",
4
- "version": "1.0.13",
4
+ "version": "1.0.14",
5
5
  "description": "Sign and store your verifiable credentials.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/types/index.d.ts",
@@ -20,6 +20,7 @@
20
20
  "@digitalbazaar/ed25519-signature-2020": "^5.3.0",
21
21
  "@digitalbazaar/ed25519-verification-key-2020": "^4.1.0",
22
22
  "@digitalbazaar/vc": "^6.3.0",
23
+ "crypto-js": "^4.2.0",
23
24
  "ethers": "^6.13.2",
24
25
  "ts-node": "^10.9.2",
25
26
  "tsc": "^2.0.4",