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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.0.1",
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.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(patientUuid, consult, workflow, this, this.toolbox.uuid(), recoveryQA, indexSearch, onProgress)
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
- uuid: e.uuid,
382
- timestamp: e.timestamp,
383
- uniqueHash: e.uniqueHash,
384
- encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
385
- {
386
- consultationId: e.consultationId,
387
- grant: e.grant,
388
- },
389
- rsaPub
390
- ),
391
- } as EncryptedIndexEntry)
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 = Meta>(
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
- return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)
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 = Metadata>(
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 = Meta>(
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
- return this.tellerClient.lockboxDataStore(lockboxUuid, request, lockboxOwnerUuid, previousDataUuid)
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 ([OtherRoleType.Patient, OtherRoleType.User].every(requiredRole => currentAccountRole.includes(requiredRole))) {
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?: (progress: number, descriptionKey: string, extraInfo?: { storedImagesNum?: number, totalImagesNum?: number }) => void
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((currentStep++)/stepsTotalNum, 'retrieve_practitioners')
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((currentStep++)/stepsTotalNum, 'create_consult')
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((currentStep++)/stepsTotalNum, 'create_lockbox')
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((currentStep++)/stepsTotalNum, 'grant_patient')
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
- onProgress,
167
- currentStep,
168
- stepsTotalNum
169
- } : undefined
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((currentStep++)/stepsTotalNum, 'store_patient_data')
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((currentStep++)/stepsTotalNum, 'set_masterkey')
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((currentStep++)/stepsTotalNum, 'set_security_questions')
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((currentStep++)/stepsTotalNum, 'success')
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
- await oroClient.vaultClient.lockboxCreate().catch((err) => {
311
- console.error('Error while creating lockbox', err)
312
- throw err
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: (progress: number, descriptionKey: string, extraInfo?: { storedImagesNum?: number; totalImagesNum?: number }) => void;
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', {storedImagesNum, totalImagesNum})
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.getOrInsertJsonData<ConsultationImageMeta>(
435
- lockboxUuid,
436
- image,
437
- {
438
- category: MetadataCategory.Consultation,
439
- documentType: DocumentType.ImageAlias,
440
- consultationId,
441
- idbId: image.idbId as string,
442
- },
443
- {}
444
- ).then(() => {
445
- if (progress) {
446
- ++storedImagesNum
447
- let progressStepValue = Math.round((((progress.currentStep + 1)/progress.stepsTotalNum) - (progress.currentStep/progress.stepsTotalNum)) * 100) / 100
448
- progress.onProgress(
449
- (progress.currentStep/progress.stepsTotalNum) + (progressStepValue * (storedImagesNum/totalImagesNum)),
450
- 'store_images',
451
- {
452
- storedImagesNum,
453
- totalImagesNum
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
+ }