@idos-network/credentials 1.2.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +289 -85
  2. package/assets/idos-credential-subject-edd-v1.json +10 -0
  3. package/assets/idos-credential-subject-v1.json +1 -1
  4. package/assets/idos-credential-subject-v2.json +1 -1
  5. package/assets/idos-credential-subject-v3.json +83 -0
  6. package/assets/idos-credentials-v1.json +2 -2
  7. package/assets/idos-credentials-v2.json +10 -0
  8. package/dist/index-0NqXMjNk.d.mts +395 -0
  9. package/dist/index-0NqXMjNk.d.mts.map +1 -0
  10. package/dist/index-WW372Tf5.d.mts +57 -0
  11. package/dist/index-WW372Tf5.d.mts.map +1 -0
  12. package/dist/index.d.mts +1 -1
  13. package/dist/index.mjs +1 -1
  14. package/dist/loader-Cg6hs1-P.mjs +2 -0
  15. package/dist/loader-Cg6hs1-P.mjs.map +1 -0
  16. package/dist/parser/index.d.mts +19 -0
  17. package/dist/parser/index.d.mts.map +1 -0
  18. package/dist/parser/index.mjs +2 -0
  19. package/dist/parser/index.mjs.map +1 -0
  20. package/dist/schemas/index.d.mts +2 -0
  21. package/dist/schemas/index.mjs +1 -0
  22. package/dist/schemas-BVGuUlPe.mjs +2 -0
  23. package/dist/schemas-BVGuUlPe.mjs.map +1 -0
  24. package/dist/types/index.d.mts +2 -135
  25. package/dist/types/index.mjs +1 -63
  26. package/dist/utils/index.d.mts +38 -22
  27. package/dist/utils/index.d.mts.map +1 -1
  28. package/dist/utils/index.mjs +1 -123
  29. package/dist/utils/index.mjs.map +1 -1
  30. package/dist/verifier/index.d.mts +8 -0
  31. package/dist/verifier/index.d.mts.map +1 -0
  32. package/dist/verifier/index.mjs +2 -0
  33. package/dist/verifier/index.mjs.map +1 -0
  34. package/package.json +31 -15
  35. package/src/parser/index.test.ts +266 -0
  36. package/src/parser/index.ts +69 -0
  37. package/src/schemas/EddV1/index.test.ts +40 -0
  38. package/src/schemas/EddV1/index.ts +53 -0
  39. package/src/schemas/Envelope.ts +37 -0
  40. package/src/schemas/FaceIdV1/index.test.ts +26 -0
  41. package/src/schemas/FaceIdV1/index.ts +33 -0
  42. package/src/schemas/KycV1/IdDocument.ts +41 -0
  43. package/src/schemas/KycV1/ResidentialAddress.ts +56 -0
  44. package/src/schemas/KycV1/Subject.ts +86 -0
  45. package/src/schemas/KycV1/index.test.ts +156 -0
  46. package/src/schemas/KycV1/index.ts +40 -0
  47. package/src/schemas/KycV2/Subject.ts +67 -0
  48. package/src/schemas/KycV2/index.test.ts +162 -0
  49. package/src/schemas/KycV2/index.ts +45 -0
  50. package/src/schemas/KycV3/Biometric.ts +14 -0
  51. package/src/schemas/KycV3/Contact.ts +13 -0
  52. package/src/schemas/KycV3/EDD.ts +32 -0
  53. package/src/schemas/KycV3/IdDocument.ts +92 -0
  54. package/src/schemas/KycV3/Onboarding.ts +36 -0
  55. package/src/schemas/KycV3/Person.ts +105 -0
  56. package/src/schemas/KycV3/ResidentialAddress.ts +73 -0
  57. package/src/schemas/KycV3/Screening.ts +27 -0
  58. package/src/schemas/KycV3/SourceOfWealth.ts +44 -0
  59. package/src/schemas/KycV3/Subject.ts +54 -0
  60. package/src/schemas/KycV3/index.test.ts +682 -0
  61. package/src/schemas/KycV3/index.ts +108 -0
  62. package/src/schemas/VerifiableCredential.ts +232 -0
  63. package/src/schemas/enums.ts +126 -0
  64. package/src/schemas/index.ts +14 -0
  65. package/src/schemas/integration.test.ts +251 -0
  66. package/src/schemas/types.ts +11 -0
  67. package/src/schemas/utils.ts +274 -0
  68. package/src/types/credentials.ts +18 -249
  69. package/src/utils/{utils.test.ts → index.test.ts} +59 -67
  70. package/src/utils/index.ts +129 -137
  71. package/src/utils/issuer.ts +42 -0
  72. package/src/{builder → utils}/loader.ts +22 -17
  73. package/src/verifier/index.test.ts +149 -0
  74. package/src/{builder/verifier.ts → verifier/index.ts} +4 -8
  75. package/types/internals.d.ts +11 -6
  76. package/dist/builder/index.d.mts +0 -20
  77. package/dist/builder/index.d.mts.map +0 -1
  78. package/dist/builder/index.mjs +0 -619
  79. package/dist/builder/index.mjs.map +0 -1
  80. package/dist/types/index.d.mts.map +0 -1
  81. package/dist/types/index.mjs.map +0 -1
  82. package/src/builder/builder.test.ts +0 -407
  83. package/src/builder/index.ts +0 -122
@@ -0,0 +1,108 @@
1
+ import type { PublicNotes } from "../types";
2
+
3
+ import { CONTEXT_IDOS_CREDENTIAL_V2, CONTEXT_IDOS_CREDENTIAL_V3_SUBJECT } from "../../utils/loader";
4
+ import { EnvelopeV2 } from "../Envelope";
5
+ import { VerifiableCredentialBase } from "../VerifiableCredential";
6
+ import { Subject } from "./Subject";
7
+
8
+ export class KycV3 extends VerifiableCredentialBase<EnvelopeV2, Subject> {
9
+ static readonly envelopeContext: string = CONTEXT_IDOS_CREDENTIAL_V2;
10
+ static readonly subjectContext: string = CONTEXT_IDOS_CREDENTIAL_V3_SUBJECT;
11
+
12
+ constructor() {
13
+ super(EnvelopeV2, Subject);
14
+ }
15
+
16
+ override level(): string {
17
+ const {
18
+ residentialAddress,
19
+ biometric,
20
+ contact,
21
+ edd,
22
+ sourceOfWealth,
23
+ screening,
24
+ onboarding,
25
+ person,
26
+ idDocument,
27
+ } = this.subject;
28
+
29
+ // A verified address with a proof is the sign of plus.
30
+ let base = "unverified";
31
+
32
+ // When we have a idDocument and person, we can set "basic"
33
+ if (person && idDocument) {
34
+ base = "basic";
35
+ }
36
+
37
+ // When we also have a verified address, we can set "plus"
38
+ if (
39
+ base === "basic" &&
40
+ residentialAddress?.proofFile &&
41
+ residentialAddress.city &&
42
+ residentialAddress.proofCategory &&
43
+ residentialAddress.source === "PROOF_OF_ADDRESS" &&
44
+ residentialAddress.country
45
+ ) {
46
+ base = "plus";
47
+ }
48
+
49
+ const addons = [
50
+ biometric?.selfieFile && "liveness",
51
+ contact?.email && "email",
52
+ contact?.phoneNumber && "phoneNumber",
53
+ edd && "edd",
54
+ sourceOfWealth && "sow",
55
+ screening && "screening",
56
+ onboarding && "onboarding",
57
+ ].filter(Boolean);
58
+
59
+ return [base, ...addons].join("+");
60
+ }
61
+
62
+ kycLevel(): number {
63
+ const { person, idDocument, biometric, residentialAddress, sourceOfWealth, onboarding } =
64
+ this.subject;
65
+
66
+ let kycLevel = 0;
67
+
68
+ // basic+liveness are always at least kycLevel = 1
69
+ if (biometric?.selfieFile && person && idDocument) {
70
+ kycLevel = 1;
71
+ }
72
+
73
+ // plus+liveness are always at least kycLevel = 2
74
+ if (
75
+ kycLevel >= 1 &&
76
+ residentialAddress?.proofFile &&
77
+ residentialAddress.source === "PROOF_OF_ADDRESS"
78
+ ) {
79
+ kycLevel = 2;
80
+ }
81
+
82
+ // full SOW and onboarding questionnaire are always at least kycLevel = 3
83
+ if (kycLevel >= 2 && sourceOfWealth && onboarding) {
84
+ kycLevel = 3;
85
+ }
86
+
87
+ return kycLevel;
88
+ }
89
+
90
+ override publicNotes(): PublicNotes {
91
+ return {
92
+ type: "kyc",
93
+ level: this.level(),
94
+ kycLevel: this.kycLevel(),
95
+ };
96
+ }
97
+
98
+ protected override setMissingFields(): void {
99
+ super.setMissingFields();
100
+
101
+ // A kycLevel of 0 means "none reached", which the envelope expresses by omission.
102
+ if (this.envelope.kycLevel === undefined && this.kycLevel() > 0) {
103
+ this.envelope.kycLevel = this.kycLevel();
104
+ }
105
+
106
+ this.envelope.expirationDate ??= this.subject.idDocument?.dateOfExpiry;
107
+ }
108
+ }
@@ -0,0 +1,232 @@
1
+ import { Ed25519Signature2020 } from "@digitalbazaar/ed25519-signature-2020";
2
+ import * as vc from "@digitalbazaar/vc";
3
+
4
+ import type { AvailableIssuerType, VerifiableCredential } from "../types";
5
+ import type { PublicNotes } from "./types";
6
+
7
+ import { assertNoExtraFields } from "../utils";
8
+ import { issuerToKey } from "../utils/issuer";
9
+ import {
10
+ CONTEXT_ED25519_SIGNATURE_2020_V1,
11
+ CONTEXT_V1,
12
+ defaultDocumentLoader,
13
+ } from "../utils/loader";
14
+ import {
15
+ assertValid,
16
+ fieldsOf,
17
+ flatFieldsOf,
18
+ fromFlat,
19
+ sectionsOf,
20
+ toClass,
21
+ toFlat,
22
+ } from "./utils";
23
+
24
+ type Ctor<T> = new () => T;
25
+
26
+ /** The sections of a subject class, with their optionality dropped. */
27
+ export type Sections<TSubject> = {
28
+ [K in keyof TSubject]-?: NonNullable<TSubject[K]>;
29
+ };
30
+
31
+ /**
32
+ * The fields of a class that are not sections: a subject's `id`, an envelope's own fields.
33
+ * Sections are the properties holding another class; everything a credential carries as a
34
+ * value is one of the types below.
35
+ */
36
+ export type OwnFields<T> = Partial<
37
+ Pick<
38
+ T,
39
+ {
40
+ [K in keyof T]-?: NonNullable<T[K]> extends string | number | boolean | Date | Buffer
41
+ ? K
42
+ : never;
43
+ }[keyof T]
44
+ >
45
+ >;
46
+
47
+ /**
48
+ * A credential under construction: an envelope and a subject built up section by section,
49
+ * validated as a whole, then flattened for issuance.
50
+ *
51
+ * Both halves stay partial until `checkValidity()` runs — proving them complete is the
52
+ * point of that call.
53
+ */
54
+ export abstract class VerifiableCredentialBase<TEnvelope extends object, TSubject extends object> {
55
+ /*
56
+ * The JSON-LD contexts, declared here and defined by each subclass. `declare static` stands in
57
+ * for the abstract static TypeScript lacks: a subclass that forgets one is not caught at compile
58
+ * time, but the instance methods below can read them.
59
+ */
60
+ declare static readonly envelopeContext: string;
61
+ declare static readonly subjectContext: string;
62
+
63
+ readonly envelope: Partial<TEnvelope> = {};
64
+ readonly subject: Partial<TSubject> = {};
65
+
66
+ protected constructor(
67
+ private readonly envelopeClass: Ctor<TEnvelope>,
68
+ private readonly subjectClass: Ctor<TSubject>,
69
+ ) {}
70
+
71
+ /**
72
+ * Adds one section of the subject. Fields the section does not declare are rejected: they
73
+ * would silently vanish on serialization, and a caller who misspells one deserves to hear
74
+ * about it rather than issue a credential missing the field.
75
+ *
76
+ * Pass `validate: false` to defer value checks to `checkValidity()`; the extra-field check
77
+ * always runs.
78
+ */
79
+ addSection<K extends keyof TSubject>(
80
+ section: K,
81
+ fields: Sections<TSubject>[K],
82
+ validate = true,
83
+ ): this {
84
+ const meta = sectionsOf(this.subjectClass).find(({ property }) => property === section);
85
+
86
+ if (!meta) throw new Error(`Unknown section: ${String(section)}`);
87
+
88
+ const cls = meta.type();
89
+ const known = new Set(fieldsOf(cls));
90
+ const extra = Object.keys(fields).filter((field) => !known.has(field));
91
+
92
+ if (extra.length > 0) {
93
+ throw new Error(`Unexpected ${String(section)} fields: ${extra.join(", ")}`);
94
+ }
95
+
96
+ /*
97
+ * Assigned onto a real instance rather than a bare object, so `validateSync` finds the
98
+ * class's metadata and `instanceToPlain` applies its transforms.
99
+ */
100
+ const instance = Object.assign(new cls(), fields);
101
+
102
+ if (validate) assertValid(String(section), instance);
103
+
104
+ this.subject[section] = instance as TSubject[K];
105
+
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * Sets the subject's own fields — the ones that are not a section, such as `id`. Unknown
111
+ * fields are rejected for the same reason `addSection` rejects them.
112
+ *
113
+ * Values are checked by `checkValidity()`, since a field left out here may still be filled
114
+ * in by `setMissingFields()` later.
115
+ */
116
+ setSubject(fields: OwnFields<TSubject>): this {
117
+ Object.assign(this.subject, this.ownFields("subject", this.subjectClass, fields));
118
+
119
+ return this;
120
+ }
121
+
122
+ /** `setSubject`, for the envelope: `id`, `issued`, `approvedAt`, `expirationDate`. */
123
+ setEnvelope(fields: OwnFields<TEnvelope>): this {
124
+ Object.assign(this.envelope, this.ownFields("envelope", this.envelopeClass, fields));
125
+
126
+ return this;
127
+ }
128
+
129
+ /**
130
+ * Fills in the fields this credential derives from its own contents, then validates both
131
+ * halves. Throws `CredentialValidationError` if either is incomplete or invalid.
132
+ */
133
+ checkValidity(): void {
134
+ this.setMissingFields();
135
+
136
+ assertValid("envelope", Object.assign(new this.envelopeClass(), this.envelope));
137
+ assertValid("subject", Object.assign(new this.subjectClass(), this.subject));
138
+ }
139
+
140
+ /** The flat credential subject, with its `@context`. */
141
+ serializeSubject(): Record<string, unknown> {
142
+ this.checkValidity();
143
+
144
+ return {
145
+ "@context": [this.contexts.subjectContext],
146
+ ...toFlat(Object.assign(new this.subjectClass(), this.subject)),
147
+ };
148
+ }
149
+
150
+ /** The flat envelope fields. */
151
+ serializeEnvelope(): Record<string, unknown> {
152
+ this.checkValidity();
153
+
154
+ return toFlat(Object.assign(new this.envelopeClass(), this.envelope));
155
+ }
156
+
157
+ /** Signs the credential with `issuer`, producing a verifiable credential. */
158
+ async issue(issuer: AvailableIssuerType): Promise<VerifiableCredential<unknown>> {
159
+ const key = await issuerToKey(issuer);
160
+
161
+ const credential = {
162
+ "@context": [CONTEXT_V1, this.contexts.envelopeContext, CONTEXT_ED25519_SIGNATURE_2020_V1],
163
+ type: ["VerifiableCredential"],
164
+ issuer: key.controller,
165
+ ...this.serializeEnvelope(),
166
+ credentialSubject: this.serializeSubject(),
167
+ };
168
+
169
+ return vc.issue({
170
+ credential,
171
+ suite: new Ed25519Signature2020({ key }),
172
+ documentLoader: defaultDocumentLoader,
173
+ });
174
+ }
175
+
176
+ /**
177
+ * Rebuilds envelope and subject from a serialized credential.
178
+ *
179
+ * A subject key the class does not declare is an error: the subject context defines the
180
+ * subject exhaustively, so an unknown key means the credential does not match the
181
+ * `@context` it claims, and reading it anyway would silently discard what it carried.
182
+ *
183
+ * The envelope is the lenient half — a credential carries W3C fields of its own there
184
+ * (`proof`, `issuanceDate`, `type`, `issuer`), which are dropped rather than rejected.
185
+ *
186
+ * SECURITY: this does not verify the signature. See `verifyCredential()`.
187
+ */
188
+ async deserialize(credential: VerifiableCredential<unknown>): Promise<void> {
189
+ const { credentialSubject, ...envelope } = credential;
190
+
191
+ // The subject's `@context` is the credential's own, not one of its fields.
192
+ const { "@context": _context, ...subject } = credentialSubject as Record<string, unknown>;
193
+
194
+ assertNoExtraFields("subject", flatFieldsOf(this.subjectClass), subject);
195
+
196
+ Object.assign(this.envelope, fromFlat(this.envelopeClass, envelope as Record<string, unknown>));
197
+
198
+ Object.assign(
199
+ this.subject,
200
+ fromFlat(this.subjectClass, credentialSubject as Record<string, unknown>),
201
+ );
202
+ }
203
+
204
+ /** The credential's level, derived from its contents. */
205
+ abstract level(): string;
206
+
207
+ /** The credential's public notes, stored unencrypted alongside it. */
208
+ abstract publicNotes(): PublicNotes;
209
+
210
+ /**
211
+ * The class's own fields, transformed onto an instance. Fields the class does not declare, or
212
+ * declares as a section rather than a value, are rejected as they are by `add`.
213
+ */
214
+ private ownFields<T extends object>(label: string, cls: Ctor<T>, fields: object): Partial<T> {
215
+ const sections = new Set(sectionsOf(cls).map(({ property }) => property));
216
+ const own = fieldsOf(cls).filter((field) => !sections.has(field));
217
+
218
+ assertNoExtraFields(label, new Set(own), fields);
219
+
220
+ return toClass(cls, fields);
221
+ }
222
+
223
+ /** The subclass's static contexts, reached through the instance. */
224
+ private get contexts(): typeof VerifiableCredentialBase {
225
+ return this.constructor as typeof VerifiableCredentialBase;
226
+ }
227
+
228
+ /** Fills in derived envelope fields left unset by the caller. */
229
+ protected setMissingFields(): void {
230
+ (this.envelope as { level?: string }).level ??= this.level();
231
+ }
232
+ }
@@ -0,0 +1,126 @@
1
+ /*
2
+ * Enum values as `as const` arrays: `@IsIn(...)` validates against the array and the union
3
+ * type is derived from it, so each set of values is written once.
4
+ */
5
+
6
+ export const IntendedUses = [
7
+ "INVESTING",
8
+ "PAYMENT_TO_FRIENDS_FAMILY_OR_OTHERS",
9
+ "PURCHASE_DIGITAL_ASSETS",
10
+ "ONLINE_PURCHASES_OF_GOODS_OR_SERVICES",
11
+ "TRADING",
12
+ ] as const;
13
+ export type IntendedUse = (typeof IntendedUses)[number];
14
+
15
+ export const IDDocumentTypes = [
16
+ "PASSPORT",
17
+ "DRIVERS",
18
+ "ID_CARD",
19
+ "VOTING_CARD",
20
+ "PAN_CARD",
21
+ "INTERNAL_PASSPORT",
22
+ "RESIDENCE_PERMIT",
23
+ ] as const;
24
+ export type IDDocumentType = (typeof IDDocumentTypes)[number];
25
+
26
+ export const ResidentialAddressSources = [
27
+ "MANUAL",
28
+ "GPS",
29
+ "EXTERNAL_DB",
30
+ "PROOF_OF_ADDRESS",
31
+ "PROOF_OF_IDENTITY",
32
+ "AUTO_COMPLETE",
33
+ ] as const;
34
+ export type ResidentialAddressSource = (typeof ResidentialAddressSources)[number];
35
+
36
+ export const ScreeningResults = ["CLEAR", "NOT_CHECKED"] as const;
37
+ export type ScreeningResult = (typeof ScreeningResults)[number];
38
+
39
+ export const Genders = ["M", "F", "OTHER"] as const;
40
+ export type Gender = (typeof Genders)[number];
41
+
42
+ export const EmploymentStatuses = [
43
+ "EMPLOYED",
44
+ "SELF_EMPLOYED",
45
+ "UNEMPLOYED",
46
+ "RETIRED",
47
+ "STUDENT",
48
+ ] as const;
49
+ export type EmploymentStatus = (typeof EmploymentStatuses)[number];
50
+
51
+ export const ExpectedMonthlyTransactionCounts = [
52
+ "LESS_THAN_5",
53
+ "BETWEEN_5_AND_10",
54
+ "MORE_THAN_10",
55
+ ] as const;
56
+ export type ExpectedMonthlyTransactionCount = (typeof ExpectedMonthlyTransactionCounts)[number];
57
+
58
+ export const ExpectedMonthlyTransactionVolumes = [
59
+ "LESS_THAN_500",
60
+ "MORE_THAN_500_LESS_THAN_2000",
61
+ "MORE_THAN_2000",
62
+ ] as const;
63
+ export type ExpectedMonthlyTransactionVolume = (typeof ExpectedMonthlyTransactionVolumes)[number];
64
+
65
+ export const SourceOfWealthTypes = [
66
+ "SALARY",
67
+ "SAVINGS",
68
+ "INVESTMENTS",
69
+ "CRYPTO_TRADING",
70
+ "OTHER",
71
+ ] as const;
72
+ export type SourceOfWealthType = (typeof SourceOfWealthTypes)[number];
73
+
74
+ export const YearlyGrossIncomes = [
75
+ "LESS_THAN_20000",
76
+ "FROM_20001_TO_30000",
77
+ "FROM_30001_TO_40000",
78
+ "FROM_40001_TO_50000",
79
+ "FROM_50001_TO_60000",
80
+ "FROM_60001_TO_70000",
81
+ "FROM_70001_TO_80000",
82
+ "FROM_80001_TO_90000",
83
+ "FROM_90001_TO_100000",
84
+ "FROM_100001_TO_110000",
85
+ "FROM_110001_TO_120000",
86
+ "FROM_120001_TO_130000",
87
+ "FROM_130001_TO_140000",
88
+ "FROM_140001_TO_150000",
89
+ "FROM_150001_TO_200000",
90
+ "FROM_200001_TO_500000",
91
+ "MORE_THAN_500000",
92
+ ] as const;
93
+ export type YearlyGrossIncome = (typeof YearlyGrossIncomes)[number];
94
+
95
+ export const ApproximateNetWorths = [
96
+ "UP_TO_25000",
97
+ "BETWEEN_25001_AND_50000",
98
+ "BETWEEN_50001_AND_100000",
99
+ "BETWEEN_100001_AND_300000",
100
+ "BETWEEN_300001_AND_500000",
101
+ "BETWEEN_500001_AND_1000000",
102
+ "OVER_1000001",
103
+ ] as const;
104
+ export type ApproximateNetWorth = (typeof ApproximateNetWorths)[number];
105
+
106
+ export const Occupations = [
107
+ "AGRICULTURE",
108
+ "ARTS_AND_ENTERTAINMENT",
109
+ "CONSTRUCTION",
110
+ "EDUCATION",
111
+ "FINANCIAL_SERVICES",
112
+ "INFORMATION_AND_TECHNOLOGY",
113
+ "RETAIL",
114
+ "REAL_ESTATE",
115
+ "OTHER",
116
+ "BUSINESS_OWNER",
117
+ "HEALTHCARE",
118
+ "INDUSTRIAL",
119
+ "LEGAL_SERVICES",
120
+ "PUBLIC_SECTOR",
121
+ "SENIOR_MANAGEMENT",
122
+ ] as const;
123
+ export type Occupation = (typeof Occupations)[number];
124
+
125
+ export const Currencies = ["EUR", "USD", "GBP", "OTHER"] as const;
126
+ export type Currency = (typeof Currencies)[number];
@@ -0,0 +1,14 @@
1
+ export * from "./enums";
2
+
3
+ export type { Sections, OwnFields } from "./VerifiableCredential";
4
+ export { VerifiableCredentialBase } from "./VerifiableCredential";
5
+ export type { PublicNotes } from "./types";
6
+
7
+ export { EnvelopeV1, EnvelopeV2 } from "./Envelope";
8
+ export { EddV1 as VerifiableCredentialEddV1 } from "./EddV1";
9
+ export { FaceIdV1 as VerifiableCredentialFaceIdV1 } from "./FaceIdV1";
10
+ export { KycV1 as VerifiableCredentialKycV1 } from "./KycV1";
11
+ export { KycV2 as VerifiableCredentialKycV2 } from "./KycV2";
12
+
13
+ export { KycV3 as VerifiableCredentialKycV3 } from "./KycV3";
14
+ export { Subject as VerifiableCredentialKycV3Subject } from "./KycV3/Subject";