@sphereon/ssi-sdk.data-store 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.
@@ -0,0 +1,145 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ export class CreateBitstringStatusListSqlite1741895823001 implements MigrationInterface {
4
+ name = 'CreateBitstringStatusList1741895823000'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ // Update StatusList table to include BitstringStatusList type and columns
8
+ await queryRunner.query(`
9
+ CREATE TABLE "temporary_StatusList" (
10
+ "id" varchar PRIMARY KEY NOT NULL,
11
+ "correlationId" varchar NOT NULL,
12
+ "length" integer NOT NULL,
13
+ "issuer" text NOT NULL,
14
+ "type" varchar CHECK( "type" IN ('StatusList2021', 'OAuthStatusList', 'BitstringStatusList') ) NOT NULL DEFAULT ('StatusList2021'),
15
+ "driverType" varchar CHECK( "driverType" IN ('agent_typeorm','agent_kv_store','github','agent_filesystem') ) NOT NULL DEFAULT ('agent_typeorm'),
16
+ "credentialIdMode" varchar CHECK( "credentialIdMode" IN ('ISSUANCE','PERSISTENCE','NEVER') ) NOT NULL DEFAULT ('ISSUANCE'),
17
+ "proofFormat" varchar CHECK( "proofFormat" IN ('lds','jwt') ) NOT NULL DEFAULT ('lds'),
18
+ "indexingDirection" varchar CHECK( "indexingDirection" IN ('rightToLeft') ),
19
+ "statusPurpose" varchar,
20
+ "statusListCredential" text,
21
+ "expiresAt" datetime,
22
+ "bitsPerStatus" integer DEFAULT (1),
23
+ "ttl" integer,
24
+ "validFrom" datetime,
25
+ "validUntil" datetime,
26
+ CONSTRAINT "UQ_correlationId" UNIQUE ("correlationId")
27
+ )
28
+ `)
29
+
30
+ await queryRunner.query(`
31
+ INSERT INTO "temporary_StatusList"(
32
+ "id", "correlationId", "length", "issuer", "type", "driverType",
33
+ "credentialIdMode", "proofFormat", "indexingDirection", "statusPurpose",
34
+ "statusListCredential", "bitsPerStatus", "expiresAt"
35
+ )
36
+ SELECT
37
+ "id", "correlationId", "length", "issuer", "type", "driverType",
38
+ "credentialIdMode", "proofFormat", "indexingDirection", "statusPurpose",
39
+ "statusListCredential", "bitsPerStatus", "expiresAt"
40
+ FROM "StatusList"
41
+ `)
42
+
43
+ await queryRunner.query(`DROP TABLE "StatusList"`)
44
+ await queryRunner.query(`ALTER TABLE "temporary_StatusList" RENAME TO "StatusList"`)
45
+
46
+ // Update StatusListEntry table with inheritance and bitstring columns
47
+ await queryRunner.query(`
48
+ CREATE TABLE "temporary_StatusListEntry" (
49
+ "statusListId" varchar NOT NULL,
50
+ "statusListIndex" integer NOT NULL,
51
+ "credentialId" text,
52
+ "credentialHash" varchar(128),
53
+ "correlationId" varchar(255),
54
+ "value" varchar(50),
55
+ "type" varchar CHECK( "type" IN ('StatusListEntryEntity', 'bitstring') ) NOT NULL DEFAULT ('StatusListEntryEntity'),
56
+ "statusPurpose" varchar,
57
+ "bitsPerStatus" integer DEFAULT (1),
58
+ "statusMessage" text,
59
+ "statusReference" text,
60
+ PRIMARY KEY ("statusListId", "statusListIndex")
61
+ )
62
+ `)
63
+
64
+ await queryRunner.query(`
65
+ INSERT INTO "temporary_StatusListEntry"(
66
+ "statusListId", "statusListIndex", "credentialId", "credentialHash",
67
+ "correlationId", "value", "type"
68
+ )
69
+ SELECT
70
+ "statusListId", "statusListIndex", "credentialId", "credentialHash",
71
+ "correlationId", "value", 'StatusListEntryEntity'
72
+ FROM "StatusListEntry"
73
+ `)
74
+
75
+ await queryRunner.query(`DROP TABLE "StatusListEntry"`)
76
+ await queryRunner.query(`ALTER TABLE "temporary_StatusListEntry" RENAME TO "StatusListEntry"`)
77
+ }
78
+
79
+ public async down(queryRunner: QueryRunner): Promise<void> {
80
+ // Revert StatusListEntry table changes
81
+ await queryRunner.query(`
82
+ CREATE TABLE "temporary_StatusListEntry" (
83
+ "statusListId" varchar NOT NULL,
84
+ "statusListIndex" integer NOT NULL,
85
+ "credentialId" text,
86
+ "credentialHash" varchar(128),
87
+ "correlationId" varchar(255),
88
+ "value" varchar(50),
89
+ PRIMARY KEY ("statusListId", "statusListIndex")
90
+ )
91
+ `)
92
+
93
+ await queryRunner.query(`
94
+ INSERT INTO "temporary_StatusListEntry"(
95
+ "statusListId", "statusListIndex", "credentialId", "credentialHash",
96
+ "correlationId", "value"
97
+ )
98
+ SELECT
99
+ "statusListId", "statusListIndex", "credentialId", "credentialHash",
100
+ "correlationId", "value"
101
+ FROM "StatusListEntry"
102
+ WHERE "type" = 'StatusListEntryEntity'
103
+ `)
104
+
105
+ await queryRunner.query(`DROP TABLE "StatusListEntry"`)
106
+ await queryRunner.query(`ALTER TABLE "temporary_StatusListEntry" RENAME TO "StatusListEntry"`)
107
+
108
+ // Revert StatusList table changes
109
+ await queryRunner.query(`
110
+ CREATE TABLE "temporary_StatusList" (
111
+ "id" varchar PRIMARY KEY NOT NULL,
112
+ "correlationId" varchar NOT NULL,
113
+ "length" integer NOT NULL,
114
+ "issuer" text NOT NULL,
115
+ "type" varchar CHECK( "type" IN ('StatusList2021', 'OAuthStatusList') ) NOT NULL DEFAULT ('StatusList2021'),
116
+ "driverType" varchar CHECK( "driverType" IN ('agent_typeorm','agent_kv_store','github','agent_filesystem') ) NOT NULL DEFAULT ('agent_typeorm'),
117
+ "credentialIdMode" varchar CHECK( "credentialIdMode" IN ('ISSUANCE','PERSISTENCE','NEVER') ) NOT NULL DEFAULT ('ISSUANCE'),
118
+ "proofFormat" varchar CHECK( "proofFormat" IN ('lds','jwt') ) NOT NULL DEFAULT ('lds'),
119
+ "indexingDirection" varchar CHECK( "indexingDirection" IN ('rightToLeft') ),
120
+ "statusPurpose" varchar,
121
+ "statusListCredential" text,
122
+ "bitsPerStatus" integer,
123
+ "expiresAt" datetime,
124
+ CONSTRAINT "UQ_correlationId" UNIQUE ("correlationId")
125
+ )
126
+ `)
127
+
128
+ await queryRunner.query(`
129
+ INSERT INTO "temporary_StatusList"(
130
+ "id", "correlationId", "length", "issuer", "type", "driverType",
131
+ "credentialIdMode", "proofFormat", "indexingDirection", "statusPurpose",
132
+ "statusListCredential", "bitsPerStatus", "expiresAt"
133
+ )
134
+ SELECT
135
+ "id", "correlationId", "length", "issuer",
136
+ CASE WHEN "type" = 'BitstringStatusList' THEN 'StatusList2021' ELSE "type" END,
137
+ "driverType", "credentialIdMode", "proofFormat", "indexingDirection",
138
+ "statusPurpose", "statusListCredential", "bitsPerStatus", "expiresAt"
139
+ FROM "StatusList"
140
+ `)
141
+
142
+ await queryRunner.query(`DROP TABLE "StatusList"`)
143
+ await queryRunner.query(`ALTER TABLE "temporary_StatusList" RENAME TO "StatusList"`)
144
+ }
145
+ }
@@ -2,6 +2,8 @@ import { StatusListEntryEntity } from '../entities/statusList/StatusList2021Entr
2
2
  import type {
3
3
  IAddStatusListArgs,
4
4
  IAddStatusListEntryArgs,
5
+ IBitstringStatusListEntity,
6
+ IBitstringStatusListEntryEntity,
5
7
  IGetStatusListArgs,
6
8
  IGetStatusListEntriesArgs,
7
9
  IGetStatusListEntryByCredentialIdArgs,
@@ -12,33 +14,34 @@ import type {
12
14
  IUpdateStatusListIndexArgs,
13
15
  } from '../types'
14
16
  import { IStatusListEntity, IStatusListEntryEntity } from '../types'
17
+ import { BitstringStatusListEntryEntity } from '../entities/statusList/BitstringStatusListEntryEntity'
15
18
 
16
19
  export interface IStatusListStore {
17
- getStatusList(args: IGetStatusListArgs): Promise<IStatusListEntity>
20
+ getStatusList(args: IGetStatusListArgs): Promise<IStatusListEntity | IBitstringStatusListEntity>
18
21
 
19
- getStatusLists(args: IGetStatusListsArgs): Promise<Array<IStatusListEntity>>
22
+ getStatusLists(args: IGetStatusListsArgs): Promise<Array<IStatusListEntity | IBitstringStatusListEntity>>
20
23
 
21
24
  removeStatusList(args: IRemoveStatusListArgs): Promise<boolean>
22
25
 
23
- addStatusList(args: IAddStatusListArgs): Promise<IStatusListEntity>
26
+ addStatusList(args: IAddStatusListArgs): Promise<IStatusListEntity | IBitstringStatusListEntity>
24
27
 
25
- updateStatusList(args: IUpdateStatusListIndexArgs): Promise<IStatusListEntity>
28
+ updateStatusList(args: IUpdateStatusListIndexArgs): Promise<IStatusListEntity | IBitstringStatusListEntity>
26
29
 
27
30
  availableStatusListEntries(args: IStatusListEntryAvailableArgs): Promise<number[]>
28
31
 
29
- addStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity>
32
+ addStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity | IBitstringStatusListEntryEntity>
30
33
 
31
- updateStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity>
34
+ updateStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity | IBitstringStatusListEntryEntity>
32
35
 
33
- getStatusListEntryByIndex(args: IGetStatusListEntryByIndexArgs): Promise<StatusListEntryEntity | undefined>
36
+ getStatusListEntryByIndex(args: IGetStatusListEntryByIndexArgs): Promise<StatusListEntryEntity | BitstringStatusListEntryEntity | undefined>
34
37
 
35
- getStatusListEntryByCredentialId(args: IGetStatusListEntryByCredentialIdArgs): Promise<StatusListEntryEntity | undefined>
38
+ getStatusListEntryByCredentialId(
39
+ args: IGetStatusListEntryByCredentialIdArgs,
40
+ ): Promise<StatusListEntryEntity | BitstringStatusListEntryEntity | undefined>
36
41
 
37
42
  removeStatusListEntryByIndex(args: IGetStatusListEntryByIndexArgs): Promise<boolean>
38
43
 
39
44
  removeStatusListEntryByCredentialId(args: IGetStatusListEntryByCredentialIdArgs): Promise<boolean>
40
45
 
41
- getStatusListEntries(args: IGetStatusListEntriesArgs): Promise<IStatusListEntryEntity[]>
42
-
43
- getStatusList(args: IGetStatusListArgs): Promise<IStatusListEntity>
46
+ getStatusListEntries(args: IGetStatusListEntriesArgs): Promise<Array<IStatusListEntryEntity | IBitstringStatusListEntryEntity>>
44
47
  }
@@ -1,11 +1,14 @@
1
1
  import { type OrPromise, StatusListType } from '@sphereon/ssi-types'
2
2
  import Debug from 'debug'
3
3
  import { DataSource, In, type Repository } from 'typeorm'
4
- import { OAuthStatusListEntity, StatusList2021Entity, StatusListEntity } from '../entities/statusList/StatusListEntities'
4
+ import { BitstringStatusListEntity, OAuthStatusListEntity, StatusList2021Entity, StatusListEntity } from '../entities/statusList/StatusListEntities'
5
5
  import { StatusListEntryEntity } from '../entities/statusList/StatusList2021EntryEntity'
6
- import type {
6
+ import { BitstringStatusListEntryEntity } from '../entities/statusList/BitstringStatusListEntryEntity'
7
+ import {
7
8
  IAddStatusListArgs,
8
9
  IAddStatusListEntryArgs,
10
+ IBitstringStatusListEntity,
11
+ IBitstringStatusListEntryEntity,
9
12
  IGetStatusListArgs,
10
13
  IGetStatusListEntriesArgs,
11
14
  IGetStatusListEntryByCredentialIdArgs,
@@ -41,11 +44,11 @@ export class StatusListStore implements IStatusListStore {
41
44
  async availableStatusListEntries(args: IStatusListEntryAvailableArgs): Promise<number[]> {
42
45
  const statusListIndex = Array.isArray(args.statusListIndex) ? args.statusListIndex : [args.statusListIndex]
43
46
  const statusList = await this.getStatusList({ ...args, id: args.statusListId })
44
- const repo = await this.getStatusListEntryRepo()
47
+ const repo = await this.getStatusListEntryRepo(statusList.type)
45
48
  const results = (
46
49
  await repo.find({
47
50
  where: {
48
- statusList,
51
+ statusListId: statusList.id,
49
52
  statusListIndex: In(statusListIndex),
50
53
  },
51
54
  })
@@ -53,23 +56,33 @@ export class StatusListStore implements IStatusListStore {
53
56
  return statusListIndex.filter((index) => !results.includes(index))
54
57
  }
55
58
 
56
- async addStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity> {
57
- return (await this.getStatusListEntryRepo()).save(args)
59
+ async addStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity | IBitstringStatusListEntryEntity> {
60
+ if (!args.statusListId) {
61
+ throw new Error('statusListId is required')
62
+ }
63
+
64
+ const statusList = await this.getStatusList({ id: args.statusListId })
65
+ const result = await (await this.getStatusListEntryRepo(statusList.type)).save(args)
66
+ return result as IStatusListEntryEntity | IBitstringStatusListEntryEntity
58
67
  }
59
68
 
60
- async updateStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity> {
61
- const statusListId = args.statusListId ?? args.statusList?.id
69
+ async updateStatusListEntry(args: IAddStatusListEntryArgs): Promise<IStatusListEntryEntity | IBitstringStatusListEntryEntity> {
70
+ const statusListId = args.statusListId
71
+ if (!statusListId) {
72
+ throw new Error('statusListId is required')
73
+ }
74
+
75
+ const statusList = await this.getStatusList({ id: statusListId })
62
76
  const result = await this.getStatusListEntryByIndex({ ...args, statusListId, errorOnNotFound: false })
63
77
  const updatedEntry: Partial<IStatusListEntryEntity> = {
64
- value: args.value,
65
- correlationId: args.correlationId,
66
- credentialHash: args.credentialHash,
67
- credentialId: args.credentialId,
78
+ ...result,
79
+ ...args,
80
+ statusListId,
68
81
  }
69
82
 
70
83
  const updStatusListId = result?.statusListId ?? statusListId
71
84
  const updateResult = await (
72
- await this.getStatusListEntryRepo()
85
+ await this.getStatusListEntryRepo(statusList.type)
73
86
  ).upsert(
74
87
  { ...(result ?? { statusListId: updStatusListId, statusListIndex: args.statusListIndex }), ...updatedEntry },
75
88
  { conflictPaths: ['statusList', 'statusListIndex'] },
@@ -79,7 +92,7 @@ export class StatusListStore implements IStatusListStore {
79
92
  ...args,
80
93
  statusListId: updStatusListId,
81
94
  errorOnNotFound: true,
82
- })) as IStatusListEntryEntity
95
+ }))!
83
96
  }
84
97
 
85
98
  async getStatusListEntryByIndex({
@@ -88,7 +101,7 @@ export class StatusListStore implements IStatusListStore {
88
101
  statusListIndex,
89
102
  entryCorrelationId,
90
103
  errorOnNotFound,
91
- }: IGetStatusListEntryByIndexArgs): Promise<StatusListEntryEntity | undefined> {
104
+ }: IGetStatusListEntryByIndexArgs): Promise<StatusListEntryEntity | BitstringStatusListEntryEntity | undefined> {
92
105
  if (!statusListId && !statusListCorrelationId) {
93
106
  throw Error(`Cannot get statusList entry without either a statusList id or statusListCorrelationId`)
94
107
  }
@@ -97,8 +110,12 @@ export class StatusListStore implements IStatusListStore {
97
110
  throw Error(`Cannot get statusList entry without either a statusListIndex or entryCorrelationId`)
98
111
  }
99
112
 
113
+ const statusList = statusListId
114
+ ? await this.getStatusList({ id: statusListId })
115
+ : await this.getStatusList({ correlationId: statusListCorrelationId })
116
+
100
117
  const result = await (
101
- await this.getStatusListEntryRepo()
118
+ await this.getStatusListEntryRepo(statusList.type)
102
119
  ).findOne({
103
120
  where: {
104
121
  ...(statusListId && { statusListId }),
@@ -118,7 +135,9 @@ export class StatusListStore implements IStatusListStore {
118
135
  return result ?? undefined
119
136
  }
120
137
 
121
- async getStatusListEntryByCredentialId(args: IGetStatusListEntryByCredentialIdArgs): Promise<StatusListEntryEntity | undefined> {
138
+ async getStatusListEntryByCredentialId(
139
+ args: IGetStatusListEntryByCredentialIdArgs,
140
+ ): Promise<StatusListEntryEntity | BitstringStatusListEntryEntity | undefined> {
122
141
  const credentialId = args.credentialId
123
142
  if (!credentialId) {
124
143
  throw Error('Can only get a credential by credentialId when a credentialId is supplied')
@@ -132,8 +151,8 @@ export class StatusListStore implements IStatusListStore {
132
151
  ...(args.entryCorrelationId && { correlationId: args.entryCorrelationId }),
133
152
  credentialId,
134
153
  }
135
- console.log(`Entries: ${JSON.stringify(await (await this.getStatusListEntryRepo()).find(), null, 2)}`)
136
- const result = await (await this.getStatusListEntryRepo()).findOne({ where })
154
+ console.log(`Entries: ${JSON.stringify(await (await this.getStatusListEntryRepo(statusList.type)).find(), null, 2)}`)
155
+ const result = await (await this.getStatusListEntryRepo(statusList.type)).findOne({ where })
137
156
 
138
157
  if (!result && args.errorOnNotFound) {
139
158
  throw Error(`Could not find status list credential id ${credentialId} for status list id ${statusList.id}`)
@@ -149,8 +168,12 @@ export class StatusListStore implements IStatusListStore {
149
168
  error = true
150
169
  }
151
170
  if (!error) {
171
+ const statusList = await this.getStatusList({
172
+ id: args.statusListId,
173
+ correlationId: args.statusListCorrelationId,
174
+ })
152
175
  const result = await (
153
- await this.getStatusListEntryRepo()
176
+ await this.getStatusListEntryRepo(statusList.type)
154
177
  ).delete({
155
178
  ...(args.statusListId && { statusList: args.statusListId }),
156
179
  ...(args.entryCorrelationId && { correlationId: args.entryCorrelationId }),
@@ -171,8 +194,9 @@ export class StatusListStore implements IStatusListStore {
171
194
  if (error) {
172
195
  console.log(`Could not delete statusList ${args.statusListId} entry by index ${args.statusListIndex}`)
173
196
  } else {
197
+ const statusList = await this.getStatusList({ id: args.statusListId })
174
198
  const result = await (
175
- await this.getStatusListEntryRepo()
199
+ await this.getStatusListEntryRepo(statusList.type)
176
200
  ).delete({
177
201
  ...(args.statusListId && { statusList: args.statusListId }),
178
202
  ...(args.entryCorrelationId && { correlationId: args.entryCorrelationId }),
@@ -183,12 +207,14 @@ export class StatusListStore implements IStatusListStore {
183
207
  return !error
184
208
  }
185
209
 
186
- async getStatusListEntries(args: IGetStatusListEntriesArgs): Promise<StatusListEntryEntity[]> {
187
- return (await this.getStatusListEntryRepo()).find({ where: { ...args?.filter, statusList: args.statusListId } })
188
- }
189
-
190
- async getStatusList(args: IGetStatusListArgs): Promise<IStatusListEntity> {
191
- return statusListFrom(await this.getStatusListEntity(args))
210
+ async getStatusListEntries(args: IGetStatusListEntriesArgs): Promise<Array<IStatusListEntryEntity | IBitstringStatusListEntryEntity>> {
211
+ const statusList = await this.getStatusList({ id: args.statusListId })
212
+ const results = await (
213
+ await this.getStatusListEntryRepo(statusList.type)
214
+ ).find({
215
+ where: { ...args?.filter, statusList: args.statusListId },
216
+ })
217
+ return results as Array<IStatusListEntryEntity | IBitstringStatusListEntryEntity>
192
218
  }
193
219
 
194
220
  private async getStatusListEntity(args: IGetStatusListArgs): Promise<StatusListEntity> {
@@ -208,7 +234,12 @@ export class StatusListStore implements IStatusListStore {
208
234
  return result
209
235
  }
210
236
 
211
- async getStatusLists(args: IGetStatusListsArgs): Promise<Array<IStatusListEntity>> {
237
+ async getStatusList(args: IGetStatusListArgs): Promise<IStatusListEntity | IBitstringStatusListEntity> {
238
+ const entity = await this.getStatusListEntity(args)
239
+ return statusListFrom(entity) as IStatusListEntity | IBitstringStatusListEntity
240
+ }
241
+
242
+ async getStatusLists(args: IGetStatusListsArgs): Promise<Array<IStatusListEntity | IBitstringStatusListEntity>> {
212
243
  const result = await (
213
244
  await this.getStatusListRepo()
214
245
  ).find({
@@ -219,7 +250,7 @@ export class StatusListStore implements IStatusListStore {
219
250
  return []
220
251
  }
221
252
 
222
- return result.map((entity) => statusListFrom(entity))
253
+ return result.map((entity) => statusListFrom(entity) as IStatusListEntity | IBitstringStatusListEntity)
223
254
  }
224
255
 
225
256
  async addStatusList(args: IAddStatusListArgs): Promise<IStatusListEntity> {
@@ -240,7 +271,7 @@ export class StatusListStore implements IStatusListStore {
240
271
  return statusListFrom(createdResult)
241
272
  }
242
273
 
243
- async updateStatusList(args: IUpdateStatusListIndexArgs): Promise<IStatusListEntity> {
274
+ async updateStatusList(args: IUpdateStatusListIndexArgs): Promise<IStatusListEntity | IBitstringStatusListEntity> {
244
275
  const result = await this.getStatusList(args)
245
276
  debug('Updating status list', result)
246
277
  const entity = statusListEntityFrom(args)
@@ -251,7 +282,7 @@ export class StatusListStore implements IStatusListStore {
251
282
  async removeStatusList(args: IRemoveStatusListArgs): Promise<boolean> {
252
283
  const result = await this.getStatusListEntity(args)
253
284
 
254
- await (await this.getStatusListEntryRepo()).delete({ statusListId: result.id })
285
+ await (await this.getStatusListEntryRepo(result.type)).delete({ statusListId: result.id })
255
286
  const deletedEntity = await (await this.getStatusListRepo()).remove(result)
256
287
 
257
288
  return Boolean(deletedEntity)
@@ -268,12 +299,20 @@ export class StatusListStore implements IStatusListStore {
268
299
  return dataSource.getRepository(StatusList2021Entity)
269
300
  case StatusListType.OAuthStatusList:
270
301
  return dataSource.getRepository(OAuthStatusListEntity)
302
+ case StatusListType.BitstringStatusList:
303
+ return dataSource.getRepository(BitstringStatusListEntity)
271
304
  default:
272
305
  return dataSource.getRepository(StatusListEntity)
273
306
  }
274
307
  }
275
308
 
276
- async getStatusListEntryRepo(): Promise<Repository<StatusListEntryEntity>> {
277
- return (await this.getDS()).getRepository(StatusListEntryEntity)
309
+ async getStatusListEntryRepo(type?: StatusListType): Promise<Repository<StatusListEntryEntity | BitstringStatusListEntryEntity>> {
310
+ const dataSource = await this.getDS()
311
+ switch (type) {
312
+ case StatusListType.BitstringStatusList:
313
+ return dataSource.getRepository(BitstringStatusListEntryEntity)
314
+ default:
315
+ return dataSource.getRepository(StatusListEntryEntity)
316
+ }
278
317
  }
279
318
  }
@@ -6,6 +6,7 @@ export * from './presentationDefinition/presentationDefinition'
6
6
  export * from './presentationDefinition/IAbstractPDStore'
7
7
  export * from './validation/validation'
8
8
  export * from './statusList/statusList'
9
+ export * from './statusList/bitstringTypes'
9
10
  export * from './statusList/IAbstractStatusListStore'
10
11
  export * from './eventLogger/IAbstractEventLoggerStore'
11
12
  export * from './eventLogger/eventLogger'
@@ -1,5 +1,16 @@
1
1
  import { FindOptionsWhere } from 'typeorm'
2
- import { IOAuthStatusListEntity, IStatusList2021Entity, IStatusListEntity, IStatusListEntryEntity } from './statusList'
2
+ import { IBitstringStatusListEntryEntity, IOAuthStatusListEntity, IStatusList2021Entity, IStatusListEntryEntity } from './statusList'
3
+ import {
4
+ CredentialProofFormat,
5
+ IIssuer,
6
+ StatusListCredential,
7
+ StatusListCredentialIdMode,
8
+ StatusListDriverType,
9
+ StatusListIndexingDirection,
10
+ StatusListType,
11
+ StatusPurpose2021,
12
+ } from '@sphereon/ssi-types'
13
+ import { BitstringStatusPurpose } from './bitstringTypes'
3
14
 
4
15
  export type FindStatusListArgs = FindOptionsWhere<IStatusList2021Entity | IOAuthStatusListEntity>[]
5
16
  export type FindStatusListEntryArgs = FindOptionsWhere<IStatusListEntryEntity>[] | FindOptionsWhere<IStatusListEntryEntity>
@@ -30,7 +41,7 @@ export interface IGetStatusListEntriesArgs {
30
41
  filter?: FindStatusListEntryArgs
31
42
  }
32
43
 
33
- export type IAddStatusListEntryArgs = IStatusListEntryEntity
44
+ export type IAddStatusListEntryArgs = IStatusListEntryEntity | IBitstringStatusListEntryEntity
34
45
 
35
46
  export interface IGetStatusListArgs {
36
47
  id?: string
@@ -43,6 +54,30 @@ export interface IGetStatusListsArgs {
43
54
  filter?: FindStatusListArgs
44
55
  }
45
56
 
46
- export type IAddStatusListArgs = IStatusListEntity
57
+ interface IBaseStatusListArgs {
58
+ id: string
59
+ correlationId: string
60
+ driverType: StatusListDriverType
61
+ credentialIdMode: StatusListCredentialIdMode
62
+ length: number
63
+ issuer: string | IIssuer
64
+ type: StatusListType
65
+ proofFormat: CredentialProofFormat
66
+ statusListCredential?: StatusListCredential
67
+ bitsPerStatus?: number
68
+ }
69
+
70
+ // Then extend for specific types when needed
71
+ export type IAddStatusListArgs =
72
+ | (IBaseStatusListArgs & { type: StatusListType.StatusList2021; indexingDirection: StatusListIndexingDirection; statusPurpose: StatusPurpose2021 })
73
+ | (IBaseStatusListArgs & { type: StatusListType.OAuthStatusList; bitsPerStatus: number; expiresAt?: Date })
74
+ | (IBaseStatusListArgs & {
75
+ type: StatusListType.BitstringStatusList
76
+ statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
77
+ bitsPerStatus?: number
78
+ validFrom?: Date
79
+ validUntil?: Date
80
+ ttl?: number
81
+ })
47
82
 
48
- export type IUpdateStatusListIndexArgs = IStatusListEntity
83
+ export type IUpdateStatusListIndexArgs = IAddStatusListArgs
@@ -0,0 +1,7 @@
1
+ export type BitstringStatusPurpose = 'revocation' | 'suspension' | 'refresh' | 'message' | string // From vc-bitstring-status-lists without pulling in the whole dep for just this one type
2
+
3
+ export type BitstringStatus = {
4
+ status: string
5
+ message?: string
6
+ [x: string]: any
7
+ }
@@ -1,15 +1,16 @@
1
1
  import {
2
+ type CredentialProofFormat,
2
3
  IIssuer,
4
+ RequireOneOf,
3
5
  StatusListCredential,
4
6
  StatusListCredentialIdMode,
5
7
  StatusListDriverType,
6
8
  StatusListIndexingDirection,
7
9
  StatusListType,
8
10
  StatusPurpose2021,
9
- type CredentialProofFormat,
10
- RequireOneOf,
11
11
  } from '@sphereon/ssi-types'
12
12
  import { StatusListEntity } from '../../entities/statusList/StatusListEntities'
13
+ import { BitstringStatus, BitstringStatusPurpose } from './bitstringTypes'
13
14
 
14
15
  export interface IStatusListEntity {
15
16
  id: string
@@ -21,6 +22,7 @@ export interface IStatusListEntity {
21
22
  type: StatusListType
22
23
  proofFormat: CredentialProofFormat
23
24
  statusListCredential?: StatusListCredential
25
+ bitsPerStatus?: number
24
26
  }
25
27
 
26
28
  export interface IStatusList2021Entity extends IStatusListEntity {
@@ -33,6 +35,26 @@ export interface IOAuthStatusListEntity extends IStatusListEntity {
33
35
  expiresAt?: Date
34
36
  }
35
37
 
38
+ export interface IBitstringStatusListEntity extends IStatusListEntity {
39
+ statusPurpose: BitstringStatusPurpose | BitstringStatusPurpose[]
40
+ bitsPerStatus?: number
41
+ validFrom?: Date
42
+ validUntil?: Date
43
+ ttl?: number
44
+ }
45
+
46
+ export interface IBitstringStatusListEntryEntity {
47
+ statusListId: string
48
+ statusListIndex: number
49
+ credentialId?: string
50
+ credentialHash?: string
51
+ entryCorrelationId?: string
52
+ statusPurpose: string
53
+ bitsPerStatus?: number
54
+ statusMessage?: Array<BitstringStatus>
55
+ statusReference?: string | string[]
56
+ }
57
+
36
58
  export type IStatusListEntryEntity = RequireOneOf<
37
59
  {
38
60
  statusList: StatusListEntity
@@ -1,5 +1,10 @@
1
- import { IOAuthStatusListEntity, IStatusList2021Entity, IStatusListEntity } from '../../types'
2
- import { OAuthStatusListEntity, StatusList2021Entity, StatusListEntity } from '../../entities/statusList/StatusListEntities'
1
+ import { IBitstringStatusListEntity, IOAuthStatusListEntity, IStatusList2021Entity, IStatusListEntity } from '../../types'
2
+ import {
3
+ BitstringStatusListEntity,
4
+ OAuthStatusListEntity,
5
+ StatusList2021Entity,
6
+ StatusListEntity,
7
+ } from '../../entities/statusList/StatusListEntities'
3
8
  import { StatusListType } from '@sphereon/ssi-types'
4
9
  import { replaceNullWithUndefined } from '../FormattingUtils'
5
10
 
@@ -32,10 +37,31 @@ export const statusListEntityFrom = (args: IStatusListEntity): StatusListEntity
32
37
  return entity
33
38
  }
34
39
 
40
+ if (args.type === StatusListType.BitstringStatusList) {
41
+ const entity = new BitstringStatusListEntity()
42
+ const bitstringsl = args as IBitstringStatusListEntity
43
+ if (!bitstringsl.bitsPerStatus) {
44
+ throw Error('bitsPerStatus must be set for BitstringStatusList')
45
+ }
46
+
47
+ entity.statusPurpose = bitstringsl.statusPurpose
48
+ entity.bitsPerStatus = bitstringsl.bitsPerStatus
49
+ entity.validFrom = bitstringsl.validFrom
50
+ entity.validUntil = bitstringsl.validUntil
51
+ entity.ttl = bitstringsl.ttl
52
+ setBaseFields(entity, args)
53
+ Object.defineProperty(entity, 'type', {
54
+ value: StatusListType.BitstringStatusList,
55
+ enumerable: true,
56
+ configurable: true,
57
+ })
58
+ return entity
59
+ }
60
+
35
61
  throw new Error(`Invalid status list type ${args.type}`)
36
62
  }
37
63
 
38
- export const statusListFrom = (entity: StatusListEntity): IStatusListEntity => {
64
+ export const statusListFrom = (entity: StatusListEntity): IStatusListEntity | IBitstringStatusListEntity => {
39
65
  if (entity instanceof StatusList2021Entity) {
40
66
  const result: IStatusList2021Entity = {
41
67
  ...getBaseFields(entity),
@@ -56,6 +82,18 @@ export const statusListFrom = (entity: StatusListEntity): IStatusListEntity => {
56
82
  return replaceNullWithUndefined(result)
57
83
  }
58
84
 
85
+ if (entity instanceof BitstringStatusListEntity) {
86
+ const result: IBitstringStatusListEntity = {
87
+ ...getBaseFields(entity),
88
+ type: StatusListType.BitstringStatusList,
89
+ statusPurpose: entity.statusPurpose,
90
+ bitsPerStatus: entity.bitsPerStatus,
91
+ validFrom: entity.validFrom,
92
+ validUntil: entity.validUntil,
93
+ ttl: entity.ttl,
94
+ }
95
+ return replaceNullWithUndefined(result)
96
+ }
59
97
  throw new Error(`Invalid status list type ${typeof entity}`)
60
98
  }
61
99