@sphereon/ssi-sdk.vc-status-list 0.34.1-feature.SSISDK.17.bitstring.sl.9 → 0.34.1-next.29

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