@sphereon/ssi-sdk.linked-vp 0.34.1-feature.SSISDK.82.linkedVP.326 → 0.34.1-feature.SSISDK.82.linkedVP.327

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.cjs CHANGED
@@ -265,7 +265,10 @@ async function createLinkedVPPresentation(holderDid, credential, agent) {
265
265
  payload: kbJwtPayload
266
266
  }
267
267
  });
268
- return presentationResult.presentation;
268
+ return {
269
+ documentFormat,
270
+ presentationPayload: presentationResult.presentation
271
+ };
269
272
  }
270
273
  case import_ssi_types.DocumentFormat.JSONLD: {
271
274
  const vcObject = typeof originalCredential === "string" ? JSON.parse(originalCredential) : originalCredential;
@@ -281,15 +284,22 @@ async function createLinkedVPPresentation(holderDid, credential, agent) {
281
284
  ],
282
285
  holder: holderDid
283
286
  };
284
- return await agent.createVerifiablePresentation({
287
+ const verifiablePresentationSP = await agent.createVerifiablePresentation({
285
288
  presentation: vpObject,
286
289
  proofFormat: "lds",
287
290
  keyRef: identifier.kmsKeyRef || identifier.kid
288
291
  });
292
+ return {
293
+ documentFormat,
294
+ presentationPayload: verifiablePresentationSP
295
+ };
289
296
  }
290
297
  case import_ssi_types.DocumentFormat.MSO_MDOC: {
291
298
  logger.warning("mso_mdoc format has basic support - production use requires proper mdoc VP token implementation");
292
- return originalCredential;
299
+ return {
300
+ documentFormat,
301
+ presentationPayload: originalCredential
302
+ };
293
303
  }
294
304
  default: {
295
305
  const vcJwt = typeof originalCredential === "string" ? originalCredential : JSON.stringify(originalCredential);
@@ -315,7 +325,10 @@ async function createLinkedVPPresentation(holderDid, credential, agent) {
315
325
  proofFormat: "jwt",
316
326
  keyRef: identifier.kmsKeyRef || identifier.kid
317
327
  });
318
- return vpJwt.proof && "jwt" in vpJwt.proof && vpJwt.proof.jwt || vpJwt;
328
+ return {
329
+ documentFormat,
330
+ presentationPayload: vpJwt.proof && "jwt" in vpJwt.proof && vpJwt.proof.jwt || vpJwt
331
+ };
319
332
  }
320
333
  }
321
334
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../plugin.schema.json","../src/agent/LinkedVPManager.ts","../src/services/LinkedVPService.ts","../src/types/ILinkedVPManager.ts"],"sourcesContent":["/**\n * @public\n */\nimport schema from '../plugin.schema.json'\nexport { schema }\nexport { LinkedVPManager, linkedVPManagerMethods } from './agent/LinkedVPManager'\nexport * from './types/ILinkedVPManager'\n","{\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 { 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 readonly holderDids: Record<string, string>\n\n constructor(options: { holderDids: Record<string, string> }) {\n this.holderDids = options.holderDids\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 .map((cred) => {\n const holderDidForEntry = this.getHolderDid(cred.tenantId)\n return 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 const holderDid = this.getHolderDid(tenantId)\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 // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueCredentials[0], context.agent)\n }\n\n private getHolderDid(tenantId: string | undefined) {\n const holderDid = this.holderDids[tenantId ?? 'default']\n if (!holderDid) {\n throw Error(`No holder did supplied for tenant ${tenantId ?? 'default'}`)\n }\n return holderDid\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-${Date.now()}-${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 { 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<string | Record<string, any>> {\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 presentationResult.presentation\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 return await agent.createVerifiablePresentation({\n presentation: vpObject,\n proofFormat: 'lds',\n keyRef: identifier.kmsKeyRef || identifier.kid,\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 originalCredential\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 (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt\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 { 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 = string | Record<string, any>\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 tenantId?: string\n linkedVpFrom?: Date\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":["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","JSONLD","vcObject","JSON","parse","vpObject","type","verifiableCredential","holder","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","holderDids","options","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","map","holderDidForEntry","getHolderDid","credentialToServiceEntry","parseTenantFromLinkedVpId","holderDid","uniqueCredentials","crsGetUniqueCredentials","createLinkedVPPresentation","idx","lastIndexOf","substring","generateLinkedVpId","now","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","startsWith","withoutPrefix","replace","parts","split","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
1
+ {"version":3,"sources":["../src/index.ts","../plugin.schema.json","../src/agent/LinkedVPManager.ts","../src/services/LinkedVPService.ts","../src/types/ILinkedVPManager.ts"],"sourcesContent":["/**\n * @public\n */\nimport schema from '../plugin.schema.json'\nexport { schema }\nexport { LinkedVPManager, linkedVPManagerMethods } from './agent/LinkedVPManager'\nexport * from './types/ILinkedVPManager'\n","{\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 { 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 readonly holderDids: Record<string, string>\n\n constructor(options: { holderDids: Record<string, string> }) {\n this.holderDids = options.holderDids\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 .map((cred) => {\n const holderDidForEntry = this.getHolderDid(cred.tenantId)\n return 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 const holderDid = this.getHolderDid(tenantId)\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 // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueCredentials[0], context.agent)\n }\n\n private getHolderDid(tenantId: string | undefined) {\n const holderDid = this.holderDids[tenantId ?? 'default']\n if (!holderDid) {\n throw Error(`No holder did supplied for tenant ${tenantId ?? 'default'}`)\n }\n return holderDid\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-${Date.now()}-${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 tenantId?: string\n linkedVpFrom?: Date\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":["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","holderDids","options","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","map","holderDidForEntry","getHolderDid","credentialToServiceEntry","parseTenantFromLinkedVpId","holderDid","uniqueCredentials","crsGetUniqueCredentials","createLinkedVPPresentation","idx","lastIndexOf","substring","generateLinkedVpId","now","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","startsWith","withoutPrefix","replace","parts","split","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
package/dist/index.d.cts CHANGED
@@ -3,6 +3,7 @@ import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resoluti
3
3
  import { ICredentialStore } from '@sphereon/ssi-sdk.credential-store';
4
4
  import { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm';
5
5
  import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt';
6
+ import { DocumentFormat } from '@sphereon/ssi-types';
6
7
  import { IKeyManager } from '@veramo/core/src/types/IKeyManager';
7
8
 
8
9
  var ILinkedVPManager$1 = {
@@ -191,7 +192,10 @@ var plugin_schema = {
191
192
  };
192
193
 
193
194
  declare const LOGGER_NAMESPACE = "sphereon:linked-vp";
194
- type LinkedVPPresentation = string | Record<string, any>;
195
+ type LinkedVPPresentation = {
196
+ documentFormat: DocumentFormat;
197
+ presentationPayload: string | Record<string, any>;
198
+ };
195
199
  interface ILinkedVPManager extends IPluginMethodMap {
196
200
  /**
197
201
  * Publish a credential as a LinkedVP by adding it to the holder's DID Document
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resoluti
3
3
  import { ICredentialStore } from '@sphereon/ssi-sdk.credential-store';
4
4
  import { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm';
5
5
  import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt';
6
+ import { DocumentFormat } from '@sphereon/ssi-types';
6
7
  import { IKeyManager } from '@veramo/core/src/types/IKeyManager';
7
8
 
8
9
  var ILinkedVPManager$1 = {
@@ -191,7 +192,10 @@ var plugin_schema = {
191
192
  };
192
193
 
193
194
  declare const LOGGER_NAMESPACE = "sphereon:linked-vp";
194
- type LinkedVPPresentation = string | Record<string, any>;
195
+ type LinkedVPPresentation = {
196
+ documentFormat: DocumentFormat;
197
+ presentationPayload: string | Record<string, any>;
198
+ };
195
199
  interface ILinkedVPManager extends IPluginMethodMap {
196
200
  /**
197
201
  * Publish a credential as a LinkedVP by adding it to the holder's DID Document
package/dist/index.js CHANGED
@@ -238,7 +238,10 @@ async function createLinkedVPPresentation(holderDid, credential, agent) {
238
238
  payload: kbJwtPayload
239
239
  }
240
240
  });
241
- return presentationResult.presentation;
241
+ return {
242
+ documentFormat,
243
+ presentationPayload: presentationResult.presentation
244
+ };
242
245
  }
243
246
  case DocumentFormat.JSONLD: {
244
247
  const vcObject = typeof originalCredential === "string" ? JSON.parse(originalCredential) : originalCredential;
@@ -254,15 +257,22 @@ async function createLinkedVPPresentation(holderDid, credential, agent) {
254
257
  ],
255
258
  holder: holderDid
256
259
  };
257
- return await agent.createVerifiablePresentation({
260
+ const verifiablePresentationSP = await agent.createVerifiablePresentation({
258
261
  presentation: vpObject,
259
262
  proofFormat: "lds",
260
263
  keyRef: identifier.kmsKeyRef || identifier.kid
261
264
  });
265
+ return {
266
+ documentFormat,
267
+ presentationPayload: verifiablePresentationSP
268
+ };
262
269
  }
263
270
  case DocumentFormat.MSO_MDOC: {
264
271
  logger.warning("mso_mdoc format has basic support - production use requires proper mdoc VP token implementation");
265
- return originalCredential;
272
+ return {
273
+ documentFormat,
274
+ presentationPayload: originalCredential
275
+ };
266
276
  }
267
277
  default: {
268
278
  const vcJwt = typeof originalCredential === "string" ? originalCredential : JSON.stringify(originalCredential);
@@ -288,7 +298,10 @@ async function createLinkedVPPresentation(holderDid, credential, agent) {
288
298
  proofFormat: "jwt",
289
299
  keyRef: identifier.kmsKeyRef || identifier.kid
290
300
  });
291
- return vpJwt.proof && "jwt" in vpJwt.proof && vpJwt.proof.jwt || vpJwt;
301
+ return {
302
+ documentFormat,
303
+ presentationPayload: vpJwt.proof && "jwt" in vpJwt.proof && vpJwt.proof.jwt || vpJwt
304
+ };
292
305
  }
293
306
  }
294
307
  }
package/dist/index.js.map CHANGED
@@ -1 +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 { 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 readonly holderDids: Record<string, string>\n\n constructor(options: { holderDids: Record<string, string> }) {\n this.holderDids = options.holderDids\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 .map((cred) => {\n const holderDidForEntry = this.getHolderDid(cred.tenantId)\n return 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 const holderDid = this.getHolderDid(tenantId)\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 // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueCredentials[0], context.agent)\n }\n\n private getHolderDid(tenantId: string | undefined) {\n const holderDid = this.holderDids[tenantId ?? 'default']\n if (!holderDid) {\n throw Error(`No holder did supplied for tenant ${tenantId ?? 'default'}`)\n }\n return holderDid\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-${Date.now()}-${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 { 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<string | Record<string, any>> {\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 presentationResult.presentation\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 return await agent.createVerifiablePresentation({\n presentation: vpObject,\n proofFormat: 'lds',\n keyRef: identifier.kmsKeyRef || identifier.kid,\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 originalCredential\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 (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt\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 { 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 = string | Record<string, any>\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 tenantId?: string\n linkedVpFrom?: Date\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","JSONLD","vcObject","JSON","parse","vpObject","type","verifiableCredential","holder","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","holderDids","options","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","map","holderDidForEntry","getHolderDid","credentialToServiceEntry","parseTenantFromLinkedVpId","holderDid","uniqueCredentials","crsGetUniqueCredentials","createLinkedVPPresentation","idx","lastIndexOf","substring","generateLinkedVpId","now","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","startsWith","withoutPrefix","replace","parts","split","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
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 { 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 readonly holderDids: Record<string, string>\n\n constructor(options: { holderDids: Record<string, string> }) {\n this.holderDids = options.holderDids\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 .map((cred) => {\n const holderDidForEntry = this.getHolderDid(cred.tenantId)\n return 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 const holderDid = this.getHolderDid(tenantId)\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 // Generate the Verifiable Presentation with all published credentials\n return createLinkedVPPresentation(holderDid, uniqueCredentials[0], context.agent)\n }\n\n private getHolderDid(tenantId: string | undefined) {\n const holderDid = this.holderDids[tenantId ?? 'default']\n if (!holderDid) {\n throw Error(`No holder did supplied for tenant ${tenantId ?? 'default'}`)\n }\n return holderDid\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-${Date.now()}-${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 tenantId?: string\n linkedVpFrom?: Date\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":";;;;AAAA;AAAA,EACE,kBAAoB;AAAA,IAClB,YAAc;AAAA,MACZ,SAAW;AAAA,QACT,0BAA4B;AAAA,UAC1B,MAAQ;AAAA,UACR,YAAc;AAAA,YACZ,YAAc;AAAA,cACZ,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,UAAY;AAAA,YACV;AAAA,UACF;AAAA,UACA,sBAAwB;AAAA,QAC1B;AAAA,QACA,sBAAwB;AAAA,UACtB,OAAS;AAAA,YACP;AAAA,cACE,MAAQ;AAAA,YACV;AAAA,YACA;AAAA,cACE,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,UACpB,MAAQ;AAAA,QACV;AAAA,QACA,uBAAyB;AAAA,UACvB,MAAQ;AAAA,UACR,YAAc;AAAA,YACZ,UAAY;AAAA,cACV,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,sBAAwB;AAAA,QAC1B;AAAA,QACA,sBAAwB;AAAA,UACtB,MAAQ;AAAA,UACR,YAAc;AAAA,YACZ,IAAM;AAAA,cACJ,MAAQ;AAAA,YACV;AAAA,YACA,MAAQ;AAAA,cACN,MAAQ;AAAA,cACR,OAAS;AAAA,YACX;AAAA,YACA,iBAAmB;AAAA,cACjB,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,UAAY;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA,sBAAwB;AAAA,QAC1B;AAAA,QACA,sBAAwB;AAAA,UACtB,MAAQ;AAAA,UACR,YAAc;AAAA,YACZ,YAAc;AAAA,cACZ,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,UAAY;AAAA,YACV;AAAA,UACF;AAAA,UACA,sBAAwB;AAAA,QAC1B;AAAA,QACA,uBAAyB;AAAA,UACvB,MAAQ;AAAA,UACR,YAAc;AAAA,YACZ,qBAAuB;AAAA,cACrB,MAAQ;AAAA,YACV;AAAA,YACA,YAAc;AAAA,cACZ,MAAQ;AAAA,YACV;AAAA,YACA,UAAY;AAAA,cACV,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,UAAY;AAAA,YACV;AAAA,UACF;AAAA,UACA,sBAAwB;AAAA,QAC1B;AAAA,QACA,eAAiB;AAAA,UACf,MAAQ;AAAA,UACR,YAAc;AAAA,YACZ,IAAM;AAAA,cACJ,MAAQ;AAAA,YACV;AAAA,YACA,YAAc;AAAA,cACZ,MAAQ;AAAA,YACV;AAAA,YACA,UAAY;AAAA,cACV,MAAQ;AAAA,YACV;AAAA,YACA,cAAgB;AAAA,cACd,MAAQ;AAAA,cACR,QAAU;AAAA,YACZ;AAAA,YACA,WAAa;AAAA,cACX,MAAQ;AAAA,cACR,QAAU;AAAA,YACZ;AAAA,UACF;AAAA,UACA,UAAY;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA,sBAAwB;AAAA,QAC1B;AAAA,QACA,yBAA2B;AAAA,UACzB,MAAQ;AAAA,UACR,YAAc;AAAA,YACZ,YAAc;AAAA,cACZ,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,UAAY;AAAA,YACV;AAAA,UACF;AAAA,UACA,sBAAwB;AAAA,QAC1B;AAAA,MACF;AAAA,MACA,SAAW;AAAA,QACT,yBAA2B;AAAA,UACzB,aAAe;AAAA,UACf,WAAa;AAAA,YACX,MAAQ;AAAA,UACV;AAAA,UACA,YAAc;AAAA,YACZ,MAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,sBAAwB;AAAA,UACtB,aAAe;AAAA,UACf,WAAa;AAAA,YACX,MAAQ;AAAA,UACV;AAAA,UACA,YAAc;AAAA,YACZ,MAAQ;AAAA,YACR,OAAS;AAAA,cACP,MAAQ;AAAA,YACV;AAAA,UACF;AAAA,QACF;AAAA,QACA,aAAe;AAAA,UACb,aAAe;AAAA,UACf,WAAa;AAAA,YACX,MAAQ;AAAA,UACV;AAAA,UACA,YAAc;AAAA,YACZ,MAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,sBAAwB;AAAA,UACtB,aAAe;AAAA,UACf,WAAa;AAAA,YACX,MAAQ;AAAA,UACV;AAAA,UACA,YAAc;AAAA,YACZ,MAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,wBAA0B;AAAA,UACxB,aAAe;AAAA,UACf,WAAa;AAAA,YACX,MAAQ;AAAA,UACV;AAAA,UACA,YAAc;AAAA,YACZ,MAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACpLA,SAASA,QAAQC,WAAW;;;ACD5B,SAASC,iBAAiBC,6BAAgD;AAE1E,SACEC,kBACAC,gBACAC,eAIK;;;ACFA,IAAMC,mBAAmB;;;ADKhC,IAAMC,SAASC,QAAQC,QAAQC,IAAIC,gBAAAA;AACnC,IAAMC,aAAa;AAKnB,SAASC,0BACPC,YAAgG;AAEhG,MAAI,OAAOA,eAAe,UAAU;AAClC,WAAOA;EACT;AAEA,MAAI,uBAAuBA,YAAY;AACrC,UAAMC,MAAMD;AACZ,QAAIC,IAAIC,8BAA8B;AACpC,aAAOD,IAAIC;IACb;AACA,WAAOD,IAAIE;EACb;AAEA,MAAI,cAAcH,YAAY;AAC5B,WAAOA,WAAWI;EACpB;AAEA,SAAOJ;AACT;AApBSD;AA2BT,eAAsBM,2BACpBC,WACAN,YACAO,OAA+B;AAE/Bd,SAAOe,MAAM,sCAAsCF,SAAAA,kBAA2BN,WAAWS,EAAE,EAAE;AAE7F,QAAMC,aAAa,MAAMH,MAAMI,qBAAqB;IAAED,YAAYJ;EAAU,CAAA;AAC5E,QAAMM,qBAAqBb,0BAA0BC,UAAAA;AACrD,QAAMa,iBAAiBC,iBAAiBC,mBAAmBH,kBAAAA;AAC3D,UAAQC,gBAAAA;IACN,KAAKG,eAAeC,WAAW;AAE7B,YAAMC,eAAe,MAAMJ,iBAAiBK,mBAC1C,OAAOP,uBAAuB,WAAWA,qBAAsBA,mBAAwDQ,gBACvHC,qBAAAA;AAGF,YAAMC,UAAUJ,aAAaK,cAAcC,WAAW;AACtD,YAAMC,SAASC,gBAAgBR,aAAaE,gBAAgBE,SAASD,qBAAAA;AACrE,YAAMM,eAA6C;QACjDC,KAAKC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,MAAOlC,UAAAA;QACpCmC,SAASR;MACX;AAEA,YAAMS,qBAAqB,MAAM3B,MAAM4B,wBAAwB;QAC7DC,cAAclB,aAAaE;QAC3BiB,IAAI;UACFC,SAASX;QACX;MACF,CAAA;AAEA,aAAO;QACLd;QACA0B,qBAAqBL,mBAAmBE;MAC1C;IACF;IACA,KAAKpB,eAAewB,QAAQ;AAE1B,YAAMC,WAAW,OAAO7B,uBAAuB,WAAW8B,KAAKC,MAAM/B,kBAAAA,IAAsBA;AAE3F,YAAMgC,WAAW;QACf,YAAY;UAAC;;QACbC,MAAM;UAAC;;QACPC,sBAAsB;UAACL;;QACvBM,QAAQzC;MACV;AAGA,YAAM0C,2BAA2B,MAAMzC,MAAM0C,6BAA6B;QACxEb,cAAcQ;QACdM,aAAa;QACbC,QAAQzC,WAAW0C,aAAa1C,WAAW2C;MAC7C,CAAA;AACA,aAAO;QACLxC;QACA0B,qBAAqBS;MACvB;IACF;IACA,KAAKhC,eAAesC,UAAU;AAO5B7D,aAAO8D,QAAQ,iGAAA;AAEf,aAAO;QACL1C;QACA0B,qBAAqB3B;MACvB;IACF;IACA,SAAS;AAEP,YAAM4C,QAAQ,OAAO5C,uBAAuB,WAAWA,qBAAqB8B,KAAKe,UAAU7C,kBAAAA;AAG3F,YAAM8C,YAAY;QAChBC,KAAKrD;QACLsD,IAAI;UACF,YAAY;YAAC;;UACbf,MAAM;YAAC;;UACPE,QAAQzC;UACRwC,sBAAsB;YAACU;;QACzB;QACA5B,KAAKC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,MAAOlC,UAAAA;QACpC+D,KAAKhC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,MAAO,MAAMlC,UAAAA;MAC5C;AAGA,YAAMgE,QAAQ,MAAMvD,MAAM0C,6BAA6B;QACrDb,cAAcsB,UAAUE;QACxBV,aAAa;QACbC,QAAQzC,WAAW0C,aAAa1C,WAAW2C;MAC7C,CAAA;AAEA,aAAO;QACLxC;QACA0B,qBAAsBuB,MAAMC,SAAS,SAASD,MAAMC,SAASD,MAAMC,MAAMC,OAAQF;MACnF;IACF;EACF;AACF;AAvGsBzD;;;AD3Bf,IAAM4D,yBAAwC;EACnD;EACA;EACA;EACA;EACA;;AAMK,IAAMC,kBAAN,MAAMA;EA5Bb,OA4BaA;;;EACFC,SAASA,sBAAOC;EAChBC,UAA4B;IACnCC,sBAAsB,KAAKA,qBAAqBC,KAAK,IAAI;IACzDC,wBAAwB,KAAKA,uBAAuBD,KAAK,IAAI;IAC7DE,aAAa,KAAKA,YAAYF,KAAK,IAAI;IACvCG,sBAAsB,KAAKA,qBAAqBH,KAAK,IAAI;IACzDI,yBAAyB,KAAKA,wBAAwBJ,KAAK,IAAI;EACjE;EAEiBK;EAEjB,YAAYC,SAAiD;AAC3D,SAAKD,aAAaC,QAAQD;EAC5B;EAEA,MAAcN,qBAAqBQ,MAA6BC,SAAkD;AAChH,UAAM,EAAEC,oBAAmB,IAAKF;AAEhC,UAAMG,aAAgC,MAAMF,QAAQG,MAAMC,iBAAiB;MAAEC,IAAIJ;IAAoB,CAAA;AAErG,QAAIC,WAAWI,YAAY;AACzB,aAAOC,QAAQC,OAAO,IAAIC,MAAM,cAAcR,mBAAAA,yCAA4DC,WAAWI,UAAU,EAAE,CAAA;IACnI;AAEA,UAAMA,aAAa,KAAKI,gBAAgBX,KAAKO,YAAYJ,WAAWS,QAAQ;AAE5E,UAAM,KAAKC,uBAAuBN,YAAYN,SAASE,WAAWS,QAAQ;AAE1E,UAAME,cAAc,oBAAIC,KAAAA;AACxB,UAAMd,QAAQG,MAAMY,oBAAoB;MACtCV,IAAIJ;MACJK;MACAU,cAAcH;IAChB,CAAA;AAEA,WAAO;MACLR,IAAIH,WAAWG;MACfC;MACAK,UAAUT,WAAWS;MACrBK,cAAcH;MACdI,WAAWf,WAAWe;IACxB;EACF;EAEA,MAAcxB,uBAAuBM,MAA+BC,SAA4C;AAC9G,UAAM,EAAEM,WAAU,IAAKP;AAGvB,UAAMmB,cAAc,MAAMlB,QAAQG,MAAMgB,kBAAkB;MACxDC,QAAQ;QAAC;UAAEd;QAAW;;IACxB,CAAA;AACA,QAAIY,YAAYG,WAAW,GAAG;AAC5B,aAAOd,QAAQC,OAAOC,MAAM,uCAAuCH,UAAAA,EAAY,CAAA;IACjF;AAEA,UAAMJ,aAAagB,YAAY,CAAA;AAC/B,UAAMlB,QAAQG,MAAMY,oBAAoB;MACtCV,IAAIH,WAAWG;MACfC,YAAYgB;MACZN,cAAcM;IAChB,CAAA;AAEA,WAAO;EACT;EAEA,MAAc5B,YAAYK,MAA4BC,SAA4C;AAChG,UAAM,EAAEM,WAAU,IAAKP;AAEvB,QAAI;AACF,YAAMmB,cAAc,MAAMlB,QAAQG,MAAMgB,kBAAkB;QACxDC,QAAQ;UAAC;YAAEd;UAAW;;MACxB,CAAA;AACA,aAAOY,YAAYG,SAAS;IAC9B,SAASE,OAAO;AACd,aAAO;IACT;EACF;EAEA,MAAc5B,qBAAqBI,MAA6BC,SAAgE;AAC9H,UAAM,EAAEW,SAAQ,IAAKZ;AAGrB,UAAMqB,SAAc;MAAEd,YAAYkB,IAAIC,OAAAA,CAAAA;IAAU;AAChD,QAAId,UAAU;AACZS,aAAOT,WAAWA;IACpB;AAEA,UAAMO,cAAc,MAAMlB,QAAQG,MAAMgB,kBAAkB;MACxDC,QAAQ;QAACA;;IACX,CAAA;AAEA,WAAOF,YACJE,OAAO,CAACM,SAASA,KAAKpB,eAAegB,UAAaI,KAAKpB,eAAe,IAAA,EACtEqB,IAAI,CAACD,SAAAA;AACJ,YAAME,oBAAoB,KAAKC,aAAaH,KAAKf,QAAQ;AACzD,aAAO,KAAKmB,yBAAyBJ,MAAME,iBAAAA;IAC7C,CAAA;EACJ;EAEA,MAAchC,wBAAwBG,MAAgCC,SAAyD;AAC7H,UAAM,EAAEM,WAAU,IAAKP;AACvB,UAAMY,WAAW,KAAKoB,0BAA0BzB,UAAAA;AAChD,UAAM0B,YAAY,KAAKH,aAAalB,QAAAA;AAEpC,UAAMsB,oBAAoB,MAAMjC,QAAQG,MAAM+B,wBAAwB;MACpEd,QAAQ;QACN;UACEd,YAAYP,KAAKO;UACjB,GAAIK,YAAY;YAAEA;UAAS;QAC7B;;IAEJ,CAAA;AACA,QAAIsB,kBAAkBZ,WAAW,GAAG;AAClC,aAAOd,QAAQC,OAAOC,MAAM,iDAAiDH,UAAAA,EAAY,CAAA;IAC3F;AACA,QAAI2B,kBAAkBZ,SAAS,GAAG;AAChC,aAAOd,QAAQC,OAAOC,MAAM,6CAA6CH,UAAAA,EAAY,CAAA;IACvF;AAGA,WAAO6B,2BAA2BH,WAAWC,kBAAkB,CAAA,GAAIjC,QAAQG,KAAK;EAClF;EAEQ0B,aAAalB,UAA8B;AACjD,UAAMqB,YAAY,KAAKnC,WAAWc,YAAY,SAAA;AAC9C,QAAI,CAACqB,WAAW;AACd,YAAMvB,MAAM,qCAAqCE,YAAY,SAAA,EAAW;IAC1E;AACA,WAAOqB;EACT;EAEQD,0BAA0BzB,YAAwC;AACxE,UAAM8B,MAAM9B,WAAW+B,YAAY,GAAA;AACnC,WAAOD,QAAQ,KAAKd,SAAYhB,WAAWgC,UAAUF,MAAM,CAAA;EAC7D;EAEQG,qBAA6B;AACnC,WAAO,OAAOzB,KAAK0B,IAAG,CAAA,IAAMC,KAAKC,OAAM,EAAGC,SAAS,EAAA,EAAIL,UAAU,GAAG,EAAA,CAAA;EACtE;EAEA,MAAc1B,uBAAuBN,YAAoBN,SAA0BW,UAAkC;AACnH,UAAMO,cAAc,MAAMlB,QAAQG,MAAMgB,kBAAkB;MACxDC,QAAQ;QAAC;UAAEd;UAAY,GAAIK,YAAY;YAAEA;UAAS;QAAG;;IACvD,CAAA;AAEA,QAAIO,YAAYG,SAAS,GAAG;AAC1B,YAAM,IAAIZ,MAAM,eAAeH,UAAAA,kBAA4BK,WAAW,eAAeA,QAAAA,KAAa,EAAA,EAAI;IACxG;EACF;EAEQD,gBAAgBJ,YAAgCK,UAA8B;AACpF,QAAIiC,kBAAkBtC,cAAc,KAAKiC,mBAAkB;AAG3D,QAAI5B,YAAYA,aAAa,MAAM,CAACiC,gBAAgBC,SAAS,GAAA,GAAM;AACjED,wBAAkB,GAAGA,eAAAA,IAAmBjC,QAAAA;IAC1C;AACA,WAAOiC;EACT;EAEQE,kBAAkBd,WAA2B;AACnD,QAAI,CAACA,UAAUe,WAAW,UAAA,GAAa;AACrC,YAAM,IAAItC,MAAM,gBAAgBuB,SAAAA,mBAA4B;IAC9D;AAEA,UAAMgB,gBAAgBhB,UAAUiB,QAAQ,YAAY,EAAA;AACpD,UAAMC,QAAQF,cAAcG,MAAM,GAAA;AAClC,UAAMC,SAASF,MAAMG,MAAK;AAC1B,UAAMC,OAAOJ,MAAMK,KAAK,GAAA;AAExB,WAAOD,OACH,WAAWF,MAAAA,IAAUE,IAAAA,KACrB,WAAWF,MAAAA;EACjB;EAEQI,qBAAqBxB,WAAmB1B,YAA4B;AAC1E,UAAMmD,UAAU,KAAKX,kBAAkBd,SAAAA;AACvC,UAAM0B,eAAeD,QAAQE,SAAS,GAAA,IAAOF,QAAQG,MAAM,GAAG,EAAC,IAAKH;AACpE,WAAO,GAAGC,YAAAA,cAA0BpD,UAAAA;EACtC;EAEQwB,yBAAyB5B,YAA+B8B,WAAyC;AACvG,QAAI,CAAC9B,WAAWI,YAAY;AAC1B,YAAM,IAAIG,MAAM,cAAcP,WAAWG,EAAE,6BAA6B;IAC1E;AAEA,WAAO;MACLA,IAAI,GAAG2B,SAAAA,IAAa9B,WAAWI,UAAU;MACzCuD,MAAM;MACNC,iBAAiB,KAAKN,qBAAqBxB,WAAW9B,WAAWI,UAAU;IAC7E;EACF;AACF;","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","holderDids","options","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","map","holderDidForEntry","getHolderDid","credentialToServiceEntry","parseTenantFromLinkedVpId","holderDid","uniqueCredentials","crsGetUniqueCredentials","createLinkedVPPresentation","idx","lastIndexOf","substring","generateLinkedVpId","now","Math","random","toString","finalLinkedVpId","includes","getBaseUrlFromDid","startsWith","withoutPrefix","replace","parts","split","domain","shift","path","join","buildServiceEndpoint","baseUrl","cleanBaseUrl","endsWith","slice","type","serviceEndpoint"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sphereon/ssi-sdk.linked-vp",
3
- "version": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
3
+ "version": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
4
4
  "source": "src/index.ts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -27,13 +27,13 @@
27
27
  "generate-plugin-schema": "tsx ../../packages/dev/bin/sphereon.js dev generate-plugin-schema"
28
28
  },
29
29
  "dependencies": {
30
- "@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
31
- "@sphereon/ssi-sdk.credential-store": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
32
- "@sphereon/ssi-sdk.credential-vcdm": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
33
- "@sphereon/ssi-sdk.data-store": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
34
- "@sphereon/ssi-sdk.data-store-types": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
35
- "@sphereon/ssi-sdk.sd-jwt": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
36
- "@sphereon/ssi-types": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
30
+ "@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
31
+ "@sphereon/ssi-sdk.credential-store": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
32
+ "@sphereon/ssi-sdk.credential-vcdm": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
33
+ "@sphereon/ssi-sdk.data-store": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
34
+ "@sphereon/ssi-sdk.data-store-types": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
35
+ "@sphereon/ssi-sdk.sd-jwt": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
36
+ "@sphereon/ssi-types": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
37
37
  "@veramo/utils": "4.2.0",
38
38
  "cross-fetch": "^4.1.0",
39
39
  "dcql": "1.0.1",
@@ -42,10 +42,10 @@
42
42
  "uint8arrays": "3.1.1"
43
43
  },
44
44
  "devDependencies": {
45
- "@sphereon/ssi-sdk-ext.key-manager": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
46
- "@sphereon/ssi-sdk-ext.kms-local": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
47
- "@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
48
- "@sphereon/ssi-sdk.credential-vcdm1-jwt-provider": "0.34.1-feature.SSISDK.82.linkedVP.326+2b4ebda9",
45
+ "@sphereon/ssi-sdk-ext.key-manager": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
46
+ "@sphereon/ssi-sdk-ext.kms-local": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
47
+ "@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
48
+ "@sphereon/ssi-sdk.credential-vcdm1-jwt-provider": "0.34.1-feature.SSISDK.82.linkedVP.327+81517113",
49
49
  "@veramo/data-store": "4.2.0",
50
50
  "@veramo/did-manager": "4.2.0",
51
51
  "@veramo/did-provider-web": "4.2.0",
@@ -77,5 +77,5 @@
77
77
  "Presentation Defintion Manager",
78
78
  "PD Manager"
79
79
  ],
80
- "gitHead": "2b4ebda97cd73ad5b73555cb8bb9d087f0d98395"
80
+ "gitHead": "81517113906547b895df06ba83f283604b52ab2e"
81
81
  }
@@ -9,7 +9,7 @@ import {
9
9
  SdJwtDecodedVerifiableCredential,
10
10
  WrappedVerifiableCredential,
11
11
  } from '@sphereon/ssi-types'
12
- import { LOGGER_NAMESPACE, RequiredContext } from '../types'
12
+ import { LinkedVPPresentation, LOGGER_NAMESPACE, RequiredContext } from '../types'
13
13
 
14
14
  const logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)
15
15
  const CLOCK_SKEW = 120 // TODO make adjustable?
@@ -48,7 +48,7 @@ export async function createLinkedVPPresentation(
48
48
  holderDid: string,
49
49
  credential: UniqueDigitalCredential,
50
50
  agent: RequiredContext['agent'],
51
- ): Promise<string | Record<string, any>> {
51
+ ): Promise<LinkedVPPresentation> {
52
52
  logger.debug(`Creating LinkedVP presentation for ${holderDid} of credential ${credential.id}`)
53
53
 
54
54
  const identifier = await agent.identifierManagedGet({ identifier: holderDid })
@@ -76,7 +76,10 @@ export async function createLinkedVPPresentation(
76
76
  },
77
77
  })
78
78
 
79
- return presentationResult.presentation
79
+ return {
80
+ documentFormat,
81
+ presentationPayload: presentationResult.presentation,
82
+ }
80
83
  }
81
84
  case DocumentFormat.JSONLD: {
82
85
  // JSON-LD VC - create JSON-LD VP with challenge and domain in proof
@@ -90,11 +93,15 @@ export async function createLinkedVPPresentation(
90
93
  }
91
94
 
92
95
  // Create JSON-LD VP with proof
93
- return await agent.createVerifiablePresentation({
96
+ const verifiablePresentationSP = await agent.createVerifiablePresentation({
94
97
  presentation: vpObject,
95
98
  proofFormat: 'lds',
96
99
  keyRef: identifier.kmsKeyRef || identifier.kid,
97
100
  })
101
+ return {
102
+ documentFormat,
103
+ presentationPayload: verifiablePresentationSP,
104
+ }
98
105
  }
99
106
  case DocumentFormat.MSO_MDOC: {
100
107
  // ISO mdoc - create mdoc VP token
@@ -105,7 +112,10 @@ export async function createLinkedVPPresentation(
105
112
  // 3. Include nonce/audience in the session transcript
106
113
  logger.warning('mso_mdoc format has basic support - production use requires proper mdoc VP token implementation')
107
114
 
108
- return originalCredential
115
+ return {
116
+ documentFormat,
117
+ presentationPayload: originalCredential,
118
+ }
109
119
  }
110
120
  default: {
111
121
  // JWT VC - create JWT VP with nonce and aud in payload
@@ -131,7 +141,10 @@ export async function createLinkedVPPresentation(
131
141
  keyRef: identifier.kmsKeyRef || identifier.kid,
132
142
  })
133
143
 
134
- return (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt
144
+ return {
145
+ documentFormat,
146
+ presentationPayload: (vpJwt.proof && 'jwt' in vpJwt.proof && vpJwt.proof.jwt) || vpJwt,
147
+ }
135
148
  }
136
149
  }
137
150
  }
@@ -2,12 +2,16 @@ import { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resoluti
2
2
  import { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'
3
3
  import { VcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
4
4
  import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'
5
+ import { DocumentFormat } from '@sphereon/ssi-types'
5
6
  import { IAgentContext, IPluginMethodMap } from '@veramo/core'
6
7
  import { IKeyManager } from '@veramo/core/src/types/IKeyManager'
7
8
 
8
9
  export const LOGGER_NAMESPACE = 'sphereon:linked-vp'
9
10
 
10
- export type LinkedVPPresentation = string | Record<string, any>
11
+ export type LinkedVPPresentation = {
12
+ documentFormat: DocumentFormat
13
+ presentationPayload: string | Record<string, any>
14
+ }
11
15
 
12
16
  export interface ILinkedVPManager extends IPluginMethodMap {
13
17
  /**