@starsched/sdk
Version:
ABA clinic control and management service API SDK
190 lines (189 loc) • 8.86 kB
JavaScript
import { HttpClient } from './http/client';
import { Accounts } from './services/account/index';
import { Appointments } from './services/appointment/index';
import { Authentication } from './services/authentication/index';
import { Companies } from './services/companies/index';
import { CompanyInvites } from './services/company-invites/index';
import { CompanyMembers } from './services/company-members/index';
import { CompanyPatients } from './services/company-patient/index';
import { CompaniesPlan } from './services/company-plan/index';
import { Companyprofessionals } from './services/company-professional/index';
import { Profiles } from './services/profiles/index';
export * from './services/account/protocols/company-sign-up-request';
export * from './services/account/protocols/finalize-company-sign-up-request.protocols';
export * from './services/account/protocols/get-company-sign-up-request.protocols';
export * from './services/account/protocols/request-company-sign-up.protocols';
export * from './services/appointment/protocols/appointment';
export * from './services/appointment/protocols/list-by-patient';
export * from './services/authentication/protocols/sign-in-with-email-and-password.protocols';
export * from './services/company-plan/protocols/company-plan';
export * from './services/company-plan/protocols/get-plan.protocols';
export * from './services/companies/protocols/company';
export * from './services/companies/protocols/create-company.protocols';
export * from './services/companies/protocols/get-my-companies.protocols';
export * from './services/companies/protocols/update-company.protocols';
export * from './services/company-invites/protocols/company-invite';
export * from './services/company-invites/protocols/create.protocols';
export * from './services/company-invites/protocols/delete.protocols';
export * from './services/company-invites/protocols/list.protocols';
export * from './services/company-invites/protocols/resend.protocols';
export * from './services/company-invites/protocols/update-role.protocols';
export * from './services/company-members/protocols/company-member';
export * from './services/company-members/protocols/list.protocols';
export * from './services/company-members/protocols/update-role.protocols';
export * from './services/company-members/protocols/update-access.protocols';
export * from './services/company-patient/protocols/company-patient';
export * from './services/company-patient/protocols/create.protocols';
export * from './services/company-patient/protocols/list.protocols';
export * from './services/company-professional/protocols/company-professional';
export * from './services/company-professional/protocols/list.protocols';
export * from './services/profiles/protocols/get-my-profile.protocols';
export * from './services/profiles/protocols/profile';
export class StarSchedAPI {
options;
isRefreshingAccessToken = false;
failedRequestsQueue = [];
accessToken = null;
refreshToken = null;
httpClient;
authentication;
profiles;
accounts;
companies;
companiesPlan;
companyMembers;
companyProfessionals;
companyInvites;
companyPatients;
appointments;
constructor(options) {
this.options = options;
this.httpClient = new HttpClient({
baseURL: options.baseURL,
requestInterceptors: [this.authenticatedRoutesInterceptor.bind(this)],
responseInterceptors: [
this.refreshAuthenticationInterceptor.bind(this),
this.storeAuthenticationOutputInterceptor.bind(this)
]
});
this.authentication = new Authentication(this.httpClient);
this.profiles = new Profiles(this.httpClient);
this.accounts = new Accounts(this.httpClient);
this.companies = new Companies(this.httpClient);
this.companiesPlan = new CompaniesPlan(this.httpClient);
this.companyMembers = new CompanyMembers(this.httpClient);
this.companyProfessionals = new Companyprofessionals(this.httpClient);
this.companyInvites = new CompanyInvites(this.httpClient);
this.companyPatients = new CompanyPatients(this.httpClient);
this.appointments = new Appointments(this.httpClient);
}
async authenticatedRoutesInterceptor(config) {
if (this.options.logRequests) {
console.log(`${config.method} ${config.url} ${this.accessToken ? '(with auth)' : ''}`);
}
const notAuthenticatedRoutes = [
'/v1/authentication/email',
'/v1/authentication/refresh'
];
const routeRequiresAuthentication = !notAuthenticatedRoutes.includes(config.url);
if (routeRequiresAuthentication) {
if (this.options.authenticationStore) {
const storedAuthentication = await this.options.authenticationStore.get();
if (storedAuthentication) {
this.accessToken = storedAuthentication.access_token;
this.refreshToken = storedAuthentication.refresh_token;
}
}
if (this.accessToken) {
config.headers.set('Authorization', `Bearer ${this.accessToken}`);
}
}
return config;
}
async refreshAuthenticationInterceptor(config, response) {
if (response.ok) {
return response;
}
const errorResponse = response;
const authenticationExpired = errorResponse.statusCode === 401 &&
errorResponse.body?.code === 'token.expired';
if (!authenticationExpired) {
return response;
}
if (!this.refreshToken) {
return response;
}
if (!this.isRefreshingAccessToken) {
this.isRefreshingAccessToken = true;
this.refreshAccessToken()
.then((refreshTokenResponse) => {
if (!refreshTokenResponse.ok) {
throw refreshTokenResponse;
}
return refreshTokenResponse.body;
})
.then(async (refreshTokenResponse) => {
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const authentication = refreshTokenResponse;
this.accessToken = authentication.access_token;
this.refreshToken = authentication.refresh_token;
if (this.options.authenticationStore) {
await this.options.authenticationStore.store(authentication);
}
// biome-ignore lint/complexity/noForEach: <explanation>
this.failedRequestsQueue.forEach((request) => {
request.onSuccess(authentication.access_token);
});
this.failedRequestsQueue = [];
})
.catch(async (refreshTokenError) => {
if (this.options.authenticationStore) {
await this.options.authenticationStore.remove();
}
// biome-ignore lint/complexity/noForEach: <explanation>
this.failedRequestsQueue.forEach((request) => {
request.onFailure(refreshTokenError);
});
this.failedRequestsQueue = [];
if (this.options.onLogout) {
this.options.onLogout();
}
})
.finally(() => {
this.isRefreshingAccessToken = false;
});
return new Promise((resolve, reject) => {
this.failedRequestsQueue.push({
onSuccess: (updatedAccessToken) => {
config.headers.set('Authorization', `Bearer ${updatedAccessToken}`);
resolve(this.httpClient.request(config));
},
onFailure: reject
});
});
}
return errorResponse;
}
async storeAuthenticationOutputInterceptor(config, response) {
if (!response.ok) {
return response;
}
const authenticationRoutes = [
'/v1/authentication/email',
'/v1/authentication/refresh'
];
const isAuthenticationResponse = authenticationRoutes.includes(config.url);
if (isAuthenticationResponse) {
const body = response.body;
if (this.options.authenticationStore) {
await this.options.authenticationStore.store(body);
}
this.accessToken = body.access_token;
this.refreshToken = body.refresh_token;
}
return response;
}
async refreshAccessToken() {
return this.httpClient.post('/v1/authentication/refresh', { refresh_token: this.refreshToken });
}
}