@interop/wallet-core 0.1.0 → 0.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.
- package/README.md +18 -2
- package/dist/display/alignment.d.ts +49 -0
- package/dist/display/alignment.d.ts.map +1 -0
- package/dist/display/alignment.js +114 -0
- package/dist/display/alignment.js.map +1 -0
- package/dist/display/credentialName.d.ts +42 -0
- package/dist/display/credentialName.d.ts.map +1 -0
- package/dist/display/credentialName.js +106 -0
- package/dist/display/credentialName.js.map +1 -0
- package/dist/display/displayFields.d.ts +55 -0
- package/dist/display/displayFields.d.ts.map +1 -0
- package/dist/display/displayFields.js +136 -0
- package/dist/display/displayFields.js.map +1 -0
- package/dist/display/evidence.d.ts +44 -0
- package/dist/display/evidence.d.ts.map +1 -0
- package/dist/display/evidence.js +65 -0
- package/dist/display/evidence.js.map +1 -0
- package/dist/display/image.d.ts +18 -0
- package/dist/display/image.d.ts.map +1 -0
- package/dist/display/image.js +23 -0
- package/dist/display/image.js.map +1 -0
- package/dist/display/index.d.ts +38 -0
- package/dist/display/index.d.ts.map +1 -0
- package/dist/display/index.js +32 -0
- package/dist/display/index.js.map +1 -0
- package/dist/display/issuer.d.ts +97 -0
- package/dist/display/issuer.d.ts.map +1 -0
- package/dist/display/issuer.js +126 -0
- package/dist/display/issuer.js.map +1 -0
- package/dist/display/obv3.d.ts +77 -0
- package/dist/display/obv3.d.ts.map +1 -0
- package/dist/display/obv3.js +127 -0
- package/dist/display/obv3.js.map +1 -0
- package/dist/display/parse.d.ts +62 -0
- package/dist/display/parse.d.ts.map +1 -0
- package/dist/display/parse.js +100 -0
- package/dist/display/parse.js.map +1 -0
- package/dist/display/subject.d.ts +75 -0
- package/dist/display/subject.d.ts.map +1 -0
- package/dist/display/subject.js +122 -0
- package/dist/display/subject.js.map +1 -0
- package/dist/display/text.d.ts +42 -0
- package/dist/display/text.d.ts.map +1 -0
- package/dist/display/text.js +62 -0
- package/dist/display/text.js.map +1 -0
- package/dist/display/types.d.ts +55 -0
- package/dist/display/types.d.ts.map +1 -0
- package/dist/display/types.js +41 -0
- package/dist/display/types.js.map +1 -0
- package/dist/display/validity.d.ts +51 -0
- package/dist/display/validity.d.ts.map +1 -0
- package/dist/display/validity.js +51 -0
- package/dist/display/validity.js.map +1 -0
- package/dist/display/verificationView.d.ts +101 -0
- package/dist/display/verificationView.d.ts.map +1 -0
- package/dist/display/verificationView.js +199 -0
- package/dist/display/verificationView.js.map +1 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/request/classify.d.ts +112 -0
- package/dist/request/classify.d.ts.map +1 -0
- package/dist/request/classify.js +210 -0
- package/dist/request/classify.js.map +1 -0
- package/dist/request/composeVp.d.ts +52 -0
- package/dist/request/composeVp.d.ts.map +1 -0
- package/dist/request/composeVp.js +177 -0
- package/dist/request/composeVp.js.map +1 -0
- package/dist/request/exchangeClient.d.ts +165 -0
- package/dist/request/exchangeClient.d.ts.map +1 -0
- package/dist/request/exchangeClient.js +212 -0
- package/dist/request/exchangeClient.js.map +1 -0
- package/dist/request/index.d.ts +35 -0
- package/dist/request/index.d.ts.map +1 -0
- package/dist/request/index.js +35 -0
- package/dist/request/index.js.map +1 -0
- package/dist/request/interactionUrl.d.ts +53 -0
- package/dist/request/interactionUrl.d.ts.map +1 -0
- package/dist/request/interactionUrl.js +83 -0
- package/dist/request/interactionUrl.js.map +1 -0
- package/dist/request/matching.d.ts +69 -0
- package/dist/request/matching.d.ts.map +1 -0
- package/dist/request/matching.js +183 -0
- package/dist/request/matching.js.map +1 -0
- package/dist/request/parse.d.ts +68 -0
- package/dist/request/parse.d.ts.map +1 -0
- package/dist/request/parse.js +114 -0
- package/dist/request/parse.js.map +1 -0
- package/dist/request/presentationSuite.d.ts +71 -0
- package/dist/request/presentationSuite.d.ts.map +1 -0
- package/dist/request/presentationSuite.js +139 -0
- package/dist/request/presentationSuite.js.map +1 -0
- package/dist/request/processRequest.d.ts +48 -0
- package/dist/request/processRequest.d.ts.map +1 -0
- package/dist/request/processRequest.js +139 -0
- package/dist/request/processRequest.js.map +1 -0
- package/dist/request/types.d.ts +150 -0
- package/dist/request/types.d.ts.map +1 -0
- package/dist/request/types.js +2 -0
- package/dist/request/types.js.map +1 -0
- package/dist/sync/types.d.ts.map +1 -1
- package/package.json +23 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obv3.js","sourceRoot":"","sources":["../../src/display/obv3.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Credential input parsing: turning decoded JSON (or a raw user / QR string)
|
|
6
|
+
* into an array of Verifiable Credentials. File reading and network transport
|
|
7
|
+
* stay app-side -- `resolveCredentialsInput` takes an injected `fetchUrl` so the
|
|
8
|
+
* library never imports an HTTP client (DCW passes its `fetchWithTimeout`,
|
|
9
|
+
* Freewallet its CORS-proxy `fetchFromURL`).
|
|
10
|
+
*
|
|
11
|
+
* Drift resolution: `credentialsFromJSON` (Freewallet) and
|
|
12
|
+
* `extractCredentialsFrom` (DCW) both survive -- the former accepts an array /
|
|
13
|
+
* a bare VC / a VP wrapper from a JSON string, the latter routes an
|
|
14
|
+
* already-decoded object. Both now share the data-integrity-core shape guards
|
|
15
|
+
* instead of open-coding the `type` checks. Freewallet's
|
|
16
|
+
* `ResolveCredentialsInputError` code taxonomy is kept; DCW's
|
|
17
|
+
* `VPQR_UNSUPPORTED_MESSAGE` constant is exported for apps that surface it.
|
|
18
|
+
*/
|
|
19
|
+
import type { IVerifiableCredential, IVerifiablePresentation } from '@interop/data-integrity-core';
|
|
20
|
+
/** Message DCW surfaced for the (now unsupported) VPQR `VP1-` input. */
|
|
21
|
+
export declare const VPQR_UNSUPPORTED_MESSAGE = "VPQR encoded credentials are not supported.";
|
|
22
|
+
/** Coded failure of {@link resolveCredentialsInput}. */
|
|
23
|
+
export declare class ResolveCredentialsInputError extends Error {
|
|
24
|
+
readonly code: 'empty' | 'invalid_input' | 'none_found' | 'vpqr_unsupported';
|
|
25
|
+
constructor(code: 'empty' | 'invalid_input' | 'none_found' | 'vpqr_unsupported');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Decodes one or more Verifiable Credentials from a JSON string: an array of
|
|
29
|
+
* VCs (non-credential entries filtered out), a Verifiable Presentation wrapping
|
|
30
|
+
* one or many credentials, or a single VC object. Throws when nothing decodes.
|
|
31
|
+
*
|
|
32
|
+
* @param text {string}
|
|
33
|
+
* @returns {IVerifiableCredential[]}
|
|
34
|
+
*/
|
|
35
|
+
export declare function credentialsFromJSON(text: string): IVerifiableCredential[];
|
|
36
|
+
/**
|
|
37
|
+
* Extracts the VCs from an already-decoded object: a bare VC becomes a
|
|
38
|
+
* single-element array, a VP yields its `verifiableCredential` (VC-vs-VP
|
|
39
|
+
* detection runs the VC check first), anything else yields `null`.
|
|
40
|
+
*
|
|
41
|
+
* @param obj {IVerifiableCredential | IVerifiablePresentation}
|
|
42
|
+
* @returns {IVerifiableCredential[] | null}
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractCredentialsFrom(obj: IVerifiableCredential | IVerifiablePresentation): IVerifiableCredential[] | null;
|
|
45
|
+
/**
|
|
46
|
+
* Normalizes raw user / QR input into an array of VCs. A URL (http/https) is
|
|
47
|
+
* fetched via the injected `fetchUrl` and its body parsed; raw JSON / JSON-LD
|
|
48
|
+
* (`{` or `[`) is parsed directly; a `VP1-` (VPQR) prefix is detected but not
|
|
49
|
+
* supported. Throws a coded {@link ResolveCredentialsInputError} on each
|
|
50
|
+
* failure path.
|
|
51
|
+
*
|
|
52
|
+
* @param options {object}
|
|
53
|
+
* @param options.raw {string} the raw input text
|
|
54
|
+
* @param options.fetchUrl {(url: string) => Promise<string>} fetches a URL's
|
|
55
|
+
* body text (app-provided transport)
|
|
56
|
+
* @returns {Promise<IVerifiableCredential[]>}
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveCredentialsInput({ raw, fetchUrl }: {
|
|
59
|
+
raw: string;
|
|
60
|
+
fetchUrl: (url: string) => Promise<string>;
|
|
61
|
+
}): Promise<IVerifiableCredential[]>;
|
|
62
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/display/parse.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EACV,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,8BAA8B,CAAA;AAMrC,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,gDACU,CAAA;AAE/C,wDAAwD;AACxD,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,YAAY,GAAG,kBAAkB,CAAA;gBAE1E,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,YAAY,GAAG,kBAAkB;CAMtE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,qBAAqB,EAAE,CA0BzE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,qBAAqB,GAAG,uBAAuB,GACnD,qBAAqB,EAAE,GAAG,IAAI,CAYhC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,GAAG,EACH,QAAQ,EACT,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAC3C,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAwBnC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { isVerifiableCredential, isVerifiablePresentation } from '@interop/data-integrity-core/guards';
|
|
2
|
+
/** Message DCW surfaced for the (now unsupported) VPQR `VP1-` input. */
|
|
3
|
+
export const VPQR_UNSUPPORTED_MESSAGE = 'VPQR encoded credentials are not supported.';
|
|
4
|
+
/** Coded failure of {@link resolveCredentialsInput}. */
|
|
5
|
+
export class ResolveCredentialsInputError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(code) {
|
|
8
|
+
super(code);
|
|
9
|
+
this.name = 'ResolveCredentialsInputError';
|
|
10
|
+
this.code = code;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Decodes one or more Verifiable Credentials from a JSON string: an array of
|
|
15
|
+
* VCs (non-credential entries filtered out), a Verifiable Presentation wrapping
|
|
16
|
+
* one or many credentials, or a single VC object. Throws when nothing decodes.
|
|
17
|
+
*
|
|
18
|
+
* @param text {string}
|
|
19
|
+
* @returns {IVerifiableCredential[]}
|
|
20
|
+
*/
|
|
21
|
+
export function credentialsFromJSON(text) {
|
|
22
|
+
const data = JSON.parse(text);
|
|
23
|
+
if (Array.isArray(data)) {
|
|
24
|
+
const vcs = data.filter(item => isVerifiableCredential(item));
|
|
25
|
+
if (vcs.length > 0) {
|
|
26
|
+
return vcs;
|
|
27
|
+
}
|
|
28
|
+
throw new Error('Array did not contain any Verifiable Credentials.');
|
|
29
|
+
}
|
|
30
|
+
if (isVerifiablePresentation(data) &&
|
|
31
|
+
data &&
|
|
32
|
+
typeof data === 'object' &&
|
|
33
|
+
'verifiableCredential' in data) {
|
|
34
|
+
const wrapped = data.verifiableCredential;
|
|
35
|
+
return Array.isArray(wrapped) ? wrapped : [wrapped];
|
|
36
|
+
}
|
|
37
|
+
if (isVerifiableCredential(data)) {
|
|
38
|
+
return [data];
|
|
39
|
+
}
|
|
40
|
+
throw new Error('Could not decode Verifiable Credential(s) from the JSON.');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Extracts the VCs from an already-decoded object: a bare VC becomes a
|
|
44
|
+
* single-element array, a VP yields its `verifiableCredential` (VC-vs-VP
|
|
45
|
+
* detection runs the VC check first), anything else yields `null`.
|
|
46
|
+
*
|
|
47
|
+
* @param obj {IVerifiableCredential | IVerifiablePresentation}
|
|
48
|
+
* @returns {IVerifiableCredential[] | null}
|
|
49
|
+
*/
|
|
50
|
+
export function extractCredentialsFrom(obj) {
|
|
51
|
+
if (isVerifiableCredential(obj)) {
|
|
52
|
+
return [obj];
|
|
53
|
+
}
|
|
54
|
+
if (isVerifiablePresentation(obj) && 'verifiableCredential' in obj) {
|
|
55
|
+
const verifiableCredential = obj.verifiableCredential;
|
|
56
|
+
if (Array.isArray(verifiableCredential)) {
|
|
57
|
+
return verifiableCredential;
|
|
58
|
+
}
|
|
59
|
+
return [verifiableCredential];
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Normalizes raw user / QR input into an array of VCs. A URL (http/https) is
|
|
65
|
+
* fetched via the injected `fetchUrl` and its body parsed; raw JSON / JSON-LD
|
|
66
|
+
* (`{` or `[`) is parsed directly; a `VP1-` (VPQR) prefix is detected but not
|
|
67
|
+
* supported. Throws a coded {@link ResolveCredentialsInputError} on each
|
|
68
|
+
* failure path.
|
|
69
|
+
*
|
|
70
|
+
* @param options {object}
|
|
71
|
+
* @param options.raw {string} the raw input text
|
|
72
|
+
* @param options.fetchUrl {(url: string) => Promise<string>} fetches a URL's
|
|
73
|
+
* body text (app-provided transport)
|
|
74
|
+
* @returns {Promise<IVerifiableCredential[]>}
|
|
75
|
+
*/
|
|
76
|
+
export async function resolveCredentialsInput({ raw, fetchUrl }) {
|
|
77
|
+
const trimmed = raw.trimStart();
|
|
78
|
+
if (!trimmed) {
|
|
79
|
+
throw new ResolveCredentialsInputError('empty');
|
|
80
|
+
}
|
|
81
|
+
let credentials;
|
|
82
|
+
if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
|
|
83
|
+
const jsonText = await fetchUrl(trimmed.trim());
|
|
84
|
+
credentials = credentialsFromJSON(jsonText);
|
|
85
|
+
}
|
|
86
|
+
else if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
87
|
+
credentials = credentialsFromJSON(trimmed);
|
|
88
|
+
}
|
|
89
|
+
else if (trimmed.startsWith('VP1-')) {
|
|
90
|
+
throw new ResolveCredentialsInputError('vpqr_unsupported');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
throw new ResolveCredentialsInputError('invalid_input');
|
|
94
|
+
}
|
|
95
|
+
if (credentials.length === 0) {
|
|
96
|
+
throw new ResolveCredentialsInputError('none_found');
|
|
97
|
+
}
|
|
98
|
+
return credentials;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/display/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Credential-subject readers: pulling the (first) subject out of a VC, deriving
|
|
6
|
+
* the recipient display name, and projecting the OBv3-flavored subject render
|
|
7
|
+
* fields.
|
|
8
|
+
*
|
|
9
|
+
* Drift resolution:
|
|
10
|
+
* - `getSubject` was identical in both apps -- take either.
|
|
11
|
+
* - Recipient-name resolution DIVERGED. Freewallet's `extractIssuedTo` +
|
|
12
|
+
* `resolvePersonFullName` win as the vc-level recipient resolver: they walk a
|
|
13
|
+
* deeper person/contact structure (`person.contact.fullName`, string
|
|
14
|
+
* `person.name`, `person.name.formattedName` / `.name`, `subject.name`) and
|
|
15
|
+
* guard the OBv3 identifier on `identityType === 'name'` (more correct than
|
|
16
|
+
* DCW's "any identityHash").
|
|
17
|
+
* - `credentialSubjectRenderInfo` keeps DCW's subject-level shape and field set
|
|
18
|
+
* (used by the OBv3 card renderer) but returns RAW `startDate` / `endDate`
|
|
19
|
+
* ISO strings instead of moment-formatted `startDateFmt` / `endDateFmt` (the
|
|
20
|
+
* raw-values seam); each app re-applies its own date formatting.
|
|
21
|
+
*/
|
|
22
|
+
import type { IAlignment, ICredentialSubject, IVerifiableCredential } from '@interop/data-integrity-core';
|
|
23
|
+
/**
|
|
24
|
+
* The subject render fields for the credential detail / card view. All dates
|
|
25
|
+
* are RAW ISO strings; the app formats them.
|
|
26
|
+
*/
|
|
27
|
+
export interface SubjectRenderInfo {
|
|
28
|
+
subjectName: string | null;
|
|
29
|
+
issuedTo: string | null;
|
|
30
|
+
degreeName: string | null;
|
|
31
|
+
description: string | null;
|
|
32
|
+
criteria: string | null;
|
|
33
|
+
numberOfCredits: string | null;
|
|
34
|
+
startDate: string | null;
|
|
35
|
+
endDate: string | null;
|
|
36
|
+
achievementImage: string | null;
|
|
37
|
+
achievementType: string | null;
|
|
38
|
+
alignment: IAlignment[] | undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The (first) credential subject. Partially supports VCs with multiple
|
|
42
|
+
* `credentialSubject` entries by picking the first one.
|
|
43
|
+
*
|
|
44
|
+
* @param vc {IVerifiableCredential}
|
|
45
|
+
* @returns {ICredentialSubject}
|
|
46
|
+
*/
|
|
47
|
+
export declare function getSubject(vc: IVerifiableCredential): ICredentialSubject;
|
|
48
|
+
/**
|
|
49
|
+
* Resolves a display name from a subject's person / contact structure, in
|
|
50
|
+
* order: `person.contact.fullName`, a string `person.name`, an object
|
|
51
|
+
* `person.name.formattedName`, `person.name.name`, then `subject.name`.
|
|
52
|
+
* Returns `''` when none is present.
|
|
53
|
+
*
|
|
54
|
+
* @param subject {Record<string, unknown>}
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolvePersonFullName(subject: Record<string, unknown>): string;
|
|
58
|
+
/**
|
|
59
|
+
* The recipient name a credential was issued to: the resolved person full name,
|
|
60
|
+
* else a name-typed OBv3 `identifier` hash, else the top-level credential
|
|
61
|
+
* `name`. Returns `''` when nothing resolves.
|
|
62
|
+
*
|
|
63
|
+
* @param verifiableCredential {IVerifiableCredential}
|
|
64
|
+
* @returns {string}
|
|
65
|
+
*/
|
|
66
|
+
export declare function extractIssuedTo(verifiableCredential: IVerifiableCredential): string;
|
|
67
|
+
/**
|
|
68
|
+
* Projects a credential subject to the render fields used by the OBv3 card /
|
|
69
|
+
* detail view. Dates are RAW ISO strings (see {@link SubjectRenderInfo}).
|
|
70
|
+
*
|
|
71
|
+
* @param credentialSubject {ICredentialSubject}
|
|
72
|
+
* @returns {SubjectRenderInfo}
|
|
73
|
+
*/
|
|
74
|
+
export declare function credentialSubjectRenderInfo(credentialSubject: ICredentialSubject): SubjectRenderInfo;
|
|
75
|
+
//# sourceMappingURL=subject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject.d.ts","sourceRoot":"","sources":["../../src/display/subject.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,8BAA8B,CAAA;AAKrC;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,SAAS,EAAE,UAAU,EAAE,GAAG,SAAS,CAAA;CACpC;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,qBAAqB,GAAG,kBAAkB,CAMxE;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CA4BR;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,oBAAoB,EAAE,qBAAqB,GAC1C,MAAM,CAyBR;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,iBAAiB,EAAE,kBAAkB,GACpC,iBAAiB,CAiDnB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { extractNameFromOBV3Identifier } from './obv3.js';
|
|
2
|
+
import { imageSourceFrom } from './image.js';
|
|
3
|
+
import { asRecord, getTrimmedString } from './text.js';
|
|
4
|
+
/**
|
|
5
|
+
* The (first) credential subject. Partially supports VCs with multiple
|
|
6
|
+
* `credentialSubject` entries by picking the first one.
|
|
7
|
+
*
|
|
8
|
+
* @param vc {IVerifiableCredential}
|
|
9
|
+
* @returns {ICredentialSubject}
|
|
10
|
+
*/
|
|
11
|
+
export function getSubject(vc) {
|
|
12
|
+
const { credentialSubject } = vc;
|
|
13
|
+
if (Array.isArray(credentialSubject)) {
|
|
14
|
+
return credentialSubject[0];
|
|
15
|
+
}
|
|
16
|
+
return credentialSubject;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves a display name from a subject's person / contact structure, in
|
|
20
|
+
* order: `person.contact.fullName`, a string `person.name`, an object
|
|
21
|
+
* `person.name.formattedName`, `person.name.name`, then `subject.name`.
|
|
22
|
+
* Returns `''` when none is present.
|
|
23
|
+
*
|
|
24
|
+
* @param subject {Record<string, unknown>}
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
export function resolvePersonFullName(subject) {
|
|
28
|
+
const person = asRecord(subject.person);
|
|
29
|
+
const contact = asRecord(person?.contact);
|
|
30
|
+
const contactFullName = getTrimmedString(contact?.fullName);
|
|
31
|
+
if (contactFullName) {
|
|
32
|
+
return contactFullName;
|
|
33
|
+
}
|
|
34
|
+
const personName = getTrimmedString(person?.name);
|
|
35
|
+
if (personName) {
|
|
36
|
+
return personName;
|
|
37
|
+
}
|
|
38
|
+
const personNameRecord = asRecord(person?.name);
|
|
39
|
+
if (personNameRecord) {
|
|
40
|
+
const formattedName = getTrimmedString(personNameRecord.formattedName);
|
|
41
|
+
if (formattedName) {
|
|
42
|
+
return formattedName;
|
|
43
|
+
}
|
|
44
|
+
const fallbackPersonName = getTrimmedString(personNameRecord.name);
|
|
45
|
+
if (fallbackPersonName) {
|
|
46
|
+
return fallbackPersonName;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return getTrimmedString(subject.name);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The recipient name a credential was issued to: the resolved person full name,
|
|
53
|
+
* else a name-typed OBv3 `identifier` hash, else the top-level credential
|
|
54
|
+
* `name`. Returns `''` when nothing resolves.
|
|
55
|
+
*
|
|
56
|
+
* @param verifiableCredential {IVerifiableCredential}
|
|
57
|
+
* @returns {string}
|
|
58
|
+
*/
|
|
59
|
+
export function extractIssuedTo(verifiableCredential) {
|
|
60
|
+
const subject = asRecord(getSubject(verifiableCredential));
|
|
61
|
+
if (!subject) {
|
|
62
|
+
return getTrimmedString(verifiableCredential.name);
|
|
63
|
+
}
|
|
64
|
+
const resolvedName = resolvePersonFullName(subject);
|
|
65
|
+
if (resolvedName) {
|
|
66
|
+
return resolvedName;
|
|
67
|
+
}
|
|
68
|
+
if (Array.isArray(subject.identifier)) {
|
|
69
|
+
const nameEntry = subject.identifier.find((identifier) => identifier?.identityType === 'name' || identifier?.type === 'name');
|
|
70
|
+
if (nameEntry?.identityHash) {
|
|
71
|
+
return nameEntry.identityHash;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return getTrimmedString(verifiableCredential.name);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Projects a credential subject to the render fields used by the OBv3 card /
|
|
78
|
+
* detail view. Dates are RAW ISO strings (see {@link SubjectRenderInfo}).
|
|
79
|
+
*
|
|
80
|
+
* @param credentialSubject {ICredentialSubject}
|
|
81
|
+
* @returns {SubjectRenderInfo}
|
|
82
|
+
*/
|
|
83
|
+
export function credentialSubjectRenderInfo(credentialSubject) {
|
|
84
|
+
// SkillClaimCredential: person.name is the subject name.
|
|
85
|
+
const personName = credentialSubject
|
|
86
|
+
?.person?.name;
|
|
87
|
+
const personNameStr = typeof personName === 'string' && personName.trim()
|
|
88
|
+
? personName.trim()
|
|
89
|
+
: null;
|
|
90
|
+
const identityHashName = extractNameFromOBV3Identifier(credentialSubject) ?? null;
|
|
91
|
+
// Used in non-OBv3 components.
|
|
92
|
+
const subjectName = personNameStr ?? credentialSubject?.name ?? identityHashName ?? null;
|
|
93
|
+
// Used in OBv3 components -- prioritize the identityHash over subject.name.
|
|
94
|
+
const issuedTo = personNameStr ?? identityHashName ?? credentialSubject?.name ?? null;
|
|
95
|
+
const degreeName = credentialSubject.degree?.name ?? null;
|
|
96
|
+
const [achievement] = Array.isArray(credentialSubject.achievement)
|
|
97
|
+
? credentialSubject.achievement
|
|
98
|
+
: [credentialSubject.achievement];
|
|
99
|
+
const description = achievement?.description ?? null;
|
|
100
|
+
const criteria = achievement?.criteria?.narrative ?? null;
|
|
101
|
+
const numberOfCredits = achievement?.awardedOnCompletionOf?.numberOfCredits?.value ?? null;
|
|
102
|
+
const achievementImage = imageSourceFrom(achievement?.image);
|
|
103
|
+
const achievementType = achievement?.achievementType
|
|
104
|
+
? achievement.achievementType
|
|
105
|
+
: null;
|
|
106
|
+
const alignment = achievement?.alignment;
|
|
107
|
+
const { startDate = null, endDate = null } = achievement?.awardedOnCompletionOf || {};
|
|
108
|
+
return {
|
|
109
|
+
subjectName,
|
|
110
|
+
issuedTo,
|
|
111
|
+
degreeName,
|
|
112
|
+
description,
|
|
113
|
+
criteria,
|
|
114
|
+
numberOfCredits,
|
|
115
|
+
startDate,
|
|
116
|
+
endDate,
|
|
117
|
+
achievementImage,
|
|
118
|
+
achievementType,
|
|
119
|
+
alignment
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=subject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject.js","sourceRoot":"","sources":["../../src/display/subject.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Small string / record coercion helpers shared by the display derivation
|
|
6
|
+
* functions. These read the loosely-typed fields of a decoded Verifiable
|
|
7
|
+
* Credential without importing any UI or formatting library.
|
|
8
|
+
*
|
|
9
|
+
* Drift resolution: two apps had two slightly different "coerce to a usable
|
|
10
|
+
* string" helpers. DCW's `asNonEmptyString` (stringifies any value, trims,
|
|
11
|
+
* returns `null` when empty) and Freewallet's `getTrimmedString` (only accepts
|
|
12
|
+
* an actual string, returns `''` when not). Both are kept verbatim because
|
|
13
|
+
* their callers depend on the different empty conventions (`null` vs `''`).
|
|
14
|
+
* `asRecord` is Freewallet's object narrower.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Coerces an arbitrary value to a trimmed, non-empty string, or `null`. Any
|
|
18
|
+
* non-string value is stringified first (so a number `3` becomes `'3'`).
|
|
19
|
+
* `null` / `undefined` and whitespace-only values yield `null`.
|
|
20
|
+
*
|
|
21
|
+
* @param value {unknown}
|
|
22
|
+
* @returns {string | null}
|
|
23
|
+
*/
|
|
24
|
+
export declare function asNonEmptyString(value: unknown): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the trimmed value when it is a string, else the empty string. Unlike
|
|
27
|
+
* {@link asNonEmptyString} this never stringifies a non-string value.
|
|
28
|
+
*
|
|
29
|
+
* @param value {unknown}
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
export declare function getTrimmedString(value: unknown): string;
|
|
33
|
+
/**
|
|
34
|
+
* Narrows an arbitrary value to a plain record (`Record<string, unknown>`), or
|
|
35
|
+
* `undefined` when it is null / a primitive / an array is acceptable here since
|
|
36
|
+
* arrays are objects too and callers pass only object-shaped subjects.
|
|
37
|
+
*
|
|
38
|
+
* @param value {unknown}
|
|
39
|
+
* @returns {Record<string, unknown> | undefined}
|
|
40
|
+
*/
|
|
41
|
+
export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
|
|
42
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/display/text.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;GAWG;AAEH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAU9D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKvD;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAK5E"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Small string / record coercion helpers shared by the display derivation
|
|
6
|
+
* functions. These read the loosely-typed fields of a decoded Verifiable
|
|
7
|
+
* Credential without importing any UI or formatting library.
|
|
8
|
+
*
|
|
9
|
+
* Drift resolution: two apps had two slightly different "coerce to a usable
|
|
10
|
+
* string" helpers. DCW's `asNonEmptyString` (stringifies any value, trims,
|
|
11
|
+
* returns `null` when empty) and Freewallet's `getTrimmedString` (only accepts
|
|
12
|
+
* an actual string, returns `''` when not). Both are kept verbatim because
|
|
13
|
+
* their callers depend on the different empty conventions (`null` vs `''`).
|
|
14
|
+
* `asRecord` is Freewallet's object narrower.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Coerces an arbitrary value to a trimmed, non-empty string, or `null`. Any
|
|
18
|
+
* non-string value is stringified first (so a number `3` becomes `'3'`).
|
|
19
|
+
* `null` / `undefined` and whitespace-only values yield `null`.
|
|
20
|
+
*
|
|
21
|
+
* @param value {unknown}
|
|
22
|
+
* @returns {string | null}
|
|
23
|
+
*/
|
|
24
|
+
export function asNonEmptyString(value) {
|
|
25
|
+
if (value === null || value === undefined) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (typeof value === 'string') {
|
|
29
|
+
const s = value.trim();
|
|
30
|
+
return s.length ? s : null;
|
|
31
|
+
}
|
|
32
|
+
const s = `${value}`.trim();
|
|
33
|
+
return s.length ? s : null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Returns the trimmed value when it is a string, else the empty string. Unlike
|
|
37
|
+
* {@link asNonEmptyString} this never stringifies a non-string value.
|
|
38
|
+
*
|
|
39
|
+
* @param value {unknown}
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
export function getTrimmedString(value) {
|
|
43
|
+
if (typeof value !== 'string') {
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
return value.trim();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Narrows an arbitrary value to a plain record (`Record<string, unknown>`), or
|
|
50
|
+
* `undefined` when it is null / a primitive / an array is acceptable here since
|
|
51
|
+
* arrays are objects too and callers pass only object-shaped subjects.
|
|
52
|
+
*
|
|
53
|
+
* @param value {unknown}
|
|
54
|
+
* @returns {Record<string, unknown> | undefined}
|
|
55
|
+
*/
|
|
56
|
+
export function asRecord(value) {
|
|
57
|
+
if (!value || typeof value !== 'object') {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/display/text.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;GAWG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAA;IACb,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;QACtB,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC5B,CAAC;IACD,MAAM,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,IAAI,EAAE,CAAA;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC5B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAA;AACrB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,KAAgC,CAAA;AACzC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Credential type predicates.
|
|
6
|
+
*
|
|
7
|
+
* Drift resolution: DCW and Freewallet disagreed on the resume check -- DCW's
|
|
8
|
+
* took a `credentialSubject` and did a case-insensitive SUBSTRING match on its
|
|
9
|
+
* `type`, while Freewallet's took the whole VC and did an exact
|
|
10
|
+
* `subject.type === 'Resume'`; and DCW's own callers passed the whole VC to the
|
|
11
|
+
* subject-typed function. Rather than pick one, TWO clearly-named functions are
|
|
12
|
+
* exposed:
|
|
13
|
+
*
|
|
14
|
+
* - `isResumeCredentialSubject(subject)` -- DCW's case-insensitive substring
|
|
15
|
+
* check over a subject's `type`.
|
|
16
|
+
* - `isResumeCredential(vc)` -- a vc-typed entry point that reads the subject's
|
|
17
|
+
* `type` off the VC and applies the same substring check, fixing both
|
|
18
|
+
* Freewallet's exact-match miss (`['...','Resume']`) and DCW's callers that
|
|
19
|
+
* passed a VC to a subject-typed function.
|
|
20
|
+
*
|
|
21
|
+
* `isEmploymentCredential` / `isVolunteerCredential` are DCW's, verbatim, over
|
|
22
|
+
* the VC's top-level `type`.
|
|
23
|
+
*/
|
|
24
|
+
import type { ICredentialSubject, IVerifiableCredential } from '@interop/data-integrity-core';
|
|
25
|
+
/**
|
|
26
|
+
* Whether a credential SUBJECT is a resume, by a case-insensitive substring
|
|
27
|
+
* match (`'resume'`) over its `type` (string or array).
|
|
28
|
+
*
|
|
29
|
+
* @param credentialSubject {ICredentialSubject}
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
export declare function isResumeCredentialSubject(credentialSubject: ICredentialSubject): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Whether a CREDENTIAL is a resume, by applying the subject-level substring
|
|
35
|
+
* check to the VC's (first) subject `type`.
|
|
36
|
+
*
|
|
37
|
+
* @param vc {IVerifiableCredential}
|
|
38
|
+
* @returns {boolean}
|
|
39
|
+
*/
|
|
40
|
+
export declare function isResumeCredential(vc: IVerifiableCredential): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a credential's top-level `type` includes `'EmploymentCredential'`.
|
|
43
|
+
*
|
|
44
|
+
* @param credential {IVerifiableCredential}
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
export declare function isEmploymentCredential(credential: IVerifiableCredential): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a credential's top-level `type` includes `'VolunteeringCredential'`.
|
|
50
|
+
*
|
|
51
|
+
* @param credential {IVerifiableCredential}
|
|
52
|
+
* @returns {boolean}
|
|
53
|
+
*/
|
|
54
|
+
export declare function isVolunteerCredential(credential: IVerifiableCredential): boolean;
|
|
55
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/display/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,8BAA8B,CAAA;AAIrC;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,iBAAiB,EAAE,kBAAkB,GACpC,OAAO,CAIT;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,qBAAqB,GAAG,OAAO,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,qBAAqB,GAChC,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,qBAAqB,GAChC,OAAO,CAET"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { typeArray } from '@interop/data-integrity-core/guards';
|
|
2
|
+
import { getSubject } from './subject.js';
|
|
3
|
+
/**
|
|
4
|
+
* Whether a credential SUBJECT is a resume, by a case-insensitive substring
|
|
5
|
+
* match (`'resume'`) over its `type` (string or array).
|
|
6
|
+
*
|
|
7
|
+
* @param credentialSubject {ICredentialSubject}
|
|
8
|
+
* @returns {boolean}
|
|
9
|
+
*/
|
|
10
|
+
export function isResumeCredentialSubject(credentialSubject) {
|
|
11
|
+
return typeArray(credentialSubject?.type).some(x => x.toLowerCase().includes('resume'));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Whether a CREDENTIAL is a resume, by applying the subject-level substring
|
|
15
|
+
* check to the VC's (first) subject `type`.
|
|
16
|
+
*
|
|
17
|
+
* @param vc {IVerifiableCredential}
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
export function isResumeCredential(vc) {
|
|
21
|
+
return isResumeCredentialSubject(getSubject(vc));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Whether a credential's top-level `type` includes `'EmploymentCredential'`.
|
|
25
|
+
*
|
|
26
|
+
* @param credential {IVerifiableCredential}
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
export function isEmploymentCredential(credential) {
|
|
30
|
+
return typeArray(credential?.type).includes('EmploymentCredential');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Whether a credential's top-level `type` includes `'VolunteeringCredential'`.
|
|
34
|
+
*
|
|
35
|
+
* @param credential {IVerifiableCredential}
|
|
36
|
+
* @returns {boolean}
|
|
37
|
+
*/
|
|
38
|
+
export function isVolunteerCredential(credential) {
|
|
39
|
+
return typeArray(credential?.type).includes('VolunteeringCredential');
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/display/types.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CACvC,iBAAqC;IAErC,OAAO,SAAS,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACnC,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAyB;IAC1D,OAAO,yBAAyB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;AAClD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAiC;IAEjC,OAAO,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAA;AACrE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,UAAiC;IAEjC,OAAO,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAA;AACvE,CAAC"}
|