@cooperation/vc-storage 1.0.32 → 1.0.34

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,7 +2,7 @@ import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-
2
2
  import { Ed25519Signature2020 } from '@digitalbazaar/ed25519-signature-2020';
3
3
  import * as dbVc from '@digitalbazaar/vc';
4
4
  import { v4 as uuidv4 } from 'uuid';
5
- import { extractKeyPairFromCredential, generateDIDSchema, generateUnsignedRecommendation, generateUnsignedVC, } from '../utils/credential.js';
5
+ import { extractKeyPairFromCredential, generateDIDSchema, generateUnsignedEmployment, generateUnsignedPerformanceReview, generateUnsignedRecommendation, generateUnsignedVC, generateUnsignedVolunteering, } from '../utils/credential.js';
6
6
  import { customDocumentLoader } from '../utils/digitalbazaar.js';
7
7
  import { saveToGoogleDrive } from '../utils/google.js';
8
8
  function delay(ms) {
@@ -135,28 +135,39 @@ export class CredentialEngine {
135
135
  * @throws Will throw an error if VC signing fails.
136
136
  */
137
137
  async signVC({ data, type, keyPair, issuerId, vcFileId }) {
138
- let credential = generateUnsignedVC({ formData: data, issuerDid: issuerId });
139
- if (type == 'RECOMMENDATION' && vcFileId) {
140
- console.log('WOW');
141
- credential = generateUnsignedRecommendation({
142
- vcId: vcFileId,
143
- recommendation: data,
144
- issuerDid: issuerId,
145
- });
146
- }
147
- try {
148
- console.log('🚀 ~ CredentialEngine ~ signVC ~ credential:', credential);
149
- if (!credential)
150
- throw new Error('Invalid credential type');
151
- const suite = new Ed25519Signature2020({ key: keyPair, verificationMethod: keyPair.id });
152
- console.log('before');
153
- const signedVC = await dbVc.issue({ credential, suite, documentLoader: customDocumentLoader });
154
- return signedVC;
155
- }
156
- catch (error) {
157
- console.error('Error signing VC:', error);
158
- throw error;
138
+ let credential;
139
+ switch (type) {
140
+ case 'VC':
141
+ credential = generateUnsignedVC({ formData: data, issuerDid: issuerId });
142
+ break;
143
+ case 'RECOMMENDATION':
144
+ if (!vcFileId)
145
+ throw new Error('vcFileId is required for recommendation');
146
+ credential = generateUnsignedRecommendation({ vcId: vcFileId, recommendation: data, issuerDid: issuerId });
147
+ break;
148
+ case 'EMPLOYMENT':
149
+ credential = generateUnsignedEmployment({ formData: data, issuerDid: issuerId });
150
+ break;
151
+ case 'VOLUNTEERING':
152
+ credential = generateUnsignedVolunteering({ formData: data, issuerDid: issuerId });
153
+ break;
154
+ case 'PERFORMANCE_REVIEW':
155
+ credential = generateUnsignedPerformanceReview({ formData: data, issuerDid: issuerId });
156
+ break;
157
+ default:
158
+ throw new Error(`Unsupported credential type: ${type}`);
159
159
  }
160
+ const suite = new Ed25519Signature2020({ key: keyPair, verificationMethod: keyPair.id });
161
+ return dbVc.issue({ credential, suite, documentLoader: customDocumentLoader });
162
+ }
163
+ async signEmploymentCredential(data, keyPair, issuerId) {
164
+ return this.signVC({ data, type: 'EMPLOYMENT', keyPair, issuerId });
165
+ }
166
+ async signVolunteeringCredential(data, keyPair, issuerId) {
167
+ return this.signVC({ data, type: 'VOLUNTEERING', keyPair, issuerId });
168
+ }
169
+ async signPerformanceReviewCredential(data, keyPair, issuerId) {
170
+ return this.signVC({ data, type: 'PERFORMANCE_REVIEW', keyPair, issuerId });
160
171
  }
161
172
  /**
162
173
  * Verify a Verifiable Credential (VC)
@@ -248,6 +259,11 @@ export class CredentialEngine {
248
259
  try {
249
260
  let keyPair;
250
261
  let didDocument;
262
+ // Check if VC already exists
263
+ const existing = await this.storage.checkEmailExists(email);
264
+ if (existing) {
265
+ return { signedVC: existing.data, fileId: existing.id };
266
+ }
251
267
  // Require SEED from environment
252
268
  if (!encodedSeed) {
253
269
  throw new Error('SEED environment variable not set. Cannot generate or use any DID.');
@@ -641,4 +641,40 @@ export class GoogleDriveStorage {
641
641
  return [];
642
642
  }
643
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
+ async checkEmailExists(email) {
650
+ try {
651
+ // Get root folders
652
+ const rootFolders = await this.findFolders();
653
+ // Find Credentials folder
654
+ const credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
655
+ if (!credentialsFolder) {
656
+ console.log('Credentials folder not found');
657
+ return null;
658
+ }
659
+ // Find EMAIL_VC subfolder
660
+ const subfolders = await this.findFolders(credentialsFolder.id);
661
+ const emailVcFolder = subfolders.find((f) => f.name === 'EMAIL_VC');
662
+ if (!emailVcFolder) {
663
+ console.log('EMAIL_VC folder not found');
664
+ return null;
665
+ }
666
+ // Search for file with exact email name (no extension)
667
+ const files = await this.searchFiles(`'${emailVcFolder.id}' in parents and name='${email}' and mimeType='application/json'`);
668
+ if (files.length === 0) {
669
+ return null;
670
+ }
671
+ // Get the content of the email VC
672
+ const emailVC = await this.retrieve(files[0].id);
673
+ return emailVC;
674
+ }
675
+ catch (error) {
676
+ console.error('Error checking email existence:', error);
677
+ return null;
678
+ }
679
+ }
644
680
  }
@@ -11,7 +11,12 @@ async function testEmailVC() {
11
11
  const testEmail = 'test@example.com';
12
12
  console.log('Starting email VC generation test...');
13
13
  console.log('Test email:', testEmail);
14
- const encodedSeed = 'your encoded seed'; // Replace with your actual encoded seed
14
+ // First check if email VC exists
15
+ console.log('\nChecking if email VC exists...');
16
+ const existingVC = await storage.checkEmailExists(testEmail);
17
+ console.log('🚀 ~ testEmailVC ~ existingVC:', existingVC);
18
+ console.log('Existing VC check:', existingVC ? 'Found' : 'Not found');
19
+ const encodedSeed = 'z1AdiEjvNdC18HdruehySWKe4HnsXdUqCXMYPEs1fQ8cY2S'; // Replace with your actual encoded seed
15
20
  // Generate and sign the email VC
16
21
  const result = await engine.generateAndSignEmailVC(testEmail, encodedSeed);
17
22
  console.log('\nTest Results:');
@@ -22,6 +27,19 @@ async function testEmailVC() {
22
27
  console.log('\nRetrieving VC from storage...');
23
28
  const retrievedVC = await storage.retrieve(result.fileId);
24
29
  console.log('Retrieved VC:', retrievedVC ? 'Success' : 'Failed');
30
+ // Test checkEmailExists again after creation
31
+ console.log('\nChecking if email VC exists after creation...');
32
+ const newExistingVC = await storage.checkEmailExists(testEmail);
33
+ console.log('Existing VC check after creation:', newExistingVC ? 'Found' : 'Not found');
34
+ if (newExistingVC) {
35
+ console.log('VC Content:', JSON.stringify(newExistingVC.data, null, 2));
36
+ console.log('VC ID:', newExistingVC.id);
37
+ }
38
+ // Test with non-existent email
39
+ console.log('\nTesting with non-existent email...');
40
+ const nonExistentEmail = 'nonexistent@example.com';
41
+ const nonExistentVC = await storage.checkEmailExists(nonExistentEmail);
42
+ console.log('Non-existent email check:', nonExistentVC ? 'Found (unexpected)' : 'Not found (expected)');
25
43
  console.log('\nTest completed successfully!');
26
44
  }
27
45
  catch (error) {
@@ -1,8 +1,8 @@
1
- import { DidDocument, KeyPair, FormDataI, RecommendationFormDataI, VerifiableCredential } from '../../types/credential.js';
1
+ import { DidDocument, KeyPair, FormDataI, RecommendationFormDataI, VerifiableCredential, EmploymentFormDataI, PerformanceReviewFormDataI, VolunteeringFormDataI } from '../../types/credential.js';
2
2
  import { GoogleDriveStorage } from './GoogleDriveStorage.js';
3
3
  interface SignPropsI {
4
- data: FormDataI | RecommendationFormDataI;
5
- type: 'VC' | 'RECOMMENDATION';
4
+ data: FormDataI | RecommendationFormDataI | EmploymentFormDataI | VolunteeringFormDataI | PerformanceReviewFormDataI;
5
+ type: 'VC' | 'RECOMMENDATION' | 'EMPLOYMENT' | 'VOLUNTEERING' | 'PERFORMANCE_REVIEW';
6
6
  keyPair: KeyPair;
7
7
  issuerId: string;
8
8
  vcFileId?: string;
@@ -59,6 +59,9 @@ export declare class CredentialEngine {
59
59
  * @throws Will throw an error if VC signing fails.
60
60
  */
61
61
  signVC({ data, type, keyPair, issuerId, vcFileId }: SignPropsI): Promise<any>;
62
+ signEmploymentCredential(data: EmploymentFormDataI, keyPair: KeyPair, issuerId: string): Promise<any>;
63
+ signVolunteeringCredential(data: VolunteeringFormDataI, keyPair: KeyPair, issuerId: string): Promise<any>;
64
+ signPerformanceReviewCredential(data: PerformanceReviewFormDataI, keyPair: KeyPair, issuerId: string): Promise<any>;
62
65
  /**
63
66
  * Verify a Verifiable Credential (VC)
64
67
  * @param {object} credential - The Verifiable Credential to verify.
@@ -90,5 +90,14 @@ export declare class GoogleDriveStorage {
90
90
  update(fileId: string, data: any): Promise<any>;
91
91
  getFileIdsFromAppDataFolder(): Promise<any>;
92
92
  getAllFilesData(): Promise<any>;
93
+ /**
94
+ * Check if an email VC exists and return its content
95
+ * @param email - The email address to check
96
+ * @returns {Promise<{data: any, id: string} | null>} - The email VC content and ID if exists, null otherwise
97
+ */
98
+ checkEmailExists(email: string): Promise<{
99
+ data: any;
100
+ id: string;
101
+ } | null>;
93
102
  }
94
103
  export {};
@@ -104,6 +104,79 @@ export declare const inlineResumeContext: {
104
104
  Resume: string;
105
105
  };
106
106
  };
107
+ export declare const employmentCredentialContext: {
108
+ '@context': {
109
+ '@vocab': string;
110
+ fullName: string;
111
+ persons: string;
112
+ credentialName: string;
113
+ credentialDuration: string;
114
+ credentialDescription: string;
115
+ portfolio: {
116
+ '@id': string;
117
+ '@container': string;
118
+ };
119
+ name: string;
120
+ url: string;
121
+ evidenceLink: string;
122
+ evidenceDescription: string;
123
+ company: string;
124
+ role: string;
125
+ };
126
+ };
127
+ export declare const volunteeringCredentialContext: {
128
+ '@context': {
129
+ '@vocab': string;
130
+ fullName: string;
131
+ persons: string;
132
+ volunteerWork: string;
133
+ volunteerOrg: string;
134
+ volunteerDescription: string;
135
+ skillsGained: {
136
+ '@id': string;
137
+ '@container': string;
138
+ };
139
+ duration: string;
140
+ volunteerDates: string;
141
+ portfolio: {
142
+ '@id': string;
143
+ '@container': string;
144
+ };
145
+ name: string;
146
+ url: string;
147
+ evidenceLink: string;
148
+ evidenceDescription: string;
149
+ };
150
+ };
151
+ export declare const performanceReviewCredentialContext: {
152
+ '@context': {
153
+ '@vocab': string;
154
+ fullName: string;
155
+ persons: string;
156
+ employeeName: string;
157
+ employeeJobTitle: string;
158
+ company: string;
159
+ role: string;
160
+ reviewStartDate: string;
161
+ reviewEndDate: string;
162
+ reviewDuration: string;
163
+ jobKnowledgeRating: string;
164
+ teamworkRating: string;
165
+ initiativeRating: string;
166
+ communicationRating: string;
167
+ overallRating: string;
168
+ reviewComments: string;
169
+ goalsNext: string;
170
+ portfolio: {
171
+ '@id': string;
172
+ '@container': string;
173
+ };
174
+ name: string;
175
+ url: string;
176
+ evidenceLink: string;
177
+ evidenceDescription: string;
178
+ };
179
+ };
107
180
  declare const localOBContext: {
108
181
  '@context': {
109
182
  '@protected': boolean;
@@ -1,4 +1,4 @@
1
- import { KeyPair, DidDocument, FormDataI, RecommendationCredential, Credential, RecommendationFormDataI, VerifiableCredential } from '../../types/credential';
1
+ import { KeyPair, DidDocument, FormDataI, RecommendationCredential, Credential, RecommendationFormDataI, VerifiableCredential, EmploymentFormDataI, VolunteeringFormDataI, PerformanceReviewFormDataI } from '../../types/credential';
2
2
  /**
3
3
  * Create a DID document using the provided key pair.
4
4
  * @param {KeyPair} keyPair - The key pair used to create the DID document.
@@ -34,6 +34,176 @@ export declare function generateUnsignedRecommendation({ vcId, recommendation, i
34
34
  recommendation: RecommendationFormDataI;
35
35
  issuerDid: string;
36
36
  }): RecommendationCredential;
37
+ /**
38
+ * Generate an unsigned Employment Credential.
39
+ */
40
+ export declare function generateUnsignedEmployment({ formData, issuerDid }: {
41
+ formData: EmploymentFormDataI;
42
+ issuerDid: string;
43
+ }): {
44
+ '@context': (string | {
45
+ '@vocab': string;
46
+ fullName: string;
47
+ persons: string;
48
+ credentialName: string;
49
+ credentialDuration: string;
50
+ credentialDescription: string;
51
+ portfolio: {
52
+ '@id': string;
53
+ '@container': string;
54
+ };
55
+ name: string;
56
+ url: string;
57
+ evidenceLink: string;
58
+ evidenceDescription: string;
59
+ company: string;
60
+ role: string;
61
+ })[];
62
+ id: string;
63
+ type: string[];
64
+ issuer: {
65
+ id: string;
66
+ type: string[];
67
+ };
68
+ issuanceDate: string;
69
+ credentialSubject: {
70
+ type: string[];
71
+ fullName: string;
72
+ persons: string;
73
+ credentialName: string;
74
+ credentialDuration: string;
75
+ credentialDescription: string;
76
+ portfolio: {
77
+ name: string;
78
+ url: string;
79
+ }[];
80
+ evidenceLink: string;
81
+ evidenceDescription: string;
82
+ company: string;
83
+ role: string;
84
+ };
85
+ };
86
+ /**
87
+ * Generate an unsigned Volunteering Credential.
88
+ */
89
+ export declare function generateUnsignedVolunteering({ formData, issuerDid }: {
90
+ formData: VolunteeringFormDataI;
91
+ issuerDid: string;
92
+ }): {
93
+ '@context': (string | {
94
+ '@vocab': string;
95
+ fullName: string;
96
+ persons: string;
97
+ volunteerWork: string;
98
+ volunteerOrg: string;
99
+ volunteerDescription: string;
100
+ skillsGained: {
101
+ '@id': string;
102
+ '@container': string;
103
+ };
104
+ duration: string;
105
+ volunteerDates: string;
106
+ portfolio: {
107
+ '@id': string;
108
+ '@container': string;
109
+ };
110
+ name: string;
111
+ url: string;
112
+ evidenceLink: string;
113
+ evidenceDescription: string;
114
+ })[];
115
+ id: string;
116
+ type: string[];
117
+ issuer: {
118
+ id: string;
119
+ type: string[];
120
+ };
121
+ issuanceDate: string;
122
+ credentialSubject: {
123
+ type: string[];
124
+ fullName: string;
125
+ persons: string;
126
+ volunteerWork: string;
127
+ volunteerOrg: string;
128
+ volunteerDescription: string;
129
+ skillsGained: string[];
130
+ duration: string;
131
+ volunteerDates: string;
132
+ portfolio: {
133
+ name: string;
134
+ url: string;
135
+ }[];
136
+ evidenceLink: string;
137
+ evidenceDescription: string;
138
+ };
139
+ };
140
+ /**
141
+ * Generate an unsigned Performance Review Credential.
142
+ */
143
+ export declare function generateUnsignedPerformanceReview({ formData, issuerDid }: {
144
+ formData: PerformanceReviewFormDataI;
145
+ issuerDid: string;
146
+ }): {
147
+ '@context': (string | {
148
+ '@vocab': string;
149
+ fullName: string;
150
+ persons: string;
151
+ employeeName: string;
152
+ employeeJobTitle: string;
153
+ company: string;
154
+ role: string;
155
+ reviewStartDate: string;
156
+ reviewEndDate: string;
157
+ reviewDuration: string;
158
+ jobKnowledgeRating: string;
159
+ teamworkRating: string;
160
+ initiativeRating: string;
161
+ communicationRating: string;
162
+ overallRating: string;
163
+ reviewComments: string;
164
+ goalsNext: string;
165
+ portfolio: {
166
+ '@id': string;
167
+ '@container': string;
168
+ };
169
+ name: string;
170
+ url: string;
171
+ evidenceLink: string;
172
+ evidenceDescription: string;
173
+ })[];
174
+ id: string;
175
+ type: string[];
176
+ issuer: {
177
+ id: string;
178
+ type: string[];
179
+ };
180
+ issuanceDate: string;
181
+ credentialSubject: {
182
+ type: string[];
183
+ fullName: string;
184
+ persons: string;
185
+ employeeName: string;
186
+ employeeJobTitle: string;
187
+ company: string;
188
+ role: string;
189
+ reviewStartDate: string;
190
+ reviewEndDate: string;
191
+ reviewDuration: string;
192
+ jobKnowledgeRating: string;
193
+ teamworkRating: string;
194
+ initiativeRating: string;
195
+ communicationRating: string;
196
+ overallRating: string;
197
+ reviewComments: string;
198
+ goalsNext: string;
199
+ portfolio: {
200
+ name: string;
201
+ url: string;
202
+ }[];
203
+ evidenceLink: string;
204
+ evidenceDescription: string;
205
+ };
206
+ };
37
207
  /**
38
208
  * Extracts the keypair from a Verifiable Credential
39
209
  * @param {Object} credential - The signed Verifiable Credential
@@ -120,6 +120,82 @@ export const inlineResumeContext = {
120
120
  Resume: 'https://schema.hropenstandards.org/4.4#Resume',
121
121
  },
122
122
  };
123
+ // 1. Employment Credential Context
124
+ export const employmentCredentialContext = {
125
+ '@context': {
126
+ '@vocab': 'https://schema.hropenstandards.org/4.4/',
127
+ fullName: 'https://schema.org/name',
128
+ persons: 'https://schema.org/name',
129
+ credentialName: 'https://schema.org/jobTitle',
130
+ credentialDuration: 'https://schema.org/duration',
131
+ credentialDescription: 'https://schema.org/description',
132
+ portfolio: {
133
+ '@id': 'https://schema.org/hasPart',
134
+ '@container': '@list'
135
+ },
136
+ name: 'https://schema.org/name',
137
+ url: 'https://schema.org/url',
138
+ evidenceLink: 'https://schema.org/url',
139
+ evidenceDescription: 'https://schema.org/description',
140
+ company: 'https://schema.org/worksFor',
141
+ role: 'https://schema.org/jobTitle'
142
+ }
143
+ };
144
+ // 2. Volunteering Credential Context
145
+ export const volunteeringCredentialContext = {
146
+ '@context': {
147
+ '@vocab': 'https://schema.hropenstandards.org/4.4/',
148
+ fullName: 'https://schema.org/name',
149
+ persons: 'https://schema.org/name',
150
+ volunteerWork: 'https://schema.org/roleName',
151
+ volunteerOrg: 'https://schema.org/organization',
152
+ volunteerDescription: 'https://schema.org/description',
153
+ skillsGained: {
154
+ '@id': 'https://schema.org/skills',
155
+ '@container': '@list'
156
+ },
157
+ duration: 'https://schema.org/duration',
158
+ volunteerDates: 'https://schema.org/temporalCoverage',
159
+ portfolio: {
160
+ '@id': 'https://schema.org/hasPart',
161
+ '@container': '@list'
162
+ },
163
+ name: 'https://schema.org/name',
164
+ url: 'https://schema.org/url',
165
+ evidenceLink: 'https://schema.org/url',
166
+ evidenceDescription: 'https://schema.org/description'
167
+ }
168
+ };
169
+ // 3. Performance Review Credential Context
170
+ export const performanceReviewCredentialContext = {
171
+ '@context': {
172
+ '@vocab': 'https://schema.hropenstandards.org/4.4/',
173
+ fullName: 'https://schema.org/name',
174
+ persons: 'https://schema.org/name',
175
+ employeeName: 'https://schema.org/name',
176
+ employeeJobTitle: 'https://schema.org/jobTitle',
177
+ company: 'https://schema.org/worksFor',
178
+ role: 'https://schema.org/jobTitle',
179
+ reviewStartDate: 'https://schema.org/startDate',
180
+ reviewEndDate: 'https://schema.org/endDate',
181
+ reviewDuration: 'https://schema.org/duration',
182
+ jobKnowledgeRating: 'https://schema.org/assessmentScore',
183
+ teamworkRating: 'https://schema.org/assessmentScore',
184
+ initiativeRating: 'https://schema.org/assessmentScore',
185
+ communicationRating: 'https://schema.org/assessmentScore',
186
+ overallRating: 'https://schema.org/aggregateRating',
187
+ reviewComments: 'https://schema.org/comment',
188
+ goalsNext: 'https://schema.hropenstandards.org/4.4/goalsNext',
189
+ portfolio: {
190
+ '@id': 'https://schema.org/hasPart',
191
+ '@container': '@list'
192
+ },
193
+ name: 'https://schema.org/name',
194
+ url: 'https://schema.org/url',
195
+ evidenceLink: 'https://schema.org/url',
196
+ evidenceDescription: 'https://schema.org/description'
197
+ }
198
+ };
123
199
  const localOBContext = {
124
200
  '@context': {
125
201
  '@protected': true,
@@ -1,7 +1,9 @@
1
1
  import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-key-2020';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
3
  import CryptoJS from 'crypto-js';
4
+ import { employmentCredentialContext, volunteeringCredentialContext, performanceReviewCredentialContext } from './context.js';
4
5
  /**
6
+ *
5
7
  * Utility function to generate a hashed ID for a credential.
6
8
  * Excludes the `id` field when hashing.
7
9
  * @param {object} credential - The credential object to hash.
@@ -169,6 +171,109 @@ export function generateUnsignedRecommendation({ vcId, recommendation, issuerDid
169
171
  };
170
172
  return unsignedRecommendation;
171
173
  }
174
+ /**
175
+ * Generate an unsigned Employment Credential.
176
+ */
177
+ export function generateUnsignedEmployment({ formData, issuerDid }) {
178
+ const issuanceDate = new Date().toISOString();
179
+ const unsignedCredential = {
180
+ '@context': [
181
+ 'https://www.w3.org/2018/credentials/v1',
182
+ employmentCredentialContext['@context'],
183
+ ],
184
+ id: '',
185
+ type: ['VerifiableCredential', 'EmploymentCredential'],
186
+ issuer: { id: issuerDid, type: ['Profile'] },
187
+ issuanceDate,
188
+ credentialSubject: {
189
+ type: ['WorkExperience'],
190
+ fullName: formData.fullName,
191
+ persons: formData.persons,
192
+ credentialName: formData.credentialName,
193
+ credentialDuration: formData.credentialDuration,
194
+ credentialDescription: formData.credentialDescription,
195
+ portfolio: formData.portfolio.map(item => ({ name: item.name, url: item.url })),
196
+ evidenceLink: formData.evidenceLink,
197
+ evidenceDescription: formData.evidenceDescription,
198
+ company: formData.company,
199
+ role: formData.role,
200
+ },
201
+ };
202
+ unsignedCredential.id = 'urn:' + generateHashedId(unsignedCredential);
203
+ return unsignedCredential;
204
+ }
205
+ /**
206
+ * Generate an unsigned Volunteering Credential.
207
+ */
208
+ export function generateUnsignedVolunteering({ formData, issuerDid }) {
209
+ const issuanceDate = new Date().toISOString();
210
+ const unsignedCredential = {
211
+ '@context': [
212
+ 'https://www.w3.org/2018/credentials/v1',
213
+ volunteeringCredentialContext['@context'],
214
+ ],
215
+ id: '',
216
+ type: ['VerifiableCredential', 'VolunteeringCredential'],
217
+ issuer: { id: issuerDid, type: ['Profile'] },
218
+ issuanceDate,
219
+ credentialSubject: {
220
+ type: ['VolunteerRole'],
221
+ fullName: formData.fullName,
222
+ persons: formData.persons,
223
+ volunteerWork: formData.volunteerWork,
224
+ volunteerOrg: formData.volunteerOrg,
225
+ volunteerDescription: formData.volunteerDescription,
226
+ skillsGained: formData.skillsGained ? formData.skillsGained.split(',').map(s => s.trim()) : undefined,
227
+ duration: formData.duration,
228
+ volunteerDates: formData.volunteerDates,
229
+ portfolio: formData.portfolio.map(item => ({ name: item.name, url: item.url })),
230
+ evidenceLink: formData.evidenceLink,
231
+ evidenceDescription: formData.evidenceDescription,
232
+ },
233
+ };
234
+ unsignedCredential.id = 'urn:' + generateHashedId(unsignedCredential);
235
+ return unsignedCredential;
236
+ }
237
+ /**
238
+ * Generate an unsigned Performance Review Credential.
239
+ */
240
+ export function generateUnsignedPerformanceReview({ formData, issuerDid }) {
241
+ const issuanceDate = new Date().toISOString();
242
+ const unsignedCredential = {
243
+ '@context': [
244
+ 'https://www.w3.org/2018/credentials/v1',
245
+ performanceReviewCredentialContext['@context'],
246
+ ],
247
+ id: '',
248
+ type: ['VerifiableCredential', 'PerformanceReviewCredential'],
249
+ issuer: { id: issuerDid, type: ['Profile'] },
250
+ issuanceDate,
251
+ credentialSubject: {
252
+ type: ['EndorsementSubject'],
253
+ fullName: formData.fullName,
254
+ persons: formData.persons,
255
+ employeeName: formData.employeeName,
256
+ employeeJobTitle: formData.employeeJobTitle,
257
+ company: formData.company,
258
+ role: formData.role,
259
+ reviewStartDate: formData.reviewStartDate,
260
+ reviewEndDate: formData.reviewEndDate,
261
+ reviewDuration: formData.reviewDuration,
262
+ jobKnowledgeRating: formData.jobKnowledgeRating,
263
+ teamworkRating: formData.teamworkRating,
264
+ initiativeRating: formData.initiativeRating,
265
+ communicationRating: formData.communicationRating,
266
+ overallRating: formData.overallRating,
267
+ reviewComments: formData.reviewComments,
268
+ goalsNext: formData.goalsNext,
269
+ portfolio: formData.portfolio.map(item => ({ name: item.name, url: item.url })),
270
+ evidenceLink: formData.evidenceLink,
271
+ evidenceDescription: formData.evidenceDescription,
272
+ },
273
+ };
274
+ unsignedCredential.id = 'urn:' + generateHashedId(unsignedCredential);
275
+ return unsignedCredential;
276
+ }
172
277
  /**
173
278
  * Extracts the keypair from a Verifiable Credential
174
279
  * @param {Object} credential - The signed Verifiable Credential
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cooperation/vc-storage",
3
3
  "type": "module",
4
- "version": "1.0.32",
4
+ "version": "1.0.34",
5
5
  "description": "Sign and store your verifiable credentials.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/types/index.d.ts",