fhirsmith 0.18.2 → 1.0.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/ACCESSIBILITY.md +119 -0
- package/CHANGELOG.md +149 -0
- package/CONFIGURATION.md +305 -0
- package/LICENSE +29 -0
- package/README.md +29 -122
- package/cluster.js +1220 -0
- package/cluster.md +707 -0
- package/config-template.json +77 -8
- package/extension-tracker/extension-tracker-template.html +5 -8
- package/extension-tracker/extension-tracker.js +0 -2
- package/folder/folder.js +7 -6
- package/ips/analysis.js +560 -0
- package/ips/ips-template.html +5 -8
- package/ips/ips.js +132 -59
- package/ips/nationality.js +120 -0
- package/ips/pipeline.js +74 -21
- package/ips/presenter.js +1 -1
- package/ips/readme.md +132 -25
- package/ips/render.js +466 -77
- package/ips/store.js +79 -22
- package/ips/structure.js +247 -0
- package/ips/terminology.js +1 -1
- package/library/body-limit.js +22 -0
- package/library/cache-generation.js +15 -0
- package/library/cgroup-memory.js +133 -1
- package/library/cluster-counts.js +121 -0
- package/library/cluster-events.js +153 -0
- package/library/cluster-metrics.js +193 -0
- package/library/cluster-status.js +468 -0
- package/library/config-reader.js +96 -0
- package/library/daily-report.js +100 -2
- package/library/html-server.js +27 -1
- package/library/i18nsupport.js +23 -1
- package/library/keep-alive.js +18 -0
- package/library/languages.js +17 -3
- package/library/logger.js +31 -0
- package/library/memory-guard.js +428 -0
- package/library/native-memory.js +52 -0
- package/library/npm-audit.js +51 -25
- package/library/openapi-doc.js +7 -5
- package/library/package-manager.js +8 -0
- package/library/role.js +197 -0
- package/library/server-credentials.js +169 -0
- package/library/sqlite-utilities.js +59 -0
- package/library/ssrf-guard.js +100 -0
- package/library/static-response-stats.js +16 -0
- package/library/version-utilities.js +50 -0
- package/library/worker-count.js +192 -0
- package/nginx.md +30 -11
- package/npmprojector/indexer.js +18 -10
- package/package.json +11 -8
- package/packages/feed-check-page.js +117 -0
- package/packages/feed-check.js +279 -0
- package/packages/npm-check.js +57 -3
- package/packages/npm-signing.js +219 -0
- package/packages/openapi.yaml +207 -1
- package/packages/package-crawler.js +322 -41
- package/packages/packages-template.html +6 -8
- package/packages/packages.js +604 -57
- package/packages/readme.md +113 -1
- package/publisher/publisher-template.html +2 -5
- package/publisher/publisher.js +121 -110
- package/publisher/readme.md +75 -0
- package/registry/crawler.js +84 -108
- package/registry/documentation/configuration.md +34 -0
- package/registry/registry-template.html +5 -8
- package/registry/registry.js +5 -4
- package/root-bare-template.html +7 -4
- package/root-template.html +5 -8
- package/server.js +398 -198
- package/shl/shl.js +38 -37
- package/static/a11y/a11y-check.js +832 -0
- package/static/a11y/axe.min.js +12 -0
- package/static/assets/css/bootstrap-fhir.css +15 -15
- package/static/assets/images/flags/au.svg +18 -0
- package/static/assets/images/flags/unknown.svg +11 -0
- package/static/assets/images/flags/us.svg +63 -0
- package/static/assets/images/icon_audit.png +0 -0
- package/static/assets/images/icon_clinical.png +0 -0
- package/static/assets/images/icon_document.png +0 -0
- package/static/assets/images/icon_external.png +0 -0
- package/static/assets/images/icon_medication.png +0 -0
- package/static/assets/images/icon_organization.png +0 -0
- package/static/assets/images/icon_other.png +0 -0
- package/static/assets/images/icon_person.png +0 -0
- package/static/assets/images/icon_section.png +0 -0
- package/stats-db.js +45 -0
- package/stats.js +197 -10
- package/testing/testing-template.html +5 -8
- package/token/nginx_passport_setup.md +1 -1
- package/token/security_guide.md +1 -1
- package/token/token-template.html +2 -5
- package/token/token.js +40 -36
- package/translations/Messages.properties +19 -0
- package/tx/README.md +154 -4
- package/tx/closure/closure-store.js +126 -3
- package/tx/cm/cm-database.js +69 -57
- package/tx/cm/cm-package.js +29 -1
- package/tx/cs/cs-api.js +284 -19
- package/tx/cs/cs-api.md +41 -4
- package/tx/cs/cs-areacode.js +1 -1
- package/tx/cs/cs-country.js +17 -5
- package/tx/cs/cs-cpt.js +33 -16
- package/tx/cs/cs-cs.js +148 -14
- package/tx/cs/cs-currency.js +1 -1
- package/tx/cs/cs-icd11.js +21 -13
- package/tx/cs/cs-icf.js +22 -3
- package/tx/cs/cs-lang.js +2 -2
- package/tx/cs/cs-loinc.js +185 -66
- package/tx/cs/cs-mimetypes.js +12 -2
- package/tx/cs/cs-ndc.js +40 -25
- package/tx/cs/cs-omop.js +54 -29
- package/tx/cs/cs-rxnorm.js +300 -196
- package/tx/cs/cs-snomed.js +608 -64
- package/tx/cs/cs-ucum.js +14 -4
- package/tx/cs/cs-unii.js +18 -14
- package/tx/cs/cs-virtual.js +210 -0
- package/tx/ecosystem-resolver.js +413 -0
- package/tx/html/cluster-dash-metrics.liquid +26 -0
- package/tx/html/cluster-home-metrics.liquid +31 -0
- package/tx/html/cluster-metrics-script.liquid +251 -0
- package/tx/html/codesystem-operations.liquid +3 -3
- package/tx/html/ecl-panel.liquid +1 -1
- package/tx/html/external-metrics.liquid +17 -0
- package/tx/html/operations-form.liquid +17 -17
- package/tx/html/search-form.liquid +11 -11
- package/tx/html/status-line.liquid +58 -0
- package/tx/html/status-panel.liquid +140 -0
- package/tx/html/status-tasks.liquid +25 -0
- package/tx/html/tx-template.html +2 -5
- package/tx/importers/atc-to-fhir.js +17 -16
- package/tx/importers/export-icd11-codesystem.js +3 -2
- package/tx/importers/import-icd11.js +4 -3
- package/tx/importers/import-loinc.module.js +118 -56
- package/tx/importers/import-ndc.module.js +56 -44
- package/tx/importers/import-rxnorm.module.js +118 -79
- package/tx/importers/import-sct.module.js +57 -58
- package/tx/importers/import-unii.module.js +37 -36
- package/tx/importers/subset-loinc.module.js +49 -48
- package/tx/importers/subset-rxnorm.module.js +29 -28
- package/tx/importers/terminal.js +18 -0
- package/tx/importers/tx-import-base.js +13 -12
- package/tx/importers/tx-import-settings.js +5 -4
- package/tx/importers/tx-import.js +53 -52
- package/tx/library/canonical-resource.js +49 -0
- package/tx/library/codesystem.js +94 -5
- package/tx/library/designations.js +45 -2
- package/tx/library/extensions.js +13 -7
- package/tx/library/implicit-valuesets.js +66 -0
- package/tx/library/renderer.js +77 -21
- package/tx/library/sqlite-utilities.js +2 -0
- package/tx/library/ucum-parsers.js +11 -1
- package/tx/library/wait-for-cache.js +43 -0
- package/tx/library.js +321 -22
- package/tx/openapi-operations.js +6 -4
- package/tx/operation-context.js +460 -99
- package/tx/params.js +25 -0
- package/tx/problems.js +3 -5
- package/tx/provider.js +278 -42
- package/tx/resource-cache-sqlite.js +1050 -0
- package/tx/sct/ecl.js +47 -6
- package/tx/sct/editions.js +39 -0
- package/tx/sct/expressions.js +10 -1
- package/tx/sct/load-config.js +107 -0
- package/tx/sct/mmap.js +109 -0
- package/tx/sct/structures.js +166 -13
- package/tx/sct/text-index.js +5 -1
- package/tx/syndication/syndication-feed.js +2 -2
- package/tx/tx-html.js +44 -8
- package/tx/tx.fhir.org.yml +8 -8
- package/tx/tx.js +282 -80
- package/tx/usage-tracker.js +39 -11
- package/tx/vs/vs-api.js +19 -0
- package/tx/vs/vs-database.js +386 -62
- package/tx/vs/vs-package.js +27 -4
- package/tx/vs/vs-vsac.js +648 -100
- package/tx/workers/batch-validate.js +37 -10
- package/tx/workers/batch.js +6 -1
- package/tx/workers/cache-control.js +15 -4
- package/tx/workers/closure.js +156 -13
- package/tx/workers/compare.js +8 -5
- package/tx/workers/expand.js +1173 -289
- package/tx/workers/metadata.js +35 -0
- package/tx/workers/search.js +53 -1
- package/tx/workers/supplement-filters.js +145 -0
- package/tx/workers/translate.js +169 -4
- package/tx/workers/validate.js +223 -119
- package/tx/workers/worker.js +123 -31
- package/tx/xversion/xv-valueset.js +7 -4
- package/utilities/submit-test-report.js +3 -1
- package/utilities/tx-stress-test.js +482 -0
- package/vcl/readme.md +37 -0
- package/vcl/vcl-parser.js +15 -0
- package/xig/readme.md +52 -0
- package/xig/xig-template.html +5 -8
- package/xig/xig.js +238 -422
- package/changelog-template.md +0 -22
- package/registry/test-runner.js +0 -237
- package/release.sh +0 -80
- package/test-scripts/repro-re2-wasm-leak.js +0 -34
- package/tsconfig.eslint.json +0 -9
- package/tx/html/dash-metrics.liquid +0 -147
- package/tx/html/home-metrics.liquid +0 -225
package/tx/library/renderer.js
CHANGED
|
@@ -23,14 +23,28 @@ const VALID_CONCEPTMAP_EQUIVALENCES = new Set([
|
|
|
23
23
|
const VALID_CODESYSTEM_CONTENT = new Set([
|
|
24
24
|
'not-present', 'example', 'fragment', 'complete', 'supplement'
|
|
25
25
|
]);
|
|
26
|
+
// How many of an include's listed codes displayValueSetInclude writes out before
|
|
27
|
+
// summarising the rest as a count.
|
|
28
|
+
const MAX_INCLUDE_CODES_SHOWN = 20;
|
|
29
|
+
|
|
26
30
|
const VALID_PUBLICATION_STATUS = new Set(['draft', 'active', 'retired', 'unknown']);
|
|
27
31
|
|
|
32
|
+
/**
|
|
33
|
+
* How many of the codes a ValueSet.compose include (or exclude) lists are rendered by
|
|
34
|
+
* default. Past this, the list ends with a line saying how many more there are and, when
|
|
35
|
+
* the renderer has been given showAllCodesHref, a link to the page with all of them.
|
|
36
|
+
* VSAC's Medication Brand Name lists 33,341 codes in one include.
|
|
37
|
+
*/
|
|
38
|
+
const MAX_RENDERED_INCLUDE_CODES = 500;
|
|
39
|
+
|
|
28
40
|
/**
|
|
29
41
|
* @typedef {Object} TerminologyLinkResolver
|
|
30
42
|
* @property {function(OperationContext, string, string=): {description: string, link: string}|null} resolveURL
|
|
31
43
|
* Given a URL and optional version, returns description and link, or null if not found
|
|
32
44
|
* @property {function(OperationContext, string, string, string=): {display: string, link: string}|null} resolveCode
|
|
33
45
|
* Given a URL, code, and optional version, returns display and link, or null if not found
|
|
46
|
+
* @property {function(OperationContext, string, string, string[]): Array<{description: string, link: string}|null>} [resolveCodes]
|
|
47
|
+
* resolveCode for many codes of one code system, in their order; used where present
|
|
34
48
|
*/
|
|
35
49
|
|
|
36
50
|
class Renderer {
|
|
@@ -38,6 +52,10 @@ class Renderer {
|
|
|
38
52
|
constructor(opContext, linkResolver = null) {
|
|
39
53
|
this.opContext = opContext;
|
|
40
54
|
this.linkResolver = linkResolver;
|
|
55
|
+
/** How many codes of an include to render; null renders them all. */
|
|
56
|
+
this.includeCodeLimit = MAX_RENDERED_INCLUDE_CODES;
|
|
57
|
+
/** Where "Show all" goes when an include is cut short; null for no link. */
|
|
58
|
+
this.showAllCodesHref = null;
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
displayCoded(...args) {
|
|
@@ -108,22 +126,21 @@ class Renderer {
|
|
|
108
126
|
return '[' + result + ']';
|
|
109
127
|
}
|
|
110
128
|
|
|
129
|
+
/**
|
|
130
|
+
* A one-line summary of a compose include/exclude, for the operation log and the
|
|
131
|
+
* $validate-code diagnostics. An include that lists many codes is summarised: the
|
|
132
|
+
* first MAX_INCLUDE_CODES_SHOWN codes, then how many more there are. (Written in
|
|
133
|
+
* full, a 33,000-code include is a ~250 KB string, built and kept for every
|
|
134
|
+
* validation against the value set.)
|
|
135
|
+
*/
|
|
111
136
|
displayValueSetInclude(inc) {
|
|
112
137
|
let result;
|
|
113
138
|
if (inc.system) {
|
|
114
139
|
result = '(' + inc.system + ')';
|
|
115
140
|
if (inc.concept) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (first) {
|
|
120
|
-
first = false;
|
|
121
|
-
} else {
|
|
122
|
-
result = result + ',';
|
|
123
|
-
}
|
|
124
|
-
result = result + cc.code;
|
|
125
|
-
}
|
|
126
|
-
result = result + ')';
|
|
141
|
+
const shown = inc.concept.slice(0, MAX_INCLUDE_CODES_SHOWN).map(cc => cc.code).join(',');
|
|
142
|
+
const more = inc.concept.length - MAX_INCLUDE_CODES_SHOWN;
|
|
143
|
+
result = result + '(' + shown + (more > 0 ? ',... +' + more + ' more (' + inc.concept.length + ' codes)' : '') + ')';
|
|
127
144
|
}
|
|
128
145
|
if (inc.filter) {
|
|
129
146
|
result = result + '(';
|
|
@@ -297,6 +314,7 @@ class Renderer {
|
|
|
297
314
|
span.tx(value);
|
|
298
315
|
let btn = span.button();
|
|
299
316
|
btn.attr("class", "btn-copy");
|
|
317
|
+
btn.attr("aria-label", "Copy");
|
|
300
318
|
btn.attr("data-clipboard-text", value);
|
|
301
319
|
btn.attr("data-original-title", this.translate('GENERAL_COPY'));
|
|
302
320
|
}
|
|
@@ -631,15 +649,15 @@ class Renderer {
|
|
|
631
649
|
this._requireAllowed(vs.status, VALID_PUBLICATION_STATUS, 'ValueSet.status', 'invalid status');
|
|
632
650
|
|
|
633
651
|
let div_ = div();
|
|
634
|
-
div_.
|
|
652
|
+
div_.h4().tx("Properties");
|
|
635
653
|
let tbl = div_.table("grid");
|
|
636
654
|
await this.renderMetadataTable(vs, tbl);
|
|
637
655
|
if (vs.compose) {
|
|
638
|
-
div_.
|
|
656
|
+
div_.h4().tx("Logical Definition");
|
|
639
657
|
await this.renderCompose(vs, div_.table("grid"));
|
|
640
658
|
}
|
|
641
659
|
if (vs.expansion) {
|
|
642
|
-
div_.
|
|
660
|
+
div_.h4().tx("Expansion");
|
|
643
661
|
await this.renderExpansion(div_, vs, tbl);
|
|
644
662
|
}
|
|
645
663
|
|
|
@@ -726,8 +744,14 @@ class Renderer {
|
|
|
726
744
|
const ul = li.ul();
|
|
727
745
|
for (let c of inc.concept) {
|
|
728
746
|
this._requireValidCode(c.code, 'ValueSet.compose.include.concept.code');
|
|
747
|
+
}
|
|
748
|
+
const limit = this.includeCodeLimit;
|
|
749
|
+
const shown = limit != null && inc.concept.length > limit ? inc.concept.slice(0, limit) : inc.concept;
|
|
750
|
+
const links = await this.resolveIncludeCodes(inc, shown);
|
|
751
|
+
for (let i = 0; i < shown.length; i++) {
|
|
752
|
+
const c = shown[i];
|
|
753
|
+
const link = links[i];
|
|
729
754
|
const li = ul.li();
|
|
730
|
-
const link = this.linkResolver ? await this.linkResolver.resolveCode(this.opContext, inc.system, inc.version, c.code) : null;
|
|
731
755
|
if (link) {
|
|
732
756
|
li.ah(link.link).tx(c.code);
|
|
733
757
|
} else {
|
|
@@ -739,6 +763,15 @@ class Renderer {
|
|
|
739
763
|
li.span("opaque: 0.5").tx(": "+link.description);
|
|
740
764
|
}
|
|
741
765
|
}
|
|
766
|
+
if (shown.length < inc.concept.length) {
|
|
767
|
+
const more = inc.concept.length - shown.length;
|
|
768
|
+
const li = ul.li();
|
|
769
|
+
li.i().tx(`\u2026 and ${more.toLocaleString('en-US')} more code${more === 1 ? '' : 's'}.`);
|
|
770
|
+
if (this.showAllCodesHref) {
|
|
771
|
+
li.tx(" ");
|
|
772
|
+
li.ah(this.showAllCodesHref).tx("Show all");
|
|
773
|
+
}
|
|
774
|
+
}
|
|
742
775
|
} else {
|
|
743
776
|
li.tx(this.translate('VALUE_SET_CODES_FROM')+" ");
|
|
744
777
|
await this.renderLink(li,inc.system+(inc.version ? "|"+inc.version : ""));
|
|
@@ -777,6 +810,29 @@ class Renderer {
|
|
|
777
810
|
}
|
|
778
811
|
}
|
|
779
812
|
|
|
813
|
+
/**
|
|
814
|
+
* The link and description for each of the codes of an include that are shown, in one
|
|
815
|
+
* request to the link resolver for the include's code system where it can take one.
|
|
816
|
+
*
|
|
817
|
+
* @param {Object} inc the include
|
|
818
|
+
* @param {Object[]} concepts the include's concepts being rendered
|
|
819
|
+
* @returns {Promise<Array<{link: string, description: string}|null>>}
|
|
820
|
+
*/
|
|
821
|
+
async resolveIncludeCodes(inc, concepts) {
|
|
822
|
+
if (!this.linkResolver || concepts.length === 0) {
|
|
823
|
+
return concepts.map(() => null);
|
|
824
|
+
}
|
|
825
|
+
const codes = concepts.map((c) => c.code);
|
|
826
|
+
if (this.linkResolver.resolveCodes) {
|
|
827
|
+
return await this.linkResolver.resolveCodes(this.opContext, inc.system, inc.version, codes);
|
|
828
|
+
}
|
|
829
|
+
const links = [];
|
|
830
|
+
for (const code of codes) {
|
|
831
|
+
links.push(await this.linkResolver.resolveCode(this.opContext, inc.system, inc.version, code));
|
|
832
|
+
}
|
|
833
|
+
return links;
|
|
834
|
+
}
|
|
835
|
+
|
|
780
836
|
async generateProperties(x, cs) {
|
|
781
837
|
if (!cs.property || cs.property.length === 0) {
|
|
782
838
|
return false;
|
|
@@ -1389,7 +1445,7 @@ class Renderer {
|
|
|
1389
1445
|
let div_ = div();
|
|
1390
1446
|
let tbl;
|
|
1391
1447
|
if (showProps) {
|
|
1392
|
-
div_.
|
|
1448
|
+
div_.h3().tx("Expansion Properties");
|
|
1393
1449
|
tbl = div_.table("grid");
|
|
1394
1450
|
} else {
|
|
1395
1451
|
tbl = div(); // dummy
|
|
@@ -1828,7 +1884,7 @@ class Renderer {
|
|
|
1828
1884
|
|
|
1829
1885
|
// Formats
|
|
1830
1886
|
if (cs.format && cs.format.length > 0) {
|
|
1831
|
-
div_.
|
|
1887
|
+
div_.h4().tx(this.translate('Formats') || 'Formats');
|
|
1832
1888
|
div_.para().tx(cs.format.join(', '));
|
|
1833
1889
|
}
|
|
1834
1890
|
|
|
@@ -2098,7 +2154,7 @@ class Renderer {
|
|
|
2098
2154
|
|
|
2099
2155
|
// Code Systems
|
|
2100
2156
|
if (tc.codeSystem && tc.codeSystem.length > 0) {
|
|
2101
|
-
div_.
|
|
2157
|
+
div_.h4().tx('Code Systems');
|
|
2102
2158
|
const ul = div_.ul();
|
|
2103
2159
|
for (const cs of tc.codeSystem) {
|
|
2104
2160
|
if (cs.uri) {
|
|
@@ -2192,10 +2248,10 @@ class Renderer {
|
|
|
2192
2248
|
let div_ = div();
|
|
2193
2249
|
|
|
2194
2250
|
// Metadata table
|
|
2195
|
-
div_.
|
|
2251
|
+
div_.h4().tx("Properties");
|
|
2196
2252
|
await this.renderMetadataTable(cm, div_.table("grid"));
|
|
2197
2253
|
|
|
2198
|
-
div_.
|
|
2254
|
+
div_.h4("Mapping Details");
|
|
2199
2255
|
// Source/Target scope line (mirrors Java: CONC_MAP_FROM / CONC_MAP_TO)
|
|
2200
2256
|
const p = div_.para();
|
|
2201
2257
|
p.tx(this.translate('CONC_MAP_FROM') + " ");
|
|
@@ -2769,4 +2825,4 @@ class Renderer {
|
|
|
2769
2825
|
|
|
2770
2826
|
}
|
|
2771
2827
|
|
|
2772
|
-
module.exports = { Renderer, VALID_FILTER_OPS };
|
|
2828
|
+
module.exports = { Renderer, VALID_FILTER_OPS, MAX_RENDERED_INCLUDE_CODES, MAX_INCLUDE_CODES_SHOWN };
|
|
@@ -185,6 +185,11 @@ class Lexer {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
// Expression parser for UCUM unit expressions (port of ExpressionParser.java)
|
|
188
|
+
// A UCUM expression parses into a chain of Terms, one level per operator and per bracket, and
|
|
189
|
+
// the parser and every walker of the result recurse along that chain. Bound it so that a hostile
|
|
190
|
+
// unit is a clean error rather than a RangeError (stack overflow). Real units have a few terms.
|
|
191
|
+
const MAX_UCUM_TERMS = 100;
|
|
192
|
+
|
|
188
193
|
class ExpressionParser {
|
|
189
194
|
constructor(model) {
|
|
190
195
|
this.model = model;
|
|
@@ -192,6 +197,7 @@ class ExpressionParser {
|
|
|
192
197
|
|
|
193
198
|
parse(code) {
|
|
194
199
|
const lexer = new Lexer(code);
|
|
200
|
+
this.terms = 0;
|
|
195
201
|
const res = this._parseTerm(lexer, true);
|
|
196
202
|
|
|
197
203
|
if (!lexer.finished()) {
|
|
@@ -202,6 +208,9 @@ class ExpressionParser {
|
|
|
202
208
|
}
|
|
203
209
|
|
|
204
210
|
_parseTerm(lexer, first) {
|
|
211
|
+
if (++this.terms > MAX_UCUM_TERMS) {
|
|
212
|
+
lexer.error(`The unit has more than ${MAX_UCUM_TERMS} terms and brackets`);
|
|
213
|
+
}
|
|
205
214
|
const res = new Term();
|
|
206
215
|
|
|
207
216
|
if (first && lexer.getType() === TokenType.NONE) {
|
|
@@ -1026,5 +1035,6 @@ module.exports = {
|
|
|
1026
1035
|
UcumEssenceParser,
|
|
1027
1036
|
Search,
|
|
1028
1037
|
Converter,
|
|
1029
|
-
UcumValidator
|
|
1038
|
+
UcumValidator,
|
|
1039
|
+
MAX_UCUM_TERMS
|
|
1030
1040
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tx-worker (cluster.md) only reads the package caches the master builds. Until the master
|
|
3
|
+
* has finished one - normally it has, since the workers start once it is ready - the worker
|
|
4
|
+
* waits for it, and gives up with a clear error rather than building it itself.
|
|
5
|
+
*
|
|
6
|
+
* @module tx/library/wait-for-cache
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// how long a worker waits for the master to finish a cache, and how often it looks
|
|
10
|
+
const DEFAULT_WAIT_MS = 5 * 60 * 1000;
|
|
11
|
+
const POLL_MS = 500;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resolve once isReady() says true; reject if it hasn't within waitMs.
|
|
15
|
+
*
|
|
16
|
+
* @param {function(): Promise<boolean>} isReady
|
|
17
|
+
* @param {string} what - the cache, for the messages
|
|
18
|
+
* @param {Object} [options]
|
|
19
|
+
* @param {number} [options.waitMs] - default DEFAULT_WAIT_MS, or FHIRSMITH_CACHE_WAIT_MS
|
|
20
|
+
* @returns {Promise<void>}
|
|
21
|
+
*/
|
|
22
|
+
async function waitForCache(isReady, what, options = {}) {
|
|
23
|
+
const waitMs = options.waitMs ?? (Number(process.env.FHIRSMITH_CACHE_WAIT_MS) || DEFAULT_WAIT_MS);
|
|
24
|
+
const start = Date.now();
|
|
25
|
+
let logged = false;
|
|
26
|
+
for (;;) {
|
|
27
|
+
if (await isReady()) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (Date.now() - start >= waitMs) {
|
|
31
|
+
throw new Error(`${what} is not ready after ${Math.round(waitMs / 1000)} s. A tx-worker only reads it; ` +
|
|
32
|
+
'the master builds it: start the master first, and the workers once it answers /health (cluster.md)');
|
|
33
|
+
}
|
|
34
|
+
if (!logged) {
|
|
35
|
+
logged = true;
|
|
36
|
+
require('../../library/logger').getInstance().child({ module: 'tx' })
|
|
37
|
+
.warn(`${what} is missing, incomplete or not yet migrated: waiting for the master to finish it`);
|
|
38
|
+
}
|
|
39
|
+
await new Promise(resolve => setTimeout(resolve, POLL_MS));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { waitForCache };
|