oro-sdk 5.0.1 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -0
- package/dist/client.d.ts +11 -7
- package/dist/oro-sdk.cjs.development.js +122 -86
- 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 +122 -86
- package/dist/oro-sdk.esm.js.map +1 -1
- package/package.json +3 -3
- package/src/client.ts +57 -34
- package/src/helpers/patient-registration.ts +72 -52
package/package.json
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"version": "5.0
|
2
|
+
"version": "5.1.0",
|
3
3
|
"main": "dist/index.js",
|
4
4
|
"typings": "dist/index.d.ts",
|
5
5
|
"files": [
|
@@ -55,8 +55,8 @@
|
|
55
55
|
"form-data": "^4.0.0",
|
56
56
|
"formdata-node": "^4.3.1",
|
57
57
|
"idb-keyval": "^5.0.6",
|
58
|
-
"oro-sdk-apis": "3.0.
|
58
|
+
"oro-sdk-apis": "3.0.1",
|
59
59
|
"oro-toolbox": "0.0.6",
|
60
60
|
"uuid": "^8.3.2"
|
61
61
|
}
|
62
|
-
}
|
62
|
+
}
|
package/src/client.ts
CHANGED
@@ -88,7 +88,7 @@ export class OroClient {
|
|
88
88
|
public workflowClient: WorkflowService,
|
89
89
|
public diagnosisClient: DiagnosisService,
|
90
90
|
private authenticationCallback?: (err: Error) => void
|
91
|
-
) {
|
91
|
+
) {}
|
92
92
|
|
93
93
|
/**
|
94
94
|
* clears the vaultIndex and cached metadata grants
|
@@ -300,7 +300,16 @@ export class OroClient {
|
|
300
300
|
onProgress?: (progress: number, descriptionKey: string) => void
|
301
301
|
): Promise<RegisterPatientOutput> {
|
302
302
|
if (!this.rsa) throw IncompleteAuthentication
|
303
|
-
return registerPatient(
|
303
|
+
return registerPatient(
|
304
|
+
patientUuid,
|
305
|
+
consult,
|
306
|
+
workflow,
|
307
|
+
this,
|
308
|
+
this.toolbox.uuid(),
|
309
|
+
recoveryQA,
|
310
|
+
indexSearch,
|
311
|
+
onProgress
|
312
|
+
)
|
304
313
|
}
|
305
314
|
|
306
315
|
/**
|
@@ -377,18 +386,18 @@ export class OroClient {
|
|
377
386
|
}))
|
378
387
|
.map(
|
379
388
|
(e: IndexConsultLockbox) =>
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
389
|
+
({
|
390
|
+
uuid: e.uuid,
|
391
|
+
timestamp: e.timestamp,
|
392
|
+
uniqueHash: e.uniqueHash,
|
393
|
+
encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
|
394
|
+
{
|
395
|
+
consultationId: e.consultationId,
|
396
|
+
grant: e.grant,
|
397
|
+
},
|
398
|
+
rsaPub
|
399
|
+
),
|
400
|
+
} as EncryptedIndexEntry)
|
392
401
|
)
|
393
402
|
break
|
394
403
|
}
|
@@ -513,6 +522,7 @@ export class OroClient {
|
|
513
522
|
* @param category the category for the attachment data
|
514
523
|
* @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)
|
515
524
|
* @param previousDataUuid if it's a revision of existing file, specify the previous data uuid
|
525
|
+
* @param withNotification if the insertion of data requires notification
|
516
526
|
* @returns the data uuid
|
517
527
|
*/
|
518
528
|
public async createConsultationAttachmentData(
|
@@ -521,7 +531,8 @@ export class OroClient {
|
|
521
531
|
consultationId: string,
|
522
532
|
documentType: DocumentType,
|
523
533
|
lockboxOwnerUuid?: Uuid,
|
524
|
-
previousDataUuid?: Uuid
|
534
|
+
previousDataUuid?: Uuid,
|
535
|
+
withNotification: boolean = false
|
525
536
|
): Promise<DataCreateResponse> {
|
526
537
|
if (!this.rsa) throw IncompleteAuthentication
|
527
538
|
|
@@ -539,7 +550,8 @@ export class OroClient {
|
|
539
550
|
fileName: data.name,
|
540
551
|
},
|
541
552
|
lockboxOwnerUuid,
|
542
|
-
previousDataUuid
|
553
|
+
previousDataUuid,
|
554
|
+
withNotification
|
543
555
|
)
|
544
556
|
}
|
545
557
|
|
@@ -552,15 +564,17 @@ export class OroClient {
|
|
552
564
|
* @param privateMeta the metadata that will be secured in the vault
|
553
565
|
* @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)
|
554
566
|
* @param previousDataUuid if it's a revision of existing data, specify the previous data uuid
|
567
|
+
* @param withNotification if the insertion of data requires notification
|
555
568
|
* @returns the data uuid
|
556
569
|
*/
|
557
|
-
public async createJsonData<T
|
570
|
+
public async createJsonData<T extends Metadata>(
|
558
571
|
lockboxUuid: Uuid,
|
559
572
|
data: any,
|
560
573
|
meta?: T,
|
561
574
|
privateMeta?: { [val: string]: any },
|
562
575
|
lockboxOwnerUuid?: Uuid,
|
563
|
-
previousDataUuid?: Uuid
|
576
|
+
previousDataUuid?: Uuid,
|
577
|
+
withNotification: boolean = false
|
564
578
|
): Promise<DataCreateResponse> {
|
565
579
|
if (!this.rsa) throw IncompleteAuthentication
|
566
580
|
|
@@ -573,8 +587,9 @@ export class OroClient {
|
|
573
587
|
publicMetadata: meta,
|
574
588
|
privateMetadata: encryptedPrivateMeta,
|
575
589
|
}
|
576
|
-
|
577
|
-
|
590
|
+
if (withNotification)
|
591
|
+
return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)
|
592
|
+
else return this.vaultClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)
|
578
593
|
}
|
579
594
|
|
580
595
|
/**
|
@@ -584,14 +599,16 @@ export class OroClient {
|
|
584
599
|
* @param publicMetadata the public Metadata
|
585
600
|
* @param privateMetadata the private Metadata
|
586
601
|
* @param forceReplace set true when the insertion of data requires to replace the data when it exists already
|
602
|
+
* @param withNotification if the insertion of data requires notification
|
587
603
|
* @returns the data uuid
|
588
604
|
*/
|
589
|
-
public async getOrInsertJsonData<M
|
605
|
+
public async getOrInsertJsonData<M extends Metadata>(
|
590
606
|
lockboxUuid: Uuid,
|
591
607
|
data: any,
|
592
608
|
publicMetadata: M,
|
593
609
|
privateMetadata: Metadata,
|
594
|
-
forceReplace: boolean = false
|
610
|
+
forceReplace: boolean = false,
|
611
|
+
withNotification: boolean = false
|
595
612
|
): Promise<Uuid> {
|
596
613
|
let manifest = await this.vaultClient.lockboxManifestGet(lockboxUuid, publicMetadata)
|
597
614
|
if (!forceReplace && manifest.length > 0) {
|
@@ -605,7 +622,8 @@ export class OroClient {
|
|
605
622
|
publicMetadata,
|
606
623
|
privateMetadata,
|
607
624
|
undefined,
|
608
|
-
forceReplace && manifest.length > 0 ? manifest[0].dataUuid : undefined // if forceReplace and data already exist, then replace data. Otherwise insert it
|
625
|
+
forceReplace && manifest.length > 0 ? manifest[0].dataUuid : undefined, // if forceReplace and data already exist, then replace data. Otherwise insert it
|
626
|
+
withNotification
|
609
627
|
).catch((err) => {
|
610
628
|
console.error(`Error while upserting data ${JSON.stringify(publicMetadata)} data`, err)
|
611
629
|
throw err
|
@@ -622,15 +640,17 @@ export class OroClient {
|
|
622
640
|
* @param privateMeta the metadata that will be secured in the vault
|
623
641
|
* @param lockboxOwnerUuid the lockbox owner (ignored if lockbox is owned by self)
|
624
642
|
* @param previousDataUuid if it's a revision of existing data, specify the previous data uuid
|
643
|
+
* @param withNotification if the insertion of data requires notification
|
625
644
|
* @returns the data uuid
|
626
645
|
*/
|
627
|
-
public async createBytesData<T
|
646
|
+
public async createBytesData<T extends Metadata>(
|
628
647
|
lockboxUuid: Uuid,
|
629
648
|
data: Uint8Array,
|
630
649
|
meta: T,
|
631
650
|
privateMeta: { [val: string]: any },
|
632
651
|
lockboxOwnerUuid?: Uuid,
|
633
|
-
previousDataUuid?: Uuid
|
652
|
+
previousDataUuid?: Uuid,
|
653
|
+
withNotification: boolean = false
|
634
654
|
): Promise<DataCreateResponse> {
|
635
655
|
if (!this.rsa) throw IncompleteAuthentication
|
636
656
|
let symmetricEncryptor = await this.getCachedSecretCryptor(lockboxUuid, lockboxOwnerUuid)
|
@@ -642,8 +662,9 @@ export class OroClient {
|
|
642
662
|
publicMetadata: meta,
|
643
663
|
privateMetadata: encryptedPrivateMeta,
|
644
664
|
}
|
645
|
-
|
646
|
-
|
665
|
+
if (withNotification)
|
666
|
+
return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)
|
667
|
+
else return this.vaultClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)
|
647
668
|
}
|
648
669
|
|
649
670
|
/**
|
@@ -704,10 +725,13 @@ export class OroClient {
|
|
704
725
|
|
705
726
|
// We're using the account role to determine the way a grant is accessed
|
706
727
|
let currentAccountRole = await this.getAccountRole()
|
707
|
-
if (currentAccountRole.length === 1 && currentAccountRole[0] === OtherRoleType.User)
|
708
|
-
return []
|
728
|
+
if (currentAccountRole.length === 1 && currentAccountRole[0] === OtherRoleType.User) return []
|
709
729
|
|
710
|
-
if (
|
730
|
+
if (
|
731
|
+
[OtherRoleType.Patient, OtherRoleType.User].every((requiredRole) =>
|
732
|
+
currentAccountRole.includes(requiredRole)
|
733
|
+
)
|
734
|
+
) {
|
711
735
|
let encryptedGrants
|
712
736
|
// if there are no grants with the applied filter from index, attempt for naive filter with backwards compatibility
|
713
737
|
if (filter) {
|
@@ -722,8 +746,7 @@ export class OroClient {
|
|
722
746
|
return decryptedGrants
|
723
747
|
}
|
724
748
|
// if not a patient, then a practitioner is trying to retrieve a grant, it **Must** contain a filter, otherwise too many grants are possible
|
725
|
-
if (!filter)
|
726
|
-
throw MissingGrantFilter
|
749
|
+
if (!filter) throw MissingGrantFilter
|
727
750
|
// Note: will work only if the filter being applied is exclusively a consult id
|
728
751
|
const grantsByConsultLockbox = await this.vaultClient
|
729
752
|
.vaultIndexGet([IndexKey.ConsultationLockbox], [filter.consultationId])
|
@@ -746,7 +769,7 @@ export class OroClient {
|
|
746
769
|
|
747
770
|
/**
|
748
771
|
* Fetches the role of the account that is logged in
|
749
|
-
*
|
772
|
+
*
|
750
773
|
* @returns the role based scopes defined by the whoami
|
751
774
|
*/
|
752
775
|
async getAccountRole(): Promise<RoleBasedScopes[]> {
|
@@ -1515,4 +1538,4 @@ export class OroClient {
|
|
1515
1538
|
|
1516
1539
|
return updatedIdentity
|
1517
1540
|
}
|
1518
|
-
}
|
1541
|
+
}
|
@@ -65,7 +65,11 @@ export async function registerPatient(
|
|
65
65
|
recoverySecurityAnswers: string[]
|
66
66
|
},
|
67
67
|
indexSearch: boolean = true,
|
68
|
-
onProgress?: (
|
68
|
+
onProgress?: (
|
69
|
+
progress: number,
|
70
|
+
descriptionKey: string,
|
71
|
+
extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }
|
72
|
+
) => void
|
69
73
|
): Promise<RegisterPatientOutput> {
|
70
74
|
let consult: Consult | undefined = undefined
|
71
75
|
let lockboxUuid: Uuid | undefined = undefined
|
@@ -80,8 +84,7 @@ export async function registerPatient(
|
|
80
84
|
try {
|
81
85
|
currentStep = 0
|
82
86
|
|
83
|
-
if (onProgress) onProgress(
|
84
|
-
|
87
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'retrieve_practitioners')
|
85
88
|
|
86
89
|
// Wait a bit each retry (we also want the first one to wait)
|
87
90
|
await new Promise((resolve) => setTimeout(resolve, 2000))
|
@@ -99,14 +102,14 @@ export async function registerPatient(
|
|
99
102
|
})
|
100
103
|
|
101
104
|
// Creating consult
|
102
|
-
if (onProgress) onProgress(
|
105
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_consult')
|
103
106
|
|
104
107
|
if (!consult) {
|
105
108
|
consult = await getOrCreatePatientConsultationUuid(consultRequest, oroClient)
|
106
109
|
}
|
107
110
|
|
108
111
|
// Creating lockbox
|
109
|
-
if (onProgress) onProgress(
|
112
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'create_lockbox')
|
110
113
|
|
111
114
|
if (!lockboxUuid) lockboxUuid = await getOrCreatePatientLockbox(oroClient)
|
112
115
|
|
@@ -119,7 +122,7 @@ export async function registerPatient(
|
|
119
122
|
})
|
120
123
|
|
121
124
|
// Patient Grant to practice
|
122
|
-
if (onProgress) onProgress(
|
125
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'grant_patient')
|
123
126
|
|
124
127
|
let grantPromises = practitioners
|
125
128
|
.filter((practitioner) => practitioner.uuid !== practitionerAdmin)
|
@@ -162,11 +165,13 @@ export async function registerPatient(
|
|
162
165
|
lockboxUuid,
|
163
166
|
workflow,
|
164
167
|
oroClient,
|
165
|
-
onProgress
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
168
|
+
onProgress
|
169
|
+
? {
|
170
|
+
onProgress,
|
171
|
+
currentStep,
|
172
|
+
stepsTotalNum,
|
173
|
+
}
|
174
|
+
: undefined
|
170
175
|
).catch((err) => {
|
171
176
|
console.error('[SDK: registration] Some errors happened during image upload', err)
|
172
177
|
// Acceptable to continue as images can be requested during the consultation, but we should still retry until the last retry remains
|
@@ -175,7 +180,7 @@ export async function registerPatient(
|
|
175
180
|
})
|
176
181
|
++currentStep
|
177
182
|
|
178
|
-
if (onProgress) onProgress(
|
183
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'store_patient_data')
|
179
184
|
|
180
185
|
await storePatientData(
|
181
186
|
consult.uuid,
|
@@ -188,7 +193,7 @@ export async function registerPatient(
|
|
188
193
|
errorsThrown.push(err)
|
189
194
|
})
|
190
195
|
|
191
|
-
if (onProgress) onProgress(
|
196
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_masterkey')
|
192
197
|
|
193
198
|
if (masterKey && !identity?.recoveryMasterKey) {
|
194
199
|
// generate and store recovery payload and updates the identity
|
@@ -204,7 +209,7 @@ export async function registerPatient(
|
|
204
209
|
masterKey = undefined
|
205
210
|
}
|
206
211
|
|
207
|
-
if (onProgress) onProgress(
|
212
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'set_security_questions')
|
208
213
|
|
209
214
|
if (recoveryQA && !identity?.recoverySecurityQuestions)
|
210
215
|
// Patient security question recovery threshold is 2 answers and updates the identity
|
@@ -225,8 +230,7 @@ export async function registerPatient(
|
|
225
230
|
|
226
231
|
await Promise.all([...grantPromises, ...consultIndexPromises])
|
227
232
|
|
228
|
-
|
229
|
-
if (onProgress) onProgress((currentStep++)/stepsTotalNum, 'search_indexing')
|
233
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'search_indexing')
|
230
234
|
|
231
235
|
if (indexSearch) {
|
232
236
|
await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {
|
@@ -247,7 +251,7 @@ export async function registerPatient(
|
|
247
251
|
})
|
248
252
|
|
249
253
|
// if we got through the complete flow, the registration succeeded
|
250
|
-
if (onProgress) onProgress(
|
254
|
+
if (onProgress) onProgress(currentStep++ / stepsTotalNum, 'success')
|
251
255
|
|
252
256
|
break
|
253
257
|
} catch (err) {
|
@@ -306,11 +310,10 @@ async function getOrCreatePatientLockbox(oroClient: OroClient): Promise<Uuid> {
|
|
306
310
|
console.log('The grant has already been created, skipping lockbox create step')
|
307
311
|
return grants[0].lockboxUuid!
|
308
312
|
} else {
|
309
|
-
let lockboxResponse =
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
})
|
313
|
+
let lockboxResponse = await oroClient.vaultClient.lockboxCreate().catch((err) => {
|
314
|
+
console.error('Error while creating lockbox', err)
|
315
|
+
throw err
|
316
|
+
})
|
314
317
|
// Since the creation of a lockbox will change the scope of a user, we will force refresh the tokens
|
315
318
|
let tokens = await oroClient.guardClient.authRefresh()
|
316
319
|
await oroClient.guardClient.setTokens({ accessToken: tokens.accessToken, refreshToken: tokens.refreshToken })
|
@@ -358,7 +361,9 @@ async function storePatientData(
|
|
358
361
|
documentType: DocumentType.PopulatedWorkflowData,
|
359
362
|
consultationId, // TODO: deprecated. Will finally only be in privateMetadata
|
360
363
|
},
|
361
|
-
{ consultationId }
|
364
|
+
{ consultationId },
|
365
|
+
false,
|
366
|
+
true // the only data that needs to include an email notification
|
362
367
|
)
|
363
368
|
),
|
364
369
|
getWorkflowDataByCategory(workflow, MetadataCategory.Medical).then((data) =>
|
@@ -412,9 +417,13 @@ async function storeImageAliases(
|
|
412
417
|
workflow: WorkflowData,
|
413
418
|
oroClient: OroClient,
|
414
419
|
progress?: {
|
415
|
-
currentStep: number
|
416
|
-
stepsTotalNum: number
|
417
|
-
onProgress: (
|
420
|
+
currentStep: number
|
421
|
+
stepsTotalNum: number
|
422
|
+
onProgress: (
|
423
|
+
progress: number,
|
424
|
+
descriptionKey: string,
|
425
|
+
extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }
|
426
|
+
) => void
|
418
427
|
}
|
419
428
|
): Promise<(Uuid | void)[]> {
|
420
429
|
const images = await getImagesFromIndexDb((await filterTriggeredAnsweredWithKind(workflow, 'images-alias')).flat())
|
@@ -428,33 +437,44 @@ async function storeImageAliases(
|
|
428
437
|
let storedImagesNum = 0
|
429
438
|
let totalImagesNum = nonNullImages.length
|
430
439
|
if (progress)
|
431
|
-
progress.onProgress(progress.currentStep/progress.stepsTotalNum, 'store_images', {
|
440
|
+
progress.onProgress(progress.currentStep / progress.stepsTotalNum, 'store_images', {
|
441
|
+
storedImagesNum,
|
442
|
+
totalImagesNum,
|
443
|
+
})
|
432
444
|
|
433
445
|
let promises = nonNullImages.map((image) => {
|
434
|
-
return oroClient
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
446
|
+
return oroClient
|
447
|
+
.getOrInsertJsonData<ConsultationImageMeta>(
|
448
|
+
lockboxUuid,
|
449
|
+
image,
|
450
|
+
{
|
451
|
+
category: MetadataCategory.Consultation,
|
452
|
+
documentType: DocumentType.ImageAlias,
|
453
|
+
consultationId,
|
454
|
+
idbId: image.idbId as string,
|
455
|
+
},
|
456
|
+
{}
|
457
|
+
)
|
458
|
+
.then(() => {
|
459
|
+
if (progress) {
|
460
|
+
++storedImagesNum
|
461
|
+
let progressStepValue =
|
462
|
+
Math.round(
|
463
|
+
((progress.currentStep + 1) / progress.stepsTotalNum -
|
464
|
+
progress.currentStep / progress.stepsTotalNum) *
|
465
|
+
100
|
466
|
+
) / 100
|
467
|
+
progress.onProgress(
|
468
|
+
progress.currentStep / progress.stepsTotalNum +
|
469
|
+
progressStepValue * (storedImagesNum / totalImagesNum),
|
470
|
+
'store_images',
|
471
|
+
{
|
472
|
+
storedImagesNum,
|
473
|
+
totalImagesNum,
|
474
|
+
}
|
475
|
+
)
|
476
|
+
}
|
477
|
+
})
|
458
478
|
})
|
459
479
|
return Promise.all(promises)
|
460
480
|
}
|
@@ -580,4 +600,4 @@ export async function buildConsultSearchIndex(consult: Consult, workflow: Workfl
|
|
580
600
|
}
|
581
601
|
|
582
602
|
await oroClient.searchClient.index(consult.uuid, terms)
|
583
|
-
}
|
603
|
+
}
|