@sphereon/ssi-sdk.data-store 0.34.1-feature.SSISDK.82.linkedVP.328 → 0.34.1-feature.SSISDK.82.linkedVP.341
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 +53 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +54 -26
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/digitalCredential/DigitalCredentialStore.ts +24 -24
- package/src/utils/digitalCredential/MappingUtils.ts +69 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/ssi-sdk.data-store",
|
|
3
|
-
"version": "0.34.1-feature.SSISDK.82.linkedVP.
|
|
3
|
+
"version": "0.34.1-feature.SSISDK.82.linkedVP.341+483672e1",
|
|
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.34.1-feature.SSISDK.82.linkedVP.
|
|
32
|
-
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.82.linkedVP.
|
|
33
|
-
"@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.82.linkedVP.
|
|
34
|
-
"@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.82.linkedVP.
|
|
35
|
-
"@sphereon/ssi-sdk.data-store-types": "0.34.1-feature.SSISDK.82.linkedVP.
|
|
36
|
-
"@sphereon/ssi-types": "0.34.1-feature.SSISDK.82.linkedVP.
|
|
31
|
+
"@sphereon/ssi-sdk-ext.did-utils": "0.34.1-feature.SSISDK.82.linkedVP.341+483672e1",
|
|
32
|
+
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.82.linkedVP.341+483672e1",
|
|
33
|
+
"@sphereon/ssi-sdk.agent-config": "0.34.1-feature.SSISDK.82.linkedVP.341+483672e1",
|
|
34
|
+
"@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.82.linkedVP.341+483672e1",
|
|
35
|
+
"@sphereon/ssi-sdk.data-store-types": "0.34.1-feature.SSISDK.82.linkedVP.341+483672e1",
|
|
36
|
+
"@sphereon/ssi-types": "0.34.1-feature.SSISDK.82.linkedVP.341+483672e1",
|
|
37
37
|
"@veramo/core": "4.2.0",
|
|
38
38
|
"@veramo/utils": "4.2.0",
|
|
39
39
|
"blakejs": "^1.2.1",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"PostgreSQL",
|
|
67
67
|
"Contact Store"
|
|
68
68
|
],
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "483672e1d9b2891a346216a0ebea64745561d6ed"
|
|
70
70
|
}
|
|
@@ -15,7 +15,13 @@ import { CredentialRole, OrPromise } from '@sphereon/ssi-types'
|
|
|
15
15
|
import Debug from 'debug'
|
|
16
16
|
import { DataSource, type FindOptionsOrder, type FindOptionsWhere, Repository } from 'typeorm'
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
digitalCredentialFrom,
|
|
20
|
+
digitalCredentialsFrom,
|
|
21
|
+
nonPersistedDigitalCredentialEntityFromAddArgs,
|
|
22
|
+
persistedDigitalCredentialEntityFromStateArgs,
|
|
23
|
+
persistedDigitalCredentialEntityFromUpdateArgs,
|
|
24
|
+
} from '../../src'
|
|
19
25
|
import { DigitalCredentialEntity } from '../entities/digitalCredential/DigitalCredentialEntity'
|
|
20
26
|
import { parseAndValidateOrderOptions } from '../utils/SortingUtils'
|
|
21
27
|
|
|
@@ -38,7 +44,7 @@ export class DigitalCredentialStore extends AbstractDigitalCredentialStore {
|
|
|
38
44
|
return Promise.reject(validationError)
|
|
39
45
|
}
|
|
40
46
|
const dcRepo = await this.getRepository()
|
|
41
|
-
const createdResult: DigitalCredentialEntity = await dcRepo.save(credentialEntity)
|
|
47
|
+
const createdResult: DigitalCredentialEntity = await dcRepo.save(credentialEntity as any)
|
|
42
48
|
return Promise.resolve(digitalCredentialFrom(createdResult))
|
|
43
49
|
}
|
|
44
50
|
|
|
@@ -93,20 +99,18 @@ export class DigitalCredentialStore extends AbstractDigitalCredentialStore {
|
|
|
93
99
|
return Promise.reject(Error(`No credential found for args: ${JSON.stringify(whereClause)}`))
|
|
94
100
|
}
|
|
95
101
|
|
|
96
|
-
//
|
|
97
|
-
const
|
|
102
|
+
// Extract updates by removing the identifier fields
|
|
103
|
+
const updates = Object.fromEntries(Object.entries(args).filter(([key]) => key !== 'id' && key !== 'hash')) as Partial<DigitalCredential>
|
|
104
|
+
|
|
105
|
+
const entityToSave = persistedDigitalCredentialEntityFromUpdateArgs(credential, updates)
|
|
98
106
|
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
id: credential.id,
|
|
103
|
-
hash: credential.hash,
|
|
104
|
-
createdAt: credential.createdAt,
|
|
105
|
-
lastUpdatedAt: new Date(),
|
|
107
|
+
const validationError = this.assertValidDigitalCredential(entityToSave)
|
|
108
|
+
if (validationError) {
|
|
109
|
+
return Promise.reject(validationError)
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
debug('Updating credential',
|
|
109
|
-
const updatedResult
|
|
112
|
+
debug('Updating credential', entityToSave)
|
|
113
|
+
const updatedResult = await dcRepo.save(entityToSave as any, { transaction: true })
|
|
110
114
|
return digitalCredentialFrom(updatedResult)
|
|
111
115
|
}
|
|
112
116
|
|
|
@@ -185,20 +189,16 @@ export class DigitalCredentialStore extends AbstractDigitalCredentialStore {
|
|
|
185
189
|
if (!credential) {
|
|
186
190
|
return Promise.reject(Error(`No credential found for args: ${JSON.stringify(whereClause)}`))
|
|
187
191
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
verifiedState: args.verifiedState,
|
|
195
|
-
}
|
|
196
|
-
debug('Updating credential', credential)
|
|
197
|
-
const updatedResult: DigitalCredentialEntity = await credentialRepository.save(updatedCredential, { transaction: true })
|
|
192
|
+
|
|
193
|
+
// Create entity with state updates applied
|
|
194
|
+
const entityToSave = persistedDigitalCredentialEntityFromStateArgs(credential, args)
|
|
195
|
+
|
|
196
|
+
debug('Updating credential state', entityToSave)
|
|
197
|
+
const updatedResult: DigitalCredentialEntity = await credentialRepository.save(entityToSave as any, { transaction: true })
|
|
198
198
|
return digitalCredentialFrom(updatedResult)
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
private assertValidDigitalCredential(credentialEntity: NonPersistedDigitalCredential): Error | undefined {
|
|
201
|
+
private assertValidDigitalCredential(credentialEntity: NonPersistedDigitalCredential | DigitalCredentialEntity): Error | undefined {
|
|
202
202
|
const { kmsKeyRef, identifierMethod, credentialRole, isIssuerSigned } = credentialEntity
|
|
203
203
|
|
|
204
204
|
const isRoleInvalid = credentialRole === CredentialRole.ISSUER || (credentialRole === CredentialRole.HOLDER && !isIssuerSigned)
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type {
|
|
3
|
+
AddCredentialArgs,
|
|
4
|
+
DigitalCredential,
|
|
5
|
+
NonPersistedDigitalCredential,
|
|
6
|
+
UpdateCredentialStateArgs,
|
|
7
|
+
} from '@sphereon/ssi-sdk.data-store-types'
|
|
8
|
+
import { CredentialDocumentFormat, CredentialStateType, DocumentType, RegulationType } from '@sphereon/ssi-sdk.data-store-types'
|
|
4
9
|
import {
|
|
5
10
|
CredentialMapper,
|
|
6
11
|
DocumentFormat,
|
|
@@ -66,6 +71,20 @@ function determineCredentialDocumentFormat(documentFormat: DocumentFormat): Cred
|
|
|
66
71
|
}
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Normalizes nullable fields by converting undefined to null.
|
|
76
|
+
* This ensures TypeORM actually clears the database fields instead of ignoring them.
|
|
77
|
+
*/
|
|
78
|
+
export function normalizeNullableFields<T extends Record<string, any>>(obj: T, nullableKeys: Array<keyof T>): T {
|
|
79
|
+
const normalized = { ...obj }
|
|
80
|
+
for (const key of nullableKeys) {
|
|
81
|
+
if (normalized[key] === undefined) {
|
|
82
|
+
normalized[key] = null as any
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return normalized
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
function getValidUntil(uniformDocument: IVerifiableCredential | IVerifiablePresentation | SdJwtDecodedVerifiableCredentialPayload): Date | undefined {
|
|
70
89
|
if ('expirationDate' in uniformDocument && uniformDocument.expirationDate) {
|
|
71
90
|
return new Date(uniformDocument.expirationDate)
|
|
@@ -127,6 +146,54 @@ export const nonPersistedDigitalCredentialEntityFromAddArgs = (addCredentialArgs
|
|
|
127
146
|
}
|
|
128
147
|
}
|
|
129
148
|
|
|
149
|
+
export const persistedDigitalCredentialEntityFromUpdateArgs = (
|
|
150
|
+
existingCredential: DigitalCredentialEntity,
|
|
151
|
+
updates: Partial<DigitalCredential>,
|
|
152
|
+
): DigitalCredentialEntity => {
|
|
153
|
+
const entity = new DigitalCredentialEntity()
|
|
154
|
+
|
|
155
|
+
// Copy all fields from existing credential
|
|
156
|
+
Object.assign(entity, existingCredential)
|
|
157
|
+
|
|
158
|
+
// Normalize nullable fields before applying updates
|
|
159
|
+
const normalizedUpdates = normalizeNullableFields(updates, ['linkedVpId', 'linkedVpFrom'])
|
|
160
|
+
|
|
161
|
+
// Apply updates
|
|
162
|
+
Object.assign(entity, normalizedUpdates)
|
|
163
|
+
|
|
164
|
+
// Ensure these fields are never overwritten
|
|
165
|
+
entity.id = existingCredential.id
|
|
166
|
+
entity.hash = existingCredential.hash
|
|
167
|
+
entity.createdAt = existingCredential.createdAt
|
|
168
|
+
entity.lastUpdatedAt = new Date()
|
|
169
|
+
|
|
170
|
+
return entity
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const persistedDigitalCredentialEntityFromStateArgs = (
|
|
174
|
+
existingCredential: DigitalCredentialEntity,
|
|
175
|
+
args: UpdateCredentialStateArgs,
|
|
176
|
+
): DigitalCredentialEntity => {
|
|
177
|
+
const entity = new DigitalCredentialEntity()
|
|
178
|
+
|
|
179
|
+
// Copy all fields from existing credential
|
|
180
|
+
Object.assign(entity, existingCredential)
|
|
181
|
+
|
|
182
|
+
// Apply state updates
|
|
183
|
+
entity.verifiedState = args.verifiedState
|
|
184
|
+
entity.lastUpdatedAt = new Date()
|
|
185
|
+
|
|
186
|
+
if (args.verifiedState === CredentialStateType.REVOKED && args.revokedAt) {
|
|
187
|
+
entity.revokedAt = args.revokedAt
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (args.verifiedState !== CredentialStateType.REVOKED && args.verifiedAt) {
|
|
191
|
+
entity.verifiedAt = args.verifiedAt
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return entity
|
|
195
|
+
}
|
|
196
|
+
|
|
130
197
|
export const digitalCredentialFrom = (credentialEntity: DigitalCredentialEntity): DigitalCredential => {
|
|
131
198
|
const result: DigitalCredential = {
|
|
132
199
|
...credentialEntity,
|