fhirsmith 0.12.0 → 0.13.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/CHANGELOG.md +305 -0
- package/README.md +1 -1
- package/config-template.json +13 -0
- package/library/languages.js +191 -34
- package/library/path-safety.js +51 -0
- package/library/request-token.js +56 -0
- package/package.json +2 -2
- package/packages/packages.js +17 -118
- package/publisher/publisher.js +60 -30
- package/publisher/validation.js +15 -3
- package/server.js +12 -3
- package/translations/Messages.properties +1 -0
- package/tx/README.md +21 -0
- package/tx/cs/cs-api.js +30 -1
- package/tx/cs/cs-cs.js +1 -1
- package/tx/cs/cs-icd11.js +805 -0
- package/tx/cs/cs-lang.js +331 -85
- package/tx/cs/cs-loinc.js +45 -4
- package/tx/cs/cs-mimetypes.js +492 -21
- package/tx/cs/cs-snomed.js +38 -4
- package/tx/cs/cs-ucum.js +33 -3
- package/tx/cs/icd11-expressions.js +243 -0
- package/tx/importers/export-icd11-codesystem.js +823 -0
- package/tx/importers/icd11-schema.md +285 -0
- package/tx/importers/import-icd11.js +861 -0
- package/tx/importers/import-loinc.module.js +14 -7
- package/tx/importers/import-sct.module.js +10 -1
- package/tx/library/codesystem.js +21 -27
- package/tx/library/nesting-limit.js +79 -0
- package/tx/library/operation-outcome.js +97 -3
- package/tx/library/valueset.js +16 -20
- package/tx/library.js +23 -1
- package/tx/ocl/cache/cache-utils.cjs +5 -3
- package/tx/ocl/cs-ocl.cjs +73 -17
- package/tx/ocl/jobs/background-queue.cjs +6 -3
- package/tx/ocl/mappers/concept-mapper.cjs +9 -1
- package/tx/ocl/shared/patches.cjs +48 -1
- package/tx/ocl/vs-ocl.cjs +15 -13
- package/tx/sct/expressions.js +194 -17
- package/tx/tx.fhir.org.yml +2 -1
- package/tx/tx.js +15 -42
- package/tx/workers/batch-validate.js +6 -16
- package/tx/workers/batch.js +16 -28
- package/tx/workers/cache-control.js +6 -12
- package/tx/workers/closure.js +3 -8
- package/tx/workers/compare.js +6 -34
- package/tx/workers/expand.js +36 -45
- package/tx/workers/lookup.js +21 -39
- package/tx/workers/read.js +6 -40
- package/tx/workers/search.js +2 -8
- package/tx/workers/subsumes.js +58 -41
- package/tx/workers/translate.js +11 -17
- package/tx/workers/validate.js +76 -77
- package/tx/workers/worker.js +70 -1
- package/tx/xml/xml-base.js +243 -76
- package/tx/xversion/xv-valueset.js +39 -1
package/tx/ocl/cs-ocl.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs/promises');
|
|
2
2
|
const { AbstractCodeSystemProvider } = require('../cs/cs-provider-api');
|
|
3
3
|
const { CodeSystemProvider, CodeSystemFactoryProvider, CodeSystemContentMode, FilterExecutionContext } = require('../cs/cs-api');
|
|
4
|
+
const { BaseCSServices } = require('../cs/cs-base');
|
|
4
5
|
const { CodeSystem } = require('../library/codesystem');
|
|
5
6
|
const { SearchFilterText } = require('../library/designations');
|
|
6
7
|
const { PAGE_SIZE, CONCEPT_PAGE_SIZE, COLD_CACHE_FRESHNESS_MS, OCL_CODESYSTEM_MARKER_EXTENSION } = require('./shared/constants');
|
|
@@ -12,8 +13,10 @@ const { computeCodeSystemFingerprint } = require('./fingerprint/fingerprint');
|
|
|
12
13
|
const { OCLBackgroundJobQueue } = require('./jobs/background-queue');
|
|
13
14
|
const { OCLConceptFilterContext } = require('./model/concept-filter-context');
|
|
14
15
|
const { toConceptContext } = require('./mappers/concept-mapper');
|
|
15
|
-
const { patchSearchWorkerForOCLCodeFiltering } = require('./shared/patches');
|
|
16
|
+
const { patchSearchWorkerForOCLCodeFiltering, patchProviderForOCLFactorySync } = require('./shared/patches');
|
|
16
17
|
const regexUtilities = require("../../library/regex-utilities");
|
|
18
|
+
const Logger = require('../../library/logger');
|
|
19
|
+
const oclLog = Logger.getInstance().child({ module: 'ocl' });
|
|
17
20
|
|
|
18
21
|
patchSearchWorkerForOCLCodeFiltering();
|
|
19
22
|
|
|
@@ -66,17 +69,17 @@ class OCLCodeSystemProvider extends AbstractCodeSystemProvider {
|
|
|
66
69
|
this._initializePromise = (async () => {
|
|
67
70
|
try {
|
|
68
71
|
const sources = await this.#fetchSourcesForDiscovery();
|
|
69
|
-
|
|
72
|
+
oclLog.info(`Fetched ${sources.length} sources`);
|
|
70
73
|
|
|
71
74
|
const snapshot = this.#buildSourceSnapshot(sources);
|
|
72
75
|
this.#applySnapshot(snapshot);
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
oclLog.info(`Loaded ${this._codeSystemsByCanonical.size} code systems`);
|
|
75
78
|
this._initialized = true;
|
|
76
79
|
} catch (error) {
|
|
77
|
-
|
|
80
|
+
oclLog.error(`Initialization failed: ${error.message}`);
|
|
78
81
|
if (error.response) {
|
|
79
|
-
|
|
82
|
+
oclLog.error(`HTTP ${error.response.status}: ${error.response.statusText}`);
|
|
80
83
|
}
|
|
81
84
|
throw error;
|
|
82
85
|
}
|
|
@@ -149,9 +152,18 @@ class OCLCodeSystemProvider extends AbstractCodeSystemProvider {
|
|
|
149
152
|
const nextSnapshot = this.#buildSourceSnapshot(sources);
|
|
150
153
|
const changes = this.#diffSnapshots(this._sourceStateByCanonical, nextSnapshot);
|
|
151
154
|
this.#applySnapshot(nextSnapshot);
|
|
155
|
+
for (const cs of changes.added || []) {
|
|
156
|
+
const entry = nextSnapshot.get(cs.url);
|
|
157
|
+
if (entry?.meta && !OCLSourceCodeSystemFactory.hasFactory(cs.url, cs.version || null)) {
|
|
158
|
+
const factory = OCLSourceCodeSystemFactory.createForDiscoveredSource(this.httpClient, entry.meta);
|
|
159
|
+
if (factory) {
|
|
160
|
+
oclLog.info(`Factory created for newly discovered source: ${cs.url}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
152
164
|
this._pendingChanges = changes;
|
|
153
165
|
} catch (error) {
|
|
154
|
-
|
|
166
|
+
oclLog.error(`Incremental source refresh failed: ${error.message}`);
|
|
155
167
|
this._pendingChanges = this.#emptyChanges();
|
|
156
168
|
} finally {
|
|
157
169
|
this._refreshPromise = null;
|
|
@@ -326,7 +338,7 @@ class OCLCodeSystemProvider extends AbstractCodeSystemProvider {
|
|
|
326
338
|
const versionChanged = (previousEntry.cs.version || null) !== (nextEntry.cs.version || null);
|
|
327
339
|
if (checksumChanged || versionChanged) {
|
|
328
340
|
if (checksumChanged) {
|
|
329
|
-
|
|
341
|
+
oclLog.info(`CodeSystem checksum changed: ${canonicalUrl} (${previousChecksum} -> ${nextChecksum})`);
|
|
330
342
|
}
|
|
331
343
|
changed.push(nextEntry.cs);
|
|
332
344
|
}
|
|
@@ -553,8 +565,8 @@ class OCLCodeSystemProvider extends AbstractCodeSystemProvider {
|
|
|
553
565
|
const result = await fetchAllPages(this.httpClient, path, {
|
|
554
566
|
pageSize: PAGE_SIZE,
|
|
555
567
|
baseUrl: this.baseUrl,
|
|
556
|
-
logger:
|
|
557
|
-
loggerPrefix: '
|
|
568
|
+
logger: oclLog,
|
|
569
|
+
loggerPrefix: ''
|
|
558
570
|
});
|
|
559
571
|
// Extra check: payload must be object or array
|
|
560
572
|
if (!result || (typeof result !== 'object' && !Array.isArray(result))) {
|
|
@@ -563,8 +575,8 @@ class OCLCodeSystemProvider extends AbstractCodeSystemProvider {
|
|
|
563
575
|
return result;
|
|
564
576
|
} catch (error) {
|
|
565
577
|
if (error.response) {
|
|
566
|
-
|
|
567
|
-
|
|
578
|
+
oclLog.error(`HTTP ${error.response.status}: ${error.response.statusText}`);
|
|
579
|
+
oclLog.error(`Response: ${JSON.stringify(error.response.data)}`);
|
|
568
580
|
}
|
|
569
581
|
throw error;
|
|
570
582
|
}
|
|
@@ -586,7 +598,7 @@ class OCLCodeSystemProvider extends AbstractCodeSystemProvider {
|
|
|
586
598
|
}
|
|
587
599
|
}
|
|
588
600
|
|
|
589
|
-
class OCLSourceCodeSystemProvider extends
|
|
601
|
+
class OCLSourceCodeSystemProvider extends BaseCSServices {
|
|
590
602
|
constructor(opContext, supplements, client, meta, sharedCaches = null) {
|
|
591
603
|
super(opContext, supplements);
|
|
592
604
|
this.httpClient = client;
|
|
@@ -727,6 +739,36 @@ class OCLSourceCodeSystemProvider extends CodeSystemProvider {
|
|
|
727
739
|
}
|
|
728
740
|
}
|
|
729
741
|
|
|
742
|
+
async extendLookup(ctxt, props, params) {
|
|
743
|
+
const context = await this.#ensureContext(ctxt);
|
|
744
|
+
const extras = context && context.extras;
|
|
745
|
+
if (!extras || typeof extras !== 'object') {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
for (const [key, value] of Object.entries(extras)) {
|
|
749
|
+
if (!key || value === null || value === undefined) {
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
if (!this._hasProp(props, key, true)) {
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
const part = [{ name: 'code', valueCode: key }];
|
|
756
|
+
if (typeof value === 'boolean') {
|
|
757
|
+
part.push({ name: 'value', valueBoolean: value });
|
|
758
|
+
} else if (typeof value === 'number' && Number.isInteger(value)) {
|
|
759
|
+
part.push({ name: 'value', valueInteger: value });
|
|
760
|
+
} else if (typeof value === 'number' && Number.isFinite(value)) {
|
|
761
|
+
part.push({ name: 'value', valueDecimal: value });
|
|
762
|
+
} else if (typeof value === 'string') {
|
|
763
|
+
part.push({ name: 'value', valueString: value });
|
|
764
|
+
} else {
|
|
765
|
+
// Extras may hold arbitrary JSON (arrays, objects); serialize rather than drop data.
|
|
766
|
+
part.push({ name: 'value', valueString: JSON.stringify(value) });
|
|
767
|
+
}
|
|
768
|
+
params.push({ name: 'property', part });
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
730
772
|
async locate(code) {
|
|
731
773
|
if (!code || typeof code !== 'string') {
|
|
732
774
|
return { context: null, message: 'Empty code' };
|
|
@@ -1251,6 +1293,14 @@ class OCLSourceCodeSystemProvider extends CodeSystemProvider {
|
|
|
1251
1293
|
|
|
1252
1294
|
class OCLSourceCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
1253
1295
|
static factoriesByKey = new Map();
|
|
1296
|
+
static #sharedI18n = null;
|
|
1297
|
+
|
|
1298
|
+
static createForDiscoveredSource(httpClient, meta) {
|
|
1299
|
+
if (!OCLSourceCodeSystemFactory.#sharedI18n) {
|
|
1300
|
+
return null;
|
|
1301
|
+
}
|
|
1302
|
+
return new OCLSourceCodeSystemFactory(OCLSourceCodeSystemFactory.#sharedI18n, httpClient, meta);
|
|
1303
|
+
}
|
|
1254
1304
|
|
|
1255
1305
|
static #normalizeSystem(system) {
|
|
1256
1306
|
return normalizeCanonicalSystem(system);
|
|
@@ -1319,6 +1369,9 @@ class OCLSourceCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
|
1319
1369
|
|
|
1320
1370
|
constructor(i18n, client, meta) {
|
|
1321
1371
|
super(i18n);
|
|
1372
|
+
if (!OCLSourceCodeSystemFactory.#sharedI18n) {
|
|
1373
|
+
OCLSourceCodeSystemFactory.#sharedI18n = i18n;
|
|
1374
|
+
}
|
|
1322
1375
|
this.httpClient = client;
|
|
1323
1376
|
this.meta = meta;
|
|
1324
1377
|
this.sharedConceptCache = new Map();
|
|
@@ -1375,7 +1428,7 @@ class OCLSourceCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
|
1375
1428
|
|
|
1376
1429
|
} catch (error) {
|
|
1377
1430
|
if (error.code !== 'ENOENT') {
|
|
1378
|
-
|
|
1431
|
+
oclLog.error(`Failed to load cold cache for CodeSystem ${canonicalUrl}: ${error.message}`);
|
|
1379
1432
|
}
|
|
1380
1433
|
}
|
|
1381
1434
|
}
|
|
@@ -1402,7 +1455,7 @@ class OCLSourceCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
|
1402
1455
|
|
|
1403
1456
|
return fingerprint;
|
|
1404
1457
|
} catch (error) {
|
|
1405
|
-
|
|
1458
|
+
oclLog.error(`Failed to save cold cache for CodeSystem ${canonicalUrl}: ${error.message}`);
|
|
1406
1459
|
return null;
|
|
1407
1460
|
}
|
|
1408
1461
|
}
|
|
@@ -1542,9 +1595,9 @@ class OCLSourceCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
|
1542
1595
|
}
|
|
1543
1596
|
}
|
|
1544
1597
|
|
|
1545
|
-
|
|
1598
|
+
oclLog.info(`CodeSystem loaded: ${this.system()} (${count} concepts)`);
|
|
1546
1599
|
} catch (error) {
|
|
1547
|
-
|
|
1600
|
+
oclLog.error(`CodeSystem background load failed: ${key}: ${error.message}`);
|
|
1548
1601
|
}
|
|
1549
1602
|
}
|
|
1550
1603
|
|
|
@@ -1660,7 +1713,7 @@ class OCLSourceCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
|
1660
1713
|
this.meta.codeSystem.jsonObj.content = CodeSystemContentMode.NotPresent;
|
|
1661
1714
|
delete this.meta.codeSystem.jsonObj.concept;
|
|
1662
1715
|
}
|
|
1663
|
-
|
|
1716
|
+
oclLog.info(`CodeSystem checksum changed, invalidated warm cache: ${this.#resourceKey()}`);
|
|
1664
1717
|
}
|
|
1665
1718
|
}
|
|
1666
1719
|
|
|
@@ -1824,8 +1877,11 @@ class OCLSourceCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
|
1824
1877
|
}
|
|
1825
1878
|
}
|
|
1826
1879
|
|
|
1880
|
+
patchProviderForOCLFactorySync(() => OCLSourceCodeSystemFactory.factoriesByKey);
|
|
1881
|
+
|
|
1827
1882
|
module.exports = {
|
|
1828
1883
|
OCLCodeSystemProvider,
|
|
1884
|
+
OCLSourceCodeSystemProvider,
|
|
1829
1885
|
OCLSourceCodeSystemFactory,
|
|
1830
1886
|
OCLBackgroundJobQueue
|
|
1831
1887
|
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
const Logger = require('../../../library/logger');
|
|
2
|
+
const oclLog = Logger.getInstance().child({ module: 'ocl' });
|
|
3
|
+
|
|
1
4
|
class OCLBackgroundJobQueue {
|
|
2
5
|
static MAX_CONCURRENT = 2;
|
|
3
6
|
static HEARTBEAT_INTERVAL_MS = 30000;
|
|
@@ -42,7 +45,7 @@ class OCLBackgroundJobQueue {
|
|
|
42
45
|
.catch((error) => {
|
|
43
46
|
this.queuedOrRunningKeys.delete(jobKey);
|
|
44
47
|
const message = error && error.message ? error.message : String(error);
|
|
45
|
-
|
|
48
|
+
oclLog.error(`Failed to enqueue background job: ${jobType || 'background-job'} ${jobKey}: ${message}`);
|
|
46
49
|
});
|
|
47
50
|
|
|
48
51
|
return true;
|
|
@@ -125,7 +128,7 @@ class OCLBackgroundJobQueue {
|
|
|
125
128
|
lines.push(` progress: ${this.formatProgress(job.getProgress)}`);
|
|
126
129
|
});
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
oclLog.info(lines.join('\n'));
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
static formatProgress(getProgress) {
|
|
@@ -181,7 +184,7 @@ class OCLBackgroundJobQueue {
|
|
|
181
184
|
.then(() => job.runJob())
|
|
182
185
|
.catch((error) => {
|
|
183
186
|
const message = error && error.message ? error.message : String(error);
|
|
184
|
-
|
|
187
|
+
oclLog.error(`Background job failed: ${job.jobType} ${job.jobKey}: ${message}`);
|
|
185
188
|
})
|
|
186
189
|
.finally(() => {
|
|
187
190
|
this.activeCount -= 1;
|
|
@@ -8,13 +8,21 @@ function toConceptContext(concept) {
|
|
|
8
8
|
return null;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const ctx = {
|
|
12
12
|
code,
|
|
13
13
|
display: concept.display_name || concept.display || concept.name || null,
|
|
14
14
|
definition: concept.description || concept.definition || null,
|
|
15
15
|
retired: concept.retired === true,
|
|
16
16
|
designation: extractDesignations(concept)
|
|
17
17
|
};
|
|
18
|
+
|
|
19
|
+
const extras = concept.extras;
|
|
20
|
+
if (extras && typeof extras === 'object' && !Array.isArray(extras)
|
|
21
|
+
&& Object.keys(extras).length > 0) {
|
|
22
|
+
ctx.extras = extras;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return ctx;
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
function extractDesignations(concept) {
|
|
@@ -254,9 +254,56 @@ function patchValueSetExpandWholeSystemForOcl() {
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
|
|
257
|
+
const OCL_PROVIDER_FACTORY_SYNC_PATCH_FLAG = Symbol.for('fhirsmith.ocl.provider.factory-sync.patch');
|
|
258
|
+
|
|
259
|
+
function patchProviderForOCLFactorySync(getFactoriesByKey) {
|
|
260
|
+
let ProviderModule;
|
|
261
|
+
try {
|
|
262
|
+
ProviderModule = require('../../provider');
|
|
263
|
+
} catch (_error) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const Provider = ProviderModule?.Provider;
|
|
268
|
+
const proto = Provider?.prototype;
|
|
269
|
+
if (!proto || proto[OCL_PROVIDER_FACTORY_SYNC_PATCH_FLAG] === true) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (typeof proto.updateCodeSystemList !== 'function') {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const originalUpdateCodeSystemList = proto.updateCodeSystemList;
|
|
277
|
+
proto.updateCodeSystemList = async function patchedUpdateCodeSystemList() {
|
|
278
|
+
await originalUpdateCodeSystemList.call(this);
|
|
279
|
+
const factoriesByKey = getFactoriesByKey();
|
|
280
|
+
for (const factory of factoriesByKey.values()) {
|
|
281
|
+
if (!factory) continue;
|
|
282
|
+
const system = typeof factory.system === 'function' ? factory.system() : null;
|
|
283
|
+
if (!system) continue;
|
|
284
|
+
const ver = typeof factory.version === 'function' ? (factory.version() ?? '') : '';
|
|
285
|
+
const vurl = `${system}|${ver}`;
|
|
286
|
+
if (!this.codeSystemFactories.has(vurl)) {
|
|
287
|
+
if (!this.codeSystemFactories.has(system)) {
|
|
288
|
+
this.codeSystemFactories.set(system, factory);
|
|
289
|
+
}
|
|
290
|
+
this.codeSystemFactories.set(vurl, factory);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
Object.defineProperty(proto, OCL_PROVIDER_FACTORY_SYNC_PATCH_FLAG, {
|
|
296
|
+
value: true,
|
|
297
|
+
writable: false,
|
|
298
|
+
configurable: false,
|
|
299
|
+
enumerable: false
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
257
303
|
module.exports = {
|
|
258
304
|
patchSearchWorkerForOCLCodeFiltering,
|
|
259
305
|
ensureTxParametersHashIncludesFilter,
|
|
260
306
|
patchValueSetExpandWholeSystemForOcl,
|
|
261
|
-
normalizeFilterForCacheKey
|
|
307
|
+
normalizeFilterForCacheKey,
|
|
308
|
+
patchProviderForOCLFactorySync
|
|
262
309
|
};
|
package/tx/ocl/vs-ocl.cjs
CHANGED
|
@@ -13,6 +13,8 @@ const { CACHE_VS_DIR, getCacheFilePath } = require('./cache/cache-paths');
|
|
|
13
13
|
const { ensureCacheDirectories, getColdCacheAgeMs, formatCacheAgeMinutes } = require('./cache/cache-utils');
|
|
14
14
|
const { computeValueSetExpansionFingerprint } = require('./fingerprint/fingerprint');
|
|
15
15
|
const { ensureTxParametersHashIncludesFilter, patchValueSetExpandWholeSystemForOcl } = require('./shared/patches');
|
|
16
|
+
const Logger = require('../../library/logger');
|
|
17
|
+
const oclVsLog = Logger.getInstance().child({ module: 'ocl-vs' });
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
ensureTxParametersHashIncludesFilter(TxParameters);
|
|
@@ -122,16 +124,16 @@ class OCLValueSetProvider extends AbstractValueSetProvider {
|
|
|
122
124
|
this.valueSetFingerprints.set(cacheKey, cached.fingerprint || null);
|
|
123
125
|
loadedCount++;
|
|
124
126
|
} catch (error) {
|
|
125
|
-
|
|
127
|
+
oclVsLog.error(`Failed to load cold cache file ${file}: ${error.message}`);
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
if (loadedCount > 0) {
|
|
130
|
-
|
|
132
|
+
oclVsLog.info(`Loaded ${loadedCount} ValueSet expansions from cold cache`);
|
|
131
133
|
}
|
|
132
134
|
} catch (error) {
|
|
133
135
|
if (error.code !== 'ENOENT') {
|
|
134
|
-
|
|
136
|
+
oclVsLog.error(`Failed to load cold cache: ${error.message}`);
|
|
135
137
|
}
|
|
136
138
|
}
|
|
137
139
|
}
|
|
@@ -165,11 +167,11 @@ class OCLValueSetProvider extends AbstractValueSetProvider {
|
|
|
165
167
|
};
|
|
166
168
|
|
|
167
169
|
await fs.writeFile(cacheFilePath, JSON.stringify(cacheData, null, 2), 'utf-8');
|
|
168
|
-
|
|
170
|
+
oclVsLog.info(`Saved ValueSet compose to cold cache: ${canonicalUrl} (${conceptCount} concepts, fingerprint=${fingerprint?.substring(0, 8)})`);
|
|
169
171
|
|
|
170
172
|
return fingerprint;
|
|
171
173
|
} catch (error) {
|
|
172
|
-
|
|
174
|
+
oclVsLog.error(`Failed to save cold cache for ValueSet ${canonicalUrl}: ${error.message}`);
|
|
173
175
|
return null;
|
|
174
176
|
}
|
|
175
177
|
}
|
|
@@ -194,7 +196,7 @@ class OCLValueSetProvider extends AbstractValueSetProvider {
|
|
|
194
196
|
await this.#loadColdCacheForValueSets();
|
|
195
197
|
|
|
196
198
|
const collections = await this.#fetchCollectionsForDiscovery();
|
|
197
|
-
|
|
199
|
+
oclVsLog.info(`Fetched ${collections.length} collections`);
|
|
198
200
|
|
|
199
201
|
for (const collection of collections) {
|
|
200
202
|
const valueSet = this.#toValueSet(collection);
|
|
@@ -204,12 +206,12 @@ class OCLValueSetProvider extends AbstractValueSetProvider {
|
|
|
204
206
|
this.#indexValueSet(valueSet);
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
|
|
209
|
+
oclVsLog.info(`Loaded ${this.valueSetMap.size} value sets`);
|
|
208
210
|
this._initialized = true;
|
|
209
211
|
} catch (error) {
|
|
210
|
-
|
|
212
|
+
oclVsLog.error(`Initialization failed: ${error.message}`);
|
|
211
213
|
if (error.response) {
|
|
212
|
-
|
|
214
|
+
oclVsLog.error(`HTTP ${error.response.status}: ${error.response.statusText}`);
|
|
213
215
|
}
|
|
214
216
|
throw error;
|
|
215
217
|
}
|
|
@@ -1104,9 +1106,9 @@ class OCLValueSetProvider extends AbstractValueSetProvider {
|
|
|
1104
1106
|
// Ensure no stale inline expansion
|
|
1105
1107
|
delete vs.jsonObj.expansion;
|
|
1106
1108
|
|
|
1107
|
-
|
|
1109
|
+
oclVsLog.info(`compose cached: ${vs.url} (${conceptCount} concepts)`);
|
|
1108
1110
|
} catch (error) {
|
|
1109
|
-
|
|
1111
|
+
oclVsLog.error(`ValueSet background expansion failed: ${cacheKey}: ${error.message}`);
|
|
1110
1112
|
} finally {
|
|
1111
1113
|
this.backgroundExpansionProgress.delete(cacheKey);
|
|
1112
1114
|
}
|
|
@@ -1350,7 +1352,7 @@ class OCLValueSetProvider extends AbstractValueSetProvider {
|
|
|
1350
1352
|
|
|
1351
1353
|
this._organizationIdsFetchPromise = (async () => {
|
|
1352
1354
|
const endpoint = '/orgs/';
|
|
1353
|
-
|
|
1355
|
+
oclVsLog.info(`Loading organizations from: ${this.baseUrl}${endpoint}`);
|
|
1354
1356
|
const orgs = await this.#fetchAllPages(endpoint);
|
|
1355
1357
|
|
|
1356
1358
|
const ids = [];
|
|
@@ -1468,7 +1470,7 @@ class OCLValueSetProvider extends AbstractValueSetProvider {
|
|
|
1468
1470
|
this.pendingCollectionConceptPageRequests.delete(cacheKey);
|
|
1469
1471
|
}
|
|
1470
1472
|
} catch (error) {
|
|
1471
|
-
|
|
1473
|
+
oclVsLog.error(`#fetchConceptPage ERROR: ${error.message}`);
|
|
1472
1474
|
throw error;
|
|
1473
1475
|
}
|
|
1474
1476
|
}
|