@sphereon/ssi-sdk.linked-vp 0.34.1-feature.SSISDK.82.and.SSISDK.70.345

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,514 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // plugin.schema.json
5
+ var plugin_schema_default = {
6
+ ILinkedVPManager: {
7
+ components: {
8
+ schemas: {
9
+ GeneratePresentationArgs: {
10
+ type: "object",
11
+ properties: {
12
+ linkedVpId: {
13
+ type: "string"
14
+ }
15
+ },
16
+ required: [
17
+ "linkedVpId"
18
+ ],
19
+ additionalProperties: false
20
+ },
21
+ LinkedVPPresentation: {
22
+ anyOf: [
23
+ {
24
+ type: "string"
25
+ },
26
+ {
27
+ $ref: "#/components/schemas/Record<string,any>"
28
+ }
29
+ ]
30
+ },
31
+ "Record<string,any>": {
32
+ type: "object"
33
+ },
34
+ GetServiceEntriesArgs: {
35
+ type: "object",
36
+ properties: {
37
+ tenantId: {
38
+ type: "string"
39
+ }
40
+ },
41
+ additionalProperties: false
42
+ },
43
+ LinkedVPServiceEntry: {
44
+ type: "object",
45
+ properties: {
46
+ id: {
47
+ type: "string"
48
+ },
49
+ type: {
50
+ type: "string",
51
+ const: "LinkedVerifiablePresentation"
52
+ },
53
+ serviceEndpoint: {
54
+ type: "string"
55
+ }
56
+ },
57
+ required: [
58
+ "id",
59
+ "type",
60
+ "serviceEndpoint"
61
+ ],
62
+ additionalProperties: false
63
+ },
64
+ HasLinkedVPEntryArgs: {
65
+ type: "object",
66
+ properties: {
67
+ linkedVpId: {
68
+ type: "string"
69
+ }
70
+ },
71
+ required: [
72
+ "linkedVpId"
73
+ ],
74
+ additionalProperties: false
75
+ },
76
+ PublishCredentialArgs: {
77
+ type: "object",
78
+ properties: {
79
+ digitalCredentialId: {
80
+ type: "string"
81
+ },
82
+ linkedVpId: {
83
+ type: "string"
84
+ },
85
+ tenantId: {
86
+ type: "string"
87
+ }
88
+ },
89
+ required: [
90
+ "digitalCredentialId"
91
+ ],
92
+ additionalProperties: false
93
+ },
94
+ LinkedVPEntry: {
95
+ type: "object",
96
+ properties: {
97
+ id: {
98
+ type: "string"
99
+ },
100
+ linkedVpId: {
101
+ type: "string"
102
+ },
103
+ tenantId: {
104
+ type: "string"
105
+ },
106
+ linkedVpFrom: {
107
+ type: "string",
108
+ format: "date-time"
109
+ },
110
+ createdAt: {
111
+ type: "string",
112
+ format: "date-time"
113
+ }
114
+ },
115
+ required: [
116
+ "id",
117
+ "linkedVpId",
118
+ "createdAt"
119
+ ],
120
+ additionalProperties: false
121
+ },
122
+ UnpublishCredentialArgs: {
123
+ type: "object",
124
+ properties: {
125
+ linkedVpId: {
126
+ type: "string"
127
+ }
128
+ },
129
+ required: [
130
+ "linkedVpId"
131
+ ],
132
+ additionalProperties: false
133
+ }
134
+ },
135
+ methods: {
136
+ lvpGeneratePresentation: {
137
+ description: "Generate and return a Verifiable Presentation for a published LinkedVP This is the main endpoint handler for GET /linked-vp/",
138
+ arguments: {
139
+ $ref: "#/components/schemas/GeneratePresentationArgs"
140
+ },
141
+ returnType: {
142
+ $ref: "#/components/schemas/LinkedVPPresentation"
143
+ }
144
+ },
145
+ lvpGetServiceEntries: {
146
+ description: "Get LinkedVP service entries for a DID to be added to a DID Document This is useful when generating DID Documents with toDidDocument",
147
+ arguments: {
148
+ $ref: "#/components/schemas/GetServiceEntriesArgs"
149
+ },
150
+ returnType: {
151
+ type: "array",
152
+ items: {
153
+ $ref: "#/components/schemas/LinkedVPServiceEntry"
154
+ }
155
+ }
156
+ },
157
+ lvpHasEntry: {
158
+ description: "Check if a LinkedVP entry exists by linkedVpId",
159
+ arguments: {
160
+ $ref: "#/components/schemas/HasLinkedVPEntryArgs"
161
+ },
162
+ returnType: {
163
+ type: "boolean"
164
+ }
165
+ },
166
+ lvpPublishCredential: {
167
+ description: "Publish a credential as a LinkedVP by adding it to the holder's DID Document",
168
+ arguments: {
169
+ $ref: "#/components/schemas/PublishCredentialArgs"
170
+ },
171
+ returnType: {
172
+ $ref: "#/components/schemas/LinkedVPEntry"
173
+ }
174
+ },
175
+ lvpUnpublishCredential: {
176
+ description: "Unpublish a credential by removing its LinkedVP entry from the DID Document",
177
+ arguments: {
178
+ $ref: "#/components/schemas/UnpublishCredentialArgs"
179
+ },
180
+ returnType: {
181
+ type: "boolean"
182
+ }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ };
188
+
189
+ // src/agent/LinkedVPManager.ts
190
+ import { IsNull, Not } from "typeorm";
191
+
192
+ // src/services/LinkedVPService.ts
193
+ import { calculateSdHash, defaultGenerateDigest } from "@sphereon/ssi-sdk.sd-jwt";
194
+ import { CredentialMapper, DocumentFormat, Loggers } from "@sphereon/ssi-types";
195
+
196
+ // src/types/ILinkedVPManager.ts
197
+ var LOGGER_NAMESPACE = "sphereon:linked-vp";
198
+
199
+ // src/services/LinkedVPService.ts
200
+ var logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE);
201
+ var CLOCK_SKEW = 120;
202
+ function extractOriginalCredential(credential) {
203
+ if (typeof credential === "string") {
204
+ return credential;
205
+ }
206
+ if ("digitalCredential" in credential) {
207
+ const udc = credential;
208
+ if (udc.originalVerifiableCredential) {
209
+ return udc.originalVerifiableCredential;
210
+ }
211
+ return udc.uniformVerifiableCredential;
212
+ }
213
+ if ("original" in credential) {
214
+ return credential.original;
215
+ }
216
+ return credential;
217
+ }
218
+ __name(extractOriginalCredential, "extractOriginalCredential");
219
+ async function createLinkedVPPresentation(holderDid, credential, agent) {
220
+ logger.debug(`Creating LinkedVP presentation for ${holderDid} of credential ${credential.id}`);
221
+ const identifier = await agent.identifierManagedGet({
222
+ identifier: holderDid
223
+ });
224
+ const originalCredential = extractOriginalCredential(credential);
225
+ const documentFormat = CredentialMapper.detectDocumentType(originalCredential);
226
+ switch (documentFormat) {
227
+ case DocumentFormat.SD_JWT_VC: {
228
+ const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(typeof originalCredential === "string" ? originalCredential : originalCredential.compactSdJwtVc, defaultGenerateDigest);
229
+ const hashAlg = decodedSdJwt.signedPayload._sd_alg ?? "sha-256";
230
+ const sdHash = calculateSdHash(decodedSdJwt.compactSdJwtVc, hashAlg, defaultGenerateDigest);
231
+ const kbJwtPayload = {
232
+ iat: Math.floor(Date.now() / 1e3 - CLOCK_SKEW),
233
+ sd_hash: sdHash
234
+ };
235
+ const presentationResult = await agent.createSdJwtPresentation({
236
+ presentation: decodedSdJwt.compactSdJwtVc,
237
+ kb: {
238
+ payload: kbJwtPayload
239
+ }
240
+ });
241
+ return {
242
+ documentFormat,
243
+ presentationPayload: presentationResult.presentation
244
+ };
245
+ }
246
+ case DocumentFormat.JSONLD: {
247
+ const vcObject = typeof originalCredential === "string" ? JSON.parse(originalCredential) : originalCredential;
248
+ const vpObject = {
249
+ "@context": [
250
+ "https://www.w3.org/2018/credentials/v1"
251
+ ],
252
+ type: [
253
+ "VerifiablePresentation"
254
+ ],
255
+ verifiableCredential: [
256
+ vcObject
257
+ ],
258
+ holder: holderDid
259
+ };
260
+ const verifiablePresentationSP = await agent.createVerifiablePresentation({
261
+ presentation: vpObject,
262
+ proofFormat: "lds",
263
+ keyRef: identifier.kmsKeyRef || identifier.kid
264
+ });
265
+ return {
266
+ documentFormat,
267
+ presentationPayload: verifiablePresentationSP
268
+ };
269
+ }
270
+ case DocumentFormat.MSO_MDOC: {
271
+ logger.warning("mso_mdoc format has basic support - production use requires proper mdoc VP token implementation");
272
+ return {
273
+ documentFormat,
274
+ presentationPayload: originalCredential
275
+ };
276
+ }
277
+ default: {
278
+ const vcJwt = typeof originalCredential === "string" ? originalCredential : JSON.stringify(originalCredential);
279
+ const vpPayload = {
280
+ iss: holderDid,
281
+ vp: {
282
+ "@context": [
283
+ "https://www.w3.org/2018/credentials/v1"
284
+ ],
285
+ type: [
286
+ "VerifiablePresentation"
287
+ ],
288
+ holder: holderDid,
289
+ verifiableCredential: [
290
+ vcJwt
291
+ ]
292
+ },
293
+ iat: Math.floor(Date.now() / 1e3 - CLOCK_SKEW),
294
+ exp: Math.floor(Date.now() / 1e3 + 600 + CLOCK_SKEW)
295
+ };
296
+ const vpJwt = await agent.createVerifiablePresentation({
297
+ presentation: vpPayload.vp,
298
+ proofFormat: "jwt",
299
+ keyRef: identifier.kmsKeyRef || identifier.kid
300
+ });
301
+ return {
302
+ documentFormat,
303
+ presentationPayload: vpJwt.proof && "jwt" in vpJwt.proof && vpJwt.proof.jwt || vpJwt
304
+ };
305
+ }
306
+ }
307
+ }
308
+ __name(createLinkedVPPresentation, "createLinkedVPPresentation");
309
+
310
+ // src/agent/LinkedVPManager.ts
311
+ var linkedVPManagerMethods = [
312
+ "lvpPublishCredential",
313
+ "lvpUnpublishCredential",
314
+ "lvpHasEntry",
315
+ "lvpGetServiceEntries",
316
+ "lvpGeneratePresentation"
317
+ ];
318
+ var LinkedVPManager = class {
319
+ static {
320
+ __name(this, "LinkedVPManager");
321
+ }
322
+ schema = plugin_schema_default.ILinkedVPManager;
323
+ methods = {
324
+ lvpPublishCredential: this.lvpPublishCredential.bind(this),
325
+ lvpUnpublishCredential: this.lvpUnpublishCredential.bind(this),
326
+ lvpHasEntry: this.lvpHasEntry.bind(this),
327
+ lvpGetServiceEntries: this.lvpGetServiceEntries.bind(this),
328
+ lvpGeneratePresentation: this.lvpGeneratePresentation.bind(this)
329
+ };
330
+ async lvpPublishCredential(args, context) {
331
+ const { digitalCredentialId } = args;
332
+ const credential = await context.agent.crsGetCredential({
333
+ id: digitalCredentialId
334
+ });
335
+ if (credential.linkedVpId) {
336
+ return Promise.reject(new Error(`Credential ${digitalCredentialId} is already published with linkedVpId ${credential.linkedVpId}`));
337
+ }
338
+ const linkedVpId = this.buildLinkedVpId(args.linkedVpId, credential.tenantId);
339
+ await this.ensureLinkedVpIdUnique(linkedVpId, context, credential.tenantId);
340
+ const publishedAt = /* @__PURE__ */ new Date();
341
+ await context.agent.crsUpdateCredential({
342
+ id: digitalCredentialId,
343
+ linkedVpId,
344
+ linkedVpFrom: publishedAt
345
+ });
346
+ return {
347
+ id: credential.id,
348
+ linkedVpId,
349
+ tenantId: credential.tenantId,
350
+ linkedVpFrom: publishedAt,
351
+ createdAt: credential.createdAt
352
+ };
353
+ }
354
+ async lvpUnpublishCredential(args, context) {
355
+ const { linkedVpId } = args;
356
+ const credentials = await context.agent.crsGetCredentials({
357
+ filter: [
358
+ {
359
+ linkedVpId
360
+ }
361
+ ]
362
+ });
363
+ if (credentials.length === 0) {
364
+ return Promise.reject(Error(`No credential found with linkedVpId ${linkedVpId}`));
365
+ }
366
+ const credential = credentials[0];
367
+ await context.agent.crsUpdateCredential({
368
+ id: credential.id,
369
+ linkedVpId: void 0,
370
+ linkedVpFrom: void 0
371
+ });
372
+ return true;
373
+ }
374
+ async lvpHasEntry(args, context) {
375
+ const { linkedVpId } = args;
376
+ try {
377
+ const credentials = await context.agent.crsGetCredentials({
378
+ filter: [
379
+ {
380
+ linkedVpId
381
+ }
382
+ ]
383
+ });
384
+ return credentials.length > 0;
385
+ } catch (error) {
386
+ return false;
387
+ }
388
+ }
389
+ async lvpGetServiceEntries(args, context) {
390
+ const { tenantId } = args;
391
+ const filter = {
392
+ linkedVpId: Not(IsNull())
393
+ };
394
+ if (tenantId) {
395
+ filter.tenantId = tenantId;
396
+ }
397
+ const credentials = await context.agent.crsGetCredentials({
398
+ filter: [
399
+ filter
400
+ ]
401
+ });
402
+ return credentials.filter((cred) => cred.linkedVpId !== void 0 && cred.linkedVpId !== null).flatMap((cred) => {
403
+ const uniformDocument = JSON.parse(cred.uniformDocument);
404
+ const holderDidForEntry = this.getHolderDid(uniformDocument);
405
+ return holderDidForEntry && holderDidForEntry.startsWith("did:web") ? [
406
+ this.credentialToServiceEntry(cred, holderDidForEntry)
407
+ ] : [];
408
+ });
409
+ }
410
+ async lvpGeneratePresentation(args, context) {
411
+ const { linkedVpId } = args;
412
+ const tenantId = this.parseTenantFromLinkedVpId(linkedVpId);
413
+ const uniqueCredentials = await context.agent.crsGetUniqueCredentials({
414
+ filter: [
415
+ {
416
+ linkedVpId: args.linkedVpId,
417
+ ...tenantId && {
418
+ tenantId
419
+ }
420
+ }
421
+ ]
422
+ });
423
+ if (uniqueCredentials.length === 0) {
424
+ return Promise.reject(Error(`No published credentials found for linkedVpId ${linkedVpId}`));
425
+ }
426
+ if (uniqueCredentials.length > 1) {
427
+ return Promise.reject(Error(`Multiple credentials found for linkedVpId ${linkedVpId}`));
428
+ }
429
+ const uniqueDigitalCredential = uniqueCredentials[0];
430
+ if (!uniqueDigitalCredential.uniformVerifiableCredential) {
431
+ return Promise.reject(Error(`uniformVerifiableCredential could not be found for credential ${uniqueDigitalCredential.digitalCredential.id}`));
432
+ }
433
+ const holderDid = this.getHolderDid(uniqueDigitalCredential.uniformVerifiableCredential);
434
+ if (!holderDid) {
435
+ return Promise.reject(Error(`Could not extract the holder did:web from cnf nor the credentialSubject id`));
436
+ }
437
+ return createLinkedVPPresentation(holderDid, uniqueDigitalCredential, context.agent);
438
+ }
439
+ getHolderDid(uniformDocument) {
440
+ if ("cnf" in uniformDocument && "jwk" in uniformDocument.cnf && "kid" in uniformDocument.cnf.jwk) {
441
+ return uniformDocument.cnf.jwk.kid.split("#")[0];
442
+ }
443
+ if ("credentialSubject" in uniformDocument) {
444
+ const credentialSubject = Array.isArray(uniformDocument.credentialSubject) ? uniformDocument.credentialSubject[0] : uniformDocument.credentialSubject;
445
+ if ("id" in credentialSubject && credentialSubject.id) {
446
+ if (credentialSubject.id.startsWith("did:web")) {
447
+ return credentialSubject.id;
448
+ }
449
+ }
450
+ }
451
+ return void 0;
452
+ }
453
+ parseTenantFromLinkedVpId(linkedVpId) {
454
+ const idx = linkedVpId.lastIndexOf("@");
455
+ return idx === -1 ? void 0 : linkedVpId.substring(idx + 1);
456
+ }
457
+ generateLinkedVpId() {
458
+ return `lvp-${Math.random().toString(36).substring(2, 15)}`;
459
+ }
460
+ async ensureLinkedVpIdUnique(linkedVpId, context, tenantId) {
461
+ const credentials = await context.agent.crsGetCredentials({
462
+ filter: [
463
+ {
464
+ linkedVpId,
465
+ ...tenantId && {
466
+ tenantId
467
+ }
468
+ }
469
+ ]
470
+ });
471
+ if (credentials.length > 0) {
472
+ throw new Error(`LinkedVP ID ${linkedVpId} already exists${tenantId ? ` for tenant ${tenantId}` : ""}`);
473
+ }
474
+ }
475
+ buildLinkedVpId(linkedVpId, tenantId) {
476
+ let finalLinkedVpId = linkedVpId || this.generateLinkedVpId();
477
+ if (tenantId && tenantId !== "" && !finalLinkedVpId.includes("@")) {
478
+ finalLinkedVpId = `${finalLinkedVpId}@${tenantId}`;
479
+ }
480
+ return finalLinkedVpId;
481
+ }
482
+ getBaseUrlFromDid(holderDid) {
483
+ if (!holderDid.startsWith("did:web:")) {
484
+ throw new Error(`Invalid DID: ${holderDid}, must be did:web`);
485
+ }
486
+ const withoutPrefix = holderDid.replace("did:web:", "");
487
+ const parts = withoutPrefix.split(":");
488
+ const domain = parts.shift();
489
+ const path = parts.join("/");
490
+ return path ? `https://${domain}/${path}` : `https://${domain}`;
491
+ }
492
+ buildServiceEndpoint(holderDid, linkedVpId) {
493
+ const baseUrl = this.getBaseUrlFromDid(holderDid);
494
+ const cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
495
+ return `${cleanBaseUrl}/linked-vp/${linkedVpId}`;
496
+ }
497
+ credentialToServiceEntry(credential, holderDid) {
498
+ if (!credential.linkedVpId) {
499
+ throw new Error(`Credential ${credential.id} does not have a linkedVpId`);
500
+ }
501
+ return {
502
+ id: `${holderDid}#${credential.linkedVpId}`,
503
+ type: "LinkedVerifiablePresentation",
504
+ serviceEndpoint: this.buildServiceEndpoint(holderDid, credential.linkedVpId)
505
+ };
506
+ }
507
+ };
508
+ export {
509
+ LOGGER_NAMESPACE,
510
+ LinkedVPManager,
511
+ linkedVPManagerMethods,
512
+ plugin_schema_default as schema
513
+ };
514
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../plugin.schema.json","../src/agent/LinkedVPManager.ts","../src/services/LinkedVPService.ts","../src/types/ILinkedVPManager.ts"],"sourcesContent":["{\n \"ILinkedVPManager\": {\n \"components\": {\n \"schemas\": {\n \"GeneratePresentationArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n },\n \"LinkedVPPresentation\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"$ref\": \"#/components/schemas/Record<string,any>\"\n }\n ]\n },\n \"Record<string,any>\": {\n \"type\": \"object\"\n },\n \"GetServiceEntriesArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"additionalProperties\": false\n },\n \"LinkedVPServiceEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"type\": {\n \"type\": \"string\",\n \"const\": \"LinkedVerifiablePresentation\"\n },\n \"serviceEndpoint\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"id\",\n \"type\",\n \"serviceEndpoint\"\n ],\n \"additionalProperties\": false\n },\n \"HasLinkedVPEntryArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n },\n \"PublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"digitalCredentialId\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"digitalCredentialId\"\n ],\n \"additionalProperties\": false\n },\n \"LinkedVPEntry\": {\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"linkedVpId\": {\n \"type\": \"string\"\n },\n \"tenantId\": {\n \"type\": \"string\"\n },\n \"linkedVpFrom\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"createdAt\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n }\n },\n \"required\": [\n \"id\",\n \"linkedVpId\",\n \"createdAt\"\n ],\n \"additionalProperties\": false\n },\n \"UnpublishCredentialArgs\": {\n \"type\": \"object\",\n \"properties\": {\n \"linkedVpId\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"linkedVpId\"\n ],\n \"additionalProperties\": false\n }\n },\n \"methods\": {\n \"lvpGeneratePresentation\": {\n \"description\": \"Generate and return a Verifiable Presentation for a published LinkedVP This is the main endpoint handler for GET /linked-vp/\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GeneratePresentationArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPPresentation\"\n }\n },\n \"lvpGetServiceEntries\": {\n \"description\": \"Get LinkedVP service entries for a DID to be added to a DID Document This is useful when generating DID Documents with toDidDocument\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/GetServiceEntriesArgs\"\n },\n \"returnType\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/LinkedVPServiceEntry\"\n }\n }\n },\n \"lvpHasEntry\": {\n \"description\": \"Check if a LinkedVP entry exists by linkedVpId\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/HasLinkedVPEntryArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n },\n \"lvpPublishCredential\": {\n \"description\": \"Publish a credential as a LinkedVP by adding it to the holder's DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/PublishCredentialArgs\"\n },\n \"returnType\": {\n \"$ref\": \"#/components/schemas/LinkedVPEntry\"\n }\n },\n \"lvpUnpublishCredential\": {\n \"description\": \"Unpublish a credential by removing its LinkedVP entry from the DID Document\",\n \"arguments\": {\n \"$ref\": \"#/components/schemas/UnpublishCredentialArgs\"\n },\n \"returnType\": {\n \"type\": \"boolean\"\n }\n }\n }\n }\n }\n}","import { DigitalCredential } from '@sphereon/ssi-sdk.data-store-types'\nimport { type IVerifiableCredential } from '@sphereon/ssi-types'\nimport { IAgentPlugin } from '@veramo/core'\nimport { IsNull, Not } from 'typeorm'\nimport { schema } from '../index'\nimport { createLinkedVPPresentation } from '../services/LinkedVPService'\nimport {\n GeneratePresentationArgs,\n GetServiceEntriesArgs,\n HasLinkedVPEntryArgs,\n ILinkedVPManager,\n LinkedVPEntry,\n LinkedVPPresentation,\n LinkedVPServiceEntry,\n PublishCredentialArgs,\n RequiredContext,\n UnpublishCredentialArgs,\n} from '../types'\n\n// Exposing the methods here for any REST implementation\nexport const linkedVPManagerMethods: Array<string> = [\n 'lvpPublishCredential',\n 'lvpUnpublishCredential',\n 'lvpHasEntry',\n 'lvpGetServiceEntries',\n 'lvpGeneratePresentation',\n]\n\n/**\n * {@inheritDoc ILinkedVPManager}\n */\nexport class LinkedVPManager implements IAgentPlugin {\n readonly schema = schema.ILinkedVPManager\n readonly methods: ILinkedVPManager = {\n lvpPublishCredential: this.lvpPublishCredential.bind(this),\n lvpUnpublishCredential: this.lvpUnpublishCredential.bind(this),\n lvpHasEntry: this.lvpHasEntry.bind(this),\n lvpGetServiceEntries: this.lvpGetServiceEntries.bind(this),\n lvpGeneratePresentation: this.lvpGeneratePresentation.bind(this),\n }\n\n private async lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry> {\n const { digitalCredentialId } = args\n\n const credential: DigitalCredential = await context.agent.crsGetCredential({ id: digitalCredentialId })\n\n if (credential.linkedVpId) {\n return Promise.reject(new Error(`Credential ${digitalCredentialId} is already published with linkedVpId ${credential.linkedVpId}`))\n }\n\n const linkedVpId = this.buildLinkedVpId(args.linkedVpId, credential.tenantId)\n\n await this.ensureLinkedVpIdUnique(linkedVpId, context, credential.tenantId)\n\n const publishedAt = new Date()\n await context.agent.crsUpdateCredential({\n id: digitalCredentialId,\n linkedVpId,\n linkedVpFrom: publishedAt,\n })\n\n return {\n id: credential.id,\n linkedVpId,\n tenantId: credential.tenantId,\n linkedVpFrom: publishedAt,\n createdAt: credential.createdAt,\n }\n }\n\n private async lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n // Find credential by linkedVpId and tenantId\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n if (credentials.length === 0) {\n return Promise.reject(Error(`No credential found with linkedVpId ${linkedVpId}`))\n }\n\n const credential = credentials[0]\n await context.agent.crsUpdateCredential({\n id: credential.id,\n linkedVpId: undefined,\n linkedVpFrom: undefined,\n })\n\n return true\n }\n\n private async lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean> {\n const { linkedVpId } = args\n\n try {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId }],\n })\n return credentials.length > 0\n } catch (error) {\n return false\n }\n }\n\n private async lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>> {\n const { tenantId } = args\n\n // Get all published credentials (credentials with linkedVpId set)\n const filter: any = { linkedVpId: Not(IsNull()) }\n if (tenantId) {\n filter.tenantId = tenantId\n }\n\n const credentials = await context.agent.crsGetCredentials({\n filter: [filter],\n })\n\n return credentials\n .filter((cred) => cred.linkedVpId !== undefined && cred.linkedVpId !== null)\n .flatMap((cred) => {\n const uniformDocument = JSON.parse(cred.uniformDocument) as IVerifiableCredential\n const holderDidForEntry = this.getHolderDid(uniformDocument)\n return holderDidForEntry && holderDidForEntry.startsWith('did:web') ? [this.credentialToServiceEntry(cred, holderDidForEntry)] : []\n })\n }\n\n private async lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation> {\n const { linkedVpId } = args\n const tenantId = this.parseTenantFromLinkedVpId(linkedVpId)\n\n const uniqueCredentials = await context.agent.crsGetUniqueCredentials({\n filter: [\n {\n linkedVpId: args.linkedVpId,\n ...(tenantId && { tenantId }),\n },\n ],\n })\n if (uniqueCredentials.length === 0) {\n return Promise.reject(Error(`No published credentials found for linkedVpId ${linkedVpId}`))\n }\n if (uniqueCredentials.length > 1) {\n return Promise.reject(Error(`Multiple credentials found for linkedVpId ${linkedVpId}`))\n }\n\n const uniqueDigitalCredential = uniqueCredentials[0]\n if (!uniqueDigitalCredential.uniformVerifiableCredential) {\n return Promise.reject(Error(`uniformVerifiableCredential could not be found for credential ${uniqueDigitalCredential.digitalCredential.id}`))\n }\n const holderDid = this.getHolderDid(uniqueDigitalCredential.uniformVerifiableCredential)\n if (!holderDid) {\n return Promise.reject(Error(`Could not extract the holder did:web from cnf nor the credentialSubject id`))\n }\n\n // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueDigitalCredential, context.agent)\n }\n\n private getHolderDid(uniformDocument: IVerifiableCredential): string | undefined {\n // Determine holder DID for identifier resolution\n if ('cnf' in uniformDocument && 'jwk' in uniformDocument.cnf && 'kid' in uniformDocument.cnf.jwk) {\n return uniformDocument.cnf.jwk.kid.split('#')[0]\n }\n\n if ('credentialSubject' in uniformDocument) {\n const credentialSubject = Array.isArray(uniformDocument.credentialSubject)\n ? uniformDocument.credentialSubject[0]\n : uniformDocument.credentialSubject\n if ('id' in credentialSubject && credentialSubject.id) {\n if (credentialSubject.id.startsWith('did:web')) {\n return credentialSubject.id\n }\n }\n }\n\n return undefined\n }\n\n private parseTenantFromLinkedVpId(linkedVpId: string): string | undefined {\n const idx = linkedVpId.lastIndexOf('@')\n return idx === -1 ? undefined : linkedVpId.substring(idx + 1)\n }\n\n private generateLinkedVpId(): string {\n return `lvp-${Math.random().toString(36).substring(2, 15)}`\n }\n\n private async ensureLinkedVpIdUnique(linkedVpId: string, context: RequiredContext, tenantId?: string): Promise<void> {\n const credentials = await context.agent.crsGetCredentials({\n filter: [{ linkedVpId, ...(tenantId && { tenantId }) }],\n })\n\n if (credentials.length > 0) {\n throw new Error(`LinkedVP ID ${linkedVpId} already exists${tenantId ? ` for tenant ${tenantId}` : ''}`)\n }\n }\n\n private buildLinkedVpId(linkedVpId: string | undefined, tenantId: string | undefined) {\n let finalLinkedVpId = linkedVpId || this.generateLinkedVpId()\n\n // Append tenantId if provided and not already present\n if (tenantId && tenantId !== '' && !finalLinkedVpId.includes('@')) {\n finalLinkedVpId = `${finalLinkedVpId}@${tenantId}`\n }\n return finalLinkedVpId\n }\n\n private getBaseUrlFromDid(holderDid: string): string {\n if (!holderDid.startsWith('did:web:')) {\n throw new Error(`Invalid DID: ${holderDid}, must be did:web`)\n }\n\n const withoutPrefix = holderDid.replace('did:web:', '') // example.com:tenants:tenant1\n const parts = withoutPrefix.split(':')\n const domain = parts.shift()! // example.com\n const path = parts.join('/') // tenants/tenant1\n\n return path\n ? `https://${domain}/${path}` // https://example.com/tenants/tenant1\n : `https://${domain}` // https://example.com\n }\n\n private buildServiceEndpoint(holderDid: string, linkedVpId: string): string {\n const baseUrl = this.getBaseUrlFromDid(holderDid)\n const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n return `${cleanBaseUrl}/linked-vp/${linkedVpId}`\n }\n\n private credentialToServiceEntry(credential: DigitalCredential, holderDid: string): LinkedVPServiceEntry {\n if (!credential.linkedVpId) {\n throw new Error(`Credential ${credential.id} does not have a linkedVpId`)\n }\n\n return {\n id: `${holderDid}#${credential.linkedVpId}`,\n type: 'LinkedVerifiablePresentation',\n serviceEndpoint: this.buildServiceEndpoint(holderDid, credential.linkedVpId),\n }\n }\n}\n","import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'\nimport { calculateSdHash, defaultGenerateDigest, PartialSdJwtKbJwt } from '@sphereon/ssi-sdk.sd-jwt'\n\nimport {\n CredentialMapper,\n DocumentFormat,\n Loggers,\n OriginalVerifiableCredential,\n SdJwtDecodedVerifiableCredential,\n WrappedVerifiableCredential,\n} from '@sphereon/ssi-types'\nimport { LinkedVPPresentation, LOGGER_NAMESPACE, RequiredContext } from '../types'\n\nconst logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)\nconst CLOCK_SKEW = 120 // TODO make adjustable?\n\n/**\n * Extracts the original credential from various wrapper types\n */\nfunction extractOriginalCredential(\n credential: UniqueDigitalCredential | WrappedVerifiableCredential | OriginalVerifiableCredential,\n): OriginalVerifiableCredential {\n if (typeof credential === 'string') {\n return credential\n }\n\n if ('digitalCredential' in credential) {\n const udc = credential as UniqueDigitalCredential\n if (udc.originalVerifiableCredential) {\n return udc.originalVerifiableCredential\n }\n return udc.uniformVerifiableCredential as OriginalVerifiableCredential\n }\n\n if ('original' in credential) {\n return credential.original\n }\n\n return credential as OriginalVerifiableCredential\n}\n\n/**\n * Creates a Verifiable Presentation for LinkedVP publishing\n * Contains multiple credentials in a single JWT VP\n * No nonce or audience since this is for publishing, not responding to verification\n */\nexport async function createLinkedVPPresentation(\n holderDid: string,\n credential: UniqueDigitalCredential,\n agent: RequiredContext['agent'],\n): Promise<LinkedVPPresentation> {\n logger.debug(`Creating LinkedVP presentation for ${holderDid} of credential ${credential.id}`)\n\n const identifier = await agent.identifierManagedGet({ identifier: holderDid })\n const originalCredential = extractOriginalCredential(credential)\n const documentFormat = CredentialMapper.detectDocumentType(originalCredential)\n switch (documentFormat) {\n case DocumentFormat.SD_JWT_VC: {\n // SD-JWT with KB-JWT\n const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(\n typeof originalCredential === 'string' ? originalCredential : (originalCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc,\n defaultGenerateDigest,\n )\n\n const hashAlg = decodedSdJwt.signedPayload._sd_alg ?? 'sha-256'\n const sdHash = calculateSdHash(decodedSdJwt.compactSdJwtVc, hashAlg, defaultGenerateDigest)\n const kbJwtPayload: PartialSdJwtKbJwt['payload'] = {\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n sd_hash: sdHash,\n }\n\n const presentationResult = await agent.createSdJwtPresentation({\n presentation: decodedSdJwt.compactSdJwtVc,\n kb: {\n payload: kbJwtPayload as any, // FIXME?\n },\n })\n\n return {\n documentFormat,\n presentationPayload: presentationResult.presentation,\n }\n }\n case DocumentFormat.JSONLD: {\n // JSON-LD VC - create JSON-LD VP with challenge and domain in proof\n const vcObject = typeof originalCredential === 'string' ? JSON.parse(originalCredential) : originalCredential\n\n const vpObject = {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n verifiableCredential: [vcObject],\n holder: holderDid,\n }\n\n // Create JSON-LD VP with proof\n const verifiablePresentationSP = await agent.createVerifiablePresentation({\n presentation: vpObject,\n proofFormat: 'lds',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n return {\n documentFormat,\n presentationPayload: verifiablePresentationSP,\n }\n }\n case DocumentFormat.MSO_MDOC: {\n // ISO mdoc - create mdoc VP token\n // This is a placeholder implementation\n // Full implementation would require:\n // 1. Decode the mdoc using CredentialMapper or mdoc utilities\n // 2. Build proper mdoc VP token with session transcript\n // 3. Include nonce/audience in the session transcript\n logger.warning('mso_mdoc format has basic support - production use requires proper mdoc VP token implementation')\n\n return {\n documentFormat,\n presentationPayload: originalCredential,\n }\n }\n default: {\n // JWT VC - create JWT VP with nonce and aud in payload\n const vcJwt = typeof originalCredential === 'string' ? originalCredential : JSON.stringify(originalCredential)\n\n // Create VP JWT using agent method\n const vpPayload = {\n iss: holderDid,\n vp: {\n '@context': ['https://www.w3.org/2018/credentials/v1'],\n type: ['VerifiablePresentation'],\n holder: holderDid,\n verifiableCredential: [vcJwt],\n },\n iat: Math.floor(Date.now() / 1000 - CLOCK_SKEW),\n exp: Math.floor(Date.now() / 1000 + 600 + CLOCK_SKEW), // 10 minutes\n }\n\n // Use the agent's JWT creation capability\n const vpJwt = await agent.createVerifiablePresentation({\n presentation: vpPayload.vp,\n proofFormat: 'jwt',\n keyRef: identifier.kmsKeyRef || identifier.kid,\n })\n\n return {\n documentFormat,\n presentationPayload: (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt,\n }\n }\n }\n}\n","import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'\nimport { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'\nimport { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'\nimport { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'\nimport { DocumentFormat } from '@sphereon/ssi-types'\nimport { IAgentContext, IPluginMethodMap } from '@veramo/core'\nimport { IKeyManager } from '@veramo/core/src/types/IKeyManager'\n\nexport const LOGGER_NAMESPACE = 'sphereon:linked-vp'\n\nexport type LinkedVPPresentation = {\n documentFormat: DocumentFormat\n presentationPayload: string | Record<string, any>\n}\n\nexport interface ILinkedVPManager extends IPluginMethodMap {\n /**\n * Publish a credential as a LinkedVP by adding it to the holder's DID Document\n * @param args - Publication arguments including credential ID and scope configuration\n * @param context - Agent context\n */\n lvpPublishCredential(args: PublishCredentialArgs, context: RequiredContext): Promise<LinkedVPEntry>\n\n /**\n * Unpublish a credential by removing its LinkedVP entry from the DID Document\n * @param args - Unpublish arguments\n * @param context - Agent context\n */\n lvpUnpublishCredential(args: UnpublishCredentialArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Check if a LinkedVP entry exists by linkedVpId\n * @param args - Query arguments\n * @param context - Agent context\n */\n lvpHasEntry(args: HasLinkedVPEntryArgs, context: RequiredContext): Promise<boolean>\n\n /**\n * Get LinkedVP service entries for a DID to be added to a DID Document\n * This is useful when generating DID Documents with toDidDocument\n * @param args - Query arguments for the DID\n * @param context - Agent context\n */\n lvpGetServiceEntries(args: GetServiceEntriesArgs, context: RequiredContext): Promise<Array<LinkedVPServiceEntry>>\n\n /**\n * Generate and return a Verifiable Presentation for a published LinkedVP\n * This is the main endpoint handler for GET /linked-vp/{linkedVpId}\n * @param args - Generation arguments\n * @param context - Agent context\n */\n lvpGeneratePresentation(args: GeneratePresentationArgs, context: RequiredContext): Promise<LinkedVPPresentation>\n}\n\nexport type PublishCredentialArgs = {\n digitalCredentialId: string\n linkedVpId?: string // Optional: if not provided, will be auto-generated\n}\n\nexport type UnpublishCredentialArgs = {\n linkedVpId: string\n}\n\nexport type HasLinkedVPEntryArgs = {\n linkedVpId: string\n}\n\nexport type GetServiceEntriesArgs = {\n tenantId?: string\n}\n\nexport type GeneratePresentationArgs = {\n linkedVpId: string\n}\n\nexport type LinkedVPEntry = {\n id: string\n linkedVpId: string\n linkedVpFrom?: Date\n tenantId?: string\n createdAt: Date\n}\n\nexport type LinkedVPServiceEntry = {\n id: string\n type: 'LinkedVerifiablePresentation'\n serviceEndpoint: string\n}\n\nexport type RequiredContext = IAgentContext<IIdentifierResolution & ICredentialStore & IKeyManager & VcdmCredentialPlugin & ISDJwtPlugin>\n"],"mappings":"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","names":["IsNull","Not","calculateSdHash","defaultGenerateDigest","CredentialMapper","DocumentFormat","Loggers","LOGGER_NAMESPACE","logger","Loggers","DEFAULT","get","LOGGER_NAMESPACE","CLOCK_SKEW","extractOriginalCredential","credential","udc","originalVerifiableCredential","uniformVerifiableCredential","original","createLinkedVPPresentation","holderDid","agent","debug","id","identifier","identifierManagedGet","originalCredential","documentFormat","CredentialMapper","detectDocumentType","DocumentFormat","SD_JWT_VC","decodedSdJwt","decodeSdJwtVcAsync","compactSdJwtVc","defaultGenerateDigest","hashAlg","signedPayload","_sd_alg","sdHash","calculateSdHash","kbJwtPayload","iat","Math","floor","Date","now","sd_hash","presentationResult","createSdJwtPresentation","presentation","kb","payload","presentationPayload","JSONLD","vcObject","JSON","parse","vpObject","type","verifiableCredential","holder","verifiablePresentationSP","createVerifiablePresentation","proofFormat","keyRef","kmsKeyRef","kid","MSO_MDOC","warning","vcJwt","stringify","vpPayload","iss","vp","exp","vpJwt","proof","jwt","linkedVPManagerMethods","LinkedVPManager","schema","ILinkedVPManager","methods","lvpPublishCredential","bind","lvpUnpublishCredential","lvpHasEntry","lvpGetServiceEntries","lvpGeneratePresentation","args","context","digitalCredentialId","credential","agent","crsGetCredential","id","linkedVpId","Promise","reject","Error","buildLinkedVpId","tenantId","ensureLinkedVpIdUnique","publishedAt","Date","crsUpdateCredential","linkedVpFrom","createdAt","credentials","crsGetCredentials","filter","length","undefined","error","Not","IsNull","cred","flatMap","uniformDocument","JSON","parse","holderDidForEntry","getHolderDid","startsWith","credentialToServiceEntry","parseTenantFromLinkedVpId","uniqueCredentials","crsGetUniqueCredentials","uniqueDigitalCredential","uniformVerifiableCredential","digitalCredential","holderDid","createLinkedVPPresentation","cnf","jwk","kid","split","credentialSubject","Array","isArray","idx","lastIndexOf","substring","generateLinkedVpId","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","withoutPrefix","replace","parts","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@sphereon/ssi-sdk.linked-vp",
3
+ "version": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
4
+ "source": "src/index.ts",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ "react-native": "./dist/index.js",
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "require": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "veramo": {
21
+ "pluginInterfaces": {
22
+ "ILinkedVPManager": "./src/types/ILinkedVPManager.ts"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsup --config ../../tsup.config.ts --tsconfig ../../tsconfig.tsup.json",
27
+ "generate-plugin-schema": "tsx ../../packages/dev/bin/sphereon.js dev generate-plugin-schema"
28
+ },
29
+ "dependencies": {
30
+ "@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
31
+ "@sphereon/ssi-sdk.credential-store": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
32
+ "@sphereon/ssi-sdk.credential-vcdm": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
33
+ "@sphereon/ssi-sdk.data-store": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
34
+ "@sphereon/ssi-sdk.data-store-types": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
35
+ "@sphereon/ssi-sdk.sd-jwt": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
36
+ "@sphereon/ssi-types": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
37
+ "@veramo/utils": "4.2.0",
38
+ "cross-fetch": "^4.1.0",
39
+ "dcql": "1.0.1",
40
+ "pkijs": "^3.2.4",
41
+ "typeorm": "0.3.20",
42
+ "uint8arrays": "3.1.1"
43
+ },
44
+ "devDependencies": {
45
+ "@sphereon/ssi-sdk-ext.key-manager": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
46
+ "@sphereon/ssi-sdk-ext.kms-local": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
47
+ "@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
48
+ "@sphereon/ssi-sdk.credential-vcdm1-jwt-provider": "0.34.1-feature.SSISDK.82.and.SSISDK.70.345+e5abbf1a",
49
+ "@veramo/data-store": "4.2.0",
50
+ "@veramo/did-manager": "4.2.0",
51
+ "@veramo/did-provider-web": "4.2.0",
52
+ "@veramo/did-resolver": "4.2.0",
53
+ "@veramo/key-manager": "4.2.0",
54
+ "@veramo/remote-client": "4.2.0",
55
+ "@veramo/remote-server": "4.2.0",
56
+ "did-resolver": "^4.1.0",
57
+ "web-did-resolver": "^2.0.30"
58
+ },
59
+ "files": [
60
+ "dist",
61
+ "src",
62
+ "README.md",
63
+ "plugin.schema.json",
64
+ "LICENSE"
65
+ ],
66
+ "private": false,
67
+ "publishConfig": {
68
+ "access": "public"
69
+ },
70
+ "repository": "git@github.com:Sphereon-Opensource/SSI-SDK.git",
71
+ "author": "Sphereon <dev@sphereon.com>",
72
+ "license": "Apache-2.0",
73
+ "keywords": [
74
+ "Sphereon",
75
+ "SSI",
76
+ "Veramo",
77
+ "Presentation Defintion Manager",
78
+ "PD Manager"
79
+ ],
80
+ "gitHead": "e5abbf1a0404fbc2aeb350a248183f70598ffbc0"
81
+ }