{"version":3,"file":"OpenBadgesCredentialFormatService.mjs","names":["input: JsonObject","out: JsonObject","image: string | undefined"],"sources":["../../src/formats/OpenBadgesCredentialFormatService.ts"],"sourcesContent":["import type { AgentContext } from '@credo-ts/core'\nimport { CredoError, JsonEncoder, deepEquality } from '@credo-ts/core'\nimport type {\n  DidCommCredentialFormatAcceptOfferOptions,\n  DidCommCredentialFormatAcceptProposalOptions,\n  DidCommCredentialFormatAcceptRequestOptions,\n  DidCommCredentialFormatAutoRespondCredentialOptions,\n  DidCommCredentialFormatAutoRespondOfferOptions,\n  DidCommCredentialFormatAutoRespondProposalOptions,\n  DidCommCredentialFormatAutoRespondRequestOptions,\n  DidCommCredentialFormatCreateOfferOptions,\n  DidCommCredentialFormatCreateOfferReturn,\n  DidCommCredentialFormatCreateProposalOptions,\n  DidCommCredentialFormatCreateProposalReturn,\n  DidCommCredentialFormatCreateRequestOptions,\n  DidCommCredentialFormatCreateReturn,\n  DidCommCredentialFormatProcessCredentialOptions,\n  DidCommCredentialFormatProcessOptions,\n  DidCommCredentialFormatService,\n} from '@credo-ts/didcomm'\nimport { DidCommAttachment, DidCommAttachmentData, DidCommCredentialFormatSpec } from '@credo-ts/didcomm'\n\nimport { IssuerService } from '../services/IssuerService'\nimport { VerifyService } from '../services/VerifyService'\nimport { OpenBadgeCredentialRecord } from '../repository/OpenBadgeCredentialRecord'\nimport { OpenBadgeCredentialRepository } from '../repository/OpenBadgeCredentialRepository'\n\nimport { OPENBADGES_CREDENTIAL, OPENBADGES_CREDENTIAL_DETAIL } from './OpenBadgesCredentialFormat'\nimport type { OpenBadgesCredentialDetail, OpenBadgesCredentialFormat } from './OpenBadgesCredentialFormat'\n\ntype JsonObject = { [key: string]: unknown }\n\nexport class OpenBadgesCredentialFormatService implements DidCommCredentialFormatService<OpenBadgesCredentialFormat> {\n  public readonly formatKey = 'openbadges' as const\n  public readonly credentialRecordType = 'openbadges' as const\n\n  public async createProposal(\n    _agentContext: AgentContext,\n    { credentialFormats, attachmentId }: DidCommCredentialFormatCreateProposalOptions<OpenBadgesCredentialFormat>\n  ): Promise<DidCommCredentialFormatCreateProposalReturn> {\n    const detail = credentialFormats.openbadges\n    if (!detail) throw new CredoError('Missing openbadges payload in createProposal')\n    this.assertValidDetail(detail)\n\n    const format = new DidCommCredentialFormatSpec({ attachmentId, format: OPENBADGES_CREDENTIAL_DETAIL })\n    const attachment = this.toAttachment(detail, format.attachmentId)\n    return { format, attachment }\n  }\n\n  public async processProposal(\n    _agentContext: AgentContext,\n    { attachment }: DidCommCredentialFormatProcessOptions\n  ): Promise<void> {\n    const detail = attachment.getDataAsJson<OpenBadgesCredentialDetail>()\n    if (!detail) throw new CredoError('Missing openbadges credential proposal data payload')\n    this.assertValidDetail(detail)\n  }\n\n  public async acceptProposal(\n    _agentContext: AgentContext,\n    { attachmentId, proposalAttachment }: DidCommCredentialFormatAcceptProposalOptions<OpenBadgesCredentialFormat>\n  ): Promise<DidCommCredentialFormatCreateOfferReturn> {\n    const detail = proposalAttachment.getDataAsJson<OpenBadgesCredentialDetail>()\n    this.assertValidDetail(detail)\n    const format = new DidCommCredentialFormatSpec({ attachmentId, format: OPENBADGES_CREDENTIAL_DETAIL })\n    const attachment = this.toAttachment(detail, format.attachmentId)\n    return { format, attachment }\n  }\n\n  public async createOffer(\n    _agentContext: AgentContext,\n    { credentialFormats, attachmentId }: DidCommCredentialFormatCreateOfferOptions<OpenBadgesCredentialFormat>\n  ): Promise<DidCommCredentialFormatCreateOfferReturn> {\n    const detail = credentialFormats?.openbadges\n    if (!detail) throw new CredoError('Missing openbadges payload in createOffer')\n    this.assertValidDetail(detail)\n\n    const format = new DidCommCredentialFormatSpec({ attachmentId, format: OPENBADGES_CREDENTIAL_DETAIL })\n    const attachment = this.toAttachment(detail, format.attachmentId)\n    return { format, attachment }\n  }\n\n  public async processOffer(\n    _agentContext: AgentContext,\n    { attachment }: DidCommCredentialFormatProcessOptions\n  ): Promise<void> {\n    const detail = attachment.getDataAsJson<OpenBadgesCredentialDetail>()\n    if (!detail) throw new CredoError('Missing openbadges credential offer data payload')\n    this.assertValidDetail(detail)\n  }\n\n  public async acceptOffer(\n    _agentContext: AgentContext,\n    { attachmentId, offerAttachment }: DidCommCredentialFormatAcceptOfferOptions<OpenBadgesCredentialFormat>\n  ): Promise<DidCommCredentialFormatCreateReturn> {\n    const detail = offerAttachment.getDataAsJson<OpenBadgesCredentialDetail>()\n    this.assertValidDetail(detail)\n    const format = new DidCommCredentialFormatSpec({ attachmentId, format: OPENBADGES_CREDENTIAL_DETAIL })\n    const attachment = this.toAttachment(detail, format.attachmentId)\n    return { format, attachment }\n  }\n\n  public async createRequest(\n    _agentContext: AgentContext,\n    { credentialFormats }: DidCommCredentialFormatCreateRequestOptions<OpenBadgesCredentialFormat>\n  ): Promise<DidCommCredentialFormatCreateReturn> {\n    const detail = credentialFormats?.openbadges\n    if (!detail) throw new CredoError('Missing openbadges payload in createRequest')\n    this.assertValidDetail(detail)\n    const format = new DidCommCredentialFormatSpec({ format: OPENBADGES_CREDENTIAL_DETAIL })\n    const attachment = this.toAttachment(detail, format.attachmentId)\n    return { format, attachment }\n  }\n\n  public async processRequest(\n    _agentContext: AgentContext,\n    { attachment }: DidCommCredentialFormatProcessOptions\n  ): Promise<void> {\n    const detail = attachment.getDataAsJson<OpenBadgesCredentialDetail>()\n    if (!detail) throw new CredoError('Missing openbadges credential request data payload')\n    this.assertValidDetail(detail)\n  }\n\n  public async acceptRequest(\n    agentContext: AgentContext,\n    {\n      credentialFormats,\n      attachmentId,\n      requestAttachment,\n    }: DidCommCredentialFormatAcceptRequestOptions<OpenBadgesCredentialFormat>\n  ): Promise<DidCommCredentialFormatCreateReturn> {\n    const issuerService = agentContext.dependencyManager.resolve(IssuerService)\n    const detail = requestAttachment.getDataAsJson<OpenBadgesCredentialDetail>()\n    this.assertValidDetail(detail)\n\n    const verificationMethod =\n      credentialFormats?.openbadges?.verificationMethod ??\n      detail.options?.verificationMethod ??\n      ((detail.credential as { proof?: { verificationMethod?: string } } | undefined)?.proof?.verificationMethod)\n\n    if (!verificationMethod) {\n      throw new CredoError('Missing verificationMethod for openbadges credential issuance')\n    }\n\n    const input: JsonObject = {\n      ...detail.credential,\n      proof: {\n        ...((detail.credential.proof as JsonObject | undefined) ?? {}),\n        verificationMethod,\n      },\n    }\n\n    const record = await issuerService.issueCredential(agentContext, input)\n    if (!record.credential) {\n      throw new CredoError('IssuerService returned a record without a signed credential')\n    }\n\n    const format = new DidCommCredentialFormatSpec({ attachmentId, format: OPENBADGES_CREDENTIAL })\n    const attachment = this.toAttachment(record.credential as JsonObject, format.attachmentId)\n    return { format, attachment }\n  }\n\n  public async processCredential(\n    agentContext: AgentContext,\n    { credentialExchangeRecord, attachment }: DidCommCredentialFormatProcessCredentialOptions\n  ): Promise<void> {\n    const verifyService = agentContext.dependencyManager.resolve(VerifyService)\n    const repository = agentContext.dependencyManager.resolve(OpenBadgeCredentialRepository)\n\n    const credential = attachment.getDataAsJson<JsonObject>()\n    if (!credential) throw new CredoError('Missing openbadges credential data payload')\n\n    const verifyResult = await verifyService.verify(agentContext, credential)\n    const derived = extractDerivedMetadata(credential)\n    const status = (verifyResult.status ?? 'unknown') as OpenBadgeCredentialRecord['status']\n\n    const record = new OpenBadgeCredentialRecord({ credential, status, derived })\n    await repository.save(agentContext, record)\n\n    credentialExchangeRecord.credentials.push({\n      credentialRecordType: this.credentialRecordType,\n      credentialRecordId: record.id,\n    })\n  }\n\n  public supportsFormat(format: string): boolean {\n    return format === OPENBADGES_CREDENTIAL_DETAIL || format === OPENBADGES_CREDENTIAL\n  }\n\n  public async deleteCredentialById(agentContext: AgentContext, credentialId: string): Promise<void> {\n    const repository = agentContext.dependencyManager.resolve(OpenBadgeCredentialRepository)\n    const record = await repository.findById(agentContext, credentialId)\n    if (record) await repository.delete(agentContext, record)\n  }\n\n  public async shouldAutoRespondToProposal(\n    _agentContext: AgentContext,\n    { proposalAttachment, offerAttachment }: DidCommCredentialFormatAutoRespondProposalOptions\n  ): Promise<boolean> {\n    return attachmentsContainEqualCredential(proposalAttachment, offerAttachment)\n  }\n\n  public async shouldAutoRespondToOffer(\n    _agentContext: AgentContext,\n    { proposalAttachment, offerAttachment }: DidCommCredentialFormatAutoRespondOfferOptions\n  ): Promise<boolean> {\n    return attachmentsContainEqualCredential(proposalAttachment, offerAttachment)\n  }\n\n  public async shouldAutoRespondToRequest(\n    _agentContext: AgentContext,\n    { offerAttachment, requestAttachment }: DidCommCredentialFormatAutoRespondRequestOptions\n  ): Promise<boolean> {\n    return attachmentsContainEqualCredential(offerAttachment, requestAttachment)\n  }\n\n  public async shouldAutoRespondToCredential(\n    _agentContext: AgentContext,\n    { requestAttachment, credentialAttachment }: DidCommCredentialFormatAutoRespondCredentialOptions\n  ): Promise<boolean> {\n    const request = requestAttachment.getDataAsJson<OpenBadgesCredentialDetail>()\n    const signed = credentialAttachment.getDataAsJson<JsonObject>()\n    if (!request || !signed) return false\n\n    const signedUnsigned = { ...signed }\n    delete signedUnsigned.proof\n\n    return deepEquality(\n      pickEnvelopeFields(signedUnsigned, request.credential),\n      pickEnvelopeFields(request.credential, request.credential)\n    )\n  }\n\n  private assertValidDetail(\n    detail: OpenBadgesCredentialDetail | undefined\n  ): asserts detail is OpenBadgesCredentialDetail {\n    if (!detail || typeof detail !== 'object') {\n      throw new CredoError('Invalid openbadges credential detail: payload missing')\n    }\n    const credential = detail.credential\n    if (!credential || typeof credential !== 'object') {\n      throw new CredoError('Invalid openbadges credential detail: credential missing')\n    }\n    const ctx = (credential as { '@context'?: unknown })['@context']\n    if (!Array.isArray(ctx) || ctx.length === 0) {\n      throw new CredoError('Invalid openbadges credential detail: @context must be a non-empty array')\n    }\n    const type = (credential as { type?: unknown }).type\n    if (!Array.isArray(type) || !type.includes('VerifiableCredential')) {\n      throw new CredoError('Invalid openbadges credential detail: type must include \"VerifiableCredential\"')\n    }\n    if (!type.some((t) => t === 'OpenBadgeCredential' || t === 'AchievementCredential')) {\n      throw new CredoError(\n        'Invalid openbadges credential detail: type must include \"OpenBadgeCredential\" or \"AchievementCredential\"'\n      )\n    }\n    const subject = (credential as { credentialSubject?: unknown }).credentialSubject\n    if (!subject || typeof subject !== 'object') {\n      throw new CredoError('Invalid openbadges credential detail: credentialSubject missing')\n    }\n  }\n\n  private toAttachment(data: unknown, id: string): DidCommAttachment {\n    return new DidCommAttachment({\n      id,\n      mimeType: 'application/json',\n      data: new DidCommAttachmentData({ base64: JsonEncoder.toBase64(data) }),\n    })\n  }\n}\n\nfunction attachmentsContainEqualCredential(\n  a: DidCommAttachment | undefined,\n  b: DidCommAttachment | undefined\n): boolean {\n  if (!a || !b) return false\n  const left = a.getDataAsJson<OpenBadgesCredentialDetail>()\n  const right = b.getDataAsJson<OpenBadgesCredentialDetail>()\n  if (!left?.credential || !right?.credential) return false\n  return deepEquality(left.credential, right.credential)\n}\n\nfunction pickEnvelopeFields(source: JsonObject, shape: JsonObject): JsonObject {\n  const out: JsonObject = {}\n  for (const key of Object.keys(shape)) {\n    if (key in source) out[key] = source[key]\n  }\n  return out\n}\n\nexport function extractDerivedMetadata(credential: JsonObject): {\n  title?: string\n  description?: string\n  issuerName?: string\n  issuedOn?: string\n  image?: string\n} {\n  const credSubject = credential.credentialSubject as JsonObject | undefined\n  const achievement = credSubject?.achievement as JsonObject | undefined\n  const issuer = credential.issuer as JsonObject | string | undefined\n\n  let image: string | undefined\n  if (achievement?.image) {\n    if (typeof achievement.image === 'string') image = achievement.image\n    else if (typeof achievement.image === 'object') image = (achievement.image as JsonObject).id as string | undefined\n  }\n\n  return {\n    title: (achievement?.name as string) || (credential.name as string | undefined),\n    description: achievement?.description as string | undefined,\n    issuerName: typeof issuer === 'string' ? issuer : (issuer?.name as string | undefined),\n    issuedOn: (credential.validFrom as string) || (credential.issuanceDate as string),\n    image,\n  }\n}\n"],"mappings":"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"}