@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,43 +1,136 @@
1
- import type { IAgentContext, ICredentialPlugin } from '@veramo/core'
1
+ import type { IAgentContext } from '@veramo/core'
2
2
  import type { IIdentifierResolution } from '@sphereon/ssi-sdk-ext.identifier-resolution'
3
3
  import {
4
- BitstringStatus,
5
4
  CheckStatusIndexArgs,
6
5
  CreateStatusListArgs,
6
+ IMergeDetailsWithEntityArgs,
7
+ IToDetailsFromCredentialArgs,
7
8
  Status2021,
9
+ StatusList2021EntryCredentialStatus,
10
+ StatusListOAuthEntryCredentialStatus,
8
11
  StatusListResult,
9
12
  StatusOAuth,
10
- ToStatusListDetailsArgs,
11
13
  UpdateStatusListFromEncodedListArgs,
12
14
  UpdateStatusListIndexArgs,
13
15
  } from '../types'
16
+ import { BitstringStatusPurpose } from '@4sure-tech/vc-bitstring-status-lists'
17
+ import {
18
+ CredentialProofFormat,
19
+ IIssuer,
20
+ StatusListCredential,
21
+ StatusListDriverType,
22
+ StatusListIndexingDirection,
23
+ StatusListType,
24
+ StatusPurpose2021,
25
+ } from '@sphereon/ssi-types'
26
+ import {
27
+ BitstringStatusListEntryCredentialStatus,
28
+ IBitstringStatusListEntryEntity,
29
+ IStatusListEntryEntity,
30
+ StatusListEntity,
31
+ } from '@sphereon/ssi-sdk.data-store'
32
+ import { IVcdmCredentialPlugin } from '@sphereon/ssi-sdk.credential-vcdm'
33
+ import { DecodedStatusListPayload } from './encoding/common'
34
+
35
+ export interface IExtractedCredentialDetails {
36
+ id: string
37
+ issuer: string | IIssuer
38
+ encodedList: string
39
+ decodedPayload?: DecodedStatusListPayload
40
+ }
14
41
 
15
42
  export interface IStatusList {
16
43
  /**
17
44
  * Creates a new status list of the specific type
18
45
  */
19
- createNewStatusList(args: CreateStatusListArgs, context: IAgentContext<ICredentialPlugin & IIdentifierResolution>): Promise<StatusListResult>
46
+ createNewStatusList(args: CreateStatusListArgs, context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>): Promise<StatusListResult>
20
47
 
21
48
  /**
22
49
  * Updates a status at the given index in the status list
23
50
  */
24
- updateStatusListIndex(args: UpdateStatusListIndexArgs, context: IAgentContext<ICredentialPlugin & IIdentifierResolution>): Promise<StatusListResult>
51
+ updateStatusListIndex(
52
+ args: UpdateStatusListIndexArgs,
53
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
54
+ ): Promise<StatusListResult>
25
55
 
26
56
  /**
27
57
  * Updates a status list using a base64 encoded list of statuses
28
58
  */
29
59
  updateStatusListFromEncodedList(
30
60
  args: UpdateStatusListFromEncodedListArgs,
31
- context: IAgentContext<ICredentialPlugin & IIdentifierResolution>,
61
+ context: IAgentContext<IVcdmCredentialPlugin & IIdentifierResolution>,
32
62
  ): Promise<StatusListResult>
33
63
 
34
64
  /**
35
65
  * Checks the status at a given index in the status list
36
66
  */
37
- checkStatusIndex(args: CheckStatusIndexArgs): Promise<number | Status2021 | StatusOAuth | BitstringStatus>
67
+ checkStatusIndex(args: CheckStatusIndexArgs): Promise<number | Status2021 | StatusOAuth>
68
+
69
+ /**
70
+ * Performs the initial parsing of a StatusListCredential.
71
+ * This method handles expensive operations like JWT/CWT decoding once.
72
+ * It extracts all details available from the credential payload itself.
73
+ */
74
+ extractCredentialDetails(credential: StatusListCredential): Promise<IExtractedCredentialDetails>
75
+
76
+ /**
77
+ * Converts a credential and its known metadata into a full StatusListResult.
78
+ */
79
+ toStatusListDetails(
80
+ args: IToDetailsFromCredentialArgs,
81
+ ): Promise<
82
+ StatusListResult & (IStatusList2021ImplementationResult | IOAuthStatusListImplementationResult | IBitstringStatusListImplementationResult)
83
+ >
38
84
 
39
85
  /**
40
- * Collects the status list details
86
+ * Merges pre-parsed details from a new credential with an existing database entity.
41
87
  */
42
- toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult>
88
+ toStatusListDetails(
89
+ args: IMergeDetailsWithEntityArgs,
90
+ ): Promise<
91
+ StatusListResult & (IStatusList2021ImplementationResult | IOAuthStatusListImplementationResult | IBitstringStatusListImplementationResult)
92
+ >
93
+
94
+ /**
95
+ * Creates a credential status object from a status list and entry
96
+ */
97
+ createCredentialStatus(args: {
98
+ statusList: StatusListEntity
99
+ statusListEntry: IStatusListEntryEntity | IBitstringStatusListEntryEntity
100
+ statusListIndex: number
101
+ }): Promise<StatusList2021EntryCredentialStatus | StatusListOAuthEntryCredentialStatus | BitstringStatusListEntryCredentialStatus>
102
+ }
103
+
104
+ export interface IStatusListImplementationResult {
105
+ id: string
106
+ encodedList: string
107
+ issuer: string | IIssuer
108
+ type: StatusListType
109
+ proofFormat: CredentialProofFormat
110
+ length: number
111
+ statusListCredential: StatusListCredential
112
+ statuslistContentType: string
113
+ correlationId?: string
114
+ driverType?: StatusListDriverType
115
+ }
116
+
117
+ export interface IStatusList2021ImplementationResult extends IStatusListImplementationResult {
118
+ type: StatusListType.StatusList2021
119
+ indexingDirection: StatusListIndexingDirection
120
+ statusPurpose: StatusPurpose2021
121
+ }
122
+
123
+ export interface IOAuthStatusListImplementationResult extends IStatusListImplementationResult {
124
+ type: StatusListType.OAuthStatusList
125
+ bitsPerStatus: number
126
+ expiresAt?: Date
127
+ }
128
+
129
+ export interface IBitstringStatusListImplementationResult extends IStatusListImplementationResult {
130
+ type: StatusListType.BitstringStatusList
131
+ statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
132
+ bitsPerStatus?: number
133
+ validFrom?: Date
134
+ validUntil?: Date
135
+ ttl?: number
43
136
  }
@@ -1,24 +1,28 @@
1
- import type { IAgentContext, ICredentialPlugin, IKeyManager } from '@veramo/core'
1
+ import type { IAgentContext, IKeyManager } from '@veramo/core'
2
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
15
  import { determineProofFormat, ensureDate, getAssertedValue, getAssertedValues } from '../utils'
14
- import type { IStatusList } from './IStatusList'
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
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
@@ -58,7 +62,7 @@ export class OAuthStatusListImplementation implements IStatusList {
58
62
 
59
63
  async updateStatusListIndex(args: UpdateStatusListIndexArgs, context: IRequiredContext): Promise<StatusListResult> {
60
64
  const { statusListCredential, value, keyRef } = args
61
- const expiresAt = ensureDate(oauthStatusList.expiresAt)
65
+ const expiresAt = ensureDate(args.expiresAt)
62
66
  if (typeof statusListCredential !== 'string') {
63
67
  return Promise.reject('statusListCredential in neither JWT nor CWT')
64
68
  }
@@ -144,10 +148,6 @@ export class OAuthStatusListImplementation implements IStatusList {
144
148
  }
145
149
  }
146
150
 
147
- private buildContentType(proofFormat: CredentialProofFormat | undefined) {
148
- return `application/statuslist+${proofFormat === 'cbor' ? 'cwt' : 'jwt'}`
149
- }
150
-
151
151
  async checkStatusIndex(args: CheckStatusIndexArgs): Promise<number | StatusOAuth> {
152
152
  const { statusListCredential, statusListIndex } = args
153
153
  if (typeof statusListCredential !== 'string') {
@@ -165,33 +165,122 @@ export class OAuthStatusListImplementation implements IStatusList {
165
165
  return statusList.getStatus(index)
166
166
  }
167
167
 
168
- async toStatusListDetails(args: ToStatusListDetailsArgs): Promise<StatusListResult> {
169
- const { statusListPayload } = args as { statusListPayload: CompactJWT | CWT }
170
- const proofFormat = determineProofFormat(statusListPayload)
171
- const decoded = proofFormat === 'jwt' ? decodeStatusListJWT(statusListPayload) : decodeStatusListCWT(statusListPayload)
172
- 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)
173
180
 
174
181
  return {
175
- id,
176
- encodedList: statusList.compressStatusList(),
177
- issuer,
178
- type: StatusListType.OAuthStatusList,
179
- proofFormat,
180
- length: statusList.statusList.length,
181
- statusListCredential: statusListPayload,
182
- statuslistContentType: this.buildContentType(proofFormat),
183
- oauthStatusList: {
184
- bitsPerStatus: statusList.getBitsPerStatus(),
185
- ...(exp && { expiresAt: new Date(exp * 1000) }),
186
- },
187
- ...(args.correlationId && { correlationId: args.correlationId }),
188
- ...(args.driverType && { driverType: args.driverType }),
182
+ id: decoded.id,
183
+ issuer: decoded.issuer,
184
+ encodedList: decoded.statusList.compressStatusList(),
185
+ decodedPayload: decoded,
189
186
  }
190
187
  }
191
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
+
192
281
  private async createSignedStatusList(
193
282
  proofFormat: CredentialProofFormat,
194
- context: IAgentContext<ICredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>,
283
+ context: IAgentContext<IVcdmCredentialPlugin & IJwtService & IIdentifierResolution & IKeyManager>,
195
284
  statusList: StatusList,
196
285
  issuerString: string,
197
286
  id: string,
@@ -1,27 +1,29 @@
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
29
  export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
@@ -29,7 +31,7 @@ export const DEFAULT_PROOF_FORMAT = 'lds' as CredentialProofFormat
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')
@@ -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,
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'