diff --git a/packages/ebsi-support/package.json b/packages/ebsi-support/package.json index 87e698bb..83ea19df 100644 --- a/packages/ebsi-support/package.json +++ b/packages/ebsi-support/package.json @@ -15,8 +15,8 @@ }, "dependencies": { "@ethersproject/random": "^5.7.0", - "@sphereon/did-auth-siop": "0.16.1-next.339", - "@sphereon/did-auth-siop-adapter": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/did-auth-siop-adapter": "0.16.1-feature.IATAB2B.52.345", "@sphereon/pex": "5.0.0-unstable.28", "@sphereon/pex-models": "^2.3.2", "@sphereon/ssi-sdk-ext.did-resolver-ebsi": "0.27.0", @@ -44,8 +44,8 @@ "xstate": "^4.38.3" }, "devDependencies": { - "@sphereon/oid4vci-client": "0.16.1-next.339", - "@sphereon/oid4vci-common": "0.16.1-next.339", + "@sphereon/oid4vci-client": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-express-support": "workspace:*", "@sphereon/ssi-sdk-ext.key-manager": "0.27.0", "@sphereon/ssi-sdk-ext.kms-local": "0.27.0", diff --git a/packages/mdl-mdoc/package.json b/packages/mdl-mdoc/package.json index e079c408..38eee3e9 100644 --- a/packages/mdl-mdoc/package.json +++ b/packages/mdl-mdoc/package.json @@ -14,7 +14,7 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/did-auth-siop": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", "@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26", "@sphereon/pex": "5.0.0-unstable.28", "@sphereon/pex-models": "^2.3.2", @@ -35,8 +35,8 @@ "uuid": "^9.0.1" }, "devDependencies": { - "@sphereon/oid4vci-client": "0.16.1-next.339", - "@sphereon/oid4vci-common": "0.16.1-next.339", + "@sphereon/oid4vci-client": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-express-support": "workspace:*", "@sphereon/ssi-sdk-ext.key-manager": "0.27.0", "@sphereon/ssi-sdk-ext.kms-local": "0.27.0", diff --git a/packages/oid4vci-holder/package.json b/packages/oid4vci-holder/package.json index 3ec00c88..6e86033d 100644 --- a/packages/oid4vci-holder/package.json +++ b/packages/oid4vci-holder/package.json @@ -15,9 +15,9 @@ }, "dependencies": { "@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26", - "@sphereon/did-auth-siop": "0.16.1-next.339", - "@sphereon/oid4vci-client": "0.16.1-next.339", - "@sphereon/oid4vci-common": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vci-client": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-sdk-ext.did-utils": "0.27.0", "@sphereon/ssi-sdk-ext.identifier-resolution": "0.27.0", "@sphereon/ssi-sdk-ext.jwt-service": "0.27.0", @@ -45,7 +45,7 @@ "xstate": "^4.38.3" }, "devDependencies": { - "@sphereon/oid4vc-common": "0.16.1-next.339", + "@sphereon/oid4vc-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-sdk.siopv2-oid4vp-common": "workspace:*", "@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.27.0", "@types/i18n-js": "^3.8.9", diff --git a/packages/oid4vci-issuer-rest-api/package.json b/packages/oid4vci-issuer-rest-api/package.json index ed4f27e4..20285bfb 100644 --- a/packages/oid4vci-issuer-rest-api/package.json +++ b/packages/oid4vci-issuer-rest-api/package.json @@ -11,9 +11,9 @@ "start:dev": "ts-node __tests__/RestAPI.ts" }, "dependencies": { - "@sphereon/oid4vci-common": "0.16.1-next.339", - "@sphereon/oid4vci-issuer": "0.16.1-next.339", - "@sphereon/oid4vci-issuer-server": "0.16.1-next.339", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vci-issuer": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vci-issuer-server": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-express-support": "workspace:*", "@sphereon/ssi-sdk-ext.identifier-resolution": "0.27.0", "@sphereon/ssi-sdk-ext.jwt-service": "0.27.0", diff --git a/packages/oid4vci-issuer-rest-client/package.json b/packages/oid4vci-issuer-rest-client/package.json index 413e719a..3a23d9e0 100644 --- a/packages/oid4vci-issuer-rest-client/package.json +++ b/packages/oid4vci-issuer-rest-client/package.json @@ -16,7 +16,7 @@ "generate-plugin-schema": "ts-node ../../packages/dev/bin/sphereon.js dev generate-plugin-schema" }, "dependencies": { - "@sphereon/oid4vci-common": "0.16.1-next.339", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-types": "workspace:*", "@veramo/core": "4.2.0", "cross-fetch": "^3.1.8" diff --git a/packages/oid4vci-issuer-store/package.json b/packages/oid4vci-issuer-store/package.json index ed597c78..9b262ab0 100644 --- a/packages/oid4vci-issuer-store/package.json +++ b/packages/oid4vci-issuer-store/package.json @@ -14,7 +14,7 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/oid4vci-common": "0.16.1-next.339", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-sdk-ext.did-utils": "0.27.0", "@sphereon/ssi-sdk-ext.identifier-resolution": "0.27.0", "@sphereon/ssi-sdk.kv-store-temp": "workspace:*", diff --git a/packages/oid4vci-issuer/package.json b/packages/oid4vci-issuer/package.json index 6242463e..6913684c 100644 --- a/packages/oid4vci-issuer/package.json +++ b/packages/oid4vci-issuer/package.json @@ -14,8 +14,8 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/oid4vci-common": "0.16.1-next.339", - "@sphereon/oid4vci-issuer": "0.16.1-next.339", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vci-issuer": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-sdk-ext.did-utils": "0.27.0", "@sphereon/ssi-sdk-ext.identifier-resolution": "0.27.0", "@sphereon/ssi-sdk-ext.jwt-service": "0.27.0", @@ -36,7 +36,7 @@ "uuid": "^9.0.1" }, "devDependencies": { - "@sphereon/did-auth-siop": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", "@sphereon/did-uni-client": "^0.6.3", "@veramo/did-provider-key": "4.2.0", "@veramo/did-resolver": "4.2.0", diff --git a/packages/oid4vci-issuer/src/functions.ts b/packages/oid4vci-issuer/src/functions.ts index 22b381b9..3b5f36c0 100644 --- a/packages/oid4vci-issuer/src/functions.ts +++ b/packages/oid4vci-issuer/src/functions.ts @@ -5,6 +5,7 @@ import { Jwt, JwtVerifyResult, OID4VCICredentialFormat, + StatusListOpts, } from '@sphereon/oid4vci-common' import { JWTHeader, JWTPayload } from '@sphereon/oid4vci-common/lib/types' import { CredentialDataSupplier, CredentialIssuanceInput, CredentialSignerCallback, VcIssuer, VcIssuerBuilder } from '@sphereon/oid4vci-issuer' @@ -182,8 +183,9 @@ export async function getCredentialSignerCallback( credential: CredentialIssuanceInput jwtVerifyResult: JwtVerifyResult format?: OID4VCICredentialFormat + statusListOpts?: Array }): Promise { - const { jwtVerifyResult, format } = args + const { jwtVerifyResult, format, statusListOpts } = args const credential = args.credential as ICredential // TODO: SDJWT let proofFormat: ProofFormat @@ -210,7 +212,7 @@ export async function getCredentialSignerCallback( // TODO: We should extend the plugin capabilities of issuance so we do not have to tuck this into the sign callback if (contextHasPlugin(context, 'slAddStatusToCredential')) { // Add status list if enabled (and when the input has a credentialStatus object (can be empty)) - const credentialStatusVC = await context.agent.slAddStatusToCredential({ credential }) + const credentialStatusVC = await context.agent.slAddStatusToCredential({ credential, statusListOpts }) if (credential.credentialStatus && !credential.credentialStatus.statusListCredential) { credential.credentialStatus = credentialStatusVC.credentialStatus } @@ -244,16 +246,18 @@ export async function getCredentialSignerCallback( } } - if (contextHasPlugin(context, 'slAddStatusToCredential') && sdJwtPayload.status && sdJwtPayload.status.status_list) { - // Add status list if enabled (and when the input has a credentialStatus object (can be empty)) - const credentialStatusVC = await context.agent.slAddStatusToSdJwtCredential({ credential: sdJwtPayload }) - if (sdJwtPayload.status?.status_list?.idx) { - if (!credentialStatusVC.status || !credentialStatusVC.status.status_list) { - // TODO check, looks like sdJwtPayload and credentialStatusVC is the same - return Promise.reject(Error('slAddStatusToSdJwtCredential did not return a status_list')) + if (contextHasPlugin(context, 'slAddStatusToCredential')) { + if (sdJwtPayload.status && sdJwtPayload.status.status_list) { + // Add status list if enabled (and when the input has a credentialStatus object (can be empty)) + const credentialStatusVC = await context.agent.slAddStatusToSdJwtCredential({ credential: sdJwtPayload, statusListOpts }) + if (sdJwtPayload.status?.status_list?.idx) { + if (!credentialStatusVC.status || !credentialStatusVC.status.status_list) { + // TODO check, looks like sdJwtPayload and credentialStatusVC is the same + return Promise.reject(Error('slAddStatusToSdJwtCredential did not return a status_list')) + } + + sdJwtPayload.status.status_list.idx = credentialStatusVC.status.status_list.idx } - - sdJwtPayload.status.status_list.idx = credentialStatusVC.status.status_list.idx } } diff --git a/packages/siopv2-oid4vp-common/package.json b/packages/siopv2-oid4vp-common/package.json index e084da24..8b8ac2a9 100644 --- a/packages/siopv2-oid4vp-common/package.json +++ b/packages/siopv2-oid4vp-common/package.json @@ -12,7 +12,7 @@ "access": "public" }, "dependencies": { - "@sphereon/did-auth-siop": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-sdk.core": "workspace:*", "@sphereon/ssi-types": "workspace:*", "uint8arrays": "3.1.1" diff --git a/packages/siopv2-oid4vp-op-auth/package.json b/packages/siopv2-oid4vp-op-auth/package.json index 72afe17f..28af0b6f 100644 --- a/packages/siopv2-oid4vp-op-auth/package.json +++ b/packages/siopv2-oid4vp-op-auth/package.json @@ -14,9 +14,9 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/did-auth-siop": "0.16.1-next.339", - "@sphereon/did-auth-siop-adapter": "0.16.1-next.339", - "@sphereon/oid4vc-common": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/did-auth-siop-adapter": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vc-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/pex": "5.0.0-unstable.28", "@sphereon/pex-models": "^2.3.2", "@sphereon/ssi-sdk-ext.did-utils": "0.27.0", diff --git a/packages/siopv2-oid4vp-rp-auth/package.json b/packages/siopv2-oid4vp-rp-auth/package.json index 7a7b9815..fc2e0c18 100644 --- a/packages/siopv2-oid4vp-rp-auth/package.json +++ b/packages/siopv2-oid4vp-rp-auth/package.json @@ -14,9 +14,9 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { - "@sphereon/did-auth-siop": "0.16.1-next.339", - "@sphereon/did-auth-siop-adapter": "0.16.1-next.339", - "@sphereon/oid4vc-common": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/did-auth-siop-adapter": "0.16.1-feature.IATAB2B.52.345", + "@sphereon/oid4vc-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/pex": "5.0.0-unstable.28", "@sphereon/ssi-sdk-ext.did-utils": "0.27.0", "@sphereon/ssi-sdk-ext.identifier-resolution": "0.27.0", diff --git a/packages/siopv2-oid4vp-rp-rest-api/package.json b/packages/siopv2-oid4vp-rp-rest-api/package.json index 424f3f78..cbc99ef2 100644 --- a/packages/siopv2-oid4vp-rp-rest-api/package.json +++ b/packages/siopv2-oid4vp-rp-rest-api/package.json @@ -11,7 +11,7 @@ "start:dev": "ts-node __tests__/RestAPI.ts" }, "dependencies": { - "@sphereon/did-auth-siop": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-express-support": "workspace:*", "@sphereon/ssi-sdk.core": "workspace:*", "@sphereon/ssi-sdk.credential-validation": "workspace:*", diff --git a/packages/ssi-types/src/types/w3c-vc.ts b/packages/ssi-types/src/types/w3c-vc.ts index 2464e0eb..7126c67f 100644 --- a/packages/ssi-types/src/types/w3c-vc.ts +++ b/packages/ssi-types/src/types/w3c-vc.ts @@ -20,7 +20,7 @@ export interface ICredential { expirationDate?: string // If jti is present, the value MUST be used to set the value of the id property of the new JSON object. id?: string - credentialStatus?: ICredentialStatus + credentialStatus?: ICredentialStatus // | Array TODO this is only true for VC v2.0 CREATE TICKET BEFORE PR description?: string name?: string diff --git a/packages/vc-status-list-issuer-rest-api/src/api-functions.ts b/packages/vc-status-list-issuer-rest-api/src/api-functions.ts index 141b9066..dea2a478 100644 --- a/packages/vc-status-list-issuer-rest-api/src/api-functions.ts +++ b/packages/vc-status-list-issuer-rest-api/src/api-functions.ts @@ -68,7 +68,7 @@ const buildStatusListId = (request: Request): string => { const forwardedPrefix = request.headers['x-forwarded-prefix']?.toString() ?? '' - return `${protocol}://${host}${forwardedPrefix}${request.originalUrl.replace(/\/status\/index\/.*/, '')}` + return `${protocol}://${host}${forwardedPrefix}${request.originalUrl.split('?')[0].replace(/\/status\/index\/.*/, '')}` } export function getStatusListCredentialEndpoint(router: Router, context: IRequiredContext, opts: ICredentialStatusListEndpointOpts) { @@ -80,8 +80,12 @@ export function getStatusListCredentialEndpoint(router: Router, context: IRequir router.get(path, checkAuth(opts?.endpoint), async (request: Request, response: Response) => { try { //todo: Check index against correlationId first. Then match originalUrl against statusList id - const correlationId = request.query.correlationId?.toString() ?? request.params.index?.toString() ?? request.originalUrl - const driver = await getDriver({ id: buildStatusListId(request), correlationId, dbName: opts.dbName }) + //const correlationId = request.query.correlationId?.toString() ?? request.params.index?.toString() ?? request.originalUrl TODO I so not get these + const correlationId = request.query.correlationId?.toString() + const driver = await getDriver({ + ...(correlationId ? { correlationId } : { id: buildStatusListId(request) }), + dbName: opts.dbName, + }) const details = await driver.getStatusList() const statuslistPayload = details.statusListCredential return sendStatuslistResponse(details, statuslistPayload, response) @@ -110,10 +114,10 @@ export function getStatusListCredentialIndexStatusEndpoint(router: Router, conte if (!statusListIndex || statusListIndex < 0) { return sendErrorResponse(response, 400, `Please provide a proper statusListIndex`) } - const correlationId = request.query.correlationId?.toString() ?? request.params.index?.toString() ?? request.originalUrl + //const correlationId = request.query.correlationId?.toString() ?? request.params.index?.toString() ?? request.originalUrl TODO I so not get these + const correlationId = request.query.correlationId?.toString() const driver = await getDriver({ - id: buildStatusListId(request), - correlationId, + ...(correlationId ? { correlationId } : { id: buildStatusListId(request) }), dbName: opts.dbName, }) const details = await driver.getStatusList() @@ -121,10 +125,10 @@ export function getStatusListCredentialIndexStatusEndpoint(router: Router, conte return sendErrorResponse(response, 400, `Please provide a proper statusListIndex`) } + const entityCorrelationId = request.query.entityCorrelationId?.toString() let entry = await driver.getStatusListEntryByIndex({ statusListIndex, - statusListId: details.id, - correlationId: details.correlationId, + ...(entityCorrelationId ? { correlationId: entityCorrelationId } : { statusListId: details.id }), errorOnNotFound: false, }) const type = details.type === StatusListType.StatusList2021 ? 'StatusList2021Entry' : details.type @@ -170,7 +174,10 @@ export function updateStatusEndpoint(router: Router, context: IRequiredContext, } else if (!updateRequest.credentialStatus || updateRequest.credentialStatus.length === 0) { return sendErrorResponse(response, 400, 'No statusList updates supplied') } - const driver = await getDriver({ id: statusListId, correlationId: statusListCorrelationId, dbName: opts.dbName }) + const driver = await getDriver({ + ...(statusListCorrelationId ? { correlationId: statusListCorrelationId } : { id: buildStatusListId(request) }), + dbName: opts.dbName, + }) // Get status list entry based on request type let statusListEntry: IStatusListEntryEntity | undefined diff --git a/packages/vc-status-list-issuer/__tests__/status-list-vc-handling.test.ts b/packages/vc-status-list-issuer/__tests__/status-list-vc-handling.test.ts index daf55690..44191241 100644 --- a/packages/vc-status-list-issuer/__tests__/status-list-vc-handling.test.ts +++ b/packages/vc-status-list-issuer/__tests__/status-list-vc-handling.test.ts @@ -73,9 +73,24 @@ type Plugins = IDIDManager & IIdentifierResolution & IStatusListPlugin -describe('JWT Verifiable Credential, should be', () => { +describe('Status List VC handling', () => { let agent: TAgent - // let agentContext: IAgentContext + + const baseCredential: IVerifiableCredential = { + '@context': ['https://www.w3.org/2018/credentials/v1'], + type: ['VerifiableCredential'], + issuer: 'did:example:123', + issuanceDate: '2024-01-15T00:00:00Z', + credentialSubject: { + id: 'did:example:456', + }, + proof: { + type: 'Ed25519Signature2018', + created: '2024-01-15T00:00:00Z', + proofPurpose: 'assertionMethod', + verificationMethod: 'did:example:123#key-1', + }, + } beforeAll(async () => { agent = createAgent({ @@ -125,7 +140,6 @@ describe('JWT Verifiable Credential, should be', () => { }), ], }) - // agentContext = {...agent.context, agent}; await agent.dataStoreORMGetIdentifiers().then((ids) => ids.forEach((id) => console.log(JSON.stringify(id, null, 2)))) await agent @@ -162,7 +176,7 @@ describe('JWT Verifiable Credential, should be', () => { }) it('should successfully create OAuth status list using JWT format with proper header and encoding', async () => { - const mockResult = { + const mockResult: StatusListResult = { type: StatusListType.OAuthStatusList, proofFormat: 'jwt', statusListCredential: 'ey_eyMockJWT', @@ -174,7 +188,7 @@ describe('JWT Verifiable Credential, should be', () => { oauthStatusList: { bitsPerStatus: 2, }, - } satisfies StatusListResult + } jest.spyOn(agent, 'slCreateStatusList').mockResolvedValue(mockResult) const result = await agent.slCreateStatusList({ @@ -196,19 +210,7 @@ describe('JWT Verifiable Credential, should be', () => { describe('slAddStatusToCredential', () => { it('should inject a status to a credential', async () => { const mockCredential: IVerifiableCredential = { - '@context': ['https://www.w3.org/2018/credentials/v1'], - type: ['VerifiableCredential'], - issuer: 'did:example:123', - issuanceDate: '2024-01-15T00:00:00Z', - credentialSubject: { - id: 'did:example:456', - }, - proof: { - type: 'Ed25519Signature2018', - created: '2024-01-15T00:00:00Z', - proofPurpose: 'assertionMethod', - verificationMethod: 'did:example:123#key-1', - }, + ...baseCredential, } const mockResultCredential: IVerifiableCredential = { @@ -225,16 +227,267 @@ describe('JWT Verifiable Credential, should be', () => { const result = await agent.slAddStatusToCredential({ credential: mockCredential, - statusListId: 'list123', - statusListIndex: 0, + statusListOpts: [ + { + statusListId: 'list123', + statusListIndex: 0, + }, + ], }) - expect(result.credentialStatus?.type).toBe('OAuth2StatusList') - expect(result.credentialStatus?.id).toBe('list123#0') - expect(result.credentialStatus?.statusListIndex).toBe('0') - expect(result.credentialStatus?.statusListCredential).toBe('eyMockJWT') + const credentialStatus = Array.isArray(result.credentialStatus) ? result.credentialStatus[0] : result.credentialStatus + expect(credentialStatus?.type).toBe('OAuth2StatusList') + expect(credentialStatus?.id).toBe('list123#0') + expect(credentialStatus?.statusListIndex).toBe('0') + expect(credentialStatus?.statusListCredential).toBe('eyMockJWT') expect(result.issuer).toBe('did:example:123') }) + + it('should add status when credential has no credentialStatus', async () => { + const mockCredential = { + ...baseCredential, + } + + const mockResultCredential = { + ...mockCredential, + credentialStatus: { + id: 'list123#0', + type: 'StatusList2021Entry', + statusPurpose: 'revocation', + statusListIndex: '0', + statusListCredential: 'list123', + }, + } + + jest.spyOn(agent, 'slAddStatusToCredential').mockResolvedValue(mockResultCredential) + + const result = await agent.slAddStatusToCredential({ + credential: mockCredential, + statusListOpts: [ + { + statusListId: 'list123', + }, + ], + }) + + expect(result.credentialStatus).toBeDefined() + }) + + /* it('should handle array of credential statuses', async () => { TODO this is only true for VC v2.0 CREATE TICKET BEFORE PR + const mockCredential: IVerifiableCredential = { + ...baseCredential, + credentialStatus: [ + { + id: 'list123#0', + type: 'StatusList2021Entry', + statusPurpose: 'revocation', + statusListIndex: '0', + statusListCredential: 'list123', + }, + ], + } + + const mockResultCredential: IVerifiableCredential = { + ...mockCredential, + credentialStatus: [ + // Need to check if array and has elements + Array.isArray(mockCredential.credentialStatus) && mockCredential.credentialStatus.length > 0 + ? mockCredential.credentialStatus[0] + : { + id: 'list123#0', + type: 'StatusList2021Entry', + statusPurpose: 'revocation', + statusListIndex: '0', + statusListCredential: 'list123', + }, + { + id: 'list456#5', + type: 'StatusList2021Entry', + statusPurpose: 'revocation', + statusListIndex: '5', + statusListCredential: 'list456', + }, + ], + } + + jest.spyOn(agent, 'slAddStatusToCredential').mockResolvedValue(mockResultCredential) + + const result = await agent.slAddStatusToCredential({ + credential: mockCredential, + statusListOpts: [ + { + statusListId: 'list456', + statusListIndex: 5, + }, + ], + }) + + expect(Array.isArray(result.credentialStatus)).toBe(true) + expect((result.credentialStatus as ICredentialStatus[]).length).toBe(2) + expect((result.credentialStatus as ICredentialStatus[])[1].statusListCredential).toBe('list456') + }) +*/ + it('should use correlation IDs when provided', async () => { + const mockCredential: IVerifiableCredential = { + ...baseCredential, + } + + const mockResultCredential: IVerifiableCredential = { + ...mockCredential, + credentialStatus: { + id: 'list123#0', + type: 'StatusList2021Entry', + statusListIndex: '0', + statusListCredential: 'list123', + }, + } + + jest.spyOn(agent, 'slAddStatusToCredential').mockResolvedValue(mockResultCredential) + + const result = await agent.slAddStatusToCredential({ + credential: mockCredential, + statusListOpts: [ + { + statusListCorrelationId: 'corr-123', + statusEntryCorrelationId: 'entry-456', + }, + ], + }) + + expect(result.credentialStatus).toBeDefined() + }) + + /* + it('should handle multiple status list options', async () => { TODO this is only true for VC v2.0 CREATE TICKET BEFORE PR + const mockCredential: IVerifiableCredential = { + ...baseCredential, + } + + const mockResultCredential: IVerifiableCredential = { + ...mockCredential, + credentialStatus: [ + { + id: 'list1#0', + type: 'StatusList2021Entry', + statusListIndex: '0', + statusListCredential: 'list1', + }, + { + id: 'list2#5', + type: 'StatusList2021Entry', + statusListIndex: '5', + statusListCredential: 'list2', + }, + ], + } + + jest.spyOn(agent, 'slAddStatusToCredential').mockResolvedValue(mockResultCredential) + + const result = await agent.slAddStatusToCredential({ + credential: mockCredential, + statusListOpts: [{ statusListId: 'list1' }, { statusListId: 'list2', statusListIndex: 5 }], + }) + + expect(Array.isArray(result.credentialStatus)).toBe(true) + const credStatus = result.credentialStatus as ICredentialStatus[] + expect(credStatus.length).toBe(2) + }) +*/ + + it('should handle credential with no options but existing status', async () => { + const mockCredential: IVerifiableCredential = { + ...baseCredential, + credentialStatus: { + id: 'list123#5', + type: 'StatusList2021Entry', + statusListIndex: '5', + statusListCredential: 'list123', + }, + } + + const mockResultCredential: IVerifiableCredential = { + ...mockCredential, + credentialStatus: { + id: 'list123#10', + type: 'StatusList2021Entry', + statusListIndex: '10', + statusListCredential: 'list123', + }, + } + + jest.spyOn(agent, 'slAddStatusToCredential').mockResolvedValue(mockResultCredential) + const result = await agent.slAddStatusToCredential({ credential: mockCredential }) + + const credStatus = Array.isArray(result.credentialStatus) ? result.credentialStatus[0] : result.credentialStatus + expect(credStatus?.statusListIndex).toBe('10') + }) + }) + + describe('slAddStatusToSdJwtCredential', () => { + it('should add status to SD-JWT credential without existing status', async () => { + const mockCredential = { + iss: 'did:example:123', + vct: 'VerifiableCredential', + sub: 'did:example:456', + } + + const mockResultCredential = { + ...mockCredential, + status: { + status_list: { + uri: 'list123', + idx: 0, + }, + }, + } + + jest.spyOn(agent, 'slAddStatusToSdJwtCredential').mockResolvedValue(mockResultCredential) + + const result = await agent.slAddStatusToSdJwtCredential({ + credential: mockCredential, + statusListOpts: [{ statusListId: 'list123' }], + }) + + expect(result.status?.status_list.uri).toBe('list123') + expect(result.status?.status_list.idx).toBe(0) + }) + + it('should update existing status in SD-JWT credential', async () => { + const mockCredential = { + iss: 'did:example:123', + vct: 'VerifiableCredential', + status: { + status_list: { + uri: 'list123', + idx: 5, + }, + }, + } + + const mockResultCredential = { + ...mockCredential, + status: { + status_list: { + uri: 'list123', + idx: 10, + }, + }, + } + + jest.spyOn(agent, 'slAddStatusToSdJwtCredential').mockResolvedValue(mockResultCredential) + + const result = await agent.slAddStatusToSdJwtCredential({ + credential: mockCredential, + statusListOpts: [ + { + statusListId: 'list123', + statusListIndex: 10, + }, + ], + }) + + expect(result.status?.status_list.idx).toBe(10) + }) }) describe('slGetStatusList', () => { @@ -255,9 +508,7 @@ describe('JWT Verifiable Credential, should be', () => { jest.spyOn(agent, 'slGetStatusList').mockResolvedValue(mockResult) - const result = await agent.slGetStatusList({ - id: 'list123', - }) + const result = await agent.slGetStatusList({ id: 'list123' }) expect(result.id).toBe('list123') expect(result.type).toBe(StatusListType.OAuthStatusList) @@ -268,12 +519,7 @@ describe('JWT Verifiable Credential, should be', () => { it('should throw when status list not found', async () => { jest.spyOn(agent, 'slGetStatusList').mockRejectedValue(new Error('Status list not found')) - - await expect( - agent.slGetStatusList({ - id: 'nonexistent', - }), - ).rejects.toThrow('Status list not found') + await expect(agent.slGetStatusList({ id: 'nonexistent' })).rejects.toThrow('Status list not found') }) }) }) diff --git a/packages/vc-status-list-issuer/package.json b/packages/vc-status-list-issuer/package.json index bba53588..3fe6e0d4 100644 --- a/packages/vc-status-list-issuer/package.json +++ b/packages/vc-status-list-issuer/package.json @@ -15,14 +15,14 @@ "build:clean": "tsc --build --clean && tsc --build" }, "dependencies": { + "@sd-jwt/core": "^0.7.2", + "@sd-jwt/sd-jwt-vc": "^0.7.2", "@sphereon/ssi-sdk-ext.did-utils": "0.27.0", "@sphereon/ssi-sdk-ext.identifier-resolution": "0.27.0", "@sphereon/ssi-sdk.core": "workspace:*", "@sphereon/ssi-sdk.vc-status-list": "workspace:*", "@sphereon/ssi-sdk.vc-status-list-issuer-drivers": "workspace:*", "@sphereon/ssi-types": "workspace:*", - "@sd-jwt/core": "^0.7.2", - "@sd-jwt/sd-jwt-vc": "^0.7.2", "@sphereon/vc-status-list": "7.0.0-next.0", "@veramo/core": "4.2.0", "debug": "^4.3.5", @@ -33,6 +33,7 @@ "uuid": "^9.0.1" }, "devDependencies": { + "@babel/preset-typescript": "^7.24.7", "@sphereon/did-uni-client": "^0.6.3", "@sphereon/ssi-sdk-ext.did-provider-jwk": "0.27.0", "@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.27.0", @@ -62,6 +63,7 @@ "@veramo/utils": "4.2.0", "did-resolver": "^4.1.0", "morgan": "^1.10.0", + "ts-jest": "^29.2.5", "typescript": "5.4.2" }, "files": [ diff --git a/packages/vc-status-list-issuer/src/agent/StatusListPlugin.ts b/packages/vc-status-list-issuer/src/agent/StatusListPlugin.ts index ee139c77..ab4429b8 100644 --- a/packages/vc-status-list-issuer/src/agent/StatusListPlugin.ts +++ b/packages/vc-status-list-issuer/src/agent/StatusListPlugin.ts @@ -117,56 +117,175 @@ export class StatusListPlugin implements IAgentPlugin { return statusListDetails } + /** + * Adds status information to a credential by either: + * 1. Using existing status ID from the credential if present + * 2. Using provided status list options + * 3. Falling back to the default status list ID + * + * @param args Contains credential and status options + * @param context Required agent context + * @returns Credential with added status information + */ private async slAddStatusToCredential(args: IAddStatusToCredentialArgs, context: IRequiredContext): Promise { const { credential, ...rest } = args + logger.debug(`Adding status to credential ${credential.id ?? 'without ID'}`) + const credentialStatus = credential.credentialStatus if (!credentialStatus) { - logger.info(`Not adding status list info, since no credentialStatus object was present in the credential`) - return Promise.resolve(credential) + logger.debug('No credential status present, returning original credential') + return credential } - // If the credential is already providing the id we favor that over the argument. Default status list as a fallback. We also allow passing in an empty id to get the default - const credentialStatusId = credentialStatus.id && credentialStatus.id.trim() !== '' ? credentialStatus.id.split('#')[0] : undefined - const statusListId = credentialStatus.statusListCredential ?? credentialStatusId ?? args.statusListId ?? this.defaultStatusListId - const instance = this.instances.find((instance) => instance.id === statusListId) - if (!instance) { - return Promise.reject(Error(`Status list with id ${statusListId} is not managed by the status list plugin`)) - } else if (!instance.dataSource && !instance.driverOptions?.dbName) { - return Promise.reject(Error(`Either a datasource or dbName needs to be supplied`)) + + let existingStatusId: string | undefined + if (Array.isArray(credentialStatus)) { + // This was implemented with VC v2.0 support, but the rest of the SDK is not ready for that, so ICredential.credentialStatus's array union is disabled for now + for (const stat of credentialStatus) { + if (stat.id && stat.id.trim() !== '') { + existingStatusId = stat.id.split('#')[0] + break + } + } + } else if (credentialStatus.id && credentialStatus.id.trim() !== '') { + existingStatusId = credentialStatus.id.split('#')[0] } - const credentialId = credential.id ?? args.credentialId - const dataSource = instance.dataSource ? await instance.dataSource : await this.allDataSources.getDbConnection(instance.driverOptions!.dbName!) - await handleCredentialStatus(credential, { - ...rest, - credentialId, - statusListId, - driver: await getDriver({ dataSource, id: statusListId }), - statusEntryCorrelationId: rest.statusEntryCorrelationId ?? instance.correlationId, - }) + + if (existingStatusId) { + logger.debug(`Using existing status ID ${existingStatusId} for credential ${credential.id ?? 'without ID'}`) + const instance = this.instances.find((inst) => inst.id === existingStatusId) + if (!instance) { + throw Error(`Status list with id ${existingStatusId} is not managed by the status list plugin`) + } + if (!instance.dataSource && !instance.driverOptions?.dbName) { + throw Error(`Either a datasource or dbName needs to be supplied`) + } + const credentialId = credential.id ?? rest.credentialId + const dataSource = instance.dataSource ? await instance.dataSource : await this.allDataSources.getDbConnection(instance.driverOptions!.dbName!) + const driver = await getDriver({ dataSource, id: existingStatusId }) + await handleCredentialStatus(credential, { + ...rest, + credentialId, + statusListOpts: [{ statusListId: existingStatusId }], + driver, + }) + return credential + } + + const statusListOpts = rest.statusListOpts && rest.statusListOpts.length > 0 ? rest.statusListOpts : [{ statusListId: this.defaultStatusListId }] + logger.debug(`Adding new status using ${statusListOpts.length} status list option(s)`) + const credentialId = credential.id ?? rest.credentialId + for (const opt of statusListOpts) { + const effectiveStatusListId = opt.statusListId ?? this.defaultStatusListId + let instance + if (opt.statusListCorrelationId && opt.statusListCorrelationId.trim() !== '') { + instance = this.instances.find((inst) => inst.correlationId === opt.statusListCorrelationId) + } else { + instance = this.instances.find((inst) => inst.id === effectiveStatusListId) + } + if (!instance) { + throw Error(`Status list with identifier ${opt.statusListCorrelationId ?? effectiveStatusListId} is not managed by the status list plugin`) + } + if (!instance.dataSource && !instance.driverOptions?.dbName) { + throw Error(`Either a datasource or dbName needs to be supplied`) + } + const dataSource = instance.dataSource ? await instance.dataSource : await this.allDataSources.getDbConnection(instance.driverOptions!.dbName!) + const driver = + opt.statusListCorrelationId && opt.statusListCorrelationId.trim() !== '' + ? await getDriver({ dataSource, correlationId: opt.statusListCorrelationId }) + : await getDriver({ dataSource, id: effectiveStatusListId }) + await handleCredentialStatus(credential, { + ...rest, + credentialId, + statusListOpts: [ + { + statusListId: effectiveStatusListId, + statusListCorrelationId: opt.statusListCorrelationId, + statusEntryCorrelationId: opt.statusEntryCorrelationId ?? instance.correlationId, + }, + ], + driver, + }) + } + logger.debug(`Successfully added status information to credential ${credential.id ?? 'without ID'}`) return credential } + /** + * Adds status information to an SD-JWT credential by either: + * 1. Using existing status URI from the credential if present + * 2. Using provided status list options + * 3. Falling back to the default status list ID + * + * @param args Contains SD-JWT credential and status options + * @param context Required agent context + * @returns SD-JWT credential with added status information + */ private async slAddStatusToSdJwtCredential(args: IAddStatusToSdJwtCredentialArgs, context: IRequiredContext): Promise { const { credential, ...rest } = args + logger.debug(`Adding status to SD-JWT credential`) + const credentialStatus = credential.status if (!credentialStatus) { - logger.info(`Not adding status list info, since no credentialStatus object was present in the credential`) - return Promise.resolve(credential) + logger.debug('No credential status present, returning original SD-JWT credential') + return credential + } + + let existingStatusUri: string | undefined + if (credentialStatus.status_list && credentialStatus.status_list.uri && credentialStatus.status_list.uri.trim() !== '') { + existingStatusUri = credentialStatus.status_list.uri + } + if (existingStatusUri) { + logger.debug(`Using existing status URI ${existingStatusUri} for SD-JWT credential`) + + const instance = this.instances.find((inst) => inst.id === existingStatusUri) + if (!instance) { + throw Error(`Status list with id ${existingStatusUri} is not managed by the status list plugin`) + } + if (!instance.dataSource && !instance.driverOptions?.dbName) { + throw Error(`Either a datasource or dbName needs to be supplied`) + } + const dataSource = instance.dataSource ? await instance.dataSource : await this.allDataSources.getDbConnection(instance.driverOptions!.dbName!) + const driver = await getDriver({ dataSource, id: existingStatusUri }) + await handleSdJwtCredentialStatus(credential, { + ...rest, + statusListOpts: [{ statusListId: existingStatusUri }], + driver, + }) + return credential + } + + const statusListOpts = rest.statusListOpts && rest.statusListOpts.length > 0 ? rest.statusListOpts : [{ statusListId: this.defaultStatusListId }] + logger.info(`Adding new status using status list options with ID ${statusListOpts[0].statusListId ?? this.defaultStatusListId}`) + const firstOpt = statusListOpts[0] + const effectiveStatusListId = firstOpt.statusListId ?? this.defaultStatusListId + let instance + if (firstOpt.statusListCorrelationId && firstOpt.statusListCorrelationId.trim() !== '') { + instance = this.instances.find((inst) => inst.correlationId === firstOpt.statusListCorrelationId) + } else { + instance = this.instances.find((inst) => inst.id === effectiveStatusListId) } - // If the credential is already providing the id we favor that over the argument. Default status list as a fallback. We also allow passing in an empty id to get the default - const statusListUri = credentialStatus.status_list.uri - const instance = this.instances.find((instance) => instance.id === statusListUri) if (!instance) { - return Promise.reject(Error(`Status list with id ${statusListUri} is not managed by the status list plugin`)) - } else if (!instance.dataSource && !instance.driverOptions?.dbName) { - return Promise.reject(Error(`Either a datasource or dbName needs to be supplied`)) + throw Error(`Status list with identifier ${firstOpt.statusListCorrelationId ?? effectiveStatusListId} is not managed by the status list plugin`) + } + if (!instance.dataSource && !instance.driverOptions?.dbName) { + throw Error(`Either a datasource or dbName needs to be supplied`) } const dataSource = instance.dataSource ? await instance.dataSource : await this.allDataSources.getDbConnection(instance.driverOptions!.dbName!) + const driver = + firstOpt.statusListCorrelationId && firstOpt.statusListCorrelationId.trim() !== '' + ? await getDriver({ dataSource, correlationId: firstOpt.statusListCorrelationId }) + : await getDriver({ dataSource, id: effectiveStatusListId }) await handleSdJwtCredentialStatus(credential, { ...rest, - statusListId: statusListUri, - driver: await getDriver({ dataSource, id: statusListUri }), - statusEntryCorrelationId: rest.statusEntryCorrelationId ?? instance.correlationId, + statusListOpts: [ + { + statusListId: effectiveStatusListId, + statusListCorrelationId: firstOpt.statusListCorrelationId, + }, + ], + driver, }) + logger.debug('Successfully added status information to SD-JWT credential') return credential } } diff --git a/packages/vc-status-list-issuer/src/functions.ts b/packages/vc-status-list-issuer/src/functions.ts index 82d6b784..056e79a2 100644 --- a/packages/vc-status-list-issuer/src/functions.ts +++ b/packages/vc-status-list-issuer/src/functions.ts @@ -7,11 +7,13 @@ import { StatusListResult, } from '@sphereon/ssi-sdk.vc-status-list' import { getDriver, IStatusListDriver } from '@sphereon/ssi-sdk.vc-status-list-issuer-drivers' -import { StatusListType, StatusPurpose2021 } from '@sphereon/ssi-types' -import { IAgentContext } from '@veramo/core' import debug from 'debug' -import { StatusListInstance } from './types' import { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc' +import { Loggers, StatusListType, StatusPurpose2021 } from '@sphereon/ssi-types' +import { StatusListInstance } from './types' +import { IAgentContext } from '@veramo/core' + +const logger = Loggers.DEFAULT.get('sphereon:ssi-sdk:vc-status-list-issuer') async function processStatusListEntry(params: { statusListId: string @@ -23,6 +25,7 @@ async function processStatusListEntry(params: { debugCredentialInfo: string useIndexCondition: (index: number) => boolean checkCredentialIdMismatch?: (existingEntry: IStatusListEntryEntity, credentialId: string, index: number) => void + statusListCorrelationId?: string }): Promise<{ statusListIndex: number; updateResult: any }> { let existingEntry: IStatusListEntryEntity | undefined = undefined // Search whether there is an existing status list entry for this credential first @@ -65,8 +68,8 @@ async function processStatusListEntry(params: { const updateArgs: any = { statusList: params.statusListId, statusListIndex, - correlationId: params.opts?.statusEntryCorrelationId, - value: params.opts?.value ?? 0, // For new entries the value may not be set. default to 0, otherwise the get API will return value null while for non-existing entries it will return 0 + correlationId: params.statusListCorrelationId, + value: params.opts?.value ?? 0, } if (params.credentialId) { updateArgs.credentialId = params.credentialId @@ -102,22 +105,55 @@ export const createStatusListFromInstance = async ( return statusList } +/** + * Adds status information to a credential using status list options from either: + * - The provided options + * - Existing credential status information + * + * The function updates each status list entry and modifies the credential's status. + * + * @param credential The credential to update with status information + * @param credentialStatusOpts Options for status handling and driver configuration + */ export const handleCredentialStatus = async ( credential: CredentialWithStatusSupport, - credentialStatusOpts?: IIssueCredentialStatusOpts & { - driver?: IStatusListDriver - }, + credentialStatusOpts?: IIssueCredentialStatusOpts & { driver?: IStatusListDriver }, ): Promise => { - if (credential.credentialStatus) { - const credentialId = credential.id ?? credentialStatusOpts?.credentialId - const statusListId = credential.credentialStatus.statusListCredential ?? credentialStatusOpts?.statusListId - debug(`Creating new credentialStatus object for credential with id ${credentialId} and statusListId ${statusListId}...`) + logger.debug(`Starting status update for credential ${credential.id ?? 'without ID'}`) + + const statusListOpts = [...(credentialStatusOpts?.statusListOpts ?? [])] + if (statusListOpts.length === 0 && credential.credentialStatus) { + if (Array.isArray(credential.credentialStatus)) { + for (const credStatus of credential.credentialStatus) { + if (credStatus.statusListCredential) { + statusListOpts.push({ + statusListId: credStatus.statusListCredential, + statusListIndex: credStatus.statusListIndex, + statusListCorrelationId: (credStatus as any).statusListCorrelationId, + }) + } + } + } else if (credential.credentialStatus.statusListCredential) { + statusListOpts.push({ + statusListId: credential.credentialStatus.statusListCredential, + statusListIndex: credential.credentialStatus.statusListIndex, + statusListCorrelationId: (credential.credentialStatus as any).statusListCorrelationId, + }) + } + } + if (!statusListOpts.length) { + logger.debug('No status list options found, skipping update') + return + } + const credentialId = credential.id ?? credentialStatusOpts?.credentialId + for (const statusListOpt of statusListOpts) { + const statusListId = statusListOpt.statusListId if (!statusListId) { - throw Error( - `A credential status is requested, but we could not determine the status list id from 'statusListCredential' value or configuration`, - ) + logger.debug('Skipping status list option without ID') + continue } + logger.debug(`Processing status list ${statusListId} for credential ${credentialId ?? 'without ID'}`) const slDriver = credentialStatusOpts?.driver ?? (await getDriver({ @@ -125,48 +161,74 @@ export const handleCredentialStatus = async ( dataSource: credentialStatusOpts?.dataSource, })) const statusList = await slDriver.statusListStore.getStatusList({ id: statusListId }) - - // Search whether there is an existing status list entry for this credential first - const currentIndex = credential.credentialStatus.statusListIndex ?? credentialStatusOpts?.statusListIndex ?? 0 - const { statusListIndex, updateResult } = await processStatusListEntry({ + const currentIndex = statusListOpt.statusListIndex ?? 0 + const { updateResult } = await processStatusListEntry({ statusListId, statusList, credentialId, currentIndex, + statusListCorrelationId: statusListOpt.statusListCorrelationId, opts: credentialStatusOpts, slDriver, debugCredentialInfo: `credential with id ${credentialId} and statusListId ${statusListId}`, useIndexCondition: (index) => Boolean(index), checkCredentialIdMismatch: (existingEntry, credentialId, index) => { throw Error( - `A credential with new id (${credentialId}) is issued, but its id does not match a registered statusListEntry id ${existingEntry.credentialId} for index ${index} `, + `A credential with new id (${credentialId}) is issued, but its id does not match a registered statusListEntry id ${existingEntry.credentialId} for index ${index}`, ) }, }) - - debug(`StatusListEntry with statusListIndex ${statusListIndex} created for credential with id ${credentialId} and statusListId ${statusListId}`) - - credential.credentialStatus = { - ...credential.credentialStatus, - ...updateResult.credentialStatus, + if (!credential.credentialStatus || Array.isArray(credential.credentialStatus)) { + credential.credentialStatus = { + id: `${statusListId}`, + type: 'StatusList2021Entry', + statusPurpose: 'revocation', + statusListCredential: statusListId, + ...updateResult.credentialStatus, + } } } + logger.debug(`Completed status updates for credential ${credentialId ?? 'without ID'}`) } + +/** + * Adds status information to an SD-JWT credential using status list options from either: + * - The provided options + * - Existing credential status information + * + * Updates the credential's status field with status list URI and index. + * + * @param credential The SD-JWT credential to update + * @param credentialStatusOpts Options for status handling and driver configuration + * @throws Error if no status list options are available + */ export const handleSdJwtCredentialStatus = async ( credential: SdJwtVcPayload, - credentialStatusOpts?: IIssueCredentialStatusOpts & { - driver?: IStatusListDriver - }, + credentialStatusOpts?: IIssueCredentialStatusOpts & { driver?: IStatusListDriver }, ): Promise => { - if (credential.status) { - const statusListId = credential.status.status_list.uri ?? credentialStatusOpts?.statusListId - debug(`Creating new credentialStatus object for credential with statusListId ${statusListId}...`) + logger.debug('Starting status update for SD-JWT credential') + + const statusListOpts = [...(credentialStatusOpts?.statusListOpts ?? [])] + if (statusListOpts.length === 0 && credential.status?.status_list) { + statusListOpts.push({ + statusListId: credential.status.status_list.uri, + statusListIndex: credential.status.status_list.idx, + statusListCorrelationId: (credential.status.status_list as any).statusListCorrelationId, + }) + } + + if (!statusListOpts.length) { + throw Error('No status list options available from credential or options') + } + + for (const statusListOpt of statusListOpts) { + const statusListId = statusListOpt.statusListId if (!statusListId) { - throw Error( - `A credential status is requested, but we could not determine the status list id from 'statusListCredential' value or configuration`, - ) + logger.debug('Skipping status list option without ID') + continue } + logger.info(`Processing status list ${statusListId}`) const slDriver = credentialStatusOpts?.driver ?? (await getDriver({ @@ -174,23 +236,35 @@ export const handleSdJwtCredentialStatus = async ( dataSource: credentialStatusOpts?.dataSource, })) const statusList = await slDriver.statusListStore.getStatusList({ id: statusListId }) - - const statusListIndex = - typeof credentialStatusOpts?.statusListIndex === 'string' - ? parseInt(credentialStatusOpts.statusListIndex, 10) - : (credentialStatusOpts?.statusListIndex ?? (await slDriver.getRandomNewStatusListIndex({ correlationId: statusList.correlationId }))) - await processStatusListEntry({ + const currentIndex = statusListOpt.statusListIndex ?? 0 + const { statusListIndex } = await processStatusListEntry({ statusListId, statusList, - currentIndex: statusListIndex, + currentIndex, + statusListCorrelationId: statusListOpt.statusListCorrelationId, opts: credentialStatusOpts, slDriver, debugCredentialInfo: `credential with statusListId ${statusListId}`, useIndexCondition: (index) => index > 0, }) - - debug(`StatusListEntry with statusListIndex ${statusListIndex} created for credential with statusListId ${statusListId}`) - - credential.status.status_list.idx = statusListIndex + if (!credential.status) { + credential.status = { + status_list: { + uri: statusListId, + idx: statusListIndex, + }, + } + } else if (!credential.status.status_list) { + credential.status.status_list = { + uri: statusListId, + idx: statusListIndex, + } + } else { + credential.status.status_list = { + uri: credential.status.status_list.uri || statusListId, + idx: statusListIndex, + } + } } + logger.debug('Completed SD-JWT credential status update') } diff --git a/packages/vc-status-list/package.json b/packages/vc-status-list/package.json index 14a97179..8d399d8e 100644 --- a/packages/vc-status-list/package.json +++ b/packages/vc-status-list/package.json @@ -16,6 +16,7 @@ "@sphereon/ssi-sdk-ext.jwt-service": "0.27.0", "@sphereon/ssi-types": "workspace:*", "@sphereon/vc-status-list": "7.0.0-next.0", + "@sphereon/oid4vci-common": "0.16.1-feature.IATAB2B.52.345", "@sphereon/kmp-cbor": "0.2.0-SNAPSHOT.25", "@sd-jwt/core": "^0.7.2", "@sd-jwt/sd-jwt-vc": "^0.7.2", diff --git a/packages/vc-status-list/src/types/index.ts b/packages/vc-status-list/src/types/index.ts index 1f16e793..e2b9a0d5 100644 --- a/packages/vc-status-list/src/types/index.ts +++ b/packages/vc-status-list/src/types/index.ts @@ -25,6 +25,7 @@ import { import { DataSource } from 'typeorm' import { BitsPerStatus } from '@sd-jwt/jwt-status-list/dist' import { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc' +import { StatusListOpts } from '@sphereon/oid4vci-common' export enum StatusOAuth { Valid = 0, @@ -231,10 +232,8 @@ export type IAddStatusToSdJwtCredentialArgs = Omit credentialId?: string // An id to use for the credential. Normally should be set as the crdential.id value - statusListId?: string // Explicit status list to use. Determines the id from the credentialStatus object in the VC itself or uses the default otherwise - statusListIndex?: number | string - statusEntryCorrelationId?: string // An id to use for correlation. Can be the credential id, but also a business identifier. Will only be used for lookups/management value?: string } diff --git a/packages/w3c-vc-api/package.json b/packages/w3c-vc-api/package.json index 8dc47b5c..d845d71d 100644 --- a/packages/w3c-vc-api/package.json +++ b/packages/w3c-vc-api/package.json @@ -11,7 +11,7 @@ "start:dev": "ts-node __tests__/agent.ts" }, "dependencies": { - "@sphereon/did-auth-siop": "0.16.1-next.339", + "@sphereon/did-auth-siop": "0.16.1-feature.IATAB2B.52.345", "@sphereon/ssi-express-support": "workspace:*", "@sphereon/ssi-sdk.agent-config": "workspace:*", "@sphereon/ssi-sdk.core": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 56f73e6c..eb42c186 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -619,11 +619,11 @@ importers: specifier: ^5.7.0 version: 5.7.0 '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/did-auth-siop-adapter': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/pex': specifier: 5.0.0-unstable.28 version: 5.0.0-unstable.28 @@ -701,11 +701,11 @@ importers: version: 4.38.3 devDependencies: '@sphereon/oid4vci-client': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/oid4vci-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-express-support': specifier: workspace:* version: link:../ssi-express-support @@ -918,8 +918,8 @@ importers: packages/mdl-mdoc: dependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/kmp-mdoc-core': specifier: 0.2.0-SNAPSHOT.26 version: 0.2.0-SNAPSHOT.26 @@ -976,11 +976,11 @@ importers: version: 9.0.1 devDependencies: '@sphereon/oid4vci-client': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/oid4vci-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-express-support': specifier: workspace:* version: link:../ssi-express-support @@ -1149,17 +1149,17 @@ importers: packages/oid4vci-holder: dependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/kmp-mdoc-core': specifier: 0.2.0-SNAPSHOT.26 version: 0.2.0-SNAPSHOT.26 '@sphereon/oid4vci-client': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/oid4vci-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-sdk-ext.did-utils': specifier: 0.27.0 version: 0.27.0(encoding@0.1.13)(pg@8.13.1)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@20.17.9)(typescript@5.6.3)) @@ -1237,8 +1237,8 @@ importers: version: 4.38.3 devDependencies: '@sphereon/oid4vc-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339 + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345 '@sphereon/ssi-sdk-ext.did-resolver-jwk': specifier: 0.27.0 version: 0.27.0 @@ -1273,11 +1273,11 @@ importers: packages/oid4vci-issuer: dependencies: '@sphereon/oid4vci-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/oid4vci-issuer': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13) '@sphereon/ssi-sdk-ext.did-utils': specifier: 0.27.0 version: 0.27.0(encoding@0.1.13)(pg@8.13.1)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@20.17.9)(typescript@5.6.3)) @@ -1334,8 +1334,8 @@ importers: version: 9.0.1 devDependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/did-uni-client': specifier: ^0.6.3 version: 0.6.3(encoding@0.1.13) @@ -1358,14 +1358,14 @@ importers: packages/oid4vci-issuer-rest-api: dependencies: '@sphereon/oid4vci-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/oid4vci-issuer': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13) '@sphereon/oid4vci-issuer-server': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(@noble/hashes@1.6.1)(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13)(passport-azure-ad@4.3.5)(passport-http-bearer@1.0.1) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(@noble/hashes@1.6.1)(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13)(passport-azure-ad@4.3.5)(passport-http-bearer@1.0.1) '@sphereon/ssi-express-support': specifier: workspace:* version: link:../ssi-express-support @@ -1527,8 +1527,8 @@ importers: packages/oid4vci-issuer-rest-client: dependencies: '@sphereon/oid4vci-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-types': specifier: workspace:* version: link:../ssi-types @@ -1564,8 +1564,8 @@ importers: packages/oid4vci-issuer-store: dependencies: '@sphereon/oid4vci-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-sdk-ext.did-utils': specifier: 0.27.0 version: 0.27.0(encoding@0.1.13)(pg@8.13.1)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@20.17.9)(typescript@5.6.3)) @@ -2262,8 +2262,8 @@ importers: packages/siopv2-oid4vp-common: dependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/ssi-sdk.core': specifier: workspace:* version: link:../ssi-sdk-core @@ -2284,14 +2284,14 @@ importers: packages/siopv2-oid4vp-op-auth: dependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/did-auth-siop-adapter': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/oid4vc-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339 + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345 '@sphereon/pex': specifier: 5.0.0-unstable.28 version: 5.0.0-unstable.28 @@ -2426,14 +2426,14 @@ importers: packages/siopv2-oid4vp-rp-auth: dependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/did-auth-siop-adapter': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/oid4vc-common': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339 + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345 '@sphereon/pex': specifier: 5.0.0-unstable.28 version: 5.0.0-unstable.28 @@ -2517,8 +2517,8 @@ importers: packages/siopv2-oid4vp-rp-rest-api: dependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/ssi-express-support': specifier: workspace:* version: link:../ssi-express-support @@ -3267,6 +3267,9 @@ importers: '@sphereon/kmp-cbor': specifier: 0.2.0-SNAPSHOT.25 version: 0.2.0-SNAPSHOT.25 + '@sphereon/oid4vci-common': + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-sdk-ext.did-utils': specifier: 0.27.0 version: 0.27.0(encoding@0.1.13)(pg@8.13.1)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@20.17.9)(typescript@5.6.3)) @@ -3383,6 +3386,9 @@ importers: specifier: ^9.0.1 version: 9.0.1 devDependencies: + '@babel/preset-typescript': + specifier: ^7.24.7 + version: 7.26.0(@babel/core@7.26.0) '@sphereon/did-uni-client': specifier: ^0.6.3 version: 0.6.3(encoding@0.1.13) @@ -3467,6 +3473,9 @@ importers: morgan: specifier: ^1.10.0 version: 1.10.0 + ts-jest: + specifier: ^29.2.5 + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3) typescript: specifier: 5.6.3 version: 5.6.3 @@ -3729,8 +3738,8 @@ importers: packages/w3c-vc-api: dependencies: '@sphereon/did-auth-siop': - specifier: 0.16.1-next.339 - version: 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + specifier: 0.16.1-feature.IATAB2B.52.345 + version: 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/ssi-express-support': specifier: workspace:* version: link:../ssi-express-support @@ -4265,6 +4274,7 @@ packages: '@azure/msal-node@1.18.4': resolution: {integrity: sha512-Kc/dRvhZ9Q4+1FSfsTFDME/v6+R2Y1fuMty/TfwqE5p9GTPw08BPbKgeWinE8JRHRp+LemjQbUZsn4Q4l6Lszg==} engines: {node: 10 || 12 || 14 || 16 || 18} + deprecated: A newer major version of this library is available. Please upgrade to the latest available version. '@babel/cli@7.25.9': resolution: {integrity: sha512-I+02IfrTiSanpxJBlZQYb18qCxB6c2Ih371cVpfgIrPQrjAYkf45XxomTJOG8JBWX5GY35/+TmhCMdJ4ZPkL8Q==} @@ -4444,6 +4454,7 @@ packages: '@babel/plugin-proposal-export-namespace-from@7.18.9': resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead. peerDependencies: '@babel/core': ^7.0.0-0 @@ -5333,6 +5344,7 @@ packages: '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -5340,6 +5352,7 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead '@hutson/parse-repository-url@3.0.2': resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} @@ -5565,14 +5578,17 @@ packages: '@lto-network/lto-crypto@1.1.1': resolution: {integrity: sha512-YA6ATCP+RfWN/0Tvb6CZKs2meUAUAf3cvEVa5tpNNkJjhozxloAONxPP/9DxhUjkmiqWU6fy8xPD2eCYv3lvmQ==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. '@lto-network/lto-transactions@1.2.12': resolution: {integrity: sha512-bUCwN1xFMr8HFg+rdpxfj5vyCM/2aBSq8kyXyhFw2t8Ovl6BL4rI9zK+4UnOHl5e5z72UWsHgdT3taicxPQiug==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. peerDependencies: typescript: 5.6.3 '@lto-network/signature-generator@1.0.0': resolution: {integrity: sha512-NhfsINt8rBoY7F8xijB7fGcY7fzr5dkqLcw3EE9fvVBBhyoI11LxTX78UlokY5T2+X8NvpNpXSSek2yJqYJxHg==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. '@mapbox/node-pre-gyp@1.0.11': resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} @@ -5703,6 +5719,7 @@ packages: '@npmcli/move-file@1.1.2': resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} engines: {node: '>=10'} + deprecated: This functionality has been moved to @npmcli/fs '@npmcli/name-from-folder@2.0.0': resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==} @@ -6138,12 +6155,12 @@ packages: '@sinonjs/fake-timers@8.1.0': resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} - '@sphereon/did-auth-siop-adapter@0.16.1-next.339': - resolution: {integrity: sha512-HeBxuv4Q8b2p6act0TL/80F2tef5OpnBxcliakzdt/GsmPwBzwczW1ViFQiCdO76JMvmjza50RSzU6f0jFVY8Q==} + '@sphereon/did-auth-siop-adapter@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-fltPdXr4nsDERpLMphie3/FRrT0xnIkOAGaY1ExE0CsejdwPh4dOt1POkXQu5pbmj77XqJklgm28WtxMB4f0oQ==} engines: {node: '>=18'} - '@sphereon/did-auth-siop@0.16.1-next.339': - resolution: {integrity: sha512-1gfsJBjzwVQcjceXEjTgxU3OZPX0C9cikR3tlogOz4pD4Yy9TL4bz+tIEk0FJup2U09LfQw/MdTNFWjfbAvYJQ==} + '@sphereon/did-auth-siop@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-RfH7eAGQrOsmFVo64UzXd1jFw03XHmx77OuQlpmQXTaO70pPf22b9Qb/xl3sboJfblYHUv8qIwcNDZK53vtqOw==} engines: {node: '>=18'} '@sphereon/did-provider-oyd@0.27.0': @@ -6166,35 +6183,33 @@ packages: '@sphereon/react-native-argon2': ^2.0.9 react-native: '>=0.60.0' - '@sphereon/jarm@0.16.1-next.339': - resolution: {integrity: sha512-PQABG/rZpK1ypZqfHRV3HuxVDxclRJnD41A8fnr8EQB5JFKElSQ/SWEIWi7DD1HeWqzZnRiLWt1boPuWjgphOQ==} + '@sphereon/jarm@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-AKEiUV1gZgVBkWMgNLVd/Op1T6482mjsPEDSylXp/6UZzSv4pFwPSi9U1c44KUewZIW3Yq4Cck+VEi1ULdsq6A==} engines: {node: '>=18'} '@sphereon/kmp-cbor@0.2.0-SNAPSHOT.25': resolution: {integrity: sha512-EFuAtA4zaONe1/BGOntx9m1Oov6iVSMhbjhht6ST/6hFx+VMCs5iDTnl8qay3dleIOoDEluK8AnSiufi56+IJA==} - bundledDependencies: [] '@sphereon/kmp-mdoc-core@0.2.0-SNAPSHOT.26': resolution: {integrity: sha512-QXJ6R8ENiZV2rPMbn06cw5JKwqUYN1kzVRbYfONqE1PEXx1noQ4md7uxr2zSczi0ubKkNcbyYDNtIMTZIhGzmQ==} - bundledDependencies: [] '@sphereon/lto-did-ts@0.1.8-unstable.0': resolution: {integrity: sha512-3jzwwuYX/VYuze+T9/yg4PcsJ5iNNwAfTp4WfS4aSfPFBErDAfKXqn6kOb0wFYGkhejr3Jz+rljPC2iKZiHiGA==} - '@sphereon/oid4vc-common@0.16.1-next.339': - resolution: {integrity: sha512-Ttw49G8liVpR/qZTuBX9YVI8vYb3rbtWAUr8Ra5GRGQo8+xE22dT5gMK0BwTeg6CRik3zhYnW6L4LN/NRPuhIA==} + '@sphereon/oid4vc-common@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-FF2O8hmabGpTDSCFxWU9FiFFtFajGmLNmfi3RdZuFUyJH7NAHIPHgQK/62iDRgGKCeFo0p901r42eYdKff92jQ==} engines: {node: '>=18'} - '@sphereon/oid4vci-client@0.16.1-next.339': - resolution: {integrity: sha512-bPkiQGauf8LjkfI8LXVBw494Z8ttCT439420PlzWohm5aYytcEw7DL/Sn+5+ME+4aHzzb4khXAVqjpSlrySSDA==} + '@sphereon/oid4vci-client@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-MS/Ps9p/WIkLxbTzdLs47kW3LfsFzPj43vmv4dZuFFps/8kasBvIji2U6D0KK2tCa66JC4plKWKz/ZH3PRdiPA==} engines: {node: '>=18'} - '@sphereon/oid4vci-common@0.16.1-next.339': - resolution: {integrity: sha512-ZZGh6xxtmeiJy5+sic8F+YZkZucx1vuYQ4wqG0bhcu17zOkvyqvW5S54G2o1K8ZVYjPTuBkI402nuqAoMGgLGg==} + '@sphereon/oid4vci-common@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-0ayEWhWLkwlhrf7zVW60x4gLcNCjUQdUdWOdKha1o0WrLeCF279UDkcE3ELMUd3giTDa1CZM/dDcEI09dW1XKQ==} engines: {node: '>=18'} - '@sphereon/oid4vci-issuer-server@0.16.1-next.339': - resolution: {integrity: sha512-6Cbrs3PSPIY1tNTyCHYGLdQgLSu/ie38OIllyhrJLuCtCpxsdRR0AE0lQi06gJMpt6S90L1sKEPKbn2lLJF22Q==} + '@sphereon/oid4vci-issuer-server@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-P/9fi4iHS/jgJA4PdHOL59+9oq+Po2qaItq8EtsCso3nThATVO1ImSBDloRbRnWvoAto2pCLzdMamWnS6B6+KQ==} engines: {node: '>=18'} peerDependencies: awesome-qr: ^2.1.5-rc.0 @@ -6202,8 +6217,8 @@ packages: awesome-qr: optional: true - '@sphereon/oid4vci-issuer@0.16.1-next.339': - resolution: {integrity: sha512-1iGdjtle4KjzqEdYL7CLG7lijwPGebagkksan6C7FA5NlSUjnS8jUt9CElrHZY/pbznCVh+qfr/dBVbhl6uuUg==} + '@sphereon/oid4vci-issuer@0.16.1-feature.IATAB2B.52.345': + resolution: {integrity: sha512-FngmTLjUfb5CrR9lSVW25YYuaBWrWnyq38NiVheCrp6mX+sO8WvGB9FkPcFhBk6z7A7JnHfcdGNIxSe7e0HDQw==} engines: {node: '>=18'} peerDependencies: awesome-qr: ^2.1.5-rc.0 @@ -6769,6 +6784,7 @@ packages: '@types/nock@11.1.0': resolution: {integrity: sha512-jI/ewavBQ7X5178262JQR0ewicPAcJhXS/iFaNJl0VHLfyosZ/kwSrsa6VNQNSO8i9d8SqdRgOtZSOKJ/+iNMw==} + deprecated: This is a stub types definition. nock provides its own type definitions, so you do not need this installed. '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} @@ -7107,6 +7123,7 @@ packages: abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -7282,10 +7299,12 @@ packages: are-we-there-yet@2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} + deprecated: This package is no longer supported. are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -7596,6 +7615,7 @@ packages: bitcoin-ts@1.15.2: resolution: {integrity: sha512-N5cjC+PjAuTvU3mMcO9aZI5w6lseHickKh6tX6n5p89i2rrUbhgq0KHeOOCYNIbnFcemjGea8uuSXMFBRDl7NQ==} engines: {node: '>=8.9'} + deprecated: The 'bitcoin-ts' package has been renamed to '@bitauth/libauth', and the 'bitcoin-ts' package is no longer maintained. Please switch to '@bitauth/libauth'. bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -7620,6 +7640,7 @@ packages: boolean@3.2.0: resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. borc@2.1.2: resolution: {integrity: sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==} @@ -8478,10 +8499,12 @@ packages: domexception@2.0.1: resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} engines: {node: '>=8'} + deprecated: Use your platform's native DOMException instead domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} @@ -8761,6 +8784,7 @@ packages: eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: @@ -9214,10 +9238,12 @@ packages: gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} engines: {node: '>=10'} + deprecated: This package is no longer supported. gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. genson-js@0.0.5: resolution: {integrity: sha512-1i1y9MIGzTRkn4TusWQwLWLu8IJGHgSE+fbQRt1fy68ZKEq2GjDZI/7NUSZFOfTbHz8bgjP4iCIOcdYrgEsMBA==} @@ -9321,13 +9347,16 @@ packages: glob@6.0.4: resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} + deprecated: Glob versions prior to v9 are no longer supported glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} @@ -9587,6 +9616,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -10627,6 +10657,7 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -10636,6 +10667,7 @@ packages: lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. lodash.isinteger@4.0.4: resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} @@ -11053,9 +11085,11 @@ packages: multibase@4.0.6: resolution: {integrity: sha512-x23pDe5+svdLz/k5JPGCVdfn7Q5mZVMBETiC+ORfO+sor9Sgs0smJzAjfTbM5tckeCqnaUuMYoz+k3RXMmJClQ==} engines: {node: '>=12.0.0', npm: '>=6.0.0'} + deprecated: This module has been superseded by the multiformats module multicodec@3.2.1: resolution: {integrity: sha512-+expTPftro8VAW8kfvcuNNNBgb9gPeNYV9dn+z1kJRWF2vih+/S79f2RVeIwmrJBUJ6NT9IUPWnZDQvegEh5pw==} + deprecated: This module has been superseded by the multiformats module multiformats@12.1.3: resolution: {integrity: sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==} @@ -11370,10 +11404,12 @@ packages: npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + deprecated: This package is no longer supported. npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. nullthrows@1.1.1: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} @@ -11669,6 +11705,7 @@ packages: passport-azure-ad@4.3.5: resolution: {integrity: sha512-LBpXEght7hCMuMNFK4oegdN0uPBa3lpDMy71zQoB0zPg1RrGwdzpjwTiN1WzN0hY77fLyjz9tBr3TGAxnSgtEg==} engines: {node: '>= 8.0.0'} + deprecated: This package is deprecated and no longer supported. For more please visit https://github.com/AzureAD/passport-azure-ad?tab=readme-ov-file#node-js-validation-replacement-for-passportjs passport-http-bearer@1.0.1: resolution: {integrity: sha512-SELQM+dOTuMigr9yu8Wo4Fm3ciFfkMq5h/ZQ8ffi4ELgZrX1xh9PlglqZdcUZ1upzJD/whVyt+YWF62s3U6Ipw==} @@ -11987,6 +12024,10 @@ packages: q@1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + deprecated: |- + You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) qr.js@0.0.0: resolution: {integrity: sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==} @@ -12284,6 +12325,7 @@ packages: rimraf@2.4.5: resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@2.6.3: @@ -12293,10 +12335,12 @@ packages: rimraf@2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@4.4.1: @@ -13447,6 +13491,7 @@ packages: w3c-hr-time@1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} + deprecated: Use your platform's native performance.now() and performance.timeOrigin. w3c-xmlserializer@2.0.0: resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==} @@ -17114,11 +17159,11 @@ snapshots: dependencies: '@sinonjs/commons': 1.8.6 - '@sphereon/did-auth-siop-adapter@0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3)': + '@sphereon/did-auth-siop-adapter@0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3)': dependencies: - '@sphereon/did-auth-siop': 0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3) + '@sphereon/did-auth-siop': 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3) '@sphereon/did-uni-client': 0.6.3(encoding@0.1.13) - '@sphereon/oid4vc-common': 0.16.1-next.339 + '@sphereon/oid4vc-common': 0.16.1-feature.IATAB2B.52.345 '@sphereon/wellknown-dids-client': 0.1.3(encoding@0.1.13) did-jwt: 6.11.6(patch_hash=afqywxnnjnsy6hwgax66dyyiey) did-resolver: 4.1.0 @@ -17127,11 +17172,11 @@ snapshots: - supports-color - typescript - '@sphereon/did-auth-siop@0.16.1-next.339(encoding@0.1.13)(typescript@5.6.3)': + '@sphereon/did-auth-siop@0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)(typescript@5.6.3)': dependencies: '@astronautlabs/jsonpath': 1.1.2 - '@sphereon/jarm': 0.16.1-next.339(typescript@5.6.3) - '@sphereon/oid4vc-common': 0.16.1-next.339 + '@sphereon/jarm': 0.16.1-feature.IATAB2B.52.345(typescript@5.6.3) + '@sphereon/oid4vc-common': 0.16.1-feature.IATAB2B.52.345 '@sphereon/pex': 5.0.0-unstable.28 '@sphereon/pex-models': 2.3.2 '@sphereon/ssi-types': link:packages/ssi-types @@ -17193,9 +17238,9 @@ snapshots: react-native: 0.76.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1) uint8arrays: 3.1.1 - '@sphereon/jarm@0.16.1-next.339(typescript@5.6.3)': + '@sphereon/jarm@0.16.1-feature.IATAB2B.52.345(typescript@5.6.3)': dependencies: - '@sphereon/oid4vc-common': 0.16.1-next.339 + '@sphereon/oid4vc-common': 0.16.1-feature.IATAB2B.52.345 valibot: 0.42.1(typescript@5.6.3) transitivePeerDependencies: - typescript @@ -17225,7 +17270,7 @@ snapshots: - encoding - typescript - '@sphereon/oid4vc-common@0.16.1-next.339': + '@sphereon/oid4vc-common@0.16.1-feature.IATAB2B.52.345': dependencies: '@sphereon/ssi-types': link:packages/ssi-types jwt-decode: 4.0.0 @@ -17233,10 +17278,10 @@ snapshots: uint8arrays: 3.1.1 uuid: 9.0.1 - '@sphereon/oid4vci-client@0.16.1-next.339(encoding@0.1.13)': + '@sphereon/oid4vci-client@0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)': dependencies: - '@sphereon/oid4vc-common': 0.16.1-next.339 - '@sphereon/oid4vci-common': 0.16.1-next.339(encoding@0.1.13) + '@sphereon/oid4vc-common': 0.16.1-feature.IATAB2B.52.345 + '@sphereon/oid4vci-common': 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-types': link:packages/ssi-types cross-fetch: 3.1.8(encoding@0.1.13) debug: 4.3.7 @@ -17244,9 +17289,9 @@ snapshots: - encoding - supports-color - '@sphereon/oid4vci-common@0.16.1-next.339(encoding@0.1.13)': + '@sphereon/oid4vci-common@0.16.1-feature.IATAB2B.52.345(encoding@0.1.13)': dependencies: - '@sphereon/oid4vc-common': 0.16.1-next.339 + '@sphereon/oid4vc-common': 0.16.1-feature.IATAB2B.52.345 '@sphereon/ssi-types': link:packages/ssi-types cross-fetch: 3.1.8(encoding@0.1.13) debug: 4.3.7 @@ -17257,11 +17302,11 @@ snapshots: - encoding - supports-color - '@sphereon/oid4vci-issuer-server@0.16.1-next.339(@noble/hashes@1.6.1)(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13)(passport-azure-ad@4.3.5)(passport-http-bearer@1.0.1)': + '@sphereon/oid4vci-issuer-server@0.16.1-feature.IATAB2B.52.345(@noble/hashes@1.6.1)(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13)(passport-azure-ad@4.3.5)(passport-http-bearer@1.0.1)': dependencies: - '@sphereon/oid4vc-common': 0.16.1-next.339 - '@sphereon/oid4vci-common': 0.16.1-next.339(encoding@0.1.13) - '@sphereon/oid4vci-issuer': 0.16.1-next.339(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13) + '@sphereon/oid4vc-common': 0.16.1-feature.IATAB2B.52.345 + '@sphereon/oid4vci-common': 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) + '@sphereon/oid4vci-issuer': 0.16.1-feature.IATAB2B.52.345(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13) '@sphereon/ssi-express-support': 0.30.2-feature.mdoc.funke2.367(@noble/hashes@1.6.1)(passport-azure-ad@4.3.5)(passport-http-bearer@1.0.1) '@sphereon/ssi-types': link:packages/ssi-types body-parser: 1.20.3 @@ -17280,10 +17325,10 @@ snapshots: - passport-http-bearer - supports-color - '@sphereon/oid4vci-issuer@0.16.1-next.339(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13)': + '@sphereon/oid4vci-issuer@0.16.1-feature.IATAB2B.52.345(awesome-qr@2.1.5-rc.0(encoding@0.1.13))(encoding@0.1.13)': dependencies: - '@sphereon/oid4vc-common': 0.16.1-next.339 - '@sphereon/oid4vci-common': 0.16.1-next.339(encoding@0.1.13) + '@sphereon/oid4vc-common': 0.16.1-feature.IATAB2B.52.345 + '@sphereon/oid4vci-common': 0.16.1-feature.IATAB2B.52.345(encoding@0.1.13) '@sphereon/ssi-types': link:packages/ssi-types uuid: 9.0.1 optionalDependencies: