gdc-common-utils-ts 2.9.6 → 2.9.8
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
CHANGED
|
@@ -245,7 +245,10 @@ defines the two-step emergency flow: resolve the individual's index provider
|
|
|
245
245
|
from an opaque subject-identifier ledger key, then ask any available trusted
|
|
246
246
|
tenant to issue one token whose `aud` remains that resolved index provider.
|
|
247
247
|
The ledger value is only `{ indexProviderDid: 'did:web:...' }`; the same opaque
|
|
248
|
-
|
|
248
|
+
hash stops at Fabric. After DID resolution, the authenticated human-facing
|
|
249
|
+
request uses IHE PDQm `POST Patient/$match` with one FHIR `Parameters` body;
|
|
250
|
+
the provider returns a FHIR search `Bundle` and projects private `sameAs`
|
|
251
|
+
associations as governed `Patient.identifier` values.
|
|
249
252
|
|
|
250
253
|
Example:
|
|
251
254
|
|
|
@@ -550,6 +553,9 @@ The canonical API contract should live in JSDoc on exported code. The README act
|
|
|
550
553
|
signing key separate. The organization, EHR/portal or individual remains
|
|
551
554
|
the document author; a registered PractitionerRole or RelatedPerson is the
|
|
552
555
|
attester, including for content entered by that authenticated person.
|
|
556
|
+
- [`normalizeClinicalCreatorBinding(...)`](src/utils/fhir-ips-creator-identity.ts)
|
|
557
|
+
- Accept stable UUIDs and governed bare role codes at the BFF boundary, then
|
|
558
|
+
add canonical UUID URNs and HL7/ISCO coding systems before transport.
|
|
553
559
|
- [`src/examples/frontend-session.ts`](src/examples/frontend-session.ts)
|
|
554
560
|
- Frontend profile/session bootstrap examples.
|
|
555
561
|
- [`src/examples/lifecycle.ts`](src/examples/lifecycle.ts)
|
|
@@ -106,6 +106,30 @@ export type ClinicalCreatorBinding = ClinicalCreatorChannelAliases & Readonly<{
|
|
|
106
106
|
/** Canonical governed ISCO/HL7 role claim; ONESELF is the subject relationship. */
|
|
107
107
|
role: string;
|
|
108
108
|
}>;
|
|
109
|
+
/**
|
|
110
|
+
* High-level creator input accepted from SDK/BFF code.
|
|
111
|
+
*
|
|
112
|
+
* Stable person, assignment and individual-owner identifiers may be either a
|
|
113
|
+
* UUID or an already canonical `urn:uuid`. The role may be a governed bare
|
|
114
|
+
* code or its governed coding-system claim. Callers never concatenate wire
|
|
115
|
+
* prefixes themselves.
|
|
116
|
+
*/
|
|
117
|
+
export type ClinicalCreatorBindingInput = ClinicalCreatorChannelAliases & Readonly<{
|
|
118
|
+
kind: FhirIpsCreatorKind;
|
|
119
|
+
actorIdentifier: string;
|
|
120
|
+
authorIdentifier: string;
|
|
121
|
+
ownerIdentifier: string;
|
|
122
|
+
role: string;
|
|
123
|
+
}>;
|
|
124
|
+
/**
|
|
125
|
+
* Normalizes high-level creator identity before persistence or transport.
|
|
126
|
+
*
|
|
127
|
+
* Personal owners are canonical UUID URNs. Professional owners remain their
|
|
128
|
+
* legal Organization DID/URN. Bare personal and professional role codes are
|
|
129
|
+
* resolved through the governed HL7/ISCO catalog and emitted with their
|
|
130
|
+
* canonical coding system.
|
|
131
|
+
*/
|
|
132
|
+
export declare function normalizeClinicalCreatorBinding(input: ClinicalCreatorBindingInput): ClinicalCreatorBinding;
|
|
109
133
|
export type AuthenticatedClinicalCreatorEvidence = Readonly<{
|
|
110
134
|
actorDid?: string;
|
|
111
135
|
verifiedContactIdentifiers?: readonly string[];
|
|
@@ -3,6 +3,7 @@ import { getHealthcareRoleByClaim } from '../constants/healthcare.js';
|
|
|
3
3
|
import { isStableActorIdentifier } from './actor-identifier.js';
|
|
4
4
|
import { normalizeUuid } from './normalize-uuid.js';
|
|
5
5
|
import { HL7_RELATED_PERSON_FUNCTIONAL_ROLES } from '../constants/hl7-roles.js';
|
|
6
|
+
import { UrnPrefixes } from '../constants/urn.js';
|
|
6
7
|
import { CompositionAttesterModes, } from '../models/interoperable-claims/composition-claims.js';
|
|
7
8
|
export const FhirIpsCreatorKinds = Object.freeze({
|
|
8
9
|
IndividualSubject: 'individual-subject',
|
|
@@ -118,6 +119,29 @@ export function buildFhirIpsCreatorAuthor(input) {
|
|
|
118
119
|
],
|
|
119
120
|
};
|
|
120
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Normalizes high-level creator identity before persistence or transport.
|
|
124
|
+
*
|
|
125
|
+
* Personal owners are canonical UUID URNs. Professional owners remain their
|
|
126
|
+
* legal Organization DID/URN. Bare personal and professional role codes are
|
|
127
|
+
* resolved through the governed HL7/ISCO catalog and emitted with their
|
|
128
|
+
* canonical coding system.
|
|
129
|
+
*/
|
|
130
|
+
export function normalizeClinicalCreatorBinding(input) {
|
|
131
|
+
const actorIdentifier = canonicalUuidUrn(input.actorIdentifier, 'actorIdentifier');
|
|
132
|
+
const authorIdentifier = canonicalUuidUrn(input.authorIdentifier, 'authorIdentifier');
|
|
133
|
+
const ownerIdentifier = input.kind === FhirIpsCreatorKinds.Professional
|
|
134
|
+
? requireReference(input.ownerIdentifier, 'ownerIdentifier')
|
|
135
|
+
: canonicalUuidUrn(input.ownerIdentifier, 'ownerIdentifier');
|
|
136
|
+
const role = canonicalRoleClaim(input.role);
|
|
137
|
+
return {
|
|
138
|
+
...input,
|
|
139
|
+
actorIdentifier,
|
|
140
|
+
authorIdentifier,
|
|
141
|
+
ownerIdentifier,
|
|
142
|
+
role,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
121
145
|
/** Builds the stable actor-and-role pair consumed by Consent permission rules. */
|
|
122
146
|
export function buildClinicalCreatorPermissionActor(binding) {
|
|
123
147
|
requireUuidUrn(binding.actorIdentifier, 'binding.actorIdentifier');
|
|
@@ -160,6 +184,27 @@ function requireUuidUrn(value, label) {
|
|
|
160
184
|
}
|
|
161
185
|
return normalized;
|
|
162
186
|
}
|
|
187
|
+
function canonicalUuidUrn(value, label) {
|
|
188
|
+
const normalized = String(value || '').trim().toLowerCase();
|
|
189
|
+
const uuidValueInput = normalized.startsWith(UrnPrefixes.Uuid)
|
|
190
|
+
? normalized.slice(UrnPrefixes.Uuid.length)
|
|
191
|
+
: normalized;
|
|
192
|
+
if (!/^(?:[0-9a-f]{32}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/.test(uuidValueInput)) {
|
|
193
|
+
throw new TypeError(`${label} must be a UUID or urn:uuid identifier.`);
|
|
194
|
+
}
|
|
195
|
+
const hexadecimal = normalizeUuid(uuidValueInput);
|
|
196
|
+
if (!hexadecimal) {
|
|
197
|
+
throw new TypeError(`${label} must be a UUID or urn:uuid identifier.`);
|
|
198
|
+
}
|
|
199
|
+
const uuid = [
|
|
200
|
+
hexadecimal.slice(0, 8),
|
|
201
|
+
hexadecimal.slice(8, 12),
|
|
202
|
+
hexadecimal.slice(12, 16),
|
|
203
|
+
hexadecimal.slice(16, 20),
|
|
204
|
+
hexadecimal.slice(20),
|
|
205
|
+
].join('-');
|
|
206
|
+
return `${UrnPrefixes.Uuid}${uuid}`;
|
|
207
|
+
}
|
|
163
208
|
function uuidValue(identifier) {
|
|
164
209
|
return identifier.slice('urn:uuid:'.length);
|
|
165
210
|
}
|
|
@@ -189,3 +234,7 @@ function requireRoleCoding(roleClaim) {
|
|
|
189
234
|
display: functionalRole.display,
|
|
190
235
|
};
|
|
191
236
|
}
|
|
237
|
+
function canonicalRoleClaim(roleClaim) {
|
|
238
|
+
const descriptor = requireRoleCoding(roleClaim);
|
|
239
|
+
return `${descriptor.system}|${descriptor.code}`;
|
|
240
|
+
}
|