oro-sdk 3.4.0 → 3.6.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/client.d.ts +2 -1
- package/dist/helpers/patient-registration.d.ts +2 -1
- package/dist/oro-sdk.cjs.development.js +117 -92
- package/dist/oro-sdk.cjs.development.js.map +1 -1
- package/dist/oro-sdk.cjs.production.min.js +1 -1
- package/dist/oro-sdk.cjs.production.min.js.map +1 -1
- package/dist/oro-sdk.esm.js +117 -92
- package/dist/oro-sdk.esm.js.map +1 -1
- package/package.json +58 -58
- package/src/client.ts +38 -35
- package/src/helpers/patient-registration.ts +70 -51
package/package.json
CHANGED
@@ -1,61 +1,61 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
},
|
13
|
-
"scripts": {
|
14
|
-
"link:watch": "npm link && tsdx watch",
|
15
|
-
"link:watch:apis": "npm link oro-sdk-apis && npm link && tsdx watch",
|
16
|
-
"start": "tsdx watch",
|
17
|
-
"build": "tsdx build",
|
18
|
-
"test": "tsdx test",
|
19
|
-
"lint": "tsdx lint",
|
20
|
-
"prepare": "tsdx build",
|
21
|
-
"size": "size-limit",
|
22
|
-
"analyze": "size-limit --why",
|
23
|
-
"package": "tsdx build && npm publish",
|
24
|
-
"pretty": "prettier --config ../../.prettierrc.yaml --write './src/**/*.{ts,js,json,md}' && prettier --write './*.md'"
|
25
|
-
},
|
26
|
-
"name": "oro-sdk",
|
27
|
-
"author": "Antoine Jaouën <antoine@orohealth.me>",
|
28
|
-
"module": "dist/oro-sdk.esm.js",
|
29
|
-
"description": "This package is intended to be run in browser only. It contains everything needed to interact with backend services, especially the vault",
|
30
|
-
"size-limit": [
|
31
|
-
{
|
32
|
-
"path": "dist/oro-sdk.cjs.production.min.js",
|
33
|
-
"limit": "10 KB"
|
2
|
+
"version": "3.6.1",
|
3
|
+
"main": "dist/index.js",
|
4
|
+
"typings": "dist/index.d.ts",
|
5
|
+
"files": [
|
6
|
+
"dist",
|
7
|
+
"src"
|
8
|
+
],
|
9
|
+
"engines": {
|
10
|
+
"node": ">=10",
|
11
|
+
"npm": ">=6.14.13"
|
34
12
|
},
|
35
|
-
{
|
36
|
-
|
37
|
-
|
13
|
+
"scripts": {
|
14
|
+
"link:watch": "npm link && tsdx watch",
|
15
|
+
"link:watch:apis": "npm link oro-sdk-apis && npm link && tsdx watch",
|
16
|
+
"start": "tsdx watch",
|
17
|
+
"build": "tsdx build",
|
18
|
+
"test": "tsdx test",
|
19
|
+
"lint": "tsdx lint",
|
20
|
+
"prepare": "tsdx build",
|
21
|
+
"size": "size-limit",
|
22
|
+
"analyze": "size-limit --why",
|
23
|
+
"package": "tsdx build && npm publish",
|
24
|
+
"pretty": "prettier --config ../../.prettierrc.yaml --write './src/**/*.{ts,js,json,md}' && prettier --write './*.md'"
|
25
|
+
},
|
26
|
+
"name": "oro-sdk",
|
27
|
+
"author": "Antoine Jaouën <antoine@orohealth.me>",
|
28
|
+
"module": "dist/oro-sdk.esm.js",
|
29
|
+
"description": "This package is intended to be run in browser only. It contains everything needed to interact with backend services, especially the vault",
|
30
|
+
"size-limit": [
|
31
|
+
{
|
32
|
+
"path": "dist/oro-sdk.cjs.production.min.js",
|
33
|
+
"limit": "10 KB"
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"path": "dist/oro-sdk.esm.js",
|
37
|
+
"limit": "10 KB"
|
38
|
+
}
|
39
|
+
],
|
40
|
+
"devDependencies": {
|
41
|
+
"@size-limit/preset-small-lib": "^4.10.2",
|
42
|
+
"@types/jest": "^27.4.1",
|
43
|
+
"@types/uuid": "^8.3.0",
|
44
|
+
"prettier": "^2.5.1",
|
45
|
+
"prettier-plugin-svelte": "^2.3.0",
|
46
|
+
"size-limit": "^4.10.2",
|
47
|
+
"tsdx": "^0.14.1",
|
48
|
+
"tslib": "^2.2.0",
|
49
|
+
"typescript": "^4.2.4"
|
50
|
+
},
|
51
|
+
"dependencies": {
|
52
|
+
"axios": "^0.21.4",
|
53
|
+
"axios-auth-refresh": "^3.2.1",
|
54
|
+
"form-data": "^4.0.0",
|
55
|
+
"formdata-node": "^4.3.1",
|
56
|
+
"idb-keyval": "^5.0.6",
|
57
|
+
"oro-sdk-apis": "1.41.0",
|
58
|
+
"oro-toolbox": "0.0.6",
|
59
|
+
"uuid": "^8.3.2"
|
38
60
|
}
|
39
|
-
|
40
|
-
"devDependencies": {
|
41
|
-
"@size-limit/preset-small-lib": "^4.10.2",
|
42
|
-
"@types/jest": "^27.4.1",
|
43
|
-
"@types/uuid": "^8.3.0",
|
44
|
-
"prettier": "^2.5.1",
|
45
|
-
"prettier-plugin-svelte": "^2.3.0",
|
46
|
-
"size-limit": "^4.10.2",
|
47
|
-
"tsdx": "^0.14.1",
|
48
|
-
"tslib": "^2.2.0",
|
49
|
-
"typescript": "^4.2.4"
|
50
|
-
},
|
51
|
-
"dependencies": {
|
52
|
-
"axios": "^0.21.4",
|
53
|
-
"axios-auth-refresh": "^3.2.1",
|
54
|
-
"form-data": "^4.0.0",
|
55
|
-
"formdata-node": "^4.3.1",
|
56
|
-
"idb-keyval": "^5.0.6",
|
57
|
-
"oro-sdk-apis": "1.40.0",
|
58
|
-
"oro-toolbox": "0.0.6",
|
59
|
-
"uuid": "^8.3.2"
|
60
|
-
}
|
61
|
-
}
|
61
|
+
}
|
package/src/client.ts
CHANGED
@@ -83,7 +83,7 @@ export class OroClient {
|
|
83
83
|
public workflowClient: WorkflowService,
|
84
84
|
public diagnosisClient: DiagnosisService,
|
85
85
|
private authenticationCallback?: (err: Error) => void
|
86
|
-
) {
|
86
|
+
) {}
|
87
87
|
|
88
88
|
/**
|
89
89
|
* clears the vaultIndex and cached metadata grants
|
@@ -280,6 +280,7 @@ export class OroClient {
|
|
280
280
|
* @param consult
|
281
281
|
* @param workflow
|
282
282
|
* @param recoveryQA
|
283
|
+
* @param indexSearch create search index for the consultation if true
|
283
284
|
* @returns
|
284
285
|
*/
|
285
286
|
public async registerPatient(
|
@@ -289,10 +290,11 @@ export class OroClient {
|
|
289
290
|
recoveryQA?: {
|
290
291
|
recoverySecurityQuestions: string[]
|
291
292
|
recoverySecurityAnswers: string[]
|
292
|
-
}
|
293
|
+
},
|
294
|
+
indexSearch: boolean = true
|
293
295
|
): Promise<RegisterPatientOutput> {
|
294
296
|
if (!this.rsa) throw IncompleteAuthentication
|
295
|
-
return registerPatient(patientUuid, consult, workflow, this, this.toolbox.uuid(), recoveryQA)
|
297
|
+
return registerPatient(patientUuid, consult, workflow, this, this.toolbox.uuid(), recoveryQA, indexSearch)
|
296
298
|
}
|
297
299
|
|
298
300
|
/**
|
@@ -391,18 +393,18 @@ export class OroClient {
|
|
391
393
|
}))
|
392
394
|
.map(
|
393
395
|
(e: IndexConsultLockbox) =>
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
396
|
+
({
|
397
|
+
uuid: e.uuid,
|
398
|
+
timestamp: e.timestamp,
|
399
|
+
uniqueHash: e.uniqueHash,
|
400
|
+
encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
|
401
|
+
{
|
402
|
+
consultationId: e.consultationId,
|
403
|
+
grant: e.grant,
|
404
|
+
},
|
405
|
+
rsaPub
|
406
|
+
),
|
407
|
+
} as EncryptedIndexEntry)
|
406
408
|
)
|
407
409
|
break
|
408
410
|
//// DEPRECATED : REMOVE ME : BEGIN ///////////////////////////////////////////
|
@@ -424,18 +426,18 @@ export class OroClient {
|
|
424
426
|
)
|
425
427
|
.map(
|
426
428
|
(e: IndexConsultLockbox) =>
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
429
|
+
({
|
430
|
+
uuid: e.uuid,
|
431
|
+
timestamp: e.timestamp,
|
432
|
+
uniqueHash: e.uniqueHash,
|
433
|
+
encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
|
434
|
+
{
|
435
|
+
consultationId: e.consultationId,
|
436
|
+
grant: e.grant,
|
437
|
+
},
|
438
|
+
rsaPub
|
439
|
+
),
|
440
|
+
} as EncryptedIndexEntry)
|
439
441
|
)
|
440
442
|
break
|
441
443
|
//// DEPRECATED : REMOVE ME : END ///////////////////////////////////////////
|
@@ -785,14 +787,15 @@ export class OroClient {
|
|
785
787
|
|
786
788
|
// if there is a filter to apply, then the grant can be retrieved from the vault index, otherwise, all grants are fetched
|
787
789
|
// Note: will work only if the filter being applied is exclusively a consult id
|
788
|
-
const grantsByConsultLockbox = filter
|
789
|
-
await this.vaultClient
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
790
|
+
const grantsByConsultLockbox = filter
|
791
|
+
? await this.vaultClient
|
792
|
+
.vaultIndexGet([IndexKey.ConsultationLockbox], [filter.consultationId])
|
793
|
+
.then((res) => res[IndexKey.ConsultationLockbox])
|
794
|
+
.catch((e) => {
|
795
|
+
console.error(e)
|
796
|
+
return []
|
797
|
+
})
|
798
|
+
: undefined
|
796
799
|
const decryptedConsults = decryptConsultLockboxGrants(grantsByConsultLockbox ?? [], this.rsa)
|
797
800
|
if (decryptedConsults.length > 0) {
|
798
801
|
console.info('[sdk:index] Grants found in user`s constant time secure index')
|
@@ -27,7 +27,7 @@ import {
|
|
27
27
|
identificationToPersonalInformations,
|
28
28
|
OroClient,
|
29
29
|
RegisterPatientOutput,
|
30
|
-
toActualObject
|
30
|
+
toActualObject,
|
31
31
|
} from '..'
|
32
32
|
|
33
33
|
const MAX_RETRIES = 15
|
@@ -50,6 +50,7 @@ const MAX_RETRIES = 15
|
|
50
50
|
* @param oroClient
|
51
51
|
* @param masterKey
|
52
52
|
* @param recoveryQA
|
53
|
+
* @param indexSearch create search index for the consultation if true
|
53
54
|
* @returns the successful registration
|
54
55
|
*/
|
55
56
|
export async function registerPatient(
|
@@ -61,7 +62,8 @@ export async function registerPatient(
|
|
61
62
|
recoveryQA?: {
|
62
63
|
recoverySecurityQuestions: string[]
|
63
64
|
recoverySecurityAnswers: string[]
|
64
|
-
}
|
65
|
+
},
|
66
|
+
indexSearch: boolean = true
|
65
67
|
): Promise<RegisterPatientOutput> {
|
66
68
|
let consult: Consult | undefined = undefined
|
67
69
|
let lockboxUuid: Uuid | undefined = undefined
|
@@ -95,8 +97,7 @@ export async function registerPatient(
|
|
95
97
|
// Creating lockbox
|
96
98
|
if (!lockboxUuid) lockboxUuid = await getOrCreatePatientLockbox(oroClient)
|
97
99
|
|
98
|
-
if (!identity)
|
99
|
-
identity = await oroClient.guardClient.identityGet(patientUuid)
|
100
|
+
if (!identity) identity = await oroClient.guardClient.identityGet(patientUuid)
|
100
101
|
|
101
102
|
await oroClient.grantLockbox(practitionerAdmin, lockboxUuid).catch((err) => {
|
102
103
|
console.error(`Error while granting lockbox to practitioner admin ${practitionerAdmin}`, err)
|
@@ -131,14 +132,16 @@ export async function registerPatient(
|
|
131
132
|
// the index will identify in which lockbox a consultation resides
|
132
133
|
let consultIndexPromises = practitioners.map(async (practitioner) => {
|
133
134
|
return oroClient.vaultIndexAdd(consultIndex, practitioner.uuid).catch((err) => {
|
134
|
-
console.error(
|
135
|
+
console.error(
|
136
|
+
`[SDK: registration] Error while adding to the practitioner's index ${practitioner.uuid}`,
|
137
|
+
err
|
138
|
+
)
|
135
139
|
// Acceptable to continue as the index can be rebuilt, but we should still retry until the last retry remains
|
136
140
|
if (retry <= 1) return
|
137
141
|
else errorsThrown.push(err)
|
138
142
|
})
|
139
143
|
})
|
140
144
|
|
141
|
-
|
142
145
|
await storeImageAliases(consult.uuid, lockboxUuid, workflow, oroClient).catch((err) => {
|
143
146
|
console.error('[SDK: registration] Some errors happened during image upload', err)
|
144
147
|
// Acceptable to continue as images can be requested during the consultation, but we should still retry until the last retry remains
|
@@ -146,13 +149,19 @@ export async function registerPatient(
|
|
146
149
|
else errorsThrown.push(err)
|
147
150
|
})
|
148
151
|
|
149
|
-
await storePatientData(
|
152
|
+
await storePatientData(
|
153
|
+
consult.uuid,
|
154
|
+
consultRequest.isoLanguageRequired,
|
155
|
+
lockboxUuid,
|
156
|
+
workflow,
|
157
|
+
oroClient
|
158
|
+
).catch((err) => {
|
150
159
|
console.error('[SDK: registration] Some errors happened during patient data upload', err)
|
151
160
|
errorsThrown.push(err)
|
152
161
|
})
|
153
162
|
|
154
163
|
if (masterKey && !identity?.recoveryMasterKey) {
|
155
|
-
// generate and store recovery payload and updates the identity
|
164
|
+
// generate and store recovery payload and updates the identity
|
156
165
|
identity = await oroClient.updateMasterKey(patientUuid, masterKey, lockboxUuid).catch((err) => {
|
157
166
|
console.error(`[SDK: registration] Error while updating master key`, err)
|
158
167
|
/// it's acceptable to continue registration (return old identity)
|
@@ -166,7 +175,7 @@ export async function registerPatient(
|
|
166
175
|
}
|
167
176
|
|
168
177
|
if (recoveryQA && !identity?.recoverySecurityQuestions)
|
169
|
-
// Patient security question recovery threshold is 2 answers and updates the identity
|
178
|
+
// Patient security question recovery threshold is 2 answers and updates the identity
|
170
179
|
identity = await oroClient
|
171
180
|
.updateSecurityQuestions(
|
172
181
|
patientUuid,
|
@@ -184,15 +193,19 @@ export async function registerPatient(
|
|
184
193
|
|
185
194
|
await Promise.all([...grantPromises, ...consultIndexPromises])
|
186
195
|
|
187
|
-
// TODO: uncomment when search is deployed in prod
|
188
|
-
// await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {
|
189
|
-
// console.error('[SDK: registration] personal information not found or another error occured during search indexing', err)
|
190
|
-
// if(retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry
|
191
|
-
// errorsThrown.push(err)
|
192
|
-
// })
|
193
196
|
|
194
|
-
if
|
195
|
-
|
197
|
+
if(indexSearch) {
|
198
|
+
await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {
|
199
|
+
console.error(
|
200
|
+
'[SDK: registration] personal information not found or another error occured during search indexing',
|
201
|
+
err
|
202
|
+
)
|
203
|
+
if (retry <= 1) return // this statement is to avoid failing the registration due to the failure in search indexing the consult, this practically implements a soft retry
|
204
|
+
errorsThrown.push(err)
|
205
|
+
})
|
206
|
+
}
|
207
|
+
|
208
|
+
if (errorsThrown.length > 0) throw errorsThrown
|
196
209
|
|
197
210
|
// Deem the consultation as ready
|
198
211
|
await oroClient.consultClient.updateConsultByUUID(consult.uuid, {
|
@@ -417,14 +430,14 @@ export async function extractAndStorePersonalWorkflowData(
|
|
417
430
|
* @param workflow
|
418
431
|
*/
|
419
432
|
export async function extractPersonalInfoFromWorkflowData(workflow: WorkflowData): Promise<{
|
420
|
-
personalInfoPopulatedWfData: PopulatedWorkflowData
|
421
|
-
childPersonalInfoPopulatedWfData: PopulatedWorkflowData
|
422
|
-
otherPersonalInfoPopulatedWfData: PopulatedWorkflowData
|
433
|
+
personalInfoPopulatedWfData: PopulatedWorkflowData
|
434
|
+
childPersonalInfoPopulatedWfData: PopulatedWorkflowData
|
435
|
+
otherPersonalInfoPopulatedWfData: PopulatedWorkflowData
|
423
436
|
}> {
|
424
437
|
return Promise.all([
|
425
438
|
getWorkflowDataByCategory(workflow, MetadataCategory.Personal),
|
426
439
|
getWorkflowDataByCategory(workflow, MetadataCategory.ChildPersonal),
|
427
|
-
getWorkflowDataByCategory(workflow, MetadataCategory.OtherPersonal)
|
440
|
+
getWorkflowDataByCategory(workflow, MetadataCategory.OtherPersonal),
|
428
441
|
]).then(([personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData]) => {
|
429
442
|
return {
|
430
443
|
personalInfoPopulatedWfData,
|
@@ -442,17 +455,14 @@ export async function extractPersonalInfoFromWorkflowData(workflow: WorkflowData
|
|
442
455
|
*/
|
443
456
|
export async function buildConsultSearchIndex(consult: Consult, workflow: WorkflowData, oroClient: OroClient) {
|
444
457
|
let terms: Terms = [
|
445
|
-
<Term>
|
458
|
+
<Term>{
|
446
459
|
kind: 'consult-shortid',
|
447
|
-
value: consult.shortId
|
448
|
-
}
|
460
|
+
value: consult.shortId,
|
461
|
+
},
|
449
462
|
]
|
450
463
|
|
451
|
-
const {
|
452
|
-
|
453
|
-
childPersonalInfoPopulatedWfData,
|
454
|
-
otherPersonalInfoPopulatedWfData
|
455
|
-
} = await extractPersonalInfoFromWorkflowData(workflow)
|
464
|
+
const { personalInfoPopulatedWfData, childPersonalInfoPopulatedWfData, otherPersonalInfoPopulatedWfData } =
|
465
|
+
await extractPersonalInfoFromWorkflowData(workflow)
|
456
466
|
|
457
467
|
const personalInfo = identificationToPersonalInformations(
|
458
468
|
toActualObject(personalInfoPopulatedWfData),
|
@@ -467,32 +477,41 @@ export async function buildConsultSearchIndex(consult: Consult, workflow: Workfl
|
|
467
477
|
MetadataCategory.OtherPersonal
|
468
478
|
)
|
469
479
|
|
470
|
-
terms.push(
|
471
|
-
|
472
|
-
value: personalInfo.firstname,
|
473
|
-
}, <Term> {
|
474
|
-
kind: 'last-name',
|
475
|
-
value: personalInfo.name
|
476
|
-
})
|
477
|
-
|
478
|
-
if(childPersonalInfo.firstname && childPersonalInfo.name) {
|
479
|
-
terms.push(<Term>{
|
480
|
+
terms.push(
|
481
|
+
<Term>{
|
480
482
|
kind: 'first-name',
|
481
|
-
value:
|
482
|
-
},
|
483
|
+
value: personalInfo.firstname,
|
484
|
+
},
|
485
|
+
<Term>{
|
483
486
|
kind: 'last-name',
|
484
|
-
value:
|
485
|
-
}
|
487
|
+
value: personalInfo.name,
|
488
|
+
}
|
489
|
+
)
|
490
|
+
|
491
|
+
if (childPersonalInfo.firstname && childPersonalInfo.name) {
|
492
|
+
terms.push(
|
493
|
+
<Term>{
|
494
|
+
kind: 'first-name',
|
495
|
+
value: childPersonalInfo.firstname,
|
496
|
+
},
|
497
|
+
<Term>{
|
498
|
+
kind: 'last-name',
|
499
|
+
value: childPersonalInfo.name,
|
500
|
+
}
|
501
|
+
)
|
486
502
|
}
|
487
503
|
|
488
|
-
if(otherPersonalInfo.firstname && otherPersonalInfo.name) {
|
489
|
-
terms.push(
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
504
|
+
if (otherPersonalInfo.firstname && otherPersonalInfo.name) {
|
505
|
+
terms.push(
|
506
|
+
<Term>{
|
507
|
+
kind: 'first-name',
|
508
|
+
value: otherPersonalInfo.firstname,
|
509
|
+
},
|
510
|
+
<Term>{
|
511
|
+
kind: 'last-name',
|
512
|
+
value: otherPersonalInfo.name,
|
513
|
+
}
|
514
|
+
)
|
496
515
|
}
|
497
516
|
|
498
517
|
await oroClient.searchClient.index(consult.uuid, terms)
|