@sphereon/ssi-sdk.data-store 0.38.0 → 0.38.1-next.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sphereon/ssi-sdk.data-store",
3
- "version": "0.38.0",
3
+ "version": "0.38.1-next.3+da87d17a",
4
4
  "source": "src/index.ts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -28,12 +28,12 @@
28
28
  "dependencies": {
29
29
  "@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26",
30
30
  "@sphereon/pex": "5.0.0-unstable.28",
31
- "@sphereon/ssi-sdk-ext.did-utils": "0.38.0",
32
- "@sphereon/ssi-sdk-ext.identifier-resolution": "0.38.0",
33
- "@sphereon/ssi-sdk.agent-config": "0.38.0",
34
- "@sphereon/ssi-sdk.core": "0.38.0",
35
- "@sphereon/ssi-sdk.data-store-types": "0.38.0",
36
- "@sphereon/ssi-types": "0.38.0",
31
+ "@sphereon/ssi-sdk-ext.did-utils": "0.38.1-next.3+da87d17a",
32
+ "@sphereon/ssi-sdk-ext.identifier-resolution": "0.38.1-next.3+da87d17a",
33
+ "@sphereon/ssi-sdk.agent-config": "0.38.1-next.3+da87d17a",
34
+ "@sphereon/ssi-sdk.core": "0.38.1-next.3+da87d17a",
35
+ "@sphereon/ssi-sdk.data-store-types": "0.38.1-next.3+da87d17a",
36
+ "@sphereon/ssi-types": "0.38.1-next.3+da87d17a",
37
37
  "@veramo/core": "4.2.0",
38
38
  "@veramo/data-store": "4.2.0",
39
39
  "@veramo/utils": "4.2.0",
@@ -67,5 +67,5 @@
67
67
  "PostgreSQL",
68
68
  "Contact Store"
69
69
  ],
70
- "gitHead": "a93cb5bf52d46acaf3b2b2d8eba83cc88aa5cda4"
70
+ "gitHead": "da87d17a9e92168943cc846da4b93dc27d1b5590"
71
71
  }
@@ -359,6 +359,32 @@ describe('Database entities tests', (): void => {
359
359
  expect(result.verifiedState).toEqual(CredentialStateType.VERIFIED)
360
360
  })
361
361
 
362
+ it('should update stored digital credential state to SUSPENDED and persist statusLastCheckedAt', async (): Promise<void> => {
363
+ const rawCredential: string =
364
+ 'eyJraWQiOiJkaWQ6a2V5Ono2TWtyaGt5M3B1c20yNk1laUZhWFUzbjJuZWtyYW13RlVtZ0dyZUdHa0RWNnpRaiN6Nk1rcmhreTNwdXNtMjZNZWlGYVhVM24ybmVrcmFtd0ZVbWdHcmVHR2tEVjZ6UWoiLCJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc3BoZXJlb24tb3BlbnNvdXJjZS5naXRodWIuaW8vc3NpLW1vYmlsZS13YWxsZXQvY29udGV4dC9zcGhlcmVvbi13YWxsZXQtaWRlbnRpdHktdjEuanNvbmxkIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJTcGhlcmVvbldhbGxldElkZW50aXR5Q3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJmaXJzdE5hbWUiOiJTIiwibGFzdE5hbWUiOiJLIiwiZW1haWxBZGRyZXNzIjoic0BrIn19LCJzdWIiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJqdGkiOiJ1cm46dXVpZDpkZGE3YmYyNC04ZTdhLTQxZjgtYjY2Yy1hNDhkYmM1YjEwZmEiLCJuYmYiOjE3MDg0NDA4MDgsImlzcyI6ImRpZDprZXk6ejZNa3Joa3kzcHVzbTI2TWVpRmFYVTNuMm5la3JhbXdGVW1nR3JlR0drRFY2elFqIn0.G0M84XVAxSmzGY-NQuB9NBofNrINSn6lvxW6761Vlq6ypvYgtc2xNdpiRmw8ryVNfnpzrr4Z5cB1RlrC05rJAw'
365
+ const digitalCredential: AddCredentialArgs = {
366
+ rawDocument: rawCredential,
367
+ kmsKeyRef: 'testRef',
368
+ identifierMethod: 'did',
369
+ issuerCorrelationType: CredentialCorrelationType.DID,
370
+ subjectCorrelationType: CredentialCorrelationType.DID,
371
+ issuerCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj',
372
+ subjectCorrelationId: 'did:key:z6Mkrhky3pusm26MeiFaXU3n2nekramwFUmgGreGGkDV6zQj',
373
+ credentialRole: CredentialRole.HOLDER,
374
+ }
375
+
376
+ const savedDigitalCredential: DigitalCredential = await digitalCredentialStore.addCredential(digitalCredential)
377
+
378
+ const checkedAt = new Date()
379
+ const result = await digitalCredentialStore.updateCredential({
380
+ id: savedDigitalCredential.id,
381
+ verifiedState: CredentialStateType.SUSPENDED,
382
+ statusLastCheckedAt: checkedAt,
383
+ })
384
+ expect(result.verifiedState).toEqual(CredentialStateType.SUSPENDED)
385
+ expect(result.statusLastCheckedAt?.getTime()).toEqual(checkedAt.getTime())
386
+ })
387
+
362
388
  // Add these test cases to digitalCredential.store.test.ts after the existing update tests
363
389
 
364
390
  it('should update digital credential fields', async (): Promise<void> => {
@@ -105,4 +105,7 @@ export class DigitalCredentialEntity extends BaseEntity implements DigitalCreden
105
105
 
106
106
  @Column({ name: 'revoked_at', nullable: true, type: typeOrmDateTime() })
107
107
  revokedAt?: Date
108
+
109
+ @Column({ name: 'status_last_checked_at', nullable: true, type: typeOrmDateTime() })
110
+ statusLastCheckedAt?: Date
108
111
  }
@@ -0,0 +1,66 @@
1
+ import Debug, { Debugger } from 'debug'
2
+ import { DatabaseType, MigrationInterface, QueryRunner } from 'typeorm'
3
+ import { AddCredentialStatusFields1780000000001 } from '../postgres/1780000000001-AddCredentialStatusFields'
4
+ import { AddCredentialStatusFields1780000000002 } from '../sqlite/1780000000002-AddCredentialStatusFields'
5
+
6
+ const debug: Debugger = Debug('sphereon:ssi-sdk:migrations')
7
+
8
+ export class AddCredentialStatusFields1780000000000 implements MigrationInterface {
9
+ name: string = 'AddCredentialStatusFields1780000000000'
10
+
11
+ public async up(queryRunner: QueryRunner): Promise<void> {
12
+ debug('migration: adding credential status fields to DigitalCredential table')
13
+ const dbType: DatabaseType = queryRunner.connection.driver.options.type
14
+
15
+ switch (dbType) {
16
+ case 'postgres': {
17
+ debug('using postgres migration file for AddCredentialStatusFields')
18
+ const mig: AddCredentialStatusFields1780000000001 = new AddCredentialStatusFields1780000000001()
19
+ await mig.up(queryRunner)
20
+ debug('Postgres migration statements for AddCredentialStatusFields executed')
21
+ return
22
+ }
23
+ case 'sqlite':
24
+ case 'expo':
25
+ case 'react-native': {
26
+ debug('using sqlite/react-native migration file for AddCredentialStatusFields')
27
+ const mig: AddCredentialStatusFields1780000000002 = new AddCredentialStatusFields1780000000002()
28
+ await mig.up(queryRunner)
29
+ debug('SQLite migration statements for AddCredentialStatusFields executed')
30
+ return
31
+ }
32
+ default:
33
+ return Promise.reject(
34
+ `Migrations are currently only supported for sqlite, react-native, expo, and postgres for AddCredentialStatusFields. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`,
35
+ )
36
+ }
37
+ }
38
+
39
+ public async down(queryRunner: QueryRunner): Promise<void> {
40
+ debug('migration: reverting credential status fields from DigitalCredential table')
41
+ const dbType: DatabaseType = queryRunner.connection.driver.options.type
42
+
43
+ switch (dbType) {
44
+ case 'postgres': {
45
+ debug('using postgres migration file for AddCredentialStatusFields')
46
+ const mig: AddCredentialStatusFields1780000000001 = new AddCredentialStatusFields1780000000001()
47
+ await mig.down(queryRunner)
48
+ debug('Postgres migration statements for AddCredentialStatusFields reverted')
49
+ return
50
+ }
51
+ case 'sqlite':
52
+ case 'expo':
53
+ case 'react-native': {
54
+ debug('using sqlite/react-native migration file for AddCredentialStatusFields')
55
+ const mig: AddCredentialStatusFields1780000000002 = new AddCredentialStatusFields1780000000002()
56
+ await mig.down(queryRunner)
57
+ debug('SQLite migration statements for AddCredentialStatusFields reverted')
58
+ return
59
+ }
60
+ default:
61
+ return Promise.reject(
62
+ `Migrations are currently only supported for sqlite, react-native, expo, and postgres for AddCredentialStatusFields. Was ${dbType}. Please run your database without migrations and with 'migrationsRun: false' and 'synchronize: true' for now`,
63
+ )
64
+ }
65
+ }
66
+ }
@@ -18,6 +18,7 @@ import { CreateMachineStateStore1708098041262 } from './7-CreateMachineStateStor
18
18
  import { CreateContacts1708525189000 } from './8-CreateContacts'
19
19
  import { CreateContacts1715761125000 } from './9-CreateContacts'
20
20
  import { AddCredentialDesigns1773657426000 } from './18-AddCredentialDesigns'
21
+ import { AddCredentialStatusFields1780000000000 } from './19-AddCredentialStatusFields'
21
22
 
22
23
  /**
23
24
  * The migrations array that SHOULD be used when initializing a TypeORM database connection.
@@ -48,7 +49,11 @@ export const DataStoreStatusListMigrations = [
48
49
  CreateBitstringStatusList1741895823000,
49
50
  ]
50
51
  export const DataStoreEventLoggerMigrations = [CreateAuditEvents1701635835330]
51
- export const DataStoreDigitalCredentialMigrations = [CreateDigitalCredential1708525189000, AddLinkedVpFields1763387280000]
52
+ export const DataStoreDigitalCredentialMigrations = [
53
+ CreateDigitalCredential1708525189000,
54
+ AddLinkedVpFields1763387280000,
55
+ AddCredentialStatusFields1780000000000,
56
+ ]
52
57
  export const DataStoreMachineStateMigrations = [CreateMachineStateStore1708098041262]
53
58
  export const DataStorePresentationDefinitionMigrations = [CreatePresentationDefinitions1716533767523, CreateDcqlQueryItem1726617600000]
54
59
  export const DataStoreServiceMigrations = [AddServiceMetadata1764000000000]
@@ -0,0 +1,30 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ /**
4
+ * Adds 'SUSPENDED' to the digital_credential_state_type enum and a "status_last_checked_at"
5
+ * column on DigitalCredential. Uses the transaction-safe recreate-type approach.
6
+ */
7
+ export class AddCredentialStatusFields1780000000001 implements MigrationInterface {
8
+ name = 'AddCredentialStatusFields1780000000001'
9
+
10
+ public async up(queryRunner: QueryRunner): Promise<void> {
11
+ await queryRunner.query(`ALTER TABLE "DigitalCredential" ADD COLUMN "status_last_checked_at" TIMESTAMP`)
12
+ await queryRunner.query(`CREATE TYPE "digital_credential_state_type_v2" AS ENUM('REVOKED', 'VERIFIED', 'EXPIRED', 'SUSPENDED')`)
13
+ await queryRunner.query(
14
+ `ALTER TABLE "DigitalCredential" ALTER COLUMN "verified_state" TYPE "digital_credential_state_type_v2" USING "verified_state"::text::"digital_credential_state_type_v2"`,
15
+ )
16
+ await queryRunner.query(`DROP TYPE "digital_credential_state_type"`)
17
+ await queryRunner.query(`ALTER TYPE "digital_credential_state_type_v2" RENAME TO "digital_credential_state_type"`)
18
+ }
19
+
20
+ public async down(queryRunner: QueryRunner): Promise<void> {
21
+ await queryRunner.query(`UPDATE "DigitalCredential" SET "verified_state" = NULL WHERE "verified_state" = 'SUSPENDED'`)
22
+ await queryRunner.query(`CREATE TYPE "digital_credential_state_type_old" AS ENUM('REVOKED', 'VERIFIED', 'EXPIRED')`)
23
+ await queryRunner.query(
24
+ `ALTER TABLE "DigitalCredential" ALTER COLUMN "verified_state" TYPE "digital_credential_state_type_old" USING "verified_state"::text::"digital_credential_state_type_old"`,
25
+ )
26
+ await queryRunner.query(`DROP TYPE "digital_credential_state_type"`)
27
+ await queryRunner.query(`ALTER TYPE "digital_credential_state_type_old" RENAME TO "digital_credential_state_type"`)
28
+ await queryRunner.query(`ALTER TABLE "DigitalCredential" DROP COLUMN "status_last_checked_at"`)
29
+ }
30
+ }
@@ -0,0 +1,137 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ /**
4
+ * Widens the DigitalCredential "verified_state" CHECK constraint to include 'SUSPENDED'
5
+ * and adds a "status_last_checked_at" column. SQLite cannot ALTER a CHECK constraint in
6
+ * place, so the table is rebuilt. This migration must run AFTER AddLinkedVpFields
7
+ * (1763387280000), so the rebuilt schema includes the linked_vp_* columns.
8
+ */
9
+ export class AddCredentialStatusFields1780000000002 implements MigrationInterface {
10
+ name = 'AddCredentialStatusFields1780000000002'
11
+
12
+ public async up(queryRunner: QueryRunner): Promise<void> {
13
+ await queryRunner.query(`
14
+ CREATE TABLE "DigitalCredential_new" (
15
+ "id" varchar PRIMARY KEY NOT NULL,
16
+ "parent_id" text,
17
+ "document_type" varchar CHECK( "document_type" IN ('VC', 'VP', 'C', 'P') ) NOT NULL,
18
+ "regulation_type" varchar CHECK( "regulation_type" IN ('PID', 'QEAA', 'EAA', 'NON_REGULATED') ) NOT NULL DEFAULT 'NON_REGULATED',
19
+ "document_format" varchar CHECK( "document_format" IN ('JSON_LD', 'JWT', 'SD_JWT', 'MSO_MDOC') ) NOT NULL,
20
+ "credential_role" varchar CHECK( "credential_role" IN ('ISSUER', 'VERIFIER', 'HOLDER', 'FEDERATION_TRUST_ANCHOR') ) NOT NULL,
21
+ "raw_document" text NOT NULL,
22
+ "uniform_document" text NOT NULL,
23
+ "credential_id" text,
24
+ "hash" text NOT NULL,
25
+ "kms_key_ref" text,
26
+ "identifier_method" text,
27
+ "issuer_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('DID', 'KID', 'URL', 'X509_SAN') ) NOT NULL,
28
+ "subject_correlation_type" varchar CHECK( "subject_correlation_type" IN ('DID', 'KID', 'URL', 'X509_SAN') ),
29
+ "issuer_correlation_id" text NOT NULL,
30
+ "subject_correlation_id" text,
31
+ "issuer_signed" boolean,
32
+ "rp_correlation_id" text,
33
+ "rp_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('DID', 'KID', 'URL', 'X509_SAN') ),
34
+ "verified_state" varchar CHECK( "verified_state" IN ('REVOKED', 'VERIFIED', 'EXPIRED', 'SUSPENDED') ),
35
+ "tenant_id" text,
36
+ "created_at" datetime NOT NULL DEFAULT (datetime('now')),
37
+ "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')),
38
+ "presented_at" datetime,
39
+ "valid_from" datetime,
40
+ "valid_until" datetime,
41
+ "verified_at" datetime,
42
+ "revoked_at" datetime,
43
+ "linked_vp_id" text,
44
+ "linked_vp_from" datetime,
45
+ "linked_vp_until" datetime,
46
+ "status_last_checked_at" datetime,
47
+ UNIQUE ("hash", "credential_role")
48
+ )
49
+ `)
50
+
51
+ await queryRunner.query(`
52
+ INSERT INTO "DigitalCredential_new" (
53
+ "id","parent_id","document_type","regulation_type","document_format","credential_role",
54
+ "raw_document","uniform_document","credential_id","hash","kms_key_ref","identifier_method",
55
+ "issuer_correlation_type","subject_correlation_type","issuer_correlation_id","subject_correlation_id",
56
+ "issuer_signed","rp_correlation_id","rp_correlation_type","verified_state","tenant_id",
57
+ "created_at","last_updated_at","presented_at","valid_from","valid_until","verified_at","revoked_at",
58
+ "linked_vp_id","linked_vp_from","linked_vp_until"
59
+ )
60
+ SELECT
61
+ "id","parent_id","document_type","regulation_type","document_format","credential_role",
62
+ "raw_document","uniform_document","credential_id","hash","kms_key_ref","identifier_method",
63
+ "issuer_correlation_type","subject_correlation_type","issuer_correlation_id","subject_correlation_id",
64
+ "issuer_signed","rp_correlation_id","rp_correlation_type","verified_state","tenant_id",
65
+ "created_at","last_updated_at","presented_at","valid_from","valid_until","verified_at","revoked_at",
66
+ "linked_vp_id","linked_vp_from","linked_vp_until"
67
+ FROM "DigitalCredential"
68
+ `)
69
+
70
+ await queryRunner.query(`DROP TABLE "DigitalCredential"`)
71
+ await queryRunner.query(`ALTER TABLE "DigitalCredential_new" RENAME TO "DigitalCredential"`)
72
+ }
73
+
74
+ public async down(queryRunner: QueryRunner): Promise<void> {
75
+ // Collapse SUSPENDED to NULL so the narrowed CHECK does not reject existing rows
76
+ await queryRunner.query(`UPDATE "DigitalCredential" SET "verified_state" = NULL WHERE "verified_state" = 'SUSPENDED'`)
77
+
78
+ await queryRunner.query(`
79
+ CREATE TABLE "DigitalCredential_old" (
80
+ "id" varchar PRIMARY KEY NOT NULL,
81
+ "parent_id" text,
82
+ "document_type" varchar CHECK( "document_type" IN ('VC', 'VP', 'C', 'P') ) NOT NULL,
83
+ "regulation_type" varchar CHECK( "regulation_type" IN ('PID', 'QEAA', 'EAA', 'NON_REGULATED') ) NOT NULL DEFAULT 'NON_REGULATED',
84
+ "document_format" varchar CHECK( "document_format" IN ('JSON_LD', 'JWT', 'SD_JWT', 'MSO_MDOC') ) NOT NULL,
85
+ "credential_role" varchar CHECK( "credential_role" IN ('ISSUER', 'VERIFIER', 'HOLDER', 'FEDERATION_TRUST_ANCHOR') ) NOT NULL,
86
+ "raw_document" text NOT NULL,
87
+ "uniform_document" text NOT NULL,
88
+ "credential_id" text,
89
+ "hash" text NOT NULL,
90
+ "kms_key_ref" text,
91
+ "identifier_method" text,
92
+ "issuer_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('DID', 'KID', 'URL', 'X509_SAN') ) NOT NULL,
93
+ "subject_correlation_type" varchar CHECK( "subject_correlation_type" IN ('DID', 'KID', 'URL', 'X509_SAN') ),
94
+ "issuer_correlation_id" text NOT NULL,
95
+ "subject_correlation_id" text,
96
+ "issuer_signed" boolean,
97
+ "rp_correlation_id" text,
98
+ "rp_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('DID', 'KID', 'URL', 'X509_SAN') ),
99
+ "verified_state" varchar CHECK( "verified_state" IN ('REVOKED', 'VERIFIED', 'EXPIRED') ),
100
+ "tenant_id" text,
101
+ "created_at" datetime NOT NULL DEFAULT (datetime('now')),
102
+ "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')),
103
+ "presented_at" datetime,
104
+ "valid_from" datetime,
105
+ "valid_until" datetime,
106
+ "verified_at" datetime,
107
+ "revoked_at" datetime,
108
+ "linked_vp_id" text,
109
+ "linked_vp_from" datetime,
110
+ "linked_vp_until" datetime,
111
+ UNIQUE ("hash", "credential_role")
112
+ )
113
+ `)
114
+
115
+ await queryRunner.query(`
116
+ INSERT INTO "DigitalCredential_old" (
117
+ "id","parent_id","document_type","regulation_type","document_format","credential_role",
118
+ "raw_document","uniform_document","credential_id","hash","kms_key_ref","identifier_method",
119
+ "issuer_correlation_type","subject_correlation_type","issuer_correlation_id","subject_correlation_id",
120
+ "issuer_signed","rp_correlation_id","rp_correlation_type","verified_state","tenant_id",
121
+ "created_at","last_updated_at","presented_at","valid_from","valid_until","verified_at","revoked_at",
122
+ "linked_vp_id","linked_vp_from","linked_vp_until"
123
+ )
124
+ SELECT
125
+ "id","parent_id","document_type","regulation_type","document_format","credential_role",
126
+ "raw_document","uniform_document","credential_id","hash","kms_key_ref","identifier_method",
127
+ "issuer_correlation_type","subject_correlation_type","issuer_correlation_id","subject_correlation_id",
128
+ "issuer_signed","rp_correlation_id","rp_correlation_type","verified_state","tenant_id",
129
+ "created_at","last_updated_at","presented_at","valid_from","valid_until","verified_at","revoked_at",
130
+ "linked_vp_id","linked_vp_from","linked_vp_until"
131
+ FROM "DigitalCredential"
132
+ `)
133
+
134
+ await queryRunner.query(`DROP TABLE "DigitalCredential"`)
135
+ await queryRunner.query(`ALTER TABLE "DigitalCredential_old" RENAME TO "DigitalCredential"`)
136
+ }
137
+ }