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
@@ -1,5 +1,5 @@
1
1
  import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
2
- import { allergyIntoleranceFlatToFhirR4, appointmentFlatToFhirR4, carePlanFlatToFhirR4, clinicalImpressionFlatToFhirR4, compositionFlatToFhirR4, conditionFlatToFhirR4, convertFhirResourceToClaims, coverageFlatToFhirR4, deviceFlatToFhirR4, documentReferenceFlatToFhirR4, diagnosticReportFlatToFhirR4, encounterFlatToFhirR4, flagFlatToFhirR4, flatClaimsToFhirResource, immunizationFlatToFhirR4, locationFlatToFhirR4, medicationStatementFlatToFhirR4, observationFlatToFhirR4, organizationFlatToFhirR4, procedureFlatToFhirR4, relatedPersonFlatToFhirR4, } from './clinical-resource-converters.js';
2
+ import { allergyIntoleranceFlatToFhirR4, appointmentFlatToFhirR4, carePlanFlatToFhirR4, clinicalImpressionFlatToFhirR4, compositionFlatToFhirR4, conditionFlatToFhirR4, convertFhirResourceToClaims, coverageFlatToFhirR4, deviceFlatToFhirR4, documentReferenceFlatToFhirR4, diagnosticReportFlatToFhirR4, encounterFlatToFhirR4, flagFlatToFhirR4, flatClaimsToFhirResource, immunizationFlatToFhirR4, locationFlatToFhirR4, medicationStatementFlatToFhirR4, observationFromFlatToFhirR4, organizationFlatToFhirR4, procedureFlatToFhirR4, relatedPersonFlatToFhirR4, } from './clinical-resource-converters.js';
3
3
  function asTrimmedString(value) {
4
4
  if (value === undefined || value === null)
5
5
  return '';
@@ -59,6 +59,24 @@ function claimsToFlatStrings(claims) {
59
59
  }
60
60
  return out;
61
61
  }
62
+ function ensureClaimsIdentifier(claims, resource) {
63
+ const resourceType = asTrimmedString(resource?.resourceType);
64
+ const identifierKey = resourceType ? `${resourceType}.identifier` : '';
65
+ if (!identifierKey) {
66
+ return claims;
67
+ }
68
+ if (asTrimmedString(claims[identifierKey])) {
69
+ return claims;
70
+ }
71
+ const resourceId = asTrimmedString(resource?.id);
72
+ if (!resourceId) {
73
+ return claims;
74
+ }
75
+ return {
76
+ ...claims,
77
+ [identifierKey]: resourceId,
78
+ };
79
+ }
62
80
  function ensureResourceIdentifier(resource, claims, fallbackIndex) {
63
81
  const identifier = Object.entries(claims).find(([key]) => String(key).toLowerCase().endsWith('.identifier'))?.[1];
64
82
  const nextId = asTrimmedString(identifier) || `${resource.resourceType.toLowerCase()}-${fallbackIndex + 1}`;
@@ -111,7 +129,7 @@ export function convertClaimsToFhirResource(claims, version = 'r4') {
111
129
  case 'Location':
112
130
  return locationFlatToFhirR4(flatClaims);
113
131
  case 'Observation':
114
- return observationFlatToFhirR4(flatClaims);
132
+ return observationFromFlatToFhirR4(flatClaims);
115
133
  case 'Organization':
116
134
  return organizationFlatToFhirR4(flatClaims);
117
135
  case 'Procedure':
@@ -166,9 +184,9 @@ export function extractBundleDocumentClaimsList(bundle, context = 'org.hl7.fhir.
166
184
  .map((resource) => {
167
185
  const metaClaims = resource?.meta?.claims;
168
186
  if (metaClaims && typeof metaClaims === 'object' && !Array.isArray(metaClaims)) {
169
- return { ...metaClaims };
187
+ return ensureClaimsIdentifier({ ...metaClaims }, resource);
170
188
  }
171
- return convertFhirResourceToClaims(resource, context);
189
+ return ensureClaimsIdentifier(convertFhirResourceToClaims(resource, context), resource);
172
190
  });
173
191
  }
174
192
  export function resolveClaimsSectionList(claims) {
@@ -1,9 +1,12 @@
1
+ import { type CodingDescriptor } from '../constants/vital-signs';
1
2
  import { type BundleEntry, type BundleJsonApi, type BundleRequest } from '../models/bundle';
2
3
  import { buildEmployeePurgeBundle, buildEmployeeSearchBundle, EmployeeBundleOperations, EmployeeClaims } from './employee';
3
4
  export type BundleOperation = (typeof EmployeeBundleOperations)[keyof typeof EmployeeBundleOperations];
4
5
  export declare const BundleEditableResourceTypes: Readonly<{
5
6
  readonly employee: "Employee";
6
7
  readonly consent: "Consent";
8
+ readonly observation: "Observation";
9
+ readonly vitalSign: "Observation";
7
10
  }>;
8
11
  export type AllowedResourceType = string;
9
12
  export type BuiltBundleEntry = {
@@ -38,9 +41,32 @@ export declare class BundleEditor {
38
41
  private bundleOperation;
39
42
  private allowedResourceType;
40
43
  private readonly entries;
41
- /** Declares which business operation this bundle is staging. */
44
+ /**
45
+ * Declares which business action this in-memory bundle is staging.
46
+ *
47
+ * Important distinction:
48
+ * - this is **not** the same concept as FHIR `Bundle.entry.request.method`
49
+ * - this is the higher-level action the editor is helping to assemble, for
50
+ * example `create`, `search`, `disable`, or `purge`
51
+ * - the lower-level transport/request method may later be derived from that
52
+ * action, and may differ by backend contract
53
+ *
54
+ * Example:
55
+ * - bundle operation `disable`
56
+ * - current employee GW contract -> inner `entry.request.method = DELETE`
57
+ * - current individual organization GW contract -> explicit `/_disable`
58
+ * route with inner `entry.request.method = POST`
59
+ */
42
60
  setBundleOperation(operation: BundleOperation): this;
43
- /** Returns the current business operation assigned to the bundle. */
61
+ /**
62
+ * Returns the current high-level business action assigned to the bundle.
63
+ *
64
+ * Read this as:
65
+ * - "what am I trying to do?"
66
+ *
67
+ * not as:
68
+ * - "which HTTP/FHIR request method will the final entry use?"
69
+ */
44
70
  getBundleOperation(): BundleOperation | null;
45
71
  /**
46
72
  * Restricts the bundle to one resource type.
@@ -104,6 +130,10 @@ export declare class BundleEntryEditor {
104
130
  constructor(bundleEditor: BundleEditor, entryIndex: number);
105
131
  /** Opens the current entry as one employee-specific resource editor. */
106
132
  asEmployee(): EmployeeEntryEditor;
133
+ /** Opens the current entry as one vital-sign-specific Observation editor. */
134
+ asVitalSign(): VitalSignEntryEditor;
135
+ /** Opens the current entry as one general Observation editor. */
136
+ asObservation(): ObservationEntryEditor;
107
137
  /** Reads one claim from this entry. */
108
138
  getClaim(key: string): unknown;
109
139
  /** Checks whether this entry contains one claim key. */
@@ -127,6 +157,79 @@ export declare class BundleEntryEditor {
127
157
  protected getMutableEntry(): BuiltBundleEntry;
128
158
  protected getClaims(): EmployeeClaims;
129
159
  }
160
+ /**
161
+ * Reduced Observation component-style editor surface.
162
+ *
163
+ * This base layer owns the reusable code/value authoring helpers shared by
164
+ * Vital Signs and broader Observation entry editors.
165
+ */
166
+ export declare class ObservationComponentEntryEditor extends BundleEntryEditor {
167
+ setCode(code: CodingDescriptor | string): this;
168
+ getCode(): string | undefined;
169
+ setCodeSystem(system: string): this;
170
+ getCodeSystem(): string | undefined;
171
+ setCodeValue(value: string): this;
172
+ getCodeValue(): string | undefined;
173
+ setCodeDisplay(display: string): this;
174
+ getCodeDisplay(): string | undefined;
175
+ /** Local-language label intended for forms and local UI. */
176
+ setLocalText(text: string): this;
177
+ getLocalText(): string | undefined;
178
+ setValueQuantityNumber(value: number): this;
179
+ getValueQuantityNumber(): number | undefined;
180
+ setValueQuantityUnit(unit: CodingDescriptor | string): this;
181
+ getValueQuantityUnit(): string | undefined;
182
+ setValueString(value: string): this;
183
+ getValueString(): string | undefined;
184
+ setValueDate(value: string): this;
185
+ getValueDate(): string | undefined;
186
+ }
187
+ /**
188
+ * Vital-sign-specific editor surface for one staged Observation entry.
189
+ *
190
+ * This layer applies the visible/searchable Vital Signs claim contract on top
191
+ * of the reduced Observation component helpers.
192
+ */
193
+ export declare class VitalSignEntryEditor extends ObservationComponentEntryEditor {
194
+ setIdentifier(identifier?: string | null): this;
195
+ getIdentifier(): string | undefined;
196
+ ensureIdentifier(): string;
197
+ setSubject(subject: string): this;
198
+ getSubject(): string | undefined;
199
+ setStatus(status: string): this;
200
+ getStatus(): string | undefined;
201
+ setCategory(category: CodingDescriptor | string): this;
202
+ getCategory(): string | undefined;
203
+ setDate(date: string): this;
204
+ getDate(): string | undefined;
205
+ setNote(note: string): this;
206
+ getNote(): string | undefined;
207
+ setVitalSignType(code: CodingDescriptor, unit?: CodingDescriptor): this;
208
+ setHeartRate(value: number): this;
209
+ getHeartRate(): number | undefined;
210
+ setBodyTemperature(value: number): this;
211
+ getBodyTemperature(): number | undefined;
212
+ setSystolicBloodPressure(value: number): this;
213
+ getSystolicBloodPressure(): number | undefined;
214
+ setDiastolicBloodPressure(value: number): this;
215
+ getDiastolicBloodPressure(): number | undefined;
216
+ }
217
+ /**
218
+ * General Observation editor surface.
219
+ *
220
+ * This extends the Vital Sign editor so generic Observation rows can reuse the
221
+ * same code/date/value helpers while adding broader Observation references.
222
+ */
223
+ export declare class ObservationEntryEditor extends VitalSignEntryEditor {
224
+ setBasedOn(reference: string): this;
225
+ getBasedOn(): string | undefined;
226
+ setEncounter(reference: string): this;
227
+ getEncounter(): string | undefined;
228
+ setPerformer(reference: string): this;
229
+ getPerformer(): string | undefined;
230
+ setHasMember(reference: string): this;
231
+ getHasMember(): string | undefined;
232
+ }
130
233
  /**
131
234
  * Employee-specific editor for one staged bundle entry.
132
235
  *
@@ -1,9 +1,13 @@
1
1
  import { ClaimsPersonSchemaorg } from '../constants/schemaorg.js';
2
2
  import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
3
+ import { ObservationCategoryCodes, VitalSignsCodes, VitalSignsUnits } from '../constants/vital-signs.js';
4
+ import { ObservationClaim } from '../models/interoperable-claims/observation-claims.js';
3
5
  import { buildEmployeeBatchEntry, buildEmployeePurgeBundle, buildEmployeeSearchBundle, EmployeeBatchEntryTypes, EmployeeBundleMethods, EmployeeBundleOperations, EmployeeResourceTypes, } from './employee.js';
4
6
  export const BundleEditableResourceTypes = Object.freeze({
5
7
  employee: EmployeeResourceTypes.employee,
6
8
  consent: ResourceTypesFhirR4.Consent,
9
+ observation: ResourceTypesFhirR4.Observation,
10
+ vitalSign: ResourceTypesFhirR4.Observation,
7
11
  });
8
12
  function cloneEntry(value) {
9
13
  return JSON.parse(JSON.stringify(value));
@@ -75,12 +79,35 @@ export class BundleEditor {
75
79
  bundleOperation = null;
76
80
  allowedResourceType = null;
77
81
  entries = [];
78
- /** Declares which business operation this bundle is staging. */
82
+ /**
83
+ * Declares which business action this in-memory bundle is staging.
84
+ *
85
+ * Important distinction:
86
+ * - this is **not** the same concept as FHIR `Bundle.entry.request.method`
87
+ * - this is the higher-level action the editor is helping to assemble, for
88
+ * example `create`, `search`, `disable`, or `purge`
89
+ * - the lower-level transport/request method may later be derived from that
90
+ * action, and may differ by backend contract
91
+ *
92
+ * Example:
93
+ * - bundle operation `disable`
94
+ * - current employee GW contract -> inner `entry.request.method = DELETE`
95
+ * - current individual organization GW contract -> explicit `/_disable`
96
+ * route with inner `entry.request.method = POST`
97
+ */
79
98
  setBundleOperation(operation) {
80
99
  this.bundleOperation = operation;
81
100
  return this;
82
101
  }
83
- /** Returns the current business operation assigned to the bundle. */
102
+ /**
103
+ * Returns the current high-level business action assigned to the bundle.
104
+ *
105
+ * Read this as:
106
+ * - "what am I trying to do?"
107
+ *
108
+ * not as:
109
+ * - "which HTTP/FHIR request method will the final entry use?"
110
+ */
84
111
  getBundleOperation() {
85
112
  return this.bundleOperation;
86
113
  }
@@ -301,6 +328,22 @@ export class BundleEntryEditor {
301
328
  }
302
329
  return new EmployeeEntryEditor(this.bundleEditor, this.entryIndex);
303
330
  }
331
+ /** Opens the current entry as one vital-sign-specific Observation editor. */
332
+ asVitalSign() {
333
+ const entry = this.getMutableEntry();
334
+ if (entry.resource?.resourceType !== ResourceTypesFhirR4.Observation) {
335
+ throw new Error(`BundleEntryEditor cannot open this entry as VitalSign: ${String(entry.resource?.resourceType || '')}`);
336
+ }
337
+ return new VitalSignEntryEditor(this.bundleEditor, this.entryIndex);
338
+ }
339
+ /** Opens the current entry as one general Observation editor. */
340
+ asObservation() {
341
+ const entry = this.getMutableEntry();
342
+ if (entry.resource?.resourceType !== ResourceTypesFhirR4.Observation) {
343
+ throw new Error(`BundleEntryEditor cannot open this entry as Observation: ${String(entry.resource?.resourceType || '')}`);
344
+ }
345
+ return new ObservationEntryEditor(this.bundleEditor, this.entryIndex);
346
+ }
304
347
  /** Reads one claim from this entry. */
305
348
  getClaim(key) {
306
349
  return cloneClaimValue(this.getClaims()[String(key).trim()]);
@@ -397,6 +440,243 @@ export class BundleEntryEditor {
397
440
  };
398
441
  }
399
442
  }
443
+ /**
444
+ * Reduced Observation component-style editor surface.
445
+ *
446
+ * This base layer owns the reusable code/value authoring helpers shared by
447
+ * Vital Signs and broader Observation entry editors.
448
+ */
449
+ export class ObservationComponentEntryEditor extends BundleEntryEditor {
450
+ setCode(code) {
451
+ const token = typeof code === 'string' ? code.trim() : code.claim;
452
+ this.setClaim(ObservationClaim.Code, token);
453
+ if (typeof code !== 'string') {
454
+ this.setClaim(ObservationClaim.CodeSystem, code.system);
455
+ this.setClaim(ObservationClaim.CodeValue, code.code);
456
+ if (code.display) {
457
+ this.setClaim(ObservationClaim.CodeDisplay, code.display);
458
+ }
459
+ }
460
+ return this;
461
+ }
462
+ getCode() {
463
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Code));
464
+ }
465
+ setCodeSystem(system) {
466
+ return this.setClaim(ObservationClaim.CodeSystem, String(system).trim());
467
+ }
468
+ getCodeSystem() {
469
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.CodeSystem));
470
+ }
471
+ setCodeValue(value) {
472
+ return this.setClaim(ObservationClaim.CodeValue, String(value).trim());
473
+ }
474
+ getCodeValue() {
475
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.CodeValue));
476
+ }
477
+ setCodeDisplay(display) {
478
+ return this.setClaim(ObservationClaim.CodeDisplay, String(display).trim());
479
+ }
480
+ getCodeDisplay() {
481
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.CodeDisplay));
482
+ }
483
+ /** Local-language label intended for forms and local UI. */
484
+ setLocalText(text) {
485
+ return this.setClaim(ObservationClaim.CodeText, String(text).trim());
486
+ }
487
+ getLocalText() {
488
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.CodeText));
489
+ }
490
+ setValueQuantityNumber(value) {
491
+ return this.setClaim(ObservationClaim.ValueQuantityNumber, String(value));
492
+ }
493
+ getValueQuantityNumber() {
494
+ const raw = this.getClaim(ObservationClaim.ValueQuantityNumber);
495
+ if (raw === undefined || raw === null || raw === '')
496
+ return undefined;
497
+ const numeric = Number(raw);
498
+ return Number.isFinite(numeric) ? numeric : undefined;
499
+ }
500
+ setValueQuantityUnit(unit) {
501
+ const normalized = typeof unit === 'string' ? unit.trim() : unit.claim;
502
+ return this.setClaim(ObservationClaim.ValueQuantityUnit, normalized);
503
+ }
504
+ getValueQuantityUnit() {
505
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.ValueQuantityUnit));
506
+ }
507
+ setValueString(value) {
508
+ return this.setClaim(ObservationClaim.ValueString, String(value).trim());
509
+ }
510
+ getValueString() {
511
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.ValueString));
512
+ }
513
+ setValueDate(value) {
514
+ return this.setClaim(ObservationClaim.ValueDate, String(value).trim());
515
+ }
516
+ getValueDate() {
517
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.ValueDate));
518
+ }
519
+ }
520
+ /**
521
+ * Vital-sign-specific editor surface for one staged Observation entry.
522
+ *
523
+ * This layer applies the visible/searchable Vital Signs claim contract on top
524
+ * of the reduced Observation component helpers.
525
+ */
526
+ export class VitalSignEntryEditor extends ObservationComponentEntryEditor {
527
+ setIdentifier(identifier) {
528
+ const normalized = normalizeOptionalIdentifier(identifier);
529
+ if (!normalized) {
530
+ this.removeClaim(ObservationClaim.Identifier);
531
+ this.setResourceId(undefined);
532
+ this.setFullUrl(undefined);
533
+ return this;
534
+ }
535
+ this.setClaim(ObservationClaim.Identifier, normalized);
536
+ this.setResourceId(normalized);
537
+ this.setFullUrl(normalized);
538
+ return this;
539
+ }
540
+ getIdentifier() {
541
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Identifier)
542
+ || this.getResourceId()
543
+ || this.getFullUrl());
544
+ }
545
+ ensureIdentifier() {
546
+ const existing = this.getIdentifier();
547
+ if (existing)
548
+ return existing;
549
+ const generated = createCanonicalIdentifierUrn();
550
+ this.setIdentifier(generated);
551
+ return generated;
552
+ }
553
+ setSubject(subject) {
554
+ const normalized = String(subject).trim();
555
+ this.setClaim(ObservationClaim.Subject, normalized);
556
+ this.setClaim(ObservationClaim.Patient, normalized);
557
+ return this;
558
+ }
559
+ getSubject() {
560
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Subject)
561
+ || this.getClaim(ObservationClaim.Patient));
562
+ }
563
+ setStatus(status) {
564
+ return this.setClaim(ObservationClaim.Status, String(status).trim());
565
+ }
566
+ getStatus() {
567
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Status));
568
+ }
569
+ setCategory(category) {
570
+ const normalized = typeof category === 'string' ? category.trim() : category.claim;
571
+ return this.setClaim(ObservationClaim.Category, normalized);
572
+ }
573
+ getCategory() {
574
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Category));
575
+ }
576
+ setDate(date) {
577
+ const normalized = String(date).trim();
578
+ this.setClaim(ObservationClaim.Date, normalized);
579
+ this.setClaim(ObservationClaim.EffectiveDateTime, normalized);
580
+ return this;
581
+ }
582
+ getDate() {
583
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Date)
584
+ || this.getClaim(ObservationClaim.EffectiveDateTime));
585
+ }
586
+ setNote(note) {
587
+ return this.setClaim(ObservationClaim.Note, String(note).trim());
588
+ }
589
+ getNote() {
590
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Note));
591
+ }
592
+ setVitalSignType(code, unit) {
593
+ this.setCategory(ObservationCategoryCodes.VitalSigns);
594
+ this.setStatus(this.getStatus() || 'final');
595
+ this.setCode(code);
596
+ this.setCodeSystem(code.system);
597
+ this.setCodeValue(code.code);
598
+ if (code.display) {
599
+ this.setCodeDisplay(code.display);
600
+ this.setLocalText(code.display);
601
+ }
602
+ if (unit) {
603
+ this.setValueQuantityUnit(unit);
604
+ }
605
+ return this;
606
+ }
607
+ setHeartRate(value) {
608
+ return this
609
+ .setVitalSignType(VitalSignsCodes.HeartRate, VitalSignsUnits.BeatsPerMinute)
610
+ .setValueQuantityNumber(value);
611
+ }
612
+ getHeartRate() {
613
+ return this.getCodeValue() === VitalSignsCodes.HeartRate.code
614
+ ? this.getValueQuantityNumber()
615
+ : undefined;
616
+ }
617
+ setBodyTemperature(value) {
618
+ return this
619
+ .setVitalSignType(VitalSignsCodes.BodyTemperature, VitalSignsUnits.Celsius)
620
+ .setValueQuantityNumber(value);
621
+ }
622
+ getBodyTemperature() {
623
+ return this.getCodeValue() === VitalSignsCodes.BodyTemperature.code
624
+ ? this.getValueQuantityNumber()
625
+ : undefined;
626
+ }
627
+ setSystolicBloodPressure(value) {
628
+ return this
629
+ .setVitalSignType(VitalSignsCodes.SystolicBloodPressure, VitalSignsUnits.MillimeterOfMercury)
630
+ .setValueQuantityNumber(value);
631
+ }
632
+ getSystolicBloodPressure() {
633
+ return this.getCodeValue() === VitalSignsCodes.SystolicBloodPressure.code
634
+ ? this.getValueQuantityNumber()
635
+ : undefined;
636
+ }
637
+ setDiastolicBloodPressure(value) {
638
+ return this
639
+ .setVitalSignType(VitalSignsCodes.DiastolicBloodPressure, VitalSignsUnits.MillimeterOfMercury)
640
+ .setValueQuantityNumber(value);
641
+ }
642
+ getDiastolicBloodPressure() {
643
+ return this.getCodeValue() === VitalSignsCodes.DiastolicBloodPressure.code
644
+ ? this.getValueQuantityNumber()
645
+ : undefined;
646
+ }
647
+ }
648
+ /**
649
+ * General Observation editor surface.
650
+ *
651
+ * This extends the Vital Sign editor so generic Observation rows can reuse the
652
+ * same code/date/value helpers while adding broader Observation references.
653
+ */
654
+ export class ObservationEntryEditor extends VitalSignEntryEditor {
655
+ setBasedOn(reference) {
656
+ return this.setClaim(ObservationClaim.BasedOn, String(reference).trim());
657
+ }
658
+ getBasedOn() {
659
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.BasedOn));
660
+ }
661
+ setEncounter(reference) {
662
+ return this.setClaim(ObservationClaim.Encounter, String(reference).trim());
663
+ }
664
+ getEncounter() {
665
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Encounter));
666
+ }
667
+ setPerformer(reference) {
668
+ return this.setClaim(ObservationClaim.Performer, String(reference).trim());
669
+ }
670
+ getPerformer() {
671
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.Performer));
672
+ }
673
+ setHasMember(reference) {
674
+ return this.setClaim(ObservationClaim.HasMember, String(reference).trim());
675
+ }
676
+ getHasMember() {
677
+ return normalizeOptionalIdentifier(this.getClaim(ObservationClaim.HasMember));
678
+ }
679
+ }
400
680
  /**
401
681
  * Employee-specific editor for one staged bundle entry.
402
682
  *
@@ -7,7 +7,7 @@ export { deviceUseStatementFlatToFhirR4, deviceUseStatementFhirR4ToFlat, } from
7
7
  export { documentReferenceFlatToFhirR4, documentReferenceFhirR4ToFlat, } from '../convert/convert-document-reference';
8
8
  export { immunizationFlatToFhirR4, immunizationFhirR4ToFlat, } from '../convert/convert-immunization';
9
9
  export { locationFlatToFhirR4, locationFhirR4ToFlat, } from '../convert/convert-location';
10
- export { observationFlatToFhirR4, observationFhirR4ToFlat, } from '../convert/convert-observation';
10
+ export { observationFromFlatToFhirR4, observationToFlatFhirR4, observationFlatToFhirR4, observationFhirR4ToFlat, } from '../convert/convert-observation';
11
11
  export { organizationFlatToFhirR4, organizationFhirR4ToFlat, } from '../convert/convert-organization';
12
12
  export { procedureFlatToFhirR4, procedureFhirR4ToFlat, } from '../convert/convert-procedure';
13
13
  export { deviceFlatToFhirR4, deviceFhirR4ToFlat, } from '../convert/convert-device';
@@ -29,7 +29,7 @@ import { deviceUseStatementFhirR4ToFlat, deviceUseStatementFlatToFhirR4 } from '
29
29
  import { documentReferenceFhirR4ToFlat, documentReferenceFlatToFhirR4 } from '../convert/convert-document-reference';
30
30
  import { immunizationFhirR4ToFlat, immunizationFlatToFhirR4 } from '../convert/convert-immunization';
31
31
  import { locationFhirR4ToFlat, locationFlatToFhirR4 } from '../convert/convert-location';
32
- import { observationFhirR4ToFlat, observationFlatToFhirR4 } from '../convert/convert-observation';
32
+ import { observationFromFlatToFhirR4, observationToFlatFhirR4 } from '../convert/convert-observation';
33
33
  import { organizationFhirR4ToFlat, organizationFlatToFhirR4 } from '../convert/convert-organization';
34
34
  import { procedureFhirR4ToFlat, procedureFlatToFhirR4 } from '../convert/convert-procedure';
35
35
  import { deviceFhirR4ToFlat, deviceFlatToFhirR4 } from '../convert/convert-device';
@@ -57,8 +57,8 @@ export declare const immunizationFlatToFhir: typeof immunizationFlatToFhirR4;
57
57
  export declare const immunizationFhirToFlat: typeof immunizationFhirR4ToFlat;
58
58
  export declare const locationFlatToFhir: typeof locationFlatToFhirR4;
59
59
  export declare const locationFhirToFlat: typeof locationFhirR4ToFlat;
60
- export declare const observationFlatToFhir: typeof observationFlatToFhirR4;
61
- export declare const observationFhirToFlat: typeof observationFhirR4ToFlat;
60
+ export declare const observationFlatToFhir: typeof observationFromFlatToFhirR4;
61
+ export declare const observationFhirToFlat: typeof observationToFlatFhirR4;
62
62
  export declare const organizationFlatToFhir: typeof organizationFlatToFhirR4;
63
63
  export declare const organizationFhirToFlat: typeof organizationFhirR4ToFlat;
64
64
  export declare const procedureFlatToFhir: typeof procedureFlatToFhirR4;
@@ -8,7 +8,7 @@ export { deviceUseStatementFlatToFhirR4, deviceUseStatementFhirR4ToFlat, } from
8
8
  export { documentReferenceFlatToFhirR4, documentReferenceFhirR4ToFlat, } from '../convert/convert-document-reference.js';
9
9
  export { immunizationFlatToFhirR4, immunizationFhirR4ToFlat, } from '../convert/convert-immunization.js';
10
10
  export { locationFlatToFhirR4, locationFhirR4ToFlat, } from '../convert/convert-location.js';
11
- export { observationFlatToFhirR4, observationFhirR4ToFlat, } from '../convert/convert-observation.js';
11
+ export { observationFromFlatToFhirR4, observationToFlatFhirR4, observationFlatToFhirR4, observationFhirR4ToFlat, } from '../convert/convert-observation.js';
12
12
  export { organizationFlatToFhirR4, organizationFhirR4ToFlat, } from '../convert/convert-organization.js';
13
13
  export { procedureFlatToFhirR4, procedureFhirR4ToFlat, } from '../convert/convert-procedure.js';
14
14
  export { deviceFlatToFhirR4, deviceFhirR4ToFlat, } from '../convert/convert-device.js';
@@ -30,7 +30,7 @@ import { deviceUseStatementFhirR4ToFlat, deviceUseStatementFlatToFhirR4 } from '
30
30
  import { documentReferenceFhirR4ToFlat, documentReferenceFlatToFhirR4 } from '../convert/convert-document-reference.js';
31
31
  import { immunizationFhirR4ToFlat, immunizationFlatToFhirR4 } from '../convert/convert-immunization.js';
32
32
  import { locationFhirR4ToFlat, locationFlatToFhirR4 } from '../convert/convert-location.js';
33
- import { observationFhirR4ToFlat, observationFlatToFhirR4 } from '../convert/convert-observation.js';
33
+ import { observationFromFlatToFhirR4, observationToFlatFhirR4, } from '../convert/convert-observation.js';
34
34
  import { organizationFhirR4ToFlat, organizationFlatToFhirR4 } from '../convert/convert-organization.js';
35
35
  import { procedureFhirR4ToFlat, procedureFlatToFhirR4 } from '../convert/convert-procedure.js';
36
36
  import { deviceFhirR4ToFlat, deviceFlatToFhirR4 } from '../convert/convert-device.js';
@@ -58,8 +58,8 @@ export const immunizationFlatToFhir = immunizationFlatToFhirR4;
58
58
  export const immunizationFhirToFlat = immunizationFhirR4ToFlat;
59
59
  export const locationFlatToFhir = locationFlatToFhirR4;
60
60
  export const locationFhirToFlat = locationFhirR4ToFlat;
61
- export const observationFlatToFhir = observationFlatToFhirR4;
62
- export const observationFhirToFlat = observationFhirR4ToFlat;
61
+ export const observationFlatToFhir = observationFromFlatToFhirR4;
62
+ export const observationFhirToFlat = observationToFlatFhirR4;
63
63
  export const organizationFlatToFhir = organizationFlatToFhirR4;
64
64
  export const organizationFhirToFlat = organizationFhirR4ToFlat;
65
65
  export const procedureFlatToFhir = procedureFlatToFhirR4;
@@ -108,7 +108,7 @@ export function convertFhirResourceToClaims(resource, context = 'org.hl7.fhir.r4
108
108
  case 'Location':
109
109
  return locationFhirR4ToFlat(resource);
110
110
  case 'Observation':
111
- return observationFhirR4ToFlat(resource);
111
+ return observationToFlatFhirR4(resource);
112
112
  case 'Organization':
113
113
  return organizationFhirR4ToFlat(resource);
114
114
  case 'Procedure':
@@ -206,6 +206,17 @@ export declare class CommunicationAttachedBundleSession {
206
206
  type?: string;
207
207
  request?: BundleRequest;
208
208
  }>): this;
209
+ /**
210
+ * Observation helper for IPS-style and sectioned bundle authoring.
211
+ *
212
+ * Expected keys should come from Observation claims constants.
213
+ */
214
+ upsertActiveObservationEntry(input: Readonly<{
215
+ claims: Record<string, unknown>;
216
+ fullUrl?: string;
217
+ type?: string;
218
+ request?: BundleRequest;
219
+ }>): this;
209
220
  /**
210
221
  * AllergyIntolerance helper for IPS-in-Communication use cases.
211
222
  *
@@ -11,6 +11,7 @@ import { BundleQuery } from './bundle-query.js';
11
11
  import { addClaimValues } from '../claims/claim-list-helpers.js';
12
12
  import { detectDuplicateConsentRuleConflicts, } from './consent-duplicate-rules.js';
13
13
  import { MedicationStatementClaim, } from '../models/interoperable-claims/medication-statement-claims.js';
14
+ import { ObservationClaim } from '../models/interoperable-claims/observation-claims.js';
14
15
  export const ConsentEditorTargetKinds = Object.freeze({
15
16
  Section: 'section',
16
17
  ResourceType: 'resource-type',
@@ -235,6 +236,22 @@ export class CommunicationAttachedBundleSession {
235
236
  request: input.request,
236
237
  });
237
238
  }
239
+ /**
240
+ * Observation helper for IPS-style and sectioned bundle authoring.
241
+ *
242
+ * Expected keys should come from Observation claims constants.
243
+ */
244
+ upsertActiveObservationEntry(input) {
245
+ return this.upsertActiveEntry({
246
+ resourceType: ResourceTypesFhirR4.Observation,
247
+ claims: {
248
+ ...input.claims,
249
+ },
250
+ fullUrl: input.fullUrl,
251
+ type: input.type,
252
+ request: input.request,
253
+ });
254
+ }
238
255
  /**
239
256
  * AllergyIntolerance helper for IPS-in-Communication use cases.
240
257
  *
@@ -439,6 +456,10 @@ export class CommunicationAttachedBundleSession {
439
456
  if (documentReferenceSubject) {
440
457
  return documentReferenceSubject;
441
458
  }
459
+ const observationSubject = asTrimmedString(claims[ObservationClaim.Subject] || claims[ObservationClaim.Patient]);
460
+ if (observationSubject) {
461
+ return observationSubject;
462
+ }
442
463
  }
443
464
  const fromClaims = asTrimmedString(this.communicationClaims[CommunicationClaim.Subject]);
444
465
  return fromClaims || undefined;
@@ -481,6 +502,10 @@ export class CommunicationAttachedBundleSession {
481
502
  if (documentReferenceIdentifier) {
482
503
  return `${ResourceTypesFhirR4.DocumentReference}:${documentReferenceIdentifier}`;
483
504
  }
505
+ const observationIdentifier = asTrimmedString(claims[ObservationClaim.Identifier]);
506
+ if (observationIdentifier) {
507
+ return `${ResourceTypesFhirR4.Observation}:${observationIdentifier}`;
508
+ }
484
509
  return '';
485
510
  }
486
511
  createBundleEntry(input) {
@@ -522,6 +547,10 @@ export class CommunicationAttachedBundleSession {
522
547
  if (documentReferenceIdentifier) {
523
548
  return documentReferenceIdentifier;
524
549
  }
550
+ const observationIdentifier = asTrimmedString(claims[ObservationClaim.Identifier]);
551
+ if (observationIdentifier) {
552
+ return observationIdentifier;
553
+ }
525
554
  const communicationIdentifier = asTrimmedString(claims[CommunicationClaim.Identifier]);
526
555
  if (communicationIdentifier) {
527
556
  return communicationIdentifier;