gdc-sdk-node-ts 2.9.20 → 2.9.21
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Input resolved by an authenticated application BFF, never directly by a browser. */
|
|
2
2
|
export type TerminologyValueSetInput = Readonly<{
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/** Optional per-request override. Dedicated BFFs normally configure this once on the client. */
|
|
4
|
+
sector?: string;
|
|
5
5
|
claim: string;
|
|
6
6
|
fhirVersion?: 'R4';
|
|
7
7
|
language?: string;
|
|
@@ -11,6 +11,7 @@ export type TerminologyValueSetInput = Readonly<{
|
|
|
11
11
|
offset?: number;
|
|
12
12
|
count?: number;
|
|
13
13
|
}>;
|
|
14
|
+
export type TerminologyValueSetCodeListInput = Omit<TerminologyValueSetInput, 'offset' | 'count'>;
|
|
14
15
|
export type TerminologyValueSetOption = Readonly<{
|
|
15
16
|
system: string;
|
|
16
17
|
code: string;
|
|
@@ -66,11 +67,23 @@ export type TerminologyValueSetResult = Readonly<{
|
|
|
66
67
|
document: TerminologyValueSetDocument;
|
|
67
68
|
cacheStatus: 'remote' | 'fresh-cache' | 'stale-cache' | 'english-fallback-cache';
|
|
68
69
|
}>;
|
|
70
|
+
/** Frontend-ready code list. Coding system and code remain separate FHIR Coding values. */
|
|
71
|
+
export type TerminologyValueSetCodeList = Readonly<{
|
|
72
|
+
codingSystem: string;
|
|
73
|
+
codeToDisplay: Readonly<Record<string, string>>;
|
|
74
|
+
requestedLanguage: string;
|
|
75
|
+
resolvedLanguage: string;
|
|
76
|
+
fallbackUsed: boolean;
|
|
77
|
+
valueSet: TerminologyValueSetDocument['meta']['valueSet'];
|
|
78
|
+
terminologyVersions?: Readonly<Record<string, string>>;
|
|
79
|
+
}>;
|
|
69
80
|
/** Server-only client for a product-neutral terminology service. */
|
|
70
81
|
export declare class TerminologyServiceClient {
|
|
71
82
|
#private;
|
|
72
83
|
constructor(options: Readonly<{
|
|
73
84
|
baseUrl: string;
|
|
85
|
+
/** Default sector for a dedicated human-health or animal-health BFF. */
|
|
86
|
+
sector?: string;
|
|
74
87
|
serviceToken?: string;
|
|
75
88
|
fetchImplementation?: typeof fetch;
|
|
76
89
|
cache?: TerminologyValueSetCache;
|
|
@@ -80,4 +93,6 @@ export declare class TerminologyServiceClient {
|
|
|
80
93
|
}>);
|
|
81
94
|
/** Resolves the ValueSet bound by the service to one canonical flat claim. */
|
|
82
95
|
expandValueSetForClaim(input: TerminologyValueSetInput): Promise<TerminologyValueSetResult>;
|
|
96
|
+
/** Resolves every page and returns the simple code-to-display object expected by forms. */
|
|
97
|
+
getValueSetCodeListForClaim(input: TerminologyValueSetCodeListInput): Promise<TerminologyValueSetCodeList>;
|
|
83
98
|
}
|
|
@@ -9,12 +9,10 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
11
|
};
|
|
12
|
-
var _MemoryTerminologyValueSetCache_entries, _TerminologyServiceClient_instances, _TerminologyServiceClient_baseUrl, _TerminologyServiceClient_serviceToken, _TerminologyServiceClient_fetch, _TerminologyServiceClient_cache, _TerminologyServiceClient_cacheTtlMs, _TerminologyServiceClient_staleIfError, _TerminologyServiceClient_now, _TerminologyServiceClient_request, _TerminologyServiceClient_validateInput, _TerminologyServiceClient_isDocument;
|
|
12
|
+
var _MemoryTerminologyValueSetCache_entries, _TerminologyServiceClient_instances, _TerminologyServiceClient_baseUrl, _TerminologyServiceClient_serviceToken, _TerminologyServiceClient_sector, _TerminologyServiceClient_fetch, _TerminologyServiceClient_cache, _TerminologyServiceClient_cacheTtlMs, _TerminologyServiceClient_staleIfError, _TerminologyServiceClient_now, _TerminologyServiceClient_request, _TerminologyServiceClient_validateInput, _TerminologyServiceClient_isDocument;
|
|
13
13
|
const DEFAULT_TTL_MS = 5 * 60 * 1000;
|
|
14
14
|
function normalizedInput(input) {
|
|
15
15
|
return {
|
|
16
|
-
sector: input.sector.trim().toLowerCase(),
|
|
17
|
-
resourceType: input.resourceType.trim(),
|
|
18
16
|
claim: input.claim.trim(),
|
|
19
17
|
fhirVersion: input.fhirVersion ?? 'R4',
|
|
20
18
|
language: (input.language?.trim() || 'en').replace(/_/g, '-').toLowerCase(),
|
|
@@ -26,13 +24,27 @@ function normalizedInput(input) {
|
|
|
26
24
|
}
|
|
27
25
|
/** Stable key usable by in-memory, GCS, Firestore or PostgreSQL cache adapters. */
|
|
28
26
|
export function terminologyValueSetCacheKey(input) {
|
|
29
|
-
const
|
|
27
|
+
const normalizedTerminologyContext = normalizedInput(input);
|
|
30
28
|
return JSON.stringify([
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
normalizedTerminologyContext.fhirVersion,
|
|
30
|
+
input.sector?.trim().toLowerCase() ?? '',
|
|
31
|
+
normalizedTerminologyContext.claim,
|
|
32
|
+
normalizedTerminologyContext.language,
|
|
33
|
+
normalizedTerminologyContext.jurisdiction ?? '',
|
|
34
|
+
normalizedTerminologyContext.version ?? 'latest',
|
|
35
|
+
normalizedTerminologyContext.offset,
|
|
36
|
+
normalizedTerminologyContext.count,
|
|
34
37
|
]);
|
|
35
38
|
}
|
|
39
|
+
function resourceTypeFromClaim(claim) {
|
|
40
|
+
const canonicalClaim = claim.trim();
|
|
41
|
+
const separatorIndex = canonicalClaim.indexOf('.');
|
|
42
|
+
const resourceType = canonicalClaim.slice(0, separatorIndex);
|
|
43
|
+
if (separatorIndex < 1 || !/^[A-Z][A-Za-z0-9]*$/.test(resourceType)) {
|
|
44
|
+
throw new Error('claim must start with its FHIR resource type');
|
|
45
|
+
}
|
|
46
|
+
return resourceType;
|
|
47
|
+
}
|
|
36
48
|
/** Process-local cache suitable for warm BFF instances and immutable startup snapshots. */
|
|
37
49
|
export class MemoryTerminologyValueSetCache {
|
|
38
50
|
constructor() {
|
|
@@ -55,6 +67,7 @@ export class TerminologyServiceClient {
|
|
|
55
67
|
_TerminologyServiceClient_instances.add(this);
|
|
56
68
|
_TerminologyServiceClient_baseUrl.set(this, void 0);
|
|
57
69
|
_TerminologyServiceClient_serviceToken.set(this, void 0);
|
|
70
|
+
_TerminologyServiceClient_sector.set(this, void 0);
|
|
58
71
|
_TerminologyServiceClient_fetch.set(this, void 0);
|
|
59
72
|
_TerminologyServiceClient_cache.set(this, void 0);
|
|
60
73
|
_TerminologyServiceClient_cacheTtlMs.set(this, void 0);
|
|
@@ -62,6 +75,7 @@ export class TerminologyServiceClient {
|
|
|
62
75
|
_TerminologyServiceClient_now.set(this, void 0);
|
|
63
76
|
__classPrivateFieldSet(this, _TerminologyServiceClient_baseUrl, options.baseUrl.replace(/\/$/, ''), "f");
|
|
64
77
|
__classPrivateFieldSet(this, _TerminologyServiceClient_serviceToken, options.serviceToken?.trim() || undefined, "f");
|
|
78
|
+
__classPrivateFieldSet(this, _TerminologyServiceClient_sector, options.sector?.trim() || undefined, "f");
|
|
65
79
|
__classPrivateFieldSet(this, _TerminologyServiceClient_fetch, options.fetchImplementation ?? fetch, "f");
|
|
66
80
|
__classPrivateFieldSet(this, _TerminologyServiceClient_cache, options.cache ?? new MemoryTerminologyValueSetCache(), "f");
|
|
67
81
|
__classPrivateFieldSet(this, _TerminologyServiceClient_cacheTtlMs, options.cacheTtlMs ?? DEFAULT_TTL_MS, "f");
|
|
@@ -71,13 +85,17 @@ export class TerminologyServiceClient {
|
|
|
71
85
|
/** Resolves the ValueSet bound by the service to one canonical flat claim. */
|
|
72
86
|
async expandValueSetForClaim(input) {
|
|
73
87
|
__classPrivateFieldGet(this, _TerminologyServiceClient_instances, "m", _TerminologyServiceClient_validateInput).call(this, input);
|
|
74
|
-
const
|
|
88
|
+
const resolvedTerminologyContext = {
|
|
89
|
+
...input,
|
|
90
|
+
sector: input.sector?.trim() || __classPrivateFieldGet(this, _TerminologyServiceClient_sector, "f"),
|
|
91
|
+
};
|
|
92
|
+
const key = terminologyValueSetCacheKey(resolvedTerminologyContext);
|
|
75
93
|
const cached = await __classPrivateFieldGet(this, _TerminologyServiceClient_cache, "f").get(key);
|
|
76
94
|
if (cached && __classPrivateFieldGet(this, _TerminologyServiceClient_now, "f").call(this) - cached.storedAt <= __classPrivateFieldGet(this, _TerminologyServiceClient_cacheTtlMs, "f")) {
|
|
77
95
|
return { document: cached.document, cacheStatus: 'fresh-cache' };
|
|
78
96
|
}
|
|
79
97
|
try {
|
|
80
|
-
const document = await __classPrivateFieldGet(this, _TerminologyServiceClient_instances, "m", _TerminologyServiceClient_request).call(this,
|
|
98
|
+
const document = await __classPrivateFieldGet(this, _TerminologyServiceClient_instances, "m", _TerminologyServiceClient_request).call(this, resolvedTerminologyContext);
|
|
81
99
|
await __classPrivateFieldGet(this, _TerminologyServiceClient_cache, "f").set(key, { document, storedAt: __classPrivateFieldGet(this, _TerminologyServiceClient_now, "f").call(this) });
|
|
82
100
|
return { document, cacheStatus: 'remote' };
|
|
83
101
|
}
|
|
@@ -87,7 +105,10 @@ export class TerminologyServiceClient {
|
|
|
87
105
|
}
|
|
88
106
|
const requestedLanguage = input.language?.trim().toLowerCase();
|
|
89
107
|
if (__classPrivateFieldGet(this, _TerminologyServiceClient_staleIfError, "f") && requestedLanguage && requestedLanguage !== 'en') {
|
|
90
|
-
const english = await __classPrivateFieldGet(this, _TerminologyServiceClient_cache, "f").get(terminologyValueSetCacheKey({
|
|
108
|
+
const english = await __classPrivateFieldGet(this, _TerminologyServiceClient_cache, "f").get(terminologyValueSetCacheKey({
|
|
109
|
+
...resolvedTerminologyContext,
|
|
110
|
+
language: 'en',
|
|
111
|
+
}));
|
|
91
112
|
if (english) {
|
|
92
113
|
return { document: english.document, cacheStatus: 'english-fallback-cache' };
|
|
93
114
|
}
|
|
@@ -95,11 +116,61 @@ export class TerminologyServiceClient {
|
|
|
95
116
|
throw new Error('Terminology service request failed');
|
|
96
117
|
}
|
|
97
118
|
}
|
|
119
|
+
/** Resolves every page and returns the simple code-to-display object expected by forms. */
|
|
120
|
+
async getValueSetCodeListForClaim(input) {
|
|
121
|
+
const pageSize = 100;
|
|
122
|
+
let nextOffset = 0;
|
|
123
|
+
let totalOptionCount = 0;
|
|
124
|
+
let codingSystem = '';
|
|
125
|
+
let resolvedLanguage = '';
|
|
126
|
+
let fallbackUsed = false;
|
|
127
|
+
let resolvedValueSet;
|
|
128
|
+
let terminologyVersions;
|
|
129
|
+
const codeToDisplay = {};
|
|
130
|
+
do {
|
|
131
|
+
const valueSetPage = await this.expandValueSetForClaim({
|
|
132
|
+
...input,
|
|
133
|
+
offset: nextOffset,
|
|
134
|
+
count: pageSize,
|
|
135
|
+
});
|
|
136
|
+
const { document } = valueSetPage;
|
|
137
|
+
totalOptionCount = document.meta.total;
|
|
138
|
+
resolvedLanguage || (resolvedLanguage = document.meta.language);
|
|
139
|
+
resolvedValueSet ?? (resolvedValueSet = document.meta.valueSet);
|
|
140
|
+
terminologyVersions ?? (terminologyVersions = document.meta.terminologyVersions);
|
|
141
|
+
if (resolvedValueSet.system !== document.meta.valueSet.system) {
|
|
142
|
+
throw new Error('Terminology service returned inconsistent ValueSet pages');
|
|
143
|
+
}
|
|
144
|
+
for (const terminologyOptionResource of document.data) {
|
|
145
|
+
const terminologyOption = terminologyOptionResource.attributes;
|
|
146
|
+
if (codingSystem && codingSystem !== terminologyOption.system) {
|
|
147
|
+
throw new Error('Terminology ValueSet contains more than one coding system');
|
|
148
|
+
}
|
|
149
|
+
codingSystem || (codingSystem = terminologyOption.system);
|
|
150
|
+
codeToDisplay[terminologyOption.code] = terminologyOption.localizedDisplay;
|
|
151
|
+
fallbackUsed || (fallbackUsed = terminologyOption.fallbackUsed);
|
|
152
|
+
}
|
|
153
|
+
if (document.data.length === 0 && nextOffset < totalOptionCount) {
|
|
154
|
+
throw new Error('Terminology service returned an incomplete ValueSet page');
|
|
155
|
+
}
|
|
156
|
+
nextOffset += document.data.length;
|
|
157
|
+
} while (nextOffset < totalOptionCount);
|
|
158
|
+
if (!resolvedValueSet)
|
|
159
|
+
throw new Error('Terminology service returned no ValueSet metadata');
|
|
160
|
+
return {
|
|
161
|
+
codingSystem: codingSystem || resolvedValueSet.system,
|
|
162
|
+
codeToDisplay,
|
|
163
|
+
requestedLanguage: (input.language?.trim() || 'en').replace(/_/g, '-').toLowerCase(),
|
|
164
|
+
resolvedLanguage: resolvedLanguage || 'en',
|
|
165
|
+
fallbackUsed,
|
|
166
|
+
valueSet: resolvedValueSet,
|
|
167
|
+
...(terminologyVersions ? { terminologyVersions } : {}),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
98
170
|
}
|
|
99
|
-
_TerminologyServiceClient_baseUrl = new WeakMap(), _TerminologyServiceClient_serviceToken = new WeakMap(), _TerminologyServiceClient_fetch = new WeakMap(), _TerminologyServiceClient_cache = new WeakMap(), _TerminologyServiceClient_cacheTtlMs = new WeakMap(), _TerminologyServiceClient_staleIfError = new WeakMap(), _TerminologyServiceClient_now = new WeakMap(), _TerminologyServiceClient_instances = new WeakSet(), _TerminologyServiceClient_request = async function _TerminologyServiceClient_request(input) {
|
|
171
|
+
_TerminologyServiceClient_baseUrl = new WeakMap(), _TerminologyServiceClient_serviceToken = new WeakMap(), _TerminologyServiceClient_sector = new WeakMap(), _TerminologyServiceClient_fetch = new WeakMap(), _TerminologyServiceClient_cache = new WeakMap(), _TerminologyServiceClient_cacheTtlMs = new WeakMap(), _TerminologyServiceClient_staleIfError = new WeakMap(), _TerminologyServiceClient_now = new WeakMap(), _TerminologyServiceClient_instances = new WeakSet(), _TerminologyServiceClient_request = async function _TerminologyServiceClient_request(input) {
|
|
100
172
|
const url = new URL(`${__classPrivateFieldGet(this, _TerminologyServiceClient_baseUrl, "f")}/v1/terminology/value-set-options`);
|
|
101
|
-
url.searchParams.set('sector', input.sector
|
|
102
|
-
url.searchParams.set('resourceType', input.resourceType.trim());
|
|
173
|
+
url.searchParams.set('sector', input.sector?.trim() || __classPrivateFieldGet(this, _TerminologyServiceClient_sector, "f") || '');
|
|
103
174
|
url.searchParams.set('claim', input.claim.trim());
|
|
104
175
|
url.searchParams.set('offset', String(input.offset ?? 0));
|
|
105
176
|
url.searchParams.set('count', String(input.count ?? 50));
|
|
@@ -124,12 +195,11 @@ _TerminologyServiceClient_baseUrl = new WeakMap(), _TerminologyServiceClient_ser
|
|
|
124
195
|
throw new Error('Terminology service returned an invalid document');
|
|
125
196
|
return document;
|
|
126
197
|
}, _TerminologyServiceClient_validateInput = function _TerminologyServiceClient_validateInput(input) {
|
|
127
|
-
if (!input.sector
|
|
198
|
+
if (!(input.sector?.trim() || __classPrivateFieldGet(this, _TerminologyServiceClient_sector, "f")))
|
|
128
199
|
throw new Error('sector is required');
|
|
129
|
-
if (!input.resourceType.trim())
|
|
130
|
-
throw new Error('resourceType is required');
|
|
131
200
|
if (!input.claim.trim())
|
|
132
201
|
throw new Error('claim is required');
|
|
202
|
+
resourceTypeFromClaim(input.claim);
|
|
133
203
|
if (input.offset !== undefined && (!Number.isInteger(input.offset) || input.offset < 0)) {
|
|
134
204
|
throw new Error('offset must be a non-negative integer');
|
|
135
205
|
}
|
|
@@ -142,7 +212,7 @@ _TerminologyServiceClient_baseUrl = new WeakMap(), _TerminologyServiceClient_ser
|
|
|
142
212
|
const document = value;
|
|
143
213
|
if (document.jsonapi?.version !== '1.1' || !Array.isArray(document.data) || !document.meta)
|
|
144
214
|
return false;
|
|
145
|
-
if (document.meta.resourceType !== input.
|
|
215
|
+
if (document.meta.resourceType !== resourceTypeFromClaim(input.claim) || document.meta.claim !== input.claim.trim())
|
|
146
216
|
return false;
|
|
147
217
|
return document.data.every((resource) => (resource?.type === 'terminology-option'
|
|
148
218
|
&& typeof resource.id === 'string'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdc-sdk-node-ts",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.21",
|
|
4
4
|
"description": "Next-generation Node runtime package for the GDC SDK family",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Antifraud Services Inc.",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"test:e2e:live-gw:clean": "bash ./scripts/run-live-gw-clean.sh"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"gdc-common-utils-ts": "2.9.
|
|
41
|
+
"gdc-common-utils-ts": "2.9.20",
|
|
42
42
|
"gdc-sdk-core-ts": "2.9.10"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|