gdc-common-utils-ts 2.3.20 → 2.3.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/utils/actor.d.ts +7 -1
- package/dist/utils/actor.js +29 -9
- package/dist/utils/communication-bundle-document-request.d.ts +7 -2
- package/dist/utils/communication-bundle-document-request.js +7 -2
- package/dist/utils/consent.d.ts +4 -0
- package/dist/utils/consent.js +6 -0
- package/dist/utils/professional-smart.d.ts +17 -0
- package/dist/utils/professional-smart.js +33 -0
- package/package.json +1 -1
package/dist/utils/actor.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type ParsedActor = {
|
|
|
2
2
|
/**
|
|
3
3
|
* The token subject / authenticated actor identifier (as provided in the token request).
|
|
4
4
|
* Examples:
|
|
5
|
+
* - did:web:api.acme.org:member:z6MksExampleHashedMemberId:ISCO-08|2211
|
|
5
6
|
* - did:web:api.acme.org:employee:z6MksExampleHashedEmployeeId:ISCO-08|2211
|
|
6
7
|
* - did:web:api.acme.org:employee:z6MksExampleHashedEmployeeId:ISCO-08|2211:<device-uuid>
|
|
7
8
|
* - did:web:api.acme.org:employee:doctor1@acme.org:ISCO-08|2211
|
|
@@ -10,10 +11,15 @@ export type ParsedActor = {
|
|
|
10
11
|
* - did:web:api.acme.org:family:<id>:v3-RoleCode|CHILD:<device-uuid>
|
|
11
12
|
*/
|
|
12
13
|
sub: string;
|
|
13
|
-
/** The
|
|
14
|
+
/** The terminal member identifier (hashed email/phone, family id, or raw email). */
|
|
14
15
|
identifier?: string;
|
|
15
16
|
/** The employee role code if present (e.g. "ISCO-08|2211"). */
|
|
16
17
|
role?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Membership domain inferred from the terminal role contract, not from a
|
|
20
|
+
* provider-specific `member`/`employee` path label.
|
|
21
|
+
*/
|
|
22
|
+
memberKind?: 'organization' | 'individual';
|
|
17
23
|
/** The base organization did:web if `sub` is did:web (e.g. "did:web:api.acme.org"). */
|
|
18
24
|
organization?: string;
|
|
19
25
|
};
|
package/dist/utils/actor.js
CHANGED
|
@@ -11,20 +11,40 @@ export function parseActorFromSub(sub) {
|
|
|
11
11
|
const host = after.split(':')[0];
|
|
12
12
|
if (host)
|
|
13
13
|
parsed.organization = `did:web:${host}`;
|
|
14
|
-
//
|
|
15
|
-
//
|
|
14
|
+
// Member vocabulary is provider-specific (`member`, `employee`, `family`,
|
|
15
|
+
// `individual-member`, ...). The interoperable identity tuple is the
|
|
16
|
+
// terminal `<identifier>:<role-system>|<role-code>` pair, optionally
|
|
17
|
+
// followed by a device id. Do not make consent matching depend on a path
|
|
18
|
+
// label chosen by a hosted or external DID provider.
|
|
16
19
|
const parts = after.split(':');
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
const roleIdx = parts.findIndex((part) => {
|
|
21
|
+
try {
|
|
22
|
+
return decodeURIComponent(part).includes('|');
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return part.includes('|');
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const hasRoleLabel = roleIdx > 0 && parts[roleIdx - 1].toLowerCase() === 'role';
|
|
29
|
+
const idIdx = roleIdx > 0 ? roleIdx - (hasRoleLabel ? 2 : 1) : -1;
|
|
20
30
|
const identifier = idIdx >= 0 ? parts[idIdx] : undefined;
|
|
21
31
|
if (identifier) {
|
|
22
32
|
parsed.identifier = identifier.includes('@') ? identifier.toLowerCase() : identifier;
|
|
23
33
|
}
|
|
24
|
-
if (
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
parsed.role =
|
|
34
|
+
if (roleIdx >= 0) {
|
|
35
|
+
const encodedRole = parts[roleIdx];
|
|
36
|
+
try {
|
|
37
|
+
parsed.role = decodeURIComponent(encodedRole);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
parsed.role = encodedRole;
|
|
41
|
+
}
|
|
42
|
+
const normalizedRole = String(parsed.role || '').trim().toLowerCase();
|
|
43
|
+
const pathLabels = parts.slice(1, Math.max(1, idIdx)).map((part) => part.toLowerCase());
|
|
44
|
+
parsed.memberKind = normalizedRole.startsWith('v3-rolecode|')
|
|
45
|
+
|| pathLabels.some((part) => part === 'family' || part === 'related-person' || part === 'individual-member')
|
|
46
|
+
? 'individual'
|
|
47
|
+
: 'organization';
|
|
28
48
|
}
|
|
29
49
|
return parsed;
|
|
30
50
|
}
|
|
@@ -157,8 +157,13 @@ export declare function buildBundleSearchReferenceUrl(input: Readonly<{
|
|
|
157
157
|
*/
|
|
158
158
|
export declare function createSummaryOperationRequestParameters(subjectIdOrInput: string | CreateSummaryOperationParametersInput, filterSections?: string[]): ReadonlyArray<ParameterData>;
|
|
159
159
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
160
|
+
* Compatibility escape hatch that flattens semantic summary parameters into a
|
|
161
|
+
* relative `Bundle/_search` operation reference.
|
|
162
|
+
*
|
|
163
|
+
* New application/BFF code uses the actor facade `requestClinicalSummary(...)`.
|
|
164
|
+
* The facade submits a `Communication`; GW interprets its content reference
|
|
165
|
+
* internally. Callers must not turn this returned value into a second direct
|
|
166
|
+
* HTTP request to the subject index.
|
|
162
167
|
*/
|
|
163
168
|
export declare function createSummaryOperationRequestReferencePath(parameters: ReadonlyArray<ParameterData>): string;
|
|
164
169
|
/**
|
|
@@ -246,8 +246,13 @@ export function createSummaryOperationRequestParameters(subjectIdOrInput, filter
|
|
|
246
246
|
];
|
|
247
247
|
}
|
|
248
248
|
/**
|
|
249
|
-
*
|
|
250
|
-
*
|
|
249
|
+
* Compatibility escape hatch that flattens semantic summary parameters into a
|
|
250
|
+
* relative `Bundle/_search` operation reference.
|
|
251
|
+
*
|
|
252
|
+
* New application/BFF code uses the actor facade `requestClinicalSummary(...)`.
|
|
253
|
+
* The facade submits a `Communication`; GW interprets its content reference
|
|
254
|
+
* internally. Callers must not turn this returned value into a second direct
|
|
255
|
+
* HTTP request to the subject index.
|
|
251
256
|
*/
|
|
252
257
|
export function createSummaryOperationRequestReferencePath(parameters) {
|
|
253
258
|
const params = ['type=document'];
|
package/dist/utils/consent.d.ts
CHANGED
|
@@ -54,6 +54,10 @@ export type BuildConsentClaimsSimpleInput = SubjectIdentifierInput & {
|
|
|
54
54
|
consentIdentifier?: string;
|
|
55
55
|
consentDate?: string;
|
|
56
56
|
decision?: 'permit' | 'deny';
|
|
57
|
+
/** Stable identifier/thread of the permission request that caused this decision. */
|
|
58
|
+
eventBasedOn?: string;
|
|
59
|
+
/** Canonical Communication reference for the permission request being answered. */
|
|
60
|
+
sourceReference?: string;
|
|
57
61
|
attachmentContentType?: string;
|
|
58
62
|
attachmentBase64?: string;
|
|
59
63
|
};
|
package/dist/utils/consent.js
CHANGED
|
@@ -169,6 +169,12 @@ export function buildConsentClaimsSimple(input, options = {}) {
|
|
|
169
169
|
[ClaimConsent.action]: (input.actions || []).join(','),
|
|
170
170
|
[ClaimConsent.actorIdentifier]: actorIdentifier,
|
|
171
171
|
[ClaimConsent.actorRole]: input.actorRole,
|
|
172
|
+
...(String(input.eventBasedOn || '').trim()
|
|
173
|
+
? { [ClaimConsent.eventBasedOn]: String(input.eventBasedOn).trim() }
|
|
174
|
+
: {}),
|
|
175
|
+
...(String(input.sourceReference || '').trim()
|
|
176
|
+
? { [ClaimConsent.sourceReference]: String(input.sourceReference).trim() }
|
|
177
|
+
: {}),
|
|
172
178
|
[ClaimConsent.attachmentContentType]: input.attachmentContentType || 'application/odrl+json',
|
|
173
179
|
[ClaimConsent.attachmentData]: input.attachmentBase64 || 'e30=',
|
|
174
180
|
},
|
|
@@ -20,6 +20,13 @@ export type ProfessionalSmartVpPayloadInput = Readonly<{
|
|
|
20
20
|
additionalVp?: Record<string, unknown>;
|
|
21
21
|
additionalPayload?: Record<string, unknown>;
|
|
22
22
|
}>;
|
|
23
|
+
/** Identity fields read from an already-verified professional credential. */
|
|
24
|
+
export type ProfessionalCredentialSummary = Readonly<{
|
|
25
|
+
actorDid: string;
|
|
26
|
+
role: string;
|
|
27
|
+
issuerDid?: string;
|
|
28
|
+
sameAs: string[];
|
|
29
|
+
}>;
|
|
23
30
|
/**
|
|
24
31
|
* Returns the normalized public continuity aliases for one professional
|
|
25
32
|
* identity VC.
|
|
@@ -62,6 +69,16 @@ export declare function getProfessionalIdentityTelephone(input: Readonly<Pick<Pr
|
|
|
62
69
|
* @param input Professional identity source values.
|
|
63
70
|
*/
|
|
64
71
|
export declare function getProfessionalIdentityVC(input: ProfessionalEmployeeCredentialInput): Record<string, unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Reads the actor and role asserted by one professional credential. Signature
|
|
74
|
+
* and employer/issuer trust verification belongs to the enclosing VP verifier.
|
|
75
|
+
*/
|
|
76
|
+
export declare function summarizeProfessionalIdentityCredential(credential: unknown): ProfessionalCredentialSummary | undefined;
|
|
77
|
+
/** Finds the exact actor and role in an already-verified professional VP. */
|
|
78
|
+
export declare function getMatchingProfessionalCredentialFromVpToken(vpToken: string, criteria: Readonly<{
|
|
79
|
+
actorDid: string;
|
|
80
|
+
role: string;
|
|
81
|
+
}>): ProfessionalCredentialSummary | undefined;
|
|
65
82
|
/**
|
|
66
83
|
* Backwards-compatible alias kept for existing SMART demo callers.
|
|
67
84
|
*
|
|
@@ -2,6 +2,7 @@ import { ClaimsPersonSchemaorg } from '../constants/schemaorg.js';
|
|
|
2
2
|
import { ProfessionalCredentialTypes, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
|
|
3
3
|
import { normalizeSameAsHashCsv, normalizeSameAsHashList, normalizeTelephoneHash } from './same-as.js';
|
|
4
4
|
import { buildUnsignedVpJwt } from './jwt.js';
|
|
5
|
+
import { getVpCredentials } from './vp-token.js';
|
|
5
6
|
/**
|
|
6
7
|
* Returns the normalized public continuity aliases for one professional
|
|
7
8
|
* identity VC.
|
|
@@ -84,6 +85,38 @@ export function getProfessionalIdentityVC(input) {
|
|
|
84
85
|
...(input.additionalCredential || {}),
|
|
85
86
|
};
|
|
86
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Reads the actor and role asserted by one professional credential. Signature
|
|
90
|
+
* and employer/issuer trust verification belongs to the enclosing VP verifier.
|
|
91
|
+
*/
|
|
92
|
+
export function summarizeProfessionalIdentityCredential(credential) {
|
|
93
|
+
const source = credential;
|
|
94
|
+
const types = Array.isArray(source?.type) ? source.type.map(String) : [String(source?.type || '')];
|
|
95
|
+
if (!types.includes(ProfessionalCredentialTypes.EmployeeCredential))
|
|
96
|
+
return undefined;
|
|
97
|
+
const subject = source?.credentialSubject || {};
|
|
98
|
+
const actorDid = String(subject.id || '').trim();
|
|
99
|
+
const role = String(subject.hasOccupation || '').trim();
|
|
100
|
+
if (!actorDid || !role)
|
|
101
|
+
return undefined;
|
|
102
|
+
const issuerDid = String(source?.issuer?.id || source?.issuer || '').trim();
|
|
103
|
+
return {
|
|
104
|
+
actorDid,
|
|
105
|
+
role,
|
|
106
|
+
...(issuerDid ? { issuerDid } : {}),
|
|
107
|
+
sameAs: normalizeSameAsHashList(subject.sameAs),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/** Finds the exact actor and role in an already-verified professional VP. */
|
|
111
|
+
export function getMatchingProfessionalCredentialFromVpToken(vpToken, criteria) {
|
|
112
|
+
const actorDid = String(criteria.actorDid || '').trim();
|
|
113
|
+
const role = String(criteria.role || '').trim().toLowerCase();
|
|
114
|
+
return getVpCredentials(vpToken)
|
|
115
|
+
.map(summarizeProfessionalIdentityCredential)
|
|
116
|
+
.find((summary) => Boolean(summary
|
|
117
|
+
&& summary.actorDid === actorDid
|
|
118
|
+
&& summary.role.toLowerCase() === role));
|
|
119
|
+
}
|
|
87
120
|
/**
|
|
88
121
|
* Backwards-compatible alias kept for existing SMART demo callers.
|
|
89
122
|
*
|