fhirsmith 0.13.3 → 0.14.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 +47 -1
- package/README.md +48 -4
- package/config-template.json +70 -1
- package/library/cgroup-memory.js +113 -0
- package/library/folder-setup.js +8 -1
- package/nginx.md +391 -0
- package/package.json +3 -2
- package/publisher/git-remote.js +141 -0
- package/publisher/github-release.js +195 -0
- package/publisher/publisher.js +146 -14
- package/server.js +51 -14
- package/stats.js +19 -13
- package/testing/readme.md +112 -0
- package/testing/render.js +482 -0
- package/testing/search.js +378 -0
- package/testing/store.js +266 -0
- package/testing/testing-template.html +126 -0
- package/testing/testing.js +486 -0
- package/translations/Messages.properties +32 -0
- package/tx/closure/closure-store.js +396 -0
- package/tx/cs/cs-api.js +6 -1
- package/tx/cs/cs-rxnorm.js +35 -8
- package/tx/cs/cs-snomed.js +142 -27
- package/tx/html/codesystem-operations.liquid +177 -0
- package/tx/html/ecl-panel.liquid +93 -0
- package/tx/html/home-metrics.liquid +39 -76
- package/tx/html/tx-template.html +1 -0
- package/tx/library/conceptmap.js +22 -6
- package/tx/library/designations.js +12 -3
- package/tx/library/extensions.js +2 -2
- package/tx/library/operation-outcome.js +3 -1
- package/tx/library/renderer.js +42 -5
- package/tx/operation-context.js +111 -15
- package/tx/provider.js +85 -0
- package/tx/sct/expressions.js +128 -44
- package/tx/sct/text-index.js +419 -0
- package/tx/tx-html.js +426 -44
- package/tx/tx.js +117 -9
- package/tx/workers/cache-control.js +2 -2
- package/tx/workers/closure.js +483 -13
- package/tx/workers/expand.js +20 -0
- package/tx/workers/metadata.js +29 -4
- package/tx/workers/read.js +18 -3
- package/tx/workers/subsumes.js +18 -2
- package/tx/workers/translate.js +167 -20
- package/tx/workers/validate.js +61 -182
- package/tx/workers/worker.js +9 -0
- package/tx/xversion/xv-conceptmap.js +17 -8
- package/utilities/submit-test-report.js +150 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,56 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
All notable changes to
|
|
3
|
+
All notable changes to Health Intersections FHIRsmith will be documented in this file.
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.14.0] - 2026-09-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- New Module: TestReport repository
|
|
13
|
+
- Initial Implementation of $closure
|
|
14
|
+
- add support for caching across multiple servers
|
|
15
|
+
- better support for web invocation of operations
|
|
16
|
+
- add ECL control panel
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- improve home page graphs and cache information
|
|
21
|
+
- better memory management - prevent an operation running the server out of memory
|
|
22
|
+
- $validate-code: inferSystem is only applied to the code parameter, per its definition - it is ignored for coding and codeableConcept
|
|
23
|
+
- $validate-code: a Coding with neither a system nor a code is reported as one problem, not two (Coding_has_no_system_or_code__cannot_validate)
|
|
24
|
+
- $subsumes: a missing system (codeA/codeB with no system parameter, or a codingA/codingB with no system) is now 400 with issue code invalid and tx-issue-type invalid-data (was 404/422 not-found), with message id SUBSUMPTION_NO_SYSTEM (shared with the Java terminology service); mismatched codingA/codingB systems use SUBSUMPTION_SYSTEM_MISMATCH
|
|
25
|
+
- SNOMED expressions: a refined or conjoined attribute value must be bracketed, per the compositional grammar (405813007=(85562004:272741003=24028007)); the unbracketed form is now rejected, and the renderer emits the brackets (it used to produce expressions other parsers reject)
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Fix processing of sourceScope during $translate operation
|
|
30
|
+
- Fix broken links in HTML references (#256)
|
|
31
|
+
- Fix bug in concept map conversion
|
|
32
|
+
- Fix issue processing MRCM rules (#287)
|
|
33
|
+
- Fix message about depending on a draft resource (add source info)
|
|
34
|
+
|
|
35
|
+
### Tx Conformance Statement
|
|
36
|
+
|
|
37
|
+
FHIRsmith passed all 3516 HL7 terminology service tests (modes tx.fhir.org+omop+general+snomed+mimetypes+icd-11+closure, tests v1.9.5
|
|
38
|
+
|
|
39
|
+
## [v0.13.4] - 2026-09-17
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- Clean up TxCaps expansion parameter list
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Fix performance issue with snomed text search
|
|
48
|
+
- clean up release process to avoid version mismatch, and to clean out old dockers
|
|
49
|
+
|
|
50
|
+
### Tx Conformance Statement
|
|
51
|
+
|
|
52
|
+
FHIRsmith passed all 3507 HL7 terminology service tests (modes tx.fhir.org+omop+general+snomed+mimetypes+icd-11, tests v1.9.4, runner v6.10.4)
|
|
53
|
+
|
|
8
54
|
## [v0.13.3] - 2026-09-10
|
|
9
55
|
|
|
10
56
|
### Fixed
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ This server provides a set of server-side services that are useful for the FHIR
|
|
|
31
31
|
[](https://github.com/HealthIntersections/fhirsmith/pkgs/container/fhirsmith)
|
|
32
32
|
|
|
33
33
|
Note: In production, this server always runs behind an nginx reverse proxy, so there's no
|
|
34
|
-
in-build support for SSL, rate limiting etc.
|
|
34
|
+
in-build support for SSL, rate limiting etc. See [nginx.md](nginx.md) for how to configure it.
|
|
35
35
|
|
|
36
36
|
## Quick Start
|
|
37
37
|
|
|
@@ -170,7 +170,8 @@ npm start
|
|
|
170
170
|
|
|
171
171
|
The server will be available at `http://localhost:{port}` using the port specified in the config.
|
|
172
172
|
In the production servers listed above, the server always sits behind an NGINX server which manages
|
|
173
|
-
SSL, security, rate limiting etc.
|
|
173
|
+
SSL, security, rate limiting etc. See [nginx.md](nginx.md) for configuration advice, including
|
|
174
|
+
running several servers behind one front door.
|
|
174
175
|
|
|
175
176
|
## Testing
|
|
176
177
|
|
|
@@ -259,6 +260,26 @@ Each GitHub Release includes:
|
|
|
259
260
|
- `ghcr.io/healthintersections/fhirsmith:X.Y.Z`
|
|
260
261
|
- **npm package** published to npmjs.org as `fhirsmith` *(if you add this)*
|
|
261
262
|
|
|
263
|
+
Release images carry OCI labels, so an image says which release it is without
|
|
264
|
+
having to trust the tag it was pulled under:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
docker inspect --format '{{json .Config.Labels}}' ghcr.io/healthintersections/fhirsmith:latest
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`org.opencontainers.image.version` is the release, `.revision` the commit it was
|
|
271
|
+
built from, and `.source` is what links the package to this repository on GHCR.
|
|
272
|
+
|
|
273
|
+
### CI Images
|
|
274
|
+
|
|
275
|
+
Every push to main also publishes `:cibuild` and `:cibuild-<sha>` to the same
|
|
276
|
+
package. These are **not releases** - they are whatever was last merged. The
|
|
277
|
+
Docker Build workflow prunes all but the ten most recent afterwards, so they do
|
|
278
|
+
not bury the current release on the package page. To prune by hand (or to run
|
|
279
|
+
the one-off backfill of images published before that job existed), run the
|
|
280
|
+
**GHCR Cleanup** workflow from the Actions tab with `dry_run` on first, read the
|
|
281
|
+
log, then run it again with `dry_run` off.
|
|
282
|
+
|
|
262
283
|
### Creating a Release
|
|
263
284
|
|
|
264
285
|
GitHub Actions will automatically:
|
|
@@ -283,7 +304,18 @@ GitHub Actions will automatically:
|
|
|
283
304
|
### Tx Conformance Statement
|
|
284
305
|
{copy content from text-cases-summary.txt}
|
|
285
306
|
```
|
|
286
|
-
2. Update `package.json` & `package-lock.json` to
|
|
307
|
+
2. Update `package.json` & `package-lock.json` to the release version:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
npm version --no-git-tag-version X.Y.Z
|
|
311
|
+
npm install --package-lock-only
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
This matters more than it looks. The server reports its version from
|
|
315
|
+
`package.json` (`server.js`, `tx/tx.js`) - not from the `APP_VERSION` build
|
|
316
|
+
arg - so a package.json left on the previous number ships a Docker image that
|
|
317
|
+
calls itself by the wrong release for good. The **Verify Version** job fails
|
|
318
|
+
the release if `package.json` or `package-lock.json` disagrees with the tag.
|
|
287
319
|
|
|
288
320
|
3. Commit your changes:
|
|
289
321
|
```bash
|
|
@@ -304,7 +336,19 @@ or do it via a PR
|
|
|
304
336
|
- Verify the [GitHub Release](https://github.com/HealthIntersections/fhirsmith/releases) was created
|
|
305
337
|
- Confirm Docker images are available at [GHCR](https://github.com/HealthIntersections/fhirsmith/pkgs/container/fhirsmith)
|
|
306
338
|
|
|
307
|
-
6.
|
|
339
|
+
6. Submit the tx conformance report to [testing.fhir.org](https://testing.fhir.org/testing):
|
|
340
|
+
```bash
|
|
341
|
+
node utilities/submit-test-report.js -token {token}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The tx test run writes `test-cases-report.json` next to `test-cases-summary.txt` (both
|
|
345
|
+
are ignored by git); this uploads it as a TestReport. The report records the version in
|
|
346
|
+
`package.json` when the tests ran, so for it to name the release, run the tx tests
|
|
347
|
+
after step 2 - the script warns if the report is from a different version, or from a
|
|
348
|
+
snapshot. Use `-server {url}` to send it to a different /testing server; the token can
|
|
349
|
+
also come from `FHIRSMITH_TESTING_TOKEN`.
|
|
350
|
+
|
|
351
|
+
7. Update `package.json` to have the next release version -SNAPSHOT
|
|
308
352
|
|
|
309
353
|
**If a release fails:**
|
|
310
354
|
- Delete the tag: `git tag -d vX.Y.Z && git push origin :refs/tags/vX.Y.Z`
|
package/config-template.json
CHANGED
|
@@ -101,7 +101,25 @@
|
|
|
101
101
|
// key - e.g. "git@github-ig-registry:FHIR/ig-registry.git", with a matching Host block
|
|
102
102
|
// in the service user's ~/.ssh/config carrying IdentityFile and IdentitiesOnly yes.
|
|
103
103
|
// The alias is what lets ssh tell this remote apart from the website remote.
|
|
104
|
-
"ig-registry-url": "git@github.com:FHIR/ig-registry.git"
|
|
104
|
+
"ig-registry-url": "git@github.com:FHIR/ig-registry.git",
|
|
105
|
+
// Tagging the IG source repo and publishing a GitHub release with a zip of its source, at
|
|
106
|
+
// the end of a successful publication. Omit this whole block to skip that step - without it
|
|
107
|
+
// there is no credential that can write to a source repository.
|
|
108
|
+
//
|
|
109
|
+
// This is a GitHub App, not a personal access token: a fine-grained PAT cannot span two
|
|
110
|
+
// organisations, and a classic PAT would act as whoever minted it. Create the App with
|
|
111
|
+
// "Where can this GitHub App be installed?" = Any account, give it Contents: Read and write
|
|
112
|
+
// (which covers tags as well as releases), then install it on each org below with access to
|
|
113
|
+
// all repositories. The installation id is in the URL of the installation's settings page.
|
|
114
|
+
"github-app": {
|
|
115
|
+
"app-id": "123456",
|
|
116
|
+
"private-key": "/absolute/path/to/app-private-key.pem",
|
|
117
|
+
// github org name (as it appears on the publication task) -> installation id
|
|
118
|
+
"installations": {
|
|
119
|
+
"HL7": 12345678,
|
|
120
|
+
"FHIR": 87654321
|
|
121
|
+
}
|
|
122
|
+
}
|
|
105
123
|
},
|
|
106
124
|
"npmprojector": {
|
|
107
125
|
"enabled": true,
|
|
@@ -163,6 +181,39 @@
|
|
|
163
181
|
// Off by default - the file names every database, cache and package the server runs.
|
|
164
182
|
"publishLibrarySource": false,
|
|
165
183
|
"cacheTimeout": 30,
|
|
184
|
+
// Optional. A short code (1-16 letters and digits) naming this server instance. Every
|
|
185
|
+
// cache-id the server issues then starts with "<code>.", so a proxy in front of
|
|
186
|
+
// several instances can route cached requests back to the instance that holds the
|
|
187
|
+
// cache. Leave unset for a single server. See nginx.md.
|
|
188
|
+
// "instanceCode": "tx1",
|
|
189
|
+
// $closure: closure tables are kept on the server, across sessions and restarts, so
|
|
190
|
+
// the operation is off unless it is turned on here. When it is on, only one server
|
|
191
|
+
// instance may use the database - route every $closure request to it (see nginx.md).
|
|
192
|
+
"closure": {
|
|
193
|
+
"enabled": false,
|
|
194
|
+
// relative paths resolve under the data folder's databases directory
|
|
195
|
+
"database": "closure.db",
|
|
196
|
+
// require table names to be UUIDs, so names chosen by unrelated clients can't
|
|
197
|
+
// collide (public servers). Otherwise a name is anything up to 64 characters with
|
|
198
|
+
// no white space
|
|
199
|
+
"requireUuidNames": false,
|
|
200
|
+
// limits: these are the defaults, which apply when a limit is left out; 0 = no limit
|
|
201
|
+
"maxTables": 1000,
|
|
202
|
+
"maxConceptsPerTable": 10000,
|
|
203
|
+
"maxConceptsPerRequest": 1000,
|
|
204
|
+
"maxEntriesPerTable": 250000,
|
|
205
|
+
"maxEntriesPerRequest": 50000,
|
|
206
|
+
// bytes of configuration kept with a table - mostly the tx-resource code systems
|
|
207
|
+
"maxConfigSize": 5242880,
|
|
208
|
+
// calls that can queue for one table (counting the one running), and how long, in
|
|
209
|
+
// seconds, a call will wait for its turn; beyond either, the call gets a 429
|
|
210
|
+
"maxQueue": 10,
|
|
211
|
+
"lockTimeout": 60
|
|
212
|
+
// delete tables that nobody has touched (initialised, added to or resynced) for this
|
|
213
|
+
// many days. Checked at startup and then daily. Leave it out and nothing is ever
|
|
214
|
+
// deleted - the right default for a private server; public servers should set it:
|
|
215
|
+
// , "retentionDays": 90
|
|
216
|
+
},
|
|
166
217
|
"expansionCacheSize": 1000,
|
|
167
218
|
"expansionCacheMemoryThreshold": 0,
|
|
168
219
|
"endpoints": [
|
|
@@ -198,6 +249,24 @@
|
|
|
198
249
|
"enabled": true,
|
|
199
250
|
"database": "/var/fhir/data/extension-tracker.db",
|
|
200
251
|
"url": "/ext-tracker"
|
|
252
|
+
},
|
|
253
|
+
// TestReports from TxTester and other tools, at /testing. See testing/readme.md
|
|
254
|
+
"testing": {
|
|
255
|
+
"enabled": false,
|
|
256
|
+
// relative paths resolve under the data folder's databases directory
|
|
257
|
+
"database": "testing.db",
|
|
258
|
+
// if set, every POST must carry this token in tokenHeader (a "Bearer " prefix is
|
|
259
|
+
// allowed). Leave it out and anyone can submit a report
|
|
260
|
+
// "token": "<!-- secret -->",
|
|
261
|
+
"tokenHeader": "Authorization",
|
|
262
|
+
// DELETE of a report needs this token, in the same header. No adminToken, no deletes
|
|
263
|
+
// "adminToken": "<!-- secret -->",
|
|
264
|
+
// bytes
|
|
265
|
+
"maxSize": 512000,
|
|
266
|
+
// reports per IP address per window; max 0 turns the limit off
|
|
267
|
+
"rateLimit": { "windowMinutes": 1, "max": 60 }
|
|
268
|
+
// delete reports received more than this many days ago. Leave it out to keep everything
|
|
269
|
+
// , "retentionDays": 365
|
|
201
270
|
}
|
|
202
271
|
}
|
|
203
272
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The memory limit the kernel will actually enforce on this process.
|
|
3
|
+
*
|
|
4
|
+
* Reading `/sys/fs/cgroup/memory.max` only works inside a container with its own
|
|
5
|
+
* cgroup namespace, where the process's cgroup is mounted as the root. Under plain
|
|
6
|
+
* systemd (how tx.fhir.org runs) the whole host hierarchy is visible, the root cgroup
|
|
7
|
+
* has no memory.max at all, and the limit lives at e.g.
|
|
8
|
+
* `/sys/fs/cgroup/system.slice/fhirsmith.service/memory.max`. So: find our cgroup in
|
|
9
|
+
* /proc/self/cgroup, then walk from it up to the root, taking the smallest limit -
|
|
10
|
+
* a MemoryMax on the enclosing slice binds just as hard as one on the unit.
|
|
11
|
+
*
|
|
12
|
+
* Handles cgroup v2 (unified) and v1 (memory controller). Anything unreadable or
|
|
13
|
+
* unlimited is ignored; if nothing is found the result is 0.
|
|
14
|
+
*
|
|
15
|
+
* @module library/cgroup-memory
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
// cgroup v1 reports "unlimited" as a page-rounded LONG_MAX; anything this big is no limit.
|
|
22
|
+
const V1_UNLIMITED = 2 ** 60;
|
|
23
|
+
|
|
24
|
+
function readLimitFile(file) {
|
|
25
|
+
let raw;
|
|
26
|
+
try {
|
|
27
|
+
raw = fs.readFileSync(file, 'utf8').trim();
|
|
28
|
+
} catch {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
if (raw === '' || raw === 'max') {
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
const n = Number(raw);
|
|
35
|
+
if (!Number.isFinite(n) || n <= 0 || n >= V1_UNLIMITED) {
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
return n;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Walk from cgroupPath up to '/', returning the smallest limit found under mountDir.
|
|
43
|
+
*/
|
|
44
|
+
function smallestLimit(mountDir, cgroupPath, fileName) {
|
|
45
|
+
let limit = 0;
|
|
46
|
+
let source = null;
|
|
47
|
+
let p = path.posix.normalize(cgroupPath || '/');
|
|
48
|
+
for (;;) {
|
|
49
|
+
const file = path.join(mountDir, p, fileName);
|
|
50
|
+
const n = readLimitFile(file);
|
|
51
|
+
if (n > 0 && (limit === 0 || n < limit)) {
|
|
52
|
+
limit = n;
|
|
53
|
+
source = file;
|
|
54
|
+
}
|
|
55
|
+
if (p === '/' || p === '.' || p === '') {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
p = path.posix.dirname(p);
|
|
59
|
+
}
|
|
60
|
+
return { limit, source };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {Object} [opts] - For tests: alternative locations of the proc file and cgroup mount.
|
|
65
|
+
* @param {string} [opts.procFile='/proc/self/cgroup']
|
|
66
|
+
* @param {string} [opts.cgroupRoot='/sys/fs/cgroup']
|
|
67
|
+
* @returns {{limit: number, source: string|null}} limit in bytes (0 = none found), and the
|
|
68
|
+
* file it came from.
|
|
69
|
+
*/
|
|
70
|
+
function readCgroupMemoryLimit(opts = {}) {
|
|
71
|
+
const procFile = opts.procFile || '/proc/self/cgroup';
|
|
72
|
+
const cgroupRoot = opts.cgroupRoot || '/sys/fs/cgroup';
|
|
73
|
+
|
|
74
|
+
let lines = [];
|
|
75
|
+
try {
|
|
76
|
+
lines = fs.readFileSync(procFile, 'utf8').split('\n').filter(l => l.trim() !== '');
|
|
77
|
+
} catch {
|
|
78
|
+
// not Linux, or /proc not mounted - fall through to the namespaced-root guess
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// v2: "0::/system.slice/fhirsmith.service"
|
|
82
|
+
const v2 = lines.find(l => l.startsWith('0::'));
|
|
83
|
+
if (v2) {
|
|
84
|
+
const result = smallestLimit(cgroupRoot, v2.substring(3), 'memory.max');
|
|
85
|
+
if (result.limit > 0) {
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// v1: "4:memory:/system.slice/fhirsmith.service"
|
|
91
|
+
for (const l of lines) {
|
|
92
|
+
const parts = l.split(':');
|
|
93
|
+
if (parts.length >= 3 && parts[1].split(',').includes('memory')) {
|
|
94
|
+
const result = smallestLimit(path.join(cgroupRoot, 'memory'), parts.slice(2).join(':'), 'memory.limit_in_bytes');
|
|
95
|
+
if (result.limit > 0) {
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// No /proc/self/cgroup: a namespaced container still has its own limit at the root.
|
|
102
|
+
if (lines.length === 0) {
|
|
103
|
+
const file = path.join(cgroupRoot, 'memory.max');
|
|
104
|
+
const n = readLimitFile(file);
|
|
105
|
+
if (n > 0) {
|
|
106
|
+
return { limit: n, source: file };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { limit: 0, source: null };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = { readCgroupMemoryLimit };
|
package/library/folder-setup.js
CHANGED
|
@@ -12,7 +12,14 @@ class FolderSetup {
|
|
|
12
12
|
return this;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const configured = dataDir || process.env.FHIRSMITH_DATA_DIR || path.join(__dirname, '..', 'data');
|
|
16
|
+
if (typeof configured !== 'string') {
|
|
17
|
+
throw new Error('Invalid data directory: expected a path, got ' + typeof configured);
|
|
18
|
+
}
|
|
19
|
+
// Absolute from here on: these paths are handed to child processes that run with a different
|
|
20
|
+
// working directory (the IG Publisher, git, sushi), and the IG Publisher refuses relative paths.
|
|
21
|
+
// A relative FHIRSMITH_DATA_DIR is taken relative to the directory the server was started in.
|
|
22
|
+
this._dataDir = path.resolve(configured);
|
|
16
23
|
fs.mkdirSync(this._dataDir, { recursive: true });
|
|
17
24
|
this._initialized = true;
|
|
18
25
|
|