gdc-common-utils-ts 1.6.0 → 1.7.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/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.js +2 -0
- package/dist/constants/service-capabilities.d.ts +53 -0
- package/dist/constants/service-capabilities.js +72 -0
- package/dist/constants/verifiable-credentials.d.ts +34 -0
- package/dist/constants/verifiable-credentials.js +42 -0
- package/dist/examples/api-flow-examples.d.ts +1 -0
- package/dist/examples/api-flow-examples.js +1 -0
- package/dist/examples/consent-access.d.ts +12 -128
- package/dist/examples/consent-access.js +27 -18
- package/dist/examples/contract-examples.d.ts +1 -0
- package/dist/examples/contract-examples.js +1 -0
- package/dist/examples/frontend-session.d.ts +0 -4
- package/dist/examples/frontend-session.js +13 -7
- package/dist/examples/ica-activation-proof.d.ts +55 -0
- package/dist/examples/ica-activation-proof.js +67 -0
- package/dist/examples/index.d.ts +1 -0
- package/dist/examples/index.js +1 -0
- package/dist/examples/individual-controller.d.ts +19 -15
- package/dist/examples/individual-controller.js +16 -31
- package/dist/examples/lifecycle.d.ts +6 -4
- package/dist/examples/lifecycle.js +9 -7
- package/dist/examples/organization-controller.d.ts +5 -0
- package/dist/examples/organization-controller.js +17 -8
- package/dist/examples/professional.js +8 -7
- package/dist/examples/relationship-access.js +2 -2
- package/dist/examples/shared.d.ts +61 -7
- package/dist/examples/shared.js +55 -7
- package/dist/models/consent-rule.d.ts +1 -0
- package/dist/models/consent-rule.js +1 -0
- package/dist/models/interoperable-claims/allergy-intolerance-claims.js +1 -0
- package/dist/models/interoperable-claims/communication-claims.d.ts +14 -0
- package/dist/models/interoperable-claims/communication-claims.js +15 -0
- package/dist/models/interoperable-claims/condition-claims.js +1 -0
- package/dist/models/interoperable-claims/device-use-statement-claims.js +1 -0
- package/dist/models/interoperable-claims/document-reference-claims.js +1 -0
- package/dist/models/interoperable-claims/medication-statement-claims.d.ts +17 -0
- package/dist/models/interoperable-claims/medication-statement-claims.js +18 -0
- package/dist/utils/activation-policy.d.ts +8 -3
- package/dist/utils/activation-policy.js +26 -12
- package/dist/utils/clinical-resource-converters.js +70 -64
- package/dist/utils/communication-document-reference.js +10 -4
- package/dist/utils/communication-fhir-r4.js +40 -34
- package/dist/utils/consent.d.ts +1 -1
- package/dist/utils/consent.js +21 -20
- package/dist/utils/vp-token.js +8 -6
- package/package.json +1 -1
package/dist/utils/consent.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { ClaimConsent } from '../models/consent-rule.js';
|
|
2
3
|
import { assignCidToClaimsId } from './fhir-cid.js';
|
|
3
4
|
/**
|
|
4
5
|
* Normalizes a phone string into a compact token form.
|
|
@@ -160,16 +161,16 @@ export function buildConsentClaimsSimple(input, options = {}) {
|
|
|
160
161
|
subjectIdentifier,
|
|
161
162
|
consentClaims: {
|
|
162
163
|
'@context': 'org.hl7.fhir.api',
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
[ClaimConsent.decision]: input.decision || 'permit',
|
|
165
|
+
[ClaimConsent.subject]: subjectIdentifier,
|
|
166
|
+
[ClaimConsent.identifier]: consentIdentifier,
|
|
167
|
+
[ClaimConsent.date]: consentDate,
|
|
168
|
+
[ClaimConsent.purpose]: input.purpose,
|
|
169
|
+
[ClaimConsent.action]: (input.actions || []).join(','),
|
|
170
|
+
[ClaimConsent.actorIdentifier]: actorIdentifier,
|
|
171
|
+
[ClaimConsent.actorRole]: input.actorRole,
|
|
172
|
+
[ClaimConsent.attachmentContentType]: input.attachmentContentType || 'application/odrl+json',
|
|
173
|
+
[ClaimConsent.attachmentData]: input.attachmentBase64 || 'e30=',
|
|
173
174
|
},
|
|
174
175
|
};
|
|
175
176
|
}
|
|
@@ -441,7 +442,7 @@ export function resolveConsentActor(actor) {
|
|
|
441
442
|
* @param options.now Optional evaluation timestamp.
|
|
442
443
|
*/
|
|
443
444
|
export function isConsentRuleActive(rule, options = {}) {
|
|
444
|
-
if (options.subject && String(rule[
|
|
445
|
+
if (options.subject && String(rule[ClaimConsent.subject] || '').trim() !== String(options.subject || '').trim()) {
|
|
445
446
|
return false;
|
|
446
447
|
}
|
|
447
448
|
const now = options.now instanceof Date
|
|
@@ -449,8 +450,8 @@ export function isConsentRuleActive(rule, options = {}) {
|
|
|
449
450
|
: options.now
|
|
450
451
|
? new Date(options.now).getTime()
|
|
451
452
|
: Date.now();
|
|
452
|
-
const periodStart = String(rule[
|
|
453
|
-
const periodEnd = String(rule[
|
|
453
|
+
const periodStart = String(rule[ClaimConsent.periodStart] || '').trim();
|
|
454
|
+
const periodEnd = String(rule[ClaimConsent.periodEnd] || '').trim();
|
|
454
455
|
if (periodStart && !Number.isNaN(Date.parse(periodStart)) && Date.parse(periodStart) > now)
|
|
455
456
|
return false;
|
|
456
457
|
if (periodEnd && !Number.isNaN(Date.parse(periodEnd)) && Date.parse(periodEnd) < now)
|
|
@@ -460,7 +461,7 @@ export function isConsentRuleActive(rule, options = {}) {
|
|
|
460
461
|
function groupRulesBy(rules, predicate) {
|
|
461
462
|
const groups = {};
|
|
462
463
|
for (const rule of rules) {
|
|
463
|
-
for (const token of splitCsv(rule[
|
|
464
|
+
for (const token of splitCsv(rule[ClaimConsent.actorIdentifier])) {
|
|
464
465
|
const normalized = normalizeConsentTarget(token, { preferOrganizationDid: true });
|
|
465
466
|
if (!predicate(normalized))
|
|
466
467
|
continue;
|
|
@@ -493,7 +494,7 @@ function normalizeRequestedList(values, wildcard = '*') {
|
|
|
493
494
|
}
|
|
494
495
|
function extractRuleResourceTypes(rule) {
|
|
495
496
|
const candidates = [
|
|
496
|
-
rule[
|
|
497
|
+
rule[ClaimConsent.resourceType],
|
|
497
498
|
rule['Consent.resource-type'],
|
|
498
499
|
rule['Consent.resource'],
|
|
499
500
|
rule['Consent.data-type'],
|
|
@@ -506,14 +507,14 @@ function extractRuleResourceTypes(rule) {
|
|
|
506
507
|
return [];
|
|
507
508
|
}
|
|
508
509
|
function ruleMatchesRole(rule, actorRole) {
|
|
509
|
-
const ruleRoles = splitCsv(rule[
|
|
510
|
+
const ruleRoles = splitCsv(rule[ClaimConsent.actorRole]).map(normalizeConsentRoleValue).filter(Boolean);
|
|
510
511
|
if (ruleRoles.length === 0 || ruleRoles.includes('*'))
|
|
511
512
|
return true;
|
|
512
513
|
const requestedRole = normalizeConsentRoleValue(String(actorRole || ''));
|
|
513
514
|
return !!requestedRole && ruleRoles.includes(requestedRole);
|
|
514
515
|
}
|
|
515
516
|
function ruleMatchesPurpose(rule, purpose) {
|
|
516
|
-
const rulePurpose = String(rule[
|
|
517
|
+
const rulePurpose = String(rule[ClaimConsent.purpose] || '').trim();
|
|
517
518
|
if (!purpose || !rulePurpose)
|
|
518
519
|
return true;
|
|
519
520
|
return rulePurpose === purpose;
|
|
@@ -522,7 +523,7 @@ function ruleMatchesSection(rule, section) {
|
|
|
522
523
|
if (!section || section === '*')
|
|
523
524
|
return true;
|
|
524
525
|
const requestedSection = normalizeSectionToken(section);
|
|
525
|
-
const actions = splitCsv(rule[
|
|
526
|
+
const actions = splitCsv(rule[ClaimConsent.action]).map(normalizeSectionToken);
|
|
526
527
|
if (actions.length === 0)
|
|
527
528
|
return false;
|
|
528
529
|
return actions.includes(requestedSection) || actions.includes('*');
|
|
@@ -536,7 +537,7 @@ function ruleMatchesResourceType(rule, resourceType) {
|
|
|
536
537
|
return resourceTypes.includes(resourceType) || resourceTypes.includes('*');
|
|
537
538
|
}
|
|
538
539
|
function resolveRuleMatch(rule, actor) {
|
|
539
|
-
for (const token of splitCsv(rule[
|
|
540
|
+
for (const token of splitCsv(rule[ClaimConsent.actorIdentifier])) {
|
|
540
541
|
const normalized = normalizeConsentTarget(token, { preferOrganizationDid: true });
|
|
541
542
|
if (actor.directTargets.some((target) => target.canonicalValue === normalized.canonicalValue)) {
|
|
542
543
|
return { matchKind: 'direct', target: normalized, precedenceBase: 10 };
|
|
@@ -554,7 +555,7 @@ function toRuleMatch(rule, actor, section, resourceType) {
|
|
|
554
555
|
const resolved = resolveRuleMatch(rule, actor);
|
|
555
556
|
if (!resolved.target || resolved.matchKind === 'none' || resolved.precedenceBase === undefined)
|
|
556
557
|
return undefined;
|
|
557
|
-
const decision = rule[
|
|
558
|
+
const decision = rule[ClaimConsent.decision];
|
|
558
559
|
const precedence = resolved.precedenceBase + (decision === 'deny' ? 0 : 1);
|
|
559
560
|
return {
|
|
560
561
|
rule,
|
package/dist/utils/vp-token.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
// Always create JSDoc, do not use strings inline in keys nor values, use types instead, and reuse the data test examples.
|
|
1
2
|
import { Content } from './content.js';
|
|
3
|
+
import { ORGANIZATION_ACTIVATION_VC_TYPES, REPRESENTATIVE_ACTIVATION_VC_TYPES, W3cCredentialContexts, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
|
|
2
4
|
function fallbackId() {
|
|
3
5
|
const rand = Math.random().toString(36).slice(2, 10);
|
|
4
6
|
return `id-${Date.now()}-${rand}`;
|
|
@@ -26,8 +28,8 @@ export function createVP(input) {
|
|
|
26
28
|
exp: input?.exp ?? ttl?.exp,
|
|
27
29
|
nonce,
|
|
28
30
|
vp: {
|
|
29
|
-
'@context': [
|
|
30
|
-
type: [
|
|
31
|
+
'@context': [W3cCredentialContexts.V1],
|
|
32
|
+
type: [W3cCredentialTypes.VerifiablePresentation],
|
|
31
33
|
holder: input?.vp?.holder || input?.iss || '',
|
|
32
34
|
verifiableCredential: [],
|
|
33
35
|
...(input?.vp || {}),
|
|
@@ -145,7 +147,7 @@ export function getVpCredentialByAnyType(vpToken, acceptedTypes) {
|
|
|
145
147
|
* @param vpToken Compact VP token or raw JSON string.
|
|
146
148
|
*/
|
|
147
149
|
export function getOrganizationCredentialFromVpToken(vpToken) {
|
|
148
|
-
return getVpCredentialByAnyType(vpToken, [
|
|
150
|
+
return getVpCredentialByAnyType(vpToken, [...ORGANIZATION_ACTIVATION_VC_TYPES]);
|
|
149
151
|
}
|
|
150
152
|
/**
|
|
151
153
|
* Extracts the legal representative credential from a VP token when present.
|
|
@@ -153,7 +155,7 @@ export function getOrganizationCredentialFromVpToken(vpToken) {
|
|
|
153
155
|
* @param vpToken Compact VP token or raw JSON string.
|
|
154
156
|
*/
|
|
155
157
|
export function getLegalRepresentativeCredentialFromVpToken(vpToken) {
|
|
156
|
-
return getVpCredentialByAnyType(vpToken, [
|
|
158
|
+
return getVpCredentialByAnyType(vpToken, [...REPRESENTATIVE_ACTIVATION_VC_TYPES]);
|
|
157
159
|
}
|
|
158
160
|
function vcHasAnyType(vcPayload, acceptedTypes) {
|
|
159
161
|
if (!vcPayload)
|
|
@@ -172,10 +174,10 @@ function addTypedVC(vpPayload, vc, acceptedTypes, label) {
|
|
|
172
174
|
return addVC(vpPayload, vc);
|
|
173
175
|
}
|
|
174
176
|
export function addOrganizationCredential(vpPayload, vc) {
|
|
175
|
-
return addTypedVC(vpPayload, vc, [
|
|
177
|
+
return addTypedVC(vpPayload, vc, [...ORGANIZATION_ACTIVATION_VC_TYPES], 'Organization');
|
|
176
178
|
}
|
|
177
179
|
export function addLegalRepresentativeCredential(vpPayload, vc) {
|
|
178
|
-
return addTypedVC(vpPayload, vc, [
|
|
180
|
+
return addTypedVC(vpPayload, vc, [...REPRESENTATIVE_ACTIVATION_VC_TYPES], 'LegalRepresentative');
|
|
179
181
|
}
|
|
180
182
|
export function prepareForSignature(header, payload) {
|
|
181
183
|
const encodedHeader = Content.objectToRawBase64UrlSafe(header);
|