oro-sdk-apis 1.13.0 → 1.16.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/helpers/hash.d.ts +6 -0
- package/dist/helpers/index.d.ts +2 -0
- package/dist/helpers/init.d.ts +9 -0
- package/dist/index.d.ts +2 -24
- package/dist/models/guard.d.ts +13 -1
- package/dist/models/index.d.ts +2 -0
- package/dist/models/init.d.ts +26 -0
- package/dist/models/practice.d.ts +13 -4
- package/dist/models/workflow.d.ts +3 -1
- package/dist/oro-sdk-apis.cjs.development.js +370 -124
- package/dist/oro-sdk-apis.cjs.development.js.map +1 -1
- package/dist/oro-sdk-apis.cjs.production.min.js +1 -1
- package/dist/oro-sdk-apis.cjs.production.min.js.map +1 -1
- package/dist/oro-sdk-apis.esm.js +368 -125
- package/dist/oro-sdk-apis.esm.js.map +1 -1
- package/dist/services/api.d.ts +9 -1
- package/dist/services/apisPracticeManager.d.ts +25 -0
- package/dist/services/guard.d.ts +8 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/practice.d.ts +2 -2
- package/dist/services/teller.d.ts +9 -0
- package/package.json +1 -1
- package/src/helpers/hash.ts +11 -0
- package/src/helpers/index.ts +2 -0
- package/src/helpers/init.ts +47 -0
- package/src/index.ts +2 -52
- package/src/models/guard.ts +18 -4
- package/src/models/index.ts +2 -0
- package/src/models/init.ts +37 -0
- package/src/models/practice.ts +13 -3
- package/src/models/workflow.ts +4 -9
- package/src/services/api.ts +51 -34
- package/src/services/apisPracticeManager.ts +52 -0
- package/src/services/guard.ts +46 -4
- package/src/services/index.ts +1 -0
- package/src/services/practice.ts +4 -4
- package/src/services/teller.ts +32 -17
package/dist/services/api.d.ts
CHANGED
|
@@ -2,9 +2,17 @@ import type { AxiosRequestConfig } from 'axios';
|
|
|
2
2
|
import { AuthRefreshFunc, Tokens } from '../models';
|
|
3
3
|
import { AxiosService } from './axios';
|
|
4
4
|
export declare class APIService extends AxiosService {
|
|
5
|
+
private useLocalStorage;
|
|
5
6
|
private tokenRefreshFailureCallback?;
|
|
6
7
|
private authRefreshFn?;
|
|
7
|
-
|
|
8
|
+
private tokens;
|
|
9
|
+
/**
|
|
10
|
+
* The API Service lets you use an axios API and handles oro backend services authentification via JWT tokens
|
|
11
|
+
* @param useLocalStorage if set to true, tokens will be stored in localStorage
|
|
12
|
+
* @param config (optional) an axios config
|
|
13
|
+
* @param tokenRefreshFailureCallback (optional) callback to call when failing to refresh the auth token
|
|
14
|
+
*/
|
|
15
|
+
constructor(useLocalStorage: boolean, config?: AxiosRequestConfig, tokenRefreshFailureCallback?: ((err: Error) => void) | undefined);
|
|
8
16
|
setAuthRefreshFn(fn: AuthRefreshFunc): void;
|
|
9
17
|
setTokens(tokens: Tokens): void;
|
|
10
18
|
getTokens(): Tokens;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AuthTokenResponse, ServiceCollection, ServiceCollectionRequest } from '../models';
|
|
2
|
+
import { GuardService } from './guard';
|
|
3
|
+
/**
|
|
4
|
+
* This service enables you to handle one authentication token per practice
|
|
5
|
+
*/
|
|
6
|
+
export declare class ApisPracticeManager {
|
|
7
|
+
private serviceCollReq;
|
|
8
|
+
private getAuthTokenCbk;
|
|
9
|
+
private useLocalStorage;
|
|
10
|
+
private practiceInstances;
|
|
11
|
+
/**
|
|
12
|
+
* The constructor
|
|
13
|
+
* @param serviceCollReq the services to initialize. Only filled urls will get corresponding service to be initialized.
|
|
14
|
+
* It will be used each time a new practices needs a `ServiceCollection`
|
|
15
|
+
* @param getAuthTokenCbk the callback function used to get a new JWT token
|
|
16
|
+
* @param useLocalStorage (default: false) if true store tokens into local storage (only for browsers)
|
|
17
|
+
*/
|
|
18
|
+
constructor(serviceCollReq: ServiceCollectionRequest, getAuthTokenCbk: (guard: GuardService, practiceUuid: string) => Promise<AuthTokenResponse>, useLocalStorage?: boolean);
|
|
19
|
+
/**
|
|
20
|
+
* This function is used to get a `ServiceCollection` associated to a practice. If missing, it will initialize a new `ServiceCollection`.
|
|
21
|
+
* @param practiceUuid the uuid of the practice
|
|
22
|
+
* @returns a promise holding a `ServiceCollection`
|
|
23
|
+
*/
|
|
24
|
+
get(practiceUuid: string): Promise<ServiceCollection>;
|
|
25
|
+
}
|
package/dist/services/guard.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AxiosAuthRefreshRequestConfig } from 'axios-auth-refresh';
|
|
2
|
-
import { AuthRecoverRequest, AuthTokenRequest, AuthTokenResponse, Base64String, IdentityCreateRequest, IdentityResendConfirmEmailRequest, IdentityResponse, IdentityUpdateRequest, QRCodeResponse, Tokens, Uuid, WhoAmIResponse } from '../models';
|
|
2
|
+
import { AuthRecoverRequest, AuthTokenRequest, AuthTokenResponse, Base64String, IdentityCreateRequest, IdentityResendConfirmEmailRequest, IdentityResponse, IdentityUpdateRequest, M2MTokenRequest, QRCodeResponse, Tokens, Uuid, WhoAmIResponse } from '../models';
|
|
3
3
|
import { APIService } from './api';
|
|
4
4
|
export interface GuardRequestConfig extends AxiosAuthRefreshRequestConfig {
|
|
5
5
|
useRefreshToken: boolean;
|
|
@@ -22,6 +22,13 @@ export declare class GuardService {
|
|
|
22
22
|
* @param tokens
|
|
23
23
|
*/
|
|
24
24
|
setTokens(tokens: Tokens): void;
|
|
25
|
+
/**
|
|
26
|
+
* Allow to retrieve a M2M token for a service
|
|
27
|
+
*
|
|
28
|
+
* @param req The credentials required to get an access token
|
|
29
|
+
* @returns AuthTokenResponse
|
|
30
|
+
*/
|
|
31
|
+
m2mToken(req: M2MTokenRequest): Promise<AuthTokenResponse>;
|
|
25
32
|
/**
|
|
26
33
|
* Allow to retrieve an access token and a refresh token in order
|
|
27
34
|
* to do authenticated request afterward
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConsultRequestMetadata, PracticeAccount, Uuid } from '../models';
|
|
2
|
-
import { Assignment, PlanType, Practice, PracticeConfigKind, PracticeConfigs, PracticeInvoice, PracticePayment, PracticePaymentIntent, PracticePlan, PracticePlanPrices, PracticeWorkflow, PracticeWorkflowWithTagSpecialty, Practitioner, PractitionerLicense, PractitionerPreference, PractitionerQuota, PractitionerRole, WorkflowType } from '../models/practice';
|
|
2
|
+
import { Assignment, AssignmentRequest, PlanType, Practice, PracticeConfigKind, PracticeConfigs, PracticeInvoice, PracticePayment, PracticePaymentIntent, PracticePlan, PracticePlanPrices, PracticeWorkflow, PracticeWorkflowWithTagSpecialty, Practitioner, PractitionerLicense, PractitionerPreference, PractitionerQuota, PractitionerRole, WorkflowType } from '../models/practice';
|
|
3
3
|
import { APIService } from './api';
|
|
4
4
|
export declare class PracticeService {
|
|
5
5
|
private api;
|
|
@@ -107,7 +107,7 @@ export declare class PracticeService {
|
|
|
107
107
|
*/
|
|
108
108
|
practiceGetPractitionerSignature(practiceUuid: Uuid, practitionerUuid: Uuid): Promise<Blob>;
|
|
109
109
|
practiceGetAssignments(practiceUuid: Uuid): Promise<Assignment[]>;
|
|
110
|
-
practiceCreateAssignment(practiceUuid: Uuid, requestBody:
|
|
110
|
+
practiceCreateAssignment(practiceUuid: Uuid, requestBody: AssignmentRequest): Promise<Assignment>;
|
|
111
111
|
practiceUpdateAssignment(practiceUuid: Uuid, assignmentId: number, requestBody: Assignment): Promise<Assignment>;
|
|
112
112
|
practiceGetAssignment(practiceUuid: Uuid, assignmentId: number): Promise<Assignment>;
|
|
113
113
|
practiceGetQuotas(practiceUuid: Uuid): Promise<PractitionerQuota[]>;
|
|
@@ -6,4 +6,13 @@ export declare class TellerService {
|
|
|
6
6
|
constructor(api: APIService, baseURL: string);
|
|
7
7
|
lockboxDataStore(lockboxUuid: Uuid, req: LockboxDataRequest, lockboxOwnerUuid?: Uuid, previousDataUuid?: Uuid): Promise<DataCreateResponse>;
|
|
8
8
|
updateConsultByUUID(patientUuid: Uuid, uuidConsult: Uuid, statusMedical: MedicalStatus, neverExpires?: boolean): Promise<Consult>;
|
|
9
|
+
/**
|
|
10
|
+
* This function notifies teller that the fax sent for a specific consult did not get through
|
|
11
|
+
* @param practiceUuid the practice uuid linked to the consult
|
|
12
|
+
* @param consultationUuid the consultation uuid
|
|
13
|
+
* @param consultationShortId the consultation short id
|
|
14
|
+
* @param fax the address where to send the fax
|
|
15
|
+
* @returns void
|
|
16
|
+
*/
|
|
17
|
+
notifyFaxFailed(practiceUuid: Uuid, consultationUuid: Uuid, consultationShortId: string, fax: string): Promise<void>;
|
|
9
18
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { sha256 } from 'hash.js'
|
|
2
|
+
import { Buffer } from 'buffer/'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This function return a base64 string representation of a hashed string
|
|
6
|
+
* @param value the string to hash
|
|
7
|
+
* @returns a base64 string representation of a hashed value
|
|
8
|
+
*/
|
|
9
|
+
export function hashToBase64String(value: string): string {
|
|
10
|
+
return Buffer.from(sha256().update(value).digest('hex'), 'hex').toString('base64')
|
|
11
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ServiceCollection, ServiceCollectionRequest } from '../models'
|
|
2
|
+
import {
|
|
3
|
+
APIService,
|
|
4
|
+
ConsultService,
|
|
5
|
+
DiagnosisService,
|
|
6
|
+
GuardService,
|
|
7
|
+
PracticeService,
|
|
8
|
+
TellerService,
|
|
9
|
+
VaultService,
|
|
10
|
+
WorkflowService,
|
|
11
|
+
} from '../services'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This function is used to initialize services with a provided url
|
|
15
|
+
* @param services an object containing the url of the services to init
|
|
16
|
+
* @param authenticationCallback (optional) the authentification callback. Called when the token were not able to be refreshed.
|
|
17
|
+
* @param useLocalStorage (default: true) if true store tokens into local storage (only for browsers)
|
|
18
|
+
* @returns an instance of each services with a provided url
|
|
19
|
+
*/
|
|
20
|
+
export const init = (
|
|
21
|
+
services: ServiceCollectionRequest,
|
|
22
|
+
authenticationCallback?: (err: Error, practiceUuid?: string) => void,
|
|
23
|
+
useLocalStorage = true
|
|
24
|
+
): ServiceCollection => {
|
|
25
|
+
const {
|
|
26
|
+
tellerBaseURL,
|
|
27
|
+
practiceBaseURL,
|
|
28
|
+
consultBaseURL,
|
|
29
|
+
vaultBaseURL,
|
|
30
|
+
guardBaseURL,
|
|
31
|
+
workflowBaseURL,
|
|
32
|
+
diagnosisBaseURL,
|
|
33
|
+
} = services
|
|
34
|
+
|
|
35
|
+
const apiService = new APIService(useLocalStorage, undefined, authenticationCallback)
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
apiService,
|
|
39
|
+
tellerService: tellerBaseURL ? new TellerService(apiService, tellerBaseURL) : undefined,
|
|
40
|
+
practiceService: practiceBaseURL ? new PracticeService(apiService, practiceBaseURL) : undefined,
|
|
41
|
+
consultService: consultBaseURL ? new ConsultService(apiService, consultBaseURL) : undefined,
|
|
42
|
+
vaultService: vaultBaseURL ? new VaultService(apiService, vaultBaseURL) : undefined,
|
|
43
|
+
guardService: guardBaseURL ? new GuardService(apiService, guardBaseURL) : undefined,
|
|
44
|
+
workflowService: workflowBaseURL ? new WorkflowService(apiService, workflowBaseURL) : undefined,
|
|
45
|
+
diagnosisService: diagnosisBaseURL ? new DiagnosisService(apiService, diagnosisBaseURL) : undefined,
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,56 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
APIService,
|
|
3
|
-
TellerService,
|
|
4
|
-
VaultService,
|
|
5
|
-
GuardService,
|
|
6
|
-
PracticeService,
|
|
7
|
-
ConsultService,
|
|
8
|
-
WorkflowService,
|
|
9
|
-
DiagnosisService,
|
|
10
|
-
} from './services'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* This function is used to initialize services with a provided url
|
|
14
|
-
* @param services an object containing the url of the services to init
|
|
15
|
-
* @param (optional) authenticationCallback the authentification callback
|
|
16
|
-
* @returns an instance of each services with a provided url
|
|
17
|
-
*/
|
|
18
|
-
const init = (
|
|
19
|
-
services: {
|
|
20
|
-
tellerBaseURL?: string
|
|
21
|
-
vaultBaseURL?: string
|
|
22
|
-
guardBaseURL?: string
|
|
23
|
-
practiceBaseURL?: string
|
|
24
|
-
consultBaseURL?: string
|
|
25
|
-
workflowBaseURL?: string
|
|
26
|
-
diagnosisBaseURL?: string
|
|
27
|
-
},
|
|
28
|
-
authenticationCallback?: (err: Error) => void
|
|
29
|
-
) => {
|
|
30
|
-
const {
|
|
31
|
-
tellerBaseURL,
|
|
32
|
-
practiceBaseURL,
|
|
33
|
-
consultBaseURL,
|
|
34
|
-
vaultBaseURL,
|
|
35
|
-
guardBaseURL,
|
|
36
|
-
workflowBaseURL,
|
|
37
|
-
diagnosisBaseURL,
|
|
38
|
-
} = services
|
|
39
|
-
|
|
40
|
-
const apiService = new APIService(undefined, authenticationCallback)
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
tellerService: tellerBaseURL ? new TellerService(apiService, tellerBaseURL) : undefined,
|
|
44
|
-
practiceService: practiceBaseURL ? new PracticeService(apiService, practiceBaseURL) : undefined,
|
|
45
|
-
consultService: consultBaseURL ? new ConsultService(apiService, consultBaseURL) : undefined,
|
|
46
|
-
vaultService: vaultBaseURL ? new VaultService(apiService, vaultBaseURL) : undefined,
|
|
47
|
-
guardService: guardBaseURL ? new GuardService(apiService, guardBaseURL) : undefined,
|
|
48
|
-
workflowService: workflowBaseURL ? new WorkflowService(apiService, workflowBaseURL) : undefined,
|
|
49
|
-
diagnosisService: diagnosisBaseURL ? new DiagnosisService(apiService, diagnosisBaseURL) : undefined,
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
1
|
+
import { init } from './helpers'
|
|
53
2
|
|
|
3
|
+
export * from './helpers'
|
|
54
4
|
export * from './models'
|
|
55
5
|
export * from './services'
|
|
56
6
|
export default init
|
package/src/models/guard.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { Uuid, Base64String, TokenData, RFC3339Date, Url } from './'
|
|
2
2
|
|
|
3
|
-
export type AuthRefreshFunc = (
|
|
4
|
-
refreshToken?: string
|
|
5
|
-
) => Promise<AuthTokenResponse>
|
|
3
|
+
export type AuthRefreshFunc = (refreshToken?: string) => Promise<AuthTokenResponse>
|
|
6
4
|
export interface Tokens {
|
|
7
5
|
accessToken?: string
|
|
8
6
|
refreshToken?: string
|
|
@@ -17,10 +15,20 @@ export interface AuthTokenRequest {
|
|
|
17
15
|
export interface AuthTokenResponse {
|
|
18
16
|
accessToken: string
|
|
19
17
|
tokenType: string
|
|
20
|
-
refreshToken
|
|
18
|
+
refreshToken?: string
|
|
21
19
|
expiresIn: number
|
|
22
20
|
}
|
|
23
21
|
|
|
22
|
+
/**
|
|
23
|
+
* This interface is used to request a M2M token as a service
|
|
24
|
+
*/
|
|
25
|
+
export interface M2MTokenRequest {
|
|
26
|
+
clientId: string
|
|
27
|
+
clientSecret: string
|
|
28
|
+
requestedScopes: string[]
|
|
29
|
+
practiceUuid: string
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
export interface AuthRecoverRequest {
|
|
25
33
|
practiceUuid: string
|
|
26
34
|
email: string
|
|
@@ -136,3 +144,9 @@ export interface LegalData {
|
|
|
136
144
|
rpAcceptedVersion: Url
|
|
137
145
|
rpAcceptedAtIP?: string
|
|
138
146
|
}
|
|
147
|
+
|
|
148
|
+
export type RoleBasedScopes = 'User' | 'Patient' | 'Practitioner' | 'Administrative'
|
|
149
|
+
|
|
150
|
+
export type PermissionBasedScopes = 'consult.consults.get' | 'consult.consults.post' | 'practice.assignments.post'
|
|
151
|
+
|
|
152
|
+
export type AllScopes = RoleBasedScopes | PermissionBasedScopes
|
package/src/models/index.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
APIService,
|
|
3
|
+
ConsultService,
|
|
4
|
+
DiagnosisService,
|
|
5
|
+
GuardService,
|
|
6
|
+
PracticeService,
|
|
7
|
+
TellerService,
|
|
8
|
+
VaultService,
|
|
9
|
+
WorkflowService,
|
|
10
|
+
} from '../services'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* This interface represents a collection of service urls you need to initialize
|
|
14
|
+
*/
|
|
15
|
+
export interface ServiceCollectionRequest {
|
|
16
|
+
tellerBaseURL?: string
|
|
17
|
+
vaultBaseURL?: string
|
|
18
|
+
guardBaseURL?: string
|
|
19
|
+
practiceBaseURL?: string
|
|
20
|
+
consultBaseURL?: string
|
|
21
|
+
workflowBaseURL?: string
|
|
22
|
+
diagnosisBaseURL?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* This interface represents a collection of service
|
|
27
|
+
*/
|
|
28
|
+
export interface ServiceCollection {
|
|
29
|
+
apiService: APIService
|
|
30
|
+
tellerService?: TellerService
|
|
31
|
+
practiceService?: PracticeService
|
|
32
|
+
consultService?: ConsultService
|
|
33
|
+
vaultService?: VaultService
|
|
34
|
+
guardService?: GuardService
|
|
35
|
+
workflowService?: WorkflowService
|
|
36
|
+
diagnosisService?: DiagnosisService
|
|
37
|
+
}
|
package/src/models/practice.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PlaceData } from
|
|
1
|
+
import { PlaceData } from '.'
|
|
2
2
|
|
|
3
3
|
export enum WorkflowType {
|
|
4
4
|
Onboard = 'Onboard',
|
|
@@ -299,8 +299,18 @@ export interface ConsultRequestMetadata {
|
|
|
299
299
|
isoLanguageRequired: string
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
export interface
|
|
303
|
-
|
|
302
|
+
export interface AssignmentRequest {
|
|
303
|
+
uuidAssignor: string //defaulting for insertion to the default practice admin
|
|
304
|
+
uuidPractitioner?: string
|
|
305
|
+
status?: AssignmentStatus
|
|
306
|
+
uuidConsult?: string
|
|
307
|
+
tagSpecialty?: string
|
|
308
|
+
isoLocality?: string,
|
|
309
|
+
isoLanguage?: string,
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export type Assignment = {
|
|
313
|
+
id: number ///optional for insertion
|
|
304
314
|
uuidPractice: string
|
|
305
315
|
uuidAssignor: string //defaulting for insertion to the default practice admin
|
|
306
316
|
uuidPractitioner?: string
|
package/src/models/workflow.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface LanguagePickerData extends ChoiceInputData {
|
|
|
32
32
|
export interface EntryData {
|
|
33
33
|
id?: number
|
|
34
34
|
label?: string
|
|
35
|
+
hideLabel?: boolean
|
|
36
|
+
minorLabel?: string
|
|
35
37
|
summaryLabel?: string
|
|
36
38
|
summaryHidden?: boolean
|
|
37
39
|
className?: string
|
|
@@ -78,15 +80,8 @@ export interface GroupedGenericQuestionData<T, A = IndexedData<ChoiceInputData>>
|
|
|
78
80
|
order?: number
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
export type QuestionData =
|
|
82
|
-
|
|
83
|
-
| GenericQuestionData<
|
|
84
|
-
'text' | 'date' | 'number' | 'images' | 'images-alias' | 'body-parts' | 'pharmacy-picker' | 'place-address'
|
|
85
|
-
>
|
|
86
|
-
| GenericQuestionData<'checkbox-group' | 'select' | 'multiple', IndexedData<ChoiceInputData>>
|
|
87
|
-
| GroupedGenericQuestionData<'radio', IndexedData<RadioInputData>>
|
|
88
|
-
| GroupedGenericQuestionData<'radio-card', IndexedData<RadioCardInputData>>
|
|
89
|
-
| GroupedGenericQuestionData<'language-picker', IndexedData<LanguagePickerData>>
|
|
83
|
+
export declare type QuestionData = GenericQuestionData<'title' | 'paragraph' | 'checkbox', void> | GenericQuestionData<'text' | 'text-area' | 'date' | 'number' | 'images' | 'images-alias' | 'body-parts' | 'pharmacy-picker' | 'place-address'> | GenericQuestionData<'checkbox-group' | 'select' | 'multiple' | 'text-select-group', IndexedData<ChoiceInputData>> | GroupedGenericQuestionData<'radio', IndexedData<RadioInputData>> | GroupedGenericQuestionData<'radio-card', IndexedData<RadioCardInputData>> | GroupedGenericQuestionData<'language-picker', IndexedData<LanguagePickerData>>;
|
|
84
|
+
|
|
90
85
|
|
|
91
86
|
export interface FieldData {
|
|
92
87
|
type: 'field'
|
package/src/services/api.ts
CHANGED
|
@@ -4,11 +4,18 @@ import { AuthRefreshFunc, Tokens } from '../models'
|
|
|
4
4
|
import { AxiosService } from './axios'
|
|
5
5
|
import { GuardRequestConfig } from './guard'
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
export class APIService extends AxiosService {
|
|
9
8
|
private authRefreshFn?: AuthRefreshFunc
|
|
9
|
+
private tokens: Tokens = {}
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* The API Service lets you use an axios API and handles oro backend services authentification via JWT tokens
|
|
13
|
+
* @param useLocalStorage if set to true, tokens will be stored in localStorage
|
|
14
|
+
* @param config (optional) an axios config
|
|
15
|
+
* @param tokenRefreshFailureCallback (optional) callback to call when failing to refresh the auth token
|
|
16
|
+
*/
|
|
11
17
|
constructor(
|
|
18
|
+
private useLocalStorage: boolean,
|
|
12
19
|
config?: AxiosRequestConfig,
|
|
13
20
|
private tokenRefreshFailureCallback?: (err: Error) => void
|
|
14
21
|
) {
|
|
@@ -16,7 +23,7 @@ export class APIService extends AxiosService {
|
|
|
16
23
|
const self = this
|
|
17
24
|
|
|
18
25
|
this.axios.interceptors.request.use(
|
|
19
|
-
config => {
|
|
26
|
+
(config) => {
|
|
20
27
|
const token = (config as GuardRequestConfig).useRefreshToken
|
|
21
28
|
? self.getTokens().refreshToken
|
|
22
29
|
: self.getTokens().accessToken
|
|
@@ -25,37 +32,40 @@ export class APIService extends AxiosService {
|
|
|
25
32
|
...config.headers,
|
|
26
33
|
Authorization: `Bearer ${token}`,
|
|
27
34
|
}
|
|
28
|
-
return config
|
|
35
|
+
return config
|
|
29
36
|
},
|
|
30
|
-
error => {
|
|
37
|
+
(error) => {
|
|
31
38
|
Promise.reject(error)
|
|
32
39
|
}
|
|
33
|
-
)
|
|
40
|
+
)
|
|
34
41
|
|
|
35
|
-
createAuthRefreshInterceptor(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
createAuthRefreshInterceptor(
|
|
43
|
+
this.axios,
|
|
44
|
+
async function (failedRequest) {
|
|
45
|
+
if (self.authRefreshFn) {
|
|
46
|
+
try {
|
|
47
|
+
let tokenResp = await self.authRefreshFn(self.getTokens().refreshToken)
|
|
48
|
+
self.setTokens({
|
|
49
|
+
accessToken: tokenResp.accessToken,
|
|
50
|
+
refreshToken: tokenResp.refreshToken,
|
|
51
|
+
})
|
|
52
|
+
failedRequest.response.config.headers['Authorization'] = `Bearer ${
|
|
53
|
+
self.getTokens().accessToken
|
|
54
|
+
}`
|
|
55
|
+
return Promise.resolve()
|
|
56
|
+
} catch (e) {
|
|
57
|
+
console.error('an error occured while refreshing tokens (notifying callback)', e)
|
|
58
|
+
if (self.tokenRefreshFailureCallback) self.tokenRefreshFailureCallback(failedRequest)
|
|
59
|
+
return Promise.resolve() // We keep it like that. Otherwise, it seems to break the api service will it is not needed
|
|
60
|
+
// return Promise.reject(e)
|
|
61
|
+
}
|
|
52
62
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
console.error('The request could not refresh the token (authRefreshFn was not set)', failedRequest)
|
|
64
|
+
return Promise.resolve() // We keep it like that. Otherwise, it seems to break the api service will it is not needed
|
|
65
|
+
// return Promise.reject(failedRequest)
|
|
66
|
+
},
|
|
67
|
+
{ statusCodes: [401, 403] }
|
|
68
|
+
)
|
|
59
69
|
}
|
|
60
70
|
|
|
61
71
|
public setAuthRefreshFn(fn: AuthRefreshFunc) {
|
|
@@ -63,15 +73,22 @@ export class APIService extends AxiosService {
|
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
public setTokens(tokens: Tokens) {
|
|
66
|
-
|
|
76
|
+
if (this.useLocalStorage) {
|
|
77
|
+
localStorage.setItem('tokens', JSON.stringify(tokens))
|
|
78
|
+
}
|
|
79
|
+
this.tokens = tokens
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
public getTokens(): Tokens {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
if (this.useLocalStorage) {
|
|
84
|
+
let tokens: Tokens = {}
|
|
85
|
+
const item = localStorage.getItem('tokens')
|
|
86
|
+
if (item) {
|
|
87
|
+
tokens = JSON.parse(item)
|
|
88
|
+
}
|
|
89
|
+
return tokens
|
|
90
|
+
} else {
|
|
91
|
+
return this.tokens
|
|
74
92
|
}
|
|
75
|
-
return tokens
|
|
76
93
|
}
|
|
77
94
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { init } from '../helpers'
|
|
2
|
+
import { AuthTokenResponse, ServiceCollection, ServiceCollectionRequest } from '../models'
|
|
3
|
+
import { GuardService } from './guard'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This service enables you to handle one authentication token per practice
|
|
7
|
+
*/
|
|
8
|
+
export class ApisPracticeManager {
|
|
9
|
+
private practiceInstances = new Map<string, ServiceCollection>()
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The constructor
|
|
13
|
+
* @param serviceCollReq the services to initialize. Only filled urls will get corresponding service to be initialized.
|
|
14
|
+
* It will be used each time a new practices needs a `ServiceCollection`
|
|
15
|
+
* @param getAuthTokenCbk the callback function used to get a new JWT token
|
|
16
|
+
* @param useLocalStorage (default: false) if true store tokens into local storage (only for browsers)
|
|
17
|
+
*/
|
|
18
|
+
constructor(
|
|
19
|
+
private serviceCollReq: ServiceCollectionRequest,
|
|
20
|
+
private getAuthTokenCbk: (guard: GuardService, practiceUuid: string) => Promise<AuthTokenResponse>,
|
|
21
|
+
private useLocalStorage = false
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* This function is used to get a `ServiceCollection` associated to a practice. If missing, it will initialize a new `ServiceCollection`.
|
|
26
|
+
* @param practiceUuid the uuid of the practice
|
|
27
|
+
* @returns a promise holding a `ServiceCollection`
|
|
28
|
+
*/
|
|
29
|
+
public async get(practiceUuid: string): Promise<ServiceCollection> {
|
|
30
|
+
const practiceInstance = this.practiceInstances.get(practiceUuid)
|
|
31
|
+
if (practiceInstance) return practiceInstance
|
|
32
|
+
|
|
33
|
+
const newPracticeInstance = init(this.serviceCollReq, undefined, this.useLocalStorage)
|
|
34
|
+
|
|
35
|
+
// Create one auth token callback per practice since the practice uuid needs to change
|
|
36
|
+
const authTokenFunc = async () => {
|
|
37
|
+
if (newPracticeInstance.guardService) {
|
|
38
|
+
console.log(`\x1b[36m[Auth] Refresh auth called (practiceUuid: ${practiceUuid})\x1b[36m`)
|
|
39
|
+
return await this.getAuthTokenCbk(newPracticeInstance.guardService, practiceUuid)
|
|
40
|
+
} else {
|
|
41
|
+
throw Error('[Auth] Unable to refresh token guard service is undefined')
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Set the refresh tokens callback
|
|
46
|
+
newPracticeInstance.apiService.setAuthRefreshFn(authTokenFunc)
|
|
47
|
+
|
|
48
|
+
this.practiceInstances.set(practiceUuid, newPracticeInstance)
|
|
49
|
+
|
|
50
|
+
return newPracticeInstance
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/services/guard.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
IdentityResendConfirmEmailRequest,
|
|
17
17
|
IdentityResponse,
|
|
18
18
|
IdentityUpdateRequest,
|
|
19
|
+
M2MTokenRequest,
|
|
19
20
|
QRCodeRequest,
|
|
20
21
|
QRCodeResponse,
|
|
21
22
|
Tokens,
|
|
@@ -32,7 +33,7 @@ export class GuardService {
|
|
|
32
33
|
private whoAmICache: Record<string, WhoAmIResponse>
|
|
33
34
|
|
|
34
35
|
constructor(private api: APIService, private baseURL: string) {
|
|
35
|
-
this.api.setAuthRefreshFn(this.authRefresh.bind(this))
|
|
36
|
+
this.api.setAuthRefreshFn(this.authRefresh.bind(this)) // This is the default behavior for User JWT tokens. If you want other kind of refresh you shall overwrite this call
|
|
36
37
|
this.identityCache = {}
|
|
37
38
|
this.whoAmICache = {}
|
|
38
39
|
}
|
|
@@ -52,6 +53,46 @@ export class GuardService {
|
|
|
52
53
|
this.api.setTokens({ ...this.api.getTokens(), ...tokens })
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Allow to retrieve a M2M token for a service
|
|
58
|
+
*
|
|
59
|
+
* @param req The credentials required to get an access token
|
|
60
|
+
* @returns AuthTokenResponse
|
|
61
|
+
*/
|
|
62
|
+
public async m2mToken(req: M2MTokenRequest): Promise<AuthTokenResponse> {
|
|
63
|
+
let resp: AuthTokenResponse | undefined
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
let config: AxiosAuthRefreshRequestConfig = {
|
|
67
|
+
skipAuthRefresh: true,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
resp = await this.api.post<AuthTokenResponse>(`${this.baseURL}/v1/m2m/token`, req, config)
|
|
71
|
+
|
|
72
|
+
this.api.setTokens({
|
|
73
|
+
accessToken: resp.accessToken,
|
|
74
|
+
})
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error('Error while posting m2m token:', e)
|
|
77
|
+
|
|
78
|
+
if ((e as any).isAxiosError) {
|
|
79
|
+
const code = (e as AxiosError).response?.status
|
|
80
|
+
switch (code) {
|
|
81
|
+
case 400:
|
|
82
|
+
throw new AuthenticationBadRequest()
|
|
83
|
+
case 500:
|
|
84
|
+
throw new AuthenticationServerError()
|
|
85
|
+
case 401:
|
|
86
|
+
default:
|
|
87
|
+
throw new AuthenticationFailed()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
throw new AuthenticationFailed()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return resp
|
|
94
|
+
}
|
|
95
|
+
|
|
55
96
|
/**
|
|
56
97
|
* Allow to retrieve an access token and a refresh token in order
|
|
57
98
|
* to do authenticated request afterward
|
|
@@ -74,6 +115,8 @@ export class GuardService {
|
|
|
74
115
|
refreshToken: resp.refreshToken,
|
|
75
116
|
})
|
|
76
117
|
} catch (e) {
|
|
118
|
+
console.error('Error while posting auth token:', e)
|
|
119
|
+
|
|
77
120
|
if ((e as any).isAxiosError) {
|
|
78
121
|
const code = (e as AxiosError).response?.status
|
|
79
122
|
switch (code) {
|
|
@@ -237,7 +280,7 @@ export class GuardService {
|
|
|
237
280
|
* @returns IdentityResponse
|
|
238
281
|
*/
|
|
239
282
|
public async identityGetByCustomerEmail(email: string): Promise<IdentityResponse> {
|
|
240
|
-
return this.identityGetByHash(email.substring(email.indexOf('+')+1, email.indexOf('@')))
|
|
283
|
+
return this.identityGetByHash(email.substring(email.indexOf('+') + 1, email.indexOf('@')))
|
|
241
284
|
}
|
|
242
285
|
|
|
243
286
|
/**
|
|
@@ -252,9 +295,8 @@ export class GuardService {
|
|
|
252
295
|
//call (ie: /v1/mapping/[b64Hash]) which would return a blob to decrypt
|
|
253
296
|
//which would contain the real identityID to call IdentityGet with.
|
|
254
297
|
|
|
255
|
-
|
|
256
298
|
//The hash comes in base64 format but it isn't URL safe soe we have to convert
|
|
257
299
|
//to base64URL (see https://en.wikipedia.org/wiki/Base64#The_URL_applications)
|
|
258
|
-
return this.identityGet(b64Hash.replace('+','-').replace('/','_'))
|
|
300
|
+
return this.identityGet(b64Hash.replace('+', '-').replace('/', '_'))
|
|
259
301
|
}
|
|
260
302
|
}
|