@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.
- package/dist/index.cjs +928 -453
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -26
- package/dist/index.d.ts +93 -26
- package/dist/index.js +873 -398
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/statusList.entities.test.ts +58 -1
- package/src/__tests__/statusList.store.test.ts +64 -1
- package/src/entities/statusList/BitstringStatusListEntryEntity.ts +60 -0
- package/src/entities/statusList/StatusList2021EntryEntity.ts +4 -3
- package/src/entities/statusList/StatusListEntities.ts +54 -5
- package/src/index.ts +12 -2
- package/src/migrations/generic/12-CreateBitstringStatusList.ts +52 -0
- package/src/migrations/generic/index.ts +2 -1
- package/src/migrations/postgres/1741895823000-CreateBitstringStatusList.ts +53 -0
- package/src/migrations/sqlite/1741895823001-CreateBitstringStatusList.ts +145 -0
- package/src/statusList/IStatusListStore.ts +14 -11
- package/src/statusList/StatusListStore.ts +72 -33
- package/src/types/index.ts +1 -0
- package/src/types/statusList/IAbstractStatusListStore.ts +39 -4
- package/src/types/statusList/bitstringTypes.ts +7 -0
- package/src/types/statusList/statusList.ts +24 -2
- package/src/utils/statusList/MappingUtils.ts +41 -3
|
@@ -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(
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
}))
|
|
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(
|
|
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<
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
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
|
-
|
|
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
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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 =
|
|
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 {
|
|
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
|
|