@sphereon/ssi-sdk.data-store 0.19.1-next.2 → 0.19.1-unstable.63

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.
Files changed (110) hide show
  1. package/dist/digitalCredential/AbstractDigitalCredentialStore.d.ts +10 -0
  2. package/dist/digitalCredential/AbstractDigitalCredentialStore.d.ts.map +1 -0
  3. package/dist/digitalCredential/AbstractDigitalCredentialStore.js +7 -0
  4. package/dist/digitalCredential/AbstractDigitalCredentialStore.js.map +1 -0
  5. package/dist/digitalCredential/DigitalCredentialStore.d.ts +15 -0
  6. package/dist/digitalCredential/DigitalCredentialStore.d.ts.map +1 -0
  7. package/dist/digitalCredential/DigitalCredentialStore.js +118 -0
  8. package/dist/digitalCredential/DigitalCredentialStore.js.map +1 -0
  9. package/dist/entities/digitalCredential/DigitalCredentialEntity.d.ts +23 -0
  10. package/dist/entities/digitalCredential/DigitalCredentialEntity.d.ts.map +1 -0
  11. package/dist/entities/digitalCredential/DigitalCredentialEntity.js +93 -0
  12. package/dist/entities/digitalCredential/DigitalCredentialEntity.js.map +1 -0
  13. package/dist/entities/xstate/StateEntity.d.ts +14 -0
  14. package/dist/entities/xstate/StateEntity.d.ts.map +1 -0
  15. package/dist/entities/xstate/StateEntity.js +60 -0
  16. package/dist/entities/xstate/StateEntity.js.map +1 -0
  17. package/dist/index.d.ts +10 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +19 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/migrations/generic/6-CreateDigitalCredential.d.ts +7 -0
  22. package/dist/migrations/generic/6-CreateDigitalCredential.d.ts.map +1 -0
  23. package/dist/migrations/generic/6-CreateDigitalCredential.js +78 -0
  24. package/dist/migrations/generic/6-CreateDigitalCredential.js.map +1 -0
  25. package/dist/migrations/generic/7-CreateXStateStore.d.ts +7 -0
  26. package/dist/migrations/generic/7-CreateXStateStore.d.ts.map +1 -0
  27. package/dist/migrations/generic/7-CreateXStateStore.js +78 -0
  28. package/dist/migrations/generic/7-CreateXStateStore.js.map +1 -0
  29. package/dist/migrations/generic/index.d.ts +4 -0
  30. package/dist/migrations/generic/index.d.ts.map +1 -1
  31. package/dist/migrations/generic/index.js +7 -1
  32. package/dist/migrations/generic/index.js.map +1 -1
  33. package/dist/migrations/index.d.ts +1 -1
  34. package/dist/migrations/index.d.ts.map +1 -1
  35. package/dist/migrations/index.js +3 -1
  36. package/dist/migrations/index.js.map +1 -1
  37. package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.d.ts +7 -0
  38. package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.d.ts.map +1 -0
  39. package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js +59 -0
  40. package/dist/migrations/postgres/1708525189001-CreateDigitalCredential.js.map +1 -0
  41. package/dist/migrations/postgres/1708797018115-CreateXStateStore.d.ts +7 -0
  42. package/dist/migrations/postgres/1708797018115-CreateXStateStore.d.ts.map +1 -0
  43. package/dist/migrations/postgres/1708797018115-CreateXStateStore.js +45 -0
  44. package/dist/migrations/postgres/1708797018115-CreateXStateStore.js.map +1 -0
  45. package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.d.ts +7 -0
  46. package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.d.ts.map +1 -0
  47. package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js +50 -0
  48. package/dist/migrations/sqlite/1708525189002-CreateDigitalCredential.js.map +1 -0
  49. package/dist/migrations/sqlite/1708796002272-CreateXStateStore.d.ts +7 -0
  50. package/dist/migrations/sqlite/1708796002272-CreateXStateStore.d.ts.map +1 -0
  51. package/dist/migrations/sqlite/1708796002272-CreateXStateStore.js +42 -0
  52. package/dist/migrations/sqlite/1708796002272-CreateXStateStore.js.map +1 -0
  53. package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.d.ts +42 -0
  54. package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.d.ts.map +1 -0
  55. package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.js +3 -0
  56. package/dist/types/digitalCredential/IAbstractDigitalCredentialStore.js.map +1 -0
  57. package/dist/types/digitalCredential/digitalCredential.d.ts +42 -0
  58. package/dist/types/digitalCredential/digitalCredential.d.ts.map +1 -0
  59. package/dist/types/digitalCredential/digitalCredential.js +28 -0
  60. package/dist/types/digitalCredential/digitalCredential.js.map +1 -0
  61. package/dist/types/index.d.ts +1 -0
  62. package/dist/types/index.d.ts.map +1 -1
  63. package/dist/types/index.js +1 -0
  64. package/dist/types/index.js.map +1 -1
  65. package/dist/types/xstate/IAbstractXStateStore.d.ts +38 -0
  66. package/dist/types/xstate/IAbstractXStateStore.d.ts.map +1 -0
  67. package/dist/types/xstate/IAbstractXStateStore.js +3 -0
  68. package/dist/types/xstate/IAbstractXStateStore.js.map +1 -0
  69. package/dist/utils/SortingUtils.d.ts +3 -0
  70. package/dist/utils/SortingUtils.d.ts.map +1 -0
  71. package/dist/utils/SortingUtils.js +18 -0
  72. package/dist/utils/SortingUtils.js.map +1 -0
  73. package/dist/utils/digitalCredential/MappingUtils.d.ts +7 -0
  74. package/dist/utils/digitalCredential/MappingUtils.d.ts.map +1 -0
  75. package/dist/utils/digitalCredential/MappingUtils.js +99 -0
  76. package/dist/utils/digitalCredential/MappingUtils.js.map +1 -0
  77. package/dist/xstate/IAbstractXStateStore.d.ts +9 -0
  78. package/dist/xstate/IAbstractXStateStore.d.ts.map +1 -0
  79. package/dist/xstate/IAbstractXStateStore.js +7 -0
  80. package/dist/xstate/IAbstractXStateStore.js.map +1 -0
  81. package/dist/xstate/XStateStore.d.ts +17 -0
  82. package/dist/xstate/XStateStore.d.ts.map +1 -0
  83. package/dist/xstate/XStateStore.js +110 -0
  84. package/dist/xstate/XStateStore.js.map +1 -0
  85. package/package.json +5 -4
  86. package/src/__tests__/digitalCredential.entities.test.ts +254 -0
  87. package/src/__tests__/digitalCredential.store.test.ts +294 -0
  88. package/src/__tests__/xstate.entities.test.ts +47 -0
  89. package/src/__tests__/xstate.store.test.ts +158 -0
  90. package/src/digitalCredential/AbstractDigitalCredentialStore.ts +17 -0
  91. package/src/digitalCredential/DigitalCredentialStore.ts +127 -0
  92. package/src/entities/digitalCredential/DigitalCredentialEntity.ts +64 -0
  93. package/src/entities/xstate/StateEntity.ts +34 -0
  94. package/src/index.ts +18 -0
  95. package/src/migrations/generic/6-CreateDigitalCredential.ts +66 -0
  96. package/src/migrations/generic/7-CreateXStateStore.ts +66 -0
  97. package/src/migrations/generic/index.ts +6 -0
  98. package/src/migrations/index.ts +2 -0
  99. package/src/migrations/postgres/1708525189001-CreateDigitalCredential.ts +44 -0
  100. package/src/migrations/postgres/1708797018115-CreateXStateStore.ts +29 -0
  101. package/src/migrations/sqlite/1708525189002-CreateDigitalCredential.ts +34 -0
  102. package/src/migrations/sqlite/1708796002272-CreateXStateStore.ts +26 -0
  103. package/src/types/digitalCredential/IAbstractDigitalCredentialStore.ts +37 -0
  104. package/src/types/digitalCredential/digitalCredential.ts +46 -0
  105. package/src/types/index.ts +1 -0
  106. package/src/types/xstate/IAbstractXStateStore.ts +39 -0
  107. package/src/utils/SortingUtils.ts +16 -0
  108. package/src/utils/digitalCredential/MappingUtils.ts +122 -0
  109. package/src/xstate/IAbstractXStateStore.ts +9 -0
  110. package/src/xstate/XStateStore.ts +107 -0
@@ -0,0 +1,29 @@
1
+ import { enablePostgresUuidExtension } from '@sphereon/ssi-sdk.core'
2
+ import { MigrationInterface, QueryRunner } from 'typeorm'
3
+
4
+ export class CreateXStateStore1708797018115 implements MigrationInterface {
5
+ name = 'CreateXStateStore1708797018115'
6
+
7
+ public async up(queryRunner: QueryRunner): Promise<void> {
8
+ await enablePostgresUuidExtension(queryRunner)
9
+ await queryRunner.query(`
10
+ CREATE TABLE "StateEntity" (
11
+ "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
12
+ "state_name" character varying NOT NULL,
13
+ "machine_type" character varying NOT NULL,
14
+ "xstate_event_type" character varying NOT NULL,
15
+ "state" text NOT NULL,
16
+ "created_at" TIMESTAMP NOT NULL DEFAULT now(),
17
+ "updated_at" TIMESTAMP NOT NULL DEFAULT now(),
18
+ "expires_at" TIMESTAMP,
19
+ "completed_at" TIMESTAMP,
20
+ "tenant_id" character varying,
21
+ CONSTRAINT "PK_StateEntity_id" PRIMARY KEY ("id")
22
+ )
23
+ `)
24
+ }
25
+
26
+ public async down(queryRunner: QueryRunner): Promise<void> {
27
+ await queryRunner.query(`DROP TABLE "StateEntity"`)
28
+ }
29
+ }
@@ -0,0 +1,34 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ export class CreateDigitalCredential1708525189002 implements MigrationInterface {
4
+ name = 'CreateDigitalCredential1708525189002'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`
8
+ CREATE TABLE "DigitalCredential" (
9
+ "id" varchar PRIMARY KEY NOT NULL,
10
+ "document_type" varchar CHECK( "document_type" IN ('VC', 'VP', 'C', 'P') ) NOT NULL,
11
+ "document_format" varchar CHECK( "document_format" IN ('JSON_LD', 'JWT', 'SD_JWT', 'MDOC') ) NOT NULL,
12
+ "raw_document" text NOT NULL,
13
+ "uniform_document" text NOT NULL,
14
+ "hash" text NOT NULL UNIQUE,
15
+ "issuer_correlation_type" varchar CHECK( "issuer_correlation_type" IN ('DID') ) NOT NULL,
16
+ "subject_correlation_type" varchar CHECK( "subject_correlation_type" IN ('DID') ),
17
+ "issuer_correlation_id" text NOT NULL,
18
+ "subject_correlation_id" text,
19
+ "verified_state" varchar CHECK( "verified_state" IN ('REVOKED', 'VERIFIED', 'EXPIRED') ),
20
+ "tenant_id" text,
21
+ "created_at" datetime NOT NULL DEFAULT (datetime('now')),
22
+ "last_updated_at" datetime NOT NULL DEFAULT (datetime('now')),
23
+ "valid_from" datetime,
24
+ "valid_until" datetime,
25
+ "verified_at" datetime,
26
+ "revoked_at" datetime
27
+ )
28
+ `)
29
+ }
30
+
31
+ public async down(queryRunner: QueryRunner): Promise<void> {
32
+ await queryRunner.query(`DROP TABLE "DigitalCredential"`)
33
+ }
34
+ }
@@ -0,0 +1,26 @@
1
+ import { MigrationInterface, QueryRunner } from 'typeorm'
2
+
3
+ export class CreateXStateStore1708796002272 implements MigrationInterface {
4
+ name = 'CreateXStateStore1708796002272'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`
8
+ CREATE TABLE "StateEntity" (
9
+ "id" varchar PRIMARY KEY NOT NULL,
10
+ "state_name" varchar NOT NULL,
11
+ "machine_type" varchar NOT NULL,
12
+ "xstate_event_type" varchar NOT NULL,
13
+ "state" text NOT NULL,
14
+ "created_at" datetime NOT NULL DEFAULT (datetime('now')),
15
+ "updated_at" datetime NOT NULL DEFAULT (datetime('now')),
16
+ "expires_at" datetime,
17
+ "completed_at" datetime,
18
+ "tenant_id" varchar
19
+ )
20
+ `)
21
+ }
22
+
23
+ public async down(queryRunner: QueryRunner): Promise<void> {
24
+ await queryRunner.query(`DROP TABLE "StateEntity"`)
25
+ }
26
+ }
@@ -0,0 +1,37 @@
1
+ import { CredentialCorrelationType, CredentialStateType, DigitalCredential } from './digitalCredential'
2
+ import { Hasher } from '@sphereon/ssi-types'
3
+ import { FindOptionsOrder } from 'typeorm'
4
+ import { DigitalCredentialEntity } from '../../entities/digitalCredential/DigitalCredentialEntity'
5
+
6
+ export type GetCredentialArgs = { id: string } | { hash: string }
7
+
8
+ export type FindDigitalCredentialArgs = Array<Partial<DigitalCredential>>
9
+
10
+ export type GetCredentialsArgs = {
11
+ filter?: FindDigitalCredentialArgs
12
+ offset?: number
13
+ limit?: number
14
+ order?: string | FindOptionsOrder<DigitalCredentialEntity>
15
+ }
16
+
17
+ export type GetCredentialsResponse = {
18
+ data: Array<DigitalCredential>
19
+ total: number
20
+ }
21
+
22
+ export type AddCredentialArgs = {
23
+ rawDocument: string
24
+ issuerCorrelationType: CredentialCorrelationType
25
+ subjectCorrelationType?: CredentialCorrelationType
26
+ issuerCorrelationId: string
27
+ subjectCorrelationId?: string
28
+ tenantId?: string
29
+ state?: CredentialStateType
30
+ verifiedAt?: Date
31
+ revokedAt?: Date
32
+ opts?: { maxTimeSkewInMS?: number; hasher?: Hasher }
33
+ }
34
+
35
+ export type UpdateCredentialStateArgs = GetCredentialArgs & { verifiedState: CredentialStateType; verifiedAt?: Date; revokedAt?: Date }
36
+
37
+ export type RemoveCredentialArgs = GetCredentialArgs
@@ -0,0 +1,46 @@
1
+ export type NonPersistedDigitalCredential = Omit<DigitalCredential, 'id'>
2
+
3
+ export type DigitalCredential = {
4
+ id: string
5
+ documentType: DocumentType
6
+ documentFormat: CredentialDocumentFormat
7
+ rawDocument: string
8
+ uniformDocument: string
9
+ hash: string
10
+ issuerCorrelationType: CredentialCorrelationType
11
+ subjectCorrelationType?: CredentialCorrelationType
12
+ issuerCorrelationId: string
13
+ subjectCorrelationId?: string
14
+ verifiedState?: CredentialStateType
15
+ tenantId?: string
16
+ createdAt: Date
17
+ lastUpdatedAt: Date
18
+ validUntil?: Date
19
+ validFrom?: Date
20
+ verifiedAt?: Date
21
+ revokedAt?: Date
22
+ }
23
+
24
+ export enum DocumentType {
25
+ VC = 'VC',
26
+ VP = 'VP',
27
+ P = 'P',
28
+ C = 'C',
29
+ }
30
+
31
+ export enum CredentialDocumentFormat {
32
+ JSON_LD = 'JSON_LD',
33
+ JWT = 'JWT',
34
+ SD_JWT = 'SD_JWT',
35
+ MDOC = 'MDOC',
36
+ }
37
+
38
+ export enum CredentialCorrelationType {
39
+ DID = 'DID',
40
+ }
41
+
42
+ export enum CredentialStateType {
43
+ REVOKED = 'REVOKED',
44
+ VERIFIED = 'VERIFIED',
45
+ EXPIRED = 'EXPIRED',
46
+ }
@@ -7,3 +7,4 @@ export * from './statusList/statusList'
7
7
  export * from './statusList/IAbstractStatusListStore'
8
8
  export * from './eventLogger/IAbstractEventLoggerStore'
9
9
  export * from './eventLogger/eventLogger'
10
+ export * from './xstate/IAbstractXStateStore'
@@ -0,0 +1,39 @@
1
+ export type SaveStateArgs = Omit<State, 'id' | 'createdAt' | 'updatedAt'>
2
+
3
+ export type GetActiveStateArgs = Pick<State, 'machineType' | 'tenantId'>
4
+
5
+ export type FindStatesArgs = Array<Partial<Omit<State, 'state'>>>
6
+
7
+ export type GetStatesArgs = {
8
+ filter: FindStatesArgs
9
+ }
10
+
11
+ export type NonPersistedXStateStoreEvent = SaveStateArgs
12
+
13
+ export type DeleteStateArgs = { id: string }
14
+ export type DeleteExpiredStateArgs = { machineType?: string }
15
+
16
+ export type State = {
17
+ id: string
18
+ /**
19
+ * value of the state's name. top level of event type. examples: acceptAgreement, enterPersonalDetails
20
+ */
21
+ stateName: string
22
+ /**
23
+ * Machine type/id
24
+ */
25
+ machineType: string
26
+ /**
27
+ * event types like SET_TOC, SET_FIRSTNAME, ...
28
+ */
29
+ xStateEventType: string
30
+ /**
31
+ * state of the machine in this snapshot
32
+ */
33
+ state: unknown
34
+ createdAt: Date
35
+ expiresAt?: Date
36
+ updatedAt: Date
37
+ completedAt?: Date
38
+ tenantId?: string
39
+ }
@@ -0,0 +1,16 @@
1
+ import { BaseEntity, FindOptionsOrder } from 'typeorm'
2
+
3
+ export const parseAndValidateOrderOptions = <T extends BaseEntity>(order: string): FindOptionsOrder<T> => {
4
+ const orderPairs = order.split(',').map((pair) => pair.trim().split('.'))
5
+ const orderOptions: FindOptionsOrder<T> = {}
6
+
7
+ orderPairs.forEach(([field, direction]) => {
8
+ const dir = direction.toUpperCase()
9
+ if (dir !== 'ASC' && dir !== 'DESC') {
10
+ throw new Error(`Invalid order direction: '${direction}'. Must be 'asc' or 'desc'.`)
11
+ }
12
+ ;(orderOptions as any)[field] = dir
13
+ })
14
+
15
+ return orderOptions
16
+ }
@@ -0,0 +1,122 @@
1
+ import { AddCredentialArgs } from '../../types/digitalCredential/IAbstractDigitalCredentialStore'
2
+ import { DigitalCredentialEntity } from '../../entities/digitalCredential/DigitalCredentialEntity'
3
+ import {
4
+ CredentialMapper,
5
+ decodeSdJwtVc,
6
+ DocumentFormat,
7
+ IVerifiableCredential,
8
+ IVerifiablePresentation,
9
+ OriginalVerifiableCredential,
10
+ OriginalVerifiablePresentation,
11
+ SdJwtDecodedVerifiableCredentialPayload,
12
+ } from '@sphereon/ssi-types'
13
+ import {
14
+ CredentialDocumentFormat,
15
+ DocumentType,
16
+ DigitalCredential,
17
+ NonPersistedDigitalCredential,
18
+ } from '../../types/digitalCredential/digitalCredential'
19
+ import { computeEntryHash } from '@veramo/utils'
20
+
21
+ function determineDocumentType(raw: string): DocumentType {
22
+ const rawDocument = parseRawDocument(raw)
23
+ if (!rawDocument) {
24
+ throw new Error(`Couldn't parse the credential: ${raw}`)
25
+ }
26
+
27
+ const hasProof = CredentialMapper.hasProof(rawDocument)
28
+ const isCredential = CredentialMapper.isCredential(rawDocument)
29
+ const isPresentation = CredentialMapper.isPresentation(rawDocument)
30
+
31
+ if (isCredential) {
32
+ return hasProof ? DocumentType.VC : DocumentType.C
33
+ } else if (isPresentation) {
34
+ return hasProof ? DocumentType.VP : DocumentType.P
35
+ }
36
+ throw new Error(`Couldn't determine the type of the credential: ${raw}`)
37
+ }
38
+
39
+ function parseRawDocument(raw: string): OriginalVerifiableCredential | OriginalVerifiablePresentation {
40
+ if (CredentialMapper.isJwtEncoded(raw) || CredentialMapper.isSdJwtEncoded(raw)) {
41
+ return raw
42
+ }
43
+ try {
44
+ return JSON.parse(raw)
45
+ } catch (e) {
46
+ throw new Error(`Can't parse the raw credential: ${raw}`)
47
+ }
48
+ }
49
+
50
+ function determineCredentialDocumentFormat(documentFormat: DocumentFormat): CredentialDocumentFormat {
51
+ switch (documentFormat) {
52
+ case DocumentFormat.JSONLD:
53
+ return CredentialDocumentFormat.JSON_LD
54
+ case DocumentFormat.JWT:
55
+ return CredentialDocumentFormat.JWT
56
+ case DocumentFormat.SD_JWT_VC:
57
+ return CredentialDocumentFormat.SD_JWT
58
+ default:
59
+ throw new Error(`Not supported document format: ${documentFormat}`)
60
+ }
61
+ }
62
+
63
+ function getValidUntil(uniformDocument: IVerifiableCredential | IVerifiablePresentation | SdJwtDecodedVerifiableCredentialPayload): Date | undefined {
64
+ if ('expirationDate' in uniformDocument) {
65
+ return new Date(uniformDocument.expirationDate)
66
+ } else if ('validUntil' in uniformDocument) {
67
+ return new Date(uniformDocument.validUntil)
68
+ } else if ('exp' in uniformDocument) {
69
+ return new Date(uniformDocument.exp)
70
+ }
71
+ return undefined
72
+ }
73
+
74
+ function getValidFrom(uniformDocument: IVerifiableCredential | IVerifiablePresentation | SdJwtDecodedVerifiableCredentialPayload): Date | undefined {
75
+ if ('issuanceDate' in uniformDocument) {
76
+ return new Date(uniformDocument.issuanceDate)
77
+ } else if ('validFrom' in uniformDocument) {
78
+ return new Date(uniformDocument['validFrom'])
79
+ } else if ('nbf' in uniformDocument) {
80
+ return new Date(uniformDocument['nbf'] * 1000)
81
+ } else if ('iat' in uniformDocument) {
82
+ return new Date(uniformDocument['iat'] * 1000)
83
+ }
84
+ return undefined
85
+ }
86
+
87
+ export const nonPersistedDigitalCredentialEntityFromAddArgs = (addCredentialArgs: AddCredentialArgs): NonPersistedDigitalCredential => {
88
+ const documentType: DocumentType = determineDocumentType(addCredentialArgs.rawDocument)
89
+ const documentFormat: DocumentFormat = CredentialMapper.detectDocumentType(addCredentialArgs.rawDocument)
90
+ if (documentFormat === DocumentFormat.SD_JWT_VC && !addCredentialArgs.opts?.hasher) {
91
+ throw new Error('No hasher function is provided for SD_JWT credential.')
92
+ }
93
+ const uniformDocument =
94
+ documentFormat === DocumentFormat.SD_JWT_VC
95
+ ? decodeSdJwtVc(addCredentialArgs.rawDocument, addCredentialArgs.opts!.hasher!).decodedPayload
96
+ : documentType === DocumentType.VC || documentType === DocumentType.C
97
+ ? CredentialMapper.toUniformCredential(addCredentialArgs.rawDocument)
98
+ : CredentialMapper.toUniformPresentation(addCredentialArgs.rawDocument)
99
+ const validFrom: Date | undefined = getValidFrom(uniformDocument)
100
+ const validUntil: Date | undefined = getValidUntil(uniformDocument)
101
+ return {
102
+ ...addCredentialArgs,
103
+ documentType,
104
+ documentFormat: determineCredentialDocumentFormat(documentFormat),
105
+ createdAt: new Date(),
106
+ hash: computeEntryHash(addCredentialArgs.rawDocument),
107
+ uniformDocument: JSON.stringify(uniformDocument),
108
+ validFrom,
109
+ validUntil,
110
+ lastUpdatedAt: new Date(),
111
+ }
112
+ }
113
+
114
+ export const digitalCredentialFrom = (credentialEntity: DigitalCredentialEntity): DigitalCredential => {
115
+ return {
116
+ ...credentialEntity,
117
+ }
118
+ }
119
+
120
+ export const digitalCredentialsFrom = (credentialEntities: Array<DigitalCredentialEntity>): DigitalCredential[] => {
121
+ return credentialEntities.map((credentialEntity) => digitalCredentialFrom(credentialEntity))
122
+ }
@@ -0,0 +1,9 @@
1
+ import { DeleteExpiredStateArgs, DeleteStateArgs, GetActiveStateArgs, GetStatesArgs, SaveStateArgs, State } from '../types'
2
+
3
+ export abstract class IAbstractXStateStore {
4
+ abstract saveState(state: SaveStateArgs): Promise<State>
5
+ abstract getActiveState(args: GetActiveStateArgs): Promise<State>
6
+ abstract getStates(args?: GetStatesArgs): Promise<Array<State>>
7
+ abstract deleteState(args: DeleteStateArgs): Promise<boolean>
8
+ abstract deleteExpiredStates(args: DeleteExpiredStateArgs): Promise<boolean>
9
+ }
@@ -0,0 +1,107 @@
1
+ import { OrPromise } from '@sphereon/ssi-types'
2
+ import Debug from 'debug'
3
+ import { Brackets, DataSource, FindOptionsWhere, LessThan } from 'typeorm'
4
+
5
+ import { StateEntity } from '../entities/xstate/StateEntity'
6
+ import { DeleteExpiredStateArgs, DeleteStateArgs, GetActiveStateArgs, GetStatesArgs, SaveStateArgs, State } from '../types'
7
+ import { IAbstractXStateStore } from './IAbstractXStateStore'
8
+
9
+ const debug = Debug('sphereon:ssi-sdk:xstate')
10
+
11
+ export class XStateStore extends IAbstractXStateStore {
12
+ private readonly dbConnection: OrPromise<DataSource>
13
+
14
+ constructor(dbConnection: OrPromise<DataSource>) {
15
+ super()
16
+ this.dbConnection = dbConnection
17
+ }
18
+
19
+ async saveState(state: SaveStateArgs): Promise<State> {
20
+ const connection: DataSource = await this.dbConnection
21
+ debug(`Executing saveState with state: ${JSON.stringify(state)}`)
22
+ return connection.getRepository(StateEntity).save(XStateStore.stateEntityFrom(state))
23
+ }
24
+
25
+ async getActiveState(args: GetActiveStateArgs): Promise<State> {
26
+ const { tenantId, machineType } = args
27
+ const connection: DataSource = await this.dbConnection
28
+ debug(`Executing getActiveState query with machineType: ${machineType}, tenantId: ${tenantId}`)
29
+
30
+ const queryBuilder = connection
31
+ .getRepository(StateEntity)
32
+ .createQueryBuilder('state')
33
+ .where('state.completedAt IS NULL')
34
+ .andWhere(
35
+ new Brackets((qb) => {
36
+ qb.where('state.expiresAt IS NULL').orWhere('state.expiresAt > :now', { now: new Date() })
37
+ })
38
+ )
39
+ .orderBy('state.updatedAt', 'DESC')
40
+
41
+ if (tenantId) {
42
+ queryBuilder.andWhere('state.tenantId = :tenantId', { tenantId })
43
+ }
44
+ if (machineType) {
45
+ queryBuilder.andWhere('state.machineType = :machineType', { machineType })
46
+ }
47
+
48
+ const result = await queryBuilder.getOne()
49
+
50
+ if (!result) {
51
+ throw new Error(`No active state found for machineType: ${machineType}, tenantId: ${tenantId}`)
52
+ }
53
+ return XStateStore.stateFrom(result)
54
+ }
55
+
56
+ async getStates(args?: GetStatesArgs): Promise<Array<State>> {
57
+ const connection: DataSource = await this.dbConnection
58
+ debug('Getting states', args)
59
+ const result: Array<StateEntity> = await connection.getRepository(StateEntity).find({
60
+ ...(args?.filter && { where: args?.filter }),
61
+ })
62
+
63
+ return result.map((event: StateEntity) => XStateStore.stateFrom(event))
64
+ }
65
+
66
+ async deleteState(args: DeleteStateArgs): Promise<boolean> {
67
+ if (!args.id) {
68
+ throw new Error('No id parameter is provided.')
69
+ }
70
+ try {
71
+ const connection: DataSource = await this.dbConnection
72
+ debug(`Executing deleteState query with id: ${args.id}`)
73
+ const result = await connection.getRepository(StateEntity).delete(args.id)
74
+ return result.affected != null && result.affected > 0
75
+ } catch (error) {
76
+ debug(`Error deleting state: ${error}`)
77
+ return false
78
+ }
79
+ }
80
+
81
+ async deleteExpiredStates(args: DeleteExpiredStateArgs): Promise<boolean> {
82
+ try {
83
+ const connection: DataSource = await this.dbConnection
84
+ debug(`Executing deleteExpiredStates query with params: ${JSON.stringify(args)}`)
85
+ const deleteCriteria: FindOptionsWhere<StateEntity> = { expiresAt: LessThan(new Date()), ...(args.machineType && { type: args.machineType }) }
86
+ const result = await connection.getRepository(StateEntity).delete(deleteCriteria)
87
+ return result.affected != null && result.affected > 0
88
+ } catch (error) {
89
+ debug(`Error deleting state: ${error}`)
90
+ return false
91
+ }
92
+ }
93
+
94
+ public static stateFrom = (stateEntity: StateEntity): State => {
95
+ return {
96
+ ...stateEntity,
97
+ state: JSON.parse(stateEntity.state),
98
+ }
99
+ }
100
+
101
+ public static stateEntityFrom = (state: State | SaveStateArgs): StateEntity => {
102
+ const entity = new StateEntity()
103
+ Object.assign(entity, state)
104
+ entity.state = JSON.stringify(state.state)
105
+ return entity
106
+ }
107
+ }