gdc-common-utils-ts 2.1.0 → 2.3.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 (175) hide show
  1. package/README.md +22 -2
  2. package/dist/claims/claims-helpers-allergy-intolerance.d.ts +8 -0
  3. package/dist/claims/claims-helpers-allergy-intolerance.js +30 -12
  4. package/dist/claims/claims-helpers-condition.d.ts +8 -0
  5. package/dist/claims/claims-helpers-condition.js +30 -12
  6. package/dist/claims/claims-helpers-consent.d.ts +4 -0
  7. package/dist/claims/claims-helpers-consent.js +15 -1
  8. package/dist/claims/claims-helpers-diagnostic-report.d.ts +4 -0
  9. package/dist/claims/claims-helpers-diagnostic-report.js +17 -2
  10. package/dist/claims/claims-helpers-medication-statement.d.ts +10 -2
  11. package/dist/claims/claims-helpers-medication-statement.js +32 -14
  12. package/dist/constants/data-collections.js +0 -1
  13. package/dist/constants/didcomm.d.ts +22 -0
  14. package/dist/constants/didcomm.js +22 -0
  15. package/dist/constants/fhir-resource-types.d.ts +16 -0
  16. package/dist/constants/fhir-resource-types.js +7 -0
  17. package/dist/constants/healthcare.d.ts +348 -193
  18. package/dist/constants/healthcare.js +99 -37
  19. package/dist/constants/hl7-roles.d.ts +38 -4
  20. package/dist/constants/hl7-roles.js +92 -4
  21. package/dist/constants/index.d.ts +1 -0
  22. package/dist/constants/index.js +1 -0
  23. package/dist/constants/lifecycle.d.ts +2 -0
  24. package/dist/constants/lifecycle.js +2 -0
  25. package/dist/constants/verifiable-credentials.d.ts +9 -0
  26. package/dist/constants/verifiable-credentials.js +9 -0
  27. package/dist/examples/bundle-didcomm-payload.js +4 -2
  28. package/dist/examples/communication-attached-bundle-session.js +27 -27
  29. package/dist/examples/communication-didcomm-payload.d.ts +8 -4
  30. package/dist/examples/communication-didcomm-payload.js +17 -11
  31. package/dist/examples/consent-access.js +2 -1
  32. package/dist/examples/employee.d.ts +21 -0
  33. package/dist/examples/employee.js +21 -0
  34. package/dist/examples/individual-controller.d.ts +27 -0
  35. package/dist/examples/individual-controller.js +28 -1
  36. package/dist/examples/inter-tenant-access-contract.js +3 -2
  37. package/dist/examples/ips-bundle.js +17 -16
  38. package/dist/examples/lifecycle.js +13 -11
  39. package/dist/examples/profile-manager-mem.js +2 -1
  40. package/dist/examples/related-person.d.ts +14 -0
  41. package/dist/examples/related-person.js +18 -4
  42. package/dist/examples/shared.d.ts +12 -3
  43. package/dist/examples/shared.js +13 -4
  44. package/dist/examples/vital-signs.js +1 -1
  45. package/dist/examples/wallet-mem.js +4 -2
  46. package/dist/i18n/role-codes.i18n.d.ts +9 -1
  47. package/dist/i18n/role-codes.i18n.js +12 -1
  48. package/dist/models/authority-resolution.d.ts +56 -0
  49. package/dist/models/authority-resolution.js +2 -0
  50. package/dist/models/bundle-editor-types.d.ts +89 -0
  51. package/dist/models/bundle-editor-types.js +45 -0
  52. package/dist/models/bundle.d.ts +5 -0
  53. package/dist/models/communication-attached-bundle-session.d.ts +6 -4
  54. package/dist/models/communication-attached-bundle-session.js +6 -4
  55. package/dist/models/confidential-storage.d.ts +2 -1
  56. package/dist/models/consent-rule.d.ts +11 -1
  57. package/dist/models/consent-rule.js +9 -1
  58. package/dist/models/device-license.d.ts +20 -0
  59. package/dist/models/index.d.ts +2 -0
  60. package/dist/models/index.js +2 -0
  61. package/dist/models/individual-onboarding.d.ts +18 -0
  62. package/dist/models/interoperable-claims/allergy-intolerance-claims.d.ts +12 -1
  63. package/dist/models/interoperable-claims/allergy-intolerance-claims.js +12 -1
  64. package/dist/models/interoperable-claims/condition-claims.d.ts +12 -1
  65. package/dist/models/interoperable-claims/condition-claims.js +12 -1
  66. package/dist/models/interoperable-claims/diagnostic-report-claims.d.ts +13 -2
  67. package/dist/models/interoperable-claims/diagnostic-report-claims.js +12 -1
  68. package/dist/models/interoperable-claims/document-reference-claims.d.ts +1 -0
  69. package/dist/models/interoperable-claims/document-reference-claims.js +3 -0
  70. package/dist/models/interoperable-claims/medication-statement-claims.d.ts +17 -0
  71. package/dist/models/interoperable-claims/medication-statement-claims.js +17 -0
  72. package/dist/models/interoperable-claims/related-person-claims.d.ts +13 -0
  73. package/dist/models/interoperable-claims/related-person-claims.js +16 -0
  74. package/dist/utils/allergy-intolerance-entry-editor.d.ts +51 -0
  75. package/dist/utils/allergy-intolerance-entry-editor.js +55 -0
  76. package/dist/utils/authority-resolution.d.ts +37 -0
  77. package/dist/utils/authority-resolution.js +112 -0
  78. package/dist/utils/backend-message-manager-mem.d.ts +11 -0
  79. package/dist/utils/backend-message-manager-mem.js +11 -0
  80. package/dist/utils/bundle-didcomm-payload.js +3 -2
  81. package/dist/utils/bundle-document-builder.d.ts +36 -0
  82. package/dist/utils/bundle-document-builder.js +310 -14
  83. package/dist/utils/bundle-editor-core.d.ts +181 -0
  84. package/dist/utils/bundle-editor-core.js +467 -0
  85. package/dist/utils/bundle-editor-helpers.d.ts +53 -0
  86. package/dist/utils/bundle-editor-helpers.js +146 -0
  87. package/dist/utils/bundle-editor-registry.d.ts +6 -0
  88. package/dist/utils/bundle-editor-registry.js +14 -0
  89. package/dist/utils/bundle-editor.d.ts +21 -722
  90. package/dist/utils/bundle-editor.js +21 -1601
  91. package/dist/utils/bundle-entry-editor.d.ts +96 -0
  92. package/dist/utils/bundle-entry-editor.js +305 -0
  93. package/dist/utils/bundle-query.d.ts +1 -0
  94. package/dist/utils/bundle-query.js +12 -3
  95. package/dist/utils/bundle-reader.d.ts +48 -0
  96. package/dist/utils/bundle-reader.js +175 -1
  97. package/dist/utils/care-plan-entry-editor.d.ts +43 -0
  98. package/dist/utils/care-plan-entry-editor.js +47 -0
  99. package/dist/utils/client-assertion.d.ts +38 -0
  100. package/dist/utils/client-assertion.js +113 -0
  101. package/dist/utils/clinical-impression-entry-editor.d.ts +43 -0
  102. package/dist/utils/clinical-impression-entry-editor.js +47 -0
  103. package/dist/utils/clinical-resource-entry-editor.d.ts +123 -0
  104. package/dist/utils/clinical-resource-entry-editor.js +296 -0
  105. package/dist/utils/clinical-resource-view.d.ts +16 -0
  106. package/dist/utils/clinical-resource-view.js +267 -33
  107. package/dist/utils/communication-attached-bundle-session-helpers.js +8 -6
  108. package/dist/utils/communication-attached-bundle-session.d.ts +29 -3
  109. package/dist/utils/communication-attached-bundle-session.js +62 -3
  110. package/dist/utils/communication-consent-access-editor.d.ts +8 -4
  111. package/dist/utils/communication-consent-access-editor.js +8 -4
  112. package/dist/utils/communication-didcomm-payload.d.ts +5 -0
  113. package/dist/utils/communication-didcomm-payload.js +28 -18
  114. package/dist/utils/communication-document-reference.d.ts +23 -0
  115. package/dist/utils/communication-document-reference.js +89 -0
  116. package/dist/utils/communication-editor.d.ts +53 -0
  117. package/dist/utils/communication-editor.js +97 -0
  118. package/dist/utils/condition-entry-editor.d.ts +30 -0
  119. package/dist/utils/condition-entry-editor.js +34 -0
  120. package/dist/utils/consent-claim-helpers.d.ts +4 -0
  121. package/dist/utils/consent-claim-helpers.js +15 -1
  122. package/dist/utils/consent-duplicate-rules.js +1 -1
  123. package/dist/utils/coverage-entry-editor.d.ts +51 -0
  124. package/dist/utils/coverage-entry-editor.js +55 -0
  125. package/dist/utils/device-entry-editor.d.ts +59 -0
  126. package/dist/utils/device-entry-editor.js +63 -0
  127. package/dist/utils/device-use-statement-entry-editor.d.ts +43 -0
  128. package/dist/utils/device-use-statement-entry-editor.js +47 -0
  129. package/dist/utils/diagnostic-report-entry-editor.d.ts +74 -0
  130. package/dist/utils/diagnostic-report-entry-editor.js +136 -0
  131. package/dist/utils/did.d.ts +8 -0
  132. package/dist/utils/did.js +22 -0
  133. package/dist/utils/document-reference-entry-editor.d.ts +62 -0
  134. package/dist/utils/document-reference-entry-editor.js +66 -0
  135. package/dist/utils/employee-entry-editor.d.ts +36 -0
  136. package/dist/utils/employee-entry-editor.js +88 -0
  137. package/dist/utils/employee.d.ts +1 -0
  138. package/dist/utils/employee.js +2 -1
  139. package/dist/utils/encounter-entry-editor.d.ts +51 -0
  140. package/dist/utils/encounter-entry-editor.js +55 -0
  141. package/dist/utils/flag-entry-editor.d.ts +47 -0
  142. package/dist/utils/flag-entry-editor.js +51 -0
  143. package/dist/utils/immunization-entry-editor.d.ts +87 -0
  144. package/dist/utils/immunization-entry-editor.js +169 -0
  145. package/dist/utils/index.d.ts +7 -0
  146. package/dist/utils/index.js +7 -0
  147. package/dist/utils/individual-onboarding-acceptance-credential.d.ts +35 -0
  148. package/dist/utils/individual-onboarding-acceptance-credential.js +55 -0
  149. package/dist/utils/individual-smart.d.ts +59 -0
  150. package/dist/utils/individual-smart.js +135 -0
  151. package/dist/utils/license-list-search.d.ts +5 -0
  152. package/dist/utils/license-list-search.js +9 -0
  153. package/dist/utils/license.d.ts +45 -1
  154. package/dist/utils/license.js +86 -2
  155. package/dist/utils/medication-statement-entry-editor.d.ts +90 -0
  156. package/dist/utils/medication-statement-entry-editor.js +94 -0
  157. package/dist/utils/observation-component-entry-editor.d.ts +57 -0
  158. package/dist/utils/observation-component-entry-editor.js +105 -0
  159. package/dist/utils/observation-entry-editor.d.ts +29 -0
  160. package/dist/utils/observation-entry-editor.js +68 -0
  161. package/dist/utils/procedure-entry-editor.d.ts +71 -0
  162. package/dist/utils/procedure-entry-editor.js +75 -0
  163. package/dist/utils/professional-smart.d.ts +87 -0
  164. package/dist/utils/professional-smart.js +118 -4
  165. package/dist/utils/related-person-list.d.ts +4 -0
  166. package/dist/utils/related-person-list.js +26 -6
  167. package/dist/utils/same-as.d.ts +40 -0
  168. package/dist/utils/same-as.js +72 -0
  169. package/dist/utils/unified-health-id.d.ts +51 -0
  170. package/dist/utils/unified-health-id.js +92 -0
  171. package/dist/utils/vital-sign-day-batch.d.ts +25 -0
  172. package/dist/utils/vital-sign-day-batch.js +115 -0
  173. package/dist/utils/vital-sign-entry-editor.d.ts +61 -0
  174. package/dist/utils/vital-sign-entry-editor.js +152 -0
  175. package/package.json +2 -1
@@ -1,6 +1,10 @@
1
1
  export type ProfessionalEmployeeCredentialInput = Readonly<{
2
2
  actorDid: string;
3
3
  role: string;
4
+ email?: string;
5
+ sameAs?: string | readonly string[];
6
+ telephone?: string;
7
+ credentialMaterial?: string;
4
8
  additionalCredentialSubject?: Record<string, unknown>;
5
9
  additionalCredential?: Record<string, unknown>;
6
10
  }>;
@@ -8,14 +12,97 @@ export type ProfessionalSmartVpPayloadInput = Readonly<{
8
12
  clientId: string;
9
13
  actorDid: string;
10
14
  role: string;
15
+ email?: string;
16
+ sameAs?: string | readonly string[];
17
+ telephone?: string;
18
+ credentialMaterial?: string;
11
19
  verifiableCredential?: string | Record<string, unknown> | ReadonlyArray<string | Record<string, unknown>>;
12
20
  additionalVp?: Record<string, unknown>;
13
21
  additionalPayload?: Record<string, unknown>;
14
22
  }>;
23
+ /**
24
+ * Returns the normalized public continuity aliases for one professional
25
+ * identity VC.
26
+ *
27
+ * The canonical source is:
28
+ * - explicit `sameAs` values when present
29
+ * - otherwise the public employee email
30
+ *
31
+ * When both are present they are merged and deduplicated after normalization.
32
+ *
33
+ * @param input Professional identity source values.
34
+ */
35
+ export declare function getProfessionalIdentitySameAs(input: Readonly<Pick<ProfessionalEmployeeCredentialInput, 'sameAs' | 'email'>>): string[];
36
+ /**
37
+ * Returns the normalized public telephone continuity value for one
38
+ * professional identity VC.
39
+ *
40
+ * Telephone continuity is kept separate from `sameAs` so callers can reuse
41
+ * ICA-compatible hashing without overloading the public alias slot.
42
+ *
43
+ * @param input Professional identity source values.
44
+ */
45
+ export declare function getProfessionalIdentityTelephone(input: Readonly<Pick<ProfessionalEmployeeCredentialInput, 'telephone'>>): string | undefined;
46
+ /**
47
+ * Builds the canonical professional identity VC payload reused by SMART VP
48
+ * token helpers and higher SDK facades.
49
+ *
50
+ * Current projection rules:
51
+ * - `credentialSubject.sameAs` stores one CSV string to preserve compatibility
52
+ * with the current flat/shared claim style
53
+ * - `credentialSubject.telephone` stores the hashed public phone continuity
54
+ * value when present
55
+ * - `credentialSubject.hasCredential.material` carries the public signing/bind
56
+ * material when present
57
+ *
58
+ * @param input Professional identity source values.
59
+ */
60
+ export declare function getProfessionalIdentityVC(input: ProfessionalEmployeeCredentialInput): Record<string, unknown>;
61
+ /**
62
+ * Backwards-compatible alias kept for existing SMART demo callers.
63
+ *
64
+ * @param input Professional identity source values.
65
+ */
15
66
  export declare function buildProfessionalEmployeeCredential(input: ProfessionalEmployeeCredentialInput): Record<string, unknown>;
67
+ /**
68
+ * Builds one SMART/OpenID4VP payload for the current professional identity
69
+ * contract.
70
+ *
71
+ * When no credential is supplied explicitly, the payload embeds the canonical
72
+ * professional identity VC built from the current actor identity input.
73
+ *
74
+ * @param input SMART/OpenID4VP actor payload input.
75
+ */
16
76
  export declare function buildProfessionalSmartVpPayload(input: ProfessionalSmartVpPayloadInput): Record<string, unknown>;
77
+ /**
78
+ * Alias that makes the VC/VP naming more explicit for consumers that want one
79
+ * identity-oriented surface rather than the historical SMART-specific helper
80
+ * names.
81
+ *
82
+ * @param input SMART/OpenID4VP actor payload input.
83
+ */
84
+ export declare function buildProfessionalIdentityVpPayload(input: ProfessionalSmartVpPayloadInput): Record<string, unknown>;
85
+ /**
86
+ * Builds one unsigned compact VP JWT for the canonical professional identity
87
+ * payload.
88
+ *
89
+ * @param input SMART/OpenID4VP actor payload input.
90
+ * @param options Optional unsigned JWT timing controls.
91
+ */
17
92
  export declare function buildUnsignedProfessionalSmartVpJwt(input: ProfessionalSmartVpPayloadInput, options?: Readonly<{
18
93
  nowSeconds?: number;
19
94
  ttlSeconds?: number;
20
95
  nonce?: string;
21
96
  }>): string;
97
+ /**
98
+ * Alias that makes the unsigned identity VP helper explicit for shared SDK
99
+ * facades.
100
+ *
101
+ * @param input SMART/OpenID4VP actor payload input.
102
+ * @param options Optional unsigned JWT timing controls.
103
+ */
104
+ export declare function buildUnsignedProfessionalIdentityVpJwt(input: ProfessionalSmartVpPayloadInput, options?: Readonly<{
105
+ nowSeconds?: number;
106
+ ttlSeconds?: number;
107
+ nonce?: string;
108
+ }>): string;
@@ -1,27 +1,114 @@
1
+ import { ClaimsPersonSchemaorg } from '../constants/schemaorg.js';
1
2
  import { ProfessionalCredentialTypes, W3cCredentialTypes, } from '../constants/verifiable-credentials.js';
3
+ import { normalizeSameAsHashCsv, normalizeSameAsHashList, normalizeTelephoneHash } from './same-as.js';
2
4
  import { buildUnsignedVpJwt } from './jwt.js';
3
- export function buildProfessionalEmployeeCredential(input) {
5
+ /**
6
+ * Returns the normalized public continuity aliases for one professional
7
+ * identity VC.
8
+ *
9
+ * The canonical source is:
10
+ * - explicit `sameAs` values when present
11
+ * - otherwise the public employee email
12
+ *
13
+ * When both are present they are merged and deduplicated after normalization.
14
+ *
15
+ * @param input Professional identity source values.
16
+ */
17
+ export function getProfessionalIdentitySameAs(input) {
18
+ const sameAsCandidates = [];
19
+ if (input.sameAs) {
20
+ sameAsCandidates.push(...normalizeSameAsHashList(input.sameAs));
21
+ }
22
+ if (input.email) {
23
+ sameAsCandidates.push(...normalizeSameAsHashList(input.email));
24
+ }
25
+ return [...new Set(sameAsCandidates)];
26
+ }
27
+ /**
28
+ * Returns the normalized public telephone continuity value for one
29
+ * professional identity VC.
30
+ *
31
+ * Telephone continuity is kept separate from `sameAs` so callers can reuse
32
+ * ICA-compatible hashing without overloading the public alias slot.
33
+ *
34
+ * @param input Professional identity source values.
35
+ */
36
+ export function getProfessionalIdentityTelephone(input) {
37
+ const normalized = normalizeTelephoneHash(String(input.telephone || ''));
38
+ return normalized || undefined;
39
+ }
40
+ /**
41
+ * Builds the canonical professional identity VC payload reused by SMART VP
42
+ * token helpers and higher SDK facades.
43
+ *
44
+ * Current projection rules:
45
+ * - `credentialSubject.sameAs` stores one CSV string to preserve compatibility
46
+ * with the current flat/shared claim style
47
+ * - `credentialSubject.telephone` stores the hashed public phone continuity
48
+ * value when present
49
+ * - `credentialSubject.hasCredential.material` carries the public signing/bind
50
+ * material when present
51
+ *
52
+ * @param input Professional identity source values.
53
+ */
54
+ export function getProfessionalIdentityVC(input) {
55
+ const normalizedSameAs = getProfessionalIdentitySameAs(input);
56
+ const normalizedTelephone = getProfessionalIdentityTelephone(input);
57
+ const normalizedCredentialMaterial = String(input.credentialMaterial || '').trim();
58
+ const canonicalCredentialSubject = {
59
+ id: String(input.actorDid || '').trim(),
60
+ hasOccupation: String(input.role || '').trim(),
61
+ ...(normalizedSameAs.length
62
+ ? { sameAs: normalizeSameAsHashCsv(normalizedSameAs) }
63
+ : {}),
64
+ ...(normalizedTelephone
65
+ ? { [ClaimsPersonSchemaorg.telephone]: normalizedTelephone }
66
+ : {}),
67
+ ...(normalizedCredentialMaterial
68
+ ? { [ClaimsPersonSchemaorg.hasCredentialMaterial]: normalizedCredentialMaterial }
69
+ : {}),
70
+ };
4
71
  return {
5
72
  type: [
6
73
  W3cCredentialTypes.VerifiableCredential,
7
74
  ProfessionalCredentialTypes.EmployeeCredential,
8
75
  ],
9
76
  credentialSubject: {
10
- id: String(input.actorDid || '').trim(),
11
- hasOccupation: String(input.role || '').trim(),
77
+ ...canonicalCredentialSubject,
12
78
  ...(input.additionalCredentialSubject || {}),
13
79
  },
14
80
  ...(input.additionalCredential || {}),
15
81
  };
16
82
  }
83
+ /**
84
+ * Backwards-compatible alias kept for existing SMART demo callers.
85
+ *
86
+ * @param input Professional identity source values.
87
+ */
88
+ export function buildProfessionalEmployeeCredential(input) {
89
+ return getProfessionalIdentityVC(input);
90
+ }
91
+ /**
92
+ * Builds one SMART/OpenID4VP payload for the current professional identity
93
+ * contract.
94
+ *
95
+ * When no credential is supplied explicitly, the payload embeds the canonical
96
+ * professional identity VC built from the current actor identity input.
97
+ *
98
+ * @param input SMART/OpenID4VP actor payload input.
99
+ */
17
100
  export function buildProfessionalSmartVpPayload(input) {
18
101
  const credentials = Array.isArray(input.verifiableCredential)
19
102
  ? [...input.verifiableCredential]
20
103
  : input.verifiableCredential
21
104
  ? [input.verifiableCredential]
22
- : [buildProfessionalEmployeeCredential({
105
+ : [getProfessionalIdentityVC({
23
106
  actorDid: input.actorDid,
24
107
  role: input.role,
108
+ email: input.email,
109
+ sameAs: input.sameAs,
110
+ telephone: input.telephone,
111
+ credentialMaterial: input.credentialMaterial,
25
112
  })];
26
113
  return {
27
114
  ...(input.additionalPayload || {}),
@@ -32,6 +119,33 @@ export function buildProfessionalSmartVpPayload(input) {
32
119
  },
33
120
  };
34
121
  }
122
+ /**
123
+ * Alias that makes the VC/VP naming more explicit for consumers that want one
124
+ * identity-oriented surface rather than the historical SMART-specific helper
125
+ * names.
126
+ *
127
+ * @param input SMART/OpenID4VP actor payload input.
128
+ */
129
+ export function buildProfessionalIdentityVpPayload(input) {
130
+ return buildProfessionalSmartVpPayload(input);
131
+ }
132
+ /**
133
+ * Builds one unsigned compact VP JWT for the canonical professional identity
134
+ * payload.
135
+ *
136
+ * @param input SMART/OpenID4VP actor payload input.
137
+ * @param options Optional unsigned JWT timing controls.
138
+ */
35
139
  export function buildUnsignedProfessionalSmartVpJwt(input, options = {}) {
36
140
  return buildUnsignedVpJwt(buildProfessionalSmartVpPayload(input), options);
37
141
  }
142
+ /**
143
+ * Alias that makes the unsigned identity VP helper explicit for shared SDK
144
+ * facades.
145
+ *
146
+ * @param input SMART/OpenID4VP actor payload input.
147
+ * @param options Optional unsigned JWT timing controls.
148
+ */
149
+ export function buildUnsignedProfessionalIdentityVpJwt(input, options = {}) {
150
+ return buildUnsignedProfessionalSmartVpJwt(input, options);
151
+ }
@@ -2,11 +2,15 @@ export type RelatedPersonListRecord = Readonly<{
2
2
  identifier?: string;
3
3
  patient?: string;
4
4
  relationship?: string;
5
+ /** Functional `RelatedPerson.role` extension values, separate from kinship. */
6
+ roles: readonly string[];
5
7
  name?: string;
6
8
  telecom?: string;
7
9
  active?: string;
8
10
  status?: string;
9
11
  resourceId?: string;
12
+ relatedEntityType?: string;
13
+ actorIdentifiers: readonly string[];
10
14
  claims: Record<string, unknown>;
11
15
  }>;
12
16
  export type RelatedPersonListSelection = Readonly<{
@@ -12,6 +12,17 @@ function extractClaims(entry) {
12
12
  const resourceClaims = resourceMeta.claims && typeof resourceMeta.claims === 'object' ? resourceMeta.claims : undefined;
13
13
  return { ...(resourceClaims || {}), ...(metaClaims || {}) };
14
14
  }
15
+ function readClaim(claims, claimKey) {
16
+ if (claims[claimKey] !== undefined)
17
+ return claims[claimKey];
18
+ const context = normalizeText(claims['@context']);
19
+ if (context && claims[`${context.replace(/\.$/, '')}.${claimKey}`] !== undefined) {
20
+ return claims[`${context.replace(/\.$/, '')}.${claimKey}`];
21
+ }
22
+ const suffix = `.${claimKey}`;
23
+ const matchedKey = Object.keys(claims).find((key) => key.endsWith(suffix));
24
+ return matchedKey ? claims[matchedKey] : undefined;
25
+ }
15
26
  /**
16
27
  * Reads subject-side relationship records from one current GW-style result
17
28
  * body into one neutral list shape for frontend screens.
@@ -29,14 +40,23 @@ export function readRelatedPersonListRecords(body) {
29
40
  const meta = entry.meta && typeof entry.meta === 'object' ? entry.meta : {};
30
41
  const resource = entry.resource && typeof entry.resource === 'object' ? entry.resource : {};
31
42
  return {
32
- identifier: normalizeText(claims[RelatedPersonClaim.IdentifierValue] ?? claims[RelatedPersonClaim.Identifier]),
33
- patient: normalizeText(claims[RelatedPersonClaim.Patient]),
34
- relationship: normalizeText(claims[RelatedPersonClaim.Relationship]),
35
- name: normalizeText(claims[RelatedPersonClaim.Name]),
36
- telecom: normalizeText(claims[RelatedPersonClaim.Telecom]),
37
- active: normalizeText(claims[RelatedPersonClaim.Active]),
43
+ identifier: normalizeText(readClaim(claims, RelatedPersonClaim.IdentifierValue) ?? readClaim(claims, RelatedPersonClaim.Identifier)),
44
+ patient: normalizeText(readClaim(claims, RelatedPersonClaim.Patient)),
45
+ relationship: normalizeText(readClaim(claims, RelatedPersonClaim.Relationship)),
46
+ roles: String(readClaim(claims, RelatedPersonClaim.Role) ?? '')
47
+ .split(',')
48
+ .map((value) => value.trim().toUpperCase())
49
+ .filter(Boolean),
50
+ name: normalizeText(readClaim(claims, RelatedPersonClaim.Name)),
51
+ telecom: normalizeText(readClaim(claims, RelatedPersonClaim.Telecom)),
52
+ active: normalizeText(readClaim(claims, RelatedPersonClaim.Active)),
38
53
  status: normalizeText(meta.status),
39
54
  resourceId: normalizeText(resource.id || entry.id),
55
+ relatedEntityType: normalizeText(readClaim(claims, RelatedPersonClaim.RelatedEntityType)),
56
+ actorIdentifiers: String(readClaim(claims, RelatedPersonClaim.ActorIdentifier) ?? '')
57
+ .split(',')
58
+ .map((value) => value.trim())
59
+ .filter(Boolean),
40
60
  claims,
41
61
  };
42
62
  });
@@ -32,6 +32,46 @@ export declare function multibase58MultihashSha3_256(value: string): string;
32
32
  * @param value Email, phone, DID, URN, or any other public alias string.
33
33
  */
34
34
  export declare function normalizeSameAsHash(value: string): string;
35
+ /**
36
+ * Normalizes one or more `sameAs` aliases into one deduplicated array.
37
+ *
38
+ * Input forms:
39
+ * - one plain string
40
+ * - one CSV string
41
+ * - one array of plain/CSV strings
42
+ *
43
+ * Normalization rules:
44
+ * - whitespace-only entries are discarded
45
+ * - emails are hashed into ICA-compatible `urn:multibase:z...`
46
+ * - already-normalized `urn:multibase:z...` values are preserved
47
+ * - duplicate normalized entries are removed while preserving order
48
+ *
49
+ * @param value Canonical sameAs source value(s).
50
+ */
51
+ export declare function normalizeSameAsHashList(value: string | readonly string[] | undefined): string[];
52
+ /**
53
+ * Joins one or more normalized `sameAs` aliases into the current flat CSV
54
+ * storage form used by some shared VC/profile helpers.
55
+ *
56
+ * @param value Canonical sameAs source value(s).
57
+ */
58
+ export declare function normalizeSameAsHashCsv(value: string | readonly string[] | undefined): string;
59
+ /**
60
+ * Normalizes one public telephone alias into the same hashed
61
+ * `urn:multibase:z...` representation used for ICA-compatible public
62
+ * continuity identifiers, while keeping the telephone claim separate from
63
+ * `sameAs`.
64
+ *
65
+ * Rules:
66
+ * - empty input becomes `''`
67
+ * - `urn:multibase:z...` stays unchanged
68
+ * - bare `z...` becomes `urn:multibase:z...`
69
+ * - plain phone-like values are compacted through `normalizePhone(...)`
70
+ * before hashing
71
+ *
72
+ * @param value Plain or already-normalized public telephone alias.
73
+ */
74
+ export declare function normalizeTelephoneHash(value: string): string;
35
75
  /**
36
76
  * Compares two public controller aliases after ICA-compatible normalization.
37
77
  *
@@ -1,4 +1,5 @@
1
1
  import { createHash } from 'crypto';
2
+ import { normalizePhone } from './consent.js';
2
3
  import { encodeMultibase58btc } from './multibase58.js';
3
4
  /**
4
5
  * Builds the ICA-compatible multibase58(multihash(sha3-256)) payload for a
@@ -28,6 +29,12 @@ function looksLikeEmail(value) {
28
29
  const trimmed = value.trim();
29
30
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed);
30
31
  }
32
+ function splitCommaSeparatedValues(value) {
33
+ return String(value || '')
34
+ .split(',')
35
+ .map((candidate) => candidate.trim())
36
+ .filter(Boolean);
37
+ }
31
38
  /**
32
39
  * Normalizes a public controller alias into the same representation used by
33
40
  * ICA for `credentialSubject.sameAs` and `controller.sameAs`.
@@ -64,6 +71,71 @@ export function normalizeSameAsHash(value) {
64
71
  }
65
72
  return trimmed;
66
73
  }
74
+ /**
75
+ * Normalizes one or more `sameAs` aliases into one deduplicated array.
76
+ *
77
+ * Input forms:
78
+ * - one plain string
79
+ * - one CSV string
80
+ * - one array of plain/CSV strings
81
+ *
82
+ * Normalization rules:
83
+ * - whitespace-only entries are discarded
84
+ * - emails are hashed into ICA-compatible `urn:multibase:z...`
85
+ * - already-normalized `urn:multibase:z...` values are preserved
86
+ * - duplicate normalized entries are removed while preserving order
87
+ *
88
+ * @param value Canonical sameAs source value(s).
89
+ */
90
+ export function normalizeSameAsHashList(value) {
91
+ const candidates = Array.isArray(value)
92
+ ? value.flatMap((entry) => splitCommaSeparatedValues(entry))
93
+ : splitCommaSeparatedValues(String(value || ''));
94
+ const normalized = candidates
95
+ .map((candidate) => normalizeSameAsHash(candidate))
96
+ .filter(Boolean);
97
+ return [...new Set(normalized)];
98
+ }
99
+ /**
100
+ * Joins one or more normalized `sameAs` aliases into the current flat CSV
101
+ * storage form used by some shared VC/profile helpers.
102
+ *
103
+ * @param value Canonical sameAs source value(s).
104
+ */
105
+ export function normalizeSameAsHashCsv(value) {
106
+ return normalizeSameAsHashList(value).join(',');
107
+ }
108
+ /**
109
+ * Normalizes one public telephone alias into the same hashed
110
+ * `urn:multibase:z...` representation used for ICA-compatible public
111
+ * continuity identifiers, while keeping the telephone claim separate from
112
+ * `sameAs`.
113
+ *
114
+ * Rules:
115
+ * - empty input becomes `''`
116
+ * - `urn:multibase:z...` stays unchanged
117
+ * - bare `z...` becomes `urn:multibase:z...`
118
+ * - plain phone-like values are compacted through `normalizePhone(...)`
119
+ * before hashing
120
+ *
121
+ * @param value Plain or already-normalized public telephone alias.
122
+ */
123
+ export function normalizeTelephoneHash(value) {
124
+ const trimmed = String(value || '').trim();
125
+ if (!trimmed)
126
+ return '';
127
+ if (trimmed.toLowerCase().startsWith('urn:multibase:')) {
128
+ const suffix = trimmed.slice('urn:multibase:'.length).trim();
129
+ return looksLikeBase58Multibase(suffix) ? `urn:multibase:${suffix}` : trimmed;
130
+ }
131
+ if (looksLikeBase58Multibase(trimmed)) {
132
+ return `urn:multibase:${trimmed}`;
133
+ }
134
+ const normalizedPhone = normalizePhone(trimmed);
135
+ if (!normalizedPhone)
136
+ return '';
137
+ return `urn:multibase:${multibase58MultihashSha3_256(normalizedPhone)}`;
138
+ }
67
139
  /**
68
140
  * Compares two public controller aliases after ICA-compatible normalization.
69
141
  *
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Computes the Damm check digit for one decimal payload.
3
+ *
4
+ * Canonical input:
5
+ * - decimal digits only
6
+ *
7
+ * Algorithm:
8
+ * - Damm check digit over the full normalized sequence
9
+ *
10
+ * Compatibility:
11
+ * - this helper is intentionally strict about the normalized payload so the
12
+ * same digits always produce the same digit, regardless of presentation
13
+ */
14
+ export declare function computeDammCheckDigit(payloadDigits: string): string;
15
+ /**
16
+ * Computes the provider-scoped Unified Health ID control digit.
17
+ *
18
+ * Canonical input:
19
+ * - `providerId` normalized to digits only
20
+ * - `personalIdWithoutCheckDigit` normalized to digits only
21
+ * - the check digit is computed over `providerId + personalIdWithoutCheckDigit`
22
+ *
23
+ * Algorithm:
24
+ * - Damm check digit over the concatenated normalized digits
25
+ *
26
+ * Compatibility:
27
+ * - separators such as `:` and `-` are ignored
28
+ * - the same personal payload can produce a different digit in another
29
+ * provider because the provider digits are part of the normalized sequence
30
+ *
31
+ * @param providerId Provider-scoped numeric identifier. Presentation separators are ignored.
32
+ * @param personalIdWithoutCheckDigit Personal identifier payload without its final control digit.
33
+ * @returns One decimal check digit as a string.
34
+ */
35
+ export declare function computeUnifiedHealthIdCheckDigit(providerId: string, personalIdWithoutCheckDigit: string): string;
36
+ /**
37
+ * Builds the provider-scoped Unified Health ID personal digits including the
38
+ * final control digit.
39
+ *
40
+ * Canonical input:
41
+ * - `providerId` normalized to digits only
42
+ * - `personalIdWithoutCheckDigit` normalized to digits only
43
+ *
44
+ * Output:
45
+ * - the normalized personal digits followed by the computed control digit
46
+ *
47
+ * @param providerId Provider-scoped numeric identifier. Presentation separators are ignored.
48
+ * @param personalIdWithoutCheckDigit Personal identifier payload without its final control digit.
49
+ * @returns The normalized personal digits plus the final control digit.
50
+ */
51
+ export declare function buildUnifiedHealthIdPersonalDigits(providerId: string, personalIdWithoutCheckDigit: string): string;
@@ -0,0 +1,92 @@
1
+ // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ /**
3
+ * Computes the Damm check digit for one decimal payload.
4
+ *
5
+ * Canonical input:
6
+ * - decimal digits only
7
+ *
8
+ * Algorithm:
9
+ * - Damm check digit over the full normalized sequence
10
+ *
11
+ * Compatibility:
12
+ * - this helper is intentionally strict about the normalized payload so the
13
+ * same digits always produce the same digit, regardless of presentation
14
+ */
15
+ export function computeDammCheckDigit(payloadDigits) {
16
+ const normalized = normalizeDigitsOnly(payloadDigits, 'payloadDigits');
17
+ const table = [
18
+ [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
19
+ [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
20
+ [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
21
+ [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
22
+ [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
23
+ [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
24
+ [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
25
+ [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
26
+ [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
27
+ [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
28
+ ];
29
+ let interim = 0;
30
+ for (const digit of normalized) {
31
+ interim = table[interim][Number(digit)];
32
+ }
33
+ return String(interim);
34
+ }
35
+ /**
36
+ * Computes the provider-scoped Unified Health ID control digit.
37
+ *
38
+ * Canonical input:
39
+ * - `providerId` normalized to digits only
40
+ * - `personalIdWithoutCheckDigit` normalized to digits only
41
+ * - the check digit is computed over `providerId + personalIdWithoutCheckDigit`
42
+ *
43
+ * Algorithm:
44
+ * - Damm check digit over the concatenated normalized digits
45
+ *
46
+ * Compatibility:
47
+ * - separators such as `:` and `-` are ignored
48
+ * - the same personal payload can produce a different digit in another
49
+ * provider because the provider digits are part of the normalized sequence
50
+ *
51
+ * @param providerId Provider-scoped numeric identifier. Presentation separators are ignored.
52
+ * @param personalIdWithoutCheckDigit Personal identifier payload without its final control digit.
53
+ * @returns One decimal check digit as a string.
54
+ */
55
+ export function computeUnifiedHealthIdCheckDigit(providerId, personalIdWithoutCheckDigit) {
56
+ const normalizedProviderId = normalizeDigitsOnly(providerId, 'providerId');
57
+ const normalizedPersonalId = normalizeDigitsOnly(personalIdWithoutCheckDigit, 'personalIdWithoutCheckDigit');
58
+ return computeDammCheckDigit(`${normalizedProviderId}${normalizedPersonalId}`);
59
+ }
60
+ /**
61
+ * Builds the provider-scoped Unified Health ID personal digits including the
62
+ * final control digit.
63
+ *
64
+ * Canonical input:
65
+ * - `providerId` normalized to digits only
66
+ * - `personalIdWithoutCheckDigit` normalized to digits only
67
+ *
68
+ * Output:
69
+ * - the normalized personal digits followed by the computed control digit
70
+ *
71
+ * @param providerId Provider-scoped numeric identifier. Presentation separators are ignored.
72
+ * @param personalIdWithoutCheckDigit Personal identifier payload without its final control digit.
73
+ * @returns The normalized personal digits plus the final control digit.
74
+ */
75
+ export function buildUnifiedHealthIdPersonalDigits(providerId, personalIdWithoutCheckDigit) {
76
+ const normalizedPersonalId = normalizeDigitsOnly(personalIdWithoutCheckDigit, 'personalIdWithoutCheckDigit');
77
+ return `${normalizedPersonalId}${computeUnifiedHealthIdCheckDigit(providerId, normalizedPersonalId)}`;
78
+ }
79
+ function normalizeDigitsOnly(value, name) {
80
+ const normalized = String(value || '').trim();
81
+ if (!normalized) {
82
+ throw new Error(`${name} must not be empty`);
83
+ }
84
+ if (!/^[0-9:\-\s]+$/.test(normalized)) {
85
+ throw new Error(`${name} must contain only digits, spaces, colons, or hyphens`);
86
+ }
87
+ const digits = normalized.replace(/\D/g, '');
88
+ if (!digits) {
89
+ throw new Error(`${name} must contain at least one digit`);
90
+ }
91
+ return digits;
92
+ }
@@ -0,0 +1,25 @@
1
+ import type { BundleEntry, BundleJsonApi } from '../models/bundle';
2
+ export declare const VitalSignDayBatchClaim: Readonly<{
3
+ readonly Identifier: "VitalSignDayBatch.identifier";
4
+ readonly Subject: "VitalSignDayBatch.subject";
5
+ readonly Actor: "VitalSignDayBatch.actor";
6
+ readonly Day: "VitalSignDayBatch.day";
7
+ readonly CreatedAtTimestamp: "VitalSignDayBatch.createdAtTimestamp";
8
+ }>;
9
+ export type VitalSignDayBatchEntryInput = Readonly<{
10
+ subject: string;
11
+ actor: string;
12
+ date: string | Date;
13
+ createdAtTimestamp?: number;
14
+ entry?: BundleEntry;
15
+ bundle?: BundleJsonApi<BundleEntry>;
16
+ }>;
17
+ export type VitalSignDayBatchResult = Readonly<{
18
+ batchId: string;
19
+ day: string;
20
+ reused: boolean;
21
+ bundle: BundleJsonApi<BundleEntry>;
22
+ }>;
23
+ export declare function buildVitalSignDayBatchClaims(input: Pick<VitalSignDayBatchEntryInput, 'subject' | 'actor' | 'date' | 'createdAtTimestamp'>): Record<string, unknown>;
24
+ export declare function resolveVitalSignDayBatchId(input: VitalSignDayBatchEntryInput): VitalSignDayBatchResult;
25
+ export declare function openOrCreateVitalSignDayBatchBundle(input: VitalSignDayBatchEntryInput): BundleJsonApi<BundleEntry>;