gdc-common-utils-ts 2.0.18 → 2.2.2

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 (185) hide show
  1. package/README.md +18 -1
  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/didcomm.d.ts +22 -0
  13. package/dist/constants/didcomm.js +22 -0
  14. package/dist/constants/fhir-resource-types.d.ts +2 -0
  15. package/dist/constants/fhir-resource-types.js +1 -0
  16. package/dist/constants/index.d.ts +1 -0
  17. package/dist/constants/index.js +1 -0
  18. package/dist/constants/lifecycle.d.ts +2 -0
  19. package/dist/constants/lifecycle.js +2 -0
  20. package/dist/constants/verifiable-credentials.d.ts +9 -0
  21. package/dist/constants/verifiable-credentials.js +9 -0
  22. package/dist/examples/bundle-didcomm-payload.d.ts +11 -0
  23. package/dist/examples/bundle-didcomm-payload.js +15 -0
  24. package/dist/examples/communication-attached-bundle-session.js +28 -27
  25. package/dist/examples/communication-didcomm-payload.d.ts +39 -0
  26. package/dist/examples/communication-didcomm-payload.js +44 -0
  27. package/dist/examples/consent-access.js +2 -1
  28. package/dist/examples/employee.d.ts +21 -0
  29. package/dist/examples/employee.js +21 -0
  30. package/dist/examples/index.d.ts +4 -0
  31. package/dist/examples/index.js +4 -0
  32. package/dist/examples/individual-controller.d.ts +27 -0
  33. package/dist/examples/individual-controller.js +28 -1
  34. package/dist/examples/inter-tenant-access-contract.js +3 -2
  35. package/dist/examples/ips-bundle.js +17 -16
  36. package/dist/examples/lifecycle.js +13 -11
  37. package/dist/examples/profile-manager-mem.d.ts +45 -0
  38. package/dist/examples/profile-manager-mem.js +30 -0
  39. package/dist/examples/related-person.d.ts +14 -0
  40. package/dist/examples/related-person.js +18 -4
  41. package/dist/examples/shared.d.ts +13 -3
  42. package/dist/examples/shared.js +14 -4
  43. package/dist/examples/vital-signs.js +1 -1
  44. package/dist/examples/wallet-mem.d.ts +38 -0
  45. package/dist/examples/wallet-mem.js +42 -0
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.js +1 -0
  48. package/dist/interfaces/IProfileOutboxRepository.d.ts +36 -0
  49. package/dist/interfaces/IProfileOutboxRepository.js +2 -0
  50. package/dist/interfaces/IWallet.d.ts +74 -0
  51. package/dist/interfaces/IWallet.js +2 -0
  52. package/dist/interfaces/IWalletQueue.d.ts +30 -0
  53. package/dist/interfaces/IWalletQueue.js +2 -0
  54. package/dist/interfaces/index.d.ts +8 -0
  55. package/dist/interfaces/index.js +8 -0
  56. package/dist/models/authority-resolution.d.ts +56 -0
  57. package/dist/models/authority-resolution.js +2 -0
  58. package/dist/models/bundle-editor-types.d.ts +89 -0
  59. package/dist/models/bundle-editor-types.js +45 -0
  60. package/dist/models/bundle.d.ts +5 -0
  61. package/dist/models/communication-attached-bundle-session.d.ts +195 -0
  62. package/dist/models/communication-attached-bundle-session.js +36 -0
  63. package/dist/models/confidential-storage.d.ts +2 -1
  64. package/dist/models/consent-rule.d.ts +11 -1
  65. package/dist/models/consent-rule.js +9 -1
  66. package/dist/models/index.d.ts +5 -0
  67. package/dist/models/index.js +5 -0
  68. package/dist/models/individual-onboarding.d.ts +18 -0
  69. package/dist/models/interoperable-claims/allergy-intolerance-claims.d.ts +12 -1
  70. package/dist/models/interoperable-claims/allergy-intolerance-claims.js +12 -1
  71. package/dist/models/interoperable-claims/condition-claims.d.ts +12 -1
  72. package/dist/models/interoperable-claims/condition-claims.js +12 -1
  73. package/dist/models/interoperable-claims/diagnostic-report-claims.d.ts +14 -4
  74. package/dist/models/interoperable-claims/diagnostic-report-claims.js +13 -3
  75. package/dist/models/interoperable-claims/document-reference-claims.d.ts +1 -0
  76. package/dist/models/interoperable-claims/document-reference-claims.js +3 -0
  77. package/dist/models/interoperable-claims/medication-statement-claims.d.ts +17 -0
  78. package/dist/models/interoperable-claims/medication-statement-claims.js +17 -0
  79. package/dist/models/profile-manager.d.ts +85 -0
  80. package/dist/models/profile-manager.js +2 -0
  81. package/dist/models/wallet.d.ts +59 -0
  82. package/dist/models/wallet.js +22 -0
  83. package/dist/utils/allergy-intolerance-entry-editor.d.ts +51 -0
  84. package/dist/utils/allergy-intolerance-entry-editor.js +55 -0
  85. package/dist/utils/authority-resolution.d.ts +37 -0
  86. package/dist/utils/authority-resolution.js +112 -0
  87. package/dist/utils/backend-message-manager-mem.d.ts +78 -0
  88. package/dist/utils/backend-message-manager-mem.js +238 -0
  89. package/dist/utils/bundle-didcomm-payload.d.ts +29 -0
  90. package/dist/utils/bundle-didcomm-payload.js +49 -0
  91. package/dist/utils/bundle-document-builder.d.ts +1 -0
  92. package/dist/utils/bundle-document-builder.js +134 -14
  93. package/dist/utils/bundle-editor-core.d.ts +181 -0
  94. package/dist/utils/bundle-editor-core.js +467 -0
  95. package/dist/utils/bundle-editor-helpers.d.ts +53 -0
  96. package/dist/utils/bundle-editor-helpers.js +146 -0
  97. package/dist/utils/bundle-editor-registry.d.ts +6 -0
  98. package/dist/utils/bundle-editor-registry.js +14 -0
  99. package/dist/utils/bundle-editor.d.ts +21 -722
  100. package/dist/utils/bundle-editor.js +21 -1601
  101. package/dist/utils/bundle-entry-editor.d.ts +96 -0
  102. package/dist/utils/bundle-entry-editor.js +305 -0
  103. package/dist/utils/bundle-query.d.ts +1 -0
  104. package/dist/utils/bundle-query.js +12 -3
  105. package/dist/utils/bundle-reader.d.ts +48 -0
  106. package/dist/utils/bundle-reader.js +175 -1
  107. package/dist/utils/care-plan-entry-editor.d.ts +43 -0
  108. package/dist/utils/care-plan-entry-editor.js +47 -0
  109. package/dist/utils/client-assertion.d.ts +38 -0
  110. package/dist/utils/client-assertion.js +113 -0
  111. package/dist/utils/clinical-impression-entry-editor.d.ts +43 -0
  112. package/dist/utils/clinical-impression-entry-editor.js +47 -0
  113. package/dist/utils/clinical-resource-entry-editor.d.ts +123 -0
  114. package/dist/utils/clinical-resource-entry-editor.js +296 -0
  115. package/dist/utils/communication-attached-bundle-session-helpers.d.ts +54 -0
  116. package/dist/utils/communication-attached-bundle-session-helpers.js +519 -0
  117. package/dist/utils/communication-attached-bundle-session.d.ts +87 -304
  118. package/dist/utils/communication-attached-bundle-session.js +175 -841
  119. package/dist/utils/communication-consent-access-editor.d.ts +85 -0
  120. package/dist/utils/communication-consent-access-editor.js +244 -0
  121. package/dist/utils/communication-didcomm-payload.d.ts +38 -0
  122. package/dist/utils/communication-didcomm-payload.js +85 -0
  123. package/dist/utils/communication-document-reference.d.ts +23 -0
  124. package/dist/utils/communication-document-reference.js +89 -0
  125. package/dist/utils/communication-editor.d.ts +53 -0
  126. package/dist/utils/communication-editor.js +97 -0
  127. package/dist/utils/condition-entry-editor.d.ts +30 -0
  128. package/dist/utils/condition-entry-editor.js +34 -0
  129. package/dist/utils/consent-claim-helpers.d.ts +4 -0
  130. package/dist/utils/consent-claim-helpers.js +15 -1
  131. package/dist/utils/coverage-entry-editor.d.ts +51 -0
  132. package/dist/utils/coverage-entry-editor.js +55 -0
  133. package/dist/utils/device-entry-editor.d.ts +59 -0
  134. package/dist/utils/device-entry-editor.js +63 -0
  135. package/dist/utils/device-use-statement-entry-editor.d.ts +43 -0
  136. package/dist/utils/device-use-statement-entry-editor.js +47 -0
  137. package/dist/utils/diagnostic-report-entry-editor.d.ts +74 -0
  138. package/dist/utils/diagnostic-report-entry-editor.js +136 -0
  139. package/dist/utils/did.d.ts +8 -0
  140. package/dist/utils/did.js +22 -0
  141. package/dist/utils/document-reference-entry-editor.d.ts +62 -0
  142. package/dist/utils/document-reference-entry-editor.js +66 -0
  143. package/dist/utils/employee-entry-editor.d.ts +36 -0
  144. package/dist/utils/employee-entry-editor.js +88 -0
  145. package/dist/utils/employee.d.ts +1 -0
  146. package/dist/utils/employee.js +2 -1
  147. package/dist/utils/encounter-entry-editor.d.ts +51 -0
  148. package/dist/utils/encounter-entry-editor.js +55 -0
  149. package/dist/utils/flag-entry-editor.d.ts +47 -0
  150. package/dist/utils/flag-entry-editor.js +51 -0
  151. package/dist/utils/immunization-entry-editor.d.ts +87 -0
  152. package/dist/utils/immunization-entry-editor.js +169 -0
  153. package/dist/utils/index.d.ts +15 -0
  154. package/dist/utils/index.js +15 -0
  155. package/dist/utils/individual-onboarding-acceptance-credential.d.ts +35 -0
  156. package/dist/utils/individual-onboarding-acceptance-credential.js +55 -0
  157. package/dist/utils/individual-smart.d.ts +59 -0
  158. package/dist/utils/individual-smart.js +135 -0
  159. package/dist/utils/medication-statement-entry-editor.d.ts +90 -0
  160. package/dist/utils/medication-statement-entry-editor.js +94 -0
  161. package/dist/utils/observation-component-entry-editor.d.ts +57 -0
  162. package/dist/utils/observation-component-entry-editor.js +105 -0
  163. package/dist/utils/observation-entry-editor.d.ts +29 -0
  164. package/dist/utils/observation-entry-editor.js +68 -0
  165. package/dist/utils/procedure-entry-editor.d.ts +71 -0
  166. package/dist/utils/procedure-entry-editor.js +75 -0
  167. package/dist/utils/professional-smart.d.ts +87 -0
  168. package/dist/utils/professional-smart.js +118 -4
  169. package/dist/utils/profile-manager-mem.d.ts +69 -0
  170. package/dist/utils/profile-manager-mem.js +79 -0
  171. package/dist/utils/profile-outbox-memory-repository.d.ts +34 -0
  172. package/dist/utils/profile-outbox-memory-repository.js +57 -0
  173. package/dist/utils/same-as.d.ts +40 -0
  174. package/dist/utils/same-as.js +72 -0
  175. package/dist/utils/unified-health-id.d.ts +51 -0
  176. package/dist/utils/unified-health-id.js +92 -0
  177. package/dist/utils/vital-sign-day-batch.d.ts +25 -0
  178. package/dist/utils/vital-sign-day-batch.js +115 -0
  179. package/dist/utils/vital-sign-entry-editor.d.ts +61 -0
  180. package/dist/utils/vital-sign-entry-editor.js +152 -0
  181. package/dist/utils/wallet-mem.d.ts +93 -0
  182. package/dist/utils/wallet-mem.js +277 -0
  183. package/dist/utils/wallet-memory-queue.d.ts +32 -0
  184. package/dist/utils/wallet-memory-queue.js +82 -0
  185. package/package.json +2 -1
@@ -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>;
@@ -0,0 +1,115 @@
1
+ // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ import { createCanonicalIdentifierUrn } from './bundle-editor-helpers.js';
3
+ import { BundleQuery } from './bundle-query.js';
4
+ export const VitalSignDayBatchClaim = Object.freeze({
5
+ Identifier: 'VitalSignDayBatch.identifier',
6
+ Subject: 'VitalSignDayBatch.subject',
7
+ Actor: 'VitalSignDayBatch.actor',
8
+ Day: 'VitalSignDayBatch.day',
9
+ CreatedAtTimestamp: 'VitalSignDayBatch.createdAtTimestamp',
10
+ });
11
+ export function buildVitalSignDayBatchClaims(input) {
12
+ const day = resolveDayKey(input.date);
13
+ const claims = {
14
+ [VitalSignDayBatchClaim.Subject]: asTrimmedString(input.subject),
15
+ [VitalSignDayBatchClaim.Actor]: asTrimmedString(input.actor),
16
+ [VitalSignDayBatchClaim.Day]: day,
17
+ };
18
+ if (typeof input.createdAtTimestamp === 'number' && Number.isFinite(input.createdAtTimestamp)) {
19
+ claims[VitalSignDayBatchClaim.CreatedAtTimestamp] = input.createdAtTimestamp;
20
+ }
21
+ return claims;
22
+ }
23
+ export function resolveVitalSignDayBatchId(input) {
24
+ const baseBundle = cloneBundle(input.bundle || createEmptyBundle());
25
+ const day = resolveDayKey(input.date);
26
+ const dayRange = resolveDayRange(day);
27
+ const existingClaims = asRecord(baseBundle.meta?.claims);
28
+ const query = new BundleQuery(baseBundle);
29
+ const dayEntryIds = query.getResourceIds({ dateFrom: dayRange.from, dateTo: dayRange.to });
30
+ const dayEntries = query.getResourceEntriesByIds(dayEntryIds);
31
+ const matchingDayEntry = dayEntries.find((entry) => matchesBatchOwner(entry, input.subject, input.actor));
32
+ const sameOwner = matchesBatchOwnerClaims(existingClaims, input.subject, input.actor);
33
+ const sameDay = asTrimmedString(existingClaims[VitalSignDayBatchClaim.Day]) === day;
34
+ const existingBatchId = asTrimmedString(baseBundle.id || existingClaims[VitalSignDayBatchClaim.Identifier]);
35
+ const reused = Boolean(existingBatchId && sameOwner && sameDay && (dayEntryIds.length > 0 || matchingDayEntry));
36
+ const batchId = reused ? existingBatchId : createCanonicalIdentifierUrn();
37
+ const bundle = {
38
+ ...baseBundle,
39
+ id: batchId,
40
+ meta: {
41
+ ...(baseBundle.meta || {}),
42
+ claims: {
43
+ ...existingClaims,
44
+ ...buildVitalSignDayBatchClaims(input),
45
+ [VitalSignDayBatchClaim.Identifier]: batchId,
46
+ },
47
+ },
48
+ data: [...(baseBundle.data || [])],
49
+ };
50
+ if (input.entry) {
51
+ bundle.data.push(cloneEntry(input.entry));
52
+ }
53
+ return {
54
+ batchId,
55
+ day,
56
+ reused,
57
+ bundle,
58
+ };
59
+ }
60
+ export function openOrCreateVitalSignDayBatchBundle(input) {
61
+ return resolveVitalSignDayBatchId(input).bundle;
62
+ }
63
+ function matchesBatchOwner(entry, subject, actor) {
64
+ const claims = asRecord(entry.resource?.meta?.claims || entry.meta?.claims);
65
+ return matchesBatchOwnerClaims(claims, subject, actor);
66
+ }
67
+ function matchesBatchOwnerClaims(claims, subject, actor) {
68
+ return asTrimmedString(claims[VitalSignDayBatchClaim.Subject]) === asTrimmedString(subject)
69
+ && asTrimmedString(claims[VitalSignDayBatchClaim.Actor]) === asTrimmedString(actor);
70
+ }
71
+ function resolveDayKey(value) {
72
+ if (value instanceof Date) {
73
+ return value.toISOString().slice(0, 10);
74
+ }
75
+ const raw = asTrimmedString(value);
76
+ if (!raw) {
77
+ return new Date().toISOString().slice(0, 10);
78
+ }
79
+ const parsed = Date.parse(raw);
80
+ if (Number.isNaN(parsed)) {
81
+ return raw.slice(0, 10);
82
+ }
83
+ return new Date(parsed).toISOString().slice(0, 10);
84
+ }
85
+ function resolveDayRange(day) {
86
+ return {
87
+ from: `${day}T00:00:00.000Z`,
88
+ to: `${day}T23:59:59.999Z`,
89
+ };
90
+ }
91
+ function asTrimmedString(value) {
92
+ if (value === undefined || value === null) {
93
+ return '';
94
+ }
95
+ return String(value).trim();
96
+ }
97
+ function asRecord(value) {
98
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
99
+ return {};
100
+ }
101
+ return value;
102
+ }
103
+ function cloneBundle(bundle) {
104
+ return JSON.parse(JSON.stringify(bundle));
105
+ }
106
+ function cloneEntry(entry) {
107
+ return JSON.parse(JSON.stringify(entry));
108
+ }
109
+ function createEmptyBundle() {
110
+ return {
111
+ resourceType: 'Bundle',
112
+ type: 'collection',
113
+ data: [],
114
+ };
115
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * File discipline note:
3
+ * - Read `ARCHITECTURE.md` and `CONTRIBUTING.md` before changing this module.
4
+ * - Keep exactly one exported class per file.
5
+ * - Keep this file focused on one typed editor surface.
6
+ * - Move shared helpers to reusable helper/base modules instead of duplicating logic here.
7
+ */
8
+ import { type CodingDescriptor } from '../constants/vital-signs';
9
+ import { ObservationComponentEntryEditor } from './observation-component-entry-editor';
10
+ /**
11
+ * Typed editor for one staged VitalSign resource entry.
12
+ *
13
+ * Use this surface when the frontend needs a simple authoring path for common
14
+ * measurements such as heart rate, temperature, or blood pressure.
15
+ */
16
+ export declare class VitalSignEntryEditor extends ObservationComponentEntryEditor {
17
+ /** Overrides the canonical identifier when import or migration logic needs one explicit public id. */
18
+ setIdentifier(identifier?: string | null): this;
19
+ /** Returns the canonical identifier currently exposed for this vital-sign entry. */
20
+ getIdentifier(): string | undefined;
21
+ /** Ensures the entry has one synchronized canonical identifier across public claim, `resource.id`, and `fullUrl`. */
22
+ ensureIdentifier(): string;
23
+ /** Sets the subject/patient reference for this vital-sign observation. */
24
+ setSubject(subject: string): this;
25
+ /** Returns the subject/patient reference for this vital-sign observation. */
26
+ getSubject(): string | undefined;
27
+ /** Sets the observation status. */
28
+ setStatus(status: string): this;
29
+ /** Returns the observation status. */
30
+ getStatus(): string | undefined;
31
+ /** Sets the observation category, usually one of the shared vital-sign category descriptors. */
32
+ setCategory(category: CodingDescriptor | string): this;
33
+ /** Returns the observation category token. */
34
+ getCategory(): string | undefined;
35
+ /** Sets the observation date/effective time. */
36
+ setDate(date: string): this;
37
+ /** Returns the observation date/effective time. */
38
+ getDate(): string | undefined;
39
+ /** Sets one free-text note for the vital sign. */
40
+ setNote(note: string): this;
41
+ /** Returns the free-text note for the vital sign. */
42
+ getNote(): string | undefined;
43
+ /** Seeds the observation code and optional quantity unit for the selected vital-sign family. */
44
+ setVitalSignType(code: CodingDescriptor, unit?: CodingDescriptor): this;
45
+ /** Convenience helper for heart-rate authoring using the shared code/unit catalog. */
46
+ setHeartRate(value: number): this;
47
+ /** Returns the heart-rate numeric value. */
48
+ getHeartRate(): number | undefined;
49
+ /** Convenience helper for body-temperature authoring using the shared code/unit catalog. */
50
+ setBodyTemperature(value: number): this;
51
+ /** Returns the body-temperature numeric value. */
52
+ getBodyTemperature(): number | undefined;
53
+ /** Convenience helper for systolic blood-pressure authoring. */
54
+ setSystolicBloodPressure(value: number): this;
55
+ /** Returns the systolic blood-pressure numeric value. */
56
+ getSystolicBloodPressure(): number | undefined;
57
+ /** Convenience helper for diastolic blood-pressure authoring. */
58
+ setDiastolicBloodPressure(value: number): this;
59
+ /** Returns the diastolic blood-pressure numeric value. */
60
+ getDiastolicBloodPressure(): number | undefined;
61
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * File discipline note:
3
+ * - Read `ARCHITECTURE.md` and `CONTRIBUTING.md` before changing this module.
4
+ * - Keep exactly one exported class per file.
5
+ * - Keep this file focused on one typed editor surface.
6
+ * - Move shared helpers to reusable helper/base modules instead of duplicating logic here.
7
+ */
8
+ import { ObservationCategoryCodes, VitalSignsCodes, VitalSignsUnits } from '../constants/vital-signs.js';
9
+ import { ObservationClaim } from '../models/interoperable-claims/observation-claims.js';
10
+ import { BundleEditableResourceTypes } from '../models/bundle-editor-types.js';
11
+ import { createCanonicalIdentifierUrn, normalizeOptionalIdentifier } from './bundle-editor-helpers.js';
12
+ import { ObservationComponentEntryEditor } from './observation-component-entry-editor.js';
13
+ import { registerBundleEntryEditor } from './bundle-editor-registry.js';
14
+ /**
15
+ * Typed editor for one staged VitalSign resource entry.
16
+ *
17
+ * Use this surface when the frontend needs a simple authoring path for common
18
+ * measurements such as heart rate, temperature, or blood pressure.
19
+ */
20
+ export class VitalSignEntryEditor extends ObservationComponentEntryEditor {
21
+ /** Overrides the canonical identifier when import or migration logic needs one explicit public id. */
22
+ setIdentifier(identifier) {
23
+ const normalized = normalizeOptionalIdentifier(identifier);
24
+ if (!normalized) {
25
+ this.removeClaim(ObservationClaim.Identifier);
26
+ this.setResourceId(undefined);
27
+ this.setFullUrl(undefined);
28
+ return this;
29
+ }
30
+ this.setClaim(ObservationClaim.Identifier, normalized);
31
+ this.setResourceId(normalized);
32
+ this.setFullUrl(normalized);
33
+ return this;
34
+ }
35
+ /** Returns the canonical identifier currently exposed for this vital-sign entry. */
36
+ getIdentifier() {
37
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Identifier)
38
+ || this.getResourceId()
39
+ || this.getFullUrl());
40
+ }
41
+ /** Ensures the entry has one synchronized canonical identifier across public claim, `resource.id`, and `fullUrl`. */
42
+ ensureIdentifier() {
43
+ const existing = this.getIdentifier();
44
+ if (existing)
45
+ return existing;
46
+ const generated = createCanonicalIdentifierUrn();
47
+ this.setIdentifier(generated);
48
+ return generated;
49
+ }
50
+ /** Sets the subject/patient reference for this vital-sign observation. */
51
+ setSubject(subject) {
52
+ const normalized = String(subject).trim();
53
+ this.setClaim(ObservationClaim.Subject, normalized);
54
+ this.setClaim(ObservationClaim.Patient, normalized);
55
+ return this;
56
+ }
57
+ /** Returns the subject/patient reference for this vital-sign observation. */
58
+ getSubject() {
59
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Subject)
60
+ || this.getClaim(ObservationClaim.Patient));
61
+ }
62
+ /** Sets the observation status. */
63
+ setStatus(status) {
64
+ return this.setClaim(ObservationClaim.Status, String(status).trim());
65
+ }
66
+ /** Returns the observation status. */
67
+ getStatus() {
68
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Status));
69
+ }
70
+ /** Sets the observation category, usually one of the shared vital-sign category descriptors. */
71
+ setCategory(category) {
72
+ const normalized = typeof category === 'string' ? category.trim() : category.claim;
73
+ return this.setClaim(ObservationClaim.Category, normalized);
74
+ }
75
+ /** Returns the observation category token. */
76
+ getCategory() {
77
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Category));
78
+ }
79
+ /** Sets the observation date/effective time. */
80
+ setDate(date) {
81
+ const normalized = String(date).trim();
82
+ this.setClaim(ObservationClaim.Date, normalized);
83
+ this.setClaim(ObservationClaim.EffectiveDateTime, normalized);
84
+ return this;
85
+ }
86
+ /** Returns the observation date/effective time. */
87
+ getDate() {
88
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Date)
89
+ || this.getClaim(ObservationClaim.EffectiveDateTime));
90
+ }
91
+ /** Sets one free-text note for the vital sign. */
92
+ setNote(note) {
93
+ return this.setClaim(ObservationClaim.Note, String(note).trim());
94
+ }
95
+ /** Returns the free-text note for the vital sign. */
96
+ getNote() {
97
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Note));
98
+ }
99
+ /** Seeds the observation code and optional quantity unit for the selected vital-sign family. */
100
+ setVitalSignType(code, unit) {
101
+ this.setCategory(ObservationCategoryCodes.VitalSigns);
102
+ this.setStatus(this.getStatus() || 'final');
103
+ this.setCode(code);
104
+ this.setCodeSystem(code.system);
105
+ this.setCodeValue(code.code);
106
+ if (code.display) {
107
+ this.setCodeDisplay(code.display);
108
+ this.setCodeTextLocal(code.display);
109
+ }
110
+ if (unit) {
111
+ this.setValueQuantityUnit(unit);
112
+ }
113
+ return this;
114
+ }
115
+ /** Convenience helper for heart-rate authoring using the shared code/unit catalog. */
116
+ setHeartRate(value) {
117
+ this.setVitalSignType(VitalSignsCodes.HeartRate, VitalSignsUnits.BeatsPerMinute);
118
+ return this.setValueQuantityNumber(value);
119
+ }
120
+ /** Returns the heart-rate numeric value. */
121
+ getHeartRate() {
122
+ return this.getValueQuantityNumber();
123
+ }
124
+ /** Convenience helper for body-temperature authoring using the shared code/unit catalog. */
125
+ setBodyTemperature(value) {
126
+ this.setVitalSignType(VitalSignsCodes.BodyTemperature, VitalSignsUnits.Celsius);
127
+ return this.setValueQuantityNumber(value);
128
+ }
129
+ /** Returns the body-temperature numeric value. */
130
+ getBodyTemperature() {
131
+ return this.getValueQuantityNumber();
132
+ }
133
+ /** Convenience helper for systolic blood-pressure authoring. */
134
+ setSystolicBloodPressure(value) {
135
+ this.setVitalSignType(VitalSignsCodes.SystolicBloodPressure, VitalSignsUnits.MillimeterOfMercury);
136
+ return this.setValueQuantityNumber(value);
137
+ }
138
+ /** Returns the systolic blood-pressure numeric value. */
139
+ getSystolicBloodPressure() {
140
+ return this.getValueQuantityNumber();
141
+ }
142
+ /** Convenience helper for diastolic blood-pressure authoring. */
143
+ setDiastolicBloodPressure(value) {
144
+ this.setVitalSignType(VitalSignsCodes.DiastolicBloodPressure, VitalSignsUnits.MillimeterOfMercury);
145
+ return this.setValueQuantityNumber(value);
146
+ }
147
+ /** Returns the diastolic blood-pressure numeric value. */
148
+ getDiastolicBloodPressure() {
149
+ return this.getValueQuantityNumber();
150
+ }
151
+ }
152
+ registerBundleEntryEditor(BundleEditableResourceTypes.vitalSign, VitalSignEntryEditor);
@@ -0,0 +1,93 @@
1
+ import { CryptographyService } from '../CryptographyService';
2
+ import type { ICryptoHelper } from '../interfaces/ICryptoHelper';
3
+ import type { IWallet } from '../interfaces/IWallet';
4
+ import type { IWalletQueue } from '../interfaces/IWalletQueue';
5
+ import type { JWK, JwkSet } from '../models/jwk';
6
+ import { type WalletEnqueueMessageInput, type WalletManagedEntityDescriptor, type WalletQueuedMessage } from '../models/wallet';
7
+ export type WalletMemOptions = Readonly<{
8
+ cryptoHelper: ICryptoHelper;
9
+ cryptography?: CryptographyService;
10
+ queue?: IWalletQueue;
11
+ }>;
12
+ /**
13
+ * In-memory wallet implementation intended for:
14
+ * - common low-level tests
15
+ * - GW template integration tests
16
+ * - frontend-like and BFF-like local transport simulations
17
+ *
18
+ * Design rule:
19
+ * - keep this class below actor-specific SDK facades
20
+ * - compose cryptography, key cache, local queue, and DIDComm-style
21
+ * pack/unpack in one portable runtime-neutral helper
22
+ */
23
+ export declare class WalletMem implements IWallet {
24
+ private readonly cryptoHelper;
25
+ private readonly cryptography;
26
+ private readonly entities;
27
+ private readonly queue;
28
+ constructor(options: WalletMemOptions);
29
+ /**
30
+ * Computes one digest through the injected platform helper.
31
+ */
32
+ digest(data: string, algorithm: string): Promise<string>;
33
+ /**
34
+ * Provisions one deterministic signing key, one deterministic encryption key,
35
+ * and one deterministic storage key for the provided entity id.
36
+ */
37
+ provisionKeys(entityId: string): Promise<JwkSet>;
38
+ /**
39
+ * Returns the public signing/encryption keys currently provisioned for one entity.
40
+ */
41
+ getPublicKeys(entityId: string): Promise<WalletManagedEntityDescriptor>;
42
+ /**
43
+ * Protects one document in memory using the entity-specific at-rest key.
44
+ */
45
+ protectConfidentialData(doc: unknown, entityId?: string): Promise<unknown>;
46
+ /**
47
+ * Unprotects one document previously encrypted through `protectConfidentialData(...)`.
48
+ */
49
+ unprotectConfidentialData(doc: unknown, entityId?: string): Promise<unknown>;
50
+ /**
51
+ * Signs one JSON payload into a compact JWS carrying the sender public JWK.
52
+ */
53
+ signCompactJws(entityId: string, claims: Record<string, unknown>): Promise<string>;
54
+ /**
55
+ * Encrypts one plaintext for the provided recipient public JWK.
56
+ */
57
+ buildCompactJwe(entityId: string, plaintext: string | Uint8Array, recipientJwk: JWK, contentType?: string): Promise<string>;
58
+ /**
59
+ * Packs one payload as nested compact JWS inside compact JWE.
60
+ */
61
+ pack(content: Record<string, unknown>, recipientJwk: JWK, entityId: string): Promise<string>;
62
+ /**
63
+ * Unpacks one compact JWE and, when present, verifies the nested compact JWS.
64
+ */
65
+ unpack(packedMessage: string, entityId?: string): Promise<{
66
+ content: unknown;
67
+ meta: Record<string, unknown>;
68
+ }>;
69
+ /**
70
+ * Enqueues one message in the local in-memory outbox/queue.
71
+ */
72
+ enqueueMessage(input: WalletEnqueueMessageInput): Promise<WalletQueuedMessage>;
73
+ /**
74
+ * Returns the highest-priority pending message without mutating queue state.
75
+ */
76
+ peekNextMessage(): Promise<WalletQueuedMessage | undefined>;
77
+ /**
78
+ * Marks one queued message as delivered.
79
+ */
80
+ markMessageDelivered(messageId: string): Promise<WalletQueuedMessage>;
81
+ /**
82
+ * Marks one queued message as failed while preserving it in the local queue.
83
+ */
84
+ markMessageFailed(messageId: string, errorMessage: string): Promise<WalletQueuedMessage>;
85
+ /**
86
+ * Lists all queued messages in priority/FIFO processing order.
87
+ */
88
+ listMessages(): Promise<WalletQueuedMessage[]>;
89
+ private deriveSeedBytes;
90
+ private requireEntityId;
91
+ private resolveEntityId;
92
+ private requireEntityState;
93
+ }