{"version":3,"file":"SdJwtVcRecord.mjs","names":[],"sources":["../../../../src/modules/sd-jwt-vc/repository/SdJwtVcRecord.ts"],"sourcesContent":["import { decodeSdJwtSync } from '@sd-jwt/core'\nimport { Hasher } from '../../../crypto'\nimport type { TagsBase } from '../../../storage/BaseRecord'\nimport { BaseRecord } from '../../../storage/BaseRecord'\nimport type { NonEmptyArray } from '../../../types'\nimport { JsonTransformer } from '../../../utils'\nimport { CredentialMultiInstanceState } from '../../../utils/credentialUseTypes'\nimport type { Constructable } from '../../../utils/mixins'\nimport { uuid } from '../../../utils/uuid'\nimport type { KnownJwaSignatureAlgorithm } from '../../kms'\nimport { decodeSdJwtVc } from '../decodeSdJwtVc'\nimport type { SdJwtVc } from '../SdJwtVcService'\nimport type { SdJwtVcTypeMetadata } from '../typeMetadata'\n\nexport type DefaultSdJwtVcRecordTags = {\n  vct: string\n\n  /**\n   * The sdAlg is the alg used for creating digests for selective disclosures\n   */\n  sdAlg: string\n\n  /**\n   * The alg is the alg used to sign the SD-JWT\n   */\n  alg: KnownJwaSignatureAlgorithm\n\n  /**\n   * @since 0.6 - tag was not defined before 0.6\n   */\n  multiInstanceState?: CredentialMultiInstanceState\n}\n\nexport type SdJwtVcRecordStorageProps = {\n  id?: string\n  createdAt?: Date\n  tags?: TagsBase\n\n  /**\n   * The SD-JWT VC instances to store on the record.\n   *\n   * NOTE that all instances should contain roughly the same data (e.g. exp can differ slighty), as they should be usable\n   * interchangeably for presentations (allowing single-use credentials and batch issuance).\n   */\n  credentialInstances: SdJwtVcRecordInstances\n\n  /**\n   * Optional VCT type metadata associated with the SD JWT VC instances, this type metadata is used for\n   * all SD JWT VC instances on this record.\n   *\n   * The type metadata is the result of resolving and merging the vct value and all `extends` values.\n   *\n   * NOTE: This may only include the latest VCT document, if the credential was stored before resolving\n   * `extends` claims was supported.\n   */\n  typeMetadata?: SdJwtVcTypeMetadata\n\n  /**\n   * The original chain of SD-JWT VC Type Metadata documents, ordered from the extending type to the last extended type.\n   * This is stored on the record to allow extensions to the type metadata (e.g. EUDI ARF TS12 for payments) to apply a\n   * custom merging strategy.\n   */\n  typeMetadataChain?: NonEmptyArray<SdJwtVcTypeMetadata>\n}\n\nexport type SdJwtVcRecordInstances = NonEmptyArray<{\n  compactSdJwtVc: string\n\n  /**\n   * The kms key id to which the credential is bound. If not defined it either:\n   * - uses a legacy key id (which can be calculated based on the key)\n   * - is bound to a did (which stores the kms key id on the did record)\n   */\n  kmsKeyId?: string\n}>\n\nexport class SdJwtVcRecord extends BaseRecord<DefaultSdJwtVcRecordTags> {\n  public static readonly type = 'SdJwtVcRecord'\n  public readonly type = SdJwtVcRecord.type\n\n  public credentialInstances!: SdJwtVcRecordInstances\n\n  /**\n   * Tracks the state of credential instances on this record.\n   *\n   * NOTE: This defaults to `CredentialMultiInstanceState.SingleInstanceUsed` for records that\n   * don't have a value set from before 0.6. We assume the credential has already been used.\n   */\n  public multiInstanceState = CredentialMultiInstanceState.SingleInstanceUsed\n\n  /**\n   * Only here for class transformation. If compactSdJwtVc is set we transform\n   * it to the new sdJwtVcs array format\n   */\n  private set compactSdJwtVc(compactSdJwtVc: string) {\n    this.credentialInstances = [\n      {\n        compactSdJwtVc,\n      },\n    ]\n  }\n\n  public typeMetadata?: SdJwtVcTypeMetadata\n\n  /**\n   * The original chain of SD-JWT VC Type Metadata documents, ordered from the extending type to the last extended type.\n   * This is stored on the record to allow extensions to the type metadata (e.g. EUDI ARF TS12 for payments) to apply a\n   * custom merging strategy.\n   */\n  public typeMetadataChain?: NonEmptyArray<SdJwtVcTypeMetadata>\n\n  public constructor(props: SdJwtVcRecordStorageProps) {\n    super()\n\n    if (props) {\n      this.id = props.id ?? uuid()\n      this.createdAt = props.createdAt ?? new Date()\n\n      this.credentialInstances = props.credentialInstances\n\n      // Set multiInstanceState based on the number of initial instances. We\n      // assume the instance is unused when the record is created.\n      this.multiInstanceState =\n        this.credentialInstances.length === 1\n          ? CredentialMultiInstanceState.SingleInstanceUnused\n          : CredentialMultiInstanceState.MultiInstanceFirstUnused\n\n      this.typeMetadata = props.typeMetadata\n      this.typeMetadataChain = props.typeMetadataChain\n      this._tags = props.tags ?? {}\n    }\n  }\n\n  public get firstCredential(): SdJwtVc {\n    return {\n      ...decodeSdJwtVc(this.credentialInstances[0].compactSdJwtVc, this.typeMetadata),\n      kmsKeyId: this.credentialInstances[0].kmsKeyId,\n    }\n  }\n\n  public static fromSdJwtVc(sdJwtVc: SdJwtVc) {\n    return new SdJwtVcRecord({\n      credentialInstances: [\n        {\n          compactSdJwtVc: sdJwtVc.compact,\n          kmsKeyId: sdJwtVc.kmsKeyId,\n        },\n      ],\n      typeMetadata: sdJwtVc.typeMetadata,\n    })\n  }\n\n  public get extendedVctValues() {\n    return this.typeMetadataChain\n      ? // Remove the first one, as that's not extended\n        this.typeMetadataChain.slice(1).map(({ vct }) => vct)\n      : this.typeMetadata?.extends\n        ? [this.typeMetadata.extends]\n        : []\n  }\n\n  public getTags() {\n    const sdjwt = decodeSdJwtSync(this.credentialInstances[0].compactSdJwtVc, Hasher.hash)\n    const vct = sdjwt.jwt.payload.vct as string\n    const sdAlg = sdjwt.jwt.payload._sd_alg as string | undefined\n    const alg = sdjwt.jwt.header.alg as KnownJwaSignatureAlgorithm\n\n    return {\n      ...this._tags,\n      vct,\n      extendedVctValues: this.extendedVctValues,\n      sdAlg: sdAlg ?? 'sha-256',\n      alg,\n      multiInstanceState: this.multiInstanceState,\n    }\n  }\n\n  public clone(): this {\n    return JsonTransformer.fromJSON(JsonTransformer.toJSON(this), this.constructor as Constructable<this>)\n  }\n\n  /**\n   * encoded is convenience method added to all credential records\n   */\n  public get encoded(): string {\n    return this.credentialInstances[0].compactSdJwtVc\n  }\n}\n"],"mappings":";;;;;;;;;;AA4EA,IAAa,gBAAb,MAAa,sBAAsB,WAAqC;;;;;CAkBtE,IAAY,eAAe,gBAAwB;EACjD,KAAK,sBAAsB,CACzB,EACE,eACF,CACF;CACF;CAWA,YAAmB,OAAkC;EACnD,MAAM;EAlCR,KAAgB,OAAO,cAAc;EAUrC,KAAO,qBAAA;EA0BL,IAAI,OAAO;GACT,KAAK,KAAK,MAAM,MAAM,KAAK;GAC3B,KAAK,YAAY,MAAM,6BAAa,IAAI,KAAK;GAE7C,KAAK,sBAAsB,MAAM;GAIjC,KAAK,qBACH,KAAK,oBAAoB,WAAW,IAAA,yBAAA;GAItC,KAAK,eAAe,MAAM;GAC1B,KAAK,oBAAoB,MAAM;GAC/B,KAAK,QAAQ,MAAM,QAAQ,CAAC;EAC9B;CACF;CAEA,IAAW,kBAA2B;EACpC,OAAO;GACL,GAAG,cAAc,KAAK,oBAAoB,EAAE,CAAC,gBAAgB,KAAK,YAAY;GAC9E,UAAU,KAAK,oBAAoB,EAAE,CAAC;EACxC;CACF;CAEA,OAAc,YAAY,SAAkB;EAC1C,OAAO,IAAI,cAAc;GACvB,qBAAqB,CACnB;IACE,gBAAgB,QAAQ;IACxB,UAAU,QAAQ;GACpB,CACF;GACA,cAAc,QAAQ;EACxB,CAAC;CACH;CAEA,IAAW,oBAAoB;EAC7B,OAAO,KAAK,oBAER,KAAK,kBAAkB,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IACpD,KAAK,cAAc,UACjB,CAAC,KAAK,aAAa,OAAO,IAC1B,CAAC;CACT;CAEA,UAAiB;EACf,MAAM,QAAQ,gBAAgB,KAAK,oBAAoB,EAAE,CAAC,gBAAgB,OAAO,IAAI;EACrF,MAAM,MAAM,MAAM,IAAI,QAAQ;EAC9B,MAAM,QAAQ,MAAM,IAAI,QAAQ;EAChC,MAAM,MAAM,MAAM,IAAI,OAAO;EAE7B,OAAO;GACL,GAAG,KAAK;GACR;GACA,mBAAmB,KAAK;GACxB,OAAO,SAAS;GAChB;GACA,oBAAoB,KAAK;EAC3B;CACF;CAEA,QAAqB;EACnB,OAAO,gBAAgB,SAAS,gBAAgB,OAAO,IAAI,GAAG,KAAK,WAAkC;CACvG;;;;CAKA,IAAW,UAAkB;EAC3B,OAAO,KAAK,oBAAoB,EAAE,CAAC;CACrC;AACF;AA9GE,cAAuB,OAAO"}