fhirsmith 0.8.6 → 0.9.1

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.
@@ -37,9 +37,9 @@ class ValueSetDatabase {
37
37
  if (!hasCol) {
38
38
  migrations.push(new Promise((res, rej) => {
39
39
  db.run(
40
- "ALTER TABLE valuesets ADD COLUMN date_first_seen INTEGER DEFAULT 0",
41
- [],
42
- (err) => err ? rej(err) : res()
40
+ "ALTER TABLE valuesets ADD COLUMN date_first_seen INTEGER DEFAULT 0",
41
+ [],
42
+ (err) => err ? rej(err) : res()
43
43
  );
44
44
  }));
45
45
  }
@@ -47,13 +47,22 @@ class ValueSetDatabase {
47
47
  migrations.push(new Promise((res, rej) => {
48
48
  db.run(`
49
49
  CREATE TABLE IF NOT EXISTS vsac_runs (
50
- id INTEGER PRIMARY KEY AUTOINCREMENT,
51
- started_at INTEGER NOT NULL,
52
- finished_at INTEGER,
53
- status TEXT NOT NULL DEFAULT 'running',
54
- error_message TEXT,
55
- total_fetched INTEGER,
56
- total_new INTEGER
50
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
51
+ started_at INTEGER NOT NULL,
52
+ finished_at INTEGER,
53
+ status TEXT NOT NULL DEFAULT 'running',
54
+ error_message TEXT,
55
+ total_fetched INTEGER,
56
+ total_new INTEGER
57
+ )
58
+ `, [], (err) => err ? rej(err) : res());
59
+ }));
60
+ // Ensure vsac_settings table exists (for _lastUpdated tracking etc.)
61
+ migrations.push(new Promise((res, rej) => {
62
+ db.run(`
63
+ CREATE TABLE IF NOT EXISTS vsac_settings (
64
+ key TEXT PRIMARY KEY,
65
+ value TEXT
57
66
  )
58
67
  `, [], (err) => err ? rej(err) : res());
59
68
  }));
@@ -170,69 +179,77 @@ class ValueSetDatabase {
170
179
  db.serialize(() => {
171
180
  // Main value sets table
172
181
  db.run(`
173
- CREATE TABLE valuesets (
174
- id TEXT PRIMARY KEY,
175
- url TEXT,
176
- version TEXT,
177
- date TEXT,
178
- description TEXT,
179
- effectivePeriod_start TEXT,
180
- effectivePeriod_end TEXT,
181
- expansion_identifier TEXT,
182
- name TEXT,
183
- publisher TEXT,
184
- status TEXT,
185
- title TEXT,
186
- content TEXT NOT NULL,
187
- last_seen INTEGER DEFAULT (strftime('%s', 'now')),
188
- date_first_seen INTEGER DEFAULT (strftime('%s', 'now'))
189
- )
182
+ CREATE TABLE valuesets (
183
+ id TEXT PRIMARY KEY,
184
+ url TEXT,
185
+ version TEXT,
186
+ date TEXT,
187
+ description TEXT,
188
+ effectivePeriod_start TEXT,
189
+ effectivePeriod_end TEXT,
190
+ expansion_identifier TEXT,
191
+ name TEXT,
192
+ publisher TEXT,
193
+ status TEXT,
194
+ title TEXT,
195
+ content TEXT NOT NULL,
196
+ last_seen INTEGER DEFAULT (strftime('%s', 'now')),
197
+ date_first_seen INTEGER DEFAULT (strftime('%s', 'now'))
198
+ )
190
199
  `);
191
200
 
192
201
  // Identifiers table (0..* Identifier)
193
202
  db.run(`
194
- CREATE TABLE valueset_identifiers (
195
- valueset_id TEXT,
196
- system TEXT,
197
- value TEXT,
198
- use_code TEXT,
199
- type_system TEXT,
200
- type_code TEXT,
201
- FOREIGN KEY (valueset_id) REFERENCES valuesets(url)
202
- )
203
+ CREATE TABLE valueset_identifiers (
204
+ valueset_id TEXT,
205
+ system TEXT,
206
+ value TEXT,
207
+ use_code TEXT,
208
+ type_system TEXT,
209
+ type_code TEXT,
210
+ FOREIGN KEY (valueset_id) REFERENCES valuesets(url)
211
+ )
203
212
  `);
204
213
 
205
214
  // Jurisdictions table (0..* CodeableConcept with 0..* Coding)
206
215
  db.run(`
207
- CREATE TABLE valueset_jurisdictions (
208
- valueset_id TEXT,
209
- system TEXT,
210
- code TEXT,
211
- display TEXT,
212
- FOREIGN KEY (valueset_id) REFERENCES valuesets(url)
213
- )
216
+ CREATE TABLE valueset_jurisdictions (
217
+ valueset_id TEXT,
218
+ system TEXT,
219
+ code TEXT,
220
+ display TEXT,
221
+ FOREIGN KEY (valueset_id) REFERENCES valuesets(url)
222
+ )
214
223
  `);
215
224
 
216
225
  // Systems table (from compose.include[].system)
217
226
  db.run(`
218
- CREATE TABLE valueset_systems (
219
- valueset_id TEXT,
220
- system TEXT,
221
- version TEXT,
222
- FOREIGN KEY (valueset_id) REFERENCES valuesets(url)
223
- )
227
+ CREATE TABLE valueset_systems (
228
+ valueset_id TEXT,
229
+ system TEXT,
230
+ version TEXT,
231
+ FOREIGN KEY (valueset_id) REFERENCES valuesets(url)
232
+ )
224
233
  `);
225
234
 
226
235
  // Run tracking table
227
236
  db.run(`
228
- CREATE TABLE vsac_runs (
229
- id INTEGER PRIMARY KEY AUTOINCREMENT,
230
- started_at INTEGER NOT NULL,
231
- finished_at INTEGER,
232
- status TEXT NOT NULL DEFAULT 'running',
233
- error_message TEXT,
234
- total_fetched INTEGER,
235
- total_new INTEGER
237
+ CREATE TABLE vsac_runs (
238
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
239
+ started_at INTEGER NOT NULL,
240
+ finished_at INTEGER,
241
+ status TEXT NOT NULL DEFAULT 'running',
242
+ error_message TEXT,
243
+ total_fetched INTEGER,
244
+ total_new INTEGER
245
+ )
246
+ `);
247
+
248
+ // Settings table (key-value store for _lastUpdated tracking etc.)
249
+ db.run(`
250
+ CREATE TABLE IF NOT EXISTS vsac_settings (
251
+ key TEXT PRIMARY KEY,
252
+ value TEXT
236
253
  )
237
254
  `);
238
255
 
@@ -271,9 +288,9 @@ class ValueSetDatabase {
271
288
  const db = await this._getWriteConnection();
272
289
  return new Promise((resolve, reject) => {
273
290
  db.run(
274
- `INSERT INTO vsac_runs (started_at, status) VALUES (strftime('%s','now'), 'running')`,
275
- [],
276
- function(err) { err ? reject(err) : resolve(this.lastID); }
291
+ `INSERT INTO vsac_runs (started_at, status) VALUES (strftime('%s','now'), 'running')`,
292
+ [],
293
+ function(err) { err ? reject(err) : resolve(this.lastID); }
277
294
  );
278
295
  });
279
296
  }
@@ -289,10 +306,10 @@ class ValueSetDatabase {
289
306
  const db = await this._getWriteConnection();
290
307
  return new Promise((resolve, reject) => {
291
308
  db.run(
292
- `UPDATE vsac_runs SET finished_at = strftime('%s','now'), status = 'ok',
293
- total_fetched = ?, total_new = ? WHERE id = ?`,
294
- [totalFetched, totalNew, id],
295
- err => err ? reject(err) : resolve()
309
+ `UPDATE vsac_runs SET finished_at = strftime('%s','now'), status = 'ok',
310
+ total_fetched = ?, total_new = ? WHERE id = ?`,
311
+ [totalFetched, totalNew, id],
312
+ err => err ? reject(err) : resolve()
296
313
  );
297
314
  });
298
315
  }
@@ -307,10 +324,43 @@ class ValueSetDatabase {
307
324
  const db = await this._getWriteConnection();
308
325
  return new Promise((resolve, reject) => {
309
326
  db.run(
310
- `UPDATE vsac_runs SET finished_at = strftime('%s','now'), status = 'error',
311
- error_message = ? WHERE id = ?`,
312
- [errorMessage, id],
313
- err => err ? reject(err) : resolve()
327
+ `UPDATE vsac_runs SET finished_at = strftime('%s','now'), status = 'error',
328
+ error_message = ? WHERE id = ?`,
329
+ [errorMessage, id],
330
+ err => err ? reject(err) : resolve()
331
+ );
332
+ });
333
+ }
334
+
335
+ /**
336
+ * Get a setting value from the vsac_settings table
337
+ * @param {string} key - The setting key
338
+ * @returns {Promise<string|null>} The setting value, or null if not found
339
+ */
340
+ async getSetting(key) {
341
+ const db = await this._getReadConnection();
342
+ return new Promise((resolve, reject) => {
343
+ db.get('SELECT value FROM vsac_settings WHERE key = ?', [key], (err, row) => {
344
+ if (err) reject(err);
345
+ else resolve(row ? row.value : null);
346
+ });
347
+ });
348
+ }
349
+
350
+ /**
351
+ * Set a setting value in the vsac_settings table
352
+ * @param {string} key - The setting key
353
+ * @param {string} value - The setting value
354
+ * @returns {Promise<void>}
355
+ */
356
+ async setSetting(key, value) {
357
+ const db = await this._getWriteConnection();
358
+ return new Promise((resolve, reject) => {
359
+ db.run(
360
+ `INSERT INTO vsac_settings (key, value) VALUES (?, ?)
361
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
362
+ [key, value],
363
+ err => err ? reject(err) : resolve()
314
364
  );
315
365
  });
316
366
  }
@@ -353,24 +403,24 @@ class ValueSetDatabase {
353
403
  const expansionId = valueSet.expansion?.identifier || null;
354
404
 
355
405
  db.run(`
356
- INSERT INTO valuesets (
357
- id, url, version, date, description, effectivePeriod_start, effectivePeriod_end,
358
- expansion_identifier, name, publisher, status, title, content, last_seen, date_first_seen
359
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, strftime('%s', 'now'), strftime('%s', 'now'))
360
- ON CONFLICT(id) DO UPDATE SET
361
- url=excluded.url,
362
- version=excluded.version,
363
- date=excluded.date,
364
- description=excluded.description,
365
- effectivePeriod_start=excluded.effectivePeriod_start,
366
- effectivePeriod_end=excluded.effectivePeriod_end,
367
- expansion_identifier=excluded.expansion_identifier,
368
- name=excluded.name,
369
- publisher=excluded.publisher,
370
- status=excluded.status,
371
- title=excluded.title,
372
- content=excluded.content,
373
- last_seen=strftime('%s', 'now')
406
+ INSERT INTO valuesets (
407
+ id, url, version, date, description, effectivePeriod_start, effectivePeriod_end,
408
+ expansion_identifier, name, publisher, status, title, content, last_seen, date_first_seen
409
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, strftime('%s', 'now'), strftime('%s', 'now'))
410
+ ON CONFLICT(id) DO UPDATE SET
411
+ url=excluded.url,
412
+ version=excluded.version,
413
+ date=excluded.date,
414
+ description=excluded.description,
415
+ effectivePeriod_start=excluded.effectivePeriod_start,
416
+ effectivePeriod_end=excluded.effectivePeriod_end,
417
+ expansion_identifier=excluded.expansion_identifier,
418
+ name=excluded.name,
419
+ publisher=excluded.publisher,
420
+ status=excluded.status,
421
+ title=excluded.title,
422
+ content=excluded.content,
423
+ last_seen=strftime('%s', 'now')
374
424
  `, [
375
425
  valueSet.id,
376
426
  valueSet.url,
@@ -414,10 +464,10 @@ class ValueSetDatabase {
414
464
 
415
465
  return new Promise((resolve, reject) => {
416
466
  db.run(`
417
- update valuesets
418
- set last_seen = strftime('%s', 'now')
419
- where url = ?
420
- and version = ?
467
+ update valuesets
468
+ set last_seen = strftime('%s', 'now')
469
+ where url = ?
470
+ and version = ?
421
471
  `, [
422
472
  valueSet.url,
423
473
  valueSet.version
@@ -466,9 +516,9 @@ class ValueSetDatabase {
466
516
  const typeCode = id.type?.coding?.[0]?.code || null;
467
517
 
468
518
  db.run(`
469
- INSERT INTO valueset_identifiers (
470
- valueset_id, system, value, use_code, type_system, type_code
471
- ) VALUES (?, ?, ?, ?, ?, ?)
519
+ INSERT INTO valueset_identifiers (
520
+ valueset_id, system, value, use_code, type_system, type_code
521
+ ) VALUES (?, ?, ?, ?, ?, ?)
472
522
  `, [
473
523
  valueSet.id,
474
524
  id.system || null,
@@ -490,9 +540,9 @@ class ValueSetDatabase {
490
540
  for (const coding of jurisdiction.coding) {
491
541
  pendingOperations++;
492
542
  db.run(`
493
- INSERT INTO valueset_jurisdictions (
494
- valueset_id, system, code, display
495
- ) VALUES (?, ?, ?, ?)
543
+ INSERT INTO valueset_jurisdictions (
544
+ valueset_id, system, code, display
545
+ ) VALUES (?, ?, ?, ?)
496
546
  `, [
497
547
  valueSet.id,
498
548
  coding.system || null,
@@ -514,7 +564,7 @@ class ValueSetDatabase {
514
564
  pendingOperations++;
515
565
 
516
566
  db.run(`
517
- INSERT INTO valueset_systems (valueset_id, system, version) VALUES (?, ?, ?)
567
+ INSERT INTO valueset_systems (valueset_id, system, version) VALUES (?, ?, ?)
518
568
  `, [valueSet.id, include.system, include.version], function(err) {
519
569
  if (err) {
520
570
  operationError(new Error(`Failed to insert system: ${err.message}`));
@@ -598,12 +648,12 @@ class ValueSetDatabase {
598
648
  async search(spaceId, map, searchParams, elements = null) {
599
649
  // Check if we can optimize by selecting only indexed columns
600
650
  const canOptimize = elements && elements.length > 0 &&
601
- elements.every(e => INDEXED_COLUMNS.includes(e));
651
+ elements.every(e => INDEXED_COLUMNS.includes(e));
602
652
 
603
653
  // Always include 'id' in the columns to select when optimizing
604
654
  const columnsToSelect = canOptimize
605
- ? (elements.includes('id') ? elements : ['id', ...elements])
606
- : null;
655
+ ? (elements.includes('id') ? elements : ['id', ...elements])
656
+ : null;
607
657
 
608
658
  const db = await this._getReadConnection();
609
659
 
package/tx/vs/vs-vsac.js CHANGED
@@ -17,6 +17,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
17
17
  * @param {string} config.cacheFolder - Local folder for cached database
18
18
  * @param {number} [config.refreshIntervalHours=24] - Hours between refresh scans
19
19
  * @param {string} [config.baseUrl='http://cts.nlm.nih.gov/fhir'] - Base URL for VSAC FHIR server
20
+ * @param {number} [config.timeoutMs=120000] - HTTP request timeout in milliseconds
20
21
  */
21
22
  constructor(config, stats) {
22
23
  super();
@@ -43,7 +44,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
43
44
  const authString = Buffer.from(`apikey:${this.apiKey}`).toString('base64');
44
45
  this.httpClient = axios.create({
45
46
  baseURL: this.baseUrl,
46
- timeout: 30000,
47
+ timeout: config.timeoutMs || 120000,
47
48
  headers: {
48
49
  'Accept': 'application/fhir+json',
49
50
  'User-Agent': 'FHIR-ValueSet-Provider/1.0',
@@ -78,7 +79,6 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
78
79
  if (this.valueSetMap.size == 0) {
79
80
  await this.refreshValueSets();
80
81
  }
81
-
82
82
  // Start periodic refresh
83
83
  this._startRefreshTimer();
84
84
  this.initialized = true;
@@ -174,6 +174,14 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
174
174
  console.log(`VSAC refresh phase 1 done. Total: ${count} with ${ncount} new items`);
175
175
  this.stats.task('VSAC Sync', `VSAC refresh phase 1 done. Total: ${count} with ${ncount} new items`);
176
176
 
177
+ // phase 1b: query for recently updated value sets via _lastUpdated
178
+ let lastUpdatedCount = await this._scanLastUpdated();
179
+ console.log(`VSAC refresh phase 1b done. ${lastUpdatedCount} additional items from _lastUpdated`);
180
+ this.stats.task('VSAC Sync', `Phase 1b: ${lastUpdatedCount} from _lastUpdated`);
181
+
182
+ // deduplicate the queue
183
+ this.queue = [...new Set(this.queue)];
184
+
177
185
  let tracking = { totalFetched: 0, totalNew: 0, count: 0, newCount : 0 };
178
186
  // phase 2: query for history & content
179
187
  this.requeue = [];
@@ -418,8 +426,8 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
418
426
  isRefreshing: this.isRefreshing,
419
427
  refreshIntervalHours: this.refreshIntervalHours,
420
428
  nextRefresh: this.refreshTimer && this.lastRefresh
421
- ? new Date(this.lastRefresh.getTime() + (this.refreshIntervalHours * 60 * 60 * 1000))
422
- : null
429
+ ? new Date(this.lastRefresh.getTime() + (this.refreshIntervalHours * 60 * 60 * 1000))
430
+ : null
423
431
  }
424
432
  };
425
433
  }
@@ -506,8 +514,8 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
506
514
  if (bundle.entry && bundle.entry.length > 0) {
507
515
  // Extract ValueSets from bundle entries
508
516
  const valueSets = bundle.entry
509
- .filter(entry => entry.resource && entry.resource.resourceType === 'ValueSet')
510
- .map(entry => entry.resource);
517
+ .filter(entry => entry.resource && entry.resource.resourceType === 'ValueSet')
518
+ .map(entry => entry.resource);
511
519
  if (valueSets.length > 0) {
512
520
  tracking.totalNew = tracking.totalNew + await this.batchUpsertValueSets(valueSets);
513
521
  tracking.totalFetched += valueSets.length;
@@ -519,6 +527,58 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
519
527
  this.stats.task('VSAC Sync', logMsg);
520
528
  }
521
529
 
530
+ /**
531
+ * Scan VSAC for recently updated value sets using the _lastUpdated parameter.
532
+ * Uses a stored date from the previous run; if none exists, defaults to 4 days ago.
533
+ * Adds any found URLs to this.queue and stores the server's response date for next time.
534
+ * @returns {Promise<number>} Number of value set URLs added to the queue
535
+ * @private
536
+ */
537
+ async _scanLastUpdated() {
538
+ const SETTING_KEY = 'vsac_last_updated_date';
539
+
540
+ let sinceDate = await this.database.getSetting(SETTING_KEY);
541
+ if (!sinceDate) {
542
+ // No stored date — default to 10 days ago
543
+ const d = new Date();
544
+ d.setDate(d.getDate() - 10);
545
+ sinceDate = d.toISOString();
546
+ }
547
+
548
+ let url = `/res/ValueSet/?_lastUpdated=ge${sinceDate}&_offset=0&_count=100&_elements=id,url,version,status`;
549
+ let count = 0;
550
+ let serverDate = null;
551
+
552
+ while (url) {
553
+ console.log(`_lastUpdated scan: ${count} found so far`);
554
+ this.stats.task('VSAC Sync', `_lastUpdated scan: ${count} found`);
555
+
556
+ const bundle = await this._fetchBundle(url);
557
+
558
+ // Capture the server's lastUpdated from the first page
559
+ if (!serverDate && bundle.meta && bundle.meta.lastUpdated) {
560
+ serverDate = bundle.meta.lastUpdated;
561
+ }
562
+
563
+ for (let be of bundle.entry || []) {
564
+ let vs = be.resource;
565
+ if (vs && vs.url) {
566
+ this.queue.push(vs.url);
567
+ count++;
568
+ }
569
+ }
570
+
571
+ url = this._getNextUrl(bundle);
572
+ }
573
+
574
+ // Store the server date for next run
575
+ if (serverDate) {
576
+ await this.database.setSetting(SETTING_KEY, serverDate);
577
+ }
578
+
579
+ return count;
580
+ }
581
+
522
582
  name() {
523
583
  return "VSAC";
524
584
  }
@@ -533,38 +593,38 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
533
593
 
534
594
  const rows = await new Promise((resolve, reject) => {
535
595
  db.all(
536
- `SELECT 'vs' AS kind,
537
- url,
538
- version,
539
- date_first_seen AS ts,
540
- NULL AS status,
541
- NULL AS error_message,
542
- NULL AS finished_at,
543
- NULL AS total_fetched,
544
- NULL AS total_new
596
+ `SELECT 'vs' AS kind,
597
+ url,
598
+ version,
599
+ date_first_seen AS ts,
600
+ NULL AS status,
601
+ NULL AS error_message,
602
+ NULL AS finished_at,
603
+ NULL AS total_fetched,
604
+ NULL AS total_new
545
605
  FROM valuesets
546
- WHERE date_first_seen > 0
547
- UNION ALL
548
- SELECT 'run' AS kind,
549
- NULL,
550
- NULL,
551
- started_at AS ts,
552
- status,
553
- error_message,
554
- finished_at,
555
- total_fetched,
556
- total_new
606
+ WHERE date_first_seen > 0
607
+ UNION ALL
608
+ SELECT 'run' AS kind,
609
+ NULL,
610
+ NULL,
611
+ started_at AS ts,
612
+ status,
613
+ error_message,
614
+ finished_at,
615
+ total_fetched,
616
+ total_new
557
617
  FROM vsac_runs
558
- ORDER BY ts DESC
559
- LIMIT 200`,
560
- [],
561
- (err, rows) => err ? reject(err) : resolve(rows)
618
+ ORDER BY ts DESC
619
+ LIMIT 200`,
620
+ [],
621
+ (err, rows) => err ? reject(err) : resolve(rows)
562
622
  );
563
623
  });
564
624
 
565
625
  const fmt = ts => ts
566
- ? new Date(ts * 1000).toISOString().replace('T', ' ').substring(0, 19) + ' UTC'
567
- : '—';
626
+ ? new Date(ts * 1000).toISOString().replace('T', ' ').substring(0, 19) + ' UTC'
627
+ : '—';
568
628
 
569
629
  let html = '<h3>VSAC Sync History</h3>';
570
630
  html += '<table class="grid">';
@@ -646,6 +646,10 @@ class ValueSetExpander {
646
646
  throw new Issue('error', 'business-rule', null, null, 'The code system definition for ' + cset.system + ' has no content, so this expansion cannot be performed', 'invalid');
647
647
  } else if (cs.contentMode() === 'supplement') {
648
648
  throw new Issue('error', 'business-rule', null, null, 'The code system definition for ' + cset.system + ' defines a supplement, so this expansion cannot be performed', 'invalid');
649
+ } else if (cs.contentMode() === 'fragment') {
650
+ this.addParamUri(exp, 'used-fragment', cs.system() + '|' + cs.version());
651
+ Extensions.addBoolean(exp, "http://hl7.org/fhir/StructureDefinition/valueset-unclosed", true);
652
+ Extensions.addString(exp, "http://hl7.org/fhir/StructureDefinition/valueset-unclosed-reason","This extension is based on a fragment of the code system " + cset.system);
649
653
  } else {
650
654
  this.addParamUri(exp, cs.contentMode(), cs.system() + '|' + cs.version());
651
655
  Extensions.addBoolean(exp, "http://hl7.org/fhir/StructureDefinition/valueset-unclosed", true);
@@ -1010,7 +1014,7 @@ class ValueSetExpander {
1010
1014
  cds.clear();
1011
1015
  Extensions.checkNoModifiers(cc, 'ValueSetExpander.processCodes', 'set concept reference', vsSrc.vurl);
1012
1016
  const cctxt = await cs.locate(cc.code, this.allAltCodes);
1013
- if (cctxt && cctxt.context && (!this.params.activeOnly || !await cs.isInactive(cctxt)) && await this.passesFilters(cs, cctxt, prep, filters, 0)) {
1017
+ if (cctxt && cctxt.context && (!this.params.activeOnly || !await cs.isInactive(cctxt.context)) && await this.passesFilters(cs, cctxt.context, prep, filters, 0)) {
1014
1018
  if (filter.passesDesignations(cds) || filter.passes(cc.code)) {
1015
1019
  let ov = Extensions.readString(cc, 'http://hl7.org/fhir/StructureDefinition/itemWeight');
1016
1020
  if (!ov) {
@@ -232,7 +232,8 @@ class MetadataHandler {
232
232
  ],
233
233
  operation: [
234
234
  { name: 'expand', definition: 'http://hl7.org/fhir/OperationDefinition/ValueSet-expand' },
235
- { name: 'validate-code', definition: 'http://hl7.org/fhir/OperationDefinition/ValueSet-validate-code' }
235
+ { name: 'validate-code', definition: 'http://hl7.org/fhir/OperationDefinition/ValueSet-validate-code' },
236
+ { name: 'related', definition: 'https://raw.githubusercontent.com/HealthIntersections/FHIRsmith/refs/heads/main/tx/data/OperationDefinition-ValueSet-related.json' }
236
237
  ]
237
238
  },
238
239
  {
@@ -265,6 +266,7 @@ class MetadataHandler {
265
266
  { name: 'validate-code', definition: 'http://hl7.org/fhir/OperationDefinition/Resource-validate-code' },
266
267
  { name: 'translate', definition: 'http://hl7.org/fhir/OperationDefinition/ConceptMap-translate' },
267
268
  { name: 'closure', definition: 'http://hl7.org/fhir/OperationDefinition/ConceptMap-closure' },
269
+ { name: 'related', definition: 'https://raw.githubusercontent.com/HealthIntersections/FHIRsmith/refs/heads/main/tx/data/OperationDefinition-ValueSet-related.json' },
268
270
  { name: 'versions', definition: 'http://hl7.org/fhir/OperationDefinition/fhir-versions' }
269
271
  ]
270
272
  }
@@ -839,7 +839,7 @@ class ValueSetChecker {
839
839
  } else {
840
840
  bAdd = !unknownSystems.has(system + '|' + version);
841
841
  if (bAdd) {
842
- let vl = await this.listVersions(system);
842
+ let vl = await this.worker.listVersions(system);
843
843
  if (vl.length == 0) {
844
844
  mid = 'UNKNOWN_CODESYSTEM_VERSION_NONE';
845
845
  vn = system;