oro-sdk 3.14.0 → 3.17.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/dist/client.d.ts +9 -24
- package/dist/models/error.d.ts +2 -0
- package/dist/oro-sdk.cjs.development.js +715 -897
- 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 +716 -899
- 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.17.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.51.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
|
}
|