@healthcloudai/hc-safe-cdx 0.1.3 → 0.2.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/README.md +860 -98
- package/dist/index.cjs +83 -93
- package/dist/index.d.cts +193 -246
- package/dist/index.d.ts +193 -246
- package/dist/index.js +83 -93
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ The connector follows the same shared-client pattern used by other Health Cloud
|
|
|
9
9
|
- `HCSafeCDXClient` builds Safe CDX URLs, wraps request payloads, and exposes one method per Safe CDX route.
|
|
10
10
|
|
|
11
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.
|
|
12
|
+
Like `HCHealthRecordClient`, `HCSafeCDXClient` reads the configured environment from `HCLoginClient` and derives its own service base URL internally.
|
|
12
13
|
|
|
13
14
|
Image upload is handled separately because the upload target is a pre-signed S3 URL, not a Safe CDX API route.
|
|
14
15
|
|
|
@@ -33,14 +34,10 @@ const http = new FetchClient();
|
|
|
33
34
|
|
|
34
35
|
const loginClient = new HCLoginClient(http);
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
loginClient.configure("healthcheck", "dev");
|
|
38
|
+
await loginClient.login(email, password);
|
|
38
39
|
|
|
39
|
-
const safeCdx = new HCSafeCDXClient(http, loginClient
|
|
40
|
-
environment: "dev",
|
|
41
|
-
defaultLanguage: "en",
|
|
42
|
-
defaultImageType: "jpg",
|
|
43
|
-
});
|
|
40
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient);
|
|
44
41
|
```
|
|
45
42
|
|
|
46
43
|
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()`.
|
|
@@ -83,9 +80,10 @@ The client receives both the HTTP client and the login client:
|
|
|
83
80
|
const http = new FetchClient();
|
|
84
81
|
const loginClient = new HCLoginClient(http);
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
loginClient.configure("healthcheck", "dev");
|
|
84
|
+
await loginClient.login(email, password);
|
|
85
|
+
|
|
86
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient);
|
|
89
87
|
```
|
|
90
88
|
|
|
91
89
|
The shared `HttpClient` is responsible for executing HTTP requests.
|
|
@@ -94,7 +92,7 @@ The `HCLoginClient` is responsible for the authenticated request headers.
|
|
|
94
92
|
|
|
95
93
|
The Safe CDX client is responsible for:
|
|
96
94
|
|
|
97
|
-
-
|
|
95
|
+
- deriving the Safe CDX base URL from the login client's configured environment
|
|
98
96
|
- building Safe CDX URLs
|
|
99
97
|
- adding auth headers from `HCLoginClient`
|
|
100
98
|
- adding optional API key headers when configured
|
|
@@ -104,31 +102,33 @@ The Safe CDX client is responsible for:
|
|
|
104
102
|
|
|
105
103
|
The Safe CDX client does not create its own internal `fetch` helpers for standard Safe CDX API routes.
|
|
106
104
|
|
|
107
|
-
##
|
|
105
|
+
## Base URL Configuration
|
|
108
106
|
|
|
109
|
-
|
|
107
|
+
Safe CDX base URL configuration follows the same constructor pattern as the Health Record connector:
|
|
110
108
|
|
|
111
109
|
```ts
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
loginClient.configure("healthcheck", "dev");
|
|
111
|
+
|
|
112
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient);
|
|
115
113
|
```
|
|
116
114
|
|
|
117
|
-
|
|
115
|
+
The Safe CDX client reads the environment from:
|
|
118
116
|
|
|
119
117
|
```ts
|
|
120
|
-
|
|
118
|
+
loginClient.getEnvironment()
|
|
121
119
|
```
|
|
122
120
|
|
|
123
|
-
Safe CDX
|
|
121
|
+
Safe CDX still uses its own service base URL. It does not reuse `loginClient.getBaseUrl()`.
|
|
122
|
+
|
|
123
|
+
Environment mapping is handled internally by the connector:
|
|
124
124
|
|
|
125
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
|
|
126
|
+
dev -> https://dev-api-hcs.healthcloud-services.com/api/console/hcservice/safecdx
|
|
127
|
+
uat -> https://uat-api-hcs.healthcloud-services.com/api/console/hcservice/safecdx
|
|
128
|
+
prod -> https://api-hcs.healthcloud-services.com/api/console/hcservice/safecdx
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
These
|
|
131
|
+
These base URLs are separate from the login connector base URL.
|
|
132
132
|
|
|
133
133
|
## Authentication
|
|
134
134
|
|
|
@@ -149,12 +149,10 @@ const http = new FetchClient();
|
|
|
149
149
|
|
|
150
150
|
const loginClient = new HCLoginClient(http);
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
loginClient.configure("healthcheck", "dev");
|
|
153
|
+
await loginClient.login(email, password);
|
|
154
154
|
|
|
155
|
-
const safeCdx = new HCSafeCDXClient(http, loginClient
|
|
156
|
-
environment: "dev",
|
|
157
|
-
});
|
|
155
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient);
|
|
158
156
|
```
|
|
159
157
|
|
|
160
158
|
Safe CDX does not manually receive a token. It does not expose `setAccessToken()`. Auth is inherited from the configured login client.
|
|
@@ -228,9 +226,7 @@ If `IsOK` is `false`, the client throws `SafeCDXError`.
|
|
|
228
226
|
|
|
229
227
|
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
228
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
Raw result methods include:
|
|
229
|
+
For the following methods, the client returns the received response directly without applying `ApiResponse` validation:
|
|
234
230
|
|
|
235
231
|
```ts
|
|
236
232
|
updateCvmlStatus(...)
|
|
@@ -264,13 +260,10 @@ const http = new FetchClient();
|
|
|
264
260
|
|
|
265
261
|
const loginClient = new HCLoginClient(http);
|
|
266
262
|
|
|
267
|
-
|
|
263
|
+
loginClient.configure("healthcheck", "dev");
|
|
264
|
+
await loginClient.login(email, password);
|
|
268
265
|
|
|
269
|
-
const safeCdx = new HCSafeCDXClient(http, loginClient
|
|
270
|
-
environment: "dev",
|
|
271
|
-
defaultLanguage: "en",
|
|
272
|
-
defaultImageType: "jpg",
|
|
273
|
-
});
|
|
266
|
+
const safeCdx = new HCSafeCDXClient(http, loginClient);
|
|
274
267
|
```
|
|
275
268
|
|
|
276
269
|
### 1. Get available test profiles
|
|
@@ -336,30 +329,6 @@ await safeCdx.submitAnswers({
|
|
|
336
329
|
```ts
|
|
337
330
|
await safeCdx.finalizeTest({
|
|
338
331
|
UserTestResultId: userTestResultId,
|
|
339
|
-
ctaResult: {
|
|
340
|
-
id: "2",
|
|
341
|
-
title: "Connect with a Telehealth Provider for Next Steps",
|
|
342
|
-
instructions: "Share your test results with a telehealth provider for next steps.",
|
|
343
|
-
urlText: "Connect with Telehealth",
|
|
344
|
-
url: "https://example.com/start",
|
|
345
|
-
},
|
|
346
|
-
indicationResult: {
|
|
347
|
-
id: "4",
|
|
348
|
-
title: "Indication",
|
|
349
|
-
text: "Results suggest follow-up may be needed.",
|
|
350
|
-
recommendTitle: "Recommendation",
|
|
351
|
-
recommendText: "Review the result with a healthcare provider.",
|
|
352
|
-
ctaId: "2",
|
|
353
|
-
},
|
|
354
|
-
decisionResult: {
|
|
355
|
-
calculation: "Total: analyte.responses.score",
|
|
356
|
-
results: [
|
|
357
|
-
{
|
|
358
|
-
indicationId: "4",
|
|
359
|
-
value: "4",
|
|
360
|
-
},
|
|
361
|
-
],
|
|
362
|
-
},
|
|
363
332
|
});
|
|
364
333
|
```
|
|
365
334
|
|
|
@@ -404,22 +373,201 @@ These values should be stored by the consuming app and passed to the next SDK me
|
|
|
404
373
|
### getTestProfileByGTIN
|
|
405
374
|
|
|
406
375
|
```ts
|
|
407
|
-
const profile = await safeCdx.getTestProfileByGTIN(gtin
|
|
376
|
+
const profile = await safeCdx.getTestProfileByGTIN(gtin);
|
|
408
377
|
```
|
|
409
378
|
|
|
410
379
|
Resolves a test profile by GTIN barcode.
|
|
411
380
|
|
|
412
|
-
|
|
381
|
+
#### API Response example
|
|
413
382
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
383
|
+
```json
|
|
384
|
+
{
|
|
385
|
+
"Data": {
|
|
386
|
+
"ID": "6a104bba6068dd9a213db810",
|
|
387
|
+
"FHIRID": null,
|
|
388
|
+
"CQLID": null,
|
|
389
|
+
"TestName": "UTI Test + Treat",
|
|
390
|
+
"CustomTestName": "UTI Test + Treat",
|
|
391
|
+
"IsDeactivated": false,
|
|
392
|
+
"IsOrderable": true,
|
|
393
|
+
"EnablePublicHealthReporting": true,
|
|
394
|
+
"IsSelfAssessmentMode": true,
|
|
395
|
+
"CaptureMethod": 0,
|
|
396
|
+
"IsMLDisabled": false,
|
|
397
|
+
"ShortName": "UTI Test + Treat",
|
|
398
|
+
"DescriptionHTML": null,
|
|
399
|
+
"OrderableName": "Winx Health",
|
|
400
|
+
"VendorName": null,
|
|
401
|
+
"ManufactureName": null,
|
|
402
|
+
"VendorTestID": "0123",
|
|
403
|
+
"Sku": "SH00131",
|
|
404
|
+
"LabTestType": null,
|
|
405
|
+
"TestClassification": "NOT_SPECIFIED",
|
|
406
|
+
"KitRegistrationRequired": false,
|
|
407
|
+
"RequiresProviderVerificationOfResults": false,
|
|
408
|
+
"DiagnosticProfile": {
|
|
409
|
+
"_id": "6780031a991814469e88237f",
|
|
410
|
+
"Created": "2025-01-09T17:10:50.8Z",
|
|
411
|
+
"Modified": "2026-05-06T12:39:08.732Z",
|
|
412
|
+
"TestInfo": {
|
|
413
|
+
"gtin": "860002060439",
|
|
414
|
+
"testInfoHeader": "Winx Health",
|
|
415
|
+
"productName": "Winx UTI Test + Treat",
|
|
416
|
+
"testCategory": "Rapid",
|
|
417
|
+
"fdaStatus": "EUA",
|
|
418
|
+
"cvmlTestName": "winx-uti",
|
|
419
|
+
"cvmlDuration": 20,
|
|
420
|
+
"isCVMLResult": true,
|
|
421
|
+
"accountIds": [
|
|
422
|
+
"winxhealth",
|
|
423
|
+
"safehealth",
|
|
424
|
+
"test-account",
|
|
425
|
+
"speedyswab",
|
|
426
|
+
"healthcheck"
|
|
427
|
+
],
|
|
428
|
+
"cvmlRetryLimit": 2,
|
|
429
|
+
"failoverEnabled": true,
|
|
430
|
+
"cvmlPollingPolicy": "FullResult"
|
|
431
|
+
},
|
|
432
|
+
"Analyte": [
|
|
433
|
+
{
|
|
434
|
+
"_id": "1",
|
|
435
|
+
"DisplayOrder": 1,
|
|
436
|
+
"Display": "CVML",
|
|
437
|
+
"Name": "Leukocyte",
|
|
438
|
+
"Question": "What is the Leukocyte reading?",
|
|
439
|
+
"Image": "/analyte/WinxLeuk.png",
|
|
440
|
+
"Responses": [
|
|
441
|
+
{
|
|
442
|
+
"value": "Negative -",
|
|
443
|
+
"displayOrder": 1,
|
|
444
|
+
"storedValue": "Neg",
|
|
445
|
+
"cvmlValue": "Neg",
|
|
446
|
+
"score": "0"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
"value": "Positive 70+",
|
|
450
|
+
"displayOrder": 3,
|
|
451
|
+
"storedValue": "70+",
|
|
452
|
+
"cvmlValue": "70+",
|
|
453
|
+
"score": "4"
|
|
454
|
+
}
|
|
455
|
+
]
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"_id": "2",
|
|
459
|
+
"DisplayOrder": 2,
|
|
460
|
+
"Display": "CVML",
|
|
461
|
+
"Name": "Nitrite",
|
|
462
|
+
"Question": "What is the Nitrite reading?",
|
|
463
|
+
"Image": "/analyte/WinxNitr.png",
|
|
464
|
+
"Responses": [
|
|
465
|
+
{
|
|
466
|
+
"value": "Negative",
|
|
467
|
+
"displayOrder": 1,
|
|
468
|
+
"storedValue": "Neg",
|
|
469
|
+
"cvmlValue": "Neg",
|
|
470
|
+
"score": "0"
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"value": "Positive High++",
|
|
474
|
+
"displayOrder": 3,
|
|
475
|
+
"storedValue": "High++",
|
|
476
|
+
"cvmlValue": "High++",
|
|
477
|
+
"score": "2"
|
|
478
|
+
}
|
|
479
|
+
]
|
|
480
|
+
}
|
|
481
|
+
],
|
|
482
|
+
"Cta": [
|
|
483
|
+
{
|
|
484
|
+
"id": "1",
|
|
485
|
+
"title": "No UTI is detected",
|
|
486
|
+
"instructions": "If you're still having symptoms, we recommend talking to your doctor about additional testing.",
|
|
487
|
+
"linkType": "url",
|
|
488
|
+
"linkText": "Find a Doctor",
|
|
489
|
+
"linkValue": "https://book.zocdoc.com/?utm_source=winx&utm_medium=app&utm_campaign=testandtreat"
|
|
490
|
+
}
|
|
491
|
+
],
|
|
492
|
+
"Indication": [
|
|
493
|
+
{
|
|
494
|
+
"id": "4",
|
|
495
|
+
"title": "Indication",
|
|
496
|
+
"text": "Results suggest you have a UTI",
|
|
497
|
+
"recommendTitle": "Recommendation",
|
|
498
|
+
"recommendText": "Drink lots of water and connect with a doctor to discuss treatment and next steps.",
|
|
499
|
+
"ctaId": "2"
|
|
500
|
+
}
|
|
501
|
+
],
|
|
502
|
+
"Decision": [
|
|
503
|
+
{
|
|
504
|
+
"calculation": "Total: analyte.responses.score",
|
|
505
|
+
"results": [
|
|
506
|
+
{
|
|
507
|
+
"indicationId": "4",
|
|
508
|
+
"value": "4"
|
|
509
|
+
}
|
|
510
|
+
]
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
},
|
|
514
|
+
"ProductAssetDetail": {
|
|
515
|
+
"imageURL": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/ProductAsset/Image/47197f0c75844ba3b11335f7bfe1959b-639062362985442065.png",
|
|
516
|
+
"body": "<p></p>"
|
|
517
|
+
},
|
|
518
|
+
"DisclaimerDetail": {
|
|
519
|
+
"body": "<p><span style=\"font-family: Avenir, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif; font-size: 14pt;\">At this time please refer back to your paper Instructions For Use (IFU).</span></p>",
|
|
520
|
+
"title": "Record Results",
|
|
521
|
+
"continueButtonTitle": "Continue",
|
|
522
|
+
"showDisclaimer": false
|
|
523
|
+
},
|
|
524
|
+
"ScanImageDetail": {
|
|
525
|
+
"ImageUrl": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/ScanImage/Image/590172d7548e4b3eb09bfe42679fc6b1-638900206144635626.png"
|
|
526
|
+
},
|
|
527
|
+
"Instructions": [
|
|
528
|
+
{
|
|
529
|
+
"NavigationTitle": "Instructional Video",
|
|
530
|
+
"Type": "CollectionInstructionOnly",
|
|
531
|
+
"Title": "Instructional Video",
|
|
532
|
+
"ButtonTitle": "Continue",
|
|
533
|
+
"TimeInSeconds": 0,
|
|
534
|
+
"VideoUrl": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/CollectionInstruction/Video/3a74d7091d65455ab675f8ddd5f9d9d5-638918232791589391.mp4",
|
|
535
|
+
"SequenceOrder": 0
|
|
536
|
+
}
|
|
537
|
+
],
|
|
538
|
+
"BillingInfo": {
|
|
539
|
+
"Taxable": false
|
|
540
|
+
},
|
|
541
|
+
"Associations": null,
|
|
542
|
+
"TestReportAsset": null,
|
|
543
|
+
"Articles": [],
|
|
544
|
+
"TestResults": [
|
|
545
|
+
{
|
|
546
|
+
"PatientTestResult": 0,
|
|
547
|
+
"ResultTitle": "Positive",
|
|
548
|
+
"ResultDisplay": "Positive",
|
|
549
|
+
"TreatmentPlanDescription": "",
|
|
550
|
+
"IsReturnToDashboardAllowed": false,
|
|
551
|
+
"IsOrderTestAllowed": false,
|
|
552
|
+
"IsFindTestRetailerAllowed": false
|
|
553
|
+
}
|
|
554
|
+
],
|
|
555
|
+
"GS1GTINs": null,
|
|
556
|
+
"Included": null,
|
|
557
|
+
"LOINCCodes": null,
|
|
558
|
+
"TestLOINCCodes": null,
|
|
559
|
+
"TestSNOMEDCTCodes": null,
|
|
560
|
+
"Created": "2024-12-23T18:00:48.619Z",
|
|
561
|
+
"Modified": "2026-05-13T17:07:07.048Z",
|
|
562
|
+
"CreatedByID": null,
|
|
563
|
+
"ModifiedByID": null,
|
|
564
|
+
"TenantID": null
|
|
565
|
+
},
|
|
566
|
+
"ErrorMessage": null,
|
|
567
|
+
"IsOK": true
|
|
568
|
+
}
|
|
419
569
|
```
|
|
420
570
|
|
|
421
|
-
Returns the full test profile for a given payload.
|
|
422
|
-
|
|
423
571
|
### getTestProfilesByAccount
|
|
424
572
|
|
|
425
573
|
```ts
|
|
@@ -436,6 +584,61 @@ const profiles = await safeCdx.getTestProfilesByAccount({
|
|
|
436
584
|
});
|
|
437
585
|
```
|
|
438
586
|
|
|
587
|
+
#### API Response example
|
|
588
|
+
|
|
589
|
+
```json
|
|
590
|
+
{
|
|
591
|
+
"Data": {
|
|
592
|
+
"success": true,
|
|
593
|
+
"data": [
|
|
594
|
+
{
|
|
595
|
+
"gtin": "810172700093",
|
|
596
|
+
"productName": "Speedy Swab COVID-19 + Flu Self-Test",
|
|
597
|
+
"description": "",
|
|
598
|
+
"testKitImageURL": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/RegisterTest/Image/4307c803740644ab8c4594f69783c1d8-638694157517533356.png",
|
|
599
|
+
"language": "en",
|
|
600
|
+
"registerTestDetail": {
|
|
601
|
+
"title": "Scan the barcode",
|
|
602
|
+
"description": "<p><span style=\"font-size: 12pt; font-family: Avenir, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;\">Hold your phone over the barcode on the box.</span></p>",
|
|
603
|
+
"buttonTitle": "Scan Code",
|
|
604
|
+
"imageURL": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/RegisterTest/Image/1ccc293f924a4c5bb2c5fc76f474c625-638769599179275771.png"
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"gtin": "860002060439",
|
|
609
|
+
"productName": "Winx UTI Test + Treat",
|
|
610
|
+
"description": "",
|
|
611
|
+
"testKitImageURL": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/RegisterTest/Image/36649cb6377c435a9e4f83af0f2fea46-639058689126409862.png",
|
|
612
|
+
"language": "en",
|
|
613
|
+
"registerTestDetail": {
|
|
614
|
+
"title": "",
|
|
615
|
+
"description": "<p></p>",
|
|
616
|
+
"buttonTitle": "Scan Barcode on the Box",
|
|
617
|
+
"imageURL": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/RegisterTest/Image/ad72c9b8c3324c1cb7aa9dbf29e46d64-638905990491115782.png"
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
"gtin": "850024942325",
|
|
622
|
+
"productName": "Vaginal Health pH Test + Treat",
|
|
623
|
+
"description": "",
|
|
624
|
+
"testKitImageURL": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/RegisterTest/Image/3cebedbb69cb4455af33da5ab524ec93-639058688331122684.png",
|
|
625
|
+
"language": "en",
|
|
626
|
+
"registerTestDetail": {
|
|
627
|
+
"title": "",
|
|
628
|
+
"description": "<p></p>",
|
|
629
|
+
"buttonTitle": "Scan Barcode on the Box",
|
|
630
|
+
"imageURL": "https://safe-content-cache-us-west-2-quality-speed.s3-us-west-2.amazonaws.com/LabTestOrderable/RegisterTest/Image/1475ae0004084d749ee2dfc9123af952-638905989776168388.png"
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
],
|
|
634
|
+
"message": "Success",
|
|
635
|
+
"code": 0
|
|
636
|
+
},
|
|
637
|
+
"ErrorMessage": null,
|
|
638
|
+
"IsOK": true
|
|
639
|
+
}
|
|
640
|
+
```
|
|
641
|
+
|
|
439
642
|
### createUploadUrl
|
|
440
643
|
|
|
441
644
|
```ts
|
|
@@ -448,7 +651,24 @@ const upload = await safeCdx.createUploadUrl(
|
|
|
448
651
|
|
|
449
652
|
Creates a pre-signed image upload URL.
|
|
450
653
|
|
|
451
|
-
`imageType` is optional. If not provided, the client
|
|
654
|
+
`imageType` is optional. If not provided, the client sends `jpg`.
|
|
655
|
+
|
|
656
|
+
#### API Response example
|
|
657
|
+
|
|
658
|
+
```json
|
|
659
|
+
{
|
|
660
|
+
"Data": {
|
|
661
|
+
"preSignedURL": "https://sf-us-west-2-lower-neural-cdx-img-uploads-quality.s3.us-west-2.amazonaws.com/healthcheck/winx-uti/860002060439_6a104bba6068dd9a213db810-1.jpg?X-Amz-Expires=1200&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=***&X-Amz-Date=20260522T123118Z&X-Amz-SignedHeaders=host&X-Amz-Signature=***",
|
|
662
|
+
"Metadata": {
|
|
663
|
+
"UploadId": "860002060439_6a104bba6068dd9a213db810-1",
|
|
664
|
+
"Type": "Rapid Test Kit Upload",
|
|
665
|
+
"File": "860002060439_6a104bba6068dd9a213db810-1.jpg"
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
"ErrorMessage": null,
|
|
669
|
+
"IsOK": true
|
|
670
|
+
}
|
|
671
|
+
```
|
|
452
672
|
|
|
453
673
|
### uploadImage
|
|
454
674
|
|
|
@@ -471,7 +691,20 @@ const result = await safeCdx.updateCvmlStatus(
|
|
|
471
691
|
|
|
472
692
|
Updates the CVML processing status for a captured image.
|
|
473
693
|
|
|
474
|
-
|
|
694
|
+
The client returns the received response directly without applying `ApiResponse` validation.
|
|
695
|
+
|
|
696
|
+
#### API Response example
|
|
697
|
+
|
|
698
|
+
```json
|
|
699
|
+
{
|
|
700
|
+
"success": true,
|
|
701
|
+
"data": {
|
|
702
|
+
"_id": "6a104bba6068dd9a213db810"
|
|
703
|
+
},
|
|
704
|
+
"message": "Success",
|
|
705
|
+
"code": 0
|
|
706
|
+
}
|
|
707
|
+
```
|
|
475
708
|
|
|
476
709
|
### getCvmlResults
|
|
477
710
|
|
|
@@ -481,7 +714,51 @@ const result = await safeCdx.getCvmlResults(imageOfCaptureId);
|
|
|
481
714
|
|
|
482
715
|
Polls CVML analysis results for a captured image.
|
|
483
716
|
|
|
484
|
-
|
|
717
|
+
The client returns the received response directly without applying `ApiResponse` validation.
|
|
718
|
+
|
|
719
|
+
#### API Response example
|
|
720
|
+
|
|
721
|
+
```json
|
|
722
|
+
{
|
|
723
|
+
"success": true,
|
|
724
|
+
"data": {
|
|
725
|
+
"userID": "5d00527a-2a9c-4d68-a7f4-8f154b2ca3e6",
|
|
726
|
+
"status": "Started",
|
|
727
|
+
"cvmlStatus": "Retake",
|
|
728
|
+
"gtin": "860002060439",
|
|
729
|
+
"isCVMLResult": true,
|
|
730
|
+
"isSelfReportingPostTest": false,
|
|
731
|
+
"schemaVersion": 1,
|
|
732
|
+
"capture": {
|
|
733
|
+
"retryCount": 0,
|
|
734
|
+
"retryLimit": 0,
|
|
735
|
+
"failoverEnabled": true,
|
|
736
|
+
"lastCvmlStatus": "Retake",
|
|
737
|
+
"failoverTriggered": false
|
|
738
|
+
},
|
|
739
|
+
"questionnaireSnapshot": {
|
|
740
|
+
"isValid": []
|
|
741
|
+
},
|
|
742
|
+
"resumed": false,
|
|
743
|
+
"imageOfCaptureResult": {
|
|
744
|
+
"parsed": {
|
|
745
|
+
"outcome": "Retake",
|
|
746
|
+
"responseCode": "Err4",
|
|
747
|
+
"responseMessage": "ml_result_code_error_04_msg",
|
|
748
|
+
"responseTitle": "ml_result_code_error_04_title"
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
"failoverEnabled": true,
|
|
752
|
+
"failoverTriggered": false,
|
|
753
|
+
"resumable": false,
|
|
754
|
+
"showValidity": false,
|
|
755
|
+
"showError": true,
|
|
756
|
+
"_id": "6a104bba6068dd9a213db810"
|
|
757
|
+
},
|
|
758
|
+
"message": "Success",
|
|
759
|
+
"code": 0
|
|
760
|
+
}
|
|
761
|
+
```
|
|
485
762
|
|
|
486
763
|
### getPendingResults
|
|
487
764
|
|
|
@@ -491,14 +768,104 @@ const pending = await safeCdx.getPendingResults();
|
|
|
491
768
|
|
|
492
769
|
Returns pending or incomplete test results.
|
|
493
770
|
|
|
494
|
-
|
|
771
|
+
When called without an argument, the SDK sends:
|
|
772
|
+
|
|
773
|
+
```ts
|
|
774
|
+
{
|
|
775
|
+
Data: {
|
|
776
|
+
ExcludeStatus: "Invalid,Canceled",
|
|
777
|
+
},
|
|
778
|
+
}
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
The same request can be made explicitly:
|
|
495
782
|
|
|
496
783
|
```ts
|
|
497
784
|
const pending = await safeCdx.getPendingResults({
|
|
498
|
-
ExcludeStatus: "
|
|
785
|
+
ExcludeStatus: "Invalid,Canceled",
|
|
499
786
|
});
|
|
500
787
|
```
|
|
501
788
|
|
|
789
|
+
#### API Response example
|
|
790
|
+
|
|
791
|
+
```json
|
|
792
|
+
{
|
|
793
|
+
"Data": {
|
|
794
|
+
"success": true,
|
|
795
|
+
"data": [
|
|
796
|
+
{
|
|
797
|
+
"status": "Started",
|
|
798
|
+
"cvmlStatus": "Retake",
|
|
799
|
+
"gtin": "860002060439",
|
|
800
|
+
"testName": "Winx UTI Test + Treat",
|
|
801
|
+
"recordedDate": "2026-05-22T12:49:26.047Z",
|
|
802
|
+
"isCVMLBackground": false,
|
|
803
|
+
"isCVMLResult": true,
|
|
804
|
+
"isSelfReportingPostTest": false,
|
|
805
|
+
"isSelfReportingPreTest": false,
|
|
806
|
+
"viewed": false,
|
|
807
|
+
"schemaVersion": 1,
|
|
808
|
+
"capture": {
|
|
809
|
+
"retryCount": 0,
|
|
810
|
+
"retryLimit": 0,
|
|
811
|
+
"failoverEnabled": true,
|
|
812
|
+
"lastCvmlStatus": "Retake",
|
|
813
|
+
"failoverTriggered": false
|
|
814
|
+
},
|
|
815
|
+
"questionnaireSnapshot": {
|
|
816
|
+
"isValid": []
|
|
817
|
+
},
|
|
818
|
+
"resumed": false,
|
|
819
|
+
"failoverEnabled": true,
|
|
820
|
+
"failoverTriggered": false,
|
|
821
|
+
"resumable": true,
|
|
822
|
+
"resumeNext": "SelfReporting",
|
|
823
|
+
"showValidity": false,
|
|
824
|
+
"showError": true,
|
|
825
|
+
"_id": "6a104bba6068dd9a213db810"
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
"status": "Started",
|
|
829
|
+
"gtin": "810172700093",
|
|
830
|
+
"testName": "Speedy Swab COVID-19 + Flu Self-Test",
|
|
831
|
+
"recordedDate": "2026-05-22T10:11:10.181Z",
|
|
832
|
+
"isCVMLBackground": true,
|
|
833
|
+
"isCVMLResult": false,
|
|
834
|
+
"isSelfReportingPostTest": true,
|
|
835
|
+
"isSelfReportingPreTest": false,
|
|
836
|
+
"viewed": false,
|
|
837
|
+
"schemaVersion": 1,
|
|
838
|
+
"capture": {
|
|
839
|
+
"retryCount": 0,
|
|
840
|
+
"retryLimit": 0,
|
|
841
|
+
"failoverEnabled": true,
|
|
842
|
+
"failoverTriggered": false
|
|
843
|
+
},
|
|
844
|
+
"questionnaireSnapshot": {
|
|
845
|
+
"isValid": [
|
|
846
|
+
{
|
|
847
|
+
"display": "post-test",
|
|
848
|
+
"question": "Do you see a control line (C)?"
|
|
849
|
+
}
|
|
850
|
+
]
|
|
851
|
+
},
|
|
852
|
+
"resumed": false,
|
|
853
|
+
"failoverEnabled": true,
|
|
854
|
+
"failoverTriggered": false,
|
|
855
|
+
"resumable": false,
|
|
856
|
+
"showValidity": false,
|
|
857
|
+
"showError": true,
|
|
858
|
+
"_id": "6a102bbe6068dd9a213db80f"
|
|
859
|
+
}
|
|
860
|
+
],
|
|
861
|
+
"message": "Success",
|
|
862
|
+
"code": 0
|
|
863
|
+
},
|
|
864
|
+
"ErrorMessage": null,
|
|
865
|
+
"IsOK": true
|
|
866
|
+
}
|
|
867
|
+
```
|
|
868
|
+
|
|
502
869
|
### getLastResults
|
|
503
870
|
|
|
504
871
|
```ts
|
|
@@ -507,6 +874,160 @@ const last = await safeCdx.getLastResults();
|
|
|
507
874
|
|
|
508
875
|
Returns the most recent test result for the authenticated patient.
|
|
509
876
|
|
|
877
|
+
When called without an argument, the SDK sends:
|
|
878
|
+
|
|
879
|
+
```ts
|
|
880
|
+
{
|
|
881
|
+
Data: {
|
|
882
|
+
ExcludeStatus: "Invalid",
|
|
883
|
+
},
|
|
884
|
+
}
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
#### API Response example
|
|
888
|
+
|
|
889
|
+
```json
|
|
890
|
+
{
|
|
891
|
+
"Data": {
|
|
892
|
+
"success": true,
|
|
893
|
+
"data": {
|
|
894
|
+
"cvmlUploadId": "6a104bba6068dd9a213db810",
|
|
895
|
+
"userID": "5d00527a-2a9c-4d68-a7f4-8f154b2ca3e6",
|
|
896
|
+
"tenantID": "healthcheck",
|
|
897
|
+
"isSelfAssessment": false,
|
|
898
|
+
"status": "Started",
|
|
899
|
+
"cvmlStatus": "Retake",
|
|
900
|
+
"gtin": "860002060439",
|
|
901
|
+
"testInfoHeader": "Winx Health",
|
|
902
|
+
"testName": "Winx UTI Test + Treat",
|
|
903
|
+
"imageOfCapture": "860002060439_6a104bba6068dd9a213db810-1.jpg",
|
|
904
|
+
"imageOfCaptureUploadAt": "2026-05-22T12:31:18.333Z",
|
|
905
|
+
"imageOfCaptureResults": [
|
|
906
|
+
{
|
|
907
|
+
"imageOfCapture": "860002060439_6a104bba6068dd9a213db810-1.jpg",
|
|
908
|
+
"uploadAt": "2026-05-22T12:31:18.333Z",
|
|
909
|
+
"cvmlStatus": "Retake",
|
|
910
|
+
"parsed": {
|
|
911
|
+
"outcome": "Retake",
|
|
912
|
+
"responseCode": "Err4",
|
|
913
|
+
"responseMessage": "ml_result_code_error_04_msg",
|
|
914
|
+
"responseTitle": "ml_result_code_error_04_title"
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
],
|
|
918
|
+
"resultPDF": "archive/2026/05/22/12/48/7ecfd730-c4c3-4cd6-8b12-4210b9a2db28.pdf",
|
|
919
|
+
"result": [
|
|
920
|
+
{
|
|
921
|
+
"analyte": "Purchase",
|
|
922
|
+
"reportedValue": "drug store",
|
|
923
|
+
"storedValue": "drug store",
|
|
924
|
+
"score": "0"
|
|
925
|
+
}
|
|
926
|
+
],
|
|
927
|
+
"recordedDate": "2026-05-22T12:49:26.047Z",
|
|
928
|
+
"cvmlTestName": "winx-uti",
|
|
929
|
+
"isCVMLBackground": false,
|
|
930
|
+
"isCVMLResult": true,
|
|
931
|
+
"isSelfReportingPostTest": false,
|
|
932
|
+
"isSelfReportingPreTest": false,
|
|
933
|
+
"viewed": false,
|
|
934
|
+
"finalized": false,
|
|
935
|
+
"schemaVersion": 1,
|
|
936
|
+
"capture": {
|
|
937
|
+
"retryCount": 1,
|
|
938
|
+
"retryLimit": 2,
|
|
939
|
+
"failoverEnabled": true,
|
|
940
|
+
"lastCvmlStatus": "Retake",
|
|
941
|
+
"failoverTriggered": false
|
|
942
|
+
},
|
|
943
|
+
"questionnaireSnapshot": {
|
|
944
|
+
"isValid": [],
|
|
945
|
+
"analyte": [
|
|
946
|
+
{
|
|
947
|
+
"_id": "1",
|
|
948
|
+
"displayOrder": 1,
|
|
949
|
+
"display": "CVML",
|
|
950
|
+
"name": "Leukocyte",
|
|
951
|
+
"question": "What is the Leukocyte reading?",
|
|
952
|
+
"image": "WinxLeuk.png",
|
|
953
|
+
"cvmlOrder": 1,
|
|
954
|
+
"responses": [
|
|
955
|
+
{
|
|
956
|
+
"value": "Negative -",
|
|
957
|
+
"displayOrder": 1,
|
|
958
|
+
"storedValue": "Neg",
|
|
959
|
+
"cvmlValue": "Neg",
|
|
960
|
+
"score": "0"
|
|
961
|
+
},
|
|
962
|
+
{
|
|
963
|
+
"value": "Trace 15+-",
|
|
964
|
+
"displayOrder": 2,
|
|
965
|
+
"storedValue": "15+-",
|
|
966
|
+
"cvmlValue": "15+-",
|
|
967
|
+
"score": "3"
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
"value": "Positive 70+",
|
|
971
|
+
"displayOrder": 3,
|
|
972
|
+
"storedValue": "70+",
|
|
973
|
+
"cvmlValue": "70+",
|
|
974
|
+
"score": "4"
|
|
975
|
+
}
|
|
976
|
+
]
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
"_id": "2",
|
|
980
|
+
"displayOrder": 2,
|
|
981
|
+
"display": "CVML",
|
|
982
|
+
"name": "Nitrite",
|
|
983
|
+
"question": "What is the Nitrite reading?",
|
|
984
|
+
"image": "WinxNitr.png",
|
|
985
|
+
"cvmlOrder": 2,
|
|
986
|
+
"responses": [
|
|
987
|
+
{
|
|
988
|
+
"value": "Negative",
|
|
989
|
+
"displayOrder": 1,
|
|
990
|
+
"storedValue": "Neg",
|
|
991
|
+
"cvmlValue": "Neg",
|
|
992
|
+
"score": "0"
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
"value": "Positive Low+",
|
|
996
|
+
"displayOrder": 2,
|
|
997
|
+
"storedValue": "Low+",
|
|
998
|
+
"cvmlValue": "Low+",
|
|
999
|
+
"score": "2"
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
"value": "Positive High++",
|
|
1003
|
+
"displayOrder": 3,
|
|
1004
|
+
"storedValue": "High++",
|
|
1005
|
+
"cvmlValue": "High++",
|
|
1006
|
+
"score": "2"
|
|
1007
|
+
}
|
|
1008
|
+
]
|
|
1009
|
+
}
|
|
1010
|
+
]
|
|
1011
|
+
},
|
|
1012
|
+
"resumed": false,
|
|
1013
|
+
"language": "en",
|
|
1014
|
+
"labVendor": "Winx Health",
|
|
1015
|
+
"labTestType": "Home Test (Rapid)",
|
|
1016
|
+
"externalId": "test-user@example.com",
|
|
1017
|
+
"positiveAnalytes": [],
|
|
1018
|
+
"_id": "6a104bba6068dd9a213db810",
|
|
1019
|
+
"modifier": "5d00527a-2a9c-4d68-a7f4-8f154b2ca3e6",
|
|
1020
|
+
"created": "2026-05-22T12:27:38.731Z",
|
|
1021
|
+
"modified": "2026-05-22T12:49:26.047Z"
|
|
1022
|
+
},
|
|
1023
|
+
"message": "Success",
|
|
1024
|
+
"code": 0
|
|
1025
|
+
},
|
|
1026
|
+
"ErrorMessage": null,
|
|
1027
|
+
"IsOK": true
|
|
1028
|
+
}
|
|
1029
|
+
```
|
|
1030
|
+
|
|
510
1031
|
### getTestHistory
|
|
511
1032
|
|
|
512
1033
|
```ts
|
|
@@ -515,6 +1036,57 @@ const history = await safeCdx.getTestHistory();
|
|
|
515
1036
|
|
|
516
1037
|
Returns the test history for the authenticated patient.
|
|
517
1038
|
|
|
1039
|
+
When called without an argument, the SDK sends:
|
|
1040
|
+
|
|
1041
|
+
```ts
|
|
1042
|
+
{
|
|
1043
|
+
Data: {
|
|
1044
|
+
ExcludeStatus: "Invalid",
|
|
1045
|
+
},
|
|
1046
|
+
}
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
#### API Response example
|
|
1050
|
+
|
|
1051
|
+
```json
|
|
1052
|
+
{
|
|
1053
|
+
"Data": {
|
|
1054
|
+
"success": true,
|
|
1055
|
+
"data": [
|
|
1056
|
+
{
|
|
1057
|
+
"status": "Started",
|
|
1058
|
+
"cvmlStatus": "Retake",
|
|
1059
|
+
"testInfoHeader": "Winx Health",
|
|
1060
|
+
"testName": "Winx UTI Test + Treat",
|
|
1061
|
+
"recordedDate": "2026-05-22T12:49:26.047Z",
|
|
1062
|
+
"viewed": false,
|
|
1063
|
+
"schemaVersion": 1,
|
|
1064
|
+
"overallResult": "Unknown",
|
|
1065
|
+
"positiveAnalytes": [],
|
|
1066
|
+
"_id": "6a104bba6068dd9a213db810",
|
|
1067
|
+
"created": "2026-05-22T12:27:38.731Z"
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
"status": "Started",
|
|
1071
|
+
"testInfoHeader": "Biolabs International",
|
|
1072
|
+
"testName": "Speedy Swab COVID-19 + Flu Self-Test",
|
|
1073
|
+
"recordedDate": "2026-05-22T10:11:10.181Z",
|
|
1074
|
+
"viewed": false,
|
|
1075
|
+
"schemaVersion": 1,
|
|
1076
|
+
"overallResult": "Unknown",
|
|
1077
|
+
"positiveAnalytes": [],
|
|
1078
|
+
"_id": "6a102bbe6068dd9a213db80f",
|
|
1079
|
+
"created": "2026-05-22T10:11:10.181Z"
|
|
1080
|
+
}
|
|
1081
|
+
],
|
|
1082
|
+
"message": "Success",
|
|
1083
|
+
"code": 0
|
|
1084
|
+
},
|
|
1085
|
+
"ErrorMessage": null,
|
|
1086
|
+
"IsOK": true
|
|
1087
|
+
}
|
|
1088
|
+
```
|
|
1089
|
+
|
|
518
1090
|
### getResultDetails
|
|
519
1091
|
|
|
520
1092
|
```ts
|
|
@@ -523,7 +1095,141 @@ const details = await safeCdx.getResultDetails(userTestResultId);
|
|
|
523
1095
|
|
|
524
1096
|
Returns detailed result data for a specific test attempt.
|
|
525
1097
|
|
|
526
|
-
|
|
1098
|
+
The client returns the received response directly without applying `ApiResponse` validation.
|
|
1099
|
+
|
|
1100
|
+
#### API Response example
|
|
1101
|
+
|
|
1102
|
+
```json
|
|
1103
|
+
{
|
|
1104
|
+
"success": true,
|
|
1105
|
+
"data": {
|
|
1106
|
+
"cvmlUploadId": "6a104bba6068dd9a213db810",
|
|
1107
|
+
"userID": "5d00527a-2a9c-4d68-a7f4-8f154b2ca3e6",
|
|
1108
|
+
"tenantID": "healthcheck",
|
|
1109
|
+
"isSelfAssessment": false,
|
|
1110
|
+
"status": "Started",
|
|
1111
|
+
"cvmlStatus": "Retake",
|
|
1112
|
+
"gtin": "860002060439",
|
|
1113
|
+
"testInfoHeader": "Winx Health",
|
|
1114
|
+
"testName": "Winx UTI Test + Treat",
|
|
1115
|
+
"imageOfCapture": "860002060439_6a104bba6068dd9a213db810-1.jpg",
|
|
1116
|
+
"imageOfCaptureUploadAt": "2026-05-22T12:31:18.333Z",
|
|
1117
|
+
"imageOfCaptureResults": [
|
|
1118
|
+
{
|
|
1119
|
+
"imageOfCapture": "860002060439_6a104bba6068dd9a213db810-1.jpg",
|
|
1120
|
+
"uploadAt": "2026-05-22T12:31:18.333Z",
|
|
1121
|
+
"cvmlStatus": "Retake",
|
|
1122
|
+
"parsed": {
|
|
1123
|
+
"outcome": "Retake",
|
|
1124
|
+
"responseCode": "Err4",
|
|
1125
|
+
"responseMessage": "ml_result_code_error_04_msg",
|
|
1126
|
+
"responseTitle": "ml_result_code_error_04_title"
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
],
|
|
1130
|
+
"result": [],
|
|
1131
|
+
"recordedDate": "2026-05-22T12:27:38.731Z",
|
|
1132
|
+
"cvmlTestName": "winx-uti",
|
|
1133
|
+
"isCVMLBackground": false,
|
|
1134
|
+
"isCVMLResult": true,
|
|
1135
|
+
"isSelfReportingPostTest": false,
|
|
1136
|
+
"isSelfReportingPreTest": false,
|
|
1137
|
+
"viewed": false,
|
|
1138
|
+
"finalized": false,
|
|
1139
|
+
"schemaVersion": 1,
|
|
1140
|
+
"capture": {
|
|
1141
|
+
"retryCount": 1,
|
|
1142
|
+
"retryLimit": 2,
|
|
1143
|
+
"failoverEnabled": true,
|
|
1144
|
+
"lastCvmlStatus": "Retake",
|
|
1145
|
+
"failoverTriggered": false
|
|
1146
|
+
},
|
|
1147
|
+
"questionnaireSnapshot": {
|
|
1148
|
+
"isValid": [],
|
|
1149
|
+
"analyte": [
|
|
1150
|
+
{
|
|
1151
|
+
"_id": "1",
|
|
1152
|
+
"displayOrder": 1,
|
|
1153
|
+
"display": "CVML",
|
|
1154
|
+
"name": "Leukocyte",
|
|
1155
|
+
"question": "What is the Leukocyte reading?",
|
|
1156
|
+
"image": "WinxLeuk.png",
|
|
1157
|
+
"cvmlOrder": 1,
|
|
1158
|
+
"responses": [
|
|
1159
|
+
{
|
|
1160
|
+
"value": "Negative -",
|
|
1161
|
+
"displayOrder": 1,
|
|
1162
|
+
"storedValue": "Neg",
|
|
1163
|
+
"cvmlValue": "Neg",
|
|
1164
|
+
"score": "0"
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
"value": "Trace 15+-",
|
|
1168
|
+
"displayOrder": 2,
|
|
1169
|
+
"storedValue": "15+-",
|
|
1170
|
+
"cvmlValue": "15+-",
|
|
1171
|
+
"score": "3"
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
"value": "Positive 70+",
|
|
1175
|
+
"displayOrder": 3,
|
|
1176
|
+
"storedValue": "70+",
|
|
1177
|
+
"cvmlValue": "70+",
|
|
1178
|
+
"score": "4"
|
|
1179
|
+
}
|
|
1180
|
+
]
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
"_id": "2",
|
|
1184
|
+
"displayOrder": 2,
|
|
1185
|
+
"display": "CVML",
|
|
1186
|
+
"name": "Nitrite",
|
|
1187
|
+
"question": "What is the Nitrite reading?",
|
|
1188
|
+
"image": "WinxNitr.png",
|
|
1189
|
+
"cvmlOrder": 2,
|
|
1190
|
+
"responses": [
|
|
1191
|
+
{
|
|
1192
|
+
"value": "Negative",
|
|
1193
|
+
"displayOrder": 1,
|
|
1194
|
+
"storedValue": "Neg",
|
|
1195
|
+
"cvmlValue": "Neg",
|
|
1196
|
+
"score": "0"
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
"value": "Positive Low+",
|
|
1200
|
+
"displayOrder": 2,
|
|
1201
|
+
"storedValue": "Low+",
|
|
1202
|
+
"cvmlValue": "Low+",
|
|
1203
|
+
"score": "2"
|
|
1204
|
+
},
|
|
1205
|
+
{
|
|
1206
|
+
"value": "Positive High++",
|
|
1207
|
+
"displayOrder": 3,
|
|
1208
|
+
"storedValue": "High++",
|
|
1209
|
+
"cvmlValue": "High++",
|
|
1210
|
+
"score": "2"
|
|
1211
|
+
}
|
|
1212
|
+
]
|
|
1213
|
+
}
|
|
1214
|
+
]
|
|
1215
|
+
},
|
|
1216
|
+
"resumed": false,
|
|
1217
|
+
"language": "en",
|
|
1218
|
+
"labVendor": "Winx Health",
|
|
1219
|
+
"labTestType": "Home Test (Rapid)",
|
|
1220
|
+
"statusResultsText": "",
|
|
1221
|
+
"externalId": "test-user@example.com",
|
|
1222
|
+
"overallResult": "Unknown",
|
|
1223
|
+
"positiveAnalytes": [],
|
|
1224
|
+
"_id": "6a104bba6068dd9a213db810",
|
|
1225
|
+
"modifier": "system",
|
|
1226
|
+
"created": "2026-05-22T12:27:38.731Z",
|
|
1227
|
+
"modified": "2026-05-22T12:33:17.308Z"
|
|
1228
|
+
},
|
|
1229
|
+
"message": "Success",
|
|
1230
|
+
"code": 0
|
|
1231
|
+
}
|
|
1232
|
+
```
|
|
527
1233
|
|
|
528
1234
|
### getResultPdf
|
|
529
1235
|
|
|
@@ -533,30 +1239,42 @@ const pdf = await safeCdx.getResultPdf({
|
|
|
533
1239
|
});
|
|
534
1240
|
```
|
|
535
1241
|
|
|
536
|
-
|
|
1242
|
+
Requests the PDF result for a specific test result.
|
|
537
1243
|
|
|
538
|
-
|
|
1244
|
+
#### API Response example
|
|
539
1245
|
|
|
540
|
-
```
|
|
541
|
-
|
|
1246
|
+
```json
|
|
1247
|
+
{
|
|
1248
|
+
"Data": {
|
|
1249
|
+
"success": true,
|
|
1250
|
+
"data": "https://safe-manual-test-results-us-west-2-quality-speed.s3.us-west-2.amazonaws.com/archive/2026/05/22/12/48/7ecfd730-c4c3-4cd6-8b12-4210b9a2db28.pdf?X-Amz-Expires=900&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=***&X-Amz-Date=20260522T124843Z&X-Amz-SignedHeaders=host&X-Amz-Signature=***",
|
|
1251
|
+
"message": "Success",
|
|
1252
|
+
"code": 0
|
|
1253
|
+
},
|
|
1254
|
+
"ErrorMessage": null,
|
|
1255
|
+
"IsOK": true
|
|
1256
|
+
}
|
|
542
1257
|
```
|
|
543
1258
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
This method returns a raw service result.
|
|
547
|
-
|
|
548
|
-
### getAnalytics
|
|
1259
|
+
### getImageCaptureUrl
|
|
549
1260
|
|
|
550
1261
|
```ts
|
|
551
|
-
const
|
|
1262
|
+
const imageUrl = await safeCdx.getImageCaptureUrl(userTestResultId);
|
|
552
1263
|
```
|
|
553
1264
|
|
|
554
|
-
|
|
1265
|
+
Requests image capture data for a specific test result.
|
|
555
1266
|
|
|
556
|
-
|
|
1267
|
+
The client returns the received response directly without applying `ApiResponse` validation.
|
|
557
1268
|
|
|
558
|
-
|
|
559
|
-
|
|
1269
|
+
#### API Response example
|
|
1270
|
+
|
|
1271
|
+
```json
|
|
1272
|
+
{
|
|
1273
|
+
"success": true,
|
|
1274
|
+
"data": "https://sf-us-west-2-lower-neural-cdx-img-uploads-quality.s3.us-west-2.amazonaws.com/healthcheck/winx-uti/860002060439_6a104bba6068dd9a213db810-1.jpg?X-Amz-Expires=900&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=***&X-Amz-Date=20260522T125017Z&X-Amz-SignedHeaders=host&X-Amz-Signature=***",
|
|
1275
|
+
"message": "Success",
|
|
1276
|
+
"code": 0
|
|
1277
|
+
}
|
|
560
1278
|
```
|
|
561
1279
|
|
|
562
1280
|
### resumeFlow
|
|
@@ -573,6 +1291,28 @@ The second argument can be used to explicitly set the resumed value:
|
|
|
573
1291
|
const resumed = await safeCdx.resumeFlow(userTestResultId, true);
|
|
574
1292
|
```
|
|
575
1293
|
|
|
1294
|
+
#### API Response example
|
|
1295
|
+
|
|
1296
|
+
```json
|
|
1297
|
+
{
|
|
1298
|
+
"Data": {
|
|
1299
|
+
"success": true,
|
|
1300
|
+
"data": {
|
|
1301
|
+
"cvmlStatus": "Retake",
|
|
1302
|
+
"reportType": "SELF",
|
|
1303
|
+
"resumed": true,
|
|
1304
|
+
"failoverTriggered": false,
|
|
1305
|
+
"showValidity": false,
|
|
1306
|
+
"_id": "6a02f6da6068dd9a213db7cb"
|
|
1307
|
+
},
|
|
1308
|
+
"message": "Success",
|
|
1309
|
+
"code": 0
|
|
1310
|
+
},
|
|
1311
|
+
"ErrorMessage": null,
|
|
1312
|
+
"IsOK": true
|
|
1313
|
+
}
|
|
1314
|
+
```
|
|
1315
|
+
|
|
576
1316
|
### submitAnswers
|
|
577
1317
|
|
|
578
1318
|
```ts
|
|
@@ -583,20 +1323,42 @@ Submits analyte answers for a test attempt.
|
|
|
583
1323
|
|
|
584
1324
|
`Result` should contain at least one answer item. The connector does not generate analyte answers automatically.
|
|
585
1325
|
|
|
1326
|
+
#### API Response example
|
|
1327
|
+
|
|
1328
|
+
```json
|
|
1329
|
+
{
|
|
1330
|
+
"Data": {
|
|
1331
|
+
"success": true,
|
|
1332
|
+
"data": {
|
|
1333
|
+
"_id": "6a104bba6068dd9a213db810"
|
|
1334
|
+
},
|
|
1335
|
+
"message": "Success",
|
|
1336
|
+
"code": 0
|
|
1337
|
+
},
|
|
1338
|
+
"ErrorMessage": null,
|
|
1339
|
+
"IsOK": true
|
|
1340
|
+
}
|
|
1341
|
+
```
|
|
1342
|
+
|
|
586
1343
|
### finalizeTest
|
|
587
1344
|
|
|
588
1345
|
```ts
|
|
589
|
-
const result = await safeCdx.finalizeTest(
|
|
1346
|
+
const result = await safeCdx.finalizeTest({
|
|
1347
|
+
UserTestResultId: userTestResultId,
|
|
1348
|
+
});
|
|
590
1349
|
```
|
|
591
1350
|
|
|
592
|
-
Finalizes a test
|
|
1351
|
+
Finalizes a test by `UserTestResultId`.
|
|
593
1352
|
|
|
594
|
-
The
|
|
1353
|
+
The SDK sends:
|
|
595
1354
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
1355
|
+
```ts
|
|
1356
|
+
{
|
|
1357
|
+
Data: {
|
|
1358
|
+
UserTestResultId: userTestResultId,
|
|
1359
|
+
},
|
|
1360
|
+
}
|
|
1361
|
+
```
|
|
600
1362
|
|
|
601
1363
|
|
|
602
1364
|
## Notes
|
|
@@ -604,7 +1366,7 @@ The payload should include:
|
|
|
604
1366
|
- The connector does not perform login.
|
|
605
1367
|
- The connector uses `HCLoginClient` for authenticated request headers.
|
|
606
1368
|
- The connector does not use `loginClient.getBaseUrl()` for Safe CDX API routes.
|
|
607
|
-
- Safe CDX
|
|
1369
|
+
- Safe CDX derives its service base URL from `loginClient.getEnvironment()`.
|
|
608
1370
|
- Standard Safe CDX API methods use the shared `HttpClient`.
|
|
609
1371
|
- POST payloads are wrapped internally as `{ Data: payload }`.
|
|
610
1372
|
- The caller should pass only the inner payload to SDK methods.
|