@openfn/language-fhir-4 0.4.1 → 0.5.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/configuration-schema.json +52 -59
- package/dist/index.cjs +61 -25
- package/dist/index.js +1304 -1268
- package/package.json +3 -2
|
@@ -2,63 +2,56 @@
|
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"type": "object",
|
|
4
4
|
"properties": {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"examples": [
|
|
56
|
-
"the-long-access-token-from-your-auth"
|
|
57
|
-
]
|
|
58
|
-
}
|
|
5
|
+
"baseUrl": {
|
|
6
|
+
"title": "Base Url",
|
|
7
|
+
"type": "string",
|
|
8
|
+
"description": "The baseUrl",
|
|
9
|
+
"examples": ["https://hapi.fhir.org"]
|
|
10
|
+
},
|
|
11
|
+
"apiPath": {
|
|
12
|
+
"title": "API Path",
|
|
13
|
+
"anyOf": [
|
|
14
|
+
{
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"type": "null"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"placeholder": "R4",
|
|
22
|
+
"description": "FHIR api path",
|
|
23
|
+
"minLength": 1,
|
|
24
|
+
"examples": ["baseR4", "R3", "R4"]
|
|
25
|
+
},
|
|
26
|
+
"username": {
|
|
27
|
+
"title": "Username",
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "Username",
|
|
30
|
+
"examples": ["openfn_test"]
|
|
31
|
+
},
|
|
32
|
+
"password": {
|
|
33
|
+
"title": "Password",
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Password",
|
|
36
|
+
"writeOnly": true,
|
|
37
|
+
"examples": ["@some(!)Str0ngp4ss0w0rd"]
|
|
38
|
+
},
|
|
39
|
+
"access_token": {
|
|
40
|
+
"title": "Access Token",
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Your FHIR access token",
|
|
43
|
+
"writeOnly": true,
|
|
44
|
+
"minLength": 1,
|
|
45
|
+
"examples": ["the-long-access-token-from-your-auth"]
|
|
46
|
+
},
|
|
47
|
+
"authorization": {
|
|
48
|
+
"title": "Authorization Header",
|
|
49
|
+
"type": "string",
|
|
50
|
+
"description": "Custom Authorization header value",
|
|
51
|
+
"writeOnly": true,
|
|
52
|
+
"minLength": 1,
|
|
53
|
+
"examples": ["custom 12345"]
|
|
54
|
+
}
|
|
59
55
|
},
|
|
60
|
-
"required": [
|
|
61
|
-
|
|
62
|
-
"apiPath"
|
|
63
|
-
]
|
|
64
|
-
}
|
|
56
|
+
"required": ["baseUrl", "apiPath"]
|
|
57
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -79,6 +79,7 @@ var import_util2 = require("@openfn/language-common/util");
|
|
|
79
79
|
|
|
80
80
|
// src/util.ts
|
|
81
81
|
var import_node_path = __toESM(require("path"), 1);
|
|
82
|
+
var import_lodash_es = __toESM(require("lodash-es"), 1);
|
|
82
83
|
var import_language_common = require("@openfn/language-common");
|
|
83
84
|
var import_util = require("@openfn/language-common/util");
|
|
84
85
|
function assertValidResourceId(id2) {
|
|
@@ -91,18 +92,22 @@ function assertValidResourceId(id2) {
|
|
|
91
92
|
}
|
|
92
93
|
function addAuth(options) {
|
|
93
94
|
var _a;
|
|
94
|
-
if ((_a = options
|
|
95
|
+
if ((_a = options.headers) == null ? void 0 : _a.Authorization) {
|
|
95
96
|
return;
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
}
|
|
98
|
+
const { username, password, access_token, authorization } = options.configuration;
|
|
99
|
+
if (authorization) {
|
|
100
|
+
return { Authorization: authorization };
|
|
101
|
+
}
|
|
102
|
+
if (access_token || authorization) {
|
|
98
103
|
return { Authorization: `Bearer ${access_token}` };
|
|
99
|
-
}
|
|
104
|
+
}
|
|
105
|
+
if (username && password) {
|
|
100
106
|
return { ...(0, import_util.makeBasicAuthHeader)(username, password) };
|
|
101
107
|
}
|
|
102
|
-
return {};
|
|
103
108
|
}
|
|
104
109
|
var prepareNextState = (state, response) => {
|
|
105
|
-
const { body, ...responseWithoutBody } = response;
|
|
110
|
+
const { body, validationErrors, ...responseWithoutBody } = response;
|
|
106
111
|
return {
|
|
107
112
|
...(0, import_language_common.composeNextState)(state, body),
|
|
108
113
|
response: responseWithoutBody
|
|
@@ -130,15 +135,15 @@ var request = (method, path, options) => {
|
|
|
130
135
|
(0, import_util.assertRelativeUrl)(path);
|
|
131
136
|
const { configuration, ...otherOptions } = options;
|
|
132
137
|
const fullPath = import_node_path.default.join(configuration.apiPath ?? "/fhir", path);
|
|
133
|
-
const headers = addAuth(options);
|
|
134
138
|
const opts = {
|
|
135
139
|
...otherOptions,
|
|
136
140
|
headers: Object.assign(
|
|
137
|
-
|
|
141
|
+
{},
|
|
138
142
|
{
|
|
139
143
|
accept: "application/fhir+json",
|
|
140
144
|
"content-type": "application/fhir+json"
|
|
141
145
|
},
|
|
146
|
+
addAuth(options),
|
|
142
147
|
options.headers
|
|
143
148
|
),
|
|
144
149
|
baseUrl: configuration.baseUrl,
|
|
@@ -146,12 +151,12 @@ var request = (method, path, options) => {
|
|
|
146
151
|
};
|
|
147
152
|
return (0, import_util.request)(method, fullPath, opts).then(logResponse).then().catch(async (e) => {
|
|
148
153
|
if (e.headers && "content-type" in e.headers && e.headers["content-type"].match(/fhir\+json/)) {
|
|
149
|
-
logValidationErrors(e);
|
|
154
|
+
logValidationErrors(e, opts.body);
|
|
150
155
|
}
|
|
151
156
|
throw e;
|
|
152
157
|
});
|
|
153
158
|
};
|
|
154
|
-
function logValidationErrors(response, logger = console) {
|
|
159
|
+
function logValidationErrors(response, payload, logger = console) {
|
|
155
160
|
const error = JSON.parse(response.body);
|
|
156
161
|
if (error.issue && error.issue.length) {
|
|
157
162
|
delete response.body;
|
|
@@ -176,20 +181,35 @@ function logValidationErrors(response, logger = console) {
|
|
|
176
181
|
error.issue.forEach((issue) => {
|
|
177
182
|
var _a, _b, _c;
|
|
178
183
|
try {
|
|
179
|
-
let
|
|
184
|
+
let resourceId = "unidentified resource";
|
|
180
185
|
if (issue.location) {
|
|
181
|
-
|
|
182
|
-
if (
|
|
183
|
-
|
|
186
|
+
let idx = issue.location[0].match(/Bundle.entry\[(\d+)\]/);
|
|
187
|
+
if (idx && idx.length >= 2) {
|
|
188
|
+
idx = idx[1];
|
|
189
|
+
const resource = (_a = import_lodash_es.default.get(payload, `entry[${idx}]`)) == null ? void 0 : _a.resource;
|
|
190
|
+
if (resource) {
|
|
191
|
+
resourceId = `${resource.resourceType}/${resource.id}`;
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
if (payload.resourceType && payload.id) {
|
|
195
|
+
resourceId = `${payload.resourceType}/${payload.id}`;
|
|
196
|
+
}
|
|
184
197
|
}
|
|
185
|
-
} else {
|
|
186
|
-
console.log({ issue });
|
|
187
198
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
(
|
|
192
|
-
|
|
199
|
+
const type = `${issue.severity}s`;
|
|
200
|
+
groups[resourceId] ?? (groups[resourceId] = {});
|
|
201
|
+
let path = "*";
|
|
202
|
+
if (issue.location[0].match(/\.resource\./)) {
|
|
203
|
+
path = issue.location[0].split(/\.resource\./)[1];
|
|
204
|
+
} else if (issue.location.includes(`*${resourceId}*`)) {
|
|
205
|
+
const suffix = issue.location[0].split(/\.resource\./)[1];
|
|
206
|
+
if (suffix && suffix.length > 1) {
|
|
207
|
+
path = suffix;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
(_b = groups[resourceId])[type] ?? (_b[type] = {});
|
|
211
|
+
(_c = groups[resourceId][type])[path] ?? (_c[path] = []);
|
|
212
|
+
groups[resourceId][type][path].push(issue.diagnostics);
|
|
193
213
|
} catch (e) {
|
|
194
214
|
logger.log("error parsing issue at ", issue.location);
|
|
195
215
|
console.log(e);
|
|
@@ -197,26 +217,36 @@ function logValidationErrors(response, logger = console) {
|
|
|
197
217
|
});
|
|
198
218
|
for (const resource in groups) {
|
|
199
219
|
logger.log(`${resource} issues:`);
|
|
200
|
-
["
|
|
220
|
+
["errors", "warnings"].forEach((type) => {
|
|
201
221
|
if (type in groups[resource]) {
|
|
202
|
-
logger.log(` ${type}
|
|
222
|
+
logger.log(` ${type}:`.toUpperCase());
|
|
203
223
|
for (const path in groups[resource][type]) {
|
|
204
224
|
logger.log();
|
|
205
225
|
logger.log(" ", path);
|
|
206
226
|
for (const message of groups[resource][type][path]) {
|
|
207
|
-
|
|
227
|
+
const fn2 = type === "error" ? console.error : console.warn;
|
|
228
|
+
fn2(" -", message);
|
|
208
229
|
}
|
|
209
230
|
}
|
|
210
231
|
logger.log();
|
|
211
232
|
}
|
|
212
233
|
});
|
|
213
234
|
}
|
|
214
|
-
|
|
235
|
+
logger.log("Issues will be written to state.fhirValidationIssues");
|
|
236
|
+
response.$validationIssues = groups;
|
|
215
237
|
} else {
|
|
216
238
|
response.body = error;
|
|
217
239
|
}
|
|
218
240
|
return response;
|
|
219
241
|
}
|
|
242
|
+
function cleanResponseObject(state, response) {
|
|
243
|
+
if (response.$validationIssues) {
|
|
244
|
+
state.fhirValidationIssues ?? (state.fhirValidationIssues = {});
|
|
245
|
+
Object.assign(state.fhirValidationIssues, response.$validationIssues);
|
|
246
|
+
delete response.$validationIssues;
|
|
247
|
+
}
|
|
248
|
+
return state;
|
|
249
|
+
}
|
|
220
250
|
function collectRefs(value2) {
|
|
221
251
|
if (!value2 || typeof value2 !== "object")
|
|
222
252
|
return [];
|
|
@@ -383,6 +413,9 @@ function create(resource) {
|
|
|
383
413
|
const response = await request("POST", $resource.resourceType, {
|
|
384
414
|
configuration: state.configuration,
|
|
385
415
|
body: $resource
|
|
416
|
+
}).catch((e) => {
|
|
417
|
+
cleanResponseObject(state, e);
|
|
418
|
+
throw e;
|
|
386
419
|
});
|
|
387
420
|
console.log(`Created ${response.body.id}`);
|
|
388
421
|
return prepareNextState(state, response);
|
|
@@ -447,6 +480,9 @@ function uploadBundle(bundle = "bundle") {
|
|
|
447
480
|
const response = await request("POST", "/", {
|
|
448
481
|
configuration: state.configuration,
|
|
449
482
|
body: data
|
|
483
|
+
}).catch((e) => {
|
|
484
|
+
cleanResponseObject(state, e);
|
|
485
|
+
throw e;
|
|
450
486
|
});
|
|
451
487
|
return prepareNextState(state, response);
|
|
452
488
|
};
|