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

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,28 @@
1
1
  import type { IAgentContext, ICredentialPlugin, IKeyManager } from '@veramo/core'
2
- import { type CompactJWT, type CWT, type CredentialProofFormat, StatusListType } from '@sphereon/ssi-types'
2
+ import { type CompactJWT, type CredentialProofFormat, type CWT, StatusListType } from '@sphereon/ssi-types'
3
3
  import type {
4
4
  CheckStatusIndexArgs,
5
5
  CreateStatusListArgs,
6
6
  SignedStatusListData,
7
+ StatusListOAuthEntryCredentialStatus,
7
8
  StatusListResult,
8
9
  StatusOAuth,
9
10
  ToStatusListDetailsArgs,
10
11
  UpdateStatusListFromEncodedListArgs,
11
12
  UpdateStatusListIndexArgs,
12
13
  } from '../types'
13
- import { determineProofFormat, getAssertedValue, getAssertedValues } from '../utils'
14
- import type { IStatusList } from './IStatusList'
14
+ import { determineProofFormat, ensureDate, getAssertedValue, getAssertedValues } from '../utils'
15
+ import type { IOAuthStatusListImplementationResult, IStatusList } from './IStatusList'
15
16
  import { StatusList } from '@sd-jwt/jwt-status-list'
16
17
  import type { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
17
18
  import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
18
19
  import { createSignedJwt, decodeStatusListJWT } from './encoding/jwt'
19
20
  import { createSignedCbor, decodeStatusListCWT } from './encoding/cbor'
21
+ import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, OAuthStatusListEntity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
20
22
 
21
23
  type IRequiredContext = IAgentContext<ICredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>
22
24
 
23
- export const DEFAULT_BITS_PER_STATUS = 1 // 1 bit is sufficient for 0x00 - "VALID" 0x01 - "INVALID" saving space in the process
25
+ export const DEFAULT_BITS_PER_STATUS = 1 // 1 bit is sufficient for 0x00 - "VALID" 0x01 - "INVALID" saving space in the process
24
26
  export const DEFAULT_LIST_LENGTH = 250000
25
27
  export const DEFAULT_PROOF_FORMAT = 'jwt' as CredentialProofFormat
26
28
 
@@ -32,7 +34,8 @@ export class OAuthStatusListImplementation implements IStatusList {
32
34
 
33
35
  const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT
34
36
  const { issuer, id, oauthStatusList, keyRef } = args
35
- const { bitsPerStatus, expiresAt } = oauthStatusList
37
+ const { bitsPerStatus } = oauthStatusList
38
+ const expiresAt = ensureDate(oauthStatusList.expiresAt)
36
39
  const length = args.length ?? DEFAULT_LIST_LENGTH
37
40
  const issuerString = typeof issuer === 'string' ? issuer : issuer.id
38
41
  const correlationId = getAssertedValue('correlationId', args.correlationId)
@@ -56,7 +59,8 @@ export class OAuthStatusListImplementation implements IStatusList {
56
59
  }
57
60
 
58
61
  async updateStatusListIndex(args: UpdateStatusListIndexArgs, context: IRequiredContext): Promise<StatusListResult> {
59
- const { statusListCredential, value, expiresAt, keyRef } = args
62
+ const { statusListCredential, value, keyRef } = args
63
+ const expiresAt = ensureDate(args.expiresAt)
60
64
  if (typeof statusListCredential !== 'string') {
61
65
  return Promise.reject('statusListCredential in neither JWT nor CWT')
62
66
  }
@@ -70,6 +74,10 @@ export class OAuthStatusListImplementation implements IStatusList {
70
74
  throw new Error('Status list index out of bounds')
71
75
  }
72
76
 
77
+ if (typeof value !== 'number') {
78
+ throw new Error('Status list values should be of type number')
79
+ }
80
+
73
81
  statusList.setStatus(index, value)
74
82
  const { statusListCredential: signedCredential, encodedList } = await this.createSignedStatusList(
75
83
  proofFormat,
@@ -102,15 +110,15 @@ export class OAuthStatusListImplementation implements IStatusList {
102
110
  throw new Error('OAuthStatusList options are required for type OAuthStatusList')
103
111
  }
104
112
  const { proofFormat, oauthStatusList, keyRef } = args
105
- const { bitsPerStatus, expiresAt } = oauthStatusList
113
+ const { bitsPerStatus } = oauthStatusList
114
+ const expiresAt = ensureDate(oauthStatusList.expiresAt)
106
115
 
107
116
  const { issuer, id } = getAssertedValues(args)
108
117
  const issuerString = typeof issuer === 'string' ? issuer : issuer.id
109
118
 
110
119
  const listToUpdate = StatusList.decompressStatusList(args.encodedList, bitsPerStatus ?? DEFAULT_BITS_PER_STATUS)
111
120
  const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
112
- // FIXME: See above.
113
- listToUpdate.setStatus(index, args.value ? 1 : 0)
121
+ listToUpdate.setStatus(index, args.value)
114
122
 
115
123
  const { statusListCredential, encodedList } = await this.createSignedStatusList(
116
124
  proofFormat ?? DEFAULT_PROOF_FORMAT,
@@ -138,10 +146,6 @@ export class OAuthStatusListImplementation implements IStatusList {
138
146
  }
139
147
  }
140
148
 
141
- private buildContentType(proofFormat: 'jwt' | 'lds' | 'EthereumEip712Signature2021' | 'cbor' | undefined) {
142
- return `application/statuslist+${proofFormat === 'cbor' ? 'cwt' : 'jwt'}`
143
- }
144
-
145
149
  async checkStatusIndex(args: CheckStatusIndexArgs): Promise<number | StatusOAuth> {
146
150
  const { statusListCredential, statusListIndex } = args
147
151
  if (typeof statusListCredential !== 'string') {
@@ -153,19 +157,23 @@ export class OAuthStatusListImplementation implements IStatusList {
153
157
 
154
158
  const index = typeof statusListIndex === 'number' ? statusListIndex : parseInt(statusListIndex)
155
159
  if (index < 0 || index >= statusList.statusList.length) {
156
- throw new Error('Status list index out of bounds')
160
+ throw new Error(`Status list index out of bounds, has ${statusList.statusList.length} items, requested ${index}`)
157
161
  }
158
162
 
159
163
  return statusList.getStatus(index)
160
164
  }
161
165
 
162
- async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult> {
166
+ async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult & IOAuthStatusListImplementationResult> {
163
167
  const { statusListPayload } = args as { statusListPayload: CompactJWT | CWT }
164
168
  const proofFormat = determineProofFormat(statusListPayload)
165
169
  const decoded = proofFormat === 'jwt' ? decodeStatusListJWT(statusListPayload) : decodeStatusListCWT(statusListPayload)
166
170
  const { statusList, issuer, id, exp } = decoded
167
171
 
172
+ const bitsPerStatus = statusList.getBitsPerStatus()
173
+ const expiresAt = exp ? new Date(exp * 1000) : undefined
174
+
168
175
  return {
176
+ // Base implementation fields
169
177
  id,
170
178
  encodedList: statusList.compressStatusList(),
171
179
  issuer,
@@ -174,17 +182,51 @@ export class OAuthStatusListImplementation implements IStatusList {
174
182
  length: statusList.statusList.length,
175
183
  statusListCredential: statusListPayload,
176
184
  statuslistContentType: this.buildContentType(proofFormat),
185
+ correlationId: args.correlationId, // FIXME these do not need to be inside the impl
186
+ driverType: args.driverType, // FIXME these do not need to be inside the impl
187
+
188
+ // Flattened OAuth-specific fields
189
+ bitsPerStatus,
190
+ ...(expiresAt && { expiresAt }),
191
+
192
+ // Legacy nested structure for backward compatibility
177
193
  oauthStatusList: {
178
- bitsPerStatus: statusList.getBitsPerStatus(),
179
- ...(exp && { expiresAt: new Date(exp * 1000) }),
194
+ bitsPerStatus,
195
+ ...(expiresAt && { expiresAt }),
180
196
  },
197
+
198
+ // Optional fields from args
181
199
  ...(args.correlationId && { correlationId: args.correlationId }),
182
200
  ...(args.driverType && { driverType: args.driverType }),
183
201
  }
184
202
  }
185
203
 
204
+ async createCredentialStatus(args: {
205
+ statusList: StatusListEntity
206
+ statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
207
+ statusListIndex: number
208
+ }): Promise<StatusListOAuthEntryCredentialStatus> {
209
+ const { statusList, statusListIndex } = args
210
+
211
+ // Cast to OAuthStatusListEntity to access specific properties
212
+ const oauthStatusList = statusList as OAuthStatusListEntity
213
+
214
+ return {
215
+ id: `${statusList.id}#${statusListIndex}`,
216
+ type: 'OAuthStatusListEntry',
217
+ bitsPerStatus: oauthStatusList.bitsPerStatus,
218
+ statusListIndex: '' + statusListIndex,
219
+ statusListCredential: statusList.id,
220
+ expiresAt: oauthStatusList.expiresAt,
221
+ }
222
+ }
223
+
224
+ private buildContentType(proofFormat: CredentialProofFormat | undefined) {
225
+ return `application/statuslist+${proofFormat === 'cbor' ? 'cwt' : 'jwt'}`
226
+ }
227
+
186
228
  private async createSignedStatusList(
187
- proofFormat: 'jwt' | 'lds' | 'EthereumEip712Signature2021' | 'cbor',
229
+ proofFormat: CredentialProofFormat,
188
230
  context: IAgentContext<ICredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>,
189
231
  statusList: StatusList,
190
232
  issuerString: string,
@@ -2,15 +2,15 @@ import type { IAgentContext, ICredentialPlugin, ProofFormat as VeramoProofFormat
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 { IStatusList, IStatusList2021ImplementationResult } from './IStatusList'
14
14
  import type {
15
15
  CheckStatusIndexArgs,
16
16
  CreateStatusListArgs,
@@ -19,12 +19,12 @@ import type {
19
19
  UpdateStatusListFromEncodedListArgs,
20
20
  UpdateStatusListIndexArgs,
21
21
  } from '../types'
22
-
23
- import { Status2021 } from '../types'
22
+ import { Status2021, StatusList2021EntryCredentialStatus } from '../types'
24
23
  import { assertValidProofType, getAssertedProperty, getAssertedValue, getAssertedValues } from '../utils'
24
+ import { IBitstringStatusListEntryEntity, IStatusListEntryEntity, StatusList2021Entity, StatusListEntity } from '@sphereon/ssi-sdk.data-store'
25
25
 
26
26
  export const DEFAULT_LIST_LENGTH = 250000
27
- export const DEFAULT_PROOF_FORMAT = 'lds' as VeramoProofFormat
27
+ export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
28
28
 
29
29
  export class StatusList2021Implementation implements IStatusList {
30
30
  async createNewStatusList(
@@ -96,11 +96,15 @@ export class StatusList2021Implementation implements IStatusList {
96
96
  context,
97
97
  )
98
98
 
99
+ if (!('statusPurpose' in credentialSubject)) {
100
+ return Promise.reject(Error('statusPurpose is required in credentialSubject for StatusList2021'))
101
+ }
102
+
99
103
  return {
100
104
  statusListCredential: updatedCredential,
101
105
  encodedList,
102
106
  statusList2021: {
103
- ...('statusPurpose' in credentialSubject ? { statusPurpose: credentialSubject.statusPurpose } : {}),
107
+ statusPurpose: credentialSubject.statusPurpose,
104
108
  indexingDirection: 'rightToLeft',
105
109
  },
106
110
  length: statusList.length - 1,
@@ -126,7 +130,7 @@ export class StatusList2021Implementation implements IStatusList {
126
130
  const { issuer, id } = getAssertedValues(args)
127
131
  const statusList = await StatusList.decode({ encodedList: args.encodedList })
128
132
  const index = typeof args.statusListIndex === 'number' ? args.statusListIndex : parseInt(args.statusListIndex)
129
- statusList.setStatus(index, args.value)
133
+ statusList.setStatus(index, args.value !== 0)
130
134
 
131
135
  const newEncodedList = await statusList.encode()
132
136
  const credential = await this.createVerifiableCredential(
@@ -166,7 +170,7 @@ export class StatusList2021Implementation implements IStatusList {
166
170
  return status ? Status2021.Invalid : Status2021.Valid
167
171
  }
168
172
 
169
- async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult> {
173
+ async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult & IStatusList2021ImplementationResult> {
170
174
  const { statusListPayload } = args
171
175
  const uniform = CredentialMapper.toUniformCredential(statusListPayload)
172
176
  const { issuer, credentialSubject } = uniform
@@ -175,9 +179,11 @@ export class StatusList2021Implementation implements IStatusList {
175
179
  const proofFormat: CredentialProofFormat = CredentialMapper.detectDocumentType(statusListPayload) === DocumentFormat.JWT ? 'jwt' : 'lds'
176
180
 
177
181
  const statusPurpose = getAssertedProperty('statusPurpose', credentialSubject)
182
+ const indexingDirection = 'rightToLeft'
178
183
  const list = await StatusList.decode({ encodedList })
179
184
 
180
185
  return {
186
+ // Base implementation fields
181
187
  id,
182
188
  encodedList,
183
189
  issuer,
@@ -186,12 +192,41 @@ export class StatusList2021Implementation implements IStatusList {
186
192
  length: list.length,
187
193
  statusListCredential: statusListPayload,
188
194
  statuslistContentType: this.buildContentType(proofFormat),
195
+ correlationId: args.correlationId, // FIXME these do not need to be inside the impl
196
+ driverType: args.driverType, // FIXME these do not need to be inside the impl
197
+
198
+ // Flattened StatusList2021-specific fields
199
+ indexingDirection,
200
+ statusPurpose,
201
+
202
+ // Legacy nested structure for backward compatibility
189
203
  statusList2021: {
190
- indexingDirection: 'rightToLeft',
204
+ indexingDirection,
191
205
  statusPurpose,
206
+
207
+ // Optional fields from args
208
+ ...(args.correlationId && { correlationId: args.correlationId }),
209
+ ...(args.driverType && { driverType: args.driverType }),
192
210
  },
193
- ...(args.correlationId && { correlationId: args.correlationId }),
194
- ...(args.driverType && { driverType: args.driverType }),
211
+ }
212
+ }
213
+
214
+ async createCredentialStatus(args: {
215
+ statusList: StatusListEntity
216
+ statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
217
+ statusListIndex: number
218
+ }): Promise<StatusList2021EntryCredentialStatus> {
219
+ const { statusList, statusListIndex } = args
220
+
221
+ // Cast to StatusList2021Entity to access specific properties
222
+ const statusList2021 = statusList as StatusList2021Entity
223
+
224
+ return {
225
+ id: `${statusList.id}#${statusListIndex}`,
226
+ type: 'StatusList2021Entry',
227
+ statusPurpose: statusList2021.statusPurpose ?? 'revocation',
228
+ statusListIndex: '' + statusListIndex,
229
+ statusListCredential: statusList.id,
195
230
  }
196
231
  }
197
232
 
@@ -234,7 +269,7 @@ export class StatusList2021Implementation implements IStatusList {
234
269
  return CredentialMapper.toWrappedVerifiableCredential(verifiableCredential as StatusListCredential).original as StatusListCredential
235
270
  }
236
271
 
237
- private buildContentType(proofFormat: 'jwt' | 'lds' | 'EthereumEip712Signature2021' | 'cbor' | undefined) {
272
+ private buildContentType(proofFormat: CredentialProofFormat | undefined) {
238
273
  switch (proofFormat) {
239
274
  case 'jwt':
240
275
  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 {
@@ -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
@@ -1,13 +1,12 @@
1
1
  import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
2
2
  import {
3
+ type CredentialProofFormat,
3
4
  type ICredential,
4
5
  type ICredentialStatus,
5
6
  type IIssuer,
6
7
  type IVerifiableCredential,
7
8
  type OrPromise,
8
- type CredentialProofFormat,
9
9
  type StatusListCredential,
10
- StatusListCredentialIdMode,
11
10
  StatusListDriverType,
12
11
  type StatusListIndexingDirection,
13
12
  StatusListType,
@@ -26,6 +25,7 @@ import { DataSource } from 'typeorm'
26
25
  import type { BitsPerStatus } from '@sd-jwt/jwt-status-list'
27
26
  import type { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc'
28
27
  import type { StatusListOpts } from '@sphereon/oid4vci-common'
28
+ import { BitstringStatusPurpose } from '@4sure-tech/vc-bitstring-status-lists'
29
29
 
30
30
  export enum StatusOAuth {
31
31
  Valid = 0,
@@ -38,6 +38,8 @@ export enum Status2021 {
38
38
  Invalid = 1,
39
39
  }
40
40
 
41
+ export type BitstringStatus = number
42
+
41
43
  export type StatusList2021Args = {
42
44
  indexingDirection: StatusListIndexingDirection
43
45
  statusPurpose?: StatusPurpose2021
@@ -45,10 +47,18 @@ export type StatusList2021Args = {
45
47
  }
46
48
 
47
49
  export type OAuthStatusListArgs = {
48
- bitsPerStatus?: BitsPerStatus
50
+ bitsPerStatus: BitsPerStatus
49
51
  expiresAt?: Date
50
52
  }
51
53
 
54
+ export type BitstringStatusListArgs = {
55
+ statusPurpose: BitstringStatusPurpose
56
+ bitsPerStatus: number
57
+ ttl?: number
58
+ validFrom?: Date
59
+ validUntil?: Date
60
+ }
61
+
52
62
  export type BaseCreateNewStatusListArgs = {
53
63
  type: StatusListType
54
64
  id: string
@@ -59,6 +69,7 @@ export type BaseCreateNewStatusListArgs = {
59
69
  keyRef?: string
60
70
  statusList2021?: StatusList2021Args
61
71
  oauthStatusList?: OAuthStatusListArgs
72
+ bitstringStatusList?: BitstringStatusListArgs
62
73
  driverType?: StatusListDriverType
63
74
  }
64
75
 
@@ -71,10 +82,18 @@ export type UpdateOAuthStatusListArgs = {
71
82
  expiresAt?: Date
72
83
  }
73
84
 
85
+ export type UpdateBitstringStatusListArgs = {
86
+ statusPurpose: BitstringStatusPurpose
87
+ bitsPerStatus: number
88
+ validFrom?: Date
89
+ validUntil?: Date
90
+ ttl?: number
91
+ }
92
+
74
93
  export interface UpdateStatusListFromEncodedListArgs {
75
94
  type?: StatusListType
76
95
  statusListIndex: number | string
77
- value: boolean
96
+ value: number
78
97
  proofFormat?: CredentialProofFormat
79
98
  keyRef?: string
80
99
  correlationId?: string
@@ -83,41 +102,57 @@ export interface UpdateStatusListFromEncodedListArgs {
83
102
  id: string
84
103
  statusList2021?: UpdateStatusList2021Args
85
104
  oauthStatusList?: UpdateOAuthStatusListArgs
105
+ bitstringStatusList?: UpdateBitstringStatusListArgs
86
106
  }
87
107
 
88
108
  export interface UpdateStatusListFromStatusListCredentialArgs {
89
109
  statusListCredential: StatusListCredential // | CompactJWT
90
110
  keyRef?: string
91
111
  statusListIndex: number | string
92
- value: number | Status2021 | StatusOAuth
112
+ value: number | Status2021 | StatusOAuth | BitstringStatus
93
113
  }
94
114
 
95
115
  export interface StatusListResult {
116
+ id: string
96
117
  encodedList: string
97
- statusListCredential: StatusListCredential
98
- length: number
118
+ issuer: string | IIssuer
99
119
  type: StatusListType
100
120
  proofFormat: CredentialProofFormat
101
- id: string
121
+ length: number
122
+ statusListCredential: StatusListCredential
102
123
  statuslistContentType: string
103
- issuer: string | IIssuer
104
- statusList2021?: StatusList2021Details
105
- oauthStatusList?: OAuthStatusDetails
106
-
107
- // These cannot be deduced from the VC, so they are present when callers pass in these values as params
108
124
  correlationId?: string
109
125
  driverType?: StatusListDriverType
110
- credentialIdMode?: StatusListCredentialIdMode
111
- }
112
126
 
113
- interface StatusList2021Details {
114
- indexingDirection: StatusListIndexingDirection
115
- statusPurpose?: StatusPurpose2021
116
- }
127
+ // Flattened StatusList2021 fields
128
+ indexingDirection?: StatusListIndexingDirection
129
+ statusPurpose?: StatusPurpose2021 | BitstringStatusPurpose | BitstringStatusPurpose[]
117
130
 
118
- interface OAuthStatusDetails {
119
- bitsPerStatus?: BitsPerStatus
131
+ // Flattened OAuth fields
132
+ bitsPerStatus?: number
120
133
  expiresAt?: Date
134
+
135
+ // Flattened Bitstring fields
136
+ validFrom?: Date
137
+ validUntil?: Date
138
+ ttl?: number
139
+
140
+ // Legacy nested structures for backward compatibility
141
+ statusList2021?: {
142
+ indexingDirection: StatusListIndexingDirection
143
+ statusPurpose: StatusPurpose2021
144
+ }
145
+ oauthStatusList?: {
146
+ bitsPerStatus: number
147
+ expiresAt?: Date
148
+ }
149
+ bitstringStatusList?: {
150
+ statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
151
+ bitsPerStatus?: number
152
+ validFrom?: Date
153
+ validUntil?: Date
154
+ ttl?: number
155
+ }
121
156
  }
122
157
 
123
158
  export interface StatusList2021EntryCredentialStatus extends ICredentialStatus {
@@ -135,6 +170,16 @@ export interface StatusListOAuthEntryCredentialStatus extends ICredentialStatus
135
170
  expiresAt?: Date
136
171
  }
137
172
 
173
+ export interface BitstringStatusListEntryCredentialStatus extends ICredentialStatus {
174
+ type: 'BitstringStatusListEntry'
175
+ statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
176
+ statusListIndex: string
177
+ statusListCredential: string
178
+ bitsPerStatus?: number
179
+ statusMessage?: Array<BitstringStatus>
180
+ statusReference?: string | string[]
181
+ }
182
+
138
183
  export interface StatusList2021ToVerifiableCredentialArgs {
139
184
  issuer: string | IIssuer
140
185
  id: string
@@ -154,12 +199,14 @@ export interface CreateStatusListArgs {
154
199
  length?: number
155
200
  statusList2021?: StatusList2021Args
156
201
  oauthStatusList?: OAuthStatusListArgs
202
+ bitstringStatusList?: BitstringStatusListArgs
157
203
  }
158
204
 
159
205
  export interface UpdateStatusListIndexArgs {
160
206
  statusListCredential: StatusListCredential // | CompactJWT
161
207
  statusListIndex: number | string
162
- value: number | Status2021 | StatusOAuth
208
+ value: number | Status2021 | StatusOAuth | BitstringStatus
209
+ bitsPerStatus?: number
163
210
  keyRef?: string
164
211
  expiresAt?: Date
165
212
  }
@@ -167,12 +214,14 @@ export interface UpdateStatusListIndexArgs {
167
214
  export interface CheckStatusIndexArgs {
168
215
  statusListCredential: StatusListCredential // | CompactJWT
169
216
  statusListIndex: string | number
217
+ bitsPerStatus?: number
170
218
  }
171
219
 
172
220
  export interface ToStatusListDetailsArgs {
173
221
  statusListPayload: StatusListCredential
174
222
  correlationId?: string
175
223
  driverType?: StatusListDriverType
224
+ bitsPerStatus?: number
176
225
  }
177
226
 
178
227
  /**
package/src/utils.ts CHANGED
@@ -11,7 +11,7 @@ import { jwtDecode } from 'jwt-decode'
11
11
 
12
12
  export function getAssertedStatusListType(type?: StatusListType) {
13
13
  const assertedType = type ?? StatusListType.StatusList2021
14
- if (![StatusListType.StatusList2021, StatusListType.OAuthStatusList].includes(assertedType)) {
14
+ if (![StatusListType.StatusList2021, StatusListType.OAuthStatusList, StatusListType.BitstringStatusList].includes(assertedType)) {
15
15
  throw Error(`StatusList type ${assertedType} is not supported (yet)`)
16
16
  }
17
17
  return assertedType
@@ -39,8 +39,9 @@ export function getAssertedProperty<T extends object>(propertyName: string, obj:
39
39
  }
40
40
 
41
41
  const ValidProofTypeMap = new Map<StatusListType, CredentialProofFormat[]>([
42
- [StatusListType.StatusList2021, ['jwt', 'lds', 'EthereumEip712Signature2021']],
42
+ [StatusListType.StatusList2021, ['jwt', 'lds']],
43
43
  [StatusListType.OAuthStatusList, ['jwt', 'cbor']],
44
+ [StatusListType.BitstringStatusList, ['lds']],
44
45
  ])
45
46
 
46
47
  export function assertValidProofType(type: StatusListType, proofFormat: CredentialProofFormat) {
@@ -93,3 +94,35 @@ export function determineProofFormat(credential: StatusListCredential): Credenti
93
94
  throw Error('Cannot determine credential payload type')
94
95
  }
95
96
  }
97
+
98
+ /**
99
+ * Ensures a value is converted to a Date object if it's a valid date string,
100
+ * otherwise returns the original value or undefined
101
+ *
102
+ * @param value - The value to convert to Date (can be Date, string, or undefined)
103
+ * @returns Date object, undefined, or the original value if conversion fails
104
+ */
105
+ export function ensureDate(value: Date | string | undefined): Date | undefined {
106
+ if (value === undefined || value === null) {
107
+ return undefined
108
+ }
109
+
110
+ if (value instanceof Date) {
111
+ return value
112
+ }
113
+
114
+ if (typeof value === 'string') {
115
+ if (value.trim() === '') {
116
+ return undefined
117
+ }
118
+
119
+ const date = new Date(value)
120
+ // Check if the date is valid
121
+ if (isNaN(date.getTime())) {
122
+ return undefined
123
+ }
124
+ return date
125
+ }
126
+
127
+ return undefined
128
+ }