@healthcloudai/hc-safe-cdx 0.2.1 → 0.3.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/dist/index.cjs +214 -62
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +220 -61
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -20,20 +20,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
APIError: () => import_hc_http2.APIError,
|
|
24
|
+
ConfigError: () => import_hc_http2.ConfigError,
|
|
25
|
+
HCSafeCDXClient: () => HCSafeCDXClient,
|
|
26
|
+
HCServiceError: () => import_hc_http2.HCServiceError,
|
|
27
|
+
NetworkError: () => import_hc_http2.NetworkError,
|
|
28
|
+
ValidationError: () => import_hc_http2.ValidationError,
|
|
29
|
+
errorFromHttpStatus: () => import_hc_http2.errorFromHttpStatus
|
|
25
30
|
});
|
|
26
31
|
module.exports = __toCommonJS(index_exports);
|
|
27
32
|
|
|
28
33
|
// src/client.ts
|
|
29
|
-
var
|
|
30
|
-
constructor(message, response) {
|
|
31
|
-
super(message);
|
|
32
|
-
this.name = "SafeCDXError";
|
|
33
|
-
this.response = response;
|
|
34
|
-
Object.setPrototypeOf(this, _SafeCDXError.prototype);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
34
|
+
var import_hc_http = require("@healthcloudai/hc-http");
|
|
37
35
|
var ENV_HOST = {
|
|
38
36
|
dev: "dev-api-hcs.healthcloud-services.com",
|
|
39
37
|
uat: "uat-api-hcs.healthcloud-services.com",
|
|
@@ -43,7 +41,7 @@ var ROUTE_PREFIX = "api/console/hcservice/safecdx";
|
|
|
43
41
|
function buildSafeCdxBaseUrl(environment) {
|
|
44
42
|
const host = ENV_HOST[environment];
|
|
45
43
|
if (!host) {
|
|
46
|
-
throw new
|
|
44
|
+
throw new import_hc_http.ConfigError("Invalid Safe CDX environment.");
|
|
47
45
|
}
|
|
48
46
|
return `https://${host}/${ROUTE_PREFIX}`;
|
|
49
47
|
}
|
|
@@ -68,10 +66,10 @@ var HCSafeCDXClient = class {
|
|
|
68
66
|
const trimmedHeaderName = headerName == null ? void 0 : headerName.trim();
|
|
69
67
|
const trimmedValue = value == null ? void 0 : value.trim();
|
|
70
68
|
if (!trimmedHeaderName) {
|
|
71
|
-
throw new
|
|
69
|
+
throw new import_hc_http.ConfigError("API key header name is required.");
|
|
72
70
|
}
|
|
73
71
|
if (!trimmedValue) {
|
|
74
|
-
throw new
|
|
72
|
+
throw new import_hc_http.ConfigError("API key value is required.");
|
|
75
73
|
}
|
|
76
74
|
this.apiKeyHeaderName = trimmedHeaderName;
|
|
77
75
|
this.apiKeyValue = trimmedValue;
|
|
@@ -84,27 +82,34 @@ var HCSafeCDXClient = class {
|
|
|
84
82
|
* Resolves the SafeCDX test profile associated with a GTIN barcode.
|
|
85
83
|
*/
|
|
86
84
|
async getTestProfileByGTIN(gtin) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
const resolvedGtin = this.requireValue(gtin, "gtin");
|
|
86
|
+
return this.execute(
|
|
87
|
+
"getTestProfileByGTIN",
|
|
88
|
+
() => this.http.get(
|
|
89
|
+
this.url(`gs1/${encodeURIComponent(resolvedGtin)}`),
|
|
90
|
+
this.getAuthHeaders()
|
|
91
|
+
)
|
|
90
92
|
);
|
|
91
93
|
}
|
|
92
94
|
/**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
* POST test/profiles/by-account
|
|
96
|
+
|
|
97
|
+
*
|
|
98
|
+
* TenantId is resolved by the backend from the authenticated patient context.
|
|
99
|
+
*/
|
|
98
100
|
async getTestProfilesByAccount(includeRegisterTestDetails = true) {
|
|
99
101
|
const request = {
|
|
100
102
|
Data: {
|
|
101
103
|
IncludeRegisterTestDetails: includeRegisterTestDetails
|
|
102
104
|
}
|
|
103
105
|
};
|
|
104
|
-
return this.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
return this.execute(
|
|
107
|
+
"getTestProfilesByAccount",
|
|
108
|
+
() => this.http.post(
|
|
109
|
+
this.url("test/profiles/by-account"),
|
|
110
|
+
request,
|
|
111
|
+
this.getJsonHeaders()
|
|
112
|
+
)
|
|
108
113
|
);
|
|
109
114
|
}
|
|
110
115
|
// -------------------------------------------------------------------------
|
|
@@ -115,19 +120,25 @@ var HCSafeCDXClient = class {
|
|
|
115
120
|
* Requests a pre-signed URL used to upload a test image.
|
|
116
121
|
*/
|
|
117
122
|
async createUploadUrl(userTestResultId, gtin, imageType = "jpg") {
|
|
123
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
124
|
+
const resolvedGtin = this.requireValue(gtin, "gtin");
|
|
125
|
+
const resolvedImageType = this.requireValue(imageType, "imageType");
|
|
118
126
|
const request = {
|
|
119
127
|
Data: {
|
|
120
|
-
Gtin:
|
|
121
|
-
UserTestResultId:
|
|
128
|
+
Gtin: resolvedGtin,
|
|
129
|
+
UserTestResultId: resolvedUserTestResultId,
|
|
122
130
|
Metadata: {
|
|
123
|
-
ImageType:
|
|
131
|
+
ImageType: resolvedImageType
|
|
124
132
|
}
|
|
125
133
|
}
|
|
126
134
|
};
|
|
127
|
-
return this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
135
|
+
return this.execute(
|
|
136
|
+
"createUploadUrl",
|
|
137
|
+
() => this.http.post(
|
|
138
|
+
this.url("upload/url"),
|
|
139
|
+
request,
|
|
140
|
+
this.getJsonHeaders()
|
|
141
|
+
)
|
|
131
142
|
);
|
|
132
143
|
}
|
|
133
144
|
/**
|
|
@@ -138,10 +149,12 @@ var HCSafeCDXClient = class {
|
|
|
138
149
|
* authenticated Health Cloud headers.
|
|
139
150
|
*/
|
|
140
151
|
async uploadImage(preSignedURL, image, contentType = "image/jpeg") {
|
|
141
|
-
const
|
|
152
|
+
const resolvedPreSignedURL = this.requireValue(preSignedURL, "preSignedURL");
|
|
153
|
+
const resolvedContentType = this.requireValue(contentType, "contentType");
|
|
154
|
+
const response = await fetch(resolvedPreSignedURL, {
|
|
142
155
|
method: "PUT",
|
|
143
156
|
headers: {
|
|
144
|
-
"Content-Type":
|
|
157
|
+
"Content-Type": resolvedContentType
|
|
145
158
|
},
|
|
146
159
|
body: image
|
|
147
160
|
});
|
|
@@ -152,9 +165,15 @@ var HCSafeCDXClient = class {
|
|
|
152
165
|
} catch {
|
|
153
166
|
body = void 0;
|
|
154
167
|
}
|
|
155
|
-
throw new
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
throw new import_hc_http.APIError({
|
|
169
|
+
message: `uploadImage: image upload failed with HTTP ${response.status}.`,
|
|
170
|
+
code: response.status >= 500 ? "SERVER_ERROR" : "UNKNOWN_ERROR",
|
|
171
|
+
statusCode: response.status,
|
|
172
|
+
backendMessage: body,
|
|
173
|
+
details: {
|
|
174
|
+
status: response.status,
|
|
175
|
+
body
|
|
176
|
+
}
|
|
158
177
|
});
|
|
159
178
|
}
|
|
160
179
|
}
|
|
@@ -166,20 +185,32 @@ var HCSafeCDXClient = class {
|
|
|
166
185
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
167
186
|
*/
|
|
168
187
|
async updateCvmlStatus(imageOfCaptureId, cvmlStatus) {
|
|
188
|
+
const resolvedImageOfCaptureId = this.requireValue(imageOfCaptureId, "imageOfCaptureId");
|
|
189
|
+
const resolvedCvmlStatus = this.requireValue(cvmlStatus, "cvmlStatus");
|
|
169
190
|
const request = {
|
|
170
191
|
Data: {
|
|
171
|
-
ImageOfCaptureId:
|
|
172
|
-
CvmlStatus:
|
|
192
|
+
ImageOfCaptureId: resolvedImageOfCaptureId,
|
|
193
|
+
CvmlStatus: resolvedCvmlStatus
|
|
173
194
|
}
|
|
174
195
|
};
|
|
175
|
-
return this.
|
|
196
|
+
return this.executeSafe(
|
|
197
|
+
"updateCvmlStatus",
|
|
198
|
+
() => this.http.post(this.url("cvml/status"), request, this.getJsonHeaders())
|
|
199
|
+
);
|
|
176
200
|
}
|
|
177
201
|
/**
|
|
178
202
|
* GET cvml/results
|
|
179
203
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
180
204
|
*/
|
|
181
205
|
async getCvmlResults(imageOfCaptureId) {
|
|
182
|
-
|
|
206
|
+
const resolvedImageOfCaptureId = this.requireValue(imageOfCaptureId, "imageOfCaptureId");
|
|
207
|
+
return this.executeSafe(
|
|
208
|
+
"getCvmlResults",
|
|
209
|
+
() => this.http.get(
|
|
210
|
+
this.url("cvml/results", { imageOfCaptureId: resolvedImageOfCaptureId }),
|
|
211
|
+
this.getAuthHeaders()
|
|
212
|
+
)
|
|
213
|
+
);
|
|
183
214
|
}
|
|
184
215
|
// -------------------------------------------------------------------------
|
|
185
216
|
// Test Results
|
|
@@ -191,7 +222,10 @@ var HCSafeCDXClient = class {
|
|
|
191
222
|
ExcludeStatus: excludeStatus
|
|
192
223
|
}
|
|
193
224
|
};
|
|
194
|
-
return this.
|
|
225
|
+
return this.execute(
|
|
226
|
+
"getPendingResults",
|
|
227
|
+
() => this.http.post(this.url("test/result/pending"), request, this.getJsonHeaders())
|
|
228
|
+
);
|
|
195
229
|
}
|
|
196
230
|
/** POST test/result/last */
|
|
197
231
|
async getLastResults(excludeStatus = "Invalid") {
|
|
@@ -200,7 +234,10 @@ var HCSafeCDXClient = class {
|
|
|
200
234
|
ExcludeStatus: excludeStatus
|
|
201
235
|
}
|
|
202
236
|
};
|
|
203
|
-
return this.
|
|
237
|
+
return this.execute(
|
|
238
|
+
"getLastResults",
|
|
239
|
+
() => this.http.post(this.url("test/result/last"), request, this.getJsonHeaders())
|
|
240
|
+
);
|
|
204
241
|
}
|
|
205
242
|
/** POST test/result/history */
|
|
206
243
|
async getTestHistory(excludeStatus = "Invalid") {
|
|
@@ -209,73 +246,188 @@ var HCSafeCDXClient = class {
|
|
|
209
246
|
ExcludeStatus: excludeStatus
|
|
210
247
|
}
|
|
211
248
|
};
|
|
212
|
-
return this.
|
|
249
|
+
return this.execute(
|
|
250
|
+
"getTestHistory",
|
|
251
|
+
() => this.http.post(this.url("test/result/history"), request, this.getJsonHeaders())
|
|
252
|
+
);
|
|
213
253
|
}
|
|
214
254
|
/**
|
|
215
255
|
* POST test/result/details
|
|
216
256
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
217
257
|
*/
|
|
218
258
|
async getResultDetails(userTestResultId) {
|
|
259
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
219
260
|
const request = {
|
|
220
261
|
Data: {
|
|
221
|
-
UserTestResultId:
|
|
262
|
+
UserTestResultId: resolvedUserTestResultId
|
|
222
263
|
}
|
|
223
264
|
};
|
|
224
|
-
return this.
|
|
265
|
+
return this.executeSafe(
|
|
266
|
+
"getResultDetails",
|
|
267
|
+
() => this.http.post(this.url("test/result/details"), request, this.getJsonHeaders())
|
|
268
|
+
);
|
|
225
269
|
}
|
|
226
270
|
/** POST test/result/pdf */
|
|
227
271
|
async getResultPdf(userTestResultId) {
|
|
272
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
228
273
|
const request = {
|
|
229
274
|
Data: {
|
|
230
|
-
UserTestResultId:
|
|
275
|
+
UserTestResultId: resolvedUserTestResultId
|
|
231
276
|
}
|
|
232
277
|
};
|
|
233
|
-
return this.
|
|
278
|
+
return this.execute(
|
|
279
|
+
"getResultPdf",
|
|
280
|
+
() => this.http.post(this.url("test/result/pdf"), request, this.getJsonHeaders())
|
|
281
|
+
);
|
|
234
282
|
}
|
|
235
283
|
/**
|
|
236
284
|
* POST test/result/image/capture
|
|
237
285
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
238
286
|
*/
|
|
239
287
|
async getImageCaptureUrl(userTestResultId) {
|
|
288
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
240
289
|
const request = {
|
|
241
290
|
Data: {
|
|
242
|
-
UserTestResultId:
|
|
291
|
+
UserTestResultId: resolvedUserTestResultId
|
|
243
292
|
}
|
|
244
293
|
};
|
|
245
|
-
return this.
|
|
294
|
+
return this.executeSafe(
|
|
295
|
+
"getImageCaptureUrl",
|
|
296
|
+
() => this.http.post(this.url("test/result/image/capture"), request, this.getJsonHeaders())
|
|
297
|
+
);
|
|
246
298
|
}
|
|
247
299
|
// -------------------------------------------------------------------------
|
|
248
300
|
// Resume / Answers / Finalize
|
|
249
301
|
// -------------------------------------------------------------------------
|
|
250
302
|
/** POST test/resume */
|
|
251
303
|
async resumeFlow(userTestResultId, resumed = true) {
|
|
304
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
252
305
|
const request = {
|
|
253
306
|
Data: {
|
|
254
|
-
UserTestResultId:
|
|
307
|
+
UserTestResultId: resolvedUserTestResultId,
|
|
255
308
|
Resumed: resumed
|
|
256
309
|
}
|
|
257
310
|
};
|
|
258
|
-
return this.
|
|
311
|
+
return this.execute(
|
|
312
|
+
"resumeFlow",
|
|
313
|
+
() => this.http.post(this.url("test/resume"), request, this.getJsonHeaders())
|
|
314
|
+
);
|
|
259
315
|
}
|
|
260
316
|
/** POST test/answers */
|
|
261
317
|
async submitAnswers(submission) {
|
|
262
318
|
const request = {
|
|
263
319
|
Data: submission
|
|
264
320
|
};
|
|
265
|
-
return this.
|
|
321
|
+
return this.execute(
|
|
322
|
+
"submitAnswers",
|
|
323
|
+
() => this.http.post(this.url("test/answers"), request, this.getJsonHeaders())
|
|
324
|
+
);
|
|
266
325
|
}
|
|
267
326
|
/** POST test/finalize */
|
|
268
327
|
async finalizeTest(userTestResultId) {
|
|
328
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
269
329
|
const request = {
|
|
270
330
|
Data: {
|
|
271
|
-
UserTestResultId:
|
|
331
|
+
UserTestResultId: resolvedUserTestResultId
|
|
272
332
|
}
|
|
273
333
|
};
|
|
274
|
-
return this.
|
|
334
|
+
return this.execute(
|
|
335
|
+
"finalizeTest",
|
|
336
|
+
() => this.http.post(this.url("test/finalize"), request, this.getJsonHeaders())
|
|
337
|
+
);
|
|
275
338
|
}
|
|
276
339
|
// -------------------------------------------------------------------------
|
|
277
340
|
// Private Helpers
|
|
278
341
|
// -------------------------------------------------------------------------
|
|
342
|
+
async execute(operation, request) {
|
|
343
|
+
const response = await this.executeRaw(operation, request);
|
|
344
|
+
if (!this.isApiResponse(response)) {
|
|
345
|
+
throw new import_hc_http.APIError({
|
|
346
|
+
message: `${operation}: invalid API response structure`,
|
|
347
|
+
code: "INVALID_RESPONSE",
|
|
348
|
+
details: response
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
if (!response.IsOK) {
|
|
352
|
+
throw new import_hc_http.HCServiceError(operation, response.ErrorMessage, response);
|
|
353
|
+
}
|
|
354
|
+
return response;
|
|
355
|
+
}
|
|
356
|
+
async executeSafe(operation, request) {
|
|
357
|
+
var _a, _b;
|
|
358
|
+
const response = await this.executeRaw(operation, request);
|
|
359
|
+
if (!this.isSafeApiResponse(response)) {
|
|
360
|
+
throw new import_hc_http.APIError({
|
|
361
|
+
message: `${operation}: invalid SafeCDX response structure`,
|
|
362
|
+
code: "INVALID_RESPONSE",
|
|
363
|
+
details: response
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
if (!response.success) {
|
|
367
|
+
throw new import_hc_http.APIError({
|
|
368
|
+
message: (_a = response.message) != null ? _a : `${operation}: backend returned success: false`,
|
|
369
|
+
code: "BACKEND_FAILURE",
|
|
370
|
+
statusCode: 200,
|
|
371
|
+
backendMessage: (_b = response.message) != null ? _b : void 0,
|
|
372
|
+
details: response
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
return response;
|
|
376
|
+
}
|
|
377
|
+
async executeRaw(operation, request) {
|
|
378
|
+
let response;
|
|
379
|
+
try {
|
|
380
|
+
response = await request();
|
|
381
|
+
} catch (err) {
|
|
382
|
+
if (err instanceof import_hc_http.APIError) {
|
|
383
|
+
throw err;
|
|
384
|
+
}
|
|
385
|
+
if (err instanceof Error) {
|
|
386
|
+
throw new import_hc_http.APIError({
|
|
387
|
+
message: `${operation}: ${err.message}`,
|
|
388
|
+
code: "UNKNOWN_ERROR",
|
|
389
|
+
details: err
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
throw new import_hc_http.APIError({
|
|
393
|
+
message: `${operation}: unexpected runtime failure`,
|
|
394
|
+
code: "UNKNOWN_ERROR",
|
|
395
|
+
details: err
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (response == null) {
|
|
399
|
+
throw new import_hc_http.APIError({
|
|
400
|
+
message: `${operation}: empty response received`,
|
|
401
|
+
code: "EMPTY_RESPONSE",
|
|
402
|
+
details: response
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
return response;
|
|
406
|
+
}
|
|
407
|
+
isApiResponse(value) {
|
|
408
|
+
if (!value || typeof value !== "object") {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
const response = value;
|
|
412
|
+
return "IsOK" in response && typeof response.IsOK === "boolean" && "Data" in response && "ErrorMessage" in response;
|
|
413
|
+
}
|
|
414
|
+
isSafeApiResponse(value) {
|
|
415
|
+
if (!value || typeof value !== "object") {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
const response = value;
|
|
419
|
+
return "success" in response && typeof response.success === "boolean" && "data" in response && "message" in response && "code" in response && typeof response.code === "number";
|
|
420
|
+
}
|
|
421
|
+
requireValue(value, parameterName) {
|
|
422
|
+
const trimmedValue = value == null ? void 0 : value.trim();
|
|
423
|
+
if (!trimmedValue) {
|
|
424
|
+
throw new import_hc_http.ValidationError({
|
|
425
|
+
message: `${parameterName} is required.`,
|
|
426
|
+
code: "INVALID_INPUT"
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
return trimmedValue;
|
|
430
|
+
}
|
|
279
431
|
getAuthHeaders() {
|
|
280
432
|
return {
|
|
281
433
|
...this.loginClient.getAuthHeader(),
|
|
@@ -302,14 +454,14 @@ var HCSafeCDXClient = class {
|
|
|
302
454
|
};
|
|
303
455
|
|
|
304
456
|
// src/errors.ts
|
|
305
|
-
var
|
|
306
|
-
constructor(message) {
|
|
307
|
-
super(message);
|
|
308
|
-
this.name = "ConfigError";
|
|
309
|
-
}
|
|
310
|
-
};
|
|
457
|
+
var import_hc_http2 = require("@healthcloudai/hc-http");
|
|
311
458
|
// Annotate the CommonJS export names for ESM import in node:
|
|
312
459
|
0 && (module.exports = {
|
|
460
|
+
APIError,
|
|
313
461
|
ConfigError,
|
|
314
|
-
HCSafeCDXClient
|
|
462
|
+
HCSafeCDXClient,
|
|
463
|
+
HCServiceError,
|
|
464
|
+
NetworkError,
|
|
465
|
+
ValidationError,
|
|
466
|
+
errorFromHttpStatus
|
|
315
467
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HCLoginClient } from '@healthcloudai/hc-login-connector';
|
|
2
2
|
import { HttpClient } from '@healthcloudai/hc-http';
|
|
3
|
+
export { APIError, ConfigError, HCServiceError, NetworkError, ValidationError, errorFromHttpStatus } from '@healthcloudai/hc-http';
|
|
3
4
|
|
|
4
5
|
type Environment = "dev" | "uat" | "prod";
|
|
5
6
|
/**
|
|
@@ -469,7 +470,7 @@ declare class HCSafeCDXClient {
|
|
|
469
470
|
getTestProfileByGTIN(gtin: string): Promise<APIResponse<GetTestProfileByGTINData>>;
|
|
470
471
|
/**
|
|
471
472
|
* POST test/profiles/by-account
|
|
472
|
-
|
|
473
|
+
|
|
473
474
|
*
|
|
474
475
|
* TenantId is resolved by the backend from the authenticated patient context.
|
|
475
476
|
*/
|
|
@@ -521,14 +522,16 @@ declare class HCSafeCDXClient {
|
|
|
521
522
|
submitAnswers(submission: SubmitAnswersRequest): Promise<APIResponse<SubmitAnswersData>>;
|
|
522
523
|
/** POST test/finalize */
|
|
523
524
|
finalizeTest(userTestResultId: string): Promise<APIResponse<FinalizeTestData>>;
|
|
525
|
+
protected execute<T>(operation: string, request: () => Promise<APIResponse<T>>): Promise<APIResponse<T>>;
|
|
526
|
+
protected executeSafe<T>(operation: string, request: () => Promise<SafeAPIResponse<T>>): Promise<SafeAPIResponse<T>>;
|
|
527
|
+
private executeRaw;
|
|
528
|
+
private isApiResponse;
|
|
529
|
+
private isSafeApiResponse;
|
|
530
|
+
private requireValue;
|
|
524
531
|
private getAuthHeaders;
|
|
525
532
|
private getJsonHeaders;
|
|
526
533
|
private getApiKeyHeader;
|
|
527
534
|
private url;
|
|
528
535
|
}
|
|
529
536
|
|
|
530
|
-
|
|
531
|
-
constructor(message: string);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
export { type APIRequest, type APIResponse, type AnswerResult, type CaptureState, ConfigError, type CreateUploadUrlData, type CreateUploadUrlRequest, type CvmlImageOfCaptureResult, type CvmlParsedResult, type CvmlResultsData, type DiagnosticProfileCta, type DiagnosticProfileData, type DiagnosticProfileDecision, type DiagnosticProfileDecisionResult, type DiagnosticProfileIndication, type DiagnosticProfileTestInfo, type DisclaimerDetail, type EntityReferenceData, type Environment, type ExcludeStatusRequest, type FinalizeTestData, type FinalizeTestRequest, type GetCvmlResultsResponse, type GetImageCaptureUrlRequest, type GetImageCaptureUrlResponse, type GetLastResultsData, type GetLastResultsRequest, type GetPendingResultsData, type GetPendingResultsRequest, type GetResultDetailsRequest, type GetResultDetailsResponse, type GetResultPdfData, type GetResultPdfRequest, type GetTestHistoryData, type GetTestHistoryRequest, type GetTestProfileByGTINData, type GetTestProfilesByAccountData, type GetTestProfilesByAccountRequest, HCSafeCDXClient, type ImageOfCaptureResult, type ProductAssetDetail, type QuestionnaireAnalyte, type QuestionnaireAnalyteResponse, type QuestionnaireSnapshot, type QuestionnaireValidityItem, type RegisterTestDetail, type ReportedAnswerResult, type ResumeFlowData, type ResumeFlowRequest, type ResumeFlowResult, type SafeAPIResponse, type SubmitAnswersData, type SubmitAnswersRequest, type TestProfileAnalyte, type TestProfileAnalyteResponse, type TestProfileArticle, type TestProfileBillingInfo, type TestProfileByAccountItem, type TestProfileInstruction, type TestProfileResult, type TestProfileScanImageDetail, type TestProfileTerritory, type TestResultDetails, type TestResultSummary, type UpdateCvmlStatusRequest, type UpdateCvmlStatusResponse, type UploadMetadata, type UserTestResultIdRequest };
|
|
537
|
+
export { type APIRequest, type APIResponse, type AnswerResult, type CaptureState, type CreateUploadUrlData, type CreateUploadUrlRequest, type CvmlImageOfCaptureResult, type CvmlParsedResult, type CvmlResultsData, type DiagnosticProfileCta, type DiagnosticProfileData, type DiagnosticProfileDecision, type DiagnosticProfileDecisionResult, type DiagnosticProfileIndication, type DiagnosticProfileTestInfo, type DisclaimerDetail, type EntityReferenceData, type Environment, type ExcludeStatusRequest, type FinalizeTestData, type FinalizeTestRequest, type GetCvmlResultsResponse, type GetImageCaptureUrlRequest, type GetImageCaptureUrlResponse, type GetLastResultsData, type GetLastResultsRequest, type GetPendingResultsData, type GetPendingResultsRequest, type GetResultDetailsRequest, type GetResultDetailsResponse, type GetResultPdfData, type GetResultPdfRequest, type GetTestHistoryData, type GetTestHistoryRequest, type GetTestProfileByGTINData, type GetTestProfilesByAccountData, type GetTestProfilesByAccountRequest, HCSafeCDXClient, type ImageOfCaptureResult, type ProductAssetDetail, type QuestionnaireAnalyte, type QuestionnaireAnalyteResponse, type QuestionnaireSnapshot, type QuestionnaireValidityItem, type RegisterTestDetail, type ReportedAnswerResult, type ResumeFlowData, type ResumeFlowRequest, type ResumeFlowResult, type SafeAPIResponse, type SubmitAnswersData, type SubmitAnswersRequest, type TestProfileAnalyte, type TestProfileAnalyteResponse, type TestProfileArticle, type TestProfileBillingInfo, type TestProfileByAccountItem, type TestProfileInstruction, type TestProfileResult, type TestProfileScanImageDetail, type TestProfileTerritory, type TestResultDetails, type TestResultSummary, type UpdateCvmlStatusRequest, type UpdateCvmlStatusResponse, type UploadMetadata, type UserTestResultIdRequest };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HCLoginClient } from '@healthcloudai/hc-login-connector';
|
|
2
2
|
import { HttpClient } from '@healthcloudai/hc-http';
|
|
3
|
+
export { APIError, ConfigError, HCServiceError, NetworkError, ValidationError, errorFromHttpStatus } from '@healthcloudai/hc-http';
|
|
3
4
|
|
|
4
5
|
type Environment = "dev" | "uat" | "prod";
|
|
5
6
|
/**
|
|
@@ -469,7 +470,7 @@ declare class HCSafeCDXClient {
|
|
|
469
470
|
getTestProfileByGTIN(gtin: string): Promise<APIResponse<GetTestProfileByGTINData>>;
|
|
470
471
|
/**
|
|
471
472
|
* POST test/profiles/by-account
|
|
472
|
-
|
|
473
|
+
|
|
473
474
|
*
|
|
474
475
|
* TenantId is resolved by the backend from the authenticated patient context.
|
|
475
476
|
*/
|
|
@@ -521,14 +522,16 @@ declare class HCSafeCDXClient {
|
|
|
521
522
|
submitAnswers(submission: SubmitAnswersRequest): Promise<APIResponse<SubmitAnswersData>>;
|
|
522
523
|
/** POST test/finalize */
|
|
523
524
|
finalizeTest(userTestResultId: string): Promise<APIResponse<FinalizeTestData>>;
|
|
525
|
+
protected execute<T>(operation: string, request: () => Promise<APIResponse<T>>): Promise<APIResponse<T>>;
|
|
526
|
+
protected executeSafe<T>(operation: string, request: () => Promise<SafeAPIResponse<T>>): Promise<SafeAPIResponse<T>>;
|
|
527
|
+
private executeRaw;
|
|
528
|
+
private isApiResponse;
|
|
529
|
+
private isSafeApiResponse;
|
|
530
|
+
private requireValue;
|
|
524
531
|
private getAuthHeaders;
|
|
525
532
|
private getJsonHeaders;
|
|
526
533
|
private getApiKeyHeader;
|
|
527
534
|
private url;
|
|
528
535
|
}
|
|
529
536
|
|
|
530
|
-
|
|
531
|
-
constructor(message: string);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
export { type APIRequest, type APIResponse, type AnswerResult, type CaptureState, ConfigError, type CreateUploadUrlData, type CreateUploadUrlRequest, type CvmlImageOfCaptureResult, type CvmlParsedResult, type CvmlResultsData, type DiagnosticProfileCta, type DiagnosticProfileData, type DiagnosticProfileDecision, type DiagnosticProfileDecisionResult, type DiagnosticProfileIndication, type DiagnosticProfileTestInfo, type DisclaimerDetail, type EntityReferenceData, type Environment, type ExcludeStatusRequest, type FinalizeTestData, type FinalizeTestRequest, type GetCvmlResultsResponse, type GetImageCaptureUrlRequest, type GetImageCaptureUrlResponse, type GetLastResultsData, type GetLastResultsRequest, type GetPendingResultsData, type GetPendingResultsRequest, type GetResultDetailsRequest, type GetResultDetailsResponse, type GetResultPdfData, type GetResultPdfRequest, type GetTestHistoryData, type GetTestHistoryRequest, type GetTestProfileByGTINData, type GetTestProfilesByAccountData, type GetTestProfilesByAccountRequest, HCSafeCDXClient, type ImageOfCaptureResult, type ProductAssetDetail, type QuestionnaireAnalyte, type QuestionnaireAnalyteResponse, type QuestionnaireSnapshot, type QuestionnaireValidityItem, type RegisterTestDetail, type ReportedAnswerResult, type ResumeFlowData, type ResumeFlowRequest, type ResumeFlowResult, type SafeAPIResponse, type SubmitAnswersData, type SubmitAnswersRequest, type TestProfileAnalyte, type TestProfileAnalyteResponse, type TestProfileArticle, type TestProfileBillingInfo, type TestProfileByAccountItem, type TestProfileInstruction, type TestProfileResult, type TestProfileScanImageDetail, type TestProfileTerritory, type TestResultDetails, type TestResultSummary, type UpdateCvmlStatusRequest, type UpdateCvmlStatusResponse, type UploadMetadata, type UserTestResultIdRequest };
|
|
537
|
+
export { type APIRequest, type APIResponse, type AnswerResult, type CaptureState, type CreateUploadUrlData, type CreateUploadUrlRequest, type CvmlImageOfCaptureResult, type CvmlParsedResult, type CvmlResultsData, type DiagnosticProfileCta, type DiagnosticProfileData, type DiagnosticProfileDecision, type DiagnosticProfileDecisionResult, type DiagnosticProfileIndication, type DiagnosticProfileTestInfo, type DisclaimerDetail, type EntityReferenceData, type Environment, type ExcludeStatusRequest, type FinalizeTestData, type FinalizeTestRequest, type GetCvmlResultsResponse, type GetImageCaptureUrlRequest, type GetImageCaptureUrlResponse, type GetLastResultsData, type GetLastResultsRequest, type GetPendingResultsData, type GetPendingResultsRequest, type GetResultDetailsRequest, type GetResultDetailsResponse, type GetResultPdfData, type GetResultPdfRequest, type GetTestHistoryData, type GetTestHistoryRequest, type GetTestProfileByGTINData, type GetTestProfilesByAccountData, type GetTestProfilesByAccountRequest, HCSafeCDXClient, type ImageOfCaptureResult, type ProductAssetDetail, type QuestionnaireAnalyte, type QuestionnaireAnalyteResponse, type QuestionnaireSnapshot, type QuestionnaireValidityItem, type RegisterTestDetail, type ReportedAnswerResult, type ResumeFlowData, type ResumeFlowRequest, type ResumeFlowResult, type SafeAPIResponse, type SubmitAnswersData, type SubmitAnswersRequest, type TestProfileAnalyte, type TestProfileAnalyteResponse, type TestProfileArticle, type TestProfileBillingInfo, type TestProfileByAccountItem, type TestProfileInstruction, type TestProfileResult, type TestProfileScanImageDetail, type TestProfileTerritory, type TestResultDetails, type TestResultSummary, type UpdateCvmlStatusRequest, type UpdateCvmlStatusResponse, type UploadMetadata, type UserTestResultIdRequest };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
};
|
|
2
|
+
import {
|
|
3
|
+
APIError,
|
|
4
|
+
ConfigError,
|
|
5
|
+
HCServiceError,
|
|
6
|
+
ValidationError
|
|
7
|
+
} from "@healthcloudai/hc-http";
|
|
10
8
|
var ENV_HOST = {
|
|
11
9
|
dev: "dev-api-hcs.healthcloud-services.com",
|
|
12
10
|
uat: "uat-api-hcs.healthcloud-services.com",
|
|
@@ -16,7 +14,7 @@ var ROUTE_PREFIX = "api/console/hcservice/safecdx";
|
|
|
16
14
|
function buildSafeCdxBaseUrl(environment) {
|
|
17
15
|
const host = ENV_HOST[environment];
|
|
18
16
|
if (!host) {
|
|
19
|
-
throw new
|
|
17
|
+
throw new ConfigError("Invalid Safe CDX environment.");
|
|
20
18
|
}
|
|
21
19
|
return `https://${host}/${ROUTE_PREFIX}`;
|
|
22
20
|
}
|
|
@@ -41,10 +39,10 @@ var HCSafeCDXClient = class {
|
|
|
41
39
|
const trimmedHeaderName = headerName == null ? void 0 : headerName.trim();
|
|
42
40
|
const trimmedValue = value == null ? void 0 : value.trim();
|
|
43
41
|
if (!trimmedHeaderName) {
|
|
44
|
-
throw new
|
|
42
|
+
throw new ConfigError("API key header name is required.");
|
|
45
43
|
}
|
|
46
44
|
if (!trimmedValue) {
|
|
47
|
-
throw new
|
|
45
|
+
throw new ConfigError("API key value is required.");
|
|
48
46
|
}
|
|
49
47
|
this.apiKeyHeaderName = trimmedHeaderName;
|
|
50
48
|
this.apiKeyValue = trimmedValue;
|
|
@@ -57,27 +55,34 @@ var HCSafeCDXClient = class {
|
|
|
57
55
|
* Resolves the SafeCDX test profile associated with a GTIN barcode.
|
|
58
56
|
*/
|
|
59
57
|
async getTestProfileByGTIN(gtin) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
const resolvedGtin = this.requireValue(gtin, "gtin");
|
|
59
|
+
return this.execute(
|
|
60
|
+
"getTestProfileByGTIN",
|
|
61
|
+
() => this.http.get(
|
|
62
|
+
this.url(`gs1/${encodeURIComponent(resolvedGtin)}`),
|
|
63
|
+
this.getAuthHeaders()
|
|
64
|
+
)
|
|
63
65
|
);
|
|
64
66
|
}
|
|
65
67
|
/**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
* POST test/profiles/by-account
|
|
69
|
+
|
|
70
|
+
*
|
|
71
|
+
* TenantId is resolved by the backend from the authenticated patient context.
|
|
72
|
+
*/
|
|
71
73
|
async getTestProfilesByAccount(includeRegisterTestDetails = true) {
|
|
72
74
|
const request = {
|
|
73
75
|
Data: {
|
|
74
76
|
IncludeRegisterTestDetails: includeRegisterTestDetails
|
|
75
77
|
}
|
|
76
78
|
};
|
|
77
|
-
return this.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
return this.execute(
|
|
80
|
+
"getTestProfilesByAccount",
|
|
81
|
+
() => this.http.post(
|
|
82
|
+
this.url("test/profiles/by-account"),
|
|
83
|
+
request,
|
|
84
|
+
this.getJsonHeaders()
|
|
85
|
+
)
|
|
81
86
|
);
|
|
82
87
|
}
|
|
83
88
|
// -------------------------------------------------------------------------
|
|
@@ -88,19 +93,25 @@ var HCSafeCDXClient = class {
|
|
|
88
93
|
* Requests a pre-signed URL used to upload a test image.
|
|
89
94
|
*/
|
|
90
95
|
async createUploadUrl(userTestResultId, gtin, imageType = "jpg") {
|
|
96
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
97
|
+
const resolvedGtin = this.requireValue(gtin, "gtin");
|
|
98
|
+
const resolvedImageType = this.requireValue(imageType, "imageType");
|
|
91
99
|
const request = {
|
|
92
100
|
Data: {
|
|
93
|
-
Gtin:
|
|
94
|
-
UserTestResultId:
|
|
101
|
+
Gtin: resolvedGtin,
|
|
102
|
+
UserTestResultId: resolvedUserTestResultId,
|
|
95
103
|
Metadata: {
|
|
96
|
-
ImageType:
|
|
104
|
+
ImageType: resolvedImageType
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
107
|
};
|
|
100
|
-
return this.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
return this.execute(
|
|
109
|
+
"createUploadUrl",
|
|
110
|
+
() => this.http.post(
|
|
111
|
+
this.url("upload/url"),
|
|
112
|
+
request,
|
|
113
|
+
this.getJsonHeaders()
|
|
114
|
+
)
|
|
104
115
|
);
|
|
105
116
|
}
|
|
106
117
|
/**
|
|
@@ -111,10 +122,12 @@ var HCSafeCDXClient = class {
|
|
|
111
122
|
* authenticated Health Cloud headers.
|
|
112
123
|
*/
|
|
113
124
|
async uploadImage(preSignedURL, image, contentType = "image/jpeg") {
|
|
114
|
-
const
|
|
125
|
+
const resolvedPreSignedURL = this.requireValue(preSignedURL, "preSignedURL");
|
|
126
|
+
const resolvedContentType = this.requireValue(contentType, "contentType");
|
|
127
|
+
const response = await fetch(resolvedPreSignedURL, {
|
|
115
128
|
method: "PUT",
|
|
116
129
|
headers: {
|
|
117
|
-
"Content-Type":
|
|
130
|
+
"Content-Type": resolvedContentType
|
|
118
131
|
},
|
|
119
132
|
body: image
|
|
120
133
|
});
|
|
@@ -125,9 +138,15 @@ var HCSafeCDXClient = class {
|
|
|
125
138
|
} catch {
|
|
126
139
|
body = void 0;
|
|
127
140
|
}
|
|
128
|
-
throw new
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
throw new APIError({
|
|
142
|
+
message: `uploadImage: image upload failed with HTTP ${response.status}.`,
|
|
143
|
+
code: response.status >= 500 ? "SERVER_ERROR" : "UNKNOWN_ERROR",
|
|
144
|
+
statusCode: response.status,
|
|
145
|
+
backendMessage: body,
|
|
146
|
+
details: {
|
|
147
|
+
status: response.status,
|
|
148
|
+
body
|
|
149
|
+
}
|
|
131
150
|
});
|
|
132
151
|
}
|
|
133
152
|
}
|
|
@@ -139,20 +158,32 @@ var HCSafeCDXClient = class {
|
|
|
139
158
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
140
159
|
*/
|
|
141
160
|
async updateCvmlStatus(imageOfCaptureId, cvmlStatus) {
|
|
161
|
+
const resolvedImageOfCaptureId = this.requireValue(imageOfCaptureId, "imageOfCaptureId");
|
|
162
|
+
const resolvedCvmlStatus = this.requireValue(cvmlStatus, "cvmlStatus");
|
|
142
163
|
const request = {
|
|
143
164
|
Data: {
|
|
144
|
-
ImageOfCaptureId:
|
|
145
|
-
CvmlStatus:
|
|
165
|
+
ImageOfCaptureId: resolvedImageOfCaptureId,
|
|
166
|
+
CvmlStatus: resolvedCvmlStatus
|
|
146
167
|
}
|
|
147
168
|
};
|
|
148
|
-
return this.
|
|
169
|
+
return this.executeSafe(
|
|
170
|
+
"updateCvmlStatus",
|
|
171
|
+
() => this.http.post(this.url("cvml/status"), request, this.getJsonHeaders())
|
|
172
|
+
);
|
|
149
173
|
}
|
|
150
174
|
/**
|
|
151
175
|
* GET cvml/results
|
|
152
176
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
153
177
|
*/
|
|
154
178
|
async getCvmlResults(imageOfCaptureId) {
|
|
155
|
-
|
|
179
|
+
const resolvedImageOfCaptureId = this.requireValue(imageOfCaptureId, "imageOfCaptureId");
|
|
180
|
+
return this.executeSafe(
|
|
181
|
+
"getCvmlResults",
|
|
182
|
+
() => this.http.get(
|
|
183
|
+
this.url("cvml/results", { imageOfCaptureId: resolvedImageOfCaptureId }),
|
|
184
|
+
this.getAuthHeaders()
|
|
185
|
+
)
|
|
186
|
+
);
|
|
156
187
|
}
|
|
157
188
|
// -------------------------------------------------------------------------
|
|
158
189
|
// Test Results
|
|
@@ -164,7 +195,10 @@ var HCSafeCDXClient = class {
|
|
|
164
195
|
ExcludeStatus: excludeStatus
|
|
165
196
|
}
|
|
166
197
|
};
|
|
167
|
-
return this.
|
|
198
|
+
return this.execute(
|
|
199
|
+
"getPendingResults",
|
|
200
|
+
() => this.http.post(this.url("test/result/pending"), request, this.getJsonHeaders())
|
|
201
|
+
);
|
|
168
202
|
}
|
|
169
203
|
/** POST test/result/last */
|
|
170
204
|
async getLastResults(excludeStatus = "Invalid") {
|
|
@@ -173,7 +207,10 @@ var HCSafeCDXClient = class {
|
|
|
173
207
|
ExcludeStatus: excludeStatus
|
|
174
208
|
}
|
|
175
209
|
};
|
|
176
|
-
return this.
|
|
210
|
+
return this.execute(
|
|
211
|
+
"getLastResults",
|
|
212
|
+
() => this.http.post(this.url("test/result/last"), request, this.getJsonHeaders())
|
|
213
|
+
);
|
|
177
214
|
}
|
|
178
215
|
/** POST test/result/history */
|
|
179
216
|
async getTestHistory(excludeStatus = "Invalid") {
|
|
@@ -182,73 +219,188 @@ var HCSafeCDXClient = class {
|
|
|
182
219
|
ExcludeStatus: excludeStatus
|
|
183
220
|
}
|
|
184
221
|
};
|
|
185
|
-
return this.
|
|
222
|
+
return this.execute(
|
|
223
|
+
"getTestHistory",
|
|
224
|
+
() => this.http.post(this.url("test/result/history"), request, this.getJsonHeaders())
|
|
225
|
+
);
|
|
186
226
|
}
|
|
187
227
|
/**
|
|
188
228
|
* POST test/result/details
|
|
189
229
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
190
230
|
*/
|
|
191
231
|
async getResultDetails(userTestResultId) {
|
|
232
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
192
233
|
const request = {
|
|
193
234
|
Data: {
|
|
194
|
-
UserTestResultId:
|
|
235
|
+
UserTestResultId: resolvedUserTestResultId
|
|
195
236
|
}
|
|
196
237
|
};
|
|
197
|
-
return this.
|
|
238
|
+
return this.executeSafe(
|
|
239
|
+
"getResultDetails",
|
|
240
|
+
() => this.http.post(this.url("test/result/details"), request, this.getJsonHeaders())
|
|
241
|
+
);
|
|
198
242
|
}
|
|
199
243
|
/** POST test/result/pdf */
|
|
200
244
|
async getResultPdf(userTestResultId) {
|
|
245
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
201
246
|
const request = {
|
|
202
247
|
Data: {
|
|
203
|
-
UserTestResultId:
|
|
248
|
+
UserTestResultId: resolvedUserTestResultId
|
|
204
249
|
}
|
|
205
250
|
};
|
|
206
|
-
return this.
|
|
251
|
+
return this.execute(
|
|
252
|
+
"getResultPdf",
|
|
253
|
+
() => this.http.post(this.url("test/result/pdf"), request, this.getJsonHeaders())
|
|
254
|
+
);
|
|
207
255
|
}
|
|
208
256
|
/**
|
|
209
257
|
* POST test/result/image/capture
|
|
210
258
|
* Returns the direct SafeCDX response without an outer APIResponse wrapper.
|
|
211
259
|
*/
|
|
212
260
|
async getImageCaptureUrl(userTestResultId) {
|
|
261
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
213
262
|
const request = {
|
|
214
263
|
Data: {
|
|
215
|
-
UserTestResultId:
|
|
264
|
+
UserTestResultId: resolvedUserTestResultId
|
|
216
265
|
}
|
|
217
266
|
};
|
|
218
|
-
return this.
|
|
267
|
+
return this.executeSafe(
|
|
268
|
+
"getImageCaptureUrl",
|
|
269
|
+
() => this.http.post(this.url("test/result/image/capture"), request, this.getJsonHeaders())
|
|
270
|
+
);
|
|
219
271
|
}
|
|
220
272
|
// -------------------------------------------------------------------------
|
|
221
273
|
// Resume / Answers / Finalize
|
|
222
274
|
// -------------------------------------------------------------------------
|
|
223
275
|
/** POST test/resume */
|
|
224
276
|
async resumeFlow(userTestResultId, resumed = true) {
|
|
277
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
225
278
|
const request = {
|
|
226
279
|
Data: {
|
|
227
|
-
UserTestResultId:
|
|
280
|
+
UserTestResultId: resolvedUserTestResultId,
|
|
228
281
|
Resumed: resumed
|
|
229
282
|
}
|
|
230
283
|
};
|
|
231
|
-
return this.
|
|
284
|
+
return this.execute(
|
|
285
|
+
"resumeFlow",
|
|
286
|
+
() => this.http.post(this.url("test/resume"), request, this.getJsonHeaders())
|
|
287
|
+
);
|
|
232
288
|
}
|
|
233
289
|
/** POST test/answers */
|
|
234
290
|
async submitAnswers(submission) {
|
|
235
291
|
const request = {
|
|
236
292
|
Data: submission
|
|
237
293
|
};
|
|
238
|
-
return this.
|
|
294
|
+
return this.execute(
|
|
295
|
+
"submitAnswers",
|
|
296
|
+
() => this.http.post(this.url("test/answers"), request, this.getJsonHeaders())
|
|
297
|
+
);
|
|
239
298
|
}
|
|
240
299
|
/** POST test/finalize */
|
|
241
300
|
async finalizeTest(userTestResultId) {
|
|
301
|
+
const resolvedUserTestResultId = this.requireValue(userTestResultId, "userTestResultId");
|
|
242
302
|
const request = {
|
|
243
303
|
Data: {
|
|
244
|
-
UserTestResultId:
|
|
304
|
+
UserTestResultId: resolvedUserTestResultId
|
|
245
305
|
}
|
|
246
306
|
};
|
|
247
|
-
return this.
|
|
307
|
+
return this.execute(
|
|
308
|
+
"finalizeTest",
|
|
309
|
+
() => this.http.post(this.url("test/finalize"), request, this.getJsonHeaders())
|
|
310
|
+
);
|
|
248
311
|
}
|
|
249
312
|
// -------------------------------------------------------------------------
|
|
250
313
|
// Private Helpers
|
|
251
314
|
// -------------------------------------------------------------------------
|
|
315
|
+
async execute(operation, request) {
|
|
316
|
+
const response = await this.executeRaw(operation, request);
|
|
317
|
+
if (!this.isApiResponse(response)) {
|
|
318
|
+
throw new APIError({
|
|
319
|
+
message: `${operation}: invalid API response structure`,
|
|
320
|
+
code: "INVALID_RESPONSE",
|
|
321
|
+
details: response
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
if (!response.IsOK) {
|
|
325
|
+
throw new HCServiceError(operation, response.ErrorMessage, response);
|
|
326
|
+
}
|
|
327
|
+
return response;
|
|
328
|
+
}
|
|
329
|
+
async executeSafe(operation, request) {
|
|
330
|
+
var _a, _b;
|
|
331
|
+
const response = await this.executeRaw(operation, request);
|
|
332
|
+
if (!this.isSafeApiResponse(response)) {
|
|
333
|
+
throw new APIError({
|
|
334
|
+
message: `${operation}: invalid SafeCDX response structure`,
|
|
335
|
+
code: "INVALID_RESPONSE",
|
|
336
|
+
details: response
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (!response.success) {
|
|
340
|
+
throw new APIError({
|
|
341
|
+
message: (_a = response.message) != null ? _a : `${operation}: backend returned success: false`,
|
|
342
|
+
code: "BACKEND_FAILURE",
|
|
343
|
+
statusCode: 200,
|
|
344
|
+
backendMessage: (_b = response.message) != null ? _b : void 0,
|
|
345
|
+
details: response
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return response;
|
|
349
|
+
}
|
|
350
|
+
async executeRaw(operation, request) {
|
|
351
|
+
let response;
|
|
352
|
+
try {
|
|
353
|
+
response = await request();
|
|
354
|
+
} catch (err) {
|
|
355
|
+
if (err instanceof APIError) {
|
|
356
|
+
throw err;
|
|
357
|
+
}
|
|
358
|
+
if (err instanceof Error) {
|
|
359
|
+
throw new APIError({
|
|
360
|
+
message: `${operation}: ${err.message}`,
|
|
361
|
+
code: "UNKNOWN_ERROR",
|
|
362
|
+
details: err
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
throw new APIError({
|
|
366
|
+
message: `${operation}: unexpected runtime failure`,
|
|
367
|
+
code: "UNKNOWN_ERROR",
|
|
368
|
+
details: err
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
if (response == null) {
|
|
372
|
+
throw new APIError({
|
|
373
|
+
message: `${operation}: empty response received`,
|
|
374
|
+
code: "EMPTY_RESPONSE",
|
|
375
|
+
details: response
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
return response;
|
|
379
|
+
}
|
|
380
|
+
isApiResponse(value) {
|
|
381
|
+
if (!value || typeof value !== "object") {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
const response = value;
|
|
385
|
+
return "IsOK" in response && typeof response.IsOK === "boolean" && "Data" in response && "ErrorMessage" in response;
|
|
386
|
+
}
|
|
387
|
+
isSafeApiResponse(value) {
|
|
388
|
+
if (!value || typeof value !== "object") {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
const response = value;
|
|
392
|
+
return "success" in response && typeof response.success === "boolean" && "data" in response && "message" in response && "code" in response && typeof response.code === "number";
|
|
393
|
+
}
|
|
394
|
+
requireValue(value, parameterName) {
|
|
395
|
+
const trimmedValue = value == null ? void 0 : value.trim();
|
|
396
|
+
if (!trimmedValue) {
|
|
397
|
+
throw new ValidationError({
|
|
398
|
+
message: `${parameterName} is required.`,
|
|
399
|
+
code: "INVALID_INPUT"
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
return trimmedValue;
|
|
403
|
+
}
|
|
252
404
|
getAuthHeaders() {
|
|
253
405
|
return {
|
|
254
406
|
...this.loginClient.getAuthHeader(),
|
|
@@ -275,13 +427,20 @@ var HCSafeCDXClient = class {
|
|
|
275
427
|
};
|
|
276
428
|
|
|
277
429
|
// src/errors.ts
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
430
|
+
import {
|
|
431
|
+
APIError as APIError2,
|
|
432
|
+
ConfigError as ConfigError2,
|
|
433
|
+
HCServiceError as HCServiceError2,
|
|
434
|
+
NetworkError,
|
|
435
|
+
ValidationError as ValidationError2,
|
|
436
|
+
errorFromHttpStatus
|
|
437
|
+
} from "@healthcloudai/hc-http";
|
|
284
438
|
export {
|
|
285
|
-
|
|
286
|
-
|
|
439
|
+
APIError2 as APIError,
|
|
440
|
+
ConfigError2 as ConfigError,
|
|
441
|
+
HCSafeCDXClient,
|
|
442
|
+
HCServiceError2 as HCServiceError,
|
|
443
|
+
NetworkError,
|
|
444
|
+
ValidationError2 as ValidationError,
|
|
445
|
+
errorFromHttpStatus
|
|
287
446
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@healthcloudai/hc-safe-cdx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Healthcheck Safe CDX connector.",
|
|
5
5
|
"author": "Healthcheck Systems Inc",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"prepublishOnly": "npm run build"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@healthcloudai/hc-http": "^0.0
|
|
37
|
-
"@healthcloudai/hc-login-connector": "^0.
|
|
36
|
+
"@healthcloudai/hc-http": "^0.1.0",
|
|
37
|
+
"@healthcloudai/hc-login-connector": "^0.2.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"react-native": ">=0.70.0"
|