@healthcloudai/hc-safe-cdx 0.1.1 → 0.1.2
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/README.md +125 -64
- package/dist/index.cjs +42 -34
- package/dist/index.d.cts +13 -8
- package/dist/index.d.ts +13 -8
- package/dist/index.js +42 -34
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,23 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
Safe CDX connector provides a thin TypeScript wrapper around Safe CDX API routes.
|
|
4
4
|
|
|
5
|
-
The connector
|
|
5
|
+
The connector follows the same shared-client pattern used by other Health Cloud connector modules:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `HttpClient` handles HTTP transport.
|
|
8
|
+
- `HCLoginClient` provides the authenticated request headers.
|
|
9
|
+
- `HCSafeCDXClient` builds Safe CDX URLs, wraps request payloads, and exposes one method per Safe CDX route.
|
|
10
|
+
|
|
11
|
+
Safe CDX has its own API host. The connector uses `HCLoginClient` for authentication only; it does not use `loginClient.getBaseUrl()` for Safe CDX routes.
|
|
8
12
|
|
|
9
13
|
Image upload is handled separately because the upload target is a pre-signed S3 URL, not a Safe CDX API route.
|
|
10
14
|
|
|
11
15
|
## Installation
|
|
12
16
|
|
|
13
17
|
```sh
|
|
14
|
-
npm install @healthcloudai/hc-safe-cdx @healthcloudai/hc-http
|
|
18
|
+
npm install @healthcloudai/hc-safe-cdx @healthcloudai/hc-http @healthcloudai/hc-login-connector
|
|
15
19
|
```
|
|
16
20
|
|
|
17
21
|
## Import
|
|
18
22
|
|
|
19
23
|
```ts
|
|
20
24
|
import { FetchClient } from "@healthcloudai/hc-http";
|
|
21
|
-
import {
|
|
25
|
+
import { HCLoginClient } from "@healthcloudai/hc-login-connector";
|
|
26
|
+
import { HCSafeCDXClient } from "@healthcloudai/hc-safe-cdx";
|
|
22
27
|
```
|
|
23
28
|
|
|
24
29
|
## Basic Setup
|
|
@@ -26,47 +31,85 @@ import { SafeCDXClient } from "@healthcloudai/hc-safe-cdx";
|
|
|
26
31
|
```ts
|
|
27
32
|
const http = new FetchClient();
|
|
28
33
|
|
|
29
|
-
const
|
|
34
|
+
const loginClient = new HCLoginClient(http);
|
|
35
|
+
|
|
36
|
+
// Configure and authenticate the login client first.
|
|
37
|
+
// Exact login/configuration calls depend on the login connector setup used by the app.
|
|
38
|
+
|
|
39
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient, {
|
|
30
40
|
environment: "dev",
|
|
31
41
|
defaultLanguage: "en",
|
|
32
42
|
defaultImageType: "jpg",
|
|
33
43
|
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The connector does not perform login. The consuming application should authenticate through the Health Cloud login connector first. Safe CDX then reuses the authenticated headers from `loginClient.getAuthHeader()`.
|
|
47
|
+
|
|
48
|
+
There is no `setAccessToken()` step in this version of the client.
|
|
49
|
+
|
|
50
|
+
## Dependency Notes
|
|
51
|
+
|
|
52
|
+
Because `HCSafeCDXClient` accepts `HCLoginClient` in the constructor, `@healthcloudai/hc-login-connector` should be included as a package dependency.
|
|
34
53
|
|
|
35
|
-
|
|
54
|
+
Example package configuration:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@healthcloudai/hc-http": "^0.x.x",
|
|
60
|
+
"@healthcloudai/hc-login-connector": "^0.x.x"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
36
63
|
```
|
|
37
64
|
|
|
38
|
-
|
|
65
|
+
In a workspace setup, use the same dependency versioning strategy already used by the other connector packages.
|
|
39
66
|
|
|
40
|
-
|
|
67
|
+
Example:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"@healthcloudai/hc-http": "workspace:*",
|
|
73
|
+
"@healthcloudai/hc-login-connector": "workspace:*"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
41
77
|
|
|
42
78
|
## How the Client Works
|
|
43
79
|
|
|
44
|
-
The client
|
|
80
|
+
The client receives both the HTTP client and the login client:
|
|
45
81
|
|
|
46
82
|
```ts
|
|
47
83
|
const http = new FetchClient();
|
|
48
|
-
const
|
|
84
|
+
const loginClient = new HCLoginClient(http);
|
|
85
|
+
|
|
86
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient, {
|
|
87
|
+
environment: "dev",
|
|
88
|
+
});
|
|
49
89
|
```
|
|
50
90
|
|
|
51
91
|
The shared `HttpClient` is responsible for executing HTTP requests.
|
|
52
92
|
|
|
93
|
+
The `HCLoginClient` is responsible for the authenticated request headers.
|
|
94
|
+
|
|
53
95
|
The Safe CDX client is responsible for:
|
|
54
96
|
|
|
97
|
+
- resolving the Safe CDX environment host
|
|
55
98
|
- building Safe CDX URLs
|
|
56
|
-
-
|
|
57
|
-
- adding
|
|
99
|
+
- adding auth headers from `HCLoginClient`
|
|
100
|
+
- adding optional API key headers when configured
|
|
58
101
|
- wrapping POST request payloads into `{ Data: payload }`
|
|
59
102
|
- validating `ApiResponse` results where the backend returns `{ IsOK, Data, ErrorMessage }`
|
|
60
|
-
- exposing one SDK method per
|
|
103
|
+
- exposing one SDK method per Safe CDX route
|
|
61
104
|
|
|
62
|
-
The Safe CDX client does not create its own internal `fetch` helpers for standard API routes.
|
|
105
|
+
The Safe CDX client does not create its own internal `fetch` helpers for standard Safe CDX API routes.
|
|
63
106
|
|
|
64
107
|
## Environment Configuration
|
|
65
108
|
|
|
66
109
|
The connector supports the following environments:
|
|
67
110
|
|
|
68
111
|
```ts
|
|
69
|
-
const safeCdx = new
|
|
112
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient, {
|
|
70
113
|
environment: "dev",
|
|
71
114
|
});
|
|
72
115
|
```
|
|
@@ -77,35 +120,54 @@ Available environments:
|
|
|
77
120
|
"dev" | "uat" | "prod"
|
|
78
121
|
```
|
|
79
122
|
|
|
80
|
-
|
|
123
|
+
Safe CDX environment host mapping is handled internally by the connector:
|
|
81
124
|
|
|
82
|
-
|
|
125
|
+
```txt
|
|
126
|
+
dev -> dev-api-hcs.healthcloud-services.com
|
|
127
|
+
uat -> uat-api-hcs.healthcloud-services.com
|
|
128
|
+
prod -> api-hcs.healthcloud-services.com
|
|
129
|
+
```
|
|
83
130
|
|
|
84
|
-
|
|
131
|
+
These hosts are separate from the login connector base URL.
|
|
85
132
|
|
|
86
|
-
|
|
87
|
-
safeCdx.setAccessToken(patientAccessToken);
|
|
88
|
-
```
|
|
133
|
+
## Authentication
|
|
89
134
|
|
|
90
|
-
|
|
135
|
+
Safe CDX API calls require authenticated Health Cloud headers.
|
|
91
136
|
|
|
92
|
-
|
|
137
|
+
The connector gets those headers from:
|
|
93
138
|
|
|
94
139
|
```ts
|
|
95
|
-
|
|
140
|
+
loginClient.getAuthHeader()
|
|
96
141
|
```
|
|
97
142
|
|
|
143
|
+
This means the login connector must be configured and authenticated before Safe CDX methods are called.
|
|
144
|
+
|
|
145
|
+
Example flow:
|
|
146
|
+
|
|
98
147
|
```ts
|
|
99
|
-
|
|
148
|
+
const http = new FetchClient();
|
|
149
|
+
|
|
150
|
+
const loginClient = new HCLoginClient(http);
|
|
151
|
+
|
|
152
|
+
// loginClient.configure(...)
|
|
153
|
+
// await loginClient.loginPatient(...)
|
|
154
|
+
|
|
155
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient, {
|
|
156
|
+
environment: "dev",
|
|
157
|
+
});
|
|
100
158
|
```
|
|
101
159
|
|
|
102
|
-
|
|
160
|
+
Safe CDX does not manually receive a token. It does not expose `setAccessToken()`. Auth is inherited from the configured login client.
|
|
161
|
+
|
|
162
|
+
## Optional API Key Header
|
|
163
|
+
|
|
164
|
+
If an API key header is required by the environment, it can be set on the Safe CDX client:
|
|
103
165
|
|
|
104
166
|
```ts
|
|
105
|
-
|
|
167
|
+
safeCdx.setApiKey("x-api-key", apiKeyValue);
|
|
106
168
|
```
|
|
107
169
|
|
|
108
|
-
|
|
170
|
+
When configured, the API key header is added to Safe CDX API calls together with the login auth headers.
|
|
109
171
|
|
|
110
172
|
## Request Payload Wrapping
|
|
111
173
|
|
|
@@ -115,29 +177,38 @@ The SDK wraps the payload internally as:
|
|
|
115
177
|
|
|
116
178
|
```ts
|
|
117
179
|
{
|
|
118
|
-
|
|
180
|
+
Data: payload
|
|
119
181
|
}
|
|
120
182
|
```
|
|
121
183
|
|
|
122
184
|
Correct:
|
|
123
185
|
|
|
124
186
|
```ts
|
|
125
|
-
await safeCdx.
|
|
126
|
-
|
|
187
|
+
await safeCdx.submitAnswers({
|
|
188
|
+
UserTestResultId: userTestResultId,
|
|
189
|
+
Result: [
|
|
190
|
+
{
|
|
191
|
+
Analyte: "Purchase",
|
|
192
|
+
ReportedValue: "drug store",
|
|
193
|
+
StoredValue: "drug store",
|
|
194
|
+
Score: "0",
|
|
195
|
+
},
|
|
196
|
+
],
|
|
127
197
|
});
|
|
128
198
|
```
|
|
129
199
|
|
|
130
200
|
Incorrect:
|
|
131
201
|
|
|
132
202
|
```ts
|
|
133
|
-
await safeCdx.
|
|
203
|
+
await safeCdx.submitAnswers({
|
|
134
204
|
Data: {
|
|
135
|
-
|
|
136
|
-
|
|
205
|
+
UserTestResultId: userTestResultId,
|
|
206
|
+
Result: [],
|
|
207
|
+
},
|
|
137
208
|
});
|
|
138
209
|
```
|
|
139
210
|
|
|
140
|
-
The caller should not manually add the `Data` wrapper
|
|
211
|
+
The caller should not manually add the `Data` wrapper.
|
|
141
212
|
|
|
142
213
|
## API Response Handling
|
|
143
214
|
|
|
@@ -155,6 +226,8 @@ For these endpoints, the client validates `IsOK`.
|
|
|
155
226
|
|
|
156
227
|
If `IsOK` is `false`, the client throws `SafeCDXError`.
|
|
157
228
|
|
|
229
|
+
This validation exists because an HTTP `200` response does not always mean the backend operation succeeded. The HTTP client validates the transport layer, while the Safe CDX client validates the API response envelope.
|
|
230
|
+
|
|
158
231
|
Some endpoints return a raw service result instead of the standard `ApiResponse` envelope. Those methods return the raw result directly.
|
|
159
232
|
|
|
160
233
|
Raw result methods include:
|
|
@@ -189,13 +262,15 @@ A typical flow looks like this:
|
|
|
189
262
|
```ts
|
|
190
263
|
const http = new FetchClient();
|
|
191
264
|
|
|
192
|
-
const
|
|
265
|
+
const loginClient = new HCLoginClient(http);
|
|
266
|
+
|
|
267
|
+
// Configure and authenticate loginClient first.
|
|
268
|
+
|
|
269
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient, {
|
|
193
270
|
environment: "dev",
|
|
194
271
|
defaultLanguage: "en",
|
|
195
272
|
defaultImageType: "jpg",
|
|
196
273
|
});
|
|
197
|
-
|
|
198
|
-
safeCdx.setAccessToken(patientAccessToken);
|
|
199
274
|
```
|
|
200
275
|
|
|
201
276
|
### 1. Get available test profiles
|
|
@@ -344,6 +419,8 @@ const scan = await safeCdx.scan2Ddm(payload);
|
|
|
344
419
|
|
|
345
420
|
Scans a 2D data matrix barcode and resolves the related test data.
|
|
346
421
|
|
|
422
|
+
This method requires a real 2D DataMatrix payload. A plain GTIN should not be used as the DataMatrix payload.
|
|
423
|
+
|
|
347
424
|
### getTestProfile
|
|
348
425
|
|
|
349
426
|
```ts
|
|
@@ -513,6 +590,8 @@ const result = await safeCdx.submitAnswers(payload);
|
|
|
513
590
|
|
|
514
591
|
Submits analyte answers for a test attempt.
|
|
515
592
|
|
|
593
|
+
`Result` should contain at least one answer item. The connector does not generate analyte answers automatically.
|
|
594
|
+
|
|
516
595
|
### finalizeTest
|
|
517
596
|
|
|
518
597
|
```ts
|
|
@@ -521,38 +600,20 @@ const result = await safeCdx.finalizeTest(payload);
|
|
|
521
600
|
|
|
522
601
|
Finalizes a test attempt with CTA, indication, and decision results.
|
|
523
602
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
The connector throws `SafeCDXError` for connector-level errors.
|
|
527
|
-
|
|
528
|
-
Examples:
|
|
529
|
-
|
|
530
|
-
- invalid environment
|
|
531
|
-
- missing access token
|
|
532
|
-
- failed `ApiResponse` validation
|
|
533
|
-
- failed image upload
|
|
534
|
-
|
|
535
|
-
```ts
|
|
536
|
-
try {
|
|
537
|
-
const profile = await safeCdx.getTestProfileByGTIN("850024942325");
|
|
538
|
-
} catch (error) {
|
|
539
|
-
if (error instanceof SafeCDXError) {
|
|
540
|
-
console.error(error.message);
|
|
541
|
-
console.error(error.response);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
throw error;
|
|
545
|
-
}
|
|
546
|
-
```
|
|
603
|
+
The payload should include:
|
|
547
604
|
|
|
548
|
-
|
|
605
|
+
- `UserTestResultId`
|
|
606
|
+
- `ctaResult`
|
|
607
|
+
- `indicationResult`
|
|
608
|
+
- `decisionResult`
|
|
549
609
|
|
|
550
|
-
For example, `FetchClient` from `@healthcloudai/hc-http` throws an HTTP error when the response status is not successful.
|
|
551
610
|
|
|
552
611
|
## Notes
|
|
553
612
|
|
|
554
613
|
- The connector does not perform login.
|
|
555
|
-
- The connector
|
|
614
|
+
- The connector uses `HCLoginClient` for authenticated request headers.
|
|
615
|
+
- The connector does not use `loginClient.getBaseUrl()` for Safe CDX API routes.
|
|
616
|
+
- Safe CDX routes use the Safe CDX environment host from `SafeCDXConfig`.
|
|
556
617
|
- Standard Safe CDX API methods use the shared `HttpClient`.
|
|
557
618
|
- POST payloads are wrapped internally as `{ Data: payload }`.
|
|
558
619
|
- The caller should pass only the inner payload to SDK methods.
|
package/dist/index.cjs
CHANGED
|
@@ -67,46 +67,52 @@ function assertApiResponse(envelope, route) {
|
|
|
67
67
|
return envelope;
|
|
68
68
|
}
|
|
69
69
|
var HCSafeCDXClient = class {
|
|
70
|
-
constructor(httpClient, config) {
|
|
70
|
+
constructor(httpClient, authClient, config) {
|
|
71
71
|
var _a;
|
|
72
72
|
if (!ENV_HOST[config.environment]) {
|
|
73
73
|
throw new SafeCDXError(`Invalid environment: ${config.environment}`);
|
|
74
74
|
}
|
|
75
75
|
this.http = httpClient;
|
|
76
|
+
this.auth = authClient;
|
|
76
77
|
this.host = ENV_HOST[config.environment];
|
|
77
78
|
this.defaultLanguage = config.defaultLanguage;
|
|
78
79
|
this.defaultImageType = (_a = config.defaultImageType) != null ? _a : "jpg";
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
setApiKey(headerName, value) {
|
|
82
|
+
const trimmedHeaderName = headerName == null ? void 0 : headerName.trim();
|
|
83
|
+
const trimmedValue = value == null ? void 0 : value.trim();
|
|
84
|
+
if (!trimmedHeaderName) {
|
|
85
|
+
throw new SafeCDXError("API key header name is required.");
|
|
84
86
|
}
|
|
85
|
-
|
|
87
|
+
if (!trimmedValue) {
|
|
88
|
+
throw new SafeCDXError("API key value is required.");
|
|
89
|
+
}
|
|
90
|
+
this.apiKeyHeaderName = trimmedHeaderName;
|
|
91
|
+
this.apiKeyValue = trimmedValue;
|
|
86
92
|
}
|
|
87
93
|
// ---------------------------------------------------------------------------
|
|
88
94
|
// Private helpers
|
|
89
95
|
// ---------------------------------------------------------------------------
|
|
90
|
-
getAuthorizationHeader() {
|
|
91
|
-
if (!this.accessToken) {
|
|
92
|
-
throw new SafeCDXError(
|
|
93
|
-
"SafeCDX requires an access token. Call setAccessToken() first."
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
const token = this.accessToken.replace(/^Bearer\s+/i, "").trim();
|
|
97
|
-
return `Bearer ${token}`;
|
|
98
|
-
}
|
|
99
96
|
getAuthHeaders() {
|
|
100
97
|
return {
|
|
101
|
-
|
|
98
|
+
...this.auth.getAuthHeader(),
|
|
99
|
+
...this.getApiKeyHeader()
|
|
102
100
|
};
|
|
103
101
|
}
|
|
104
|
-
|
|
102
|
+
getJsonHeaders() {
|
|
105
103
|
return {
|
|
106
|
-
|
|
104
|
+
...this.getAuthHeaders(),
|
|
107
105
|
"Content-Type": "application/json"
|
|
108
106
|
};
|
|
109
107
|
}
|
|
108
|
+
getApiKeyHeader() {
|
|
109
|
+
if (!this.apiKeyHeaderName || !this.apiKeyValue) {
|
|
110
|
+
return {};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
[this.apiKeyHeaderName]: this.apiKeyValue
|
|
114
|
+
};
|
|
115
|
+
}
|
|
110
116
|
url(route, query) {
|
|
111
117
|
return buildUrl(this.host, route, query);
|
|
112
118
|
}
|
|
@@ -134,7 +140,7 @@ var HCSafeCDXClient = class {
|
|
|
134
140
|
const envelope = await this.http.post(
|
|
135
141
|
this.url("scan/2ddm"),
|
|
136
142
|
wrapData(payload),
|
|
137
|
-
this.
|
|
143
|
+
this.getJsonHeaders()
|
|
138
144
|
);
|
|
139
145
|
return assertApiResponse(envelope, "scan/2ddm");
|
|
140
146
|
}
|
|
@@ -149,7 +155,7 @@ var HCSafeCDXClient = class {
|
|
|
149
155
|
const envelope = await this.http.post(
|
|
150
156
|
this.url("test/profile"),
|
|
151
157
|
wrapData(payload),
|
|
152
|
-
this.
|
|
158
|
+
this.getJsonHeaders()
|
|
153
159
|
);
|
|
154
160
|
return assertApiResponse(envelope, "test/profile");
|
|
155
161
|
}
|
|
@@ -163,7 +169,7 @@ var HCSafeCDXClient = class {
|
|
|
163
169
|
const envelope = await this.http.post(
|
|
164
170
|
this.url("test/profiles/by-account"),
|
|
165
171
|
wrapData(payload),
|
|
166
|
-
this.
|
|
172
|
+
this.getJsonHeaders()
|
|
167
173
|
);
|
|
168
174
|
return assertApiResponse(envelope, "test/profiles/by-account");
|
|
169
175
|
}
|
|
@@ -186,14 +192,16 @@ var HCSafeCDXClient = class {
|
|
|
186
192
|
const envelope = await this.http.post(
|
|
187
193
|
this.url("upload/url"),
|
|
188
194
|
wrapData(payload),
|
|
189
|
-
this.
|
|
195
|
+
this.getJsonHeaders()
|
|
190
196
|
);
|
|
191
197
|
return assertApiResponse(envelope, "upload/url");
|
|
192
198
|
}
|
|
193
199
|
/**
|
|
194
200
|
* PUT preSignedURL — direct S3 upload, not a SafeCDX API route.
|
|
195
201
|
* preSignedURL comes from createUploadUrl() response: Data.preSignedURL.
|
|
196
|
-
|
|
202
|
+
*
|
|
203
|
+
* This intentionally does not use the shared HttpClient because the existing
|
|
204
|
+
* HttpClient.put() is JSON-oriented and stringifies the request body.
|
|
197
205
|
*/
|
|
198
206
|
async uploadImage(preSignedURL, image, contentType = "image/jpeg") {
|
|
199
207
|
const response = await fetch(preSignedURL, {
|
|
@@ -234,7 +242,7 @@ var HCSafeCDXClient = class {
|
|
|
234
242
|
return this.http.post(
|
|
235
243
|
this.url("cvml/status"),
|
|
236
244
|
wrapData(payload),
|
|
237
|
-
this.
|
|
245
|
+
this.getJsonHeaders()
|
|
238
246
|
);
|
|
239
247
|
}
|
|
240
248
|
/**
|
|
@@ -263,7 +271,7 @@ var HCSafeCDXClient = class {
|
|
|
263
271
|
const envelope = await this.http.post(
|
|
264
272
|
this.url("test/result/pending"),
|
|
265
273
|
wrapData(payload),
|
|
266
|
-
this.
|
|
274
|
+
this.getJsonHeaders()
|
|
267
275
|
);
|
|
268
276
|
return assertApiResponse(envelope, "test/result/pending");
|
|
269
277
|
}
|
|
@@ -275,7 +283,7 @@ var HCSafeCDXClient = class {
|
|
|
275
283
|
const envelope = await this.http.post(
|
|
276
284
|
this.url("test/result/last"),
|
|
277
285
|
wrapData(payload),
|
|
278
|
-
this.
|
|
286
|
+
this.getJsonHeaders()
|
|
279
287
|
);
|
|
280
288
|
return assertApiResponse(envelope, "test/result/last");
|
|
281
289
|
}
|
|
@@ -287,7 +295,7 @@ var HCSafeCDXClient = class {
|
|
|
287
295
|
const envelope = await this.http.post(
|
|
288
296
|
this.url("test/result/history"),
|
|
289
297
|
wrapData(payload),
|
|
290
|
-
this.
|
|
298
|
+
this.getJsonHeaders()
|
|
291
299
|
);
|
|
292
300
|
return assertApiResponse(envelope, "test/result/history");
|
|
293
301
|
}
|
|
@@ -303,7 +311,7 @@ var HCSafeCDXClient = class {
|
|
|
303
311
|
return this.http.post(
|
|
304
312
|
this.url("test/result/details"),
|
|
305
313
|
wrapData(payload),
|
|
306
|
-
this.
|
|
314
|
+
this.getJsonHeaders()
|
|
307
315
|
);
|
|
308
316
|
}
|
|
309
317
|
/**
|
|
@@ -314,7 +322,7 @@ var HCSafeCDXClient = class {
|
|
|
314
322
|
const envelope = await this.http.post(
|
|
315
323
|
this.url("test/result/pdf"),
|
|
316
324
|
wrapData(payload),
|
|
317
|
-
this.
|
|
325
|
+
this.getJsonHeaders()
|
|
318
326
|
);
|
|
319
327
|
return assertApiResponse(envelope, "test/result/pdf");
|
|
320
328
|
}
|
|
@@ -330,7 +338,7 @@ var HCSafeCDXClient = class {
|
|
|
330
338
|
return this.http.post(
|
|
331
339
|
this.url("test/result/image/capture"),
|
|
332
340
|
wrapData(payload),
|
|
333
|
-
this.
|
|
341
|
+
this.getJsonHeaders()
|
|
334
342
|
);
|
|
335
343
|
}
|
|
336
344
|
/**
|
|
@@ -341,7 +349,7 @@ var HCSafeCDXClient = class {
|
|
|
341
349
|
const envelope = await this.http.post(
|
|
342
350
|
this.url("test/result/analytics"),
|
|
343
351
|
wrapData(payload),
|
|
344
|
-
this.
|
|
352
|
+
this.getJsonHeaders()
|
|
345
353
|
);
|
|
346
354
|
return assertApiResponse(envelope, "test/result/analytics");
|
|
347
355
|
}
|
|
@@ -360,7 +368,7 @@ var HCSafeCDXClient = class {
|
|
|
360
368
|
const envelope = await this.http.post(
|
|
361
369
|
this.url("test/resume"),
|
|
362
370
|
wrapData(payload),
|
|
363
|
-
this.
|
|
371
|
+
this.getJsonHeaders()
|
|
364
372
|
);
|
|
365
373
|
return assertApiResponse(envelope, "test/resume");
|
|
366
374
|
}
|
|
@@ -372,7 +380,7 @@ var HCSafeCDXClient = class {
|
|
|
372
380
|
const envelope = await this.http.post(
|
|
373
381
|
this.url("test/answers"),
|
|
374
382
|
wrapData(payload),
|
|
375
|
-
this.
|
|
383
|
+
this.getJsonHeaders()
|
|
376
384
|
);
|
|
377
385
|
return assertApiResponse(envelope, "test/answers");
|
|
378
386
|
}
|
|
@@ -384,7 +392,7 @@ var HCSafeCDXClient = class {
|
|
|
384
392
|
const envelope = await this.http.post(
|
|
385
393
|
this.url("test/finalize"),
|
|
386
394
|
wrapData(payload),
|
|
387
|
-
this.
|
|
395
|
+
this.getJsonHeaders()
|
|
388
396
|
);
|
|
389
397
|
return assertApiResponse(envelope, "test/finalize");
|
|
390
398
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HCLoginClient } from '@healthcloudai/hc-login-connector';
|
|
1
2
|
import { HttpClient } from '@healthcloudai/hc-http';
|
|
2
3
|
|
|
3
4
|
type Environment = "dev" | "uat" | "prod";
|
|
@@ -256,15 +257,17 @@ interface FinalizeTestRequest {
|
|
|
256
257
|
|
|
257
258
|
declare class HCSafeCDXClient {
|
|
258
259
|
private readonly http;
|
|
260
|
+
private readonly auth;
|
|
259
261
|
private readonly host;
|
|
260
|
-
private
|
|
261
|
-
private
|
|
262
|
-
private
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
private readonly defaultLanguage;
|
|
263
|
+
private readonly defaultImageType;
|
|
264
|
+
private apiKeyHeaderName?;
|
|
265
|
+
private apiKeyValue?;
|
|
266
|
+
constructor(httpClient: HttpClient, authClient: HCLoginClient, config: SafeCDXConfig);
|
|
267
|
+
setApiKey(headerName: string, value: string): void;
|
|
266
268
|
private getAuthHeaders;
|
|
267
|
-
private
|
|
269
|
+
private getJsonHeaders;
|
|
270
|
+
private getApiKeyHeader;
|
|
268
271
|
private url;
|
|
269
272
|
/**
|
|
270
273
|
* GET gs1/:gtin
|
|
@@ -295,7 +298,9 @@ declare class HCSafeCDXClient {
|
|
|
295
298
|
/**
|
|
296
299
|
* PUT preSignedURL — direct S3 upload, not a SafeCDX API route.
|
|
297
300
|
* preSignedURL comes from createUploadUrl() response: Data.preSignedURL.
|
|
298
|
-
|
|
301
|
+
*
|
|
302
|
+
* This intentionally does not use the shared HttpClient because the existing
|
|
303
|
+
* HttpClient.put() is JSON-oriented and stringifies the request body.
|
|
299
304
|
*/
|
|
300
305
|
uploadImage(preSignedURL: string, image: BodyInit, contentType?: string): Promise<void>;
|
|
301
306
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HCLoginClient } from '@healthcloudai/hc-login-connector';
|
|
1
2
|
import { HttpClient } from '@healthcloudai/hc-http';
|
|
2
3
|
|
|
3
4
|
type Environment = "dev" | "uat" | "prod";
|
|
@@ -256,15 +257,17 @@ interface FinalizeTestRequest {
|
|
|
256
257
|
|
|
257
258
|
declare class HCSafeCDXClient {
|
|
258
259
|
private readonly http;
|
|
260
|
+
private readonly auth;
|
|
259
261
|
private readonly host;
|
|
260
|
-
private
|
|
261
|
-
private
|
|
262
|
-
private
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
private readonly defaultLanguage;
|
|
263
|
+
private readonly defaultImageType;
|
|
264
|
+
private apiKeyHeaderName?;
|
|
265
|
+
private apiKeyValue?;
|
|
266
|
+
constructor(httpClient: HttpClient, authClient: HCLoginClient, config: SafeCDXConfig);
|
|
267
|
+
setApiKey(headerName: string, value: string): void;
|
|
266
268
|
private getAuthHeaders;
|
|
267
|
-
private
|
|
269
|
+
private getJsonHeaders;
|
|
270
|
+
private getApiKeyHeader;
|
|
268
271
|
private url;
|
|
269
272
|
/**
|
|
270
273
|
* GET gs1/:gtin
|
|
@@ -295,7 +298,9 @@ declare class HCSafeCDXClient {
|
|
|
295
298
|
/**
|
|
296
299
|
* PUT preSignedURL — direct S3 upload, not a SafeCDX API route.
|
|
297
300
|
* preSignedURL comes from createUploadUrl() response: Data.preSignedURL.
|
|
298
|
-
|
|
301
|
+
*
|
|
302
|
+
* This intentionally does not use the shared HttpClient because the existing
|
|
303
|
+
* HttpClient.put() is JSON-oriented and stringifies the request body.
|
|
299
304
|
*/
|
|
300
305
|
uploadImage(preSignedURL: string, image: BodyInit, contentType?: string): Promise<void>;
|
|
301
306
|
/**
|
package/dist/index.js
CHANGED
|
@@ -40,46 +40,52 @@ function assertApiResponse(envelope, route) {
|
|
|
40
40
|
return envelope;
|
|
41
41
|
}
|
|
42
42
|
var HCSafeCDXClient = class {
|
|
43
|
-
constructor(httpClient, config) {
|
|
43
|
+
constructor(httpClient, authClient, config) {
|
|
44
44
|
var _a;
|
|
45
45
|
if (!ENV_HOST[config.environment]) {
|
|
46
46
|
throw new SafeCDXError(`Invalid environment: ${config.environment}`);
|
|
47
47
|
}
|
|
48
48
|
this.http = httpClient;
|
|
49
|
+
this.auth = authClient;
|
|
49
50
|
this.host = ENV_HOST[config.environment];
|
|
50
51
|
this.defaultLanguage = config.defaultLanguage;
|
|
51
52
|
this.defaultImageType = (_a = config.defaultImageType) != null ? _a : "jpg";
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
setApiKey(headerName, value) {
|
|
55
|
+
const trimmedHeaderName = headerName == null ? void 0 : headerName.trim();
|
|
56
|
+
const trimmedValue = value == null ? void 0 : value.trim();
|
|
57
|
+
if (!trimmedHeaderName) {
|
|
58
|
+
throw new SafeCDXError("API key header name is required.");
|
|
57
59
|
}
|
|
58
|
-
|
|
60
|
+
if (!trimmedValue) {
|
|
61
|
+
throw new SafeCDXError("API key value is required.");
|
|
62
|
+
}
|
|
63
|
+
this.apiKeyHeaderName = trimmedHeaderName;
|
|
64
|
+
this.apiKeyValue = trimmedValue;
|
|
59
65
|
}
|
|
60
66
|
// ---------------------------------------------------------------------------
|
|
61
67
|
// Private helpers
|
|
62
68
|
// ---------------------------------------------------------------------------
|
|
63
|
-
getAuthorizationHeader() {
|
|
64
|
-
if (!this.accessToken) {
|
|
65
|
-
throw new SafeCDXError(
|
|
66
|
-
"SafeCDX requires an access token. Call setAccessToken() first."
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
const token = this.accessToken.replace(/^Bearer\s+/i, "").trim();
|
|
70
|
-
return `Bearer ${token}`;
|
|
71
|
-
}
|
|
72
69
|
getAuthHeaders() {
|
|
73
70
|
return {
|
|
74
|
-
|
|
71
|
+
...this.auth.getAuthHeader(),
|
|
72
|
+
...this.getApiKeyHeader()
|
|
75
73
|
};
|
|
76
74
|
}
|
|
77
|
-
|
|
75
|
+
getJsonHeaders() {
|
|
78
76
|
return {
|
|
79
|
-
|
|
77
|
+
...this.getAuthHeaders(),
|
|
80
78
|
"Content-Type": "application/json"
|
|
81
79
|
};
|
|
82
80
|
}
|
|
81
|
+
getApiKeyHeader() {
|
|
82
|
+
if (!this.apiKeyHeaderName || !this.apiKeyValue) {
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
[this.apiKeyHeaderName]: this.apiKeyValue
|
|
87
|
+
};
|
|
88
|
+
}
|
|
83
89
|
url(route, query) {
|
|
84
90
|
return buildUrl(this.host, route, query);
|
|
85
91
|
}
|
|
@@ -107,7 +113,7 @@ var HCSafeCDXClient = class {
|
|
|
107
113
|
const envelope = await this.http.post(
|
|
108
114
|
this.url("scan/2ddm"),
|
|
109
115
|
wrapData(payload),
|
|
110
|
-
this.
|
|
116
|
+
this.getJsonHeaders()
|
|
111
117
|
);
|
|
112
118
|
return assertApiResponse(envelope, "scan/2ddm");
|
|
113
119
|
}
|
|
@@ -122,7 +128,7 @@ var HCSafeCDXClient = class {
|
|
|
122
128
|
const envelope = await this.http.post(
|
|
123
129
|
this.url("test/profile"),
|
|
124
130
|
wrapData(payload),
|
|
125
|
-
this.
|
|
131
|
+
this.getJsonHeaders()
|
|
126
132
|
);
|
|
127
133
|
return assertApiResponse(envelope, "test/profile");
|
|
128
134
|
}
|
|
@@ -136,7 +142,7 @@ var HCSafeCDXClient = class {
|
|
|
136
142
|
const envelope = await this.http.post(
|
|
137
143
|
this.url("test/profiles/by-account"),
|
|
138
144
|
wrapData(payload),
|
|
139
|
-
this.
|
|
145
|
+
this.getJsonHeaders()
|
|
140
146
|
);
|
|
141
147
|
return assertApiResponse(envelope, "test/profiles/by-account");
|
|
142
148
|
}
|
|
@@ -159,14 +165,16 @@ var HCSafeCDXClient = class {
|
|
|
159
165
|
const envelope = await this.http.post(
|
|
160
166
|
this.url("upload/url"),
|
|
161
167
|
wrapData(payload),
|
|
162
|
-
this.
|
|
168
|
+
this.getJsonHeaders()
|
|
163
169
|
);
|
|
164
170
|
return assertApiResponse(envelope, "upload/url");
|
|
165
171
|
}
|
|
166
172
|
/**
|
|
167
173
|
* PUT preSignedURL — direct S3 upload, not a SafeCDX API route.
|
|
168
174
|
* preSignedURL comes from createUploadUrl() response: Data.preSignedURL.
|
|
169
|
-
|
|
175
|
+
*
|
|
176
|
+
* This intentionally does not use the shared HttpClient because the existing
|
|
177
|
+
* HttpClient.put() is JSON-oriented and stringifies the request body.
|
|
170
178
|
*/
|
|
171
179
|
async uploadImage(preSignedURL, image, contentType = "image/jpeg") {
|
|
172
180
|
const response = await fetch(preSignedURL, {
|
|
@@ -207,7 +215,7 @@ var HCSafeCDXClient = class {
|
|
|
207
215
|
return this.http.post(
|
|
208
216
|
this.url("cvml/status"),
|
|
209
217
|
wrapData(payload),
|
|
210
|
-
this.
|
|
218
|
+
this.getJsonHeaders()
|
|
211
219
|
);
|
|
212
220
|
}
|
|
213
221
|
/**
|
|
@@ -236,7 +244,7 @@ var HCSafeCDXClient = class {
|
|
|
236
244
|
const envelope = await this.http.post(
|
|
237
245
|
this.url("test/result/pending"),
|
|
238
246
|
wrapData(payload),
|
|
239
|
-
this.
|
|
247
|
+
this.getJsonHeaders()
|
|
240
248
|
);
|
|
241
249
|
return assertApiResponse(envelope, "test/result/pending");
|
|
242
250
|
}
|
|
@@ -248,7 +256,7 @@ var HCSafeCDXClient = class {
|
|
|
248
256
|
const envelope = await this.http.post(
|
|
249
257
|
this.url("test/result/last"),
|
|
250
258
|
wrapData(payload),
|
|
251
|
-
this.
|
|
259
|
+
this.getJsonHeaders()
|
|
252
260
|
);
|
|
253
261
|
return assertApiResponse(envelope, "test/result/last");
|
|
254
262
|
}
|
|
@@ -260,7 +268,7 @@ var HCSafeCDXClient = class {
|
|
|
260
268
|
const envelope = await this.http.post(
|
|
261
269
|
this.url("test/result/history"),
|
|
262
270
|
wrapData(payload),
|
|
263
|
-
this.
|
|
271
|
+
this.getJsonHeaders()
|
|
264
272
|
);
|
|
265
273
|
return assertApiResponse(envelope, "test/result/history");
|
|
266
274
|
}
|
|
@@ -276,7 +284,7 @@ var HCSafeCDXClient = class {
|
|
|
276
284
|
return this.http.post(
|
|
277
285
|
this.url("test/result/details"),
|
|
278
286
|
wrapData(payload),
|
|
279
|
-
this.
|
|
287
|
+
this.getJsonHeaders()
|
|
280
288
|
);
|
|
281
289
|
}
|
|
282
290
|
/**
|
|
@@ -287,7 +295,7 @@ var HCSafeCDXClient = class {
|
|
|
287
295
|
const envelope = await this.http.post(
|
|
288
296
|
this.url("test/result/pdf"),
|
|
289
297
|
wrapData(payload),
|
|
290
|
-
this.
|
|
298
|
+
this.getJsonHeaders()
|
|
291
299
|
);
|
|
292
300
|
return assertApiResponse(envelope, "test/result/pdf");
|
|
293
301
|
}
|
|
@@ -303,7 +311,7 @@ var HCSafeCDXClient = class {
|
|
|
303
311
|
return this.http.post(
|
|
304
312
|
this.url("test/result/image/capture"),
|
|
305
313
|
wrapData(payload),
|
|
306
|
-
this.
|
|
314
|
+
this.getJsonHeaders()
|
|
307
315
|
);
|
|
308
316
|
}
|
|
309
317
|
/**
|
|
@@ -314,7 +322,7 @@ var HCSafeCDXClient = class {
|
|
|
314
322
|
const envelope = await this.http.post(
|
|
315
323
|
this.url("test/result/analytics"),
|
|
316
324
|
wrapData(payload),
|
|
317
|
-
this.
|
|
325
|
+
this.getJsonHeaders()
|
|
318
326
|
);
|
|
319
327
|
return assertApiResponse(envelope, "test/result/analytics");
|
|
320
328
|
}
|
|
@@ -333,7 +341,7 @@ var HCSafeCDXClient = class {
|
|
|
333
341
|
const envelope = await this.http.post(
|
|
334
342
|
this.url("test/resume"),
|
|
335
343
|
wrapData(payload),
|
|
336
|
-
this.
|
|
344
|
+
this.getJsonHeaders()
|
|
337
345
|
);
|
|
338
346
|
return assertApiResponse(envelope, "test/resume");
|
|
339
347
|
}
|
|
@@ -345,7 +353,7 @@ var HCSafeCDXClient = class {
|
|
|
345
353
|
const envelope = await this.http.post(
|
|
346
354
|
this.url("test/answers"),
|
|
347
355
|
wrapData(payload),
|
|
348
|
-
this.
|
|
356
|
+
this.getJsonHeaders()
|
|
349
357
|
);
|
|
350
358
|
return assertApiResponse(envelope, "test/answers");
|
|
351
359
|
}
|
|
@@ -357,7 +365,7 @@ var HCSafeCDXClient = class {
|
|
|
357
365
|
const envelope = await this.http.post(
|
|
358
366
|
this.url("test/finalize"),
|
|
359
367
|
wrapData(payload),
|
|
360
|
-
this.
|
|
368
|
+
this.getJsonHeaders()
|
|
361
369
|
);
|
|
362
370
|
return assertApiResponse(envelope, "test/finalize");
|
|
363
371
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@healthcloudai/hc-safe-cdx",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Healthcheck Safe CDX connector.",
|
|
5
5
|
"author": "Healthcheck Systems Inc",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"prepublishOnly": "npm run build"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@healthcloudai/hc-http": "^0.0.6"
|
|
36
|
+
"@healthcloudai/hc-http": "^0.0.6",
|
|
37
|
+
"@healthcloudai/hc-login-connector": "^0.0.15"
|
|
37
38
|
},
|
|
38
39
|
"peerDependencies": {
|
|
39
40
|
"react-native": ">=0.70.0"
|