@learncard/linked-claims-plugin 0.1.3 → 0.2.1
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.d.ts.map +1 -1
- package/dist/linked-claims-plugin.cjs.development.js +24 -32
- package/dist/linked-claims-plugin.cjs.development.js.map +2 -2
- package/dist/linked-claims-plugin.cjs.production.min.js +1 -1
- package/dist/linked-claims-plugin.cjs.production.min.js.map +3 -3
- package/dist/linked-claims-plugin.esm.js +21 -29
- package/dist/linked-claims-plugin.esm.js.map +2 -2
- package/package.json +8 -8
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,kCAAkC,EAAE,MAAM,SAAS,CAAC;AAEtF,cAAc,SAAS,CAAC;AA8BxB,eAAO,MAAM,qBAAqB,cACnB,SAAS,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,EAAE,kCAAkC,CAAC,KACjG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,kCAAkC,EAAE,MAAM,SAAS,CAAC;AAEtF,cAAc,SAAS,CAAC;AA8BxB,eAAO,MAAM,qBAAqB,cACnB,SAAS,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,EAAE,kCAAkC,CAAC,KACjG,kBA+ID,CAAC"}
|
|
@@ -19,36 +19,30 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
|
|
21
21
|
// src/index.ts
|
|
22
|
-
var
|
|
23
|
-
__export(
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
24
|
getLinkedClaimsPlugin: () => getLinkedClaimsPlugin
|
|
25
25
|
});
|
|
26
|
-
module.exports = __toCommonJS(
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
27
|
var ENDORSEMENT_CONTEXT = "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json";
|
|
28
28
|
var getSubjectIds = /* @__PURE__ */ __name((credential) => {
|
|
29
29
|
const subject = credential.credentialSubject;
|
|
30
|
-
if (Array.isArray(subject))
|
|
31
|
-
return subject.map((s) => s?.id).filter(Boolean);
|
|
30
|
+
if (Array.isArray(subject)) return subject.map((s) => s?.id).filter(Boolean);
|
|
32
31
|
return subject?.id ? [subject.id] : [];
|
|
33
32
|
}, "getSubjectIds");
|
|
34
33
|
var pickIndexProvider = /* @__PURE__ */ __name((learnCard, preferred) => {
|
|
35
34
|
const providers = Object.keys(learnCard.index || {}).filter(
|
|
36
35
|
(k) => !["providers", "all"].includes(k)
|
|
37
36
|
);
|
|
38
|
-
if (!providers.length)
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
return preferred;
|
|
42
|
-
if (providers.includes("LearnCloud"))
|
|
43
|
-
return "LearnCloud";
|
|
37
|
+
if (!providers.length) return void 0;
|
|
38
|
+
if (preferred && providers.includes(preferred)) return preferred;
|
|
39
|
+
if (providers.includes("LearnCloud")) return "LearnCloud";
|
|
44
40
|
return providers[0];
|
|
45
41
|
}, "pickIndexProvider");
|
|
46
42
|
var pickStoreProvider = /* @__PURE__ */ __name((learnCard, preferred) => {
|
|
47
43
|
const providers = Object.keys(learnCard.store || {}).filter((k) => k !== "providers");
|
|
48
|
-
if (!providers.length)
|
|
49
|
-
|
|
50
|
-
if (preferred && providers.includes(preferred))
|
|
51
|
-
return preferred;
|
|
44
|
+
if (!providers.length) return void 0;
|
|
45
|
+
if (preferred && providers.includes(preferred)) return preferred;
|
|
52
46
|
return providers[0];
|
|
53
47
|
}, "pickStoreProvider");
|
|
54
48
|
var ensureArray = /* @__PURE__ */ __name((arr) => Array.isArray(arr) ? arr : arr ? [arr] : [], "ensureArray");
|
|
@@ -57,7 +51,7 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
57
51
|
displayName: "LinkedClaims",
|
|
58
52
|
description: "Create, verify, store, and retrieve endorsement credentials linked to originals.",
|
|
59
53
|
methods: {
|
|
60
|
-
endorseCredential: async (_learnCard, original, details, opts) => {
|
|
54
|
+
endorseCredential: /* @__PURE__ */ __name(async (_learnCard, original, details, opts) => {
|
|
61
55
|
const issuer = learnCard.id.did();
|
|
62
56
|
const originalId = original.id;
|
|
63
57
|
const subjectIds = getSubjectIds(original);
|
|
@@ -73,7 +67,7 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
73
67
|
"@context": context,
|
|
74
68
|
type: types,
|
|
75
69
|
issuer,
|
|
76
|
-
validFrom: new Date().toISOString(),
|
|
70
|
+
validFrom: (/* @__PURE__ */ new Date()).toISOString(),
|
|
77
71
|
credentialSubject: {
|
|
78
72
|
type: ["EndorsementSubject"],
|
|
79
73
|
id: targetId,
|
|
@@ -84,8 +78,8 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
84
78
|
...details.evidence && { evidence: details.evidence }
|
|
85
79
|
};
|
|
86
80
|
return learnCard.invoke.issueCredential(unsigned);
|
|
87
|
-
},
|
|
88
|
-
verifyEndorsement: async (_learnCard, endorsement, options) => {
|
|
81
|
+
}, "endorseCredential"),
|
|
82
|
+
verifyEndorsement: /* @__PURE__ */ __name(async (_learnCard, endorsement, options) => {
|
|
89
83
|
const check = await learnCard.invoke.verifyCredential(endorsement, options);
|
|
90
84
|
const ctx = ensureArray(endorsement["@context"]);
|
|
91
85
|
const types = ensureArray(endorsement["type"]);
|
|
@@ -106,14 +100,12 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
106
100
|
if (!csObj?.id) {
|
|
107
101
|
check.errors.push("linked-claims error: credentialSubject.id missing");
|
|
108
102
|
}
|
|
109
|
-
if (!check.errors.length)
|
|
110
|
-
check.checks.push("linked-claims");
|
|
103
|
+
if (!check.errors.length) check.checks.push("linked-claims");
|
|
111
104
|
return check;
|
|
112
|
-
},
|
|
113
|
-
storeEndorsement: async (_learnCard, endorsement, options) => {
|
|
105
|
+
}, "verifyEndorsement"),
|
|
106
|
+
storeEndorsement: /* @__PURE__ */ __name(async (_learnCard, endorsement, options) => {
|
|
114
107
|
const storeName = pickStoreProvider(learnCard, options?.storeName);
|
|
115
|
-
if (!storeName)
|
|
116
|
-
throw new Error("No store plane provider available");
|
|
108
|
+
if (!storeName) throw new Error("No store plane provider available");
|
|
117
109
|
if (!learnCard.store[storeName].uploadEncrypted || typeof learnCard.store[storeName].uploadEncrypted !== "function") {
|
|
118
110
|
throw new Error(
|
|
119
111
|
`Store provider '${storeName}' does not support uploadEncrypted method`
|
|
@@ -142,18 +134,19 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
142
134
|
issuedOn: endorsement.validFrom || endorsement.issuanceDate,
|
|
143
135
|
category: "Endorsement",
|
|
144
136
|
credentialId: options?.credentialId,
|
|
137
|
+
// original credential id
|
|
145
138
|
sharedUri: options?.sharedUri,
|
|
139
|
+
// original credential shared uri
|
|
146
140
|
relationship: options?.relationship,
|
|
147
141
|
visibility: options?.visibility ?? "public"
|
|
148
142
|
};
|
|
149
143
|
indexed = await learnCard.index[indexName].add(record);
|
|
150
144
|
}
|
|
151
145
|
return { uri, indexed, id, indexName, storeName };
|
|
152
|
-
},
|
|
153
|
-
getEndorsements: async (_learnCard, original, options) => {
|
|
146
|
+
}, "storeEndorsement"),
|
|
147
|
+
getEndorsements: /* @__PURE__ */ __name(async (_learnCard, original, options) => {
|
|
154
148
|
const indexName = pickIndexProvider(learnCard, options?.indexName);
|
|
155
|
-
if (!indexName)
|
|
156
|
-
return [];
|
|
149
|
+
if (!indexName) return [];
|
|
157
150
|
const subjectIds = getSubjectIds(original);
|
|
158
151
|
const originalId = original.id;
|
|
159
152
|
const query = originalId ? { originalCredentialId: originalId } : { endorsedId: subjectIds[0] };
|
|
@@ -161,11 +154,10 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
161
154
|
const results = [];
|
|
162
155
|
for (const rec of records) {
|
|
163
156
|
const vc = await learnCard.read.get(rec.uri);
|
|
164
|
-
if (vc)
|
|
165
|
-
results.push(vc);
|
|
157
|
+
if (vc) results.push(vc);
|
|
166
158
|
}
|
|
167
159
|
return results;
|
|
168
|
-
}
|
|
160
|
+
}, "getEndorsements")
|
|
169
161
|
}
|
|
170
162
|
}), "getLinkedClaimsPlugin");
|
|
171
163
|
//# sourceMappingURL=linked-claims-plugin.cjs.development.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { LearnCard } from '@learncard/core';\nimport type { VC, UnsignedVC } from '@learncard/types';\nimport type { LinkedClaimsPlugin, LinkedClaimsPluginDependentMethods } from './types';\n\nexport * from './types';\n\nconst ENDORSEMENT_CONTEXT = 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json';\n\nconst getSubjectIds = (credential: VC): string[] => {\n const subject = credential.credentialSubject as any;\n if (Array.isArray(subject)) return subject.map(s => s?.id).filter(Boolean);\n return subject?.id ? [subject.id] : [];\n};\n\nconst pickIndexProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.index || {}).filter(\n k => !['providers', 'all'].includes(k)\n );\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n if (providers.includes('LearnCloud')) return 'LearnCloud';\n return providers[0];\n};\n\nconst pickStoreProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.store || {}).filter(k => k !== 'providers');\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n return providers[0];\n};\n\nconst ensureArray = <T>(arr: T | T[] | undefined): T[] =>\n Array.isArray(arr) ? arr : arr ? [arr] : [];\n\nexport const getLinkedClaimsPlugin = (\n learnCard: LearnCard<any, 'id' | 'store' | 'index' | 'read', LinkedClaimsPluginDependentMethods>\n): LinkedClaimsPlugin => ({\n name: 'LinkedClaims',\n displayName: 'LinkedClaims',\n description: 'Create, verify, store, and retrieve endorsement credentials linked to originals.',\n methods: {\n endorseCredential: async (_learnCard, original, details, opts) => {\n const issuer = learnCard.id.did();\n\n const originalId: string | undefined = (original as any).id;\n const subjectIds = getSubjectIds(original);\n const targetId = originalId || subjectIds[0];\n if (!targetId)\n throw new Error('Original credential must have either id or credentialSubject.id');\n\n const context: (string | Record<string, any>)[] = [\n 'https://www.w3.org/ns/credentials/v2',\n ENDORSEMENT_CONTEXT,\n ];\n\n const types: [string, ...string[]] = ['VerifiableCredential', 'EndorsementCredential'];\n\n const unsigned: UnsignedVC = {\n '@context': context as any,\n type: types,\n issuer,\n validFrom: new Date().toISOString(),\n credentialSubject: {\n type: ['EndorsementSubject'],\n id: targetId,\n ...(details.endorsementComment\n ? { endorsementComment: details.endorsementComment }\n : {}),\n },\n ...(details.name ? { name: details.name } : { name: `Endorsement of ${targetId}` }),\n ...(details.description ? { description: details.description } : {}),\n ...(details.evidence && { evidence: details.evidence }),\n };\n\n return learnCard.invoke.issueCredential(unsigned);\n },\n\n verifyEndorsement: async (_learnCard, endorsement, options) => {\n const check = await learnCard.invoke.verifyCredential(endorsement, options);\n\n const ctx = ensureArray((endorsement as any)['@context']);\n const types = ensureArray((endorsement as any)['type']);\n\n if (\n !ctx.some((c: string) => c === 'https://www.w3.org/ns/credentials/v2') ||\n !ctx.some((c: string) => c === ENDORSEMENT_CONTEXT)\n ) {\n check.errors.push('linked-claims error: missing VCv2 or OBv3 context');\n }\n if (!types.includes('EndorsementCredential')) {\n check.errors.push('linked-claims error: missing EndorsementCredential type');\n }\n\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const csTypes = ensureArray<string>(csObj?.type);\n if (!csTypes.includes('EndorsementSubject')) {\n check.errors.push(\n 'linked-claims error: credentialSubject.type must include EndorsementSubject'\n );\n }\n if (!csObj?.id) {\n check.errors.push('linked-claims error: credentialSubject.id missing');\n }\n\n if (!check.errors.length) check.checks.push('linked-claims');\n return check;\n },\n\n storeEndorsement: async (_learnCard, endorsement, options) => {\n const storeName = pickStoreProvider(learnCard, options?.storeName);\n if (!storeName) throw new Error('No store plane provider available');\n if (\n !learnCard.store[storeName].uploadEncrypted ||\n typeof learnCard.store[storeName].uploadEncrypted !== 'function'\n ) {\n throw new Error(\n `Store provider '${storeName}' does not support uploadEncrypted method`\n );\n }\n const uri: string = await (learnCard.store as any)[storeName].uploadEncrypted(\n endorsement\n );\n\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n let indexed = false;\n let id =\n (endorsement as any).id ||\n `urn:uuid:${
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,IAAM,sBAAsB;AAE5B,IAAM,gBAAgB,wBAAC,eAA6B;AAChD,QAAM,UAAU,WAAW;AAC3B,MAAI,MAAM,QAAQ,OAAO
|
|
4
|
+
"sourcesContent": ["import type { LearnCard } from '@learncard/core';\nimport type { VC, UnsignedVC } from '@learncard/types';\nimport type { LinkedClaimsPlugin, LinkedClaimsPluginDependentMethods } from './types';\n\nexport * from './types';\n\nconst ENDORSEMENT_CONTEXT = 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json';\n\nconst getSubjectIds = (credential: VC): string[] => {\n const subject = credential.credentialSubject as any;\n if (Array.isArray(subject)) return subject.map(s => s?.id).filter(Boolean);\n return subject?.id ? [subject.id] : [];\n};\n\nconst pickIndexProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.index || {}).filter(\n k => !['providers', 'all'].includes(k)\n );\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n if (providers.includes('LearnCloud')) return 'LearnCloud';\n return providers[0];\n};\n\nconst pickStoreProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.store || {}).filter(k => k !== 'providers');\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n return providers[0];\n};\n\nconst ensureArray = <T>(arr: T | T[] | undefined): T[] =>\n Array.isArray(arr) ? arr : arr ? [arr] : [];\n\nexport const getLinkedClaimsPlugin = (\n learnCard: LearnCard<any, 'id' | 'store' | 'index' | 'read', LinkedClaimsPluginDependentMethods>\n): LinkedClaimsPlugin => ({\n name: 'LinkedClaims',\n displayName: 'LinkedClaims',\n description: 'Create, verify, store, and retrieve endorsement credentials linked to originals.',\n methods: {\n endorseCredential: async (_learnCard, original, details, opts) => {\n const issuer = learnCard.id.did();\n\n const originalId: string | undefined = (original as any).id;\n const subjectIds = getSubjectIds(original);\n const targetId = originalId || subjectIds[0];\n if (!targetId)\n throw new Error('Original credential must have either id or credentialSubject.id');\n\n const context: (string | Record<string, any>)[] = [\n 'https://www.w3.org/ns/credentials/v2',\n ENDORSEMENT_CONTEXT,\n ];\n\n const types: [string, ...string[]] = ['VerifiableCredential', 'EndorsementCredential'];\n\n const unsigned: UnsignedVC = {\n '@context': context as any,\n type: types,\n issuer,\n validFrom: new Date().toISOString(),\n credentialSubject: {\n type: ['EndorsementSubject'],\n id: targetId,\n ...(details.endorsementComment\n ? { endorsementComment: details.endorsementComment }\n : {}),\n },\n ...(details.name ? { name: details.name } : { name: `Endorsement of ${targetId}` }),\n ...(details.description ? { description: details.description } : {}),\n ...(details.evidence && { evidence: details.evidence as any }),\n };\n\n return learnCard.invoke.issueCredential(unsigned);\n },\n\n verifyEndorsement: async (_learnCard, endorsement, options) => {\n const check = await learnCard.invoke.verifyCredential(endorsement, options);\n\n const ctx = ensureArray((endorsement as any)['@context']);\n const types = ensureArray((endorsement as any)['type']);\n\n if (\n !ctx.some((c: string) => c === 'https://www.w3.org/ns/credentials/v2') ||\n !ctx.some((c: string) => c === ENDORSEMENT_CONTEXT)\n ) {\n check.errors.push('linked-claims error: missing VCv2 or OBv3 context');\n }\n if (!types.includes('EndorsementCredential')) {\n check.errors.push('linked-claims error: missing EndorsementCredential type');\n }\n\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const csTypes = ensureArray<string>(csObj?.type);\n if (!csTypes.includes('EndorsementSubject')) {\n check.errors.push(\n 'linked-claims error: credentialSubject.type must include EndorsementSubject'\n );\n }\n if (!csObj?.id) {\n check.errors.push('linked-claims error: credentialSubject.id missing');\n }\n\n if (!check.errors.length) check.checks.push('linked-claims');\n return check;\n },\n\n storeEndorsement: async (_learnCard, endorsement, options) => {\n const storeName = pickStoreProvider(learnCard, options?.storeName);\n if (!storeName) throw new Error('No store plane provider available');\n if (\n !learnCard.store[storeName].uploadEncrypted ||\n typeof learnCard.store[storeName].uploadEncrypted !== 'function'\n ) {\n throw new Error(\n `Store provider '${storeName}' does not support uploadEncrypted method`\n );\n }\n const uri: string = await (learnCard.store as any)[storeName].uploadEncrypted(\n endorsement\n );\n\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n let indexed = false;\n let id =\n (endorsement as any).id ||\n `urn:uuid:${(globalThis as any).crypto?.randomUUID?.() ||\n (() => {\n throw new Error(\n 'Secure random UUID generation is not available. Please use an environment that supports crypto.randomUUID().'\n );\n })()\n }`;\n\n if (indexName) {\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const record = {\n id,\n uri,\n type: ensureArray((endorsement as any).type),\n endorsedId: csObj?.id,\n subjectId: csObj?.id,\n originalCredentialId: csObj?.id,\n issuedOn: (endorsement as any).validFrom || (endorsement as any).issuanceDate,\n category: 'Endorsement',\n credentialId: options?.credentialId, // original credential id\n sharedUri: options?.sharedUri, // original credential shared uri\n relationship: options?.relationship,\n visibility: options?.visibility ?? 'public',\n };\n indexed = await (learnCard.index as any)[indexName].add(record);\n }\n\n return { uri, indexed, id, indexName, storeName };\n },\n\n getEndorsements: async (_learnCard, original, options) => {\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n if (!indexName) return [];\n\n const subjectIds = getSubjectIds(original);\n const originalId = (original as any).id;\n\n const query = originalId\n ? { originalCredentialId: originalId }\n : { endorsedId: subjectIds[0] };\n const records = await (learnCard.index as any)[indexName].get(query);\n\n const results: VC[] = [];\n for (const rec of records) {\n const vc = await learnCard.read.get(rec.uri);\n if (vc) results.push(vc as VC);\n }\n return results;\n },\n },\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var p=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var
|
|
1
|
+
"use strict";var p=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var c=(e,t)=>p(e,"name",{value:t,configurable:!0});var E=(e,t)=>{for(var n in t)p(e,n,{get:t[n],enumerable:!0})},w=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of b(t))!C.call(e,i)&&i!==n&&p(e,i,{get:()=>t[i],enumerable:!(r=h(t,i))||r.enumerable});return e};var k=e=>w(p({},"__esModule",{value:!0}),e);var I={};E(I,{getLinkedClaimsPlugin:()=>x});module.exports=k(I);var g="https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json",f=c(e=>{let t=e.credentialSubject;return Array.isArray(t)?t.map(n=>n?.id).filter(Boolean):t?.id?[t.id]:[]},"getSubjectIds"),v=c((e,t)=>{let n=Object.keys(e.index||{}).filter(r=>!["providers","all"].includes(r));if(n.length)return t&&n.includes(t)?t:n.includes("LearnCloud")?"LearnCloud":n[0]},"pickIndexProvider"),j=c((e,t)=>{let n=Object.keys(e.store||{}).filter(r=>r!=="providers");if(n.length)return t&&n.includes(t)?t:n[0]},"pickStoreProvider"),m=c(e=>Array.isArray(e)?e:e?[e]:[],"ensureArray"),x=c(e=>({name:"LinkedClaims",displayName:"LinkedClaims",description:"Create, verify, store, and retrieve endorsement credentials linked to originals.",methods:{endorseCredential:c(async(t,n,r,i)=>{let l=e.id.did(),o=n.id,d=f(n),s=o||d[0];if(!s)throw new Error("Original credential must have either id or credentialSubject.id");let y={"@context":["https://www.w3.org/ns/credentials/v2",g],type:["VerifiableCredential","EndorsementCredential"],issuer:l,validFrom:new Date().toISOString(),credentialSubject:{type:["EndorsementSubject"],id:s,...r.endorsementComment?{endorsementComment:r.endorsementComment}:{}},...r.name?{name:r.name}:{name:`Endorsement of ${s}`},...r.description?{description:r.description}:{},...r.evidence&&{evidence:r.evidence}};return e.invoke.issueCredential(y)},"endorseCredential"),verifyEndorsement:c(async(t,n,r)=>{let i=await e.invoke.verifyCredential(n,r),l=m(n["@context"]),o=m(n.type);(!l.some(a=>a==="https://www.w3.org/ns/credentials/v2")||!l.some(a=>a===g))&&i.errors.push("linked-claims error: missing VCv2 or OBv3 context"),o.includes("EndorsementCredential")||i.errors.push("linked-claims error: missing EndorsementCredential type");let d=n.credentialSubject,s=Array.isArray(d)?d[0]:d;return m(s?.type).includes("EndorsementSubject")||i.errors.push("linked-claims error: credentialSubject.type must include EndorsementSubject"),s?.id||i.errors.push("linked-claims error: credentialSubject.id missing"),i.errors.length||i.checks.push("linked-claims"),i},"verifyEndorsement"),storeEndorsement:c(async(t,n,r)=>{let i=j(e,r?.storeName);if(!i)throw new Error("No store plane provider available");if(!e.store[i].uploadEncrypted||typeof e.store[i].uploadEncrypted!="function")throw new Error(`Store provider '${i}' does not support uploadEncrypted method`);let l=await e.store[i].uploadEncrypted(n),o=v(e,r?.indexName),d=!1,s=n.id||`urn:uuid:${globalThis.crypto?.randomUUID?.()||(()=>{throw new Error("Secure random UUID generation is not available. Please use an environment that supports crypto.randomUUID().")})()}`;if(o){let u=n.credentialSubject,a=Array.isArray(u)?u[0]:u,y={id:s,uri:l,type:m(n.type),endorsedId:a?.id,subjectId:a?.id,originalCredentialId:a?.id,issuedOn:n.validFrom||n.issuanceDate,category:"Endorsement",credentialId:r?.credentialId,sharedUri:r?.sharedUri,relationship:r?.relationship,visibility:r?.visibility??"public"};d=await e.index[o].add(y)}return{uri:l,indexed:d,id:s,indexName:o,storeName:i}},"storeEndorsement"),getEndorsements:c(async(t,n,r)=>{let i=v(e,r?.indexName);if(!i)return[];let l=f(n),o=n.id,d=o?{originalCredentialId:o}:{endorsedId:l[0]},s=await e.index[i].get(d),u=[];for(let a of s){let y=await e.read.get(a.uri);y&&u.push(y)}return u},"getEndorsements")}}),"getLinkedClaimsPlugin");
|
|
2
2
|
//# sourceMappingURL=linked-claims-plugin.cjs.production.min.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { LearnCard } from '@learncard/core';\nimport type { VC, UnsignedVC } from '@learncard/types';\nimport type { LinkedClaimsPlugin, LinkedClaimsPluginDependentMethods } from './types';\n\nexport * from './types';\n\nconst ENDORSEMENT_CONTEXT = 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json';\n\nconst getSubjectIds = (credential: VC): string[] => {\n const subject = credential.credentialSubject as any;\n if (Array.isArray(subject)) return subject.map(s => s?.id).filter(Boolean);\n return subject?.id ? [subject.id] : [];\n};\n\nconst pickIndexProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.index || {}).filter(\n k => !['providers', 'all'].includes(k)\n );\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n if (providers.includes('LearnCloud')) return 'LearnCloud';\n return providers[0];\n};\n\nconst pickStoreProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.store || {}).filter(k => k !== 'providers');\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n return providers[0];\n};\n\nconst ensureArray = <T>(arr: T | T[] | undefined): T[] =>\n Array.isArray(arr) ? arr : arr ? [arr] : [];\n\nexport const getLinkedClaimsPlugin = (\n learnCard: LearnCard<any, 'id' | 'store' | 'index' | 'read', LinkedClaimsPluginDependentMethods>\n): LinkedClaimsPlugin => ({\n name: 'LinkedClaims',\n displayName: 'LinkedClaims',\n description: 'Create, verify, store, and retrieve endorsement credentials linked to originals.',\n methods: {\n endorseCredential: async (_learnCard, original, details, opts) => {\n const issuer = learnCard.id.did();\n\n const originalId: string | undefined = (original as any).id;\n const subjectIds = getSubjectIds(original);\n const targetId = originalId || subjectIds[0];\n if (!targetId)\n throw new Error('Original credential must have either id or credentialSubject.id');\n\n const context: (string | Record<string, any>)[] = [\n 'https://www.w3.org/ns/credentials/v2',\n ENDORSEMENT_CONTEXT,\n ];\n\n const types: [string, ...string[]] = ['VerifiableCredential', 'EndorsementCredential'];\n\n const unsigned: UnsignedVC = {\n '@context': context as any,\n type: types,\n issuer,\n validFrom: new Date().toISOString(),\n credentialSubject: {\n type: ['EndorsementSubject'],\n id: targetId,\n ...(details.endorsementComment\n ? { endorsementComment: details.endorsementComment }\n : {}),\n },\n ...(details.name ? { name: details.name } : { name: `Endorsement of ${targetId}` }),\n ...(details.description ? { description: details.description } : {}),\n ...(details.evidence && { evidence: details.evidence }),\n };\n\n return learnCard.invoke.issueCredential(unsigned);\n },\n\n verifyEndorsement: async (_learnCard, endorsement, options) => {\n const check = await learnCard.invoke.verifyCredential(endorsement, options);\n\n const ctx = ensureArray((endorsement as any)['@context']);\n const types = ensureArray((endorsement as any)['type']);\n\n if (\n !ctx.some((c: string) => c === 'https://www.w3.org/ns/credentials/v2') ||\n !ctx.some((c: string) => c === ENDORSEMENT_CONTEXT)\n ) {\n check.errors.push('linked-claims error: missing VCv2 or OBv3 context');\n }\n if (!types.includes('EndorsementCredential')) {\n check.errors.push('linked-claims error: missing EndorsementCredential type');\n }\n\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const csTypes = ensureArray<string>(csObj?.type);\n if (!csTypes.includes('EndorsementSubject')) {\n check.errors.push(\n 'linked-claims error: credentialSubject.type must include EndorsementSubject'\n );\n }\n if (!csObj?.id) {\n check.errors.push('linked-claims error: credentialSubject.id missing');\n }\n\n if (!check.errors.length) check.checks.push('linked-claims');\n return check;\n },\n\n storeEndorsement: async (_learnCard, endorsement, options) => {\n const storeName = pickStoreProvider(learnCard, options?.storeName);\n if (!storeName) throw new Error('No store plane provider available');\n if (\n !learnCard.store[storeName].uploadEncrypted ||\n typeof learnCard.store[storeName].uploadEncrypted !== 'function'\n ) {\n throw new Error(\n `Store provider '${storeName}' does not support uploadEncrypted method`\n );\n }\n const uri: string = await (learnCard.store as any)[storeName].uploadEncrypted(\n endorsement\n );\n\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n let indexed = false;\n let id =\n (endorsement as any).id ||\n `urn:uuid:${
|
|
5
|
-
"mappings": "4dAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,2BAAAE,IAAA,eAAAC,EAAAH,GAMA,IAAMI,EAAsB,6DAEtBC,EAAgBC,EAACC,GAA6B,CAChD,IAAMC,EAAUD,EAAW,kBAC3B,OAAI,MAAM,QAAQC,CAAO,EAAUA,EAAQ,IAAIC,GAAKA,GAAG,EAAE,EAAE,OAAO,OAAO,EAClED,GAAS,GAAK,CAACA,EAAQ,EAAE,EAAI,CAAC,CACzC,EAJsB,iBAMhBE,EAAoBJ,EAAA,CAACK,EAAgBC,IAA2C,CAClF,IAAMC,EAAY,OAAO,KAAKF,EAAU,OAAS,CAAC,CAAC,EAAE,OACjDG,GAAK,CAAC,CAAC,YAAa,KAAK,EAAE,SAASA,CAAC,CACzC,EACA,
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["import type { LearnCard } from '@learncard/core';\nimport type { VC, UnsignedVC } from '@learncard/types';\nimport type { LinkedClaimsPlugin, LinkedClaimsPluginDependentMethods } from './types';\n\nexport * from './types';\n\nconst ENDORSEMENT_CONTEXT = 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json';\n\nconst getSubjectIds = (credential: VC): string[] => {\n const subject = credential.credentialSubject as any;\n if (Array.isArray(subject)) return subject.map(s => s?.id).filter(Boolean);\n return subject?.id ? [subject.id] : [];\n};\n\nconst pickIndexProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.index || {}).filter(\n k => !['providers', 'all'].includes(k)\n );\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n if (providers.includes('LearnCloud')) return 'LearnCloud';\n return providers[0];\n};\n\nconst pickStoreProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.store || {}).filter(k => k !== 'providers');\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n return providers[0];\n};\n\nconst ensureArray = <T>(arr: T | T[] | undefined): T[] =>\n Array.isArray(arr) ? arr : arr ? [arr] : [];\n\nexport const getLinkedClaimsPlugin = (\n learnCard: LearnCard<any, 'id' | 'store' | 'index' | 'read', LinkedClaimsPluginDependentMethods>\n): LinkedClaimsPlugin => ({\n name: 'LinkedClaims',\n displayName: 'LinkedClaims',\n description: 'Create, verify, store, and retrieve endorsement credentials linked to originals.',\n methods: {\n endorseCredential: async (_learnCard, original, details, opts) => {\n const issuer = learnCard.id.did();\n\n const originalId: string | undefined = (original as any).id;\n const subjectIds = getSubjectIds(original);\n const targetId = originalId || subjectIds[0];\n if (!targetId)\n throw new Error('Original credential must have either id or credentialSubject.id');\n\n const context: (string | Record<string, any>)[] = [\n 'https://www.w3.org/ns/credentials/v2',\n ENDORSEMENT_CONTEXT,\n ];\n\n const types: [string, ...string[]] = ['VerifiableCredential', 'EndorsementCredential'];\n\n const unsigned: UnsignedVC = {\n '@context': context as any,\n type: types,\n issuer,\n validFrom: new Date().toISOString(),\n credentialSubject: {\n type: ['EndorsementSubject'],\n id: targetId,\n ...(details.endorsementComment\n ? { endorsementComment: details.endorsementComment }\n : {}),\n },\n ...(details.name ? { name: details.name } : { name: `Endorsement of ${targetId}` }),\n ...(details.description ? { description: details.description } : {}),\n ...(details.evidence && { evidence: details.evidence as any }),\n };\n\n return learnCard.invoke.issueCredential(unsigned);\n },\n\n verifyEndorsement: async (_learnCard, endorsement, options) => {\n const check = await learnCard.invoke.verifyCredential(endorsement, options);\n\n const ctx = ensureArray((endorsement as any)['@context']);\n const types = ensureArray((endorsement as any)['type']);\n\n if (\n !ctx.some((c: string) => c === 'https://www.w3.org/ns/credentials/v2') ||\n !ctx.some((c: string) => c === ENDORSEMENT_CONTEXT)\n ) {\n check.errors.push('linked-claims error: missing VCv2 or OBv3 context');\n }\n if (!types.includes('EndorsementCredential')) {\n check.errors.push('linked-claims error: missing EndorsementCredential type');\n }\n\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const csTypes = ensureArray<string>(csObj?.type);\n if (!csTypes.includes('EndorsementSubject')) {\n check.errors.push(\n 'linked-claims error: credentialSubject.type must include EndorsementSubject'\n );\n }\n if (!csObj?.id) {\n check.errors.push('linked-claims error: credentialSubject.id missing');\n }\n\n if (!check.errors.length) check.checks.push('linked-claims');\n return check;\n },\n\n storeEndorsement: async (_learnCard, endorsement, options) => {\n const storeName = pickStoreProvider(learnCard, options?.storeName);\n if (!storeName) throw new Error('No store plane provider available');\n if (\n !learnCard.store[storeName].uploadEncrypted ||\n typeof learnCard.store[storeName].uploadEncrypted !== 'function'\n ) {\n throw new Error(\n `Store provider '${storeName}' does not support uploadEncrypted method`\n );\n }\n const uri: string = await (learnCard.store as any)[storeName].uploadEncrypted(\n endorsement\n );\n\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n let indexed = false;\n let id =\n (endorsement as any).id ||\n `urn:uuid:${(globalThis as any).crypto?.randomUUID?.() ||\n (() => {\n throw new Error(\n 'Secure random UUID generation is not available. Please use an environment that supports crypto.randomUUID().'\n );\n })()\n }`;\n\n if (indexName) {\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const record = {\n id,\n uri,\n type: ensureArray((endorsement as any).type),\n endorsedId: csObj?.id,\n subjectId: csObj?.id,\n originalCredentialId: csObj?.id,\n issuedOn: (endorsement as any).validFrom || (endorsement as any).issuanceDate,\n category: 'Endorsement',\n credentialId: options?.credentialId, // original credential id\n sharedUri: options?.sharedUri, // original credential shared uri\n relationship: options?.relationship,\n visibility: options?.visibility ?? 'public',\n };\n indexed = await (learnCard.index as any)[indexName].add(record);\n }\n\n return { uri, indexed, id, indexName, storeName };\n },\n\n getEndorsements: async (_learnCard, original, options) => {\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n if (!indexName) return [];\n\n const subjectIds = getSubjectIds(original);\n const originalId = (original as any).id;\n\n const query = originalId\n ? { originalCredentialId: originalId }\n : { endorsedId: subjectIds[0] };\n const records = await (learnCard.index as any)[indexName].get(query);\n\n const results: VC[] = [];\n for (const rec of records) {\n const vc = await learnCard.read.get(rec.uri);\n if (vc) results.push(vc as VC);\n }\n return results;\n },\n },\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["index_exports", "__export", "getLinkedClaimsPlugin", "__toCommonJS", "ENDORSEMENT_CONTEXT", "getSubjectIds", "__name", "credential", "subject", "s", "pickIndexProvider", "learnCard", "preferred", "providers", "k", "pickStoreProvider", "ensureArray", "arr", "getLinkedClaimsPlugin", "_learnCard", "original", "details", "opts", "issuer", "originalId", "subjectIds", "targetId", "unsigned", "endorsement", "options", "check", "ctx", "types", "c", "cs", "csObj", "storeName", "uri", "indexName", "indexed", "id", "record", "query", "records", "results", "rec", "vc"]
|
|
7
7
|
}
|
|
@@ -5,28 +5,22 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
5
5
|
var ENDORSEMENT_CONTEXT = "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json";
|
|
6
6
|
var getSubjectIds = /* @__PURE__ */ __name((credential) => {
|
|
7
7
|
const subject = credential.credentialSubject;
|
|
8
|
-
if (Array.isArray(subject))
|
|
9
|
-
return subject.map((s) => s?.id).filter(Boolean);
|
|
8
|
+
if (Array.isArray(subject)) return subject.map((s) => s?.id).filter(Boolean);
|
|
10
9
|
return subject?.id ? [subject.id] : [];
|
|
11
10
|
}, "getSubjectIds");
|
|
12
11
|
var pickIndexProvider = /* @__PURE__ */ __name((learnCard, preferred) => {
|
|
13
12
|
const providers = Object.keys(learnCard.index || {}).filter(
|
|
14
13
|
(k) => !["providers", "all"].includes(k)
|
|
15
14
|
);
|
|
16
|
-
if (!providers.length)
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
return preferred;
|
|
20
|
-
if (providers.includes("LearnCloud"))
|
|
21
|
-
return "LearnCloud";
|
|
15
|
+
if (!providers.length) return void 0;
|
|
16
|
+
if (preferred && providers.includes(preferred)) return preferred;
|
|
17
|
+
if (providers.includes("LearnCloud")) return "LearnCloud";
|
|
22
18
|
return providers[0];
|
|
23
19
|
}, "pickIndexProvider");
|
|
24
20
|
var pickStoreProvider = /* @__PURE__ */ __name((learnCard, preferred) => {
|
|
25
21
|
const providers = Object.keys(learnCard.store || {}).filter((k) => k !== "providers");
|
|
26
|
-
if (!providers.length)
|
|
27
|
-
|
|
28
|
-
if (preferred && providers.includes(preferred))
|
|
29
|
-
return preferred;
|
|
22
|
+
if (!providers.length) return void 0;
|
|
23
|
+
if (preferred && providers.includes(preferred)) return preferred;
|
|
30
24
|
return providers[0];
|
|
31
25
|
}, "pickStoreProvider");
|
|
32
26
|
var ensureArray = /* @__PURE__ */ __name((arr) => Array.isArray(arr) ? arr : arr ? [arr] : [], "ensureArray");
|
|
@@ -35,7 +29,7 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
35
29
|
displayName: "LinkedClaims",
|
|
36
30
|
description: "Create, verify, store, and retrieve endorsement credentials linked to originals.",
|
|
37
31
|
methods: {
|
|
38
|
-
endorseCredential: async (_learnCard, original, details, opts) => {
|
|
32
|
+
endorseCredential: /* @__PURE__ */ __name(async (_learnCard, original, details, opts) => {
|
|
39
33
|
const issuer = learnCard.id.did();
|
|
40
34
|
const originalId = original.id;
|
|
41
35
|
const subjectIds = getSubjectIds(original);
|
|
@@ -51,7 +45,7 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
51
45
|
"@context": context,
|
|
52
46
|
type: types,
|
|
53
47
|
issuer,
|
|
54
|
-
validFrom: new Date().toISOString(),
|
|
48
|
+
validFrom: (/* @__PURE__ */ new Date()).toISOString(),
|
|
55
49
|
credentialSubject: {
|
|
56
50
|
type: ["EndorsementSubject"],
|
|
57
51
|
id: targetId,
|
|
@@ -62,8 +56,8 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
62
56
|
...details.evidence && { evidence: details.evidence }
|
|
63
57
|
};
|
|
64
58
|
return learnCard.invoke.issueCredential(unsigned);
|
|
65
|
-
},
|
|
66
|
-
verifyEndorsement: async (_learnCard, endorsement, options) => {
|
|
59
|
+
}, "endorseCredential"),
|
|
60
|
+
verifyEndorsement: /* @__PURE__ */ __name(async (_learnCard, endorsement, options) => {
|
|
67
61
|
const check = await learnCard.invoke.verifyCredential(endorsement, options);
|
|
68
62
|
const ctx = ensureArray(endorsement["@context"]);
|
|
69
63
|
const types = ensureArray(endorsement["type"]);
|
|
@@ -84,14 +78,12 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
84
78
|
if (!csObj?.id) {
|
|
85
79
|
check.errors.push("linked-claims error: credentialSubject.id missing");
|
|
86
80
|
}
|
|
87
|
-
if (!check.errors.length)
|
|
88
|
-
check.checks.push("linked-claims");
|
|
81
|
+
if (!check.errors.length) check.checks.push("linked-claims");
|
|
89
82
|
return check;
|
|
90
|
-
},
|
|
91
|
-
storeEndorsement: async (_learnCard, endorsement, options) => {
|
|
83
|
+
}, "verifyEndorsement"),
|
|
84
|
+
storeEndorsement: /* @__PURE__ */ __name(async (_learnCard, endorsement, options) => {
|
|
92
85
|
const storeName = pickStoreProvider(learnCard, options?.storeName);
|
|
93
|
-
if (!storeName)
|
|
94
|
-
throw new Error("No store plane provider available");
|
|
86
|
+
if (!storeName) throw new Error("No store plane provider available");
|
|
95
87
|
if (!learnCard.store[storeName].uploadEncrypted || typeof learnCard.store[storeName].uploadEncrypted !== "function") {
|
|
96
88
|
throw new Error(
|
|
97
89
|
`Store provider '${storeName}' does not support uploadEncrypted method`
|
|
@@ -120,18 +112,19 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
120
112
|
issuedOn: endorsement.validFrom || endorsement.issuanceDate,
|
|
121
113
|
category: "Endorsement",
|
|
122
114
|
credentialId: options?.credentialId,
|
|
115
|
+
// original credential id
|
|
123
116
|
sharedUri: options?.sharedUri,
|
|
117
|
+
// original credential shared uri
|
|
124
118
|
relationship: options?.relationship,
|
|
125
119
|
visibility: options?.visibility ?? "public"
|
|
126
120
|
};
|
|
127
121
|
indexed = await learnCard.index[indexName].add(record);
|
|
128
122
|
}
|
|
129
123
|
return { uri, indexed, id, indexName, storeName };
|
|
130
|
-
},
|
|
131
|
-
getEndorsements: async (_learnCard, original, options) => {
|
|
124
|
+
}, "storeEndorsement"),
|
|
125
|
+
getEndorsements: /* @__PURE__ */ __name(async (_learnCard, original, options) => {
|
|
132
126
|
const indexName = pickIndexProvider(learnCard, options?.indexName);
|
|
133
|
-
if (!indexName)
|
|
134
|
-
return [];
|
|
127
|
+
if (!indexName) return [];
|
|
135
128
|
const subjectIds = getSubjectIds(original);
|
|
136
129
|
const originalId = original.id;
|
|
137
130
|
const query = originalId ? { originalCredentialId: originalId } : { endorsedId: subjectIds[0] };
|
|
@@ -139,11 +132,10 @@ var getLinkedClaimsPlugin = /* @__PURE__ */ __name((learnCard) => ({
|
|
|
139
132
|
const results = [];
|
|
140
133
|
for (const rec of records) {
|
|
141
134
|
const vc = await learnCard.read.get(rec.uri);
|
|
142
|
-
if (vc)
|
|
143
|
-
results.push(vc);
|
|
135
|
+
if (vc) results.push(vc);
|
|
144
136
|
}
|
|
145
137
|
return results;
|
|
146
|
-
}
|
|
138
|
+
}, "getEndorsements")
|
|
147
139
|
}
|
|
148
140
|
}), "getLinkedClaimsPlugin");
|
|
149
141
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { LearnCard } from '@learncard/core';\nimport type { VC, UnsignedVC } from '@learncard/types';\nimport type { LinkedClaimsPlugin, LinkedClaimsPluginDependentMethods } from './types';\n\nexport * from './types';\n\nconst ENDORSEMENT_CONTEXT = 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json';\n\nconst getSubjectIds = (credential: VC): string[] => {\n const subject = credential.credentialSubject as any;\n if (Array.isArray(subject)) return subject.map(s => s?.id).filter(Boolean);\n return subject?.id ? [subject.id] : [];\n};\n\nconst pickIndexProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.index || {}).filter(\n k => !['providers', 'all'].includes(k)\n );\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n if (providers.includes('LearnCloud')) return 'LearnCloud';\n return providers[0];\n};\n\nconst pickStoreProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.store || {}).filter(k => k !== 'providers');\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n return providers[0];\n};\n\nconst ensureArray = <T>(arr: T | T[] | undefined): T[] =>\n Array.isArray(arr) ? arr : arr ? [arr] : [];\n\nexport const getLinkedClaimsPlugin = (\n learnCard: LearnCard<any, 'id' | 'store' | 'index' | 'read', LinkedClaimsPluginDependentMethods>\n): LinkedClaimsPlugin => ({\n name: 'LinkedClaims',\n displayName: 'LinkedClaims',\n description: 'Create, verify, store, and retrieve endorsement credentials linked to originals.',\n methods: {\n endorseCredential: async (_learnCard, original, details, opts) => {\n const issuer = learnCard.id.did();\n\n const originalId: string | undefined = (original as any).id;\n const subjectIds = getSubjectIds(original);\n const targetId = originalId || subjectIds[0];\n if (!targetId)\n throw new Error('Original credential must have either id or credentialSubject.id');\n\n const context: (string | Record<string, any>)[] = [\n 'https://www.w3.org/ns/credentials/v2',\n ENDORSEMENT_CONTEXT,\n ];\n\n const types: [string, ...string[]] = ['VerifiableCredential', 'EndorsementCredential'];\n\n const unsigned: UnsignedVC = {\n '@context': context as any,\n type: types,\n issuer,\n validFrom: new Date().toISOString(),\n credentialSubject: {\n type: ['EndorsementSubject'],\n id: targetId,\n ...(details.endorsementComment\n ? { endorsementComment: details.endorsementComment }\n : {}),\n },\n ...(details.name ? { name: details.name } : { name: `Endorsement of ${targetId}` }),\n ...(details.description ? { description: details.description } : {}),\n ...(details.evidence && { evidence: details.evidence }),\n };\n\n return learnCard.invoke.issueCredential(unsigned);\n },\n\n verifyEndorsement: async (_learnCard, endorsement, options) => {\n const check = await learnCard.invoke.verifyCredential(endorsement, options);\n\n const ctx = ensureArray((endorsement as any)['@context']);\n const types = ensureArray((endorsement as any)['type']);\n\n if (\n !ctx.some((c: string) => c === 'https://www.w3.org/ns/credentials/v2') ||\n !ctx.some((c: string) => c === ENDORSEMENT_CONTEXT)\n ) {\n check.errors.push('linked-claims error: missing VCv2 or OBv3 context');\n }\n if (!types.includes('EndorsementCredential')) {\n check.errors.push('linked-claims error: missing EndorsementCredential type');\n }\n\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const csTypes = ensureArray<string>(csObj?.type);\n if (!csTypes.includes('EndorsementSubject')) {\n check.errors.push(\n 'linked-claims error: credentialSubject.type must include EndorsementSubject'\n );\n }\n if (!csObj?.id) {\n check.errors.push('linked-claims error: credentialSubject.id missing');\n }\n\n if (!check.errors.length) check.checks.push('linked-claims');\n return check;\n },\n\n storeEndorsement: async (_learnCard, endorsement, options) => {\n const storeName = pickStoreProvider(learnCard, options?.storeName);\n if (!storeName) throw new Error('No store plane provider available');\n if (\n !learnCard.store[storeName].uploadEncrypted ||\n typeof learnCard.store[storeName].uploadEncrypted !== 'function'\n ) {\n throw new Error(\n `Store provider '${storeName}' does not support uploadEncrypted method`\n );\n }\n const uri: string = await (learnCard.store as any)[storeName].uploadEncrypted(\n endorsement\n );\n\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n let indexed = false;\n let id =\n (endorsement as any).id ||\n `urn:uuid:${
|
|
5
|
-
"mappings": ";;;;AAMA,IAAM,sBAAsB;AAE5B,IAAM,gBAAgB,wBAAC,eAA6B;AAChD,QAAM,UAAU,WAAW;AAC3B,MAAI,MAAM,QAAQ,OAAO
|
|
4
|
+
"sourcesContent": ["import type { LearnCard } from '@learncard/core';\nimport type { VC, UnsignedVC } from '@learncard/types';\nimport type { LinkedClaimsPlugin, LinkedClaimsPluginDependentMethods } from './types';\n\nexport * from './types';\n\nconst ENDORSEMENT_CONTEXT = 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json';\n\nconst getSubjectIds = (credential: VC): string[] => {\n const subject = credential.credentialSubject as any;\n if (Array.isArray(subject)) return subject.map(s => s?.id).filter(Boolean);\n return subject?.id ? [subject.id] : [];\n};\n\nconst pickIndexProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.index || {}).filter(\n k => !['providers', 'all'].includes(k)\n );\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n if (providers.includes('LearnCloud')) return 'LearnCloud';\n return providers[0];\n};\n\nconst pickStoreProvider = (learnCard: any, preferred?: string): string | undefined => {\n const providers = Object.keys(learnCard.store || {}).filter(k => k !== 'providers');\n if (!providers.length) return undefined;\n if (preferred && providers.includes(preferred)) return preferred;\n return providers[0];\n};\n\nconst ensureArray = <T>(arr: T | T[] | undefined): T[] =>\n Array.isArray(arr) ? arr : arr ? [arr] : [];\n\nexport const getLinkedClaimsPlugin = (\n learnCard: LearnCard<any, 'id' | 'store' | 'index' | 'read', LinkedClaimsPluginDependentMethods>\n): LinkedClaimsPlugin => ({\n name: 'LinkedClaims',\n displayName: 'LinkedClaims',\n description: 'Create, verify, store, and retrieve endorsement credentials linked to originals.',\n methods: {\n endorseCredential: async (_learnCard, original, details, opts) => {\n const issuer = learnCard.id.did();\n\n const originalId: string | undefined = (original as any).id;\n const subjectIds = getSubjectIds(original);\n const targetId = originalId || subjectIds[0];\n if (!targetId)\n throw new Error('Original credential must have either id or credentialSubject.id');\n\n const context: (string | Record<string, any>)[] = [\n 'https://www.w3.org/ns/credentials/v2',\n ENDORSEMENT_CONTEXT,\n ];\n\n const types: [string, ...string[]] = ['VerifiableCredential', 'EndorsementCredential'];\n\n const unsigned: UnsignedVC = {\n '@context': context as any,\n type: types,\n issuer,\n validFrom: new Date().toISOString(),\n credentialSubject: {\n type: ['EndorsementSubject'],\n id: targetId,\n ...(details.endorsementComment\n ? { endorsementComment: details.endorsementComment }\n : {}),\n },\n ...(details.name ? { name: details.name } : { name: `Endorsement of ${targetId}` }),\n ...(details.description ? { description: details.description } : {}),\n ...(details.evidence && { evidence: details.evidence as any }),\n };\n\n return learnCard.invoke.issueCredential(unsigned);\n },\n\n verifyEndorsement: async (_learnCard, endorsement, options) => {\n const check = await learnCard.invoke.verifyCredential(endorsement, options);\n\n const ctx = ensureArray((endorsement as any)['@context']);\n const types = ensureArray((endorsement as any)['type']);\n\n if (\n !ctx.some((c: string) => c === 'https://www.w3.org/ns/credentials/v2') ||\n !ctx.some((c: string) => c === ENDORSEMENT_CONTEXT)\n ) {\n check.errors.push('linked-claims error: missing VCv2 or OBv3 context');\n }\n if (!types.includes('EndorsementCredential')) {\n check.errors.push('linked-claims error: missing EndorsementCredential type');\n }\n\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const csTypes = ensureArray<string>(csObj?.type);\n if (!csTypes.includes('EndorsementSubject')) {\n check.errors.push(\n 'linked-claims error: credentialSubject.type must include EndorsementSubject'\n );\n }\n if (!csObj?.id) {\n check.errors.push('linked-claims error: credentialSubject.id missing');\n }\n\n if (!check.errors.length) check.checks.push('linked-claims');\n return check;\n },\n\n storeEndorsement: async (_learnCard, endorsement, options) => {\n const storeName = pickStoreProvider(learnCard, options?.storeName);\n if (!storeName) throw new Error('No store plane provider available');\n if (\n !learnCard.store[storeName].uploadEncrypted ||\n typeof learnCard.store[storeName].uploadEncrypted !== 'function'\n ) {\n throw new Error(\n `Store provider '${storeName}' does not support uploadEncrypted method`\n );\n }\n const uri: string = await (learnCard.store as any)[storeName].uploadEncrypted(\n endorsement\n );\n\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n let indexed = false;\n let id =\n (endorsement as any).id ||\n `urn:uuid:${(globalThis as any).crypto?.randomUUID?.() ||\n (() => {\n throw new Error(\n 'Secure random UUID generation is not available. Please use an environment that supports crypto.randomUUID().'\n );\n })()\n }`;\n\n if (indexName) {\n const cs: any = (endorsement as any).credentialSubject;\n const csObj = Array.isArray(cs) ? cs[0] : cs;\n const record = {\n id,\n uri,\n type: ensureArray((endorsement as any).type),\n endorsedId: csObj?.id,\n subjectId: csObj?.id,\n originalCredentialId: csObj?.id,\n issuedOn: (endorsement as any).validFrom || (endorsement as any).issuanceDate,\n category: 'Endorsement',\n credentialId: options?.credentialId, // original credential id\n sharedUri: options?.sharedUri, // original credential shared uri\n relationship: options?.relationship,\n visibility: options?.visibility ?? 'public',\n };\n indexed = await (learnCard.index as any)[indexName].add(record);\n }\n\n return { uri, indexed, id, indexName, storeName };\n },\n\n getEndorsements: async (_learnCard, original, options) => {\n const indexName = pickIndexProvider(learnCard, options?.indexName);\n if (!indexName) return [];\n\n const subjectIds = getSubjectIds(original);\n const originalId = (original as any).id;\n\n const query = originalId\n ? { originalCredentialId: originalId }\n : { endorsedId: subjectIds[0] };\n const records = await (learnCard.index as any)[indexName].get(query);\n\n const results: VC[] = [];\n for (const rec of records) {\n const vc = await learnCard.read.get(rec.uri);\n if (vc) results.push(vc as VC);\n }\n return results;\n },\n },\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@learncard/linked-claims-plugin",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "LinkedClaims plugin to create, verify, store, and query endorsement credentials.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/linked-claims-plugin.esm.js",
|
|
@@ -9,19 +9,19 @@
|
|
|
9
9
|
],
|
|
10
10
|
"author": "Learning Economy Foundation (www.learningeconomy.io)",
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"homepage": "https://github.com/
|
|
12
|
+
"homepage": "https://github.com/learningeconomy/LearnCard/tree/main/packages/plugins/linked-claims/README.md",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
|
-
"url": "
|
|
15
|
+
"url": "https://github.com/learningeconomy/LearnCard"
|
|
16
16
|
},
|
|
17
17
|
"bugs": {
|
|
18
|
-
"url": "https://github.com/
|
|
18
|
+
"url": "https://github.com/learningeconomy/LearnCard/issues"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/jest": "^29.2.2",
|
|
22
22
|
"@types/node": "^17.0.31",
|
|
23
23
|
"aqu": "0.4.3",
|
|
24
|
-
"esbuild": "^0.
|
|
24
|
+
"esbuild": "^0.27.1",
|
|
25
25
|
"esbuild-jest": "^0.5.0",
|
|
26
26
|
"esbuild-plugin-copy": "^1.3.0",
|
|
27
27
|
"jest": "^29.3.0",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"types": "./dist/index.d.ts",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"why-is-node-running": "^2.2.2",
|
|
34
|
-
"@learncard/
|
|
35
|
-
"@learncard/
|
|
36
|
-
"@learncard/
|
|
34
|
+
"@learncard/types": "5.11.0",
|
|
35
|
+
"@learncard/vc-plugin": "^1.3.1",
|
|
36
|
+
"@learncard/core": "9.4.1"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "node ./scripts/build.mjs && shx cp ./scripts/mixedEntypoint.js ./dist/index.js && tsc --p tsconfig.json",
|