@cooperation/vc-storage 1.0.46 → 1.0.49

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.
@@ -5,15 +5,11 @@ import { v4 as uuidv4 } from 'uuid';
5
5
  import { extractKeyPairFromCredential, generateDIDSchema, generateUnsignedEmployment, generateUnsignedPerformanceReview, generateUnsignedRecommendation, generateUnsignedSkillClaim, generateUnsignedVC, generateUnsignedVolunteering, } from '../utils/credential.js';
6
6
  import { securityLoader } from '@digitalcredentials/security-document-loader';
7
7
  import hrContext from 'hr-context';
8
- // Add hr-context for SkillClaimCredential; patch socCode (@type→@container)
9
- const hrCtxData = JSON.parse(JSON.stringify(hrContext.CONTEXT_V1));
10
- if (hrCtxData?.['@context']?.socCode) {
11
- delete hrCtxData['@context'].socCode['@type'];
12
- hrCtxData['@context'].socCode['@container'] = '@set';
13
- }
8
+ // Add hr-context for SkillClaimCredential (defines socCode, inferredSkill,
9
+ // model, source, frameworkMatch as of hr-context@0.2.0).
14
10
  const loader = securityLoader();
15
- loader.addStatic(hrContext.CONTEXT_URL_V1, hrCtxData);
16
- loader.addStatic('https://w3id.org/hr/v1', hrCtxData);
11
+ loader.addStatic(hrContext.CONTEXT_URL_V1, hrContext.CONTEXT_V1);
12
+ loader.addStatic('https://w3id.org/hr/v1', hrContext.CONTEXT_V1);
17
13
  const builtLoader = loader.build();
18
14
  /** Document loader compatible with @digitalcredentials/vc */
19
15
  export const documentLoader = async (url) => {
@@ -5,8 +5,7 @@ export declare const documentLoader: (url: string) => Promise<{
5
5
  document: any;
6
6
  }>;
7
7
  import type { IVerifiableCredential } from '@digitalcredentials/ssi';
8
- import { DidDocument, KeyPair, FormDataI, RecommendationFormDataI, EmploymentFormDataI, PerformanceReviewFormDataI, VolunteeringFormDataI } from '../../types';
9
- import type { ISkillClaimCredential } from 'hr-context';
8
+ import { DidDocument, KeyPair, FormDataI, RecommendationFormDataI, EmploymentFormDataI, PerformanceReviewFormDataI, VolunteeringFormDataI, SkillClaimFormDataI } from '../../types';
10
9
  import { GoogleDriveStorage } from './GoogleDriveStorage.js';
11
10
  interface SignPropsI {
12
11
  data: FormDataI | RecommendationFormDataI | EmploymentFormDataI | VolunteeringFormDataI | PerformanceReviewFormDataI;
@@ -82,7 +81,7 @@ export declare class CredentialEngine {
82
81
  * @param {string} issuerId - The issuer DID.
83
82
  * @returns {Promise<any>} The signed SkillClaimCredential.
84
83
  */
85
- signSkillClaimVC(data: ISkillClaimCredential, keyPair: KeyPair, issuerId: string): Promise<any>;
84
+ signSkillClaimVC(data: SkillClaimFormDataI, keyPair: KeyPair, issuerId: string): Promise<any>;
86
85
  /**
87
86
  * Verify a Verifiable Credential (VC)
88
87
  * @param {object} credential - The Verifiable Credential to verify.
@@ -1,5 +1,4 @@
1
- import { KeyPair, DidDocument, FormDataI, RecommendationFormDataI, EvidenceItem, EmploymentFormDataI, VolunteeringFormDataI, PerformanceReviewFormDataI } from '../../types';
2
- import type { ISkillClaimCredential } from 'hr-context';
1
+ import { KeyPair, DidDocument, FormDataI, RecommendationFormDataI, EvidenceItem, EmploymentFormDataI, VolunteeringFormDataI, PerformanceReviewFormDataI, SkillClaimFormDataI } from '../../types';
3
2
  import { IVerifiableCredential } from '@digitalcredentials/ssi';
4
3
  /**
5
4
  * Create a DID document using the provided key pair.
@@ -59,12 +58,15 @@ export declare function generateUnsignedPerformanceReview({ formData, issuerDid
59
58
  * - Uses `https://www.w3.org/ns/credentials/v2` and `https://w3id.org/hr/v1` contexts
60
59
  * - VC subtype is `SkillClaimCredential` (not `OpenBadgeCredential`)
61
60
  * - `credentialSubject.type` is `SkillClaim` with a `person` object and `skill` array
61
+ * - User-entered skills go in `credentialSubject.skill`; LLM-extracted skills go in
62
+ * `credentialSubject.inferredSkill` with `source`/`model` provenance and
63
+ * `frameworkMatch` alignments
62
64
  * - Evidence lives at the credential root (not inside `credentialSubject`)
63
65
  * - No `issuanceDate`/`expirationDate` set by the author
64
66
  * - Issuer is a plain DID string (no `type` wrapper)
65
67
  */
66
68
  export declare function generateUnsignedSkillClaim({ formData, issuerDid, }: {
67
- formData: ISkillClaimCredential;
69
+ formData: SkillClaimFormDataI;
68
70
  issuerDid: string;
69
71
  }): IVerifiableCredential;
70
72
  /**
@@ -264,6 +264,9 @@ export function generateUnsignedPerformanceReview({ formData, issuerDid }) {
264
264
  * - Uses `https://www.w3.org/ns/credentials/v2` and `https://w3id.org/hr/v1` contexts
265
265
  * - VC subtype is `SkillClaimCredential` (not `OpenBadgeCredential`)
266
266
  * - `credentialSubject.type` is `SkillClaim` with a `person` object and `skill` array
267
+ * - User-entered skills go in `credentialSubject.skill`; LLM-extracted skills go in
268
+ * `credentialSubject.inferredSkill` with `source`/`model` provenance and
269
+ * `frameworkMatch` alignments
267
270
  * - Evidence lives at the credential root (not inside `credentialSubject`)
268
271
  * - No `issuanceDate`/`expirationDate` set by the author
269
272
  * - Issuer is a plain DID string (no `type` wrapper)
@@ -290,11 +293,20 @@ export function generateUnsignedSkillClaim({ formData, issuerDid, }) {
290
293
  name: s.name,
291
294
  description: s.description,
292
295
  durationPerformed: s.durationPerformed,
293
- narrative: s.narrative,
294
296
  image: s.image,
295
297
  source: s.source,
296
- frameworkMatch: s.frameworkMatch,
297
298
  })),
299
+ ...(formData.inferredSkills?.length
300
+ ? {
301
+ inferredSkill: formData.inferredSkills.map((s) => ({
302
+ id: `urn:uuid:${uuidv4()}`,
303
+ name: s.name,
304
+ source: s.source,
305
+ model: s.model,
306
+ frameworkMatch: s.frameworkMatch,
307
+ })),
308
+ }
309
+ : {}),
298
310
  },
299
311
  evidence: formData.evidence?.length ? formData.evidence.map((e) => ({
300
312
  id: e.id,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cooperation/vc-storage",
3
3
  "type": "module",
4
- "version": "1.0.46",
4
+ "version": "1.0.49",
5
5
  "description": "Sign and store your verifiable credentials.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/types/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  "crypto-js": "^4.2.0",
33
33
  "crypto-ld": "^7.0.0",
34
34
  "ethers": "^6.13.2",
35
- "hr-context": "^0.1.6",
35
+ "hr-context": "^0.2.0",
36
36
  "jest": "^29.7.0",
37
37
  "multiformats": "^13.3.6",
38
38
  "ts-jest": "^29.2.5",
@@ -1,25 +0,0 @@
1
- /**
2
- * Ed25519 signer compatible with @wallet.storage/fetch-client.
3
- * Uses @digitalcredentials packages instead of @digitalbazaar.
4
- */
5
- import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020';
6
- export declare class Ed25519Signer {
7
- private readonly keyPair;
8
- private readonly verificationMethod;
9
- readonly algorithm = "Ed25519";
10
- constructor(keyPair: Ed25519VerificationKey2020, verificationMethod: {
11
- id: string;
12
- type: string;
13
- controller: string;
14
- publicKeyMultibase: string;
15
- });
16
- static generate(): Promise<Ed25519Signer>;
17
- static fromJSON(json: string): Promise<Ed25519Signer>;
18
- get controller(): string;
19
- get id(): string;
20
- get publicKeyMultibase(): string;
21
- sign({ data }: {
22
- data: Uint8Array;
23
- }): Promise<Uint8Array>;
24
- toJSON(): object;
25
- }
@@ -1,6 +0,0 @@
1
- /** Document loader compatible with @digitalcredentials/vc */
2
- export declare const customDocumentLoader: (url: string) => Promise<{
3
- contextUrl: string;
4
- documentUrl: string;
5
- document: any;
6
- }>;
@@ -1 +0,0 @@
1
- export declare const customDocumentLoader: (url: string) => Promise<any>;
@@ -1,71 +0,0 @@
1
- /**
2
- * Ed25519 signer compatible with @wallet.storage/fetch-client.
3
- * Uses @digitalcredentials packages instead of @digitalbazaar.
4
- */
5
- import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020';
6
- export class Ed25519Signer {
7
- keyPair;
8
- verificationMethod;
9
- algorithm = 'Ed25519';
10
- constructor(keyPair, verificationMethod) {
11
- this.keyPair = keyPair;
12
- this.verificationMethod = verificationMethod;
13
- }
14
- static async generate() {
15
- const keyPair = await Ed25519VerificationKey2020.generate();
16
- const fingerprint = keyPair.fingerprint();
17
- const controller = `did:key:${fingerprint}`;
18
- keyPair.controller = controller;
19
- keyPair.id = `${controller}#${fingerprint}`;
20
- const verificationMethod = {
21
- id: keyPair.id,
22
- type: 'Ed25519VerificationKey2020',
23
- controller,
24
- publicKeyMultibase: keyPair.publicKeyMultibase,
25
- };
26
- return new Ed25519Signer(keyPair, verificationMethod);
27
- }
28
- static async fromJSON(json) {
29
- const object = JSON.parse(json);
30
- const { publicKeyMultibase, privateKeyMultibase, controller } = object;
31
- if (typeof controller !== 'string') {
32
- throw new Error('json object must have controller string', { cause: { parsedJson: object } });
33
- }
34
- if (typeof publicKeyMultibase !== 'string') {
35
- throw new Error('json object must have publicKeyMultibase string', { cause: object });
36
- }
37
- if (typeof privateKeyMultibase !== 'string') {
38
- throw new Error('json object must have privateKeyMultibase string', { cause: object });
39
- }
40
- const keyPair = await Ed25519VerificationKey2020.from({
41
- type: 'Ed25519VerificationKey2020',
42
- controller,
43
- publicKeyMultibase,
44
- privateKeyMultibase,
45
- });
46
- const fingerprint = keyPair.fingerprint();
47
- const verificationMethod = {
48
- id: `${controller}#${fingerprint}`,
49
- type: 'Ed25519VerificationKey2020',
50
- controller,
51
- publicKeyMultibase: keyPair.publicKeyMultibase,
52
- };
53
- return new Ed25519Signer(keyPair, verificationMethod);
54
- }
55
- get controller() {
56
- return this.keyPair.controller;
57
- }
58
- get id() {
59
- return this.verificationMethod.id;
60
- }
61
- get publicKeyMultibase() {
62
- return this.keyPair.publicKeyMultibase;
63
- }
64
- async sign({ data }) {
65
- const signature = await this.keyPair.signer().sign({ data });
66
- return signature;
67
- }
68
- toJSON() {
69
- return this.keyPair.export({ publicKey: true, privateKey: true });
70
- }
71
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Document loader using @digitalcredentials/security-document-loader.
3
- * Adds hr-context for SkillClaimCredential support.
4
- * @see https://github.com/digitalcredentials/security-document-loader
5
- */
6
- import { securityLoader } from '@digitalcredentials/security-document-loader';
7
- import hrContext from 'hr-context';
8
- const loader = securityLoader();
9
- loader.addStatic(hrContext.CONTEXT_URL_V1, hrContext.CONTEXT_V1);
10
- loader.addStatic('https://w3id.org/hr/v1', hrContext.CONTEXT_V1);
11
- const builtLoader = loader.build();
12
- /** Document loader compatible with @digitalcredentials/vc */
13
- export const customDocumentLoader = async (url) => {
14
- const result = await builtLoader(url);
15
- return {
16
- contextUrl: result.contextUrl ?? null,
17
- documentUrl: result.documentUrl ?? url,
18
- document: result.document,
19
- };
20
- };
@@ -1,51 +0,0 @@
1
- import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-key-2020';
2
- import { suiteContext as ed25519Context } from '@digitalbazaar/ed25519-signature-2020';
3
- import { driver as didKeyDriver } from '@digitalbazaar/did-method-key';
4
- import { defaultDocumentLoader } from '@digitalcredentials/vc';
5
- import { contexts as obContexts } from '@digitalcredentials/open-badges-context';
6
- import { contexts as credV1Contexts } from 'credentials-context';
7
- import { contexts as credV2Contexts } from '@digitalcredentials/credentials-v2-context';
8
- import hrContext from 'hr-context';
9
- // Initialize the DID method key driver
10
- const didKeyDriverInstance = didKeyDriver();
11
- didKeyDriverInstance.use({
12
- multibaseMultikeyHeader: 'z6Mk',
13
- fromMultibase: Ed25519VerificationKey2020.from,
14
- });
15
- // Patch the upstream hr-context socCode bug: "@type":"@set" -> "@container":"@set"
16
- const hrCtxData = structuredClone(hrContext.CONTEXT_V1);
17
- if (hrCtxData?.['@context']?.socCode) {
18
- delete hrCtxData['@context'].socCode['@type'];
19
- hrCtxData['@context'].socCode['@container'] = '@set';
20
- }
21
- // Build context map from installed packages
22
- const contextMap = new Map([
23
- ...credV1Contexts,
24
- ...credV2Contexts,
25
- ...obContexts,
26
- ...ed25519Context.contexts,
27
- [hrContext.CONTEXT_URL_V1, hrCtxData],
28
- ['https://w3id.org/hr/v1', hrCtxData],
29
- ]);
30
- // Custom document loader
31
- export const customDocumentLoader = async (url) => {
32
- const context = contextMap.get(url);
33
- if (context) {
34
- return {
35
- contextUrl: null,
36
- documentUrl: url,
37
- document: context,
38
- };
39
- }
40
- // Handle did:key resolution
41
- if (url.startsWith('did:key:')) {
42
- const didDocument = await didKeyDriverInstance.get({ did: url });
43
- return {
44
- contextUrl: null,
45
- documentUrl: url,
46
- document: didDocument,
47
- };
48
- }
49
- // Fallback to the default document loader
50
- return defaultDocumentLoader(url);
51
- };