fhir-validator-wrapper 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/fhir-validator.js +58 -30
- package/package.json +3 -3
package/fhir-validator.js
CHANGED
|
@@ -7,14 +7,51 @@ const { URL } = require('url');
|
|
|
7
7
|
* Node.js wrapper for the FHIR Validator HTTP Service
|
|
8
8
|
*/
|
|
9
9
|
class FhirValidator {
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Create a new FHIR Validator instance
|
|
12
|
+
* @param {string} validatorJarPath - Path to the validator JAR file
|
|
13
|
+
* @param {Object} [logger] - Winston logger instance (optional)
|
|
14
|
+
*/
|
|
15
|
+
constructor(validatorJarPath, logger = null) {
|
|
11
16
|
this.validatorJarPath = validatorJarPath;
|
|
17
|
+
this.logger = logger; // Store the logger
|
|
12
18
|
this.process = null;
|
|
13
19
|
this.port = null;
|
|
14
20
|
this.baseUrl = null;
|
|
15
21
|
this.isReady = false;
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Set a logger after initialization
|
|
26
|
+
* @param {Object} logger - Winston logger instance
|
|
27
|
+
*/
|
|
28
|
+
setLogger(logger) {
|
|
29
|
+
this.logger = logger;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Log a message with the appropriate level
|
|
34
|
+
* @private
|
|
35
|
+
* @param {string} level - Log level ('info', 'error', 'warn')
|
|
36
|
+
* @param {string} message - Message to log
|
|
37
|
+
* @param {Object} [meta] - Optional metadata
|
|
38
|
+
*/
|
|
39
|
+
log(level, message, meta = {}) {
|
|
40
|
+
if (this.logger) {
|
|
41
|
+
// Use the Winston logger if available
|
|
42
|
+
this.logger[level](message, meta);
|
|
43
|
+
} else {
|
|
44
|
+
// Fall back to console
|
|
45
|
+
if (level === 'error') {
|
|
46
|
+
console.error(message, meta);
|
|
47
|
+
} else if (level === 'warn') {
|
|
48
|
+
console.warn(message, meta);
|
|
49
|
+
} else {
|
|
50
|
+
console.log(message, meta);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
18
55
|
/**
|
|
19
56
|
* Start the FHIR validator service
|
|
20
57
|
* @param {Object} config - Configuration object
|
|
@@ -54,7 +91,7 @@ class FhirValidator {
|
|
|
54
91
|
args.push('-ig', ig);
|
|
55
92
|
}
|
|
56
93
|
|
|
57
|
-
|
|
94
|
+
this.log('info', `Starting FHIR validator with command: java ${args.join(' ')}`);
|
|
58
95
|
|
|
59
96
|
// Spawn the Java process
|
|
60
97
|
this.process = spawn('java', args, {
|
|
@@ -63,12 +100,12 @@ class FhirValidator {
|
|
|
63
100
|
|
|
64
101
|
// Handle process events
|
|
65
102
|
this.process.on('error', (error) => {
|
|
66
|
-
|
|
103
|
+
this.log('error', 'Failed to start validator process:', error);
|
|
67
104
|
throw error;
|
|
68
105
|
});
|
|
69
106
|
|
|
70
107
|
this.process.on('exit', (code, signal) => {
|
|
71
|
-
|
|
108
|
+
this.log('info', `Validator process exited with code ${code} and signal ${signal}`);
|
|
72
109
|
this.cleanup();
|
|
73
110
|
});
|
|
74
111
|
|
|
@@ -79,18 +116,18 @@ class FhirValidator {
|
|
|
79
116
|
// Remove ANSI escape sequences (color codes, etc.)
|
|
80
117
|
const cleanLine = line.replace(/\u001b\[[0-9;]*m/g, '').trim();
|
|
81
118
|
if (cleanLine.length > 1) { // Only log non-empty lines
|
|
82
|
-
|
|
119
|
+
this.log('info', `Validator: ${cleanLine}`);
|
|
83
120
|
}
|
|
84
121
|
});
|
|
85
122
|
});
|
|
86
123
|
|
|
87
124
|
this.process.stderr.on('data', (data) => {
|
|
88
|
-
|
|
125
|
+
this.log('error', `Validator-err: ${data}`);
|
|
89
126
|
});
|
|
90
127
|
|
|
91
128
|
// Wait for the service to be ready
|
|
92
129
|
await this.waitForReady(timeout);
|
|
93
|
-
|
|
130
|
+
this.log('info', 'FHIR validator service is ready');
|
|
94
131
|
}
|
|
95
132
|
|
|
96
133
|
/**
|
|
@@ -100,7 +137,7 @@ class FhirValidator {
|
|
|
100
137
|
*/
|
|
101
138
|
async waitForReady(timeout) {
|
|
102
139
|
const startTime = Date.now();
|
|
103
|
-
|
|
140
|
+
|
|
104
141
|
while (Date.now() - startTime < timeout) {
|
|
105
142
|
try {
|
|
106
143
|
await this.healthCheck();
|
|
@@ -111,7 +148,7 @@ class FhirValidator {
|
|
|
111
148
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
112
149
|
}
|
|
113
150
|
}
|
|
114
|
-
|
|
151
|
+
|
|
115
152
|
throw new Error(`Validator service did not become ready within ${timeout}ms`);
|
|
116
153
|
}
|
|
117
154
|
|
|
@@ -181,7 +218,7 @@ class FhirValidator {
|
|
|
181
218
|
|
|
182
219
|
// Build query parameters
|
|
183
220
|
const queryParams = new URLSearchParams();
|
|
184
|
-
|
|
221
|
+
|
|
185
222
|
if (options.profiles && options.profiles.length > 0) {
|
|
186
223
|
queryParams.set('profiles', options.profiles.join(','));
|
|
187
224
|
}
|
|
@@ -216,11 +253,11 @@ class FhirValidator {
|
|
|
216
253
|
|
|
217
254
|
const req = http.request(requestOptions, (res) => {
|
|
218
255
|
let data = '';
|
|
219
|
-
|
|
256
|
+
|
|
220
257
|
res.on('data', (chunk) => {
|
|
221
258
|
data += chunk;
|
|
222
259
|
});
|
|
223
|
-
|
|
260
|
+
|
|
224
261
|
res.on('end', () => {
|
|
225
262
|
try {
|
|
226
263
|
const result = JSON.parse(data);
|
|
@@ -232,7 +269,7 @@ class FhirValidator {
|
|
|
232
269
|
});
|
|
233
270
|
|
|
234
271
|
req.on('error', reject);
|
|
235
|
-
|
|
272
|
+
|
|
236
273
|
req.setTimeout(30000, () => {
|
|
237
274
|
req.destroy();
|
|
238
275
|
reject(new Error('Validation request timeout'));
|
|
@@ -254,7 +291,7 @@ class FhirValidator {
|
|
|
254
291
|
if (!Buffer.isBuffer(resourceBytes)) {
|
|
255
292
|
throw new Error('resourceBytes must be a Buffer');
|
|
256
293
|
}
|
|
257
|
-
|
|
294
|
+
|
|
258
295
|
return this.validate(resourceBytes, options);
|
|
259
296
|
}
|
|
260
297
|
|
|
@@ -268,7 +305,7 @@ class FhirValidator {
|
|
|
268
305
|
if (typeof resourceObject !== 'object' || resourceObject === null) {
|
|
269
306
|
throw new Error('resourceObject must be an object');
|
|
270
307
|
}
|
|
271
|
-
|
|
308
|
+
|
|
272
309
|
return this.validate(resourceObject, options);
|
|
273
310
|
}
|
|
274
311
|
|
|
@@ -303,11 +340,11 @@ class FhirValidator {
|
|
|
303
340
|
|
|
304
341
|
const req = http.request(requestOptions, (res) => {
|
|
305
342
|
let data = '';
|
|
306
|
-
|
|
343
|
+
|
|
307
344
|
res.on('data', (chunk) => {
|
|
308
345
|
data += chunk;
|
|
309
346
|
});
|
|
310
|
-
|
|
347
|
+
|
|
311
348
|
res.on('end', () => {
|
|
312
349
|
try {
|
|
313
350
|
const result = JSON.parse(data);
|
|
@@ -319,7 +356,7 @@ class FhirValidator {
|
|
|
319
356
|
});
|
|
320
357
|
|
|
321
358
|
req.on('error', reject);
|
|
322
|
-
|
|
359
|
+
|
|
323
360
|
req.setTimeout(30000, () => {
|
|
324
361
|
req.destroy();
|
|
325
362
|
reject(new Error('Load IG request timeout'));
|
|
@@ -340,7 +377,7 @@ class FhirValidator {
|
|
|
340
377
|
|
|
341
378
|
return new Promise((resolve, reject) => {
|
|
342
379
|
const timeout = setTimeout(() => {
|
|
343
|
-
|
|
380
|
+
this.log('warn', 'Force killing validator process after timeout');
|
|
344
381
|
if (this.process && !this.process.killed) {
|
|
345
382
|
this.process.kill('SIGKILL');
|
|
346
383
|
}
|
|
@@ -359,17 +396,8 @@ class FhirValidator {
|
|
|
359
396
|
|
|
360
397
|
// Since Java process is blocking on System.in.read(), SIGTERM likely won't work
|
|
361
398
|
// Go straight to SIGKILL for immediate termination
|
|
362
|
-
|
|
399
|
+
this.log('info', 'Stopping validator process...');
|
|
363
400
|
this.process.kill('SIGKILL');
|
|
364
|
-
|
|
365
|
-
// Backup: try SIGTERM first, then SIGKILL after 2 seconds
|
|
366
|
-
// this.process.kill('SIGTERM');
|
|
367
|
-
// setTimeout(() => {
|
|
368
|
-
// if (this.process && !this.process.killed) {
|
|
369
|
-
// console.log('Escalating to SIGKILL...');
|
|
370
|
-
// this.process.kill('SIGKILL');
|
|
371
|
-
// }
|
|
372
|
-
// }, 2000);
|
|
373
401
|
});
|
|
374
402
|
}
|
|
375
403
|
|
|
@@ -393,4 +421,4 @@ class FhirValidator {
|
|
|
393
421
|
}
|
|
394
422
|
}
|
|
395
423
|
|
|
396
|
-
module.exports = FhirValidator;
|
|
424
|
+
module.exports = FhirValidator;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fhir-validator-wrapper",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Node.js wrapper for the HL7 FHIR Validator CLI",
|
|
5
5
|
"main": "fhir-validator.js",
|
|
6
6
|
"scripts": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|
|
29
|
-
"url": "https://github.com/FHIR/fhir-validator-wrapper.git"
|
|
29
|
+
"url": "git+https://github.com/FHIR/fhir-validator-wrapper.git"
|
|
30
30
|
},
|
|
31
31
|
"bugs": {
|
|
32
32
|
"url": "https://github.com/FHIR/fhir-validator-wrapper/issues"
|
|
@@ -41,4 +41,4 @@
|
|
|
41
41
|
"README.md",
|
|
42
42
|
"LICENSE"
|
|
43
43
|
]
|
|
44
|
-
}
|
|
44
|
+
}
|