@sphereon/ssi-sdk.vc-status-list 0.34.1-feature.SSISDK.17.bitstring.sl.11 → 0.34.1-feature.SSISDK.17.bitstring.sl.14

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,4 +1,22 @@
1
- import type { IAgentContext, ICredentialPlugin, ProofFormat as VeramoProofFormat } from '@veramo/core'
1
+ /**
2
+ * Bitstring Status List Implementation
3
+ *
4
+ * This module implements the W3C Bitstring Status List specification for managing
5
+ * credential status information. It provides functionality to create, update, and
6
+ * check the status of verifiable credentials using compressed bitstring status lists.
7
+ *
8
+ * Key features:
9
+ * - Create new bitstring status lists with configurable purposes and bit sizes
10
+ * - Update individual credential status entries in existing lists
11
+ * - Check the status of specific credentials by index
12
+ * - Support for multiple proof formats (JWT, LDS, CBOR)
13
+ * - Integration with Veramo agent context for credential signing
14
+ *
15
+ * @author Sphereon International B.V.
16
+ * @since 2024
17
+ */
18
+
19
+ import type { IAgentContext } from '@veramo/core'
2
20
  import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
3
21
 
4
22
  import {
@@ -10,31 +28,56 @@ import {
10
28
  StatusListType,
11
29
  } from '@sphereon/ssi-types'
12
30
 
13
- import type { IBitstringStatusListImplementationResult, IStatusList } from './IStatusList'
31
+ import type { IBitstringStatusListImplementationResult, IExtractedCredentialDetails, IStatusList } from './IStatusList'
14
32
  import {
15
- BitstringStatus,
16
- BitstringStatusListEntryCredentialStatus,
17
33
  CheckStatusIndexArgs,
18
34
  CreateStatusListArgs,
35
+ IMergeDetailsWithEntityArgs,
36
+ IToDetailsFromCredentialArgs,
19
37
  StatusListResult,
20
- ToStatusListDetailsArgs,
21
38
  UpdateStatusListFromEncodedListArgs,
22
39
  UpdateStatusListIndexArgs,
23
40
  } from '../types'
24
41
 
25
42
  import { assertValidProofType, ensureDate, getAssertedProperty, getAssertedValue, getAssertedValues } from '../utils'
26
43
  import { BitstringStatusListCredential } from '../types/BitstringStatusList'
27
- import { BitstreamStatusList, BitstringStatusPurpose, createStatusListCredential } from '@4sure-tech/vc-bitstring-status-lists'
28
- import { BitstringStatusListEntity, IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
44
+ import {
45
+ BitstreamStatusList,
46
+ BitstringStatusListCredentialUnsigned,
47
+ BitstringStatusPurpose,
48
+ createStatusListCredential,
49
+ } from '@4sure-tech/vc-bitstring-status-lists'
50
+ import {
51
+ BitstringStatusListEntity,
52
+ BitstringStatusListEntryCredentialStatus,
53
+ IBitstringStatusListEntryEntity,
54
+ IStatusListEntryEntity,
55
+ StatusListEntity,
56
+ } from '@sphereon/ssi-sdk.data-store'
57
+ import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
29
58
 
30
59
  export const DEFAULT_LIST_LENGTH = 131072 // W3C spec minimum
31
- export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
60
+ export const DEFAULT_PROOF_FORMAT = 'vc+jwt' as CredentialProofFormat
32
61
  export const DEFAULT_STATUS_PURPOSE: BitstringStatusPurpose = 'revocation'
33
62
 
63
+ /**
64
+ * Implementation of the IStatusList interface for W3C Bitstring Status Lists
65
+ *
66
+ * This class handles the creation, updating, and verification of bitstring status lists
67
+ * according to the W3C Bitstring Status List specification. It supports multiple
68
+ * status purposes (revocation, suspension, etc.) and various proof formats.
69
+ */
34
70
  export class BitstringStatusListImplementation implements IStatusList {
71
+ /**
72
+ * Creates a new bitstring status list with the specified configuration
73
+ *
74
+ * @param args - Configuration for the new status list including issuer, purpose, and size
75
+ * @param context - Veramo agent context for credential operations
76
+ * @returns Promise resolving to the created status list details
77
+ */
35
78
  async createNewStatusList(
36
79
  args: CreateStatusListArgs,
37
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
80
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
38
81
  ): Promise<StatusListResult> {
39
82
  if (!args.bitstringStatusList) {
40
83
  throw new Error('BitstringStatusList options are required for type BitstringStatusList')
@@ -43,30 +86,37 @@ export class BitstringStatusListImplementation implements IStatusList {
43
86
  const length = args?.length ?? DEFAULT_LIST_LENGTH
44
87
  const proofFormat: CredentialProofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
45
88
  assertValidProofType(StatusListType.BitstringStatusList, proofFormat)
46
- const veramoProofFormat: VeramoProofFormat = proofFormat as VeramoProofFormat
47
89
 
48
90
  const { issuer, id } = args
49
91
  const correlationId = getAssertedValue('correlationId', args.correlationId)
50
92
  const { statusPurpose, bitsPerStatus, validFrom, validUntil, ttl } = args.bitstringStatusList
93
+
94
+ const unsignedCredential: BitstringStatusListCredentialUnsigned = await createStatusListCredential({
95
+ id,
96
+ issuer,
97
+ statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
98
+ validFrom: ensureDate(validFrom),
99
+ validUntil: ensureDate(validUntil),
100
+ ttl,
101
+ })
51
102
  const statusListCredential = await this.createVerifiableCredential(
52
103
  {
53
- ...args,
54
- proofFormat: veramoProofFormat,
55
- statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
56
- validFrom: ensureDate(validFrom),
57
- validUntil: ensureDate(validUntil),
58
- ttl,
104
+ unsignedCredential,
105
+ id,
106
+ issuer,
107
+ proofFormat,
108
+ keyRef: args.keyRef,
59
109
  },
60
110
  context,
61
111
  )
62
112
 
63
113
  return {
64
- encodedList: statusListCredential.credentialSubject.encodedList,
65
- statusListCredential: statusListCredential,
114
+ encodedList: unsignedCredential.credentialSubject.encodedList,
115
+ statusListCredential,
66
116
  bitstringStatusList: {
67
117
  statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
68
- ...(statusListCredential.validFrom && { validFrom: new Date(statusListCredential.validFrom) }),
69
- ...(statusListCredential.validUntil && { validUntil: new Date(statusListCredential.validUntil) }),
118
+ ...(unsignedCredential.validFrom && { validFrom: new Date(unsignedCredential.validFrom) }),
119
+ ...(unsignedCredential.validUntil && { validUntil: new Date(unsignedCredential.validUntil) }),
70
120
  ttl,
71
121
  bitsPerStatus,
72
122
  },
@@ -80,12 +130,19 @@ export class BitstringStatusListImplementation implements IStatusList {
80
130
  }
81
131
  }
82
132
 
133
+ /**
134
+ * Updates the status of a specific credential in an existing status list
135
+ *
136
+ * @param args - Update parameters including the status list credential, index, and new value
137
+ * @param context - Veramo agent context for credential operations
138
+ * @returns Promise resolving to the updated status list details
139
+ */
83
140
  async updateStatusListIndex(
84
141
  args: UpdateStatusListIndexArgs,
85
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
142
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
86
143
  ): Promise<StatusListResult> {
87
144
  if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
88
- return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)')
145
+ return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)'))
89
146
  }
90
147
 
91
148
  const credential = args.statusListCredential
@@ -96,9 +153,10 @@ export class BitstringStatusListImplementation implements IStatusList {
96
153
 
97
154
  const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
98
155
  const statusList: BitstreamStatusList = await BitstreamStatusList.decode({ encodedList: origEncodedList, statusSize: args.bitsPerStatus })
99
- statusList.setStatus(index, args.value)
156
+ const bitstringStatusId = args.value as number
157
+ statusList.setStatus(index, bitstringStatusId)
100
158
 
101
- const proofFormat = CredentialMapper.detectDocumentType(credential) === DocumentFormat.JWT ? 'jwt' : 'lds'
159
+ const proofFormat = CredentialMapper.detectDocumentType(credential) === DocumentFormat.JWT ? 'vc+jwt' : 'lds'
102
160
 
103
161
  const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
104
162
 
@@ -108,74 +166,92 @@ export class BitstringStatusListImplementation implements IStatusList {
108
166
  const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : undefined
109
167
  const ttl = credSubject.ttl
110
168
 
169
+ const unsignedCredential: BitstringStatusListCredentialUnsigned = await createStatusListCredential({
170
+ id,
171
+ issuer,
172
+ statusList,
173
+ statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
174
+ validFrom: ensureDate(validFrom),
175
+ validUntil: ensureDate(validUntil),
176
+ ttl,
177
+ })
178
+
111
179
  const updatedCredential = await this.createVerifiableCredential(
112
180
  {
113
- ...args,
181
+ unsignedCredential,
114
182
  id,
115
183
  issuer,
116
- statusList,
117
- proofFormat: proofFormat,
118
- statusPurpose,
119
- ttl,
120
- validFrom,
121
- validUntil,
184
+ proofFormat,
185
+ keyRef: args.keyRef,
122
186
  },
123
187
  context,
124
188
  )
125
189
 
126
190
  return {
127
191
  statusListCredential: updatedCredential,
128
- encodedList: updatedCredential.credentialSubject.encodedList,
192
+ encodedList: unsignedCredential.credentialSubject.encodedList,
129
193
  bitstringStatusList: {
130
194
  statusPurpose,
131
- ...(updatedCredential.validFrom && { validFrom: new Date(updatedCredential.validFrom) }),
132
- ...(updatedCredential.validUntil && { validUntil: new Date(updatedCredential.validUntil) }),
195
+ ...(unsignedCredential.validFrom && { validFrom: new Date(unsignedCredential.validFrom) }),
196
+ ...(unsignedCredential.validUntil && { validUntil: new Date(unsignedCredential.validUntil) }),
133
197
  bitsPerStatus: args.bitsPerStatus,
134
198
  ttl,
135
199
  },
136
200
  length: statusList.getLength(),
137
201
  type: StatusListType.BitstringStatusList,
138
- proofFormat: proofFormat,
202
+ proofFormat,
139
203
  id,
140
204
  issuer,
141
205
  statuslistContentType: this.buildContentType(proofFormat),
142
206
  }
143
207
  }
144
208
 
209
+ /**
210
+ * Updates a status list by decoding an encoded list, modifying it, and re-encoding
211
+ *
212
+ * @param args - Update parameters including encoded list, index, and new value
213
+ * @param context - Veramo agent context for credential operations
214
+ * @returns Promise resolving to the updated status list details
215
+ */
145
216
  async updateStatusListFromEncodedList(
146
217
  args: UpdateStatusListFromEncodedListArgs,
147
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
218
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
148
219
  ): Promise<StatusListResult> {
149
220
  if (!args.bitstringStatusList) {
150
221
  throw new Error('bitstringStatusList options required for type BitstringStatusList')
151
222
  }
152
223
 
153
224
  if (args.bitstringStatusList.bitsPerStatus < 1) {
154
- return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)')
225
+ return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)'))
155
226
  }
156
227
 
157
228
  const { statusPurpose, bitsPerStatus, ttl, validFrom, validUntil } = args.bitstringStatusList
158
229
 
159
230
  const proofFormat: CredentialProofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
160
231
  assertValidProofType(StatusListType.BitstringStatusList, proofFormat)
161
- const veramoProofFormat: VeramoProofFormat = proofFormat as VeramoProofFormat
162
232
 
163
233
  const { issuer, id } = getAssertedValues(args)
164
234
  const statusList: BitstreamStatusList = await BitstreamStatusList.decode({ encodedList: args.encodedList, statusSize: bitsPerStatus })
165
235
  const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
166
236
  statusList.setStatus(index, args.value)
167
237
 
238
+ const unsignedCredential: BitstringStatusListCredentialUnsigned = await createStatusListCredential({
239
+ id,
240
+ issuer,
241
+ statusList,
242
+ statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
243
+ validFrom: ensureDate(validFrom),
244
+ validUntil: ensureDate(validUntil),
245
+ ttl,
246
+ })
247
+
168
248
  const credential = await this.createVerifiableCredential(
169
249
  {
250
+ unsignedCredential,
170
251
  id,
171
252
  issuer,
172
- statusList,
173
- proofFormat: veramoProofFormat,
253
+ proofFormat,
174
254
  keyRef: args.keyRef,
175
- statusPurpose,
176
- validFrom: ensureDate(validFrom),
177
- validUntil: ensureDate(validUntil),
178
- ttl,
179
255
  },
180
256
  context,
181
257
  )
@@ -183,34 +259,38 @@ export class BitstringStatusListImplementation implements IStatusList {
183
259
  return {
184
260
  type: StatusListType.BitstringStatusList,
185
261
  statusListCredential: credential,
186
- encodedList: credential.credentialSubject.encodedList,
262
+ encodedList: unsignedCredential.credentialSubject.encodedList,
187
263
  bitstringStatusList: {
188
264
  statusPurpose,
189
265
  bitsPerStatus,
190
- ...(credential.validFrom && { validFrom: new Date(credential.validFrom) }),
191
- ...(credential.validUntil && { validUntil: new Date(credential.validUntil) }),
266
+ ...(unsignedCredential.validFrom && { validFrom: new Date(unsignedCredential.validFrom) }),
267
+ ...(unsignedCredential.validUntil && { validUntil: new Date(unsignedCredential.validUntil) }),
192
268
  ttl,
193
269
  },
194
270
  length: statusList.getLength(),
195
271
  proofFormat: args.proofFormat ?? 'lds',
196
- id: id,
197
- issuer: issuer,
272
+ id,
273
+ issuer,
198
274
  statuslistContentType: this.buildContentType(proofFormat),
199
275
  }
200
276
  }
201
277
 
202
- async checkStatusIndex(args: CheckStatusIndexArgs): Promise<BitstringStatus> {
278
+ /**
279
+ * Checks the status of a specific credential by its index in the status list
280
+ *
281
+ * @param args - Check parameters including the status list credential and index
282
+ * @returns Promise resolving to the status value at the specified index
283
+ */
284
+ async checkStatusIndex(args: CheckStatusIndexArgs): Promise<number> {
203
285
  if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
204
- return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)')
286
+ return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)'))
205
287
  }
206
288
 
207
289
  const uniform = CredentialMapper.toUniformCredential(args.statusListCredential)
208
290
  const { credentialSubject } = uniform
209
291
  const encodedList = getAssertedProperty('encodedList', credentialSubject)
210
292
 
211
- const statusSize = args.bitsPerStatus
212
- const statusList = await BitstreamStatusList.decode({ encodedList, statusSize })
213
-
293
+ const statusList = await BitstreamStatusList.decode({ encodedList, statusSize: args.bitsPerStatus })
214
294
  const numIndex = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
215
295
  if (statusList.getLength() <= numIndex) {
216
296
  throw new Error(`Status list index out of bounds, has ${statusList.getLength()} entries, requested ${numIndex}`)
@@ -218,59 +298,120 @@ export class BitstringStatusListImplementation implements IStatusList {
218
298
  return statusList.getStatus(numIndex)
219
299
  }
220
300
 
221
- async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult & IBitstringStatusListImplementationResult> {
222
- const { statusListPayload, bitsPerStatus } = args
223
- if (!bitsPerStatus || bitsPerStatus < 1) {
224
- return Promise.reject('bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (toStatusListDetails)')
225
- }
226
-
227
- const uniform = CredentialMapper.toUniformCredential(statusListPayload)
301
+ async extractCredentialDetails(credential: StatusListCredential): Promise<IExtractedCredentialDetails> {
302
+ const uniform = CredentialMapper.toUniformCredential(credential)
228
303
  const { issuer, credentialSubject } = uniform
229
- const id = getAssertedValue('id', uniform.id)
230
- const encodedList = getAssertedProperty('encodedList', credentialSubject)
231
- const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListPayload) === DocumentFormat.JWT ? 'jwt' : 'lds'
232
- const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
233
- const statusPurpose = getAssertedProperty('statusPurpose', credSubject)
234
- const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : undefined
235
- const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : undefined
236
- const ttl = credSubject.ttl
237
- const statuslistLength: number = BitstreamStatusList.getStatusListLength(encodedList, bitsPerStatus)
304
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
238
305
 
239
306
  return {
240
- // Base implementation fields
241
- id,
242
- encodedList,
307
+ id: getAssertedValue('id', uniform.id),
243
308
  issuer,
244
- type: StatusListType.BitstringStatusList,
245
- proofFormat,
246
- length: statuslistLength,
247
- statusListCredential: statusListPayload,
248
- statuslistContentType: this.buildContentType(proofFormat),
249
- correlationId: args.correlationId, // FIXME these do not need to be inside the impl
250
- driverType: args.driverType, // FIXME these do not need to be inside the impl
251
-
252
- // Flattened Bitstring-specific fields
253
- statusPurpose,
254
- bitsPerStatus,
255
- ...(validFrom && { validFrom }),
256
- ...(validUntil && { validUntil }),
257
- ...(ttl && { ttl }),
309
+ encodedList: getAssertedProperty('encodedList', subject),
310
+ }
311
+ }
258
312
 
259
- // Legacy nested structure for backward compatibility
260
- bitstringStatusList: {
313
+ /**
314
+ * Converts a status list credential payload to detailed status list information
315
+ *
316
+ * @param args - Conversion parameters including the status list payload
317
+ * @returns Promise resolving to detailed status list information
318
+ */
319
+ // For CREATE and READ contexts
320
+ async toStatusListDetails(args: IToDetailsFromCredentialArgs): Promise<StatusListResult & IBitstringStatusListImplementationResult>
321
+ // For UPDATE contexts
322
+ async toStatusListDetails(args: IMergeDetailsWithEntityArgs): Promise<StatusListResult & IBitstringStatusListImplementationResult>
323
+ async toStatusListDetails(
324
+ args: IToDetailsFromCredentialArgs | IMergeDetailsWithEntityArgs,
325
+ ): Promise<StatusListResult & IBitstringStatusListImplementationResult> {
326
+ if ('statusListCredential' in args) {
327
+ // CREATE/READ context
328
+ const { statusListCredential, bitsPerStatus, correlationId, driverType } = args
329
+ if (!bitsPerStatus || bitsPerStatus < 1) {
330
+ return Promise.reject(Error('bitsPerStatus must be set for bitstring status lists and must be 1 or higher'))
331
+ }
332
+
333
+ const uniform = CredentialMapper.toUniformCredential(statusListCredential)
334
+ const { issuer, credentialSubject } = uniform
335
+ const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject
336
+
337
+ const id = getAssertedValue('id', uniform.id)
338
+ const encodedList = getAssertedProperty('encodedList', subject)
339
+ const statusPurpose = getAssertedProperty('statusPurpose', subject)
340
+ const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : undefined
341
+ const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : undefined
342
+ const ttl = subject.ttl
343
+ const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListCredential) === DocumentFormat.JWT ? 'vc+jwt' : 'lds'
344
+ const statuslistLength = BitstreamStatusList.getStatusListLength(encodedList, bitsPerStatus)
345
+
346
+ return {
347
+ id,
348
+ encodedList,
349
+ issuer,
350
+ type: StatusListType.BitstringStatusList,
351
+ proofFormat,
352
+ length: statuslistLength,
353
+ statusListCredential,
354
+ statuslistContentType: this.buildContentType(proofFormat),
355
+ correlationId,
356
+ driverType,
261
357
  statusPurpose,
262
358
  bitsPerStatus,
263
359
  ...(validFrom && { validFrom }),
264
360
  ...(validUntil && { validUntil }),
265
361
  ...(ttl && { ttl }),
266
- },
267
-
268
- // Optional fields from args
269
- ...(args.correlationId && { correlationId: args.correlationId }),
270
- ...(args.driverType && { driverType: args.driverType }),
362
+ bitstringStatusList: {
363
+ statusPurpose,
364
+ bitsPerStatus,
365
+ ...(validFrom && { validFrom }),
366
+ ...(validUntil && { validUntil }),
367
+ ...(ttl && { ttl }),
368
+ },
369
+ }
370
+ } else {
371
+ // UPDATE context
372
+ const { extractedDetails, statusListEntity } = args
373
+ const bitstringEntity = statusListEntity as BitstringStatusListEntity
374
+ if (!bitstringEntity.bitsPerStatus) {
375
+ return Promise.reject(Error('bitsPerStatus must be present for a bitstring status list'))
376
+ }
377
+
378
+ const proofFormat: CredentialProofFormat =
379
+ CredentialMapper.detectDocumentType(statusListEntity.statusListCredential!) === DocumentFormat.JWT ? 'vc+jwt' : 'lds'
380
+ const statuslistLength = BitstreamStatusList.getStatusListLength(extractedDetails.encodedList, bitstringEntity.bitsPerStatus)
381
+
382
+ return {
383
+ id: extractedDetails.id,
384
+ encodedList: extractedDetails.encodedList,
385
+ issuer: extractedDetails.issuer,
386
+ type: StatusListType.BitstringStatusList,
387
+ proofFormat,
388
+ length: statuslistLength,
389
+ statusListCredential: statusListEntity.statusListCredential!,
390
+ statuslistContentType: this.buildContentType(proofFormat),
391
+ correlationId: statusListEntity.correlationId,
392
+ driverType: statusListEntity.driverType,
393
+ statusPurpose: bitstringEntity.statusPurpose,
394
+ bitsPerStatus: bitstringEntity.bitsPerStatus,
395
+ ...(bitstringEntity.validFrom && { validFrom: bitstringEntity.validFrom }),
396
+ ...(bitstringEntity.validUntil && { validUntil: bitstringEntity.validUntil }),
397
+ ...(bitstringEntity.ttl && { ttl: bitstringEntity.ttl }),
398
+ bitstringStatusList: {
399
+ statusPurpose: bitstringEntity.statusPurpose,
400
+ bitsPerStatus: bitstringEntity.bitsPerStatus,
401
+ ...(bitstringEntity.validFrom && { validFrom: bitstringEntity.validFrom }),
402
+ ...(bitstringEntity.validUntil && { validUntil: bitstringEntity.validUntil }),
403
+ ...(bitstringEntity.ttl && { ttl: bitstringEntity.ttl }),
404
+ },
405
+ }
271
406
  }
272
407
  }
273
408
 
409
+ /**
410
+ * Creates a credential status entry for a specific credential in a status list
411
+ *
412
+ * @param args - Parameters including the status list, entry details, and index
413
+ * @returns Promise resolving to the credential status entry
414
+ */
274
415
  async createCredentialStatus(args: {
275
416
  statusList: StatusListEntity
276
417
  statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
@@ -278,66 +419,69 @@ export class BitstringStatusListImplementation implements IStatusList {
278
419
  }): Promise<BitstringStatusListEntryCredentialStatus> {
279
420
  const { statusList, statusListEntry, statusListIndex } = args
280
421
 
281
- // Type guard to ensure we have a bitstring entry
282
- const isBitstringEntry = (entry: IStatusListEntryEntity | IBitstringStatusListEntryEntity): entry is IBitstringStatusListEntryEntity => {
283
- return 'statusPurpose' in entry
284
- }
285
-
286
- if (!isBitstringEntry(statusListEntry)) {
287
- throw new Error('Expected bitstring status list entry for bitstring status list')
288
- }
289
-
290
- // Cast to BitstringStatusListEntity to access specific properties
291
422
  const bitstringStatusList = statusList as BitstringStatusListEntity
292
-
423
+ const bitstringStatusListEntry = statusListEntry as IBitstringStatusListEntryEntity
293
424
  return {
294
425
  id: `${statusList.id}#${statusListIndex}`,
295
426
  type: 'BitstringStatusListEntry',
296
- statusPurpose: statusListEntry.statusPurpose,
427
+ statusPurpose: bitstringStatusListEntry.statusPurpose,
297
428
  statusListIndex: '' + statusListIndex,
298
429
  statusListCredential: statusList.id,
299
430
  bitsPerStatus: bitstringStatusList.bitsPerStatus,
431
+ statusMessage: bitstringStatusListEntry.statusMessage,
432
+ statusReference: bitstringStatusListEntry.statusReference,
300
433
  } satisfies BitstringStatusListEntryCredentialStatus
301
434
  }
302
435
 
436
+ /**
437
+ * Creates a signed verifiable credential from an unsigned status list credential
438
+ *
439
+ * @param args - Parameters including the unsigned credential and signing details
440
+ * @param context - Veramo agent context for credential operations
441
+ * @returns Promise resolving to the signed credential
442
+ */
303
443
  private async createVerifiableCredential(
304
444
  args: {
445
+ unsignedCredential: BitstringStatusListCredentialUnsigned
305
446
  id: string
306
447
  issuer: string | IIssuer
307
- statusList?: BitstreamStatusList
308
- proofFormat: VeramoProofFormat
309
- statusPurpose: BitstringStatusPurpose
310
- validFrom?: Date
311
- validUntil?: Date
312
- ttl?: number
448
+ proofFormat: CredentialProofFormat
313
449
  keyRef?: string
314
450
  },
315
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
451
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
316
452
  ): Promise<BitstringStatusListCredential> {
453
+ const { unsignedCredential, issuer, proofFormat, keyRef } = args
454
+
317
455
  const identifier = await context.agent.identifierManagedGet({
318
- identifier: typeof args.issuer === 'string' ? args.issuer : args.issuer.id,
456
+ identifier: typeof issuer === 'string' ? issuer : issuer.id,
319
457
  vmRelationship: 'assertionMethod',
320
458
  offlineWhenNoDIDRegistered: true,
321
459
  })
322
460
 
323
- const unsignedCredential = await createStatusListCredential(args)
324
-
325
461
  const verifiableCredential = await context.agent.createVerifiableCredential({
326
462
  credential: unsignedCredential,
327
- keyRef: args.keyRef ?? identifier.kmsKeyRef,
328
- proofFormat: args.proofFormat,
463
+ keyRef: keyRef ?? identifier.kmsKeyRef,
464
+ proofFormat,
329
465
  fetchRemoteContexts: true,
330
466
  })
331
467
 
332
468
  return CredentialMapper.toWrappedVerifiableCredential(verifiableCredential as StatusListCredential).original as BitstringStatusListCredential
333
469
  }
334
470
 
335
- private buildContentType(proofFormat: CredentialProofFormat | undefined) {
471
+ /**
472
+ * Builds the appropriate content type string for a given proof format
473
+ *
474
+ * @param proofFormat - The proof format to build content type for
475
+ * @returns The corresponding content type string
476
+ */
477
+ private buildContentType(proofFormat: CredentialProofFormat | undefined): string {
336
478
  switch (proofFormat) {
337
479
  case 'jwt':
338
- return `application/statuslist+jwt`
480
+ return 'application/statuslist+jwt'
339
481
  case 'cbor':
340
- return `application/statuslist+cwt`
482
+ return 'application/statuslist+cwt'
483
+ case 'vc+jwt':
484
+ return 'application/statuslist+vc+jwt'
341
485
  case 'lds':
342
486
  return 'application/statuslist+ld+json'
343
487
  default: