@peerbits/fhir-validator 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @peerbits/fhir-validator
2
2
 
3
+ Version 1.1 validates Bundle structure and recursively validates bundled resources, including transaction/batch request details. Observation checks now cover periods, components, finite quantities, UCUM codes, and FHIR choice-field cardinality.
4
+
3
5
  > Fast, lightweight structural, cardinality, and reference validation for FHIR R4 resources.
4
6
 
5
7
  [![CI](https://github.com/PeerbitsSolution/fhir-validator/actions/workflows/ci.yml/badge.svg)](https://github.com/PeerbitsSolution/fhir-validator/actions)
@@ -49,7 +51,9 @@ npm install @peerbits/fhir-validator
49
51
 
50
52
  ---
51
53
 
52
- ## Quick Start
54
+ ## Demo and Quick Start
55
+
56
+ [Peerbits HealthTech - Fhir Validator Demo](https://healthcare.peerbits.com/demo/fhir-validator)
53
57
 
54
58
  ### 1. Validating a Resource
55
59
 
@@ -0,0 +1,2 @@
1
+ import type { ValidationIssue } from '../types.js';
2
+ export declare function validateBundle(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,41 @@
1
+ const BUNDLE_TYPES = ['document', 'message', 'transaction', 'transaction-response', 'batch', 'batch-response', 'history', 'searchset', 'collection'];
2
+ export function validateBundle(resource, path = 'Bundle') {
3
+ const issues = [];
4
+ if (resource.resourceType !== 'Bundle')
5
+ issues.push({ severity: 'error', path: `${path}.resourceType`, code: 'invalid-resource-type', message: "Expected resourceType 'Bundle'." });
6
+ if (typeof resource.type !== 'string' || !BUNDLE_TYPES.includes(resource.type)) {
7
+ issues.push({ severity: 'error', path: `${path}.type`, code: 'invalid-value', message: `Bundle.type must be one of: ${BUNDLE_TYPES.join(', ')}.` });
8
+ }
9
+ if (resource.entry !== undefined && !Array.isArray(resource.entry)) {
10
+ issues.push({ severity: 'error', path: `${path}.entry`, code: 'invalid-type', message: 'Bundle.entry must be an array.' });
11
+ }
12
+ if (Array.isArray(resource.entry)) {
13
+ resource.entry.forEach((entry, index) => {
14
+ const entryPath = `${path}.entry[${index}]`;
15
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
16
+ issues.push({ severity: 'error', path: entryPath, code: 'invalid-structure', message: 'Bundle entry must be an object.' });
17
+ return;
18
+ }
19
+ const value = entry;
20
+ if (!value.resource || typeof value.resource !== 'object' || Array.isArray(value.resource)) {
21
+ issues.push({ severity: 'error', path: `${entryPath}.resource`, code: 'required', message: 'Bundle entry requires a resource object.' });
22
+ }
23
+ if (resource.type === 'transaction' || resource.type === 'batch') {
24
+ if (!value.request || typeof value.request !== 'object' || Array.isArray(value.request)) {
25
+ issues.push({ severity: 'error', path: `${entryPath}.request`, code: 'required', message: `${resource.type} Bundle entry requires request.` });
26
+ }
27
+ else {
28
+ const request = value.request;
29
+ const methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'PATCH'];
30
+ if (typeof request.method !== 'string' || !methods.includes(request.method)) {
31
+ issues.push({ severity: 'error', path: `${entryPath}.request.method`, code: 'invalid-value', message: `Bundle request.method must be one of: ${methods.join(', ')}.` });
32
+ }
33
+ if (typeof request.url !== 'string' || !request.url.trim()) {
34
+ issues.push({ severity: 'error', path: `${entryPath}.request.url`, code: 'required', message: 'Bundle request.url must be a non-empty string.' });
35
+ }
36
+ }
37
+ }
38
+ });
39
+ }
40
+ return issues;
41
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 ClaimResponse resource.
4
+ */
5
+ export declare function validateClaimResponse(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,186 @@
1
+ import { validateCodeableConcept } from "../coding.js";
2
+ import { validateReference } from "../reference-rules.js";
3
+ const VALID_CLAIM_RESPONSE_STATUSES = ["active", "cancelled", "draft", "entered-in-error"];
4
+ const VALID_CLAIM_RESPONSE_USES = ["claim", "preauthorization", "predetermination"];
5
+ const VALID_CLAIM_RESPONSE_OUTCOMES = ["queued", "complete", "error", "partial"];
6
+ /**
7
+ * Validates base structural rules for FHIR R4 ClaimResponse resource.
8
+ */
9
+ export function validateClaimResponse(resource, path = "ClaimResponse") {
10
+ const issues = [];
11
+ if (resource.resourceType !== "ClaimResponse") {
12
+ issues.push({
13
+ severity: "error",
14
+ path: `${path}.resourceType`,
15
+ code: "invalid-resource-type",
16
+ message: `Expected resourceType 'ClaimResponse', found '${String(resource.resourceType)}'.`,
17
+ });
18
+ }
19
+ // status (Required)
20
+ if (resource.status === undefined || resource.status === null || resource.status === "") {
21
+ issues.push({
22
+ severity: "error",
23
+ path: `${path}.status`,
24
+ code: "required",
25
+ message: `Missing required 'status' in '${path}'.`,
26
+ });
27
+ }
28
+ else if (typeof resource.status !== "string" || !VALID_CLAIM_RESPONSE_STATUSES.includes(resource.status)) {
29
+ issues.push({
30
+ severity: "error",
31
+ path: `${path}.status`,
32
+ code: "invalid-value",
33
+ message: `Invalid ClaimResponse status '${String(resource.status)}'. Allowed values: ${VALID_CLAIM_RESPONSE_STATUSES.join(", ")}.`,
34
+ });
35
+ }
36
+ // type (Required CodeableConcept)
37
+ if (resource.type === undefined || resource.type === null) {
38
+ issues.push({
39
+ severity: "error",
40
+ path: `${path}.type`,
41
+ code: "required",
42
+ message: `Missing required 'type' in '${path}'.`,
43
+ });
44
+ }
45
+ else {
46
+ issues.push(...validateCodeableConcept(resource.type, `${path}.type`));
47
+ }
48
+ // use (Required enum: claim | preauthorization | predetermination)
49
+ if (resource.use === undefined || resource.use === null || resource.use === "") {
50
+ issues.push({
51
+ severity: "error",
52
+ path: `${path}.use`,
53
+ code: "required",
54
+ message: `Missing required 'use' in '${path}'.`,
55
+ });
56
+ }
57
+ else if (typeof resource.use !== "string" || !VALID_CLAIM_RESPONSE_USES.includes(resource.use)) {
58
+ issues.push({
59
+ severity: "error",
60
+ path: `${path}.use`,
61
+ code: "invalid-value",
62
+ message: `Invalid ClaimResponse use '${String(resource.use)}'. Allowed values: ${VALID_CLAIM_RESPONSE_USES.join(", ")}.`,
63
+ });
64
+ }
65
+ // patient (Required Reference: Patient)
66
+ if (resource.patient === undefined || resource.patient === null) {
67
+ issues.push({
68
+ severity: "error",
69
+ path: `${path}.patient`,
70
+ code: "required",
71
+ message: `Missing required 'patient' in '${path}'.`,
72
+ });
73
+ }
74
+ else {
75
+ issues.push(...validateReference(resource.patient, `${path}.patient`, ["Patient"]));
76
+ }
77
+ // created (Required string dateTime)
78
+ if (resource.created === undefined || resource.created === null || resource.created === "") {
79
+ issues.push({
80
+ severity: "error",
81
+ path: `${path}.created`,
82
+ code: "required",
83
+ message: `Missing required 'created' in '${path}'.`,
84
+ });
85
+ }
86
+ else if (typeof resource.created !== "string") {
87
+ issues.push({
88
+ severity: "error",
89
+ path: `${path}.created`,
90
+ code: "invalid-type",
91
+ message: `Expected '${path}.created' to be a string dateTime.`,
92
+ });
93
+ }
94
+ // insurer (Required Reference: Organization)
95
+ if (resource.insurer === undefined || resource.insurer === null) {
96
+ issues.push({
97
+ severity: "error",
98
+ path: `${path}.insurer`,
99
+ code: "required",
100
+ message: `Missing required 'insurer' in '${path}'.`,
101
+ });
102
+ }
103
+ else {
104
+ issues.push(...validateReference(resource.insurer, `${path}.insurer`, ["Organization"]));
105
+ }
106
+ // outcome (Required enum: queued | complete | error | partial)
107
+ if (resource.outcome === undefined || resource.outcome === null || resource.outcome === "") {
108
+ issues.push({
109
+ severity: "error",
110
+ path: `${path}.outcome`,
111
+ code: "required",
112
+ message: `Missing required 'outcome' in '${path}'.`,
113
+ });
114
+ }
115
+ else if (typeof resource.outcome !== "string" || !VALID_CLAIM_RESPONSE_OUTCOMES.includes(resource.outcome)) {
116
+ issues.push({
117
+ severity: "error",
118
+ path: `${path}.outcome`,
119
+ code: "invalid-value",
120
+ message: `Invalid ClaimResponse outcome '${String(resource.outcome)}'. Allowed values: ${VALID_CLAIM_RESPONSE_OUTCOMES.join(", ")}.`,
121
+ });
122
+ }
123
+ // request (Reference: Claim)
124
+ if (resource.request !== undefined) {
125
+ issues.push(...validateReference(resource.request, `${path}.request`, ["Claim"]));
126
+ }
127
+ // requestor (Reference: Practitioner | PractitionerRole | Organization)
128
+ if (resource.requestor !== undefined) {
129
+ issues.push(...validateReference(resource.requestor, `${path}.requestor`, ["Practitioner", "PractitionerRole", "Organization"]));
130
+ }
131
+ // insurance (Array)
132
+ if (resource.insurance !== undefined) {
133
+ if (!Array.isArray(resource.insurance)) {
134
+ issues.push({
135
+ severity: "error",
136
+ path: `${path}.insurance`,
137
+ code: "invalid-type",
138
+ message: `Expected '${path}.insurance' to be an array.`,
139
+ });
140
+ }
141
+ else {
142
+ resource.insurance.forEach((ins, idx) => {
143
+ const insPath = `${path}.insurance[${idx}]`;
144
+ if (typeof ins !== "object" || ins === null || Array.isArray(ins)) {
145
+ issues.push({
146
+ severity: "error",
147
+ path: insPath,
148
+ code: "invalid-structure",
149
+ message: `Expected '${insPath}' to be an object.`,
150
+ });
151
+ }
152
+ else {
153
+ const obj = ins;
154
+ if (typeof obj.sequence !== "number") {
155
+ issues.push({
156
+ severity: "error",
157
+ path: `${insPath}.sequence`,
158
+ code: "required",
159
+ message: `Missing or invalid 'sequence' number in '${insPath}'.`,
160
+ });
161
+ }
162
+ if (typeof obj.focal !== "boolean") {
163
+ issues.push({
164
+ severity: "error",
165
+ path: `${insPath}.focal`,
166
+ code: "required",
167
+ message: `Missing or invalid 'focal' boolean in '${insPath}'.`,
168
+ });
169
+ }
170
+ if (obj.coverage === undefined || obj.coverage === null) {
171
+ issues.push({
172
+ severity: "error",
173
+ path: `${insPath}.coverage`,
174
+ code: "required",
175
+ message: `Missing required 'coverage' reference in '${insPath}'.`,
176
+ });
177
+ }
178
+ else {
179
+ issues.push(...validateReference(obj.coverage, `${insPath}.coverage`, ["Coverage"]));
180
+ }
181
+ }
182
+ });
183
+ }
184
+ }
185
+ return issues;
186
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 Claim resource.
4
+ */
5
+ export declare function validateClaim(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,240 @@
1
+ import { validateCodeableConcept } from "../coding.js";
2
+ import { validateReference } from "../reference-rules.js";
3
+ const VALID_CLAIM_STATUSES = ["active", "cancelled", "draft", "entered-in-error"];
4
+ const VALID_CLAIM_USES = ["claim", "preauthorization", "predetermination"];
5
+ /**
6
+ * Validates base structural rules for FHIR R4 Claim resource.
7
+ */
8
+ export function validateClaim(resource, path = "Claim") {
9
+ const issues = [];
10
+ if (resource.resourceType !== "Claim") {
11
+ issues.push({
12
+ severity: "error",
13
+ path: `${path}.resourceType`,
14
+ code: "invalid-resource-type",
15
+ message: `Expected resourceType 'Claim', found '${String(resource.resourceType)}'.`,
16
+ });
17
+ }
18
+ // status (Required)
19
+ if (resource.status === undefined || resource.status === null || resource.status === "") {
20
+ issues.push({
21
+ severity: "error",
22
+ path: `${path}.status`,
23
+ code: "required",
24
+ message: `Missing required 'status' in '${path}'.`,
25
+ });
26
+ }
27
+ else if (typeof resource.status !== "string" || !VALID_CLAIM_STATUSES.includes(resource.status)) {
28
+ issues.push({
29
+ severity: "error",
30
+ path: `${path}.status`,
31
+ code: "invalid-value",
32
+ message: `Invalid Claim status '${String(resource.status)}'. Allowed values: ${VALID_CLAIM_STATUSES.join(", ")}.`,
33
+ });
34
+ }
35
+ // type (Required CodeableConcept)
36
+ if (resource.type === undefined || resource.type === null) {
37
+ issues.push({
38
+ severity: "error",
39
+ path: `${path}.type`,
40
+ code: "required",
41
+ message: `Missing required 'type' in '${path}'.`,
42
+ });
43
+ }
44
+ else {
45
+ issues.push(...validateCodeableConcept(resource.type, `${path}.type`));
46
+ }
47
+ // use (Required enum: claim | preauthorization | predetermination)
48
+ if (resource.use === undefined || resource.use === null || resource.use === "") {
49
+ issues.push({
50
+ severity: "error",
51
+ path: `${path}.use`,
52
+ code: "required",
53
+ message: `Missing required 'use' in '${path}'.`,
54
+ });
55
+ }
56
+ else if (typeof resource.use !== "string" || !VALID_CLAIM_USES.includes(resource.use)) {
57
+ issues.push({
58
+ severity: "error",
59
+ path: `${path}.use`,
60
+ code: "invalid-value",
61
+ message: `Invalid Claim use '${String(resource.use)}'. Allowed values: ${VALID_CLAIM_USES.join(", ")}.`,
62
+ });
63
+ }
64
+ // patient (Required Reference: Patient)
65
+ if (resource.patient === undefined || resource.patient === null) {
66
+ issues.push({
67
+ severity: "error",
68
+ path: `${path}.patient`,
69
+ code: "required",
70
+ message: `Missing required 'patient' in '${path}'.`,
71
+ });
72
+ }
73
+ else {
74
+ issues.push(...validateReference(resource.patient, `${path}.patient`, ["Patient"]));
75
+ }
76
+ // created (Required string dateTime)
77
+ if (resource.created === undefined || resource.created === null || resource.created === "") {
78
+ issues.push({
79
+ severity: "error",
80
+ path: `${path}.created`,
81
+ code: "required",
82
+ message: `Missing required 'created' in '${path}'.`,
83
+ });
84
+ }
85
+ else if (typeof resource.created !== "string") {
86
+ issues.push({
87
+ severity: "error",
88
+ path: `${path}.created`,
89
+ code: "invalid-type",
90
+ message: `Expected '${path}.created' to be a string dateTime.`,
91
+ });
92
+ }
93
+ // provider (Required Reference: Practitioner | PractitionerRole | Organization)
94
+ if (resource.provider === undefined || resource.provider === null) {
95
+ issues.push({
96
+ severity: "error",
97
+ path: `${path}.provider`,
98
+ code: "required",
99
+ message: `Missing required 'provider' in '${path}'.`,
100
+ });
101
+ }
102
+ else {
103
+ issues.push(...validateReference(resource.provider, `${path}.provider`, ["Practitioner", "PractitionerRole", "Organization"]));
104
+ }
105
+ // priority (Required CodeableConcept)
106
+ if (resource.priority === undefined || resource.priority === null) {
107
+ issues.push({
108
+ severity: "error",
109
+ path: `${path}.priority`,
110
+ code: "required",
111
+ message: `Missing required 'priority' in '${path}'.`,
112
+ });
113
+ }
114
+ else {
115
+ issues.push(...validateCodeableConcept(resource.priority, `${path}.priority`));
116
+ }
117
+ // insurer (Reference: Organization)
118
+ if (resource.insurer !== undefined) {
119
+ issues.push(...validateReference(resource.insurer, `${path}.insurer`, ["Organization"]));
120
+ }
121
+ // facility (Reference: Location)
122
+ if (resource.facility !== undefined) {
123
+ issues.push(...validateReference(resource.facility, `${path}.facility`, ["Location"]));
124
+ }
125
+ // insurance (Required array, min 1)
126
+ if (resource.insurance === undefined || resource.insurance === null) {
127
+ issues.push({
128
+ severity: "error",
129
+ path: `${path}.insurance`,
130
+ code: "required",
131
+ message: `Missing required 'insurance' in '${path}'.`,
132
+ });
133
+ }
134
+ else if (!Array.isArray(resource.insurance)) {
135
+ issues.push({
136
+ severity: "error",
137
+ path: `${path}.insurance`,
138
+ code: "invalid-type",
139
+ message: `Expected '${path}.insurance' to be an array, got ${typeof resource.insurance}.`,
140
+ });
141
+ }
142
+ else if (resource.insurance.length === 0) {
143
+ issues.push({
144
+ severity: "error",
145
+ path: `${path}.insurance`,
146
+ code: "cardinality",
147
+ message: `Expected at least 1 insurance element in '${path}.insurance', found 0.`,
148
+ });
149
+ }
150
+ else {
151
+ resource.insurance.forEach((ins, idx) => {
152
+ const insPath = `${path}.insurance[${idx}]`;
153
+ if (typeof ins !== "object" || ins === null || Array.isArray(ins)) {
154
+ issues.push({
155
+ severity: "error",
156
+ path: insPath,
157
+ code: "invalid-structure",
158
+ message: `Expected '${insPath}' to be an object.`,
159
+ });
160
+ }
161
+ else {
162
+ const obj = ins;
163
+ if (typeof obj.sequence !== "number") {
164
+ issues.push({
165
+ severity: "error",
166
+ path: `${insPath}.sequence`,
167
+ code: "required",
168
+ message: `Missing or invalid 'sequence' number in '${insPath}'.`,
169
+ });
170
+ }
171
+ if (typeof obj.focal !== "boolean") {
172
+ issues.push({
173
+ severity: "error",
174
+ path: `${insPath}.focal`,
175
+ code: "required",
176
+ message: `Missing or invalid 'focal' boolean in '${insPath}'.`,
177
+ });
178
+ }
179
+ if (obj.coverage === undefined || obj.coverage === null) {
180
+ issues.push({
181
+ severity: "error",
182
+ path: `${insPath}.coverage`,
183
+ code: "required",
184
+ message: `Missing required 'coverage' reference in '${insPath}'.`,
185
+ });
186
+ }
187
+ else {
188
+ issues.push(...validateReference(obj.coverage, `${insPath}.coverage`, ["Coverage"]));
189
+ }
190
+ }
191
+ });
192
+ }
193
+ // item (Array)
194
+ if (resource.item !== undefined) {
195
+ if (!Array.isArray(resource.item)) {
196
+ issues.push({
197
+ severity: "error",
198
+ path: `${path}.item`,
199
+ code: "invalid-type",
200
+ message: `Expected '${path}.item' to be an array, got ${typeof resource.item}.`,
201
+ });
202
+ }
203
+ else {
204
+ resource.item.forEach((it, idx) => {
205
+ const itPath = `${path}.item[${idx}]`;
206
+ if (typeof it !== "object" || it === null || Array.isArray(it)) {
207
+ issues.push({
208
+ severity: "error",
209
+ path: itPath,
210
+ code: "invalid-structure",
211
+ message: `Expected '${itPath}' to be an object.`,
212
+ });
213
+ }
214
+ else {
215
+ const itemObj = it;
216
+ if (typeof itemObj.sequence !== "number") {
217
+ issues.push({
218
+ severity: "error",
219
+ path: `${itPath}.sequence`,
220
+ code: "required",
221
+ message: `Missing or invalid 'sequence' number in '${itPath}'.`,
222
+ });
223
+ }
224
+ if (itemObj.productOrService === undefined || itemObj.productOrService === null) {
225
+ issues.push({
226
+ severity: "error",
227
+ path: `${itPath}.productOrService`,
228
+ code: "required",
229
+ message: `Missing required 'productOrService' in '${itPath}'.`,
230
+ });
231
+ }
232
+ else {
233
+ issues.push(...validateCodeableConcept(itemObj.productOrService, `${itPath}.productOrService`));
234
+ }
235
+ }
236
+ });
237
+ }
238
+ }
239
+ return issues;
240
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 Condition resource.
4
+ */
5
+ export declare function validateCondition(resource: Record<string, unknown>, path?: string): ValidationIssue[];
@@ -0,0 +1,78 @@
1
+ import { validateCodeableConcept } from "../coding.js";
2
+ import { validateReference } from "../reference-rules.js";
3
+ /**
4
+ * Validates base structural rules for FHIR R4 Condition resource.
5
+ */
6
+ export function validateCondition(resource, path = "Condition") {
7
+ const issues = [];
8
+ if (resource.resourceType !== "Condition") {
9
+ issues.push({
10
+ severity: "error",
11
+ path: `${path}.resourceType`,
12
+ code: "invalid-resource-type",
13
+ message: `Expected resourceType 'Condition', found '${String(resource.resourceType)}'.`,
14
+ });
15
+ }
16
+ // subject (Required Reference: Patient | Group)
17
+ if (resource.subject === undefined || resource.subject === null) {
18
+ issues.push({
19
+ severity: "error",
20
+ path: `${path}.subject`,
21
+ code: "required",
22
+ message: `Missing required 'subject' in '${path}'.`,
23
+ });
24
+ }
25
+ else {
26
+ issues.push(...validateReference(resource.subject, `${path}.subject`, ["Patient", "Group"]));
27
+ }
28
+ // clinicalStatus (CodeableConcept)
29
+ if (resource.clinicalStatus !== undefined) {
30
+ issues.push(...validateCodeableConcept(resource.clinicalStatus, `${path}.clinicalStatus`));
31
+ }
32
+ // verificationStatus (CodeableConcept)
33
+ if (resource.verificationStatus !== undefined) {
34
+ issues.push(...validateCodeableConcept(resource.verificationStatus, `${path}.verificationStatus`));
35
+ }
36
+ // category (CodeableConcept[])
37
+ if (resource.category !== undefined) {
38
+ if (!Array.isArray(resource.category)) {
39
+ issues.push({
40
+ severity: "error",
41
+ path: `${path}.category`,
42
+ code: "invalid-type",
43
+ message: `Expected '${path}.category' to be an array, got ${typeof resource.category}.`,
44
+ });
45
+ }
46
+ else {
47
+ resource.category.forEach((cat, idx) => {
48
+ issues.push(...validateCodeableConcept(cat, `${path}.category[${idx}]`));
49
+ });
50
+ }
51
+ }
52
+ // code (CodeableConcept)
53
+ if (resource.code !== undefined) {
54
+ issues.push(...validateCodeableConcept(resource.code, `${path}.code`));
55
+ }
56
+ // encounter (Reference: Encounter)
57
+ if (resource.encounter !== undefined) {
58
+ issues.push(...validateReference(resource.encounter, `${path}.encounter`, ["Encounter"]));
59
+ }
60
+ // recorder (Reference)
61
+ if (resource.recorder !== undefined) {
62
+ issues.push(...validateReference(resource.recorder, `${path}.recorder`, ["Practitioner", "PractitionerRole", "Patient", "RelatedPerson"]));
63
+ }
64
+ // asserter (Reference)
65
+ if (resource.asserter !== undefined) {
66
+ issues.push(...validateReference(resource.asserter, `${path}.asserter`, ["Practitioner", "PractitionerRole", "Patient", "RelatedPerson"]));
67
+ }
68
+ // recordedDate
69
+ if (resource.recordedDate !== undefined && typeof resource.recordedDate !== "string") {
70
+ issues.push({
71
+ severity: "error",
72
+ path: `${path}.recordedDate`,
73
+ code: "invalid-type",
74
+ message: `Expected '${path}.recordedDate' to be a string.`,
75
+ });
76
+ }
77
+ return issues;
78
+ }
@@ -0,0 +1,5 @@
1
+ import { ValidationIssue } from "../types.js";
2
+ /**
3
+ * Validates base structural rules for FHIR R4 Coverage resource.
4
+ */
5
+ export declare function validateCoverage(resource: Record<string, unknown>, path?: string): ValidationIssue[];