gdc-common-utils-ts 1.20.2 → 1.23.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 (86) hide show
  1. package/README.md +2 -2
  2. package/dist/claims/claims-helpers-related-person.d.ts +14 -0
  3. package/dist/claims/claims-helpers-related-person.js +28 -0
  4. package/dist/constants/Schemas.d.ts +3 -0
  5. package/dist/constants/Schemas.js +3 -0
  6. package/dist/constants/fhir-code-systems.d.ts +1 -0
  7. package/dist/constants/fhir-code-systems.js +1 -0
  8. package/dist/constants/fhir-resource-types.d.ts +2 -0
  9. package/dist/constants/fhir-resource-types.js +1 -0
  10. package/dist/constants/index.d.ts +3 -0
  11. package/dist/constants/index.js +3 -0
  12. package/dist/constants/individual-sections.d.ts +210 -0
  13. package/dist/constants/individual-sections.js +35 -0
  14. package/dist/constants/lifecycle.d.ts +17 -0
  15. package/dist/constants/lifecycle.js +18 -0
  16. package/dist/constants/observation-category.d.ts +72 -0
  17. package/dist/constants/observation-category.js +30 -0
  18. package/dist/constants/schemaorg.d.ts +4 -0
  19. package/dist/constants/schemaorg.js +4 -0
  20. package/dist/constants/vital-signs.d.ts +2 -17
  21. package/dist/constants/vital-signs.js +1 -6
  22. package/dist/convert/convert-observation.d.ts +20 -2
  23. package/dist/convert/convert-observation.js +80 -9
  24. package/dist/examples/index.d.ts +2 -0
  25. package/dist/examples/index.js +2 -0
  26. package/dist/examples/invoice.d.ts +37 -0
  27. package/dist/examples/invoice.js +72 -0
  28. package/dist/examples/license.d.ts +161 -0
  29. package/dist/examples/license.js +136 -7
  30. package/dist/examples/lifecycle.d.ts +44 -0
  31. package/dist/examples/lifecycle.js +25 -0
  32. package/dist/examples/related-person.d.ts +348 -0
  33. package/dist/examples/related-person.js +184 -2
  34. package/dist/examples/shared.d.ts +110 -8
  35. package/dist/examples/shared.js +129 -17
  36. package/dist/examples/vital-signs.d.ts +56 -0
  37. package/dist/examples/vital-signs.js +159 -0
  38. package/dist/models/fhir-documents.d.ts +35 -0
  39. package/dist/models/indexing.d.ts +68 -6
  40. package/dist/models/indexing.js +294 -11
  41. package/dist/models/interoperable-claims/index.d.ts +1 -0
  42. package/dist/models/interoperable-claims/index.js +1 -0
  43. package/dist/models/interoperable-claims/invoice-claims.d.ts +277 -0
  44. package/dist/models/interoperable-claims/invoice-claims.js +353 -0
  45. package/dist/models/interoperable-claims/observation-claims.d.ts +253 -1
  46. package/dist/models/interoperable-claims/observation-claims.js +249 -3
  47. package/dist/models/interoperable-claims.d.ts +1 -1
  48. package/dist/models/interoperable-claims.js +1 -1
  49. package/dist/models/urlPath.d.ts +3 -1
  50. package/dist/models/urlPath.js +2 -0
  51. package/dist/utils/bundle-document-builder.js +22 -4
  52. package/dist/utils/bundle-editor.d.ts +105 -2
  53. package/dist/utils/bundle-editor.js +282 -2
  54. package/dist/utils/clinical-resource-converters.d.ts +4 -4
  55. package/dist/utils/clinical-resource-converters.js +5 -5
  56. package/dist/utils/communication-attached-bundle-session.d.ts +11 -0
  57. package/dist/utils/communication-attached-bundle-session.js +29 -0
  58. package/dist/utils/consent-lifecycle-result-reader.d.ts +24 -0
  59. package/dist/utils/consent-lifecycle-result-reader.js +27 -0
  60. package/dist/utils/employee.d.ts +25 -0
  61. package/dist/utils/employee.js +57 -0
  62. package/dist/utils/gw-core-path.d.ts +24 -0
  63. package/dist/utils/gw-core-path.js +21 -0
  64. package/dist/utils/index.d.ts +11 -0
  65. package/dist/utils/index.js +11 -0
  66. package/dist/utils/individual-bundle-vault.d.ts +144 -0
  67. package/dist/utils/individual-bundle-vault.js +455 -0
  68. package/dist/utils/individual-organization-lifecycle.d.ts +104 -0
  69. package/dist/utils/individual-organization-lifecycle.js +179 -0
  70. package/dist/utils/interoperable-resource-operation.d.ts +158 -0
  71. package/dist/utils/interoperable-resource-operation.js +244 -0
  72. package/dist/utils/invoice-bundle.d.ts +82 -0
  73. package/dist/utils/invoice-bundle.js +240 -0
  74. package/dist/utils/license-commercial-search.d.ts +118 -0
  75. package/dist/utils/license-commercial-search.js +228 -0
  76. package/dist/utils/license-list-search.d.ts +105 -0
  77. package/dist/utils/license-list-search.js +209 -0
  78. package/dist/utils/license-offer-order.d.ts +107 -0
  79. package/dist/utils/license-offer-order.js +262 -0
  80. package/dist/utils/license.d.ts +6 -0
  81. package/dist/utils/license.js +6 -0
  82. package/dist/utils/lifecycle-result-reader.d.ts +33 -0
  83. package/dist/utils/lifecycle-result-reader.js +99 -0
  84. package/dist/utils/related-person-list.d.ts +20 -0
  85. package/dist/utils/related-person-list.js +54 -0
  86. package/package.json +2 -1
@@ -0,0 +1,159 @@
1
+ // Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
2
+ import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
3
+ import { VitalSignsCodes, VitalSignsUnits } from '../constants/vital-signs.js';
4
+ import { CommunicationClaim } from '../models/interoperable-claims/communication-claims.js';
5
+ import { Format } from '../constants/Schemas.js';
6
+ import { observationFromFlatToFhirR4 } from '../convert/convert-observation.js';
7
+ import { CommunicationAttachedBundleSession } from '../utils/communication-attached-bundle-session.js';
8
+ import { buildVitalSignObservationClaims } from '../utils/individual-bundle-vault.js';
9
+ import { EXAMPLE_COMMUNICATION_IDENTIFIER, EXAMPLE_OBSERVATION_COMPONENT_IDENTIFIER, EXAMPLE_OBSERVATION_COMPONENT_IDENTIFIER_SECONDARY, EXAMPLE_OBSERVATION_IDENTIFIER, EXAMPLE_OBSERVATION_PANEL_IDENTIFIER, EXAMPLE_SUBJECT_DID, EXAMPLE_VITAL_SIGN_DISPLAY_VITAL_SIGNS, EXAMPLE_VITAL_SIGNS_EFFECTIVE_DATE_TIME, EXAMPLE_VITAL_SIGNS_NOTE, EXAMPLE_VITAL_SIGN_VALUE_BODY_TEMPERATURE, EXAMPLE_VITAL_SIGN_VALUE_DIASTOLIC, EXAMPLE_VITAL_SIGN_VALUE_HEART_RATE, EXAMPLE_VITAL_SIGN_VALUE_SYSTOLIC, } from './shared.js';
10
+ /**
11
+ * Shared example inputs for authoring vital-sign Observations in claims-first
12
+ * flows.
13
+ *
14
+ * Reference:
15
+ * - HL7 CIMI Vital Signs with Qualifying Elements IG
16
+ * https://build.fhir.org/ig/HL7/cimi-vital-signs/
17
+ *
18
+ * These examples intentionally cover only direct vital-sign authoring inputs
19
+ * that a person or simple frontend form would create:
20
+ * - heart rate
21
+ * - body temperature
22
+ * - systolic blood pressure
23
+ * - diastolic blood pressure
24
+ *
25
+ * Panel/group authoring is excluded on purpose because panels are typically
26
+ * imported from external FHIR systems or composed by professional workflows.
27
+ */
28
+ /** Example claims-first input for one heart rate Observation (LOINC 8867-4, UCUM /min). */
29
+ export const EXAMPLE_VITAL_SIGN_HEART_RATE_INPUT = {
30
+ identifier: EXAMPLE_OBSERVATION_IDENTIFIER,
31
+ subject: EXAMPLE_SUBJECT_DID,
32
+ code: VitalSignsCodes.HeartRate,
33
+ unit: VitalSignsUnits.BeatsPerMinute,
34
+ valueQuantity: EXAMPLE_VITAL_SIGN_VALUE_HEART_RATE,
35
+ effectiveDateTime: EXAMPLE_VITAL_SIGNS_EFFECTIVE_DATE_TIME,
36
+ };
37
+ /** Example claims-first input for one body temperature Observation (LOINC 8310-5, UCUM Cel). */
38
+ export const EXAMPLE_VITAL_SIGN_BODY_TEMPERATURE_INPUT = {
39
+ identifier: EXAMPLE_OBSERVATION_PANEL_IDENTIFIER,
40
+ subject: EXAMPLE_SUBJECT_DID,
41
+ code: VitalSignsCodes.BodyTemperature,
42
+ unit: VitalSignsUnits.Celsius,
43
+ valueQuantity: EXAMPLE_VITAL_SIGN_VALUE_BODY_TEMPERATURE,
44
+ effectiveDateTime: EXAMPLE_VITAL_SIGNS_EFFECTIVE_DATE_TIME,
45
+ };
46
+ /** Example claims-first input for one systolic blood pressure Observation (LOINC 8480-6, UCUM mm[Hg]). */
47
+ export const EXAMPLE_VITAL_SIGN_SYSTOLIC_BLOOD_PRESSURE_INPUT = {
48
+ identifier: EXAMPLE_OBSERVATION_COMPONENT_IDENTIFIER,
49
+ subject: EXAMPLE_SUBJECT_DID,
50
+ code: VitalSignsCodes.SystolicBloodPressure,
51
+ unit: VitalSignsUnits.MillimeterOfMercury,
52
+ valueQuantity: EXAMPLE_VITAL_SIGN_VALUE_SYSTOLIC,
53
+ effectiveDateTime: EXAMPLE_VITAL_SIGNS_EFFECTIVE_DATE_TIME,
54
+ };
55
+ /** Example claims-first input for one diastolic blood pressure Observation (LOINC 8462-4, UCUM mm[Hg]). */
56
+ export const EXAMPLE_VITAL_SIGN_DIASTOLIC_BLOOD_PRESSURE_INPUT = {
57
+ identifier: EXAMPLE_OBSERVATION_COMPONENT_IDENTIFIER_SECONDARY,
58
+ subject: EXAMPLE_SUBJECT_DID,
59
+ code: VitalSignsCodes.DiastolicBloodPressure,
60
+ unit: VitalSignsUnits.MillimeterOfMercury,
61
+ valueQuantity: EXAMPLE_VITAL_SIGN_VALUE_DIASTOLIC,
62
+ effectiveDateTime: EXAMPLE_VITAL_SIGNS_EFFECTIVE_DATE_TIME,
63
+ };
64
+ function resolveObservationEntryFullUrl(identifier) {
65
+ return String(identifier || '').startsWith('urn:')
66
+ ? String(identifier)
67
+ : `urn:uuid:${String(identifier)}`;
68
+ }
69
+ function toFlatClaims(record) {
70
+ const claims = {};
71
+ for (const [key, value] of Object.entries(record || {})) {
72
+ if (value === undefined || value === null)
73
+ continue;
74
+ claims[key] = typeof value === 'string' ? value : String(value);
75
+ }
76
+ return claims;
77
+ }
78
+ /**
79
+ * Builds one high-level bundle entry for a vital-sign Observation.
80
+ *
81
+ * This is the preferred copy-paste pattern for frontend flows:
82
+ * 1. author flat claims with `buildVitalSignObservationClaims(...)`
83
+ * 2. convert them to one FHIR R4 `Observation`
84
+ * 3. keep the claims in `resource.meta.claims`
85
+ * 4. append the entry to a `Bundle.data` array
86
+ */
87
+ export function buildVitalSignObservationEntry(input) {
88
+ const claims = buildVitalSignObservationClaims(input);
89
+ const flatClaims = toFlatClaims(claims);
90
+ const resource = observationFromFlatToFhirR4(flatClaims);
91
+ return {
92
+ id: String(claims['Observation.identifier'] || input.identifier),
93
+ fullUrl: resolveObservationEntryFullUrl(String(claims['Observation.identifier'] || input.identifier)),
94
+ type: `${ResourceTypesFhirR4.Observation}-entry-v1.0`,
95
+ resource: {
96
+ ...resource,
97
+ meta: {
98
+ ...(resource.meta || {}),
99
+ claims: flatClaims,
100
+ },
101
+ },
102
+ };
103
+ }
104
+ /**
105
+ * Builds a high-level bundle with one entry per directly authored vital sign.
106
+ *
107
+ * Included examples:
108
+ * - heart rate
109
+ * - body temperature
110
+ * - systolic blood pressure
111
+ * - diastolic blood pressure
112
+ *
113
+ * Panels are intentionally excluded because the app user normally authors
114
+ * simple observations, not professional/imported panel structures.
115
+ */
116
+ export function buildExampleVitalSignsObservationBundle() {
117
+ return {
118
+ resourceType: 'Bundle',
119
+ type: 'collection',
120
+ data: [
121
+ buildVitalSignObservationEntry(EXAMPLE_VITAL_SIGN_HEART_RATE_INPUT),
122
+ buildVitalSignObservationEntry(EXAMPLE_VITAL_SIGN_BODY_TEMPERATURE_INPUT),
123
+ buildVitalSignObservationEntry(EXAMPLE_VITAL_SIGN_SYSTOLIC_BLOOD_PRESSURE_INPUT),
124
+ buildVitalSignObservationEntry(EXAMPLE_VITAL_SIGN_DIASTOLIC_BLOOD_PRESSURE_INPUT),
125
+ ],
126
+ };
127
+ }
128
+ /**
129
+ * Builds the same vital-sign bundle through `CommunicationAttachedBundleSession`
130
+ * for flows that already use the in-memory bundle editor/session abstraction.
131
+ */
132
+ export function buildExampleVitalSignsObservationBundleSession() {
133
+ const session = new CommunicationAttachedBundleSession({
134
+ communicationClaims: {
135
+ '@context': Format.FHIR_API,
136
+ [CommunicationClaim.Identifier]: EXAMPLE_COMMUNICATION_IDENTIFIER,
137
+ [CommunicationClaim.Subject]: EXAMPLE_SUBJECT_DID,
138
+ [CommunicationClaim.Text]: EXAMPLE_VITAL_SIGN_DISPLAY_VITAL_SIGNS,
139
+ },
140
+ });
141
+ const inputs = [
142
+ EXAMPLE_VITAL_SIGN_HEART_RATE_INPUT,
143
+ EXAMPLE_VITAL_SIGN_BODY_TEMPERATURE_INPUT,
144
+ EXAMPLE_VITAL_SIGN_SYSTOLIC_BLOOD_PRESSURE_INPUT,
145
+ EXAMPLE_VITAL_SIGN_DIASTOLIC_BLOOD_PRESSURE_INPUT,
146
+ ];
147
+ for (const input of inputs) {
148
+ session.upsertActiveObservationEntry({
149
+ claims: buildVitalSignObservationClaims({
150
+ ...input,
151
+ note: EXAMPLE_VITAL_SIGNS_NOTE,
152
+ }),
153
+ fullUrl: resolveObservationEntryFullUrl(input.identifier),
154
+ type: `${ResourceTypesFhirR4.Observation}-entry-v1.0`,
155
+ });
156
+ session.saveAndReleaseActiveEntry();
157
+ }
158
+ return session.getBundleInMemory();
159
+ }
@@ -23,6 +23,10 @@ export type FhirAttachment = {
23
23
  url?: string;
24
24
  title?: string;
25
25
  creation?: string;
26
+ hash?: string;
27
+ };
28
+ export type FhirMeta = {
29
+ claims?: Record<string, unknown>;
26
30
  };
27
31
  export interface FhirCompositionResource {
28
32
  resourceType: 'Composition';
@@ -46,6 +50,7 @@ export interface FhirCompositionResource {
46
50
  export interface FhirDocumentReferenceResource {
47
51
  resourceType: 'DocumentReference';
48
52
  id?: string;
53
+ meta?: FhirMeta;
49
54
  status?: string;
50
55
  identifier?: Array<{
51
56
  system?: string;
@@ -81,9 +86,39 @@ export interface FhirDocumentReferenceResource {
81
86
  format?: FhirCoding;
82
87
  }>;
83
88
  }
89
+ export interface FhirInvoiceResource {
90
+ resourceType: 'Invoice';
91
+ id?: string;
92
+ meta?: FhirMeta;
93
+ status?: string;
94
+ identifier?: Array<{
95
+ system?: string;
96
+ value?: string;
97
+ }>;
98
+ subject?: FhirReference;
99
+ recipient?: FhirReference;
100
+ issuer?: {
101
+ reference?: string;
102
+ display?: string;
103
+ };
104
+ date?: string;
105
+ paymentTerms?: string;
106
+ note?: Array<{
107
+ text?: string;
108
+ }>;
109
+ totalNet?: {
110
+ value?: number;
111
+ currency?: string;
112
+ };
113
+ totalGross?: {
114
+ value?: number;
115
+ currency?: string;
116
+ };
117
+ }
84
118
  export interface FhirCommunicationResource {
85
119
  resourceType: 'Communication';
86
120
  id?: string;
121
+ meta?: FhirMeta;
87
122
  status?: string;
88
123
  category?: FhirCodeableConcept[];
89
124
  subject?: FhirReference;
@@ -1,11 +1,73 @@
1
- import { ClaimsOrganizationSchemaorg } from "../constants/schemaorg";
1
+ import { ClaimsOrganizationSchemaorg } from '../constants/schemaorg';
2
+ import type { ParameterData } from './params';
3
+ /**
4
+ * Canonical index profile names used under each resource type.
5
+ */
6
+ export declare const IndexingClaimSet: Readonly<{
7
+ readonly General: "General";
8
+ readonly Registry: "Registry";
9
+ readonly VitalSigns: "VitalSigns";
10
+ }>;
11
+ export type IndexingClaimSetKey = typeof IndexingClaimSet[keyof typeof IndexingClaimSet];
2
12
  /**
3
13
  * Defines which claims are allowed to be indexed for different resource types.
4
- * This provides a single, strongly-typed source of truth for indexing strategies.
14
+ *
15
+ * Preferred shape:
16
+ * `AllowedIndexableClaims[ResourceType][General/category/type]`
5
17
  */
6
18
  export declare const AllowedIndexableClaims: {
7
- /**
8
- * Defines the claims that can be indexed in the central tenant registry for an Organization.
9
- */
10
- organizationRegistry: readonly [ClaimsOrganizationSchemaorg.alternateName, ClaimsOrganizationSchemaorg.identifierValue, ClaimsOrganizationSchemaorg.identifierType, ClaimsOrganizationSchemaorg.addressCountry];
19
+ readonly Organization: {
20
+ /**
21
+ * Claims that can be indexed in the central tenant registry for an Organization.
22
+ */
23
+ readonly Registry: readonly [ClaimsOrganizationSchemaorg.alternateName, ClaimsOrganizationSchemaorg.identifierValue, ClaimsOrganizationSchemaorg.identifierType, ClaimsOrganizationSchemaorg.addressCountry];
24
+ };
25
+ readonly Observation: {
26
+ /**
27
+ * Searchable/indexable subset for a general Observation row.
28
+ *
29
+ * Keep this aligned with GW managers that build `indexed.attributes` from
30
+ * claims-first payloads. UI-only or long free-text fields stay out.
31
+ */
32
+ readonly General: readonly ["Observation.identifier", "Observation.subject", "Observation.patient", "Observation.status", "Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code", "Observation.date", "Observation.effectiveDateTime", "Observation.value-concept-system", "Observation.value-concept-value", "Observation.value-concept", "Observation.value-date", "Observation.value-quantity-comparator", "Observation.value-quantity-number", "Observation.value-quantity-unit", "Observation.score-total-number", "Observation.component-tags", "Observation.component-code-values", "Observation.component-names", "Observation.bp-systolic-number", "Observation.bp-diastolic-number", "Observation.has-member", "Observation.encounter", "Observation.device", "Observation.specimen", "Observation.performer", "Observation.based-on", "Observation.focus", "Observation.method", "Observation.language"];
33
+ /**
34
+ * Searchable/indexable subset for a Vital Signs Observation row.
35
+ *
36
+ * This is intentionally narrower than the full persisted claims list and
37
+ * excludes local-language labels, XHTML/narrative, and note text.
38
+ */
39
+ readonly VitalSigns: readonly ["Observation.identifier", "Observation.subject", "Observation.patient", "Observation.status", "Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code", "Observation.date", "Observation.effectiveDateTime", "Observation.value-concept-system", "Observation.value-concept-value", "Observation.value-concept", "Observation.value-date", "Observation.value-quantity-comparator", "Observation.value-quantity-number", "Observation.value-quantity-unit", "Observation.score-total-number", "Observation.component-tags", "Observation.component-code-values", "Observation.component-names", "Observation.bp-systolic-number", "Observation.bp-diastolic-number", "Observation.has-member", "Observation.method", "Observation.language"];
40
+ };
41
+ readonly Condition: {
42
+ readonly General: readonly ["Condition.identifier", "Condition.subject", "Condition.clinical-status", "Condition.verification-status", "Condition.category", "Condition.code", "Condition.severity", "Condition.onset-datetime", "Condition.recorder"];
43
+ };
44
+ readonly MedicationStatement: {
45
+ readonly General: readonly ["MedicationStatement.identifier", "MedicationStatement.subject", "MedicationStatement.patient", "MedicationStatement.status", "MedicationStatement.category", "MedicationStatement.effective", "MedicationStatement.code", "MedicationStatement.medication", "MedicationStatement.part-of", "MedicationStatement.source", "MedicationStatement.medication-identifier", "MedicationStatement.medication-serial-number", "MedicationStatement.medication-expiration-date"];
46
+ };
47
+ readonly DocumentReference: {
48
+ readonly General: readonly ["DocumentReference.identifier", "DocumentReference.subject", "DocumentReference.author", "DocumentReference.attester", "DocumentReference.basedOn", "DocumentReference.category", "DocumentReference.contenthash", "DocumentReference.contenttype", "DocumentReference.context", "DocumentReference.creation", "DocumentReference.date", "DocumentReference.event-code", "DocumentReference.event-reference", "DocumentReference.format-uri", "DocumentReference.language", "DocumentReference.location", "DocumentReference.modality", "DocumentReference.relatesto", "DocumentReference.relation", "DocumentReference.type"];
49
+ };
11
50
  };
51
+ export type AllowedIndexableClaimsKey = keyof typeof AllowedIndexableClaims;
52
+ /**
53
+ * Deprecated compatibility aliases.
54
+ *
55
+ * Prefer `AllowedIndexableClaims[ResourceTypesFhirR4.Observation].General`,
56
+ * `AllowedIndexableClaims[ResourceTypesFhirR4.Observation].VitalSigns`, and
57
+ * `AllowedIndexableClaims.Organization.Registry` in new code.
58
+ */
59
+ export declare const AllowedIndexableClaimAliases: Readonly<{
60
+ readonly organizationRegistry: readonly [ClaimsOrganizationSchemaorg.alternateName, ClaimsOrganizationSchemaorg.identifierValue, ClaimsOrganizationSchemaorg.identifierType, ClaimsOrganizationSchemaorg.addressCountry];
61
+ readonly observationGeneral: readonly ["Observation.identifier", "Observation.subject", "Observation.patient", "Observation.status", "Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code", "Observation.date", "Observation.effectiveDateTime", "Observation.value-concept-system", "Observation.value-concept-value", "Observation.value-concept", "Observation.value-date", "Observation.value-quantity-comparator", "Observation.value-quantity-number", "Observation.value-quantity-unit", "Observation.score-total-number", "Observation.component-tags", "Observation.component-code-values", "Observation.component-names", "Observation.bp-systolic-number", "Observation.bp-diastolic-number", "Observation.has-member", "Observation.encounter", "Observation.device", "Observation.specimen", "Observation.performer", "Observation.based-on", "Observation.focus", "Observation.method", "Observation.language"];
62
+ readonly observationVitalSigns: readonly ["Observation.identifier", "Observation.subject", "Observation.patient", "Observation.status", "Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code", "Observation.date", "Observation.effectiveDateTime", "Observation.value-concept-system", "Observation.value-concept-value", "Observation.value-concept", "Observation.value-date", "Observation.value-quantity-comparator", "Observation.value-quantity-number", "Observation.value-quantity-unit", "Observation.score-total-number", "Observation.component-tags", "Observation.component-code-values", "Observation.component-names", "Observation.bp-systolic-number", "Observation.bp-diastolic-number", "Observation.has-member", "Observation.method", "Observation.language"];
63
+ }>;
64
+ /**
65
+ * Projects a claims-first record to the `ParameterData[]` shape used by GW/KMS
66
+ * before optional HMAC protection.
67
+ */
68
+ export declare function buildIndexParametersFromClaims(claims: Record<string, unknown>, allowedClaims: readonly string[]): ParameterData[];
69
+ /**
70
+ * Sanity guard to keep the indexable subset anchored to the broader claims
71
+ * lists declared by the interoperable-claims contract.
72
+ */
73
+ export declare function isAllowedObservationIndexableClaim(claimKey: string, variant: 'general' | 'vital-signs'): boolean;
@@ -1,18 +1,301 @@
1
1
  // Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
2
2
  // File: src/models/indexing.ts
3
- import { ClaimsOrganizationSchemaorg } from "../constants/schemaorg.js";
3
+ import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
4
+ import { ClaimsOrganizationSchemaorg } from '../constants/schemaorg.js';
5
+ import { ConditionClaim } from './interoperable-claims/condition-claims.js';
6
+ import { DocumentReferenceClaim } from './interoperable-claims/document-reference-claims.js';
7
+ import { MedicationStatementClaim } from './interoperable-claims/medication-statement-claims.js';
8
+ import { ObservationClaim, ObservationGeneralClaimsList, ObservationVitalSignsClaimsList, } from './interoperable-claims/observation-claims.js';
9
+ /**
10
+ * Canonical index profile names used under each resource type.
11
+ */
12
+ export const IndexingClaimSet = Object.freeze({
13
+ General: 'General',
14
+ Registry: 'Registry',
15
+ VitalSigns: 'VitalSigns',
16
+ });
4
17
  /**
5
18
  * Defines which claims are allowed to be indexed for different resource types.
6
- * This provides a single, strongly-typed source of truth for indexing strategies.
19
+ *
20
+ * Preferred shape:
21
+ * `AllowedIndexableClaims[ResourceType][General/category/type]`
7
22
  */
8
23
  export const AllowedIndexableClaims = {
9
- /**
10
- * Defines the claims that can be indexed in the central tenant registry for an Organization.
11
- */
12
- organizationRegistry: [
13
- ClaimsOrganizationSchemaorg.alternateName,
14
- ClaimsOrganizationSchemaorg.identifierValue,
15
- ClaimsOrganizationSchemaorg.identifierType,
16
- ClaimsOrganizationSchemaorg.addressCountry,
17
- ], // Use 'as const' to provide strong typing for the array elements
24
+ Organization: {
25
+ /**
26
+ * Claims that can be indexed in the central tenant registry for an Organization.
27
+ */
28
+ [IndexingClaimSet.Registry]: [
29
+ ClaimsOrganizationSchemaorg.alternateName,
30
+ ClaimsOrganizationSchemaorg.identifierValue,
31
+ ClaimsOrganizationSchemaorg.identifierType,
32
+ ClaimsOrganizationSchemaorg.addressCountry,
33
+ ],
34
+ },
35
+ [ResourceTypesFhirR4.Observation]: {
36
+ /**
37
+ * Searchable/indexable subset for a general Observation row.
38
+ *
39
+ * Keep this aligned with GW managers that build `indexed.attributes` from
40
+ * claims-first payloads. UI-only or long free-text fields stay out.
41
+ */
42
+ [IndexingClaimSet.General]: [
43
+ ObservationClaim.Identifier,
44
+ ObservationClaim.Subject,
45
+ ObservationClaim.Patient,
46
+ ObservationClaim.Status,
47
+ ObservationClaim.Category,
48
+ ObservationClaim.CodeSystem,
49
+ ObservationClaim.CodeValue,
50
+ ObservationClaim.Code,
51
+ ObservationClaim.Date,
52
+ ObservationClaim.EffectiveDateTime,
53
+ ObservationClaim.ValueConceptSystem,
54
+ ObservationClaim.ValueConceptValue,
55
+ ObservationClaim.ValueConcept,
56
+ ObservationClaim.ValueDate,
57
+ ObservationClaim.ValueQuantityComparator,
58
+ ObservationClaim.ValueQuantityNumber,
59
+ ObservationClaim.ValueQuantityUnit,
60
+ ObservationClaim.ScoreTotalNumber,
61
+ ObservationClaim.ComponentTags,
62
+ ObservationClaim.ComponentCodeValues,
63
+ ObservationClaim.ComponentNames,
64
+ ObservationClaim.BloodPressureSystolicNumber,
65
+ ObservationClaim.BloodPressureDiastolicNumber,
66
+ ObservationClaim.HasMember,
67
+ ObservationClaim.Encounter,
68
+ ObservationClaim.Device,
69
+ ObservationClaim.Specimen,
70
+ ObservationClaim.Performer,
71
+ ObservationClaim.BasedOn,
72
+ ObservationClaim.Focus,
73
+ ObservationClaim.Method,
74
+ ObservationClaim.Language,
75
+ ],
76
+ /**
77
+ * Searchable/indexable subset for a Vital Signs Observation row.
78
+ *
79
+ * This is intentionally narrower than the full persisted claims list and
80
+ * excludes local-language labels, XHTML/narrative, and note text.
81
+ */
82
+ [IndexingClaimSet.VitalSigns]: [
83
+ ObservationClaim.Identifier,
84
+ ObservationClaim.Subject,
85
+ ObservationClaim.Patient,
86
+ ObservationClaim.Status,
87
+ ObservationClaim.Category,
88
+ ObservationClaim.CodeSystem,
89
+ ObservationClaim.CodeValue,
90
+ ObservationClaim.Code,
91
+ ObservationClaim.Date,
92
+ ObservationClaim.EffectiveDateTime,
93
+ ObservationClaim.ValueConceptSystem,
94
+ ObservationClaim.ValueConceptValue,
95
+ ObservationClaim.ValueConcept,
96
+ ObservationClaim.ValueDate,
97
+ ObservationClaim.ValueQuantityComparator,
98
+ ObservationClaim.ValueQuantityNumber,
99
+ ObservationClaim.ValueQuantityUnit,
100
+ ObservationClaim.ScoreTotalNumber,
101
+ ObservationClaim.ComponentTags,
102
+ ObservationClaim.ComponentCodeValues,
103
+ ObservationClaim.ComponentNames,
104
+ ObservationClaim.BloodPressureSystolicNumber,
105
+ ObservationClaim.BloodPressureDiastolicNumber,
106
+ ObservationClaim.HasMember,
107
+ ObservationClaim.Method,
108
+ ObservationClaim.Language,
109
+ ],
110
+ },
111
+ [ResourceTypesFhirR4.Condition]: {
112
+ [IndexingClaimSet.General]: [
113
+ ConditionClaim.Identifier,
114
+ ConditionClaim.Subject,
115
+ ConditionClaim.ClinicalStatus,
116
+ ConditionClaim.VerificationStatus,
117
+ ConditionClaim.Category,
118
+ ConditionClaim.Code,
119
+ ConditionClaim.Severity,
120
+ ConditionClaim.OnsetDateTime,
121
+ ConditionClaim.Recorder,
122
+ ],
123
+ },
124
+ [ResourceTypesFhirR4.MedicationStatement]: {
125
+ [IndexingClaimSet.General]: [
126
+ MedicationStatementClaim.Identifier,
127
+ MedicationStatementClaim.Subject,
128
+ MedicationStatementClaim.Patient,
129
+ MedicationStatementClaim.Status,
130
+ MedicationStatementClaim.Category,
131
+ MedicationStatementClaim.Effective,
132
+ MedicationStatementClaim.Code,
133
+ MedicationStatementClaim.Medication,
134
+ MedicationStatementClaim.PartOf,
135
+ MedicationStatementClaim.Source,
136
+ MedicationStatementClaim.MedicationIdentifier,
137
+ MedicationStatementClaim.MedicationSerialNumber,
138
+ MedicationStatementClaim.MedicationExpirationDate,
139
+ ],
140
+ },
141
+ [ResourceTypesFhirR4.DocumentReference]: {
142
+ [IndexingClaimSet.General]: [
143
+ DocumentReferenceClaim.Identifier,
144
+ DocumentReferenceClaim.Subject,
145
+ DocumentReferenceClaim.Author,
146
+ DocumentReferenceClaim.Attester,
147
+ DocumentReferenceClaim.BasedOn,
148
+ DocumentReferenceClaim.Category,
149
+ DocumentReferenceClaim.ContentHash,
150
+ DocumentReferenceClaim.ContentType,
151
+ DocumentReferenceClaim.Context,
152
+ DocumentReferenceClaim.Creation,
153
+ DocumentReferenceClaim.Date,
154
+ DocumentReferenceClaim.EventCode,
155
+ DocumentReferenceClaim.EventReference,
156
+ DocumentReferenceClaim.FormatUri,
157
+ DocumentReferenceClaim.Language,
158
+ DocumentReferenceClaim.Location,
159
+ DocumentReferenceClaim.Modality,
160
+ DocumentReferenceClaim.RelatesTo,
161
+ DocumentReferenceClaim.Relation,
162
+ DocumentReferenceClaim.Type,
163
+ ],
164
+ },
18
165
  };
166
+ /**
167
+ * Deprecated compatibility aliases.
168
+ *
169
+ * Prefer `AllowedIndexableClaims[ResourceTypesFhirR4.Observation].General`,
170
+ * `AllowedIndexableClaims[ResourceTypesFhirR4.Observation].VitalSigns`, and
171
+ * `AllowedIndexableClaims.Organization.Registry` in new code.
172
+ */
173
+ export const AllowedIndexableClaimAliases = Object.freeze({
174
+ organizationRegistry: AllowedIndexableClaims.Organization.Registry,
175
+ observationGeneral: AllowedIndexableClaims[ResourceTypesFhirR4.Observation][IndexingClaimSet.General],
176
+ observationVitalSigns: AllowedIndexableClaims[ResourceTypesFhirR4.Observation][IndexingClaimSet.VitalSigns],
177
+ });
178
+ /**
179
+ * Projects a claims-first record to the `ParameterData[]` shape used by GW/KMS
180
+ * before optional HMAC protection.
181
+ */
182
+ export function buildIndexParametersFromClaims(claims, allowedClaims) {
183
+ const parameters = [];
184
+ for (const claimKey of allowedClaims) {
185
+ const rawValue = claims[claimKey];
186
+ if (rawValue === undefined || rawValue === null || rawValue === '') {
187
+ continue;
188
+ }
189
+ const value = typeof rawValue === 'number' ? rawValue : String(rawValue).trim();
190
+ if (value === '') {
191
+ continue;
192
+ }
193
+ const parameter = {
194
+ name: claimKey,
195
+ value: value,
196
+ type: inferParameterTypeFromClaimKey(claimKey, rawValue),
197
+ ...(claimKey === ObservationClaim.ValueQuantityUnit && typeof rawValue === 'string'
198
+ ? { unit: rawValue }
199
+ : {}),
200
+ };
201
+ parameters.push(parameter);
202
+ }
203
+ return parameters;
204
+ }
205
+ function inferParameterTypeFromClaimKey(claimKey, rawValue) {
206
+ if (claimKey === ObservationClaim.ValueQuantityNumber
207
+ || claimKey === ObservationClaim.ScoreTotalNumber
208
+ || claimKey === ObservationClaim.BloodPressureSystolicNumber
209
+ || claimKey === ObservationClaim.BloodPressureDiastolicNumber) {
210
+ return 'number';
211
+ }
212
+ if (claimKey === ObservationClaim.Date
213
+ || claimKey === ObservationClaim.EffectiveDateTime
214
+ || claimKey === ObservationClaim.ValueDate
215
+ || claimKey === ConditionClaim.OnsetDateTime
216
+ || claimKey === MedicationStatementClaim.Effective
217
+ || claimKey === MedicationStatementClaim.MedicationExpirationDate
218
+ || claimKey === DocumentReferenceClaim.Creation
219
+ || claimKey === DocumentReferenceClaim.Date) {
220
+ return 'date';
221
+ }
222
+ if (claimKey === ObservationClaim.Subject
223
+ || claimKey === ObservationClaim.Patient
224
+ || claimKey === ObservationClaim.Encounter
225
+ || claimKey === ObservationClaim.Device
226
+ || claimKey === ObservationClaim.Specimen
227
+ || claimKey === ObservationClaim.Performer
228
+ || claimKey === ObservationClaim.BasedOn
229
+ || claimKey === ObservationClaim.Focus
230
+ || claimKey === ObservationClaim.HasMember
231
+ || claimKey === ConditionClaim.Subject
232
+ || claimKey === ConditionClaim.Recorder
233
+ || claimKey === MedicationStatementClaim.Subject
234
+ || claimKey === MedicationStatementClaim.Patient
235
+ || claimKey === MedicationStatementClaim.PartOf
236
+ || claimKey === MedicationStatementClaim.Source
237
+ || claimKey === DocumentReferenceClaim.Subject
238
+ || claimKey === DocumentReferenceClaim.Author
239
+ || claimKey === DocumentReferenceClaim.Attester
240
+ || claimKey === DocumentReferenceClaim.BasedOn
241
+ || claimKey === DocumentReferenceClaim.Context
242
+ || claimKey === DocumentReferenceClaim.EventReference
243
+ || claimKey === DocumentReferenceClaim.RelatesTo) {
244
+ return 'reference';
245
+ }
246
+ if (claimKey === ObservationClaim.Category
247
+ || claimKey === ObservationClaim.ComponentTags
248
+ || claimKey === ObservationClaim.ComponentCodeValues
249
+ || claimKey === ObservationClaim.CodeSystem
250
+ || claimKey === ObservationClaim.CodeValue
251
+ || claimKey === ObservationClaim.Code
252
+ || claimKey === ObservationClaim.ValueConceptSystem
253
+ || claimKey === ObservationClaim.ValueConceptValue
254
+ || claimKey === ObservationClaim.ValueConcept
255
+ || claimKey === ObservationClaim.Method
256
+ || claimKey === ObservationClaim.Language
257
+ || claimKey === ObservationClaim.ValueQuantityComparator
258
+ || claimKey === ObservationClaim.ValueQuantityUnit
259
+ || claimKey === ConditionClaim.ClinicalStatus
260
+ || claimKey === ConditionClaim.VerificationStatus
261
+ || claimKey === ConditionClaim.Category
262
+ || claimKey === ConditionClaim.Code
263
+ || claimKey === ConditionClaim.Severity
264
+ || claimKey === MedicationStatementClaim.Status
265
+ || claimKey === MedicationStatementClaim.Category
266
+ || claimKey === MedicationStatementClaim.Code
267
+ || claimKey === MedicationStatementClaim.Medication
268
+ || claimKey === DocumentReferenceClaim.Category
269
+ || claimKey === DocumentReferenceClaim.ContentType
270
+ || claimKey === DocumentReferenceClaim.EventCode
271
+ || claimKey === DocumentReferenceClaim.FormatUri
272
+ || claimKey === DocumentReferenceClaim.Language
273
+ || claimKey === DocumentReferenceClaim.Modality
274
+ || claimKey === DocumentReferenceClaim.Relation
275
+ || claimKey === DocumentReferenceClaim.Type) {
276
+ return 'token';
277
+ }
278
+ if (claimKey === ObservationClaim.ComponentNames) {
279
+ return 'string';
280
+ }
281
+ if ((claimKey === ObservationClaim.Identifier
282
+ || claimKey === ConditionClaim.Identifier
283
+ || claimKey === MedicationStatementClaim.Identifier
284
+ || claimKey === DocumentReferenceClaim.Identifier)
285
+ && typeof rawValue === 'string'
286
+ && /^urn:|^did:|^https?:/i.test(rawValue)) {
287
+ return 'uri';
288
+ }
289
+ return 'string';
290
+ }
291
+ /**
292
+ * Sanity guard to keep the indexable subset anchored to the broader claims
293
+ * lists declared by the interoperable-claims contract.
294
+ */
295
+ export function isAllowedObservationIndexableClaim(claimKey, variant) {
296
+ const fullList = variant === 'general' ? ObservationGeneralClaimsList : ObservationVitalSignsClaimsList;
297
+ const allowed = variant === 'general'
298
+ ? AllowedIndexableClaims[ResourceTypesFhirR4.Observation][IndexingClaimSet.General]
299
+ : AllowedIndexableClaims[ResourceTypesFhirR4.Observation][IndexingClaimSet.VitalSigns];
300
+ return fullList.some((item) => item === claimKey) && allowed.some((item) => item === claimKey);
301
+ }
@@ -22,3 +22,4 @@ export * from './related-person-claims';
22
22
  export * from './coverage-claims';
23
23
  export * from './clinical-impression-claims';
24
24
  export * from './task-claims';
25
+ export * from './invoice-claims';
@@ -24,3 +24,4 @@ export * from './related-person-claims.js';
24
24
  export * from './coverage-claims.js';
25
25
  export * from './clinical-impression-claims.js';
26
26
  export * from './task-claims.js';
27
+ export * from './invoice-claims.js';