@sphereon/ssi-sdk.vc-status-list 0.34.1-next.3 → 0.34.1-next.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,26 +1,30 @@
1
- import type { IAgentContext, ICredentialPlugin, IKeyManager } from '@veramo/core'
2
- import { type CompactJWT, type CWT, type CredentialProofFormat, StatusListType } from '@sphereon/ssi-types'
1
+ import type { IAgentContext, IKeyManager } from '@veramo/core'
2
+ import { type CompactJWT, type CredentialProofFormat, type CWT, StatusListType } from '@sphereon/ssi-types'
3
3
  import type {
4
4
  CheckStatusIndexArgs,
5
5
  CreateStatusListArgs,
6
+ IMergeDetailsWithEntityArgs,
7
+ IToDetailsFromCredentialArgs,
6
8
  SignedStatusListData,
9
+ StatusListOAuthEntryCredentialStatus,
7
10
  StatusListResult,
8
11
  StatusOAuth,
9
- ToStatusListDetailsArgs,
10
12
  UpdateStatusListFromEncodedListArgs,
11
13
  UpdateStatusListIndexArgs,
12
14
  } from '../types'
13
- import { determineProofFormat, getAssertedValue, getAssertedValues } from '../utils'
14
- import type { IStatusList } from './IStatusList'
15
+ import { determineProofFormat, ensureDate, getAssertedValue, getAssertedValues } from '../utils'
16
+ import type { IExtractedCredentialDetails, IOAuthStatusListImplementationResult, IStatusList } from './IStatusList'
15
17
  import { StatusList } from '@sd-jwt/jwt-status-list'
16
18
  import type { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
17
19
  import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
18
20
  import { createSignedJwt, decodeStatusListJWT } from './encoding/jwt'
19
21
  import { createSignedCbor, decodeStatusListCWT } from './encoding/cbor'
22
+ import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, OAuthStatusListEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
23
+ import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
20
24
 
21
- type IRequiredContext = IAgentContext<ICredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>
25
+ type IRequiredContext = IAgentContext<IVcdmCredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>
22
26
 
23
- export const DEFAULT_BITS_PER_STATUS = 1 // 1 bit is sufficient for 0x00 - "VALID" 0x01 - "INVALID" saving space in the process
27
+ export const DEFAULT_BITS_PER_STATUS = 1 // 1 bit is sufficient for 0x00 - "VALID" 0x01 - "INVALID" saving space in the process
24
28
  export const DEFAULT_LIST_LENGTH = 250000
25
29
  export const DEFAULT_PROOF_FORMAT = 'jwt' as CredentialProofFormat
26
30
 
@@ -32,7 +36,8 @@ export class OAuthStatusListImplementation implements IStatusList {
32
36
 
33
37
  const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
34
38
  const { issuer, id, oauthStatusList, keyRef } = args
35
- const { bitsPerStatus, expiresAt } = oauthStatusList
39
+ const { bitsPerStatus } = oauthStatusList
40
+ const expiresAt = ensureDate(oauthStatusList.expiresAt)
36
41
  const length = args.length ?? DEFAULT_LIST_LENGTH
37
42
  const issuerString = typeof issuer === 'string' ? issuer : issuer.id
38
43
  const correlationId = getAssertedValue('correlationId', args.correlationId)
@@ -56,7 +61,8 @@ export class OAuthStatusListImplementation implements IStatusList {
56
61
  }
57
62
 
58
63
  async updateStatusListIndex(args: UpdateStatusListIndexArgs, context: IRequiredContext): Promise<StatusListResult> {
59
- const { statusListCredential, value, expiresAt, keyRef } = args
64
+ const { statusListCredential, value, keyRef } = args
65
+ const expiresAt = ensureDate(args.expiresAt)
60
66
  if (typeof statusListCredential !== 'string') {
61
67
  return Promise.reject('statusListCredential in neither JWT nor CWT')
62
68
  }
@@ -70,6 +76,10 @@ export class OAuthStatusListImplementation implements IStatusList {
70
76
  throw new Error('Status list index out of bounds')
71
77
  }
72
78
 
79
+ if (typeof value !== 'number') {
80
+ throw new Error('Status list values should be of type number')
81
+ }
82
+
73
83
  statusList.setStatus(index, value)
74
84
  const { statusListCredential: signedCredential, encodedList } = await this.createSignedStatusList(
75
85
  proofFormat,
@@ -102,15 +112,15 @@ export class OAuthStatusListImplementation implements IStatusList {
102
112
  throw new Error('OAuthStatusList options are required for type OAuthStatusList')
103
113
  }
104
114
  const { proofFormat, oauthStatusList, keyRef } = args
105
- const { bitsPerStatus, expiresAt } = oauthStatusList
115
+ const { bitsPerStatus } = oauthStatusList
116
+ const expiresAt = ensureDate(oauthStatusList.expiresAt)
106
117
 
107
118
  const { issuer, id } = getAssertedValues(args)
108
119
  const issuerString = typeof issuer === 'string' ? issuer : issuer.id
109
120
 
110
121
  const listToUpdate = StatusList.decompressStatusList(args.encodedList, bitsPerStatus ?? DEFAULT_BITS_PER_STATUS)
111
122
  const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
112
- // FIXME: See above.
113
- listToUpdate.setStatus(index, args.value ? 1 : 0)
123
+ listToUpdate.setStatus(index, args.value)
114
124
 
115
125
  const { statusListCredential, encodedList } = await this.createSignedStatusList(
116
126
  proofFormat ?? DEFAULT_PROOF_FORMAT,
@@ -138,10 +148,6 @@ export class OAuthStatusListImplementation implements IStatusList {
138
148
  }
139
149
  }
140
150
 
141
- private buildContentType(proofFormat: 'jwt' | 'lds' | 'EthereumEip712Signature2021' | 'cbor' | undefined) {
142
- return `application/statuslist+${proofFormat === 'cbor' ? 'cwt' : 'jwt'}`
143
- }
144
-
145
151
  async checkStatusIndex(args: CheckStatusIndexArgs): Promise<number | StatusOAuth> {
146
152
  const { statusListCredential, statusListIndex } = args
147
153
  if (typeof statusListCredential !== 'string') {
@@ -153,39 +159,128 @@ export class OAuthStatusListImplementation implements IStatusList {
153
159
 
154
160
  const index = typeof statusListIndex === 'number' ? statusListIndex : parseInt(statusListIndex)
155
161
  if (index < 0 || index >= statusList.statusList.length) {
156
- throw new Error('Status list index out of bounds')
162
+ throw new Error(`Status list index out of bounds, has ${statusList.statusList.length} items, requested ${index}`)
157
163
  }
158
164
 
159
165
  return statusList.getStatus(index)
160
166
  }
161
167
 
162
- async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult> {
163
- const { statusListPayload } = args as { statusListPayload: CompactJWT | CWT }
164
- const proofFormat = determineProofFormat(statusListPayload)
165
- const decoded = proofFormat === 'jwt' ? decodeStatusListJWT(statusListPayload) : decodeStatusListCWT(statusListPayload)
166
- const { statusList, issuer, id, exp } = decoded
168
+ /**
169
+ * Performs the initial parsing of a StatusListCredential.
170
+ * This method handles expensive operations like JWT/CWT decoding once.
171
+ * It extracts all details available from the credential payload itself.
172
+ */
173
+ async extractCredentialDetails(credential: CompactJWT | CWT): Promise<IExtractedCredentialDetails> {
174
+ if (typeof credential !== 'string') {
175
+ return Promise.reject('statusListCredential must be a JWT or CWT string')
176
+ }
177
+
178
+ const proofFormat = determineProofFormat(credential)
179
+ const decoded = proofFormat === 'jwt' ? decodeStatusListJWT(credential) : decodeStatusListCWT(credential)
167
180
 
168
181
  return {
169
- id,
170
- encodedList: statusList.compressStatusList(),
171
- issuer,
172
- type: StatusListType.OAuthStatusList,
173
- proofFormat,
174
- length: statusList.statusList.length,
175
- statusListCredential: statusListPayload,
176
- statuslistContentType: this.buildContentType(proofFormat),
177
- oauthStatusList: {
178
- bitsPerStatus: statusList.getBitsPerStatus(),
179
- ...(exp && { expiresAt: new Date(exp * 1000) }),
180
- },
181
- ...(args.correlationId && { correlationId: args.correlationId }),
182
- ...(args.driverType && { driverType: args.driverType }),
182
+ id: decoded.id,
183
+ issuer: decoded.issuer,
184
+ encodedList: decoded.statusList.compressStatusList(),
185
+ decodedPayload: decoded,
183
186
  }
184
187
  }
185
188
 
189
+ // For CREATE and READ contexts
190
+ async toStatusListDetails(args: IToDetailsFromCredentialArgs): Promise<StatusListResult & IOAuthStatusListImplementationResult>
191
+ // For UPDATE contexts
192
+ async toStatusListDetails(args: IMergeDetailsWithEntityArgs): Promise<StatusListResult & IOAuthStatusListImplementationResult>
193
+ async toStatusListDetails(
194
+ args: IToDetailsFromCredentialArgs | IMergeDetailsWithEntityArgs,
195
+ ): Promise<StatusListResult & IOAuthStatusListImplementationResult> {
196
+ if ('statusListCredential' in args) {
197
+ // CREATE/READ context
198
+ const { statusListCredential, bitsPerStatus, correlationId, driverType } = args
199
+ if (!bitsPerStatus || bitsPerStatus < 1) {
200
+ return Promise.reject(Error('bitsPerStatus must be set for OAuth status lists and must be 1 or higher'))
201
+ }
202
+
203
+ const proofFormat = determineProofFormat(statusListCredential as string)
204
+ const decoded =
205
+ proofFormat === 'jwt' ? decodeStatusListJWT(statusListCredential as string) : decodeStatusListCWT(statusListCredential as string)
206
+ const { statusList, issuer, id, exp } = decoded
207
+ const expiresAt = exp ? new Date(exp * 1000) : undefined
208
+
209
+ return {
210
+ id,
211
+ encodedList: statusList.compressStatusList(),
212
+ issuer,
213
+ type: StatusListType.OAuthStatusList,
214
+ proofFormat,
215
+ length: statusList.statusList.length,
216
+ statusListCredential: statusListCredential as CompactJWT | CWT,
217
+ statuslistContentType: this.buildContentType(proofFormat),
218
+ correlationId,
219
+ driverType,
220
+ bitsPerStatus,
221
+ ...(expiresAt && { expiresAt }),
222
+ oauthStatusList: {
223
+ bitsPerStatus,
224
+ ...(expiresAt && { expiresAt }),
225
+ },
226
+ }
227
+ } else {
228
+ // UPDATE context
229
+ const { extractedDetails, statusListEntity } = args
230
+ const oauthEntity = statusListEntity as OAuthStatusListEntity
231
+ const decoded = extractedDetails.decodedPayload as { statusList: StatusList; exp?: number }
232
+
233
+ const proofFormat = determineProofFormat(statusListEntity.statusListCredential as string)
234
+ const expiresAt = decoded.exp ? new Date(decoded.exp * 1000) : undefined
235
+
236
+ return {
237
+ id: extractedDetails.id,
238
+ encodedList: extractedDetails.encodedList,
239
+ issuer: extractedDetails.issuer,
240
+ type: StatusListType.OAuthStatusList,
241
+ proofFormat,
242
+ length: decoded.statusList.statusList.length,
243
+ statusListCredential: statusListEntity.statusListCredential!,
244
+ statuslistContentType: this.buildContentType(proofFormat),
245
+ correlationId: statusListEntity.correlationId,
246
+ driverType: statusListEntity.driverType,
247
+ bitsPerStatus: oauthEntity.bitsPerStatus,
248
+ ...(expiresAt && { expiresAt }),
249
+ oauthStatusList: {
250
+ bitsPerStatus: oauthEntity.bitsPerStatus,
251
+ ...(expiresAt && { expiresAt }),
252
+ },
253
+ }
254
+ }
255
+ }
256
+
257
+ async createCredentialStatus(args: {
258
+ statusList: StatusListEntity
259
+ statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
260
+ statusListIndex: number
261
+ }): Promise<StatusListOAuthEntryCredentialStatus> {
262
+ const { statusList, statusListIndex } = args
263
+
264
+ // Cast to OAuthStatusListEntity to access specific properties
265
+ const oauthStatusList = statusList as OAuthStatusListEntity
266
+
267
+ return {
268
+ id: `${statusList.id}#${statusListIndex}`,
269
+ type: 'OAuthStatusListEntry',
270
+ bitsPerStatus: oauthStatusList.bitsPerStatus,
271
+ statusListIndex: '' + statusListIndex,
272
+ statusListCredential: statusList.id,
273
+ expiresAt: oauthStatusList.expiresAt,
274
+ }
275
+ }
276
+
277
+ private buildContentType(proofFormat: CredentialProofFormat | undefined) {
278
+ return `application/statuslist+${proofFormat === 'cbor' ? 'cwt' : 'jwt'}`
279
+ }
280
+
186
281
  private async createSignedStatusList(
187
- proofFormat: 'jwt' | 'lds' | 'EthereumEip712Signature2021' | 'cbor',
188
- context: IAgentContext<ICredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>,
282
+ proofFormat: CredentialProofFormat,
283
+ context: IAgentContext<IVcdmCredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>,
189
284
  statusList: StatusList,
190
285
  issuerString: string,
191
286
  id: string,
@@ -1,35 +1,37 @@
1
- import type { IAgentContext, ICredentialPlugin, ProofFormat as VeramoProofFormat } from '@veramo/core'
1
+ import type { IAgentContext, ProofFormat as VeramoProofFormat } from '@veramo/core'
2
2
  import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
3
3
  import {
4
4
  CredentialMapper,
5
+ type CredentialProofFormat,
5
6
  DocumentFormat,
6
7
  type IIssuer,
7
- type CredentialProofFormat,
8
8
  type StatusListCredential,
9
9
  StatusListType,
10
10
  } from '@sphereon/ssi-types'
11
11
 
12
12
  import { StatusList } from '@sphereon/vc-status-list'
13
- import type { IStatusList } from './IStatusList'
13
+ import type { IExtractedCredentialDetails, IStatusList, IStatusList2021ImplementationResult } from './IStatusList'
14
14
  import type {
15
15
  CheckStatusIndexArgs,
16
16
  CreateStatusListArgs,
17
+ IMergeDetailsWithEntityArgs,
18
+ IToDetailsFromCredentialArgs,
17
19
  StatusListResult,
18
- ToStatusListDetailsArgs,
19
20
  UpdateStatusListFromEncodedListArgs,
20
21
  UpdateStatusListIndexArgs,
21
22
  } from '../types'
22
-
23
- import { Status2021 } from '../types'
23
+ import { Status2021, StatusList2021EntryCredentialStatus } from '../types'
24
24
  import { assertValidProofType, getAssertedProperty, getAssertedValue, getAssertedValues } from '../utils'
25
+ import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusList2021Entity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
26
+ import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
25
27
 
26
28
  export const DEFAULT_LIST_LENGTH = 250000
27
- export const DEFAULT_PROOF_FORMAT = 'lds' as VeramoProofFormat
29
+ export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
28
30
 
29
31
  export class StatusList2021Implementation implements IStatusList {
30
32
  async createNewStatusList(
31
33
  args: CreateStatusListArgs,
32
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
34
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
33
35
  ): Promise<StatusListResult> {
34
36
  const length = args?.length ?? DEFAULT_LIST_LENGTH
35
37
  const proofFormat: CredentialProofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
@@ -71,7 +73,7 @@ export class StatusList2021Implementation implements IStatusList {
71
73
 
72
74
  async updateStatusListIndex(
73
75
  args: UpdateStatusListIndexArgs,
74
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
76
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
75
77
  ): Promise<StatusListResult> {
76
78
  const credential = args.statusListCredential
77
79
  const uniform = CredentialMapper.toUniformCredential(credential)
@@ -96,11 +98,15 @@ export class StatusList2021Implementation implements IStatusList {
96
98
  context,
97
99
  )
98
100
 
101
+ if (!('statusPurpose' in credentialSubject)) {
102
+ return Promise.reject(Error('statusPurpose is required in credentialSubject for StatusList2021'))
103
+ }
104
+
99
105
  return {
100
106
  statusListCredential: updatedCredential,
101
107
  encodedList,
102
108
  statusList2021: {
103
- ...('statusPurpose' in credentialSubject ? { statusPurpose: credentialSubject.statusPurpose } : {}),
109
+ statusPurpose: credentialSubject.statusPurpose,
104
110
  indexingDirection: 'rightToLeft',
105
111
  },
106
112
  length: statusList.length - 1,
@@ -114,7 +120,7 @@ export class StatusList2021Implementation implements IStatusList {
114
120
 
115
121
  async updateStatusListFromEncodedList(
116
122
  args: UpdateStatusListFromEncodedListArgs,
117
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
123
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
118
124
  ): Promise<StatusListResult> {
119
125
  if (!args.statusList2021) {
120
126
  throw new Error('statusList2021 options required for type StatusList2021')
@@ -126,7 +132,7 @@ export class StatusList2021Implementation implements IStatusList {
126
132
  const { issuer, id } = getAssertedValues(args)
127
133
  const statusList = await StatusList.decode({ encodedList: args.encodedList })
128
134
  const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
129
- statusList.setStatus(index, args.value)
135
+ statusList.setStatus(index, args.value !== 0)
130
136
 
131
137
  const newEncodedList = await statusList.encode()
132
138
  const credential = await this.createVerifiableCredential(
@@ -166,32 +172,106 @@ export class StatusList2021Implementation implements IStatusList {
166
172
  return status ? Status2021.Invalid : Status2021.Valid
167
173
  }
168
174
 
169
- async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult> {
170
- const { statusListPayload } = args
171
- const uniform = CredentialMapper.toUniformCredential(statusListPayload)
175
+ /**
176
+ * Performs the initial parsing of a StatusListCredential.
177
+ * This method handles expensive operations like JWT/CWT decoding once.
178
+ * It extracts all details available from the credential payload itself.
179
+ */
180
+ async extractCredentialDetails(credential: StatusListCredential): Promise<IExtractedCredentialDetails> {
181
+ const uniform = CredentialMapper.toUniformCredential(credential)
172
182
  const { issuer, credentialSubject } = uniform
173
- const id = getAssertedValue('id', uniform.id)
174
- const encodedList = getAssertedProperty('encodedList', credentialSubject)
175
- const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListPayload) === DocumentFormat.JWT ? 'jwt' : 'lds'
176
-
177
- const statusPurpose = getAssertedProperty('statusPurpose', credentialSubject)
178
- const list = await StatusList.decode({ encodedList })
183
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
179
184
 
180
185
  return {
181
- id,
182
- encodedList,
186
+ id: getAssertedValue('id', uniform.id),
183
187
  issuer,
184
- type: StatusListType.StatusList2021,
185
- proofFormat,
186
- length: list.length,
187
- statusListCredential: statusListPayload,
188
- statuslistContentType: this.buildContentType(proofFormat),
189
- statusList2021: {
188
+ encodedList: getAssertedProperty('encodedList', subject),
189
+ }
190
+ }
191
+
192
+ async toStatusListDetails(args: IToDetailsFromCredentialArgs): Promise<StatusListResult & IStatusList2021ImplementationResult>
193
+ // For UPDATE contexts
194
+ async toStatusListDetails(args: IMergeDetailsWithEntityArgs): Promise<StatusListResult & IStatusList2021ImplementationResult>
195
+ async toStatusListDetails(
196
+ args: IToDetailsFromCredentialArgs | IMergeDetailsWithEntityArgs,
197
+ ): Promise<StatusListResult & IStatusList2021ImplementationResult> {
198
+ if ('statusListCredential' in args) {
199
+ // CREATE/READ context
200
+ const { statusListCredential, correlationId, driverType } = args
201
+ const uniform = CredentialMapper.toUniformCredential(statusListCredential)
202
+ const { issuer, credentialSubject } = uniform
203
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
204
+
205
+ const id = getAssertedValue('id', uniform.id)
206
+ const encodedList = getAssertedProperty('encodedList', subject)
207
+ const statusPurpose = getAssertedProperty('statusPurpose', subject)
208
+ const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListCredential) === DocumentFormat.JWT ? 'jwt' : 'lds'
209
+ const list = await StatusList.decode({ encodedList })
210
+
211
+ return {
212
+ id,
213
+ encodedList,
214
+ issuer,
215
+ type: StatusListType.StatusList2021,
216
+ proofFormat,
217
+ length: list.length,
218
+ statusListCredential,
219
+ statuslistContentType: this.buildContentType(proofFormat),
220
+ correlationId,
221
+ driverType,
190
222
  indexingDirection: 'rightToLeft',
191
223
  statusPurpose,
192
- },
193
- ...(args.correlationId && { correlationId: args.correlationId }),
194
- ...(args.driverType && { driverType: args.driverType }),
224
+ statusList2021: {
225
+ indexingDirection: 'rightToLeft',
226
+ statusPurpose,
227
+ },
228
+ }
229
+ } else {
230
+ // UPDATE context
231
+ const { extractedDetails, statusListEntity } = args
232
+ const statusList2021Entity = statusListEntity as StatusList2021Entity
233
+
234
+ const proofFormat: CredentialProofFormat =
235
+ CredentialMapper.detectDocumentType(statusListEntity.statusListCredential!) === DocumentFormat.JWT ? 'jwt' : 'lds'
236
+ const list = await StatusList.decode({ encodedList: extractedDetails.encodedList })
237
+
238
+ return {
239
+ id: extractedDetails.id,
240
+ encodedList: extractedDetails.encodedList,
241
+ issuer: extractedDetails.issuer,
242
+ type: StatusListType.StatusList2021,
243
+ proofFormat,
244
+ length: list.length,
245
+ statusListCredential: statusListEntity.statusListCredential!,
246
+ statuslistContentType: this.buildContentType(proofFormat),
247
+ correlationId: statusListEntity.correlationId,
248
+ driverType: statusListEntity.driverType,
249
+ indexingDirection: statusList2021Entity.indexingDirection,
250
+ statusPurpose: statusList2021Entity.statusPurpose,
251
+ statusList2021: {
252
+ indexingDirection: statusList2021Entity.indexingDirection,
253
+ statusPurpose: statusList2021Entity.statusPurpose,
254
+ },
255
+ }
256
+ }
257
+ }
258
+
259
+ async createCredentialStatus(args: {
260
+ statusList: StatusListEntity
261
+ statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
262
+ statusListIndex: number
263
+ }): Promise<StatusList2021EntryCredentialStatus> {
264
+ const { statusList, statusListIndex } = args
265
+
266
+ // Cast to StatusList2021Entity to access specific properties
267
+ const statusList2021 = statusList as StatusList2021Entity
268
+
269
+ return {
270
+ id: `${statusList.id}#${statusListIndex}`,
271
+ type: 'StatusList2021Entry',
272
+ statusPurpose: statusList2021.statusPurpose ?? 'revocation',
273
+ statusListIndex: '' + statusListIndex,
274
+ statusListCredential: statusList.id,
195
275
  }
196
276
  }
197
277
 
@@ -203,7 +283,7 @@ export class StatusList2021Implementation implements IStatusList {
203
283
  proofFormat: VeramoProofFormat
204
284
  keyRef?: string
205
285
  },
206
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
286
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
207
287
  ): Promise<StatusListCredential> {
208
288
  const identifier = await context.agent.identifierManagedGet({
209
289
  identifier: typeof args.issuer === 'string' ? args.issuer : args.issuer.id,
@@ -234,7 +314,7 @@ export class StatusList2021Implementation implements IStatusList {
234
314
  return CredentialMapper.toWrappedVerifiableCredential(verifiableCredential as StatusListCredential).original as StatusListCredential
235
315
  }
236
316
 
237
- private buildContentType(proofFormat: 'jwt' | 'lds' | 'EthereumEip712Signature2021' | 'cbor' | undefined) {
317
+ private buildContentType(proofFormat: CredentialProofFormat | undefined) {
238
318
  switch (proofFormat) {
239
319
  case 'jwt':
240
320
  return `application/statuslist+jwt`
@@ -2,6 +2,7 @@ import type { IStatusList } from './IStatusList'
2
2
  import { StatusList2021Implementation } from './StatusList2021'
3
3
  import { OAuthStatusListImplementation } from './OAuthStatusList'
4
4
  import { StatusListType } from '@sphereon/ssi-types'
5
+ import { BitstringStatusListImplementation } from './BitstringStatusListImplementation'
5
6
 
6
7
  export class StatusListFactory {
7
8
  private static instance: StatusListFactory
@@ -11,6 +12,7 @@ export class StatusListFactory {
11
12
  this.implementations = new Map()
12
13
  this.implementations.set(StatusListType.StatusList2021, new StatusList2021Implementation())
13
14
  this.implementations.set(StatusListType.OAuthStatusList, new OAuthStatusListImplementation())
15
+ this.implementations.set(StatusListType.BitstringStatusList, new BitstringStatusListImplementation())
14
16
  }
15
17
 
16
18
  public static getInstance(): StatusListFactory {
package/src/index.ts CHANGED
@@ -3,3 +3,4 @@
3
3
 
4
4
  export * from './types'
5
5
  export * from './functions'
6
+ export { determineStatusListType } from './utils'
@@ -0,0 +1,4 @@
1
+ import { StatusListCredential } from '@sphereon/ssi-types'
2
+ import { BitstringStatusListCredentialUnsigned } from '../../../../../vc-bitstring-status-lists'
3
+
4
+ export type BitstringStatusListCredential = BitstringStatusListCredentialUnsigned & StatusListCredential