@event-inc/connections
Version:
Event Inc is a fully managed event bus lets you send and receive data across mission-critical cloud apps, databases and warehouses.
164 lines (145 loc) • 4.21 kB
text/typescript
import { OauthConnections, OauthConnectionTypes } from '@event-inc/types';
import {
makeHttpNetworkCall,
matchResultAndHandleHttpError,
} from '@event-inc/utils';
import { identity } from 'ramda';
import jwt_decode from 'jwt-decode';
interface OauthConnectionOptions {
OAUTH_APP_CLIENT_ID: string;
OAUTH_APP_CLIENT_SECRET: string;
type: OauthConnections;
}
interface Tenants {
id: string;
tenantId: string;
tenantType: string;
tenantName: string;
createdDateUtc: string;
updatedDateUtc: string;
authEventId: string;
}
[];
const endpoints = {
xero: 'https://identity.xero.com/connect/token',
};
const deleteEndpoints = {
xero: 'https://api.xero.com/connections/{connectionId}',
};
export class OauthConnection {
private readonly OAUTH_APP_CLIENT_ID: string;
private readonly OAUTH_APP_CLIENT_SECRET: string;
private readonly type: string;
constructor({
OAUTH_APP_CLIENT_ID,
OAUTH_APP_CLIENT_SECRET,
type,
}: OauthConnectionOptions) {
this.OAUTH_APP_CLIENT_ID = OAUTH_APP_CLIENT_ID;
this.OAUTH_APP_CLIENT_SECRET = OAUTH_APP_CLIENT_SECRET;
this.type = type;
}
getOauthDetails = () => {
switch (this.type) {
case OauthConnectionTypes.Xero:
return {
endpoint: endpoints[this.type],
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${Buffer.from(
`${this.OAUTH_APP_CLIENT_ID}:${this.OAUTH_APP_CLIENT_SECRET}`
).toString('base64')}`,
},
sourceIntegrationDefinitionId:
'conn_def_src_MTY4ODc2MzM3ODY2OQ::OWE2NDdmYjAtZjFlMy00MWEyLTgwMTctMzVhODMxYTBkOWNi',
destinationIntegrationDefinitionId:
'conn_def_dst_MTY4NjA3MDUyOTk1OA::MTgwM2E1NGItMTYxMC00NjE4LTk1NTItNjBjY2I1NmY1ZmQx',
};
}
};
getOauthFormData = ({
accessToken,
refreshToken,
}: {
accessToken: string;
refreshToken: string;
}) => {
switch (this.type) {
case OauthConnectionTypes.Xero:
return {
XERO_REFRESH_TOKEN: refreshToken,
XERO_ACCESS_TOKEN: accessToken,
XERO_CLIENT_ID: this.OAUTH_APP_CLIENT_ID,
XERO_CLIENT_SECRET: this.OAUTH_APP_CLIENT_SECRET,
};
}
};
deleteOauthConnection = async ({
connectionId,
accessToken,
}: {
connectionId: string;
accessToken: string;
}) => {
const deleteEndpoint = deleteEndpoints[this.type as OauthConnections];
const response = await makeHttpNetworkCall({
method: 'DELETE',
url: deleteEndpoint.replace('{connectionId}', connectionId),
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
return matchResultAndHandleHttpError(response, identity);
};
getTenantId = async (accessToken: string) => {
switch (this.type) {
case OauthConnectionTypes.Xero:
const decodedToken: {
authentication_event_id: string;
} = jwt_decode(accessToken);
const response = await makeHttpNetworkCall({
method: 'GET',
url: 'https://api.xero.com/connections',
headers: {
Authorization: `Bearer ${accessToken}`,
},
params: {
authEventId: decodedToken?.authentication_event_id,
},
});
let { data } = matchResultAndHandleHttpError(response, identity) as {
data: Tenants[];
};
if (data?.length === 0 || data?.length > 1) {
const existingTenants = await this.getAuthorizedTenants(accessToken);
const tenantNames = existingTenants
?.map((item) => item.tenantName)
?.join(', ');
const existingTenantsMessage =
tenantNames?.length > 0
? ` The following tenants are currently connected: ${tenantNames}.`
: '';
throw new Error(
`No tenant was explicitly selected on connect.${existingTenantsMessage}Ensure you disconnect and connect again with a single tenant selected.`
);
}
return data?.[0]?.id;
}
};
getAuthorizedTenants = async (accessToken: string) => {
switch (this.type) {
case OauthConnectionTypes.Xero:
const response = await makeHttpNetworkCall({
method: 'GET',
url: 'https://api.xero.com/connections',
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const { data } = matchResultAndHandleHttpError(response, identity) as {
data: Tenants[];
};
return data;
}
};
}