oro-sdk 3.13.0 → 3.16.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 +9 -24
- package/dist/models/error.d.ts +2 -0
- package/dist/oro-sdk.cjs.development.js +723 -903
- 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 +724 -905
- package/dist/oro-sdk.esm.js.map +1 -1
- package/dist/sdk-revision/client.d.ts +6 -15
- package/package.json +2 -2
- package/src/client.ts +65 -134
- package/src/helpers/patient-registration.ts +2 -2
- package/src/models/error.ts +7 -6
- package/src/sdk-revision/client.ts +14 -52
@@ -1,21 +1,12 @@
|
|
1
|
-
import { Grant
|
1
|
+
import { Grant } from 'oro-sdk-apis';
|
2
2
|
import { OroClient, Uuid } from '..';
|
3
3
|
/**
|
4
4
|
* @name filterGrantsWithLockboxMetadata
|
5
|
-
* @description searches for the
|
5
|
+
* @description searches for the existance of a consult uuid in each granted lockbox
|
6
6
|
* @param oroClient
|
7
|
-
* @param filter: the
|
8
|
-
* @
|
9
|
-
* @param forceRefresh
|
10
|
-
* @returns the filtered grants
|
7
|
+
* @param filter: the consult uuid
|
8
|
+
* @returns the grants containing the consult uuid
|
11
9
|
*/
|
12
|
-
export declare function filterGrantsWithLockboxMetadata(oroClient: OroClient, filter
|
10
|
+
export declare function filterGrantsWithLockboxMetadata(oroClient: OroClient, filter: {
|
13
11
|
consultationId: Uuid;
|
14
|
-
}
|
15
|
-
/** Finds all grants for the logged user
|
16
|
-
* requests a list of unique consultation ids for each lockbox the user has access to
|
17
|
-
* builds and sets the index of consultations
|
18
|
-
* @param oroClient
|
19
|
-
* @returns the constructed vaultIndex
|
20
|
-
*/
|
21
|
-
export declare function buildLegacyVaultIndex(oroClient: OroClient): Promise<VaultIndex>;
|
12
|
+
}): Promise<Grant[]>;
|
package/package.json
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"version": "3.
|
2
|
+
"version": "3.16.0",
|
3
3
|
"main": "dist/index.js",
|
4
4
|
"typings": "dist/index.d.ts",
|
5
5
|
"files": [
|
@@ -54,7 +54,7 @@
|
|
54
54
|
"form-data": "^4.0.0",
|
55
55
|
"formdata-node": "^4.3.1",
|
56
56
|
"idb-keyval": "^5.0.6",
|
57
|
-
"oro-sdk-apis": "1.
|
57
|
+
"oro-sdk-apis": "1.50.0",
|
58
58
|
"oro-toolbox": "0.0.6",
|
59
59
|
"uuid": "^8.3.2"
|
60
60
|
}
|
package/src/client.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import {
|
2
|
+
AllRoleType,
|
2
3
|
AuthTokenRequest,
|
3
4
|
Consult,
|
4
5
|
ConsultRequest,
|
@@ -23,12 +24,15 @@ import {
|
|
23
24
|
Meta,
|
24
25
|
Metadata,
|
25
26
|
MetadataCategory,
|
27
|
+
OtherRoleType,
|
26
28
|
PersonalMeta,
|
27
29
|
PopulatedWorkflowData,
|
28
30
|
Practice,
|
29
31
|
PracticeService,
|
32
|
+
PractitionnerRoleType,
|
30
33
|
PreferenceMeta,
|
31
34
|
RecoveryMeta,
|
35
|
+
RoleBasedScopes,
|
32
36
|
SearchService,
|
33
37
|
SecretShard,
|
34
38
|
TellerService,
|
@@ -48,13 +52,14 @@ import {
|
|
48
52
|
IncompleteAuthentication,
|
49
53
|
LocalEncryptedData,
|
50
54
|
MissingGrant,
|
55
|
+
MissingGrantFilter,
|
51
56
|
MissingLockbox,
|
52
57
|
MissingLockboxOwner,
|
53
58
|
RecoveryData,
|
54
59
|
RegisterPatientOutput,
|
55
60
|
UserPreference,
|
56
61
|
} from './models'
|
57
|
-
import {
|
62
|
+
import { filterGrantsWithLockboxMetadata } from './sdk-revision'
|
58
63
|
|
59
64
|
export class OroClient {
|
60
65
|
private rsa?: CryptoRSA
|
@@ -83,13 +88,12 @@ export class OroClient {
|
|
83
88
|
public workflowClient: WorkflowService,
|
84
89
|
public diagnosisClient: DiagnosisService,
|
85
90
|
private authenticationCallback?: (err: Error) => void
|
86
|
-
) {}
|
91
|
+
) { }
|
87
92
|
|
88
93
|
/**
|
89
94
|
* clears the vaultIndex and cached metadata grants
|
90
95
|
*/
|
91
96
|
public async cleanIndex() {
|
92
|
-
this.vaultIndex = undefined
|
93
97
|
this.cachedMetadataGrants = {}
|
94
98
|
this.cachedManifest = {}
|
95
99
|
}
|
@@ -297,28 +301,6 @@ export class OroClient {
|
|
297
301
|
return registerPatient(patientUuid, consult, workflow, this, this.toolbox.uuid(), recoveryQA, indexSearch)
|
298
302
|
}
|
299
303
|
|
300
|
-
/**
|
301
|
-
* Builds the vault index for the logged user
|
302
|
-
*
|
303
|
-
* Steps:
|
304
|
-
* 1. Retrieves, decrypts and sets the lockbox IndexSnapshot
|
305
|
-
* 2. Retrieves, decrypts and adds all other index entries starting at the snapshot timestamp
|
306
|
-
* 3. Updates the IndexSnapshot if changed
|
307
|
-
* @deprecated
|
308
|
-
* @returns the latest vault index
|
309
|
-
*/
|
310
|
-
public async buildVaultIndex(forceRefresh: boolean = false) {
|
311
|
-
if (!this.vaultIndex || forceRefresh) await buildLegacyVaultIndex(this)
|
312
|
-
}
|
313
|
-
|
314
|
-
/**
|
315
|
-
* Setter for the vault index
|
316
|
-
* @param index
|
317
|
-
*/
|
318
|
-
public setVaultIndex(index: VaultIndex) {
|
319
|
-
this.vaultIndex = index
|
320
|
-
}
|
321
|
-
|
322
304
|
/**
|
323
305
|
* Fetches all grants, and consultations that exist in each lockbox
|
324
306
|
* Then updates the index for the current user with the lockbox consult relationship
|
@@ -393,91 +375,25 @@ export class OroClient {
|
|
393
375
|
}))
|
394
376
|
.map(
|
395
377
|
(e: IndexConsultLockbox) =>
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
378
|
+
({
|
379
|
+
uuid: e.uuid,
|
380
|
+
timestamp: e.timestamp,
|
381
|
+
uniqueHash: e.uniqueHash,
|
382
|
+
encryptedIndexEntry: CryptoRSA.jsonWithPubEncryptToBase64(
|
383
|
+
{
|
384
|
+
consultationId: e.consultationId,
|
385
|
+
grant: e.grant,
|
386
|
+
},
|
387
|
+
rsaPub
|
388
|
+
),
|
389
|
+
} as EncryptedIndexEntry)
|
408
390
|
)
|
409
391
|
break
|
410
|
-
//// DEPRECATED : REMOVE ME : BEGIN ///////////////////////////////////////////
|
411
|
-
case IndexKey.Consultation:
|
412
|
-
encryptedIndex[key] = (entries[key] as IndexConsultLockbox[])
|
413
|
-
.map((e) => ({
|
414
|
-
...e,
|
415
|
-
uniqueHash: this.toolbox.hashStringToBase64(
|
416
|
-
JSON.stringify({
|
417
|
-
consultationId: e.consultationId,
|
418
|
-
grant: e.grant,
|
419
|
-
})
|
420
|
-
),
|
421
|
-
}))
|
422
|
-
.filter(
|
423
|
-
(e) =>
|
424
|
-
!this.vaultIndex ||
|
425
|
-
!this.vaultIndex[IndexKey.Consultation]?.find((v) => v.uniqueHash === e.uniqueHash)
|
426
|
-
)
|
427
|
-
.map(
|
428
|
-
(e: IndexConsultLockbox) =>
|
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)
|
441
|
-
)
|
442
|
-
break
|
443
|
-
//// DEPRECATED : REMOVE ME : END ///////////////////////////////////////////
|
444
392
|
}
|
445
393
|
}
|
446
394
|
await this.vaultClient.vaultIndexPut(encryptedIndex, indexOwnerUuid)
|
447
395
|
}
|
448
396
|
|
449
|
-
/**
|
450
|
-
* adds or updates the index snapshot for the logged user
|
451
|
-
* @param index
|
452
|
-
*/
|
453
|
-
public async indexSnapshotAdd(index: VaultIndex) {
|
454
|
-
if (!this.rsa) throw IncompleteAuthentication
|
455
|
-
let rsaPub: Uint8Array = this.rsa.public()
|
456
|
-
|
457
|
-
let cleanedIndex: VaultIndex = {
|
458
|
-
[IndexKey.Consultation]: index[IndexKey.Consultation]
|
459
|
-
?.filter((c) => c)
|
460
|
-
.map((c) => {
|
461
|
-
return {
|
462
|
-
grant: c.grant,
|
463
|
-
consultationId: c.consultationId,
|
464
|
-
}
|
465
|
-
}),
|
466
|
-
}
|
467
|
-
|
468
|
-
// the data of the snapshot should not contain the `IndexEntry` data
|
469
|
-
// (will create conflicts while updating)
|
470
|
-
let encryptedIndexEntry = CryptoRSA.jsonWithPubEncryptToBase64(cleanedIndex, rsaPub)
|
471
|
-
|
472
|
-
// The encryptedIndexEntry can have the uuid and timstamp (for updating)
|
473
|
-
let encryptedIndex: EncryptedIndexEntry = {
|
474
|
-
uuid: index.uuid,
|
475
|
-
timestamp: index.timestamp,
|
476
|
-
encryptedIndexEntry,
|
477
|
-
}
|
478
|
-
this.vaultClient.vaultIndexSnapshotPut(encryptedIndex)
|
479
|
-
}
|
480
|
-
|
481
397
|
/**
|
482
398
|
* @name grantLockbox
|
483
399
|
* @description Grants a lockbox by retrieving the shared secret of the lockbox and encrypting it with the grantees public key
|
@@ -777,44 +693,60 @@ export class OroClient {
|
|
777
693
|
* @param filter: the consultationId in which the grant exists
|
778
694
|
* @returns decrypted lockboxes granted to user
|
779
695
|
*/
|
780
|
-
public async getGrants(filter?: { consultationId: Uuid }
|
696
|
+
public async getGrants(filter?: { consultationId: Uuid }): Promise<Grant[]> {
|
781
697
|
if (!this.rsa) throw IncompleteAuthentication
|
782
698
|
|
783
699
|
let filterString = JSON.stringify(filter)
|
784
700
|
// retrieves cached grants
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
701
|
+
if (this.cachedMetadataGrants[filterString]) return this.cachedMetadataGrants[filterString]
|
702
|
+
|
703
|
+
// We're using the account role to determine the way a grant is accessed
|
704
|
+
let currentAccountRole = await this.getAccountRole()
|
705
|
+
|
706
|
+
if ([OtherRoleType.Patient, OtherRoleType.User].every(requiredRole => currentAccountRole.includes(requiredRole))) {
|
707
|
+
let encryptedGrants
|
708
|
+
// if there are no grants with the applied filter from index, attempt for naive filter with backwards compatibility
|
709
|
+
if (filter) {
|
710
|
+
encryptedGrants = await filterGrantsWithLockboxMetadata(this, filter)
|
711
|
+
} else {
|
712
|
+
encryptedGrants = (await this.vaultClient.grantsGet()).grants
|
713
|
+
}
|
714
|
+
const decryptedGrants = await decryptGrants(encryptedGrants, this.rsa)
|
715
|
+
// sets the cached grant
|
716
|
+
this.cachedMetadataGrants[filterString] = decryptedGrants
|
717
|
+
console.info('[sdk:grant] Found grant for patient')
|
718
|
+
return decryptedGrants
|
719
|
+
}
|
720
|
+
// if not a patient, then a practitioner is trying to retrieve a grant, it **Must** contain a filter, otherwise too many grants are possible
|
721
|
+
if (!filter)
|
722
|
+
throw MissingGrantFilter
|
789
723
|
// Note: will work only if the filter being applied is exclusively a consult id
|
790
|
-
const grantsByConsultLockbox =
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
: undefined
|
724
|
+
const grantsByConsultLockbox = await this.vaultClient
|
725
|
+
.vaultIndexGet([IndexKey.ConsultationLockbox], [filter.consultationId])
|
726
|
+
.then((res) => res[IndexKey.ConsultationLockbox])
|
727
|
+
.catch((e) => {
|
728
|
+
console.error(e)
|
729
|
+
return []
|
730
|
+
})
|
731
|
+
|
799
732
|
const decryptedConsults = decryptConsultLockboxGrants(grantsByConsultLockbox ?? [], this.rsa)
|
800
733
|
if (decryptedConsults.length > 0) {
|
801
734
|
console.info('[sdk:index] Grants found in user`s constant time secure index')
|
802
|
-
this.cachedMetadataGrants[
|
735
|
+
this.cachedMetadataGrants[filterString] = decryptedConsults
|
803
736
|
return this.cachedMetadataGrants[filterString]
|
804
737
|
}
|
805
738
|
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
encryptedGrants = await filterGrantsWithLockboxMetadata(this, filter, this.vaultIndex, forceRefresh)
|
810
|
-
} else {
|
811
|
-
encryptedGrants = (await this.vaultClient.grantsGet()).grants
|
812
|
-
}
|
739
|
+
// if we have no valid grants, then return nothing
|
740
|
+
return []
|
741
|
+
}
|
813
742
|
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
743
|
+
/**
|
744
|
+
* Fetches the role of the account that is logged in
|
745
|
+
*
|
746
|
+
* @returns the role based scopes defined by the whoami
|
747
|
+
*/
|
748
|
+
async getAccountRole(): Promise<RoleBasedScopes[]> {
|
749
|
+
return (await this.guardClient.whoAmI()).scope.split(' ') as RoleBasedScopes[]
|
818
750
|
}
|
819
751
|
|
820
752
|
/**
|
@@ -1206,9 +1138,9 @@ export class OroClient {
|
|
1206
1138
|
* @param practiceUuid the uuid of the practice to look consult into
|
1207
1139
|
* @returns the list of consults
|
1208
1140
|
*/
|
1209
|
-
public async getAssignedConsultations(practiceUuid: Uuid
|
1141
|
+
public async getAssignedConsultations(practiceUuid: Uuid): Promise<Consult[]> {
|
1210
1142
|
return Promise.all(
|
1211
|
-
(await this.getGrants(
|
1143
|
+
(await this.getGrants()).map((grant) =>
|
1212
1144
|
this.getLockboxManifest(
|
1213
1145
|
grant.lockboxUuid!,
|
1214
1146
|
{
|
@@ -1216,8 +1148,7 @@ export class OroClient {
|
|
1216
1148
|
documentType: DocumentType.PopulatedWorkflowData,
|
1217
1149
|
},
|
1218
1150
|
true,
|
1219
|
-
undefined
|
1220
|
-
forceRefresh
|
1151
|
+
undefined
|
1221
1152
|
).then((manifest) =>
|
1222
1153
|
Promise.all(
|
1223
1154
|
manifest.map(
|
@@ -1278,7 +1209,7 @@ export class OroClient {
|
|
1278
1209
|
): Promise<PopulatedWorkflowData[]> {
|
1279
1210
|
//TODO: make use of getPatientDocumentsList instead of doing it manually here
|
1280
1211
|
return Promise.all(
|
1281
|
-
(await this.getGrants({ consultationId }
|
1212
|
+
(await this.getGrants({ consultationId }))
|
1282
1213
|
.map((grant) =>
|
1283
1214
|
this.getLockboxManifest(
|
1284
1215
|
grant.lockboxUuid!,
|
@@ -194,7 +194,7 @@ export async function registerPatient(
|
|
194
194
|
await Promise.all([...grantPromises, ...consultIndexPromises])
|
195
195
|
|
196
196
|
|
197
|
-
if(indexSearch) {
|
197
|
+
if (indexSearch) {
|
198
198
|
await buildConsultSearchIndex(consult, workflow, oroClient).catch((err) => {
|
199
199
|
console.error(
|
200
200
|
'[SDK: registration] personal information not found or another error occured during search indexing',
|
@@ -265,7 +265,7 @@ async function getOrCreatePatientConsultationUuid(consult: ConsultRequest, oroCl
|
|
265
265
|
* @returns the lockbox Uuid
|
266
266
|
*/
|
267
267
|
async function getOrCreatePatientLockbox(oroClient: OroClient): Promise<Uuid> {
|
268
|
-
let grants = await oroClient.getGrants(
|
268
|
+
let grants = await oroClient.getGrants()
|
269
269
|
if (grants.length > 0) {
|
270
270
|
console.log('The grant has already been created, skipping lockbox create step')
|
271
271
|
return grants[0].lockboxUuid!
|
package/src/models/error.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
export class IncompleteAuthentication extends Error {}
|
2
|
-
export class MissingGrant extends Error {}
|
3
|
-
export class
|
4
|
-
export class
|
5
|
-
export class
|
6
|
-
export class
|
1
|
+
export class IncompleteAuthentication extends Error { }
|
2
|
+
export class MissingGrant extends Error { }
|
3
|
+
export class MissingGrantFilter extends Error { }
|
4
|
+
export class MissingLockbox extends Error { }
|
5
|
+
export class MissingLockboxOwner extends Error { }
|
6
|
+
export class AssociatedLockboxNotFound extends Error { }
|
7
|
+
export class WorkflowAnswersMissingError extends Error { }
|
@@ -3,65 +3,27 @@ import { OroClient, Uuid } from '..'
|
|
3
3
|
|
4
4
|
/**
|
5
5
|
* @name filterGrantsWithLockboxMetadata
|
6
|
-
* @description searches for the
|
6
|
+
* @description searches for the existance of a consult uuid in each granted lockbox
|
7
7
|
* @param oroClient
|
8
|
-
* @param filter: the
|
9
|
-
* @
|
10
|
-
* @param forceRefresh
|
11
|
-
* @returns the filtered grants
|
8
|
+
* @param filter: the consult uuid
|
9
|
+
* @returns the grants containing the consult uuid
|
12
10
|
*/
|
13
11
|
export async function filterGrantsWithLockboxMetadata(
|
14
12
|
oroClient: OroClient,
|
15
|
-
filter
|
16
|
-
vaultIndex?: VaultIndex,
|
17
|
-
forceRefresh = false
|
13
|
+
filter: { consultationId: Uuid },
|
18
14
|
): Promise<Grant[]> {
|
19
|
-
if (!vaultIndex || forceRefresh) {
|
20
|
-
vaultIndex = await buildLegacyVaultIndex(oroClient)
|
21
|
-
}
|
22
|
-
if (vaultIndex[IndexKey.Consultation] && filter) {
|
23
|
-
let indexConsults = (vaultIndex[IndexKey.Consultation] ?? [])
|
24
|
-
.filter((consultGrant: { consultationId: Uuid }) => consultGrant.consultationId === filter.consultationId)
|
25
|
-
.map((consultGrant: { consultationId: Uuid; grant: Grant }) => consultGrant.grant as Grant)
|
26
|
-
return indexConsults as Grant[]
|
27
|
-
} else {
|
28
|
-
// No grants exist and the index has already been built
|
29
|
-
return []
|
30
|
-
}
|
31
|
-
}
|
32
|
-
|
33
|
-
/** Finds all grants for the logged user
|
34
|
-
* requests a list of unique consultation ids for each lockbox the user has access to
|
35
|
-
* builds and sets the index of consultations
|
36
|
-
* @param oroClient
|
37
|
-
* @returns the constructed vaultIndex
|
38
|
-
*/
|
39
|
-
export async function buildLegacyVaultIndex(oroClient: OroClient): Promise<VaultIndex> {
|
40
15
|
let grants = await oroClient.getGrants()
|
41
|
-
let
|
16
|
+
let filteredGrants = []
|
42
17
|
for (let grant of grants) {
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
...consults.map((consult: any) => ({
|
52
|
-
...consult,
|
53
|
-
grant: {
|
54
|
-
lockboxOwnerUuid: grant.lockboxOwnerUuid,
|
55
|
-
lockboxUuid: grant.lockboxUuid,
|
56
|
-
},
|
57
|
-
})),
|
58
|
-
]
|
18
|
+
// Fetches in each lockbox the existance of a given consult id
|
19
|
+
let consultationIdExistsInMetadata = await oroClient.vaultClient.lockboxMetadataGet(grant.lockboxUuid!, ['consultationId'], [], {
|
20
|
+
category: MetadataCategory.Consultation,
|
21
|
+
consultationId: filter.consultationId
|
22
|
+
})
|
23
|
+
// If there are entries in the metadata, it means that the consult exists in the lockbox
|
24
|
+
if (consultationIdExistsInMetadata[0].length >= 0)
|
25
|
+
filteredGrants.push(grant)
|
59
26
|
}
|
60
27
|
|
61
|
-
|
62
|
-
[IndexKey.Consultation]: consultGrants,
|
63
|
-
}
|
64
|
-
oroClient.setVaultIndex(vaultIndex)
|
65
|
-
console.info('[sdk:index] Successfully Built Vault Index')
|
66
|
-
return vaultIndex
|
28
|
+
return filteredGrants
|
67
29
|
}
|