From c08f28c6f456b359e48df37ddc3c03f2581afe81 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Thu, 19 Mar 2026 13:12:38 +0100 Subject: [PATCH 1/6] chore: fixes --- packages/credential-design-manager/README.md | 8 +- .../credentialDesignManagerAgentLogic.ts | 50 +++++------ .../credential-design-manager/package.json | 4 +- .../plugin.schema.json | 56 ++++++++----- .../src/agent/CredentialDesignManager.ts | 11 ++- .../src/types/ICredentialDesignManager.ts | 35 +++++++- packages/data-store-types/package.json | 6 +- .../credentialDesign/credentialDesign.ts | 18 ++-- packages/data-store/package.json | 12 +-- .../__tests__/credential-design-store.test.ts | 56 ++++++------- .../credential-design.entities.test.ts | 84 +++++++++---------- .../credentialDesign/CredentialDesignStore.ts | 62 +++++++------- .../CredentialDesignBrandingEntity.ts | 6 +- ...aDataKeyEntity.ts => MetadataKeyEntity.ts} | 14 ++-- ...aDataSetEntity.ts => MetadataSetEntity.ts} | 12 +-- ...aValueEntity.ts => MetadataValueEntity.ts} | 8 +- .../SchemaDefinitionEntity.ts | 6 +- .../src/entities/credentialDesign/index.ts | 6 +- packages/data-store/src/index.ts | 20 ++--- .../1773657426000-AddCredentialDesigns.ts | 6 +- .../utils/credentialDesign/MappingUtils.ts | 38 ++++----- 21 files changed, 282 insertions(+), 236 deletions(-) rename packages/data-store/src/entities/credentialDesign/{MetaDataKeyEntity.ts => MetadataKeyEntity.ts} (59%) rename packages/data-store/src/entities/credentialDesign/{MetaDataSetEntity.ts => MetadataSetEntity.ts} (77%) rename packages/data-store/src/entities/credentialDesign/{MetaDataValueEntity.ts => MetadataValueEntity.ts} (76%) diff --git a/packages/credential-design-manager/README.md b/packages/credential-design-manager/README.md index e760cac7e..205974f47 100644 --- a/packages/credential-design-manager/README.md +++ b/packages/credential-design-manager/README.md @@ -82,11 +82,11 @@ const result = await agent.cdmAddCredentialDesign({ tenantId: 'your-tenant-id', design: { label: 'MyCredentialDesign', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: 'MyCredentialDesign' }, ], @@ -122,11 +122,11 @@ const result = await agent.cdmUpdateCredentialDesign({ credentialDesignId, name: 'UpdatedDesignName', design: { - metaDataKeys: [ + metadataKeys: [ { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'sd-jwt' }], + metadataValues: [{ index: 0, textValue: 'sd-jwt' }], }, ], }, diff --git a/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts b/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts index e6f782bea..a50a1c9c3 100644 --- a/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts +++ b/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts @@ -21,11 +21,11 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro design: { label: 'DefaultDesign', tenantId: 'tenant-default', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: 'DefaultDesign' }, ], @@ -33,7 +33,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'sd-jwt' }], + metadataValues: [{ index: 0, textValue: 'sd-jwt' }], }, ], schemaDefinitions: [ @@ -68,11 +68,11 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro design: { label: 'TestDesign', tenantId: 'tenant-123', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: 'TestDesign' }, ], @@ -80,12 +80,12 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'jwt_vc_json' }], + metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], }, { key: 'advancedSchema', valueType: ValueType.Boolean, - metaDataValues: [{ index: 0, booleanValue: false }], + metadataValues: [{ index: 0, booleanValue: false }], }, ], schemaDefinitions: [ @@ -128,25 +128,25 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(result.label).toEqual(credentialDesign.name) expect(result.tenantId).toEqual(credentialDesign.tenantId) - expect(result.metaDataKeys).toBeDefined() - expect(result.metaDataKeys.length).toEqual(3) + expect(result.metadataKeys).toBeDefined() + expect(result.metadataKeys.length).toEqual(3) - const credentialTypeKey = result.metaDataKeys.find((k) => k.key === 'credentialType') + const credentialTypeKey = result.metadataKeys.find((k) => k.key === 'credentialType') expect(credentialTypeKey).toBeDefined() expect(credentialTypeKey!.valueType).toEqual(ValueType.Text) - expect(credentialTypeKey!.metaDataValues.length).toEqual(2) - expect(credentialTypeKey!.metaDataValues[0].textValue).toEqual('VerifiableCredential') - expect(credentialTypeKey!.metaDataValues[1].textValue).toEqual('TestDesign') + expect(credentialTypeKey!.metadataValues.length).toEqual(2) + expect(credentialTypeKey!.metadataValues[0].textValue).toEqual('VerifiableCredential') + expect(credentialTypeKey!.metadataValues[1].textValue).toEqual('TestDesign') - const credentialFormatKey = result.metaDataKeys.find((k) => k.key === 'credentialFormat') + const credentialFormatKey = result.metadataKeys.find((k) => k.key === 'credentialFormat') expect(credentialFormatKey).toBeDefined() - expect(credentialFormatKey!.metaDataValues.length).toEqual(1) - expect(credentialFormatKey!.metaDataValues[0].textValue).toEqual('jwt_vc_json') + expect(credentialFormatKey!.metadataValues.length).toEqual(1) + expect(credentialFormatKey!.metadataValues[0].textValue).toEqual('jwt_vc_json') - const advancedSchemaKey = result.metaDataKeys.find((k) => k.key === 'advancedSchema') + const advancedSchemaKey = result.metadataKeys.find((k) => k.key === 'advancedSchema') expect(advancedSchemaKey).toBeDefined() expect(advancedSchemaKey!.valueType).toEqual(ValueType.Boolean) - expect(advancedSchemaKey!.metaDataValues[0].booleanValue).toEqual(false) + expect(advancedSchemaKey!.metadataValues[0].booleanValue).toEqual(false) expect(result.schemaDefinitions).toBeDefined() expect(result.schemaDefinitions.length).toEqual(2) @@ -191,7 +191,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(result.id).toEqual(defaultCredentialDesign.id) expect(result.label).toEqual('DefaultDesign') expect(result.tenantId).toEqual('tenant-default') - expect(result.metaDataKeys.length).toEqual(2) + expect(result.metadataKeys.length).toEqual(2) expect(result.schemaDefinitions.length).toEqual(1) expect(result.branding).toBeDefined() expect(result.branding!.textColor).toEqual('#000000') @@ -230,11 +230,11 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro credentialDesignId: defaultCredentialDesign.id, name: updatedName, design: { - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: updatedName }, ], @@ -242,7 +242,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'jwt_vc_json' }], + metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], }, ], }, @@ -251,11 +251,11 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro const result: CredentialDesign = await agent.cdmUpdateCredentialDesign(args) expect(result.label).toEqual(updatedName) - expect(result.metaDataKeys.length).toEqual(2) + expect(result.metadataKeys.length).toEqual(2) - const credentialFormatKey = result.metaDataKeys.find((k) => k.key === 'credentialFormat') + const credentialFormatKey = result.metadataKeys.find((k) => k.key === 'credentialFormat') expect(credentialFormatKey).toBeDefined() - expect(credentialFormatKey!.metaDataValues[0].textValue).toEqual('jwt_vc_json') + expect(credentialFormatKey!.metadataValues[0].textValue).toEqual('jwt_vc_json') }) it('should throw error when updating credential design with unknown id', async (): Promise => { diff --git a/packages/credential-design-manager/package.json b/packages/credential-design-manager/package.json index a127fd45b..a88c223f0 100644 --- a/packages/credential-design-manager/package.json +++ b/packages/credential-design-manager/package.json @@ -27,11 +27,11 @@ "generate-plugin-schema": "tsx ../../packages/dev/bin/sphereon.js dev generate-plugin-schema" }, "dependencies": { - "@sphereon/ssi-sdk.data-store-types": "workspace:*", + "@sphereon/ssi-sdk.data-store-types": "0.37.1", "@veramo/core": "4.2.0" }, "devDependencies": { - "@sphereon/ssi-sdk.agent-config": "workspace:*", + "@sphereon/ssi-sdk.agent-config": "0.37.1", "@veramo/remote-client": "4.2.0", "@veramo/remote-server": "4.2.0", "cross-fetch": "^4.1.0", diff --git a/packages/credential-design-manager/plugin.schema.json b/packages/credential-design-manager/plugin.schema.json index 5253b8432..1aff6bd42 100644 --- a/packages/credential-design-manager/plugin.schema.json +++ b/packages/credential-design-manager/plugin.schema.json @@ -24,10 +24,10 @@ "type": "object", "additionalProperties": false, "properties": { - "metaDataKeys": { + "metadataKeys": { "type": "array", "items": { - "$ref": "#/components/schemas/NonPersistedMetaDataKey" + "$ref": "#/components/schemas/NonPersistedMetadataKey" } }, "schemaDefinitions": { @@ -50,14 +50,14 @@ "label" ] }, - "NonPersistedMetaDataKey": { + "NonPersistedMetadataKey": { "type": "object", "additionalProperties": false, "properties": { - "metaDataValues": { + "metadataValues": { "type": "array", "items": { - "$ref": "#/components/schemas/NonPersistedMetaDataValue" + "$ref": "#/components/schemas/NonPersistedMetadataValue" } }, "key": { @@ -69,17 +69,17 @@ }, "required": [ "key", - "metaDataValues", + "metadataValues", "valueType" ] }, - "NonPersistedMetaDataValue": { - "$ref": "#/components/schemas/Omit" + "NonPersistedMetadataValue": { + "$ref": "#/components/schemas/Omit" }, - "Omit": { - "$ref": "#/components/schemas/Pick>" + "Omit": { + "$ref": "#/components/schemas/Pick>" }, - "Pick>": { + "Pick>": { "type": "object", "properties": { "index": { @@ -210,10 +210,10 @@ "tenantId": { "type": "string" }, - "metaDataKeys": { + "metadataKeys": { "type": "array", "items": { - "$ref": "#/components/schemas/MetaDataKey" + "$ref": "#/components/schemas/MetadataKey" } }, "schemaDefinitions": { @@ -229,12 +229,12 @@ "required": [ "id", "label", - "metaDataKeys", + "metadataKeys", "schemaDefinitions" ], "additionalProperties": false }, - "MetaDataKey": { + "MetadataKey": { "type": "object", "properties": { "id": { @@ -246,10 +246,10 @@ "valueType": { "$ref": "#/components/schemas/ValueType" }, - "metaDataValues": { + "metadataValues": { "type": "array", "items": { - "$ref": "#/components/schemas/MetaDataValue" + "$ref": "#/components/schemas/MetadataValue" } } }, @@ -257,11 +257,11 @@ "id", "key", "valueType", - "metaDataValues" + "metadataValues" ], "additionalProperties": false }, - "MetaDataValue": { + "MetadataValue": { "type": "object", "properties": { "id": { @@ -430,6 +430,18 @@ ], "additionalProperties": false }, + "RemoveCredentialDesignResult": { + "type": "object", + "properties": { + "result": { + "type": "boolean" + } + }, + "required": [ + "result" + ], + "additionalProperties": false + }, "UpdateCredentialDesignArgs": { "type": "object", "properties": { @@ -460,10 +472,10 @@ "tenantId": { "type": "string" }, - "metaDataKeys": { + "metadataKeys": { "type": "array", "items": { - "$ref": "#/components/schemas/NonPersistedMetaDataKey" + "$ref": "#/components/schemas/NonPersistedMetadataKey" } }, "schemaDefinitions": { @@ -516,7 +528,7 @@ "$ref": "#/components/schemas/RemoveCredentialDesignArgs" }, "returnType": { - "type": "boolean" + "$ref": "#/components/schemas/RemoveCredentialDesignResult" } }, "cdmUpdateCredentialDesign": { diff --git a/packages/credential-design-manager/src/agent/CredentialDesignManager.ts b/packages/credential-design-manager/src/agent/CredentialDesignManager.ts index 11842e3f0..3c361e154 100644 --- a/packages/credential-design-manager/src/agent/CredentialDesignManager.ts +++ b/packages/credential-design-manager/src/agent/CredentialDesignManager.ts @@ -1,6 +1,6 @@ import { IAgentPlugin } from '@veramo/core' import { AbstractCredentialDesignStore, CredentialDesign } from '@sphereon/ssi-sdk.data-store-types' -import { schema } from '../index' +import { RemoveCredentialDesignResult, schema } from '../index' import { AddCredentialDesignArgs, GetCredentialDesignArgs, @@ -61,8 +61,11 @@ export class CredentialDesignManager implements IAgentPlugin { } /** {@inheritDoc ICredentialDesignManager.cdmRemoveCredentialDesign} */ - private async cdmRemoveCredentialDesign(args: RemoveCredentialDesignArgs, context: RequiredContext): Promise { - await this.store.removeCredentialDesign(args) - return true + private async cdmRemoveCredentialDesign(args: RemoveCredentialDesignArgs, context: RequiredContext): Promise { + return this.store.removeCredentialDesign(args).then(() => ({ + result: true + })).catch(() => ({ + result: false + })) } } diff --git a/packages/credential-design-manager/src/types/ICredentialDesignManager.ts b/packages/credential-design-manager/src/types/ICredentialDesignManager.ts index 034fa369e..71d89bb2b 100644 --- a/packages/credential-design-manager/src/types/ICredentialDesignManager.ts +++ b/packages/credential-design-manager/src/types/ICredentialDesignManager.ts @@ -1,13 +1,14 @@ import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config' import { IAgentContext, IPluginMethodMap } from '@veramo/core' import { CredentialDesign, NonPersistedCredentialDesign } from '@sphereon/ssi-sdk.data-store-types' +import { CredentialFormat } from '@sphereon/ssi-types' export interface ICredentialDesignManager extends IPluginMethodMap { cdmGetCredentialDesign(args: GetCredentialDesignArgs, context: RequiredContext): Promise cdmGetCredentialDesigns(args: GetCredentialDesignsArgs, context: RequiredContext): Promise> cdmAddCredentialDesign(args: AddCredentialDesignArgs, context: RequiredContext): Promise cdmUpdateCredentialDesign(args: UpdateCredentialDesignArgs, context: RequiredContext): Promise - cdmRemoveCredentialDesign(args: RemoveCredentialDesignArgs, context: RequiredContext): Promise + cdmRemoveCredentialDesign(args: RemoveCredentialDesignArgs, context: RequiredContext): Promise } export function contextHasCredentialDesignManager(context: IAgentContext): context is IAgentContext { @@ -25,9 +26,31 @@ export type GetCredentialDesignsArgs = { } export type AddCredentialDesignArgs = { - name: string - tenantId?: string - design?: NonPersistedCredentialDesign + identifier: string + schema: CredentialSchema + uiSchema: CredentialUISchema + options: { + format: CredentialFormat + vct?: string,//options.vct ?? null, + scope?: string + cryptographicBindingMethodsSupported: Array + credentialSigningAlgValuesSupported: Array + proofTypesSupported: Record + } + isAdvancedSchema: boolean + branding: { + logo: { + uri: string + } + backgroundImage: { + uri: string + } + textColor: string + backgroundColor: string + } + //name: string + //tenantId?: string + //design?: NonPersistedCredentialDesign } export type UpdateCredentialDesignArgs = { @@ -41,4 +64,8 @@ export type RemoveCredentialDesignArgs = { credentialDesignId: string } +export type RemoveCredentialDesignResult = { + result: boolean +} + export type RequiredContext = IAgentContext diff --git a/packages/data-store-types/package.json b/packages/data-store-types/package.json index 16d78fdbe..88804dcff 100644 --- a/packages/data-store-types/package.json +++ b/packages/data-store-types/package.json @@ -21,12 +21,12 @@ "build": "tsup --config ../../tsup.config.ts --tsconfig ../../tsconfig.tsup.json" }, "dependencies": { - "@sphereon/ssi-sdk.core": "workspace:*", - "@sphereon/ssi-types": "workspace:*", + "@sphereon/ssi-sdk.core": "0.37.1", + "@sphereon/ssi-types": "0.37.1", "dcql": "1.0.1" }, "devDependencies": { - "@sphereon/ssi-sdk-ext.identifier-resolution": "workspace:*" + "@sphereon/ssi-sdk-ext.identifier-resolution": "0.37.1" }, "files": [ "dist", diff --git a/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts b/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts index 7ceb6fd3f..d326b33f8 100644 --- a/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts +++ b/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts @@ -7,7 +7,7 @@ export enum ValueType { Date = 'Date', } -export type MetaDataValue = { +export type MetadataValue = { id: string index?: number textValue?: string @@ -16,17 +16,17 @@ export type MetaDataValue = { timestampValue?: Date } -export type NonPersistedMetaDataValue = Omit +export type NonPersistedMetadataValue = Omit -export type MetaDataKey = { +export type MetadataKey = { id: string key: string valueType: ValueType - metaDataValues: Array + metadataValues: Array } -export type NonPersistedMetaDataKey = Omit & { - metaDataValues: Array +export type NonPersistedMetadataKey = Omit & { + metadataValues: Array } export type SchemaDefinition = { @@ -58,13 +58,13 @@ export type CredentialDesign = { id: string label: string tenantId?: string - metaDataKeys: Array + metadataKeys: Array schemaDefinitions: Array branding?: CredentialDesignBranding } -export type NonPersistedCredentialDesign = Omit & { - metaDataKeys?: Array +export type NonPersistedCredentialDesign = Omit & { + metadataKeys?: Array schemaDefinitions?: Array branding?: NonPersistedCredentialDesignBranding } diff --git a/packages/data-store/package.json b/packages/data-store/package.json index a5b9f9f2b..2b92e9e3a 100644 --- a/packages/data-store/package.json +++ b/packages/data-store/package.json @@ -28,12 +28,12 @@ "dependencies": { "@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26", "@sphereon/pex": "5.0.0-unstable.28", - "@sphereon/ssi-sdk-ext.did-utils": "workspace:*", - "@sphereon/ssi-sdk-ext.identifier-resolution": "workspace:*", - "@sphereon/ssi-sdk.agent-config": "workspace:*", - "@sphereon/ssi-sdk.core": "workspace:*", - "@sphereon/ssi-sdk.data-store-types": "workspace:*", - "@sphereon/ssi-types": "workspace:*", + "@sphereon/ssi-sdk-ext.did-utils": "0.37.1", + "@sphereon/ssi-sdk-ext.identifier-resolution": "0.37.1", + "@sphereon/ssi-sdk.agent-config": "0.37.1", + "@sphereon/ssi-sdk.core": "0.37.1", + "@sphereon/ssi-sdk.data-store-types": "0.37.1", + "@sphereon/ssi-types": "0.37.1", "@veramo/core": "4.2.0", "@veramo/data-store": "4.2.0", "@veramo/utils": "4.2.0", diff --git a/packages/data-store/src/__tests__/credential-design-store.test.ts b/packages/data-store/src/__tests__/credential-design-store.test.ts index 69ac87e3c..0dd3a24d0 100644 --- a/packages/data-store/src/__tests__/credential-design-store.test.ts +++ b/packages/data-store/src/__tests__/credential-design-store.test.ts @@ -42,11 +42,11 @@ describe('Credential Design store tests', (): void => { design: { label: 'GetByIdDesign', tenantId: 'tenant-get-by-id', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'VerifiableCredential' }], + metadataValues: [{ index: 0, textValue: 'VerifiableCredential' }], }, ], schemaDefinitions: [ @@ -86,11 +86,11 @@ describe('Credential Design store tests', (): void => { design: { label: 'Design1', tenantId: 'tenant-1', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'VerifiableCredential' }], + metadataValues: [{ index: 0, textValue: 'VerifiableCredential' }], }, ], schemaDefinitions: [ @@ -112,11 +112,11 @@ describe('Credential Design store tests', (): void => { design: { label: 'Design2', tenantId: 'tenant-2', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'sd-jwt' }], + metadataValues: [{ index: 0, textValue: 'sd-jwt' }], }, ], schemaDefinitions: [ @@ -160,11 +160,11 @@ describe('Credential Design store tests', (): void => { design: { label: 'WholeDesign', tenantId: 'tenant-whole', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: 'WholeDesign' }, ], @@ -172,12 +172,12 @@ describe('Credential Design store tests', (): void => { { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'jwt_vc_json' }], + metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], }, { key: 'advancedSchema', valueType: ValueType.Boolean, - metaDataValues: [{ index: 0, booleanValue: false }], + metadataValues: [{ index: 0, booleanValue: false }], }, ], schemaDefinitions: [ @@ -212,7 +212,7 @@ describe('Credential Design store tests', (): void => { const result: Array = await store.getCredentialDesigns({ filter: { tenantId: 'tenant-whole' } }) expect(result.length).toEqual(1) - expect(result[0].metaDataKeys.length).toEqual(3) + expect(result[0].metadataKeys.length).toEqual(3) expect(result[0].schemaDefinitions.length).toEqual(2) expect(result[0].branding).toBeDefined() expect(result[0].branding!.logo).toBeDefined() @@ -234,11 +234,11 @@ describe('Credential Design store tests', (): void => { design: { label: 'AddDesign', tenantId: 'tenant-add', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: 'AddDesign' }, ], @@ -246,7 +246,7 @@ describe('Credential Design store tests', (): void => { { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'jwt_vc_json' }], + metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], }, ], schemaDefinitions: [ @@ -288,7 +288,7 @@ describe('Credential Design store tests', (): void => { expect(result.id).toBeDefined() expect(result.label).toEqual(args.name) expect(result.tenantId).toEqual(args.tenantId) - expect(result.metaDataKeys.length).toEqual(2) + expect(result.metadataKeys.length).toEqual(2) expect(result.schemaDefinitions.length).toEqual(2) expect(result.branding).toBeDefined() expect(result.branding!.textColor).toEqual('#FFFFFF') @@ -309,16 +309,16 @@ describe('Credential Design store tests', (): void => { design: { label: 'OriginalDesign', tenantId: 'tenant-original', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'VerifiableCredential' }], + metadataValues: [{ index: 0, textValue: 'VerifiableCredential' }], }, { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'jwt_vc_json' }], + metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], }, ], schemaDefinitions: [ @@ -341,11 +341,11 @@ describe('Credential Design store tests', (): void => { credentialDesignId: created.id, name: 'UpdatedDesign', design: { - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: 'UpdatedDesign' }, ], @@ -353,12 +353,12 @@ describe('Credential Design store tests', (): void => { { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'sd-jwt' }], + metadataValues: [{ index: 0, textValue: 'sd-jwt' }], }, { key: 'vct', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'https://example.com/vct' }], + metadataValues: [{ index: 0, textValue: 'https://example.com/vct' }], }, ], }, @@ -369,17 +369,17 @@ describe('Credential Design store tests', (): void => { expect(result).toBeDefined() expect(result.label).toEqual('UpdatedDesign') - expect(result.metaDataKeys.length).toEqual(3) + expect(result.metadataKeys.length).toEqual(3) - const credentialFormatKey = result.metaDataKeys.find((k) => k.key === 'credentialFormat') + const credentialFormatKey = result.metadataKeys.find((k) => k.key === 'credentialFormat') expect(credentialFormatKey).toBeDefined() - expect(credentialFormatKey!.metaDataValues[0].textValue).toEqual('sd-jwt') + expect(credentialFormatKey!.metadataValues[0].textValue).toEqual('sd-jwt') - const vctKey = result.metaDataKeys.find((k) => k.key === 'vct') + const vctKey = result.metadataKeys.find((k) => k.key === 'vct') expect(vctKey).toBeDefined() - expect(vctKey!.metaDataValues[0].textValue).toEqual('https://example.com/vct') + expect(vctKey!.metadataValues[0].textValue).toEqual('https://example.com/vct') - // Branding should remain untouched since we only updated metaDataKeys + // Branding should remain untouched since we only updated metadataKeys expect(result.branding).toBeDefined() expect(result.branding!.textColor).toEqual('#000000') }) diff --git a/packages/data-store/src/__tests__/credential-design.entities.test.ts b/packages/data-store/src/__tests__/credential-design.entities.test.ts index 414bf45aa..a4c6b0c99 100644 --- a/packages/data-store/src/__tests__/credential-design.entities.test.ts +++ b/packages/data-store/src/__tests__/credential-design.entities.test.ts @@ -2,12 +2,12 @@ import { DataSources } from '@sphereon/ssi-sdk.agent-config' import { NonPersistedCredentialDesign, ValueType } from '@sphereon/ssi-sdk.data-store-types' import { DataSource } from 'typeorm' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { MetaDataSetEntity, MetaDataKeyEntity, MetaDataValueEntity } from '../entities/credentialDesign' +import { MetadataSetEntity, MetadataKeyEntity, MetadataValueEntity } from '../entities/credentialDesign' import { DataStoreEntities, DataStoreMigrations } from '../index' import { credentialDesignBrandingEntityFrom, credentialDesignFrom, - metaDataKeyEntityFrom, + metadataKeyEntityFrom, schemaDefinitionEntityFrom, } from '../utils/credentialDesign/MappingUtils' @@ -37,11 +37,11 @@ describe('Credential Design entities tests', (): void => { const design: NonPersistedCredentialDesign = { label: 'TestCredentialDesign', tenantId: 'tenant-entity-test', - metaDataKeys: [ + metadataKeys: [ { key: 'credentialType', valueType: ValueType.Text, - metaDataValues: [ + metadataValues: [ { index: 0, textValue: 'VerifiableCredential' }, { index: 1, textValue: 'TestCredentialDesign' }, ], @@ -49,12 +49,12 @@ describe('Credential Design entities tests', (): void => { { key: 'credentialFormat', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'jwt_vc_json' }], + metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], }, { key: 'advancedSchema', valueType: ValueType.Boolean, - metaDataValues: [{ index: 0, booleanValue: false }], + metadataValues: [{ index: 0, booleanValue: false }], }, ], schemaDefinitions: [ @@ -90,15 +90,15 @@ describe('Credential Design entities tests', (): void => { } // Build entity graph using mappers - const metaDataSetEntity = new MetaDataSetEntity() - metaDataSetEntity.name = design.label - metaDataSetEntity.tenantId = design.tenantId - metaDataSetEntity.metaDataKeys = design.metaDataKeys!.map(metaDataKeyEntityFrom) - metaDataSetEntity.schemaDefinitions = design.schemaDefinitions!.map(schemaDefinitionEntityFrom) - metaDataSetEntity.credentialDesignBranding = credentialDesignBrandingEntityFrom(design.branding!) + const metadataSetEntity = new MetadataSetEntity() + metadataSetEntity.name = design.label + metadataSetEntity.tenantId = design.tenantId + metadataSetEntity.metadataKeys = design.metadataKeys!.map(metadataKeyEntityFrom) + metadataSetEntity.schemaDefinitions = design.schemaDefinitions!.map(schemaDefinitionEntityFrom) + metadataSetEntity.credentialDesignBranding = credentialDesignBrandingEntityFrom(design.branding!) // Save to DB - const savedEntity = await dbConnection.getRepository(MetaDataSetEntity).save(metaDataSetEntity) + const savedEntity = await dbConnection.getRepository(MetadataSetEntity).save(metadataSetEntity) // Map back to type const fromDb = credentialDesignFrom(savedEntity) @@ -109,32 +109,32 @@ describe('Credential Design entities tests', (): void => { expect(fromDb.label).toEqual(design.label) expect(fromDb.tenantId).toEqual(design.tenantId) - // ── MetaDataKeys ── - expect(fromDb.metaDataKeys).toBeDefined() - expect(fromDb.metaDataKeys.length).toEqual(3) + // ── MetadataKeys ── + expect(fromDb.metadataKeys).toBeDefined() + expect(fromDb.metadataKeys.length).toEqual(3) - const credentialTypeKey = fromDb.metaDataKeys.find((k) => k.key === 'credentialType') + const credentialTypeKey = fromDb.metadataKeys.find((k) => k.key === 'credentialType') expect(credentialTypeKey).toBeDefined() expect(credentialTypeKey!.id).toBeDefined() expect(credentialTypeKey!.valueType).toEqual(ValueType.Text) - expect(credentialTypeKey!.metaDataValues.length).toEqual(2) - expect(credentialTypeKey!.metaDataValues[0].id).toBeDefined() - expect(credentialTypeKey!.metaDataValues[0].index).toEqual(0) - expect(credentialTypeKey!.metaDataValues[0].textValue).toEqual('VerifiableCredential') - expect(credentialTypeKey!.metaDataValues[1].index).toEqual(1) - expect(credentialTypeKey!.metaDataValues[1].textValue).toEqual('TestCredentialDesign') - - const credentialFormatKey = fromDb.metaDataKeys.find((k) => k.key === 'credentialFormat') + expect(credentialTypeKey!.metadataValues.length).toEqual(2) + expect(credentialTypeKey!.metadataValues[0].id).toBeDefined() + expect(credentialTypeKey!.metadataValues[0].index).toEqual(0) + expect(credentialTypeKey!.metadataValues[0].textValue).toEqual('VerifiableCredential') + expect(credentialTypeKey!.metadataValues[1].index).toEqual(1) + expect(credentialTypeKey!.metadataValues[1].textValue).toEqual('TestCredentialDesign') + + const credentialFormatKey = fromDb.metadataKeys.find((k) => k.key === 'credentialFormat') expect(credentialFormatKey).toBeDefined() expect(credentialFormatKey!.valueType).toEqual(ValueType.Text) - expect(credentialFormatKey!.metaDataValues.length).toEqual(1) - expect(credentialFormatKey!.metaDataValues[0].textValue).toEqual('jwt_vc_json') + expect(credentialFormatKey!.metadataValues.length).toEqual(1) + expect(credentialFormatKey!.metadataValues[0].textValue).toEqual('jwt_vc_json') - const advancedSchemaKey = fromDb.metaDataKeys.find((k) => k.key === 'advancedSchema') + const advancedSchemaKey = fromDb.metadataKeys.find((k) => k.key === 'advancedSchema') expect(advancedSchemaKey).toBeDefined() expect(advancedSchemaKey!.valueType).toEqual(ValueType.Boolean) - expect(advancedSchemaKey!.metaDataValues.length).toEqual(1) - expect(advancedSchemaKey!.metaDataValues[0].booleanValue).toEqual(false) + expect(advancedSchemaKey!.metadataValues.length).toEqual(1) + expect(advancedSchemaKey!.metadataValues[0].booleanValue).toEqual(false) // ── SchemaDefinitions ── expect(fromDb.schemaDefinitions).toBeDefined() @@ -180,25 +180,25 @@ describe('Credential Design entities tests', (): void => { expect(fromDb.branding!.backgroundImage!.dimensions!.height).toEqual(design.branding!.backgroundImage!.dimensions!.height) }) - it('should cascade delete keys and values when removing MetaDataSet', async (): Promise => { - const metaDataSetEntity = new MetaDataSetEntity() - metaDataSetEntity.name = 'cascade_test' - metaDataSetEntity.metaDataKeys = [ - metaDataKeyEntityFrom({ + it('should cascade delete keys and values when removing MetadataSet', async (): Promise => { + const metadataSetEntity = new MetadataSetEntity() + metadataSetEntity.name = 'cascade_test' + metadataSetEntity.metadataKeys = [ + metadataKeyEntityFrom({ key: 'testKey', valueType: ValueType.Text, - metaDataValues: [{ index: 0, textValue: 'test_value' }], + metadataValues: [{ index: 0, textValue: 'test_value' }], }), ] - metaDataSetEntity.schemaDefinitions = [] + metadataSetEntity.schemaDefinitions = [] - const saved = await dbConnection.getRepository(MetaDataSetEntity).save(metaDataSetEntity) - expect(saved.metaDataKeys.length).toEqual(1) + const saved = await dbConnection.getRepository(MetadataSetEntity).save(metadataSetEntity) + expect(saved.metadataKeys.length).toEqual(1) - await dbConnection.getRepository(MetaDataSetEntity).remove(saved) + await dbConnection.getRepository(MetadataSetEntity).remove(saved) - const keys = await dbConnection.getRepository(MetaDataKeyEntity).find() - const values = await dbConnection.getRepository(MetaDataValueEntity).find() + const keys = await dbConnection.getRepository(MetadataKeyEntity).find() + const values = await dbConnection.getRepository(MetadataValueEntity).find() expect(keys.length).toEqual(0) expect(values.length).toEqual(0) }) diff --git a/packages/data-store/src/credentialDesign/CredentialDesignStore.ts b/packages/data-store/src/credentialDesign/CredentialDesignStore.ts index 59d6ee5d7..21b0f80e0 100644 --- a/packages/data-store/src/credentialDesign/CredentialDesignStore.ts +++ b/packages/data-store/src/credentialDesign/CredentialDesignStore.ts @@ -5,7 +5,7 @@ import { GetCredentialDesignArgs, GetCredentialDesignsArgs, NonPersistedCredentialDesignBranding, - NonPersistedMetaDataKey, + NonPersistedMetadataKey, NonPersistedSchemaDefinition, RemoveCredentialDesignArgs, UpdateCredentialDesignArgs, @@ -13,13 +13,13 @@ import { import { OrPromise } from '@sphereon/ssi-types' import Debug from 'debug' import { DataSource, EntityManager, Repository } from 'typeorm' -import { MetaDataSetEntity, MetaDataKeyEntity, MetaDataValueEntity, SchemaDefinitionEntity, CredentialDesignBrandingEntity } from '../entities/credentialDesign' +import { MetadataSetEntity, MetadataKeyEntity, MetadataValueEntity, SchemaDefinitionEntity, CredentialDesignBrandingEntity } from '../entities/credentialDesign' import { ImageAttributesEntity } from '../entities/issuanceBranding/ImageAttributesEntity' import { ImageDimensionsEntity } from '../entities/issuanceBranding/ImageDimensionsEntity' import { credentialDesignBrandingEntityFrom, credentialDesignFrom, - metaDataKeyEntityFrom, + metadataKeyEntityFrom, schemaDefinitionEntityFrom, } from '../utils/credentialDesign/MappingUtils' @@ -36,7 +36,7 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { getCredentialDesign = async (args: GetCredentialDesignArgs): Promise => { const { credentialDesignId } = args debug('getCredentialDesign', credentialDesignId) - const repo: Repository = (await this.dbConnection).getRepository(MetaDataSetEntity) + const repo: Repository = (await this.dbConnection).getRepository(MetadataSetEntity) const result = await repo.findOne({ where: { id: credentialDesignId }, }) @@ -50,7 +50,7 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { getCredentialDesigns = async (args?: GetCredentialDesignsArgs): Promise> => { debug('getCredentialDesigns', args) - const repo: Repository = (await this.dbConnection).getRepository(MetaDataSetEntity) + const repo: Repository = (await this.dbConnection).getRepository(MetadataSetEntity) const where = args?.filter?.tenantId ? { tenantId: args.filter.tenantId } : undefined const results = await repo.find({ where }) return results.map(credentialDesignFrom) @@ -61,28 +61,28 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { const dataSource = await this.dbConnection return dataSource.transaction(async (transactionalEntityManager) => { - const metaDataSet = new MetaDataSetEntity() - metaDataSet.name = args.name - metaDataSet.tenantId = args.tenantId - metaDataSet.metaDataKeys = [] - metaDataSet.schemaDefinitions = [] + const metadataSet = new MetadataSetEntity() + metadataSet.name = args.name + metadataSet.tenantId = args.tenantId + metadataSet.metadataKeys = [] + metadataSet.schemaDefinitions = [] const { design } = args if (design) { - if (design.metaDataKeys) { - metaDataSet.metaDataKeys = design.metaDataKeys.map(metaDataKeyEntityFrom) + if (design.metadataKeys) { + metadataSet.metadataKeys = design.metadataKeys.map(metadataKeyEntityFrom) } if (design.schemaDefinitions) { - metaDataSet.schemaDefinitions = design.schemaDefinitions.map(schemaDefinitionEntityFrom) + metadataSet.schemaDefinitions = design.schemaDefinitions.map(schemaDefinitionEntityFrom) } if (design.branding) { - metaDataSet.credentialDesignBranding = credentialDesignBrandingEntityFrom(design.branding) + metadataSet.credentialDesignBranding = credentialDesignBrandingEntityFrom(design.branding) } } - const saved = await transactionalEntityManager.save(MetaDataSetEntity, metaDataSet) + const saved = await transactionalEntityManager.save(MetadataSetEntity, metadataSet) return credentialDesignFrom(saved) }) } @@ -92,7 +92,7 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { const dataSource = await this.dbConnection return dataSource.transaction(async (transactionalEntityManager) => { - const existing = await transactionalEntityManager.findOne(MetaDataSetEntity, { + const existing = await transactionalEntityManager.findOne(MetadataSetEntity, { where: { id: args.credentialDesignId }, }) @@ -109,8 +109,8 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { const { design } = args if (design) { - if (design.metaDataKeys !== undefined) { - await this.replaceMetaDataKeys(transactionalEntityManager, existing, design.metaDataKeys) + if (design.metadataKeys !== undefined) { + await this.replaceMetadataKeys(transactionalEntityManager, existing, design.metadataKeys) } if (design.schemaDefinitions !== undefined) { @@ -122,14 +122,14 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { } } - const saved = await transactionalEntityManager.save(MetaDataSetEntity, existing) + const saved = await transactionalEntityManager.save(MetadataSetEntity, existing) return credentialDesignFrom(saved) }) } removeCredentialDesign = async (args: RemoveCredentialDesignArgs): Promise => { debug('removeCredentialDesign', args) - const repo: Repository = (await this.dbConnection).getRepository(MetaDataSetEntity) + const repo: Repository = (await this.dbConnection).getRepository(MetadataSetEntity) const existing = await repo.findOne({ where: { id: args.credentialDesignId }, }) @@ -141,25 +141,25 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { await repo.remove(existing) } - private async replaceMetaDataKeys( + private async replaceMetadataKeys( entityManager: EntityManager, - existing: MetaDataSetEntity, - newKeys: Array, + existing: MetadataSetEntity, + newKeys: Array, ): Promise { - if (existing.metaDataKeys?.length) { - for (const key of existing.metaDataKeys) { - if (key.metaDataValues?.length) { - await entityManager.remove(MetaDataValueEntity, key.metaDataValues) + if (existing.metadataKeys?.length) { + for (const key of existing.metadataKeys) { + if (key.metadataValues?.length) { + await entityManager.remove(MetadataValueEntity, key.metadataValues) } } - await entityManager.remove(MetaDataKeyEntity, existing.metaDataKeys) + await entityManager.remove(MetadataKeyEntity, existing.metadataKeys) } - existing.metaDataKeys = newKeys.map(metaDataKeyEntityFrom) + existing.metadataKeys = newKeys.map(metadataKeyEntityFrom) } private async replaceSchemaDefinitions( entityManager: EntityManager, - existing: MetaDataSetEntity, + existing: MetadataSetEntity, newSchemas: Array, ): Promise { if (existing.schemaDefinitions?.length) { @@ -170,7 +170,7 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { private async replaceBranding( entityManager: EntityManager, - existing: MetaDataSetEntity, + existing: MetadataSetEntity, newBranding: NonPersistedCredentialDesignBranding | undefined, ): Promise { if (existing.credentialDesignBranding) { diff --git a/packages/data-store/src/entities/credentialDesign/CredentialDesignBrandingEntity.ts b/packages/data-store/src/entities/credentialDesign/CredentialDesignBrandingEntity.ts index 8aa37039e..376cc5020 100644 --- a/packages/data-store/src/entities/credentialDesign/CredentialDesignBrandingEntity.ts +++ b/packages/data-store/src/entities/credentialDesign/CredentialDesignBrandingEntity.ts @@ -1,6 +1,6 @@ import { BaseEntity, Column, Entity, JoinColumn, ManyToOne, OneToOne, PrimaryGeneratedColumn } from 'typeorm' import { ImageAttributesEntity } from '../issuanceBranding/ImageAttributesEntity' -import { MetaDataSetEntity } from './MetaDataSetEntity' +import { MetadataSetEntity } from './MetadataSetEntity' @Entity('credential_design_branding') export class CredentialDesignBrandingEntity extends BaseEntity { @@ -31,9 +31,9 @@ export class CredentialDesignBrandingEntity extends BaseEntity { @JoinColumn({ name: 'background_image' }) backgroundImage?: ImageAttributesEntity - @OneToOne(() => MetaDataSetEntity, (set: MetaDataSetEntity) => set.credentialDesignBranding, { + @OneToOne(() => MetadataSetEntity, (set: MetadataSetEntity) => set.credentialDesignBranding, { onDelete: 'CASCADE', }) @JoinColumn({ name: 'meta_data_set_id' }) - metaDataSet!: MetaDataSetEntity + metadataSet!: MetadataSetEntity } diff --git a/packages/data-store/src/entities/credentialDesign/MetaDataKeyEntity.ts b/packages/data-store/src/entities/credentialDesign/MetadataKeyEntity.ts similarity index 59% rename from packages/data-store/src/entities/credentialDesign/MetaDataKeyEntity.ts rename to packages/data-store/src/entities/credentialDesign/MetadataKeyEntity.ts index a7d897a12..fcec7767e 100644 --- a/packages/data-store/src/entities/credentialDesign/MetaDataKeyEntity.ts +++ b/packages/data-store/src/entities/credentialDesign/MetadataKeyEntity.ts @@ -1,11 +1,11 @@ export { ValueType } from '@sphereon/ssi-sdk.data-store-types' import { ValueType } from '@sphereon/ssi-sdk.data-store-types' import { BaseEntity, Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm' -import { MetaDataSetEntity } from './MetaDataSetEntity' -import { MetaDataValueEntity } from './MetaDataValueEntity' +import { MetadataSetEntity } from './MetadataSetEntity' +import { MetadataValueEntity } from './MetadataValueEntity' @Entity('meta_data_keys') -export class MetaDataKeyEntity extends BaseEntity { +export class MetadataKeyEntity extends BaseEntity { @PrimaryGeneratedColumn('uuid') id!: string @@ -15,16 +15,16 @@ export class MetaDataKeyEntity extends BaseEntity { @Column('text', { name: 'key', nullable: false }) key!: string - @ManyToOne(() => MetaDataSetEntity, (set: MetaDataSetEntity) => set.metaDataKeys, { + @ManyToOne(() => MetadataSetEntity, (set: MetadataSetEntity) => set.metadataKeys, { onDelete: 'CASCADE', }) @JoinColumn({ name: 'set_id' }) - set!: MetaDataSetEntity + set!: MetadataSetEntity - @OneToMany(() => MetaDataValueEntity, (value: MetaDataValueEntity) => value.metaDataKey, { + @OneToMany(() => MetadataValueEntity, (value: MetadataValueEntity) => value.metadataKey, { cascade: true, onDelete: 'CASCADE', eager: true, }) - metaDataValues!: Array + metadataValues!: Array } diff --git a/packages/data-store/src/entities/credentialDesign/MetaDataSetEntity.ts b/packages/data-store/src/entities/credentialDesign/MetadataSetEntity.ts similarity index 77% rename from packages/data-store/src/entities/credentialDesign/MetaDataSetEntity.ts rename to packages/data-store/src/entities/credentialDesign/MetadataSetEntity.ts index fcfbe23a7..6cb8391d6 100644 --- a/packages/data-store/src/entities/credentialDesign/MetaDataSetEntity.ts +++ b/packages/data-store/src/entities/credentialDesign/MetadataSetEntity.ts @@ -1,11 +1,11 @@ import { BaseEntity, Column, Entity, Index, OneToMany, OneToOne, PrimaryGeneratedColumn } from 'typeorm' -import { MetaDataKeyEntity } from './MetaDataKeyEntity' +import { MetadataKeyEntity } from './MetadataKeyEntity' import { SchemaDefinitionEntity } from './SchemaDefinitionEntity' import { CredentialDesignBrandingEntity } from './CredentialDesignBrandingEntity' @Entity('meta_data_set') @Index('meta_data_set_unique_tenant', ['name', 'tenantId'], { unique: true }) -export class MetaDataSetEntity extends BaseEntity { +export class MetadataSetEntity extends BaseEntity { @PrimaryGeneratedColumn('uuid') id!: string @@ -15,21 +15,21 @@ export class MetaDataSetEntity extends BaseEntity { @Column('text', { name: 'name', nullable: false }) name!: string - @OneToMany(() => MetaDataKeyEntity, (key: MetaDataKeyEntity) => key.set, { + @OneToMany(() => MetadataKeyEntity, (key: MetadataKeyEntity) => key.set, { cascade: true, onDelete: 'CASCADE', eager: true, }) - metaDataKeys!: Array + metadataKeys!: Array - @OneToMany(() => SchemaDefinitionEntity, (schema: SchemaDefinitionEntity) => schema.metaDataSet, { + @OneToMany(() => SchemaDefinitionEntity, (schema: SchemaDefinitionEntity) => schema.metadataSet, { cascade: true, onDelete: 'CASCADE', eager: true, }) schemaDefinitions!: Array - @OneToOne(() => CredentialDesignBrandingEntity, (branding: CredentialDesignBrandingEntity) => branding.metaDataSet, { + @OneToOne(() => CredentialDesignBrandingEntity, (branding: CredentialDesignBrandingEntity) => branding.metadataSet, { cascade: true, onDelete: 'CASCADE', eager: true, diff --git a/packages/data-store/src/entities/credentialDesign/MetaDataValueEntity.ts b/packages/data-store/src/entities/credentialDesign/MetadataValueEntity.ts similarity index 76% rename from packages/data-store/src/entities/credentialDesign/MetaDataValueEntity.ts rename to packages/data-store/src/entities/credentialDesign/MetadataValueEntity.ts index 3d2be68d7..9b7ca2a72 100644 --- a/packages/data-store/src/entities/credentialDesign/MetaDataValueEntity.ts +++ b/packages/data-store/src/entities/credentialDesign/MetadataValueEntity.ts @@ -1,9 +1,9 @@ import { typeOrmDateTime } from '@sphereon/ssi-sdk.agent-config' import { BaseEntity, Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' -import { MetaDataKeyEntity } from './MetaDataKeyEntity' +import { MetadataKeyEntity } from './MetadataKeyEntity' @Entity('meta_data_values') -export class MetaDataValueEntity extends BaseEntity { +export class MetadataValueEntity extends BaseEntity { @PrimaryGeneratedColumn('uuid') id!: string @@ -22,9 +22,9 @@ export class MetaDataValueEntity extends BaseEntity { @Column({ name: 'timestamp_value', nullable: true, type: typeOrmDateTime() }) timestampValue?: Date - @ManyToOne(() => MetaDataKeyEntity, (key: MetaDataKeyEntity) => key.metaDataValues, { + @ManyToOne(() => MetadataKeyEntity, (key: MetadataKeyEntity) => key.metadataValues, { onDelete: 'CASCADE', }) @JoinColumn({ name: 'key_id' }) - metaDataKey!: MetaDataKeyEntity + metadataKey!: MetadataKeyEntity } diff --git a/packages/data-store/src/entities/credentialDesign/SchemaDefinitionEntity.ts b/packages/data-store/src/entities/credentialDesign/SchemaDefinitionEntity.ts index b243e1381..513b2cf6b 100644 --- a/packages/data-store/src/entities/credentialDesign/SchemaDefinitionEntity.ts +++ b/packages/data-store/src/entities/credentialDesign/SchemaDefinitionEntity.ts @@ -1,5 +1,5 @@ import { BaseEntity, Column, Entity, JoinColumn, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' -import { MetaDataSetEntity } from './MetaDataSetEntity' +import { MetadataSetEntity } from './MetadataSetEntity' import { FormStepEntity } from './FormStepEntity' @Entity('schema_definition') @@ -25,11 +25,11 @@ export class SchemaDefinitionEntity extends BaseEntity { @Column('text', { name: 'schema', nullable: false }) schema!: string - @ManyToOne(() => MetaDataSetEntity, (set: MetaDataSetEntity) => set.schemaDefinitions, { + @ManyToOne(() => MetadataSetEntity, (set: MetadataSetEntity) => set.schemaDefinitions, { onDelete: 'CASCADE', }) @JoinColumn({ name: 'meta_data_set_id' }) - metaDataSet!: MetaDataSetEntity + metadataSet!: MetadataSetEntity @ManyToMany(() => FormStepEntity, (formStep: FormStepEntity) => formStep.schemaDefinitions) formSteps!: Array diff --git a/packages/data-store/src/entities/credentialDesign/index.ts b/packages/data-store/src/entities/credentialDesign/index.ts index eeebca990..8765cad58 100644 --- a/packages/data-store/src/entities/credentialDesign/index.ts +++ b/packages/data-store/src/entities/credentialDesign/index.ts @@ -1,6 +1,6 @@ -export { MetaDataSetEntity } from './MetaDataSetEntity' -export { MetaDataKeyEntity, ValueType } from './MetaDataKeyEntity' -export { MetaDataValueEntity } from './MetaDataValueEntity' +export { MetadataSetEntity } from './MetadataSetEntity' +export { MetadataKeyEntity, ValueType } from './MetadataKeyEntity' +export { MetadataValueEntity } from './MetadataValueEntity' export { FormStepEntity } from './FormStepEntity' export { SchemaDefinitionEntity } from './SchemaDefinitionEntity' export { CredentialDesignBrandingEntity } from './CredentialDesignBrandingEntity' diff --git a/packages/data-store/src/index.ts b/packages/data-store/src/index.ts index cba4b9d8d..d4f1c30bb 100644 --- a/packages/data-store/src/index.ts +++ b/packages/data-store/src/index.ts @@ -29,9 +29,9 @@ import { IssuerBrandingEntity } from './entities/issuanceBranding/IssuerBranding import { IssuerLocaleBrandingEntity } from './entities/issuanceBranding/IssuerLocaleBrandingEntity' import { TextAttributesEntity } from './entities/issuanceBranding/TextAttributesEntity' import { MachineStateInfoEntity } from './entities/machineState/MachineStateInfoEntity' -import { MetaDataSetEntity } from './entities/credentialDesign/MetaDataSetEntity' -import { MetaDataKeyEntity } from './entities/credentialDesign/MetaDataKeyEntity' -import { MetaDataValueEntity } from './entities/credentialDesign/MetaDataValueEntity' +import { MetadataSetEntity } from './entities/credentialDesign/MetadataSetEntity' +import { MetadataKeyEntity } from './entities/credentialDesign/MetadataKeyEntity' +import { MetadataValueEntity } from './entities/credentialDesign/MetadataValueEntity' import { FormStepEntity } from './entities/credentialDesign/FormStepEntity' import { SchemaDefinitionEntity } from './entities/credentialDesign/SchemaDefinitionEntity' import { CredentialDesignBrandingEntity } from './entities/credentialDesign/CredentialDesignBrandingEntity' @@ -125,9 +125,9 @@ export const DataStoreDigitalCredentialEntities = [DigitalCredentialEntity] export const DataStoreMachineStateEntities = [MachineStateInfoEntity] export const DataStoreCredentialDesignEntities = [ - MetaDataSetEntity, - MetaDataKeyEntity, - MetaDataValueEntity, + MetadataSetEntity, + MetadataKeyEntity, + MetadataValueEntity, FormStepEntity, SchemaDefinitionEntity, CredentialDesignBrandingEntity, @@ -187,12 +187,12 @@ export { ContactMetadataItemEntity, CredentialClaimsEntity, Oid4vcStateEntity, - MetaDataSetEntity, - MetaDataKeyEntity, - MetaDataValueEntity, + MetadataSetEntity, + MetadataKeyEntity, + MetadataValueEntity, FormStepEntity, SchemaDefinitionEntity, CredentialDesignBrandingEntity, } -export { ValueType } from './entities/credentialDesign/MetaDataKeyEntity' +export { ValueType } from './entities/credentialDesign/MetadataKeyEntity' diff --git a/packages/data-store/src/migrations/postgres/1773657426000-AddCredentialDesigns.ts b/packages/data-store/src/migrations/postgres/1773657426000-AddCredentialDesigns.ts index 4d2bc7f95..dba0cf7d7 100644 --- a/packages/data-store/src/migrations/postgres/1773657426000-AddCredentialDesigns.ts +++ b/packages/data-store/src/migrations/postgres/1773657426000-AddCredentialDesigns.ts @@ -6,7 +6,11 @@ export class AddCredentialDesignsPostgres1773657426000 implements MigrationInter public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(` - CREATE TYPE IF NOT EXISTS "value_type" AS ENUM ('Text', 'Number', 'Boolean', 'Date'); + DO $$ BEGIN + CREATE TYPE "value_type" AS ENUM ('Text', 'Number', 'Boolean', 'Date'); + EXCEPTION + WHEN duplicate_object THEN NULL; + END $$; `) await queryRunner.query(` diff --git a/packages/data-store/src/utils/credentialDesign/MappingUtils.ts b/packages/data-store/src/utils/credentialDesign/MappingUtils.ts index 85fc168f9..16a0f71cc 100644 --- a/packages/data-store/src/utils/credentialDesign/MappingUtils.ts +++ b/packages/data-store/src/utils/credentialDesign/MappingUtils.ts @@ -2,29 +2,29 @@ import type { CredentialDesign, CredentialDesignBranding, IImageAttributes, - MetaDataKey, - MetaDataValue, + MetadataKey, + MetadataValue, NonPersistedCredentialDesignBranding, - NonPersistedMetaDataKey, - NonPersistedMetaDataValue, + NonPersistedMetadataKey, + NonPersistedMetadataValue, NonPersistedSchemaDefinition, SchemaDefinition, } from '@sphereon/ssi-sdk.data-store-types' import { CredentialDesignBrandingEntity } from '../../entities/credentialDesign' -import { MetaDataKeyEntity, ValueType } from '../../entities/credentialDesign' -import { MetaDataSetEntity } from '../../entities/credentialDesign' -import { MetaDataValueEntity } from '../../entities/credentialDesign' +import { MetadataKeyEntity, ValueType } from '../../entities/credentialDesign' +import { MetadataSetEntity } from '../../entities/credentialDesign' +import { MetadataValueEntity } from '../../entities/credentialDesign' import { SchemaDefinitionEntity } from '../../entities/credentialDesign' import { ImageAttributesEntity } from '../../entities/issuanceBranding/ImageAttributesEntity' import { replaceNullWithUndefined } from '../FormattingUtils' import { imageAttributesEntityFrom } from '../issuanceBranding/MappingUtils' -export const credentialDesignFrom = (entity: MetaDataSetEntity): CredentialDesign => { +export const credentialDesignFrom = (entity: MetadataSetEntity): CredentialDesign => { const result: CredentialDesign = { id: entity.id, label: entity.name, tenantId: entity.tenantId, - metaDataKeys: entity.metaDataKeys?.map((key) => metaDataKeyFrom(key)) ?? [], + metadataKeys: entity.metadataKeys?.map((key) => metadataKeyFrom(key)) ?? [], schemaDefinitions: entity.schemaDefinitions?.map((schema) => schemaDefinitionFrom(schema)) ?? [], branding: entity.credentialDesignBranding ? credentialDesignBrandingFrom(entity.credentialDesignBranding) : undefined, } @@ -32,19 +32,19 @@ export const credentialDesignFrom = (entity: MetaDataSetEntity): CredentialDesig return replaceNullWithUndefined(result) } -export const metaDataKeyFrom = (entity: MetaDataKeyEntity): MetaDataKey => { - const result: MetaDataKey = { +export const metadataKeyFrom = (entity: MetadataKeyEntity): MetadataKey => { + const result: MetadataKey = { id: entity.id, key: entity.key, valueType: entity.valueType, - metaDataValues: entity.metaDataValues?.map((value) => metaDataValueFrom(value)) ?? [], + metadataValues: entity.metadataValues?.map((value) => metadataValueFrom(value)) ?? [], } return replaceNullWithUndefined(result) } -export const metaDataValueFrom = (entity: MetaDataValueEntity): MetaDataValue => { - const result: MetaDataValue = { +export const metadataValueFrom = (entity: MetadataValueEntity): MetadataValue => { + const result: MetadataValue = { id: entity.id, index: entity.index, textValue: entity.textValue, @@ -101,16 +101,16 @@ export const imageAttributesFrom = (entity: ImageAttributesEntity): IImageAttrib return replaceNullWithUndefined(result) } -export const metaDataKeyEntityFrom = (input: NonPersistedMetaDataKey): MetaDataKeyEntity => { - const keyEntity = new MetaDataKeyEntity() +export const metadataKeyEntityFrom = (input: NonPersistedMetadataKey): MetadataKeyEntity => { + const keyEntity = new MetadataKeyEntity() keyEntity.key = input.key keyEntity.valueType = input.valueType as ValueType - keyEntity.metaDataValues = input.metaDataValues.map((valInput) => metaDataValueEntityFrom(valInput)) + keyEntity.metadataValues = input.metadataValues.map((valInput) => metadataValueEntityFrom(valInput)) return keyEntity } -export const metaDataValueEntityFrom = (input: NonPersistedMetaDataValue): MetaDataValueEntity => { - const valEntity = new MetaDataValueEntity() +export const metadataValueEntityFrom = (input: NonPersistedMetadataValue): MetadataValueEntity => { + const valEntity = new MetadataValueEntity() valEntity.index = input.index valEntity.textValue = input.textValue valEntity.numberValue = input.numberValue From 6c53e3a7f6045d95e0d238ea5e8b08ca535f852a Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Thu, 19 Mar 2026 16:25:29 +0100 Subject: [PATCH 2/6] chore: credential-design-manager fixes --- packages/credential-design-manager/README.md | 107 +++--- .../credentialDesignManagerAgentLogic.ts | 341 ++++++++++-------- .../plugin.schema.json | 304 +++++++++------- .../src/agent/CredentialDesignManager.ts | 215 ++++++++++- .../src/types/ICredentialDesignManager.ts | 83 +++-- .../AbstractCredentialDesignStore.ts | 4 + .../IAbstractCredentialDesignStore.ts | 17 +- .../credentialDesign/credentialDesign.ts | 2 +- .../__tests__/credential-design-store.test.ts | 26 +- .../credentialDesign/CredentialDesignStore.ts | 50 ++- .../utils/credentialDesign/MappingUtils.ts | 2 +- 11 files changed, 748 insertions(+), 403 deletions(-) diff --git a/packages/credential-design-manager/README.md b/packages/credential-design-manager/README.md index 205974f47..69ff97764 100644 --- a/packages/credential-design-manager/README.md +++ b/packages/credential-design-manager/README.md @@ -14,13 +14,17 @@ A Veramo credential design manager plugin. This plugin manages credential designs, including metadata keys, schema definitions, and branding configurations, and persists them. These designs can then be used to configure credential issuance and presentation. +The manager accepts high-level arguments (schema, uiSchema, credential format options, branding) and translates them into the underlying data store format (metadata keys, schema definitions, branding entities). + ## Available functions - cdmGetCredentialDesign -- cdmGetCredentialDesigns +- cdmGetCredentialDesigns (with pagination: limit, offset) - cdmAddCredentialDesign - cdmUpdateCredentialDesign - cdmRemoveCredentialDesign +- cdmCredentialDesignCount +- cdmFormStepGetOrCreate ## Usage @@ -51,67 +55,62 @@ const agent = createAgent({ }) ``` -### Get a credential design: +### Add a credential design: ```typescript -const credentialDesignId = '8efb937f-4e90-4056-9a4d-7185ce8dc173' -const result = await agent.cdmGetCredentialDesign({ - credentialDesignId, +const result = await agent.cdmAddCredentialDesign({ + identifier: 'MyCredentialDesign', + tenantId: 'your-tenant-id', + schema: { type: 'object', properties: { name: { type: 'string' } } }, + uiSchema: { type: 'VerticalLayout', elements: [{ type: 'Control', scope: '#/properties/name' }] }, + options: { + format: 'sd-jwt', + vct: 'MyVCT', + scope: 'my_scope', + cryptographicBindingMethodsSupported: ['did:key', 'did:jwk'], + credentialSigningAlgValuesSupported: ['ES256'], + proofTypesSupported: { jwt: { proof_signing_alg_values_supported: ['ES256'] } }, + }, + isAdvancedSchema: false, + branding: { + textColor: '#FFFFFF', + backgroundColor: '#003399', + logo: { + uri: 'https://example.com/logo.png', + mediaType: 'image/png', + alt: 'Logo', + dimensions: { width: 200, height: 100 }, + }, + }, }) ``` -### Get credential designs: +### Get a credential design: ```typescript -const result = await agent.cdmGetCredentialDesigns() +const credentialDesignId = '8efb937f-4e90-4056-9a4d-7185ce8dc173' +const result = await agent.cdmGetCredentialDesign({ + credentialDesignId, +}) ``` -### Get credential designs by tenant: +### List credential designs with pagination: ```typescript const result = await agent.cdmGetCredentialDesigns({ filter: { tenantId: 'your-tenant-id' }, + limit: 10, + offset: 0, }) ``` -### Add a credential design: +### Count credential designs: ```typescript -const result = await agent.cdmAddCredentialDesign({ - name: 'MyCredentialDesign', - tenantId: 'your-tenant-id', - design: { - label: 'MyCredentialDesign', - metadataKeys: [ - { - key: 'credentialType', - valueType: ValueType.Text, - metadataValues: [ - { index: 0, textValue: 'VerifiableCredential' }, - { index: 1, textValue: 'MyCredentialDesign' }, - ], - }, - ], - schemaDefinitions: [ - { - correlationId: 'MyCredentialDesign', - schemaType: 'Data', - entityType: 'VC', - schema: JSON.stringify({ type: 'object', properties: { name: { type: 'string' } } }), - }, - ], - branding: { - textColor: '#FFFFFF', - backgroundColor: '#003399', - logo: { - uri: 'https://example.com/logo.png', - mediaType: 'image/png', - alt: 'Logo', - dimensions: { width: 200, height: 100 }, - }, - }, - }, +const result = await agent.cdmCredentialDesignCount({ + filter: { tenantId: 'your-tenant-id' }, }) +console.log(result.count) ``` ### Update a credential design: @@ -120,15 +119,11 @@ const result = await agent.cdmAddCredentialDesign({ const credentialDesignId = '8efb937f-4e90-4056-9a4d-7185ce8dc173' const result = await agent.cdmUpdateCredentialDesign({ credentialDesignId, - name: 'UpdatedDesignName', - design: { - metadataKeys: [ - { - key: 'credentialFormat', - valueType: ValueType.Text, - metadataValues: [{ index: 0, textValue: 'sd-jwt' }], - }, - ], + identifier: 'UpdatedDesignName', + schema: { type: 'object', properties: { age: { type: 'number' } } }, + uiSchema: { type: 'VerticalLayout', elements: [{ type: 'Control', scope: '#/properties/age' }] }, + options: { + format: 'sd-jwt', }, }) ``` @@ -138,6 +133,14 @@ const result = await agent.cdmUpdateCredentialDesign({ ```typescript const credentialDesignId = 'ef6e13b2-a520-4bb6-9a13-9be529ce22b8' const result = await agent.cdmRemoveCredentialDesign({ credentialDesignId }) +console.log(result.result) // true +``` + +### Get or create a form step: + +```typescript +const result = await agent.cdmFormStepGetOrCreate({ formId: 'credentialIssuanceWizard' }) +console.log(result.formStepId) ``` ## Installation diff --git a/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts b/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts index a50a1c9c3..c79cc0019 100644 --- a/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts +++ b/packages/credential-design-manager/__tests__/shared/credentialDesignManagerAgentLogic.ts @@ -1,6 +1,10 @@ import { TAgent } from '@veramo/core' -import { AddCredentialDesignArgs, CredentialDesign, ValueType } from '@sphereon/ssi-sdk.data-store-types' -import { ICredentialDesignManager, UpdateCredentialDesignArgs } from '../../src' +import { CredentialDesign } from '@sphereon/ssi-sdk.data-store-types' +import { + AddCredentialDesignArgs, + ICredentialDesignManager, + UpdateCredentialDesignArgs, +} from '../../src' import { afterAll, beforeAll, describe, expect, it } from 'vitest' @@ -16,42 +20,18 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro agent = testContext.getAgent() defaultCredentialDesign = await agent.cdmAddCredentialDesign({ - name: 'DefaultDesign', + identifier: 'DefaultDesign', tenantId: 'tenant-default', - design: { - label: 'DefaultDesign', - tenantId: 'tenant-default', - metadataKeys: [ - { - key: 'credentialType', - valueType: ValueType.Text, - metadataValues: [ - { index: 0, textValue: 'VerifiableCredential' }, - { index: 1, textValue: 'DefaultDesign' }, - ], - }, - { - key: 'credentialFormat', - valueType: ValueType.Text, - metadataValues: [{ index: 0, textValue: 'sd-jwt' }], - }, - ], - schemaDefinitions: [ - { - correlationId: 'DefaultDesign', - schemaType: 'Data', - entityType: 'VC', - schema: JSON.stringify({ type: 'object', properties: { age: { type: 'number' } } }), - }, - ], - branding: { - textColor: '#000000', - backgroundColor: '#EEEEEE', - logo: { - uri: 'https://example.com/default-logo.png', - mediaType: 'image/png', - alt: 'Default Logo', - }, + schema: { type: 'object', properties: { age: { type: 'number' } } }, + uiSchema: { type: 'VerticalLayout', elements: [] }, + options: { + format: 'sd-jwt', + }, + branding: { + textColor: '#000000', + backgroundColor: '#EEEEEE', + logo: { + uri: 'https://example.com/default-logo.png', }, }, }) @@ -62,92 +42,75 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro }) it('should add a credential design', async (): Promise => { - const credentialDesign: AddCredentialDesignArgs = { - name: 'TestDesign', + const args: AddCredentialDesignArgs = { + identifier: 'TestDesign', tenantId: 'tenant-123', - design: { - label: 'TestDesign', - tenantId: 'tenant-123', - metadataKeys: [ - { - key: 'credentialType', - valueType: ValueType.Text, - metadataValues: [ - { index: 0, textValue: 'VerifiableCredential' }, - { index: 1, textValue: 'TestDesign' }, - ], - }, - { - key: 'credentialFormat', - valueType: ValueType.Text, - metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], - }, - { - key: 'advancedSchema', - valueType: ValueType.Boolean, - metadataValues: [{ index: 0, booleanValue: false }], - }, - ], - schemaDefinitions: [ - { - correlationId: 'TestDesign', - schemaType: 'Data', - entityType: 'VC', - schema: JSON.stringify({ type: 'object', properties: { name: { type: 'string' } } }), - }, - { - correlationId: 'TestDesign', - schemaType: 'UI_Form', - entityType: 'VC', - schema: JSON.stringify({ type: 'VerticalLayout', elements: [] }), - }, - ], - branding: { - textColor: '#FFFFFF', - backgroundColor: '#003399', - logo: { - uri: 'https://example.com/logo.png', - mediaType: 'image/png', - alt: 'Company Logo', - dimensions: { width: 200, height: 100 }, - }, - backgroundImage: { - uri: 'https://example.com/bg.jpg', - mediaType: 'image/jpeg', - alt: 'Background', - dimensions: { width: 1920, height: 1080 }, - }, + schema: { type: 'object', properties: { name: { type: 'string' } } }, + uiSchema: { type: 'VerticalLayout', elements: [] }, + options: { + format: 'jwt_vc_json', + vct: 'TestVCT', + scope: 'test_scope', + cryptographicBindingMethodsSupported: ['did:key', 'did:jwk'], + credentialSigningAlgValuesSupported: ['ES256', 'EdDSA'], + proofTypesSupported: { jwt: { proof_signing_alg_values_supported: ['ES256'] } }, + }, + isAdvancedSchema: false, + branding: { + textColor: '#FFFFFF', + backgroundColor: '#003399', + logo: { + uri: 'https://example.com/logo.png', + dimensions: { width: 200, height: 100 }, + }, + backgroundImage: { + uri: 'https://example.com/bg.jpg', + dimensions: { width: 1920, height: 1080 }, }, }, } - const result: CredentialDesign = await agent.cdmAddCredentialDesign(credentialDesign) + const result: CredentialDesign = await agent.cdmAddCredentialDesign(args) expect(result).toBeDefined() expect(result.id).toBeDefined() - expect(result.label).toEqual(credentialDesign.name) - expect(result.tenantId).toEqual(credentialDesign.tenantId) + expect(result.identifier).toEqual(args.identifier) + expect(result.tenantId).toEqual(args.tenantId) + // Verify metadata keys are built from options expect(result.metadataKeys).toBeDefined() - expect(result.metadataKeys.length).toEqual(3) - const credentialTypeKey = result.metadataKeys.find((k) => k.key === 'credentialType') - expect(credentialTypeKey).toBeDefined() - expect(credentialTypeKey!.valueType).toEqual(ValueType.Text) - expect(credentialTypeKey!.metadataValues.length).toEqual(2) - expect(credentialTypeKey!.metadataValues[0].textValue).toEqual('VerifiableCredential') - expect(credentialTypeKey!.metadataValues[1].textValue).toEqual('TestDesign') + const formatKey = result.metadataKeys.find((k) => k.key === 'format') + expect(formatKey).toBeDefined() + expect(formatKey!.metadataValues[0].textValue).toEqual('jwt_vc_json') + + const vctKey = result.metadataKeys.find((k) => k.key === 'vct') + expect(vctKey).toBeDefined() + expect(vctKey!.metadataValues[0].textValue).toEqual('TestVCT') + + const scopeKey = result.metadataKeys.find((k) => k.key === 'scope') + expect(scopeKey).toBeDefined() + expect(scopeKey!.metadataValues[0].textValue).toEqual('test_scope') + + const bindingMethodsKey = result.metadataKeys.find((k) => k.key === 'cryptographicBindingMethodsSupported') + expect(bindingMethodsKey).toBeDefined() + expect(bindingMethodsKey!.metadataValues.length).toEqual(2) + expect(bindingMethodsKey!.metadataValues[0].textValue).toEqual('did:key') + expect(bindingMethodsKey!.metadataValues[1].textValue).toEqual('did:jwk') - const credentialFormatKey = result.metadataKeys.find((k) => k.key === 'credentialFormat') - expect(credentialFormatKey).toBeDefined() - expect(credentialFormatKey!.metadataValues.length).toEqual(1) - expect(credentialFormatKey!.metadataValues[0].textValue).toEqual('jwt_vc_json') + const signingAlgKey = result.metadataKeys.find((k) => k.key === 'credentialSigningAlgValuesSupported') + expect(signingAlgKey).toBeDefined() + expect(signingAlgKey!.metadataValues.length).toEqual(2) - const advancedSchemaKey = result.metadataKeys.find((k) => k.key === 'advancedSchema') + const proofTypesKey = result.metadataKeys.find((k) => k.key === 'proofTypesSupported') + expect(proofTypesKey).toBeDefined() + expect(JSON.parse(proofTypesKey!.metadataValues[0].textValue!)).toEqual(args.options.proofTypesSupported) + + const advancedSchemaKey = result.metadataKeys.find((k) => k.key === 'isAdvancedSchema') expect(advancedSchemaKey).toBeDefined() - expect(advancedSchemaKey!.valueType).toEqual(ValueType.Boolean) expect(advancedSchemaKey!.metadataValues[0].booleanValue).toEqual(false) + // Verify schema definitions are built from schema + uiSchema expect(result.schemaDefinitions).toBeDefined() expect(result.schemaDefinitions.length).toEqual(2) @@ -155,33 +118,28 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(dataSchema).toBeDefined() expect(dataSchema!.correlationId).toEqual('TestDesign') expect(dataSchema!.entityType).toEqual('VC') - expect(dataSchema!.schema).toEqual(credentialDesign.design!.schemaDefinitions![0].schema) + expect(JSON.parse(dataSchema!.schema)).toEqual(args.schema) const uiSchema = result.schemaDefinitions.find((s) => s.schemaType === 'UI_Form') expect(uiSchema).toBeDefined() - expect(uiSchema!.correlationId).toEqual('TestDesign') - expect(uiSchema!.schema).toEqual(credentialDesign.design!.schemaDefinitions![1].schema) + expect(JSON.parse(uiSchema!.schema)).toEqual(args.uiSchema) + // Verify branding expect(result.branding).toBeDefined() expect(result.branding!.textColor).toEqual('#FFFFFF') expect(result.branding!.backgroundColor).toEqual('#003399') expect(result.branding!.logo).toBeDefined() expect(result.branding!.logo!.uri).toEqual('https://example.com/logo.png') - expect(result.branding!.logo!.mediaType).toEqual('image/png') - expect(result.branding!.logo!.alt).toEqual('Company Logo') expect(result.branding!.logo!.dimensions).toBeDefined() expect(result.branding!.logo!.dimensions!.width).toEqual(200) expect(result.branding!.logo!.dimensions!.height).toEqual(100) expect(result.branding!.backgroundImage).toBeDefined() expect(result.branding!.backgroundImage!.uri).toEqual('https://example.com/bg.jpg') - expect(result.branding!.backgroundImage!.mediaType).toEqual('image/jpeg') - expect(result.branding!.backgroundImage!.alt).toEqual('Background') expect(result.branding!.backgroundImage!.dimensions).toBeDefined() expect(result.branding!.backgroundImage!.dimensions!.width).toEqual(1920) expect(result.branding!.backgroundImage!.dimensions!.height).toEqual(1080) - }) it('should get a credential design by id', async (): Promise => { @@ -189,10 +147,9 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(result).toBeDefined() expect(result.id).toEqual(defaultCredentialDesign.id) - expect(result.label).toEqual('DefaultDesign') + expect(result.identifier).toEqual('DefaultDesign') expect(result.tenantId).toEqual('tenant-default') - expect(result.metadataKeys.length).toEqual(2) - expect(result.schemaDefinitions.length).toEqual(1) + expect(result.schemaDefinitions.length).toEqual(2) expect(result.branding).toBeDefined() expect(result.branding!.textColor).toEqual('#000000') expect(result.branding!.logo).toBeDefined() @@ -215,7 +172,7 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro const result: Array = await agent.cdmGetCredentialDesigns({ filter: { tenantId: 'tenant-default' } }) expect(result.length).toBe(1) - expect(result[0].label).toEqual('DefaultDesign') + expect(result[0].identifier).toEqual('DefaultDesign') }) it('should return no credential designs if filter does not match', async (): Promise => { @@ -224,54 +181,142 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro expect(result.length).toBe(0) }) + it('should get credential designs with pagination using limit', async (): Promise => { + // Add extra designs for pagination testing + await agent.cdmAddCredentialDesign({ + identifier: 'PaginationDesign1', + tenantId: 'tenant-pagination', + schema: { type: 'object' }, + uiSchema: { type: 'VerticalLayout', elements: [] }, + options: { format: 'sd-jwt' }, + }) + await agent.cdmAddCredentialDesign({ + identifier: 'PaginationDesign2', + tenantId: 'tenant-pagination', + schema: { type: 'object' }, + uiSchema: { type: 'VerticalLayout', elements: [] }, + options: { format: 'sd-jwt' }, + }) + await agent.cdmAddCredentialDesign({ + identifier: 'PaginationDesign3', + tenantId: 'tenant-pagination', + schema: { type: 'object' }, + uiSchema: { type: 'VerticalLayout', elements: [] }, + options: { format: 'sd-jwt' }, + }) + + const page1 = await agent.cdmGetCredentialDesigns({ filter: { tenantId: 'tenant-pagination' }, limit: 2, offset: 0 }) + expect(page1.length).toBe(2) + + const page2 = await agent.cdmGetCredentialDesigns({ filter: { tenantId: 'tenant-pagination' }, limit: 2, offset: 2 }) + expect(page2.length).toBe(1) + + // Ensure no overlap between pages + const page1Ids = page1.map((d) => d.id) + const page2Ids = page2.map((d) => d.id) + for (const id of page2Ids) { + expect(page1Ids).not.toContain(id) + } + }) + + it('should get credential designs with offset only', async (): Promise => { + const all = await agent.cdmGetCredentialDesigns({ filter: { tenantId: 'tenant-pagination' } }) + const offset1 = await agent.cdmGetCredentialDesigns({ filter: { tenantId: 'tenant-pagination' }, offset: 1 }) + + expect(offset1.length).toBe(all.length - 1) + }) + + it('should return empty array when offset exceeds total', async (): Promise => { + const result = await agent.cdmGetCredentialDesigns({ filter: { tenantId: 'tenant-pagination' }, offset: 1000 }) + + expect(result.length).toBe(0) + }) + + it('should count credential designs', async (): Promise => { + const total = await agent.cdmCredentialDesignCount({}) + expect(total.count).toBeGreaterThan(0) + + const tenantCount = await agent.cdmCredentialDesignCount({ filter: { tenantId: 'tenant-pagination' } }) + expect(tenantCount.count).toBe(3) + + const emptyCount = await agent.cdmCredentialDesignCount({ filter: { tenantId: 'non-existent-tenant' } }) + expect(emptyCount.count).toBe(0) + }) + + it('should get or create a form step', async (): Promise => { + const result = await agent.cdmFormStepGetOrCreate({ formId: 'credentialIssuanceWizard' }) + expect(result.formStepId).toBeDefined() + expect(typeof result.formStepId).toBe('string') + + // Calling again should return the same ID + const sameResult = await agent.cdmFormStepGetOrCreate({ formId: 'credentialIssuanceWizard' }) + expect(sameResult.formStepId).toEqual(result.formStepId) + + // Different formId should return a different ID + const otherResult = await agent.cdmFormStepGetOrCreate({ formId: 'anotherForm' }) + expect(otherResult.formStepId).toBeDefined() + expect(otherResult.formStepId).not.toEqual(result.formStepId) + }) + it('should update credential design by id', async (): Promise => { - const updatedName = 'UpdatedDefaultDesign' const args: UpdateCredentialDesignArgs = { credentialDesignId: defaultCredentialDesign.id, - name: updatedName, - design: { - metadataKeys: [ - { - key: 'credentialType', - valueType: ValueType.Text, - metadataValues: [ - { index: 0, textValue: 'VerifiableCredential' }, - { index: 1, textValue: updatedName }, - ], - }, - { - key: 'credentialFormat', - valueType: ValueType.Text, - metadataValues: [{ index: 0, textValue: 'jwt_vc_json' }], - }, - ], + identifier: 'UpdatedDefaultDesign', + schema: { type: 'object', properties: { updatedField: { type: 'string' } } }, + uiSchema: { type: 'VerticalLayout', elements: [{ type: 'Control', scope: '#/properties/updatedField' }] }, + options: { + format: 'jwt_vc_json', + vct: 'UpdatedVCT', }, + isAdvancedSchema: true, } const result: CredentialDesign = await agent.cdmUpdateCredentialDesign(args) - expect(result.label).toEqual(updatedName) - expect(result.metadataKeys.length).toEqual(2) + expect(result.identifier).toEqual('UpdatedDefaultDesign') + + const formatKey = result.metadataKeys.find((k) => k.key === 'format') + expect(formatKey).toBeDefined() + expect(formatKey!.metadataValues[0].textValue).toEqual('jwt_vc_json') + + const vctKey = result.metadataKeys.find((k) => k.key === 'vct') + expect(vctKey).toBeDefined() + expect(vctKey!.metadataValues[0].textValue).toEqual('UpdatedVCT') + + const advancedSchemaKey = result.metadataKeys.find((k) => k.key === 'isAdvancedSchema') + expect(advancedSchemaKey).toBeDefined() + expect(advancedSchemaKey!.metadataValues[0].booleanValue).toEqual(true) - const credentialFormatKey = result.metadataKeys.find((k) => k.key === 'credentialFormat') - expect(credentialFormatKey).toBeDefined() - expect(credentialFormatKey!.metadataValues[0].textValue).toEqual('jwt_vc_json') + const dataSchema = result.schemaDefinitions.find((s) => s.schemaType === 'Data') + expect(dataSchema).toBeDefined() + expect(JSON.parse(dataSchema!.schema)).toEqual(args.schema) }) it('should throw error when updating credential design with unknown id', async (): Promise => { const credentialDesignId = 'unknownCredentialDesignId' - await expect(agent.cdmUpdateCredentialDesign({ credentialDesignId, name: 'ShouldFail' })).rejects.toThrow( - `No credential design found for id: ${credentialDesignId}`, - ) + await expect( + agent.cdmUpdateCredentialDesign({ + credentialDesignId, + identifier: 'ShouldFail', + schema: { type: 'object' }, + uiSchema: { type: 'VerticalLayout', elements: [] }, + options: { format: 'sd-jwt' }, + }), + ).rejects.toThrow(`No credential design found for id: ${credentialDesignId}`) }) it('should remove a credential design', async (): Promise => { - const credentialDesign = await agent.cdmAddCredentialDesign({ name: 'ToBeRemoved' }) + const credentialDesign = await agent.cdmAddCredentialDesign({ + identifier: 'ToBeRemoved', + schema: { type: 'object' }, + uiSchema: { type: 'VerticalLayout', elements: [] }, + options: { format: 'sd-jwt' }, + }) expect(credentialDesign).toBeDefined() - const removeCredentialDesignResult: boolean = await agent.cdmRemoveCredentialDesign({ credentialDesignId: credentialDesign.id }) - expect(removeCredentialDesignResult).toBeTruthy() + const removeResult = await agent.cdmRemoveCredentialDesign({ credentialDesignId: credentialDesign.id }) + expect(removeResult.result).toBe(true) await expect(agent.cdmGetCredentialDesign({ credentialDesignId: credentialDesign.id })).rejects.toThrow( `No credential design found for id: ${credentialDesign.id}`, diff --git a/packages/credential-design-manager/plugin.schema.json b/packages/credential-design-manager/plugin.schema.json index 1aff6bd42..a779ef197 100644 --- a/packages/credential-design-manager/plugin.schema.json +++ b/packages/credential-design-manager/plugin.schema.json @@ -5,147 +5,91 @@ "AddCredentialDesignArgs": { "type": "object", "properties": { - "name": { + "identifier": { "type": "string" }, "tenantId": { "type": "string" }, - "design": { - "$ref": "#/components/schemas/NonPersistedCredentialDesign" - } - }, - "required": [ - "name" - ], - "additionalProperties": false - }, - "NonPersistedCredentialDesign": { - "type": "object", - "additionalProperties": false, - "properties": { - "metadataKeys": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NonPersistedMetadataKey" - } + "schema": { + "$ref": "#/components/schemas/Record" + }, + "uiSchema": { + "anyOf": [ + { + "$ref": "#/components/schemas/Record" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/Record" + } + } + ] }, - "schemaDefinitions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NonPersistedSchemaDefinition" - } + "options": { + "$ref": "#/components/schemas/CredentialConfigurationOptions" + }, + "isAdvancedSchema": { + "type": "boolean" }, "branding": { - "$ref": "#/components/schemas/NonPersistedCredentialDesignBranding" + "$ref": "#/components/schemas/CredentialDesignBrandingInput" }, - "label": { + "formStepId": { "type": "string" }, - "tenantId": { + "statusListUri": { "type": "string" } }, "required": [ - "label" - ] - }, - "NonPersistedMetadataKey": { - "type": "object", - "additionalProperties": false, - "properties": { - "metadataValues": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NonPersistedMetadataValue" - } - }, - "key": { - "type": "string" - }, - "valueType": { - "$ref": "#/components/schemas/ValueType" - } - }, - "required": [ - "key", - "metadataValues", - "valueType" - ] - }, - "NonPersistedMetadataValue": { - "$ref": "#/components/schemas/Omit" - }, - "Omit": { - "$ref": "#/components/schemas/Pick>" - }, - "Pick>": { - "type": "object", - "properties": { - "index": { - "type": "number" - }, - "textValue": { - "type": "string" - }, - "numberValue": { - "type": "number" - }, - "booleanValue": { - "type": "boolean" - }, - "timestampValue": { - "type": "string", - "format": "date-time" - } - }, + "identifier", + "schema", + "uiSchema", + "options" + ], "additionalProperties": false }, - "ValueType": { - "type": "string", - "enum": [ - "Text", - "Number", - "Boolean", - "Date" - ] - }, - "NonPersistedSchemaDefinition": { - "$ref": "#/components/schemas/Omit" - }, - "Omit": { - "$ref": "#/components/schemas/Pick>" + "Record": { + "type": "object", + "additionalProperties": {} }, - "Pick>": { + "CredentialConfigurationOptions": { "type": "object", "properties": { - "tenantId": { + "format": { "type": "string" }, - "extendsId": { + "vct": { "type": "string" }, - "correlationId": { + "scope": { "type": "string" }, - "schemaType": { - "type": "string" + "cryptographicBindingMethodsSupported": { + "type": "array", + "items": { + "type": "string" + } }, - "entityType": { - "type": "string" + "credentialSigningAlgValuesSupported": { + "type": "array", + "items": { + "type": "string" + } }, - "schema": { - "type": "string" + "proofTypesSupported": { + "$ref": "#/components/schemas/Record" } }, "required": [ - "schema" + "format" ], "additionalProperties": false }, - "NonPersistedCredentialDesignBranding": { + "CredentialDesignBrandingInput": { "type": "object", - "additionalProperties": false, "properties": { "logo": { "$ref": "#/components/schemas/IBasicImageAttributes" @@ -159,7 +103,8 @@ "backgroundColor": { "type": "string" } - } + }, + "additionalProperties": false }, "IBasicImageAttributes": { "type": "object", @@ -204,7 +149,7 @@ "id": { "type": "string" }, - "label": { + "identifier": { "type": "string" }, "tenantId": { @@ -228,7 +173,7 @@ }, "required": [ "id", - "label", + "identifier", "metadataKeys", "schemaDefinitions" ], @@ -261,6 +206,15 @@ ], "additionalProperties": false }, + "ValueType": { + "type": "string", + "enum": [ + "Text", + "Number", + "Boolean", + "Date" + ] + }, "MetadataValue": { "type": "object", "properties": { @@ -391,6 +345,57 @@ ], "additionalProperties": false }, + "CredentialDesignCountArgs": { + "type": "object", + "properties": { + "filter": { + "type": "object", + "properties": { + "tenantId": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "CredentialDesignCountResult": { + "type": "object", + "properties": { + "count": { + "type": "number" + } + }, + "required": [ + "count" + ], + "additionalProperties": false + }, + "FormStepGetOrCreateArgs": { + "type": "object", + "properties": { + "formId": { + "type": "string" + } + }, + "required": [ + "formId" + ], + "additionalProperties": false + }, + "FormStepGetOrCreateResult": { + "type": "object", + "properties": { + "formStepId": { + "type": "string" + } + }, + "required": [ + "formStepId" + ], + "additionalProperties": false + }, "GetCredentialDesignArgs": { "type": "object", "properties": { @@ -414,6 +419,12 @@ } }, "additionalProperties": false + }, + "limit": { + "type": "number" + }, + "offset": { + "type": "number" } }, "additionalProperties": false @@ -448,46 +459,45 @@ "credentialDesignId": { "type": "string" }, - "name": { + "identifier": { "type": "string" }, "tenantId": { "type": "string" }, - "design": { - "$ref": "#/components/schemas/Partial" - } - }, - "required": [ - "credentialDesignId" - ], - "additionalProperties": false - }, - "Partial": { - "type": "object", - "properties": { - "label": { - "type": "string" + "schema": { + "$ref": "#/components/schemas/Record" + }, + "uiSchema": { + "anyOf": [ + { + "$ref": "#/components/schemas/Record" + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/Record" + } + } + ] }, - "tenantId": { - "type": "string" + "options": { + "$ref": "#/components/schemas/CredentialConfigurationOptions" }, - "metadataKeys": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NonPersistedMetadataKey" - } - }, - "schemaDefinitions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/NonPersistedSchemaDefinition" - } + "isAdvancedSchema": { + "type": "boolean" }, "branding": { - "$ref": "#/components/schemas/NonPersistedCredentialDesignBranding" + "$ref": "#/components/schemas/CredentialDesignBrandingInput" } }, + "required": [ + "credentialDesignId", + "identifier", + "schema", + "uiSchema", + "options" + ], "additionalProperties": false } }, @@ -501,6 +511,24 @@ "$ref": "#/components/schemas/CredentialDesign" } }, + "cdmCredentialDesignCount": { + "description": "", + "arguments": { + "$ref": "#/components/schemas/CredentialDesignCountArgs" + }, + "returnType": { + "$ref": "#/components/schemas/CredentialDesignCountResult" + } + }, + "cdmFormStepGetOrCreate": { + "description": "", + "arguments": { + "$ref": "#/components/schemas/FormStepGetOrCreateArgs" + }, + "returnType": { + "$ref": "#/components/schemas/FormStepGetOrCreateResult" + } + }, "cdmGetCredentialDesign": { "description": "", "arguments": { diff --git a/packages/credential-design-manager/src/agent/CredentialDesignManager.ts b/packages/credential-design-manager/src/agent/CredentialDesignManager.ts index 3c361e154..6953f5e43 100644 --- a/packages/credential-design-manager/src/agent/CredentialDesignManager.ts +++ b/packages/credential-design-manager/src/agent/CredentialDesignManager.ts @@ -1,8 +1,22 @@ import { IAgentPlugin } from '@veramo/core' -import { AbstractCredentialDesignStore, CredentialDesign } from '@sphereon/ssi-sdk.data-store-types' -import { RemoveCredentialDesignResult, schema } from '../index' +import { + AbstractCredentialDesignStore, + CredentialDesign, + NonPersistedCredentialDesign, + NonPersistedMetadataKey, + NonPersistedSchemaDefinition, + ValueType, +} from '@sphereon/ssi-sdk.data-store-types' +import { + CredentialDesignCountResult, + FormStepGetOrCreateResult, RemoveCredentialDesignResult, schema +} from '../index' import { AddCredentialDesignArgs, + CredentialConfigurationOptions, + CredentialDesignBrandingInput, + CredentialDesignCountArgs, + FormStepGetOrCreateArgs, GetCredentialDesignArgs, GetCredentialDesignsArgs, ICredentialDesignManager, @@ -11,13 +25,14 @@ import { UpdateCredentialDesignArgs, } from '../types/ICredentialDesignManager' -// Exposing the methods here for any REST implementation export const credentialDesignManagerMethods: Array = [ 'cdmGetCredentialDesign', 'cdmGetCredentialDesigns', 'cdmAddCredentialDesign', 'cdmUpdateCredentialDesign', 'cdmRemoveCredentialDesign', + 'cdmCredentialDesignCount', + 'cdmFormStepGetOrCreate', ] /** @@ -31,6 +46,8 @@ export class CredentialDesignManager implements IAgentPlugin { cdmAddCredentialDesign: this.cdmAddCredentialDesign.bind(this), cdmUpdateCredentialDesign: this.cdmUpdateCredentialDesign.bind(this), cdmRemoveCredentialDesign: this.cdmRemoveCredentialDesign.bind(this), + cdmCredentialDesignCount: this.cdmCredentialDesignCount.bind(this), + cdmFormStepGetOrCreate: this.cdmFormStepGetOrCreate.bind(this), } private readonly store: AbstractCredentialDesignStore @@ -41,31 +58,201 @@ export class CredentialDesignManager implements IAgentPlugin { /** {@inheritDoc ICredentialDesignManager.cdmGetCredentialDesign} */ private async cdmGetCredentialDesign(args: GetCredentialDesignArgs, context: RequiredContext): Promise { - const { credentialDesignId } = args - return this.store.getCredentialDesign({ credentialDesignId }) + return this.store.getCredentialDesign({ credentialDesignId: args.credentialDesignId }) } /** {@inheritDoc ICredentialDesignManager.cdmGetCredentialDesigns} */ - private async cdmGetCredentialDesigns(args: GetCredentialDesignsArgs, context: RequiredContext): Promise> { - return this.store.getCredentialDesigns(args) + private async cdmGetCredentialDesigns(args?: GetCredentialDesignsArgs): Promise> { + return this.store.getCredentialDesigns({ + filter: args?.filter, + limit: args?.limit, + offset: args?.offset, + }) } /** {@inheritDoc ICredentialDesignManager.cdmAddCredentialDesign} */ private async cdmAddCredentialDesign(args: AddCredentialDesignArgs, context: RequiredContext): Promise { - return this.store.addCredentialDesign(args) + const design = this.buildDesign(args) + + let formStepId: string | undefined + if (args.formStepId) { + formStepId = await this.store.formStepGetOrCreate({ formStepId: args.formStepId }) + } + + return this.store.addCredentialDesign({ + identifier: args.identifier, + tenantId: args.tenantId, + design, + formStepId, + }) } /** {@inheritDoc ICredentialDesignManager.cdmUpdateCredentialDesign} */ private async cdmUpdateCredentialDesign(args: UpdateCredentialDesignArgs, context: RequiredContext): Promise { - return this.store.updateCredentialDesign(args) + const design = this.buildDesign(args) + return this.store.updateCredentialDesign({ + credentialDesignId: args.credentialDesignId, + identifier: args.identifier, + tenantId: args.tenantId, + design, + }) } /** {@inheritDoc ICredentialDesignManager.cdmRemoveCredentialDesign} */ private async cdmRemoveCredentialDesign(args: RemoveCredentialDesignArgs, context: RequiredContext): Promise { - return this.store.removeCredentialDesign(args).then(() => ({ - result: true - })).catch(() => ({ - result: false - })) + return this.store + .removeCredentialDesign({ credentialDesignId: args.credentialDesignId }) + .then(() => ({ result: true })) + .catch(() => ({ result: false })) + } + + /** {@inheritDoc ICredentialDesignManager.cdmCredentialDesignCount} */ + private async cdmCredentialDesignCount(args: CredentialDesignCountArgs, context: RequiredContext): Promise { + const count = await this.store.countCredentialDesigns({ filter: args.filter }) + return { count } + } + + /** {@inheritDoc ICredentialDesignManager.cdmFormStepGetOrCreate} */ + private async cdmFormStepGetOrCreate(args: FormStepGetOrCreateArgs, context: RequiredContext): Promise { + const formStepId = await this.store.formStepGetOrCreate({ formStepId: args.formId }) + return { formStepId } + } + + /** + * Translate high-level create/update args into the store-level NonPersistedCredentialDesign format. + * + * Maps: + * - options fields → metadataKeys (format, vct, scope, etc.) + * - schema → schemaDefinition with schemaType 'Data' + * - uiSchema → schemaDefinition with schemaType 'UI_Form' + * - branding → NonPersistedCredentialDesignBranding + */ + private buildDesign(args: { + identifier: string + schema: Record + uiSchema: Record | Array> + options: CredentialConfigurationOptions + isAdvancedSchema?: boolean + statusListUri?: string + branding?: CredentialDesignBrandingInput + }): NonPersistedCredentialDesign { + const metadataKeys = this.buildMetadataKeys(args.options, args.isAdvancedSchema, args.statusListUri) + const schemaDefinitions = this.buildSchemaDefinitions(args.identifier, args.schema, args.uiSchema) + const branding = args.branding ? this.buildBranding(args.branding) : undefined + + return { + identifier: args.identifier, + metadataKeys, + schemaDefinitions, + branding, + } + } + + private buildMetadataKeys( + options: CredentialConfigurationOptions, + isAdvancedSchema?: boolean, + statusListUri?: string, + ): Array { + const keys: Array = [] + + keys.push({ + key: 'format', + valueType: ValueType.Text, + metadataValues: [{ index: 0, textValue: options.format }], + }) + + if (options.vct !== undefined) { + keys.push({ + key: 'vct', + valueType: ValueType.Text, + metadataValues: [{ index: 0, textValue: options.vct }], + }) + } + + if (options.scope !== undefined) { + keys.push({ + key: 'scope', + valueType: ValueType.Text, + metadataValues: [{ index: 0, textValue: options.scope }], + }) + } + + if (options.cryptographicBindingMethodsSupported?.length) { + keys.push({ + key: 'cryptographicBindingMethodsSupported', + valueType: ValueType.Text, + metadataValues: options.cryptographicBindingMethodsSupported.map((method, index) => ({ + index, + textValue: method, + })), + }) + } + + if (options.credentialSigningAlgValuesSupported?.length) { + keys.push({ + key: 'credentialSigningAlgValuesSupported', + valueType: ValueType.Text, + metadataValues: options.credentialSigningAlgValuesSupported.map((alg, index) => ({ + index, + textValue: alg, + })), + }) + } + + if (options.proofTypesSupported && Object.keys(options.proofTypesSupported).length > 0) { + keys.push({ + key: 'proofTypesSupported', + valueType: ValueType.Text, + metadataValues: [{ index: 0, textValue: JSON.stringify(options.proofTypesSupported) }], + }) + } + + if (isAdvancedSchema !== undefined) { + keys.push({ + key: 'isAdvancedSchema', + valueType: ValueType.Boolean, + metadataValues: [{ index: 0, booleanValue: isAdvancedSchema }], + }) + } + + if (statusListUri !== undefined) { + keys.push({ + key: 'statusListUri', + valueType: ValueType.Text, + metadataValues: [{ index: 0, textValue: statusListUri }], + }) + } + + return keys + } + + private buildSchemaDefinitions( + identifier: string, + schema: Record, + uiSchema: Record | Array>, + ): Array { + return [ + { + correlationId: identifier, + schemaType: 'Data', + entityType: 'VC', + schema: JSON.stringify(schema), + }, + { + correlationId: identifier, + schemaType: 'UI_Form', + entityType: 'VC', + schema: JSON.stringify(uiSchema), + }, + ] + } + + private buildBranding(input: CredentialDesignBrandingInput): NonPersistedCredentialDesign['branding'] { + return { + textColor: input.textColor, + backgroundColor: input.backgroundColor, + logo: input.logo, + backgroundImage: input.backgroundImage, + } } } diff --git a/packages/credential-design-manager/src/types/ICredentialDesignManager.ts b/packages/credential-design-manager/src/types/ICredentialDesignManager.ts index 71d89bb2b..fad6475a5 100644 --- a/packages/credential-design-manager/src/types/ICredentialDesignManager.ts +++ b/packages/credential-design-manager/src/types/ICredentialDesignManager.ts @@ -1,14 +1,15 @@ import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config' import { IAgentContext, IPluginMethodMap } from '@veramo/core' -import { CredentialDesign, NonPersistedCredentialDesign } from '@sphereon/ssi-sdk.data-store-types' -import { CredentialFormat } from '@sphereon/ssi-types' +import { CredentialDesign, IBasicImageAttributes } from '@sphereon/ssi-sdk.data-store-types' export interface ICredentialDesignManager extends IPluginMethodMap { cdmGetCredentialDesign(args: GetCredentialDesignArgs, context: RequiredContext): Promise - cdmGetCredentialDesigns(args: GetCredentialDesignsArgs, context: RequiredContext): Promise> + cdmGetCredentialDesigns(args?: GetCredentialDesignsArgs): Promise> cdmAddCredentialDesign(args: AddCredentialDesignArgs, context: RequiredContext): Promise cdmUpdateCredentialDesign(args: UpdateCredentialDesignArgs, context: RequiredContext): Promise cdmRemoveCredentialDesign(args: RemoveCredentialDesignArgs, context: RequiredContext): Promise + cdmCredentialDesignCount(args: CredentialDesignCountArgs, context: RequiredContext): Promise + cdmFormStepGetOrCreate(args: FormStepGetOrCreateArgs, context: RequiredContext): Promise } export function contextHasCredentialDesignManager(context: IAgentContext): context is IAgentContext { @@ -23,41 +24,31 @@ export type GetCredentialDesignsArgs = { filter?: { tenantId?: string } + limit?: number + offset?: number } export type AddCredentialDesignArgs = { identifier: string - schema: CredentialSchema - uiSchema: CredentialUISchema - options: { - format: CredentialFormat - vct?: string,//options.vct ?? null, - scope?: string - cryptographicBindingMethodsSupported: Array - credentialSigningAlgValuesSupported: Array - proofTypesSupported: Record - } - isAdvancedSchema: boolean - branding: { - logo: { - uri: string - } - backgroundImage: { - uri: string - } - textColor: string - backgroundColor: string - } - //name: string - //tenantId?: string - //design?: NonPersistedCredentialDesign + tenantId?: string + schema: Record + uiSchema: Record | Array> + options: CredentialConfigurationOptions + isAdvancedSchema?: boolean + branding?: CredentialDesignBrandingInput + formStepId?: string + statusListUri?: string } export type UpdateCredentialDesignArgs = { credentialDesignId: string - name?: string + identifier: string tenantId?: string - design?: Partial + schema: Record + uiSchema: Record | Array> + options: CredentialConfigurationOptions + isAdvancedSchema?: boolean + branding?: CredentialDesignBrandingInput } export type RemoveCredentialDesignArgs = { @@ -68,4 +59,38 @@ export type RemoveCredentialDesignResult = { result: boolean } +export type CredentialDesignCountArgs = { + filter?: { + tenantId?: string + } +} + +export type CredentialDesignCountResult = { + count: number +} + +export type FormStepGetOrCreateArgs = { + formId: string +} + +export type FormStepGetOrCreateResult = { + formStepId: string +} + +export type CredentialConfigurationOptions = { + format: string + vct?: string + scope?: string + cryptographicBindingMethodsSupported?: Array + credentialSigningAlgValuesSupported?: Array + proofTypesSupported?: Record +} + +export type CredentialDesignBrandingInput = { + logo?: IBasicImageAttributes + backgroundImage?: IBasicImageAttributes + textColor?: string + backgroundColor?: string +} + export type RequiredContext = IAgentContext diff --git a/packages/data-store-types/src/credentialDesign/AbstractCredentialDesignStore.ts b/packages/data-store-types/src/credentialDesign/AbstractCredentialDesignStore.ts index fba28b21f..869b9ef80 100644 --- a/packages/data-store-types/src/credentialDesign/AbstractCredentialDesignStore.ts +++ b/packages/data-store-types/src/credentialDesign/AbstractCredentialDesignStore.ts @@ -2,6 +2,8 @@ import { CredentialDesign, GetCredentialDesignArgs, GetCredentialDesignsArgs, + CountCredentialDesignsArgs, + FormStepGetOrCreateArgs, AddCredentialDesignArgs, UpdateCredentialDesignArgs, RemoveCredentialDesignArgs @@ -10,7 +12,9 @@ import { export abstract class AbstractCredentialDesignStore { abstract getCredentialDesign(args: GetCredentialDesignArgs): Promise abstract getCredentialDesigns(args?: GetCredentialDesignsArgs): Promise> + abstract countCredentialDesigns(args?: CountCredentialDesignsArgs): Promise abstract addCredentialDesign(args: AddCredentialDesignArgs): Promise abstract updateCredentialDesign(args: UpdateCredentialDesignArgs): Promise abstract removeCredentialDesign(args: RemoveCredentialDesignArgs): Promise + abstract formStepGetOrCreate(args: FormStepGetOrCreateArgs): Promise } diff --git a/packages/data-store-types/src/types/credentialDesign/IAbstractCredentialDesignStore.ts b/packages/data-store-types/src/types/credentialDesign/IAbstractCredentialDesignStore.ts index bc5a5f2ca..a5f5598ff 100644 --- a/packages/data-store-types/src/types/credentialDesign/IAbstractCredentialDesignStore.ts +++ b/packages/data-store-types/src/types/credentialDesign/IAbstractCredentialDesignStore.ts @@ -8,12 +8,25 @@ export type GetCredentialDesignsArgs = { filter?: { tenantId?: string } + limit?: number + offset?: number +} + +export type CountCredentialDesignsArgs = { + filter?: { + tenantId?: string + } +} + +export type FormStepGetOrCreateArgs = { + formStepId: string } export type AddCredentialDesignArgs = { - name: string + identifier: string tenantId?: string design?: NonPersistedCredentialDesign + formStepId?: string } export type RemoveCredentialDesignArgs = { @@ -22,7 +35,7 @@ export type RemoveCredentialDesignArgs = { export type UpdateCredentialDesignArgs = { credentialDesignId: string - name?: string + identifier?: string tenantId?: string design?: Partial } diff --git a/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts b/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts index d326b33f8..f186fd70a 100644 --- a/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts +++ b/packages/data-store-types/src/types/credentialDesign/credentialDesign.ts @@ -56,7 +56,7 @@ export type NonPersistedCredentialDesignBranding = Omit schemaDefinitions: Array diff --git a/packages/data-store/src/__tests__/credential-design-store.test.ts b/packages/data-store/src/__tests__/credential-design-store.test.ts index 0dd3a24d0..87ea72e90 100644 --- a/packages/data-store/src/__tests__/credential-design-store.test.ts +++ b/packages/data-store/src/__tests__/credential-design-store.test.ts @@ -37,7 +37,7 @@ describe('Credential Design store tests', (): void => { it('should get a credential design by id', async (): Promise => { const args: AddCredentialDesignArgs = { - name: 'GetByIdDesign', + identifier: 'GetByIdDesign', tenantId: 'tenant-get-by-id', design: { label: 'GetByIdDesign', @@ -81,7 +81,7 @@ describe('Credential Design store tests', (): void => { it('should get all credential designs', async (): Promise => { const design1: AddCredentialDesignArgs = { - name: 'Design1', + identifier: 'Design1', tenantId: 'tenant-1', design: { label: 'Design1', @@ -107,7 +107,7 @@ describe('Credential Design store tests', (): void => { expect(savedDesign1).toBeDefined() const design2: AddCredentialDesignArgs = { - name: 'Design2', + identifier: 'Design2', tenantId: 'tenant-2', design: { label: 'Design2', @@ -139,8 +139,8 @@ describe('Credential Design store tests', (): void => { }) it('should get credential designs by filter', async (): Promise => { - await store.addCredentialDesign({ name: 'FilterDesign1', tenantId: 'tenant-filter' }) - await store.addCredentialDesign({ name: 'FilterDesign2', tenantId: 'tenant-other' }) + await store.addCredentialDesign({ identifier: 'FilterDesign1', tenantId: 'tenant-filter' }) + await store.addCredentialDesign({ identifier: 'FilterDesign2', tenantId: 'tenant-other' }) const args: GetCredentialDesignsArgs = { filter: { @@ -155,7 +155,7 @@ describe('Credential Design store tests', (): void => { it('should get whole credential design with all relations by filter', async (): Promise => { const args: AddCredentialDesignArgs = { - name: 'WholeDesign', + identifier: 'WholeDesign', tenantId: 'tenant-whole', design: { label: 'WholeDesign', @@ -220,7 +220,7 @@ describe('Credential Design store tests', (): void => { }) it('should return no credential designs if filter does not match', async (): Promise => { - await store.addCredentialDesign({ name: 'SomeDesign', tenantId: 'tenant-exists' }) + await store.addCredentialDesign({ identifier: 'SomeDesign', tenantId: 'tenant-exists' }) const result: Array = await store.getCredentialDesigns({ filter: { tenantId: 'non-existent-tenant' } }) @@ -229,7 +229,7 @@ describe('Credential Design store tests', (): void => { it('should add credential design', async (): Promise => { const args: AddCredentialDesignArgs = { - name: 'AddDesign', + identifier: 'AddDesign', tenantId: 'tenant-add', design: { label: 'AddDesign', @@ -286,7 +286,7 @@ describe('Credential Design store tests', (): void => { expect(result).toBeDefined() expect(result.id).toBeDefined() - expect(result.label).toEqual(args.name) + expect(result.identifier).toEqual(args.identifier) expect(result.tenantId).toEqual(args.tenantId) expect(result.metadataKeys.length).toEqual(2) expect(result.schemaDefinitions.length).toEqual(2) @@ -304,7 +304,7 @@ describe('Credential Design store tests', (): void => { it('should update credential design by id', async (): Promise => { const created: CredentialDesign = await store.addCredentialDesign({ - name: 'OriginalDesign', + identifier: 'OriginalDesign', tenantId: 'tenant-original', design: { label: 'OriginalDesign', @@ -339,7 +339,7 @@ describe('Credential Design store tests', (): void => { const updateArgs: UpdateCredentialDesignArgs = { credentialDesignId: created.id, - name: 'UpdatedDesign', + identifier: 'UpdatedDesign', design: { metadataKeys: [ { @@ -387,14 +387,14 @@ describe('Credential Design store tests', (): void => { it('should throw error when updating credential design with unknown id', async (): Promise => { const credentialDesignId = 'unknownCredentialDesignId' - await expect(store.updateCredentialDesign({ credentialDesignId, name: 'ShouldFail' })).rejects.toThrow( + await expect(store.updateCredentialDesign({ credentialDesignId, identifier: 'ShouldFail' })).rejects.toThrow( `No credential design found for id: ${credentialDesignId}`, ) }) it('should remove credential design', async (): Promise => { const created: CredentialDesign = await store.addCredentialDesign({ - name: 'ToBeRemoved', + identifier: 'ToBeRemoved', tenantId: 'tenant-remove', }) expect(created).toBeDefined() diff --git a/packages/data-store/src/credentialDesign/CredentialDesignStore.ts b/packages/data-store/src/credentialDesign/CredentialDesignStore.ts index 21b0f80e0..e314dfa52 100644 --- a/packages/data-store/src/credentialDesign/CredentialDesignStore.ts +++ b/packages/data-store/src/credentialDesign/CredentialDesignStore.ts @@ -1,7 +1,9 @@ import { AbstractCredentialDesignStore, AddCredentialDesignArgs, + CountCredentialDesignsArgs, CredentialDesign, + FormStepGetOrCreateArgs, GetCredentialDesignArgs, GetCredentialDesignsArgs, NonPersistedCredentialDesignBranding, @@ -13,7 +15,7 @@ import { import { OrPromise } from '@sphereon/ssi-types' import Debug from 'debug' import { DataSource, EntityManager, Repository } from 'typeorm' -import { MetadataSetEntity, MetadataKeyEntity, MetadataValueEntity, SchemaDefinitionEntity, CredentialDesignBrandingEntity } from '../entities/credentialDesign' +import { MetadataSetEntity, MetadataKeyEntity, MetadataValueEntity, SchemaDefinitionEntity, CredentialDesignBrandingEntity, FormStepEntity } from '../entities/credentialDesign' import { ImageAttributesEntity } from '../entities/issuanceBranding/ImageAttributesEntity' import { ImageDimensionsEntity } from '../entities/issuanceBranding/ImageDimensionsEntity' import { @@ -52,17 +54,29 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { debug('getCredentialDesigns', args) const repo: Repository = (await this.dbConnection).getRepository(MetadataSetEntity) const where = args?.filter?.tenantId ? { tenantId: args.filter.tenantId } : undefined - const results = await repo.find({ where }) + const results = await repo.find({ + where, + order: { name: 'ASC' }, + take: args?.limit, + skip: args?.offset, + }) return results.map(credentialDesignFrom) } + countCredentialDesigns = async (args?: CountCredentialDesignsArgs): Promise => { + debug('countCredentialDesigns', args) + const repo: Repository = (await this.dbConnection).getRepository(MetadataSetEntity) + const where = args?.filter?.tenantId ? { tenantId: args.filter.tenantId } : undefined + return repo.count({ where }) + } + addCredentialDesign = async (args: AddCredentialDesignArgs): Promise => { debug('addCredentialDesign', args) const dataSource = await this.dbConnection return dataSource.transaction(async (transactionalEntityManager) => { const metadataSet = new MetadataSetEntity() - metadataSet.name = args.name + metadataSet.name = args.identifier metadataSet.tenantId = args.tenantId metadataSet.metadataKeys = [] metadataSet.schemaDefinitions = [] @@ -83,6 +97,17 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { } const saved = await transactionalEntityManager.save(MetadataSetEntity, metadataSet) + + if (args.formStepId && saved.schemaDefinitions?.length) { + const formStep = await transactionalEntityManager.findOne(FormStepEntity, { + where: { id: args.formStepId }, + }) + if (formStep) { + formStep.schemaDefinitions = [...(formStep.schemaDefinitions ?? []), ...saved.schemaDefinitions] + await transactionalEntityManager.save(FormStepEntity, formStep) + } + } + return credentialDesignFrom(saved) }) } @@ -100,8 +125,8 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { return Promise.reject(Error(`No credential design found for id: ${args.credentialDesignId}`)) } - if (args.name !== undefined) { - existing.name = args.name + if (args.identifier !== undefined) { + existing.name = args.identifier } if (args.tenantId !== undefined) { existing.tenantId = args.tenantId @@ -127,6 +152,21 @@ export class CredentialDesignStore extends AbstractCredentialDesignStore { }) } + formStepGetOrCreate = async (args: FormStepGetOrCreateArgs): Promise => { + debug('formStepGetOrCreate', args) + const repo: Repository = (await this.dbConnection).getRepository(FormStepEntity) + const existing = await repo.findOne({ where: { formId: args.formStepId } }) + if (existing) { + return existing.id + } + const formStep = new FormStepEntity() + formStep.formId = args.formStepId + formStep.stepNr = 1 + formStep.order = 1 + const saved = await repo.save(formStep) + return saved.id + } + removeCredentialDesign = async (args: RemoveCredentialDesignArgs): Promise => { debug('removeCredentialDesign', args) const repo: Repository = (await this.dbConnection).getRepository(MetadataSetEntity) diff --git a/packages/data-store/src/utils/credentialDesign/MappingUtils.ts b/packages/data-store/src/utils/credentialDesign/MappingUtils.ts index 16a0f71cc..c1fbc4e76 100644 --- a/packages/data-store/src/utils/credentialDesign/MappingUtils.ts +++ b/packages/data-store/src/utils/credentialDesign/MappingUtils.ts @@ -22,7 +22,7 @@ import { imageAttributesEntityFrom } from '../issuanceBranding/MappingUtils' export const credentialDesignFrom = (entity: MetadataSetEntity): CredentialDesign => { const result: CredentialDesign = { id: entity.id, - label: entity.name, + identifier: entity.name, tenantId: entity.tenantId, metadataKeys: entity.metadataKeys?.map((key) => metadataKeyFrom(key)) ?? [], schemaDefinitions: entity.schemaDefinitions?.map((schema) => schemaDefinitionFrom(schema)) ?? [], From 9c7e1730c8cbc908b4050f37d0395083f27998e1 Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Thu, 19 Mar 2026 16:28:51 +0100 Subject: [PATCH 3/6] chore: credential-design-manager fixes --- packages/credential-design-manager/package.json | 4 ++-- packages/data-store-types/package.json | 6 +++--- packages/data-store/package.json | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/credential-design-manager/package.json b/packages/credential-design-manager/package.json index a88c223f0..a127fd45b 100644 --- a/packages/credential-design-manager/package.json +++ b/packages/credential-design-manager/package.json @@ -27,11 +27,11 @@ "generate-plugin-schema": "tsx ../../packages/dev/bin/sphereon.js dev generate-plugin-schema" }, "dependencies": { - "@sphereon/ssi-sdk.data-store-types": "0.37.1", + "@sphereon/ssi-sdk.data-store-types": "workspace:*", "@veramo/core": "4.2.0" }, "devDependencies": { - "@sphereon/ssi-sdk.agent-config": "0.37.1", + "@sphereon/ssi-sdk.agent-config": "workspace:*", "@veramo/remote-client": "4.2.0", "@veramo/remote-server": "4.2.0", "cross-fetch": "^4.1.0", diff --git a/packages/data-store-types/package.json b/packages/data-store-types/package.json index 88804dcff..16d78fdbe 100644 --- a/packages/data-store-types/package.json +++ b/packages/data-store-types/package.json @@ -21,12 +21,12 @@ "build": "tsup --config ../../tsup.config.ts --tsconfig ../../tsconfig.tsup.json" }, "dependencies": { - "@sphereon/ssi-sdk.core": "0.37.1", - "@sphereon/ssi-types": "0.37.1", + "@sphereon/ssi-sdk.core": "workspace:*", + "@sphereon/ssi-types": "workspace:*", "dcql": "1.0.1" }, "devDependencies": { - "@sphereon/ssi-sdk-ext.identifier-resolution": "0.37.1" + "@sphereon/ssi-sdk-ext.identifier-resolution": "workspace:*" }, "files": [ "dist", diff --git a/packages/data-store/package.json b/packages/data-store/package.json index 2b92e9e3a..a5b9f9f2b 100644 --- a/packages/data-store/package.json +++ b/packages/data-store/package.json @@ -28,12 +28,12 @@ "dependencies": { "@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26", "@sphereon/pex": "5.0.0-unstable.28", - "@sphereon/ssi-sdk-ext.did-utils": "0.37.1", - "@sphereon/ssi-sdk-ext.identifier-resolution": "0.37.1", - "@sphereon/ssi-sdk.agent-config": "0.37.1", - "@sphereon/ssi-sdk.core": "0.37.1", - "@sphereon/ssi-sdk.data-store-types": "0.37.1", - "@sphereon/ssi-types": "0.37.1", + "@sphereon/ssi-sdk-ext.did-utils": "workspace:*", + "@sphereon/ssi-sdk-ext.identifier-resolution": "workspace:*", + "@sphereon/ssi-sdk.agent-config": "workspace:*", + "@sphereon/ssi-sdk.core": "workspace:*", + "@sphereon/ssi-sdk.data-store-types": "workspace:*", + "@sphereon/ssi-types": "workspace:*", "@veramo/core": "4.2.0", "@veramo/data-store": "4.2.0", "@veramo/utils": "4.2.0", From 78d821521d69e036dce42549c93b6630de5ed8ac Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Thu, 19 Mar 2026 16:48:02 +0100 Subject: [PATCH 4/6] chore: test fixes --- .../__tests__/credential-design-store.test.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/data-store/src/__tests__/credential-design-store.test.ts b/packages/data-store/src/__tests__/credential-design-store.test.ts index 87ea72e90..7b7653771 100644 --- a/packages/data-store/src/__tests__/credential-design-store.test.ts +++ b/packages/data-store/src/__tests__/credential-design-store.test.ts @@ -40,7 +40,7 @@ describe('Credential Design store tests', (): void => { identifier: 'GetByIdDesign', tenantId: 'tenant-get-by-id', design: { - label: 'GetByIdDesign', + identifier: 'GetByIdDesign', tenantId: 'tenant-get-by-id', metadataKeys: [ { @@ -67,7 +67,7 @@ describe('Credential Design store tests', (): void => { expect(result).toBeDefined() expect(result.id).toEqual(savedDesign.id) - expect(result.label).toEqual('GetByIdDesign') + expect(result.identifier).toEqual('GetByIdDesign') expect(result.tenantId).toEqual('tenant-get-by-id') }) @@ -84,7 +84,7 @@ describe('Credential Design store tests', (): void => { identifier: 'Design1', tenantId: 'tenant-1', design: { - label: 'Design1', + identifier: 'Design1', tenantId: 'tenant-1', metadataKeys: [ { @@ -110,7 +110,7 @@ describe('Credential Design store tests', (): void => { identifier: 'Design2', tenantId: 'tenant-2', design: { - label: 'Design2', + identifier: 'Design2', tenantId: 'tenant-2', metadataKeys: [ { @@ -150,7 +150,7 @@ describe('Credential Design store tests', (): void => { const result: Array = await store.getCredentialDesigns(args) expect(result.length).toEqual(1) - expect(result[0].label).toEqual('FilterDesign1') + expect(result[0].identifier).toEqual('FilterDesign1') }) it('should get whole credential design with all relations by filter', async (): Promise => { @@ -158,7 +158,7 @@ describe('Credential Design store tests', (): void => { identifier: 'WholeDesign', tenantId: 'tenant-whole', design: { - label: 'WholeDesign', + identifier: 'WholeDesign', tenantId: 'tenant-whole', metadataKeys: [ { @@ -207,7 +207,7 @@ describe('Credential Design store tests', (): void => { }, } await store.addCredentialDesign(args) - await store.addCredentialDesign({ name: 'OtherDesign', tenantId: 'tenant-other' }) + await store.addCredentialDesign({ identifier: 'OtherDesign', tenantId: 'tenant-other' }) const result: Array = await store.getCredentialDesigns({ filter: { tenantId: 'tenant-whole' } }) @@ -232,7 +232,7 @@ describe('Credential Design store tests', (): void => { identifier: 'AddDesign', tenantId: 'tenant-add', design: { - label: 'AddDesign', + identifier: 'AddDesign', tenantId: 'tenant-add', metadataKeys: [ { @@ -307,7 +307,7 @@ describe('Credential Design store tests', (): void => { identifier: 'OriginalDesign', tenantId: 'tenant-original', design: { - label: 'OriginalDesign', + identifier: 'OriginalDesign', tenantId: 'tenant-original', metadataKeys: [ { @@ -368,7 +368,7 @@ describe('Credential Design store tests', (): void => { const result: CredentialDesign = await store.getCredentialDesign({ credentialDesignId: created.id }) expect(result).toBeDefined() - expect(result.label).toEqual('UpdatedDesign') + expect(result.identifier).toEqual('UpdatedDesign') expect(result.metadataKeys.length).toEqual(3) const credentialFormatKey = result.metadataKeys.find((k) => k.key === 'credentialFormat') From 2205327eeb9728930c1aab8069c45ab7fd640caa Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Fri, 20 Mar 2026 11:56:39 +0100 Subject: [PATCH 5/6] chore: removed catch --- .../src/agent/CredentialDesignManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/credential-design-manager/src/agent/CredentialDesignManager.ts b/packages/credential-design-manager/src/agent/CredentialDesignManager.ts index 6953f5e43..3c70c9b60 100644 --- a/packages/credential-design-manager/src/agent/CredentialDesignManager.ts +++ b/packages/credential-design-manager/src/agent/CredentialDesignManager.ts @@ -103,7 +103,6 @@ export class CredentialDesignManager implements IAgentPlugin { return this.store .removeCredentialDesign({ credentialDesignId: args.credentialDesignId }) .then(() => ({ result: true })) - .catch(() => ({ result: false })) } /** {@inheritDoc ICredentialDesignManager.cdmCredentialDesignCount} */ From 28ae6fe89eebe0aa5f5465874db098f389605cff Mon Sep 17 00:00:00 2001 From: "A.G.J. Cate" Date: Tue, 24 Mar 2026 10:14:48 +0100 Subject: [PATCH 6/6] chore: test fixes --- .../src/__tests__/credential-design.entities.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/data-store/src/__tests__/credential-design.entities.test.ts b/packages/data-store/src/__tests__/credential-design.entities.test.ts index a4c6b0c99..bb8fdaaa7 100644 --- a/packages/data-store/src/__tests__/credential-design.entities.test.ts +++ b/packages/data-store/src/__tests__/credential-design.entities.test.ts @@ -35,7 +35,7 @@ describe('Credential Design entities tests', (): void => { it('Should save credential design to database', async (): Promise => { const design: NonPersistedCredentialDesign = { - label: 'TestCredentialDesign', + identifier: 'TestCredentialDesign', tenantId: 'tenant-entity-test', metadataKeys: [ { @@ -91,7 +91,7 @@ describe('Credential Design entities tests', (): void => { // Build entity graph using mappers const metadataSetEntity = new MetadataSetEntity() - metadataSetEntity.name = design.label + metadataSetEntity.name = design.identifier metadataSetEntity.tenantId = design.tenantId metadataSetEntity.metadataKeys = design.metadataKeys!.map(metadataKeyEntityFrom) metadataSetEntity.schemaDefinitions = design.schemaDefinitions!.map(schemaDefinitionEntityFrom) @@ -106,7 +106,7 @@ describe('Credential Design entities tests', (): void => { // ── Root level ── expect(fromDb).toBeDefined() expect(fromDb.id).toBeDefined() - expect(fromDb.label).toEqual(design.label) + expect(fromDb.identifier).toEqual(design.identifier) expect(fromDb.tenantId).toEqual(design.tenantId) // ── MetadataKeys ──