-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7002989
commit 424cb67
Showing
10 changed files
with
448 additions
and
191 deletions.
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
src/v0/destinations/salesforce/salesforce-sdk/src/api/salesforceClient.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { HttpClient } from "../utils/httpClient"; | ||
import { SalesforceAuth, AuthProvider, SalesforceRecord, SalesforceResponse, QueryResponse, OAuthCredentials, SalesforceDestinationConfig } from "../types/salesforceTypes"; | ||
import { TokenProvider } from "../auth/tokenProvider"; | ||
import { OAuthProvider } from "../auth/oauthProvider"; | ||
|
||
export class SalesforceClient { | ||
private httpClient: HttpClient; | ||
|
||
constructor(auth: SalesforceAuth) { | ||
let authProvider: AuthProvider; | ||
let instanceUrl: string; | ||
|
||
if ("accessToken" in auth) { | ||
authProvider = new OAuthProvider(auth as OAuthCredentials ); | ||
instanceUrl = auth.instanceUrl; | ||
} else { | ||
authProvider = new TokenProvider(auth as SalesforceDestinationConfig); | ||
instanceUrl = auth.instanceUrl; | ||
} | ||
|
||
this.httpClient = new HttpClient(instanceUrl, authProvider); | ||
} | ||
|
||
async create(objectType: string, record: SalesforceRecord, salesforceId?: string): Promise<SalesforceResponse> { | ||
let targetEndpoint = `/services/data/v50.0/sobjects/${objectType}`; | ||
if (salesforceId) { | ||
targetEndpoint += `/${salesforceId}?_HttpMethod=PATCH`; | ||
} | ||
return this.httpClient.post<SalesforceResponse>(targetEndpoint, record); | ||
} | ||
|
||
async search(objectType: string, identifierValue: string, identifierType: string): Promise<QueryResponse<SalesforceRecord>> { | ||
return this.httpClient.get<QueryResponse<SalesforceRecord>>(`/services/data/v50.0/parameterizedSearch/?q=${identifierValue}&sobject=${objectType}&in=${identifierType}&${objectType}.fields=id,${identifierType}`); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/v0/destinations/salesforce/salesforce-sdk/src/auth/authContext.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** | ||
* AuthProvider interface acts as a contract for authentication mechanisms. | ||
* Each implementation of this interface will define how to retrieve the access token. | ||
*/ | ||
export interface AuthProvider { | ||
/** | ||
* Retrieves the access token required for authenticating API calls. | ||
* @returns A Promise that resolves to the access token as a string. | ||
*/ | ||
getAccessToken(): Promise<string>; | ||
|
||
getAuthenticationHeader(token: string): any; | ||
|
||
areCredentialsSet(): boolean; | ||
} |
30 changes: 30 additions & 0 deletions
30
src/v0/destinations/salesforce/salesforce-sdk/src/auth/oauthProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { AuthProvider } from './authContext'; | ||
import { OAuthCredentials } from '../types/salesforceTypes'; | ||
|
||
/** | ||
* OAuthProvider is an implementation of AuthProvider that retrieves an access token using OAuth. | ||
*/ | ||
export class OAuthProvider implements AuthProvider { | ||
private readonly credentials: OAuthCredentials; | ||
|
||
constructor(credentials: OAuthCredentials) { | ||
if (!credentials.token || !credentials.instanceUrl) { | ||
throw new Error('OAuth credentials are incomplete.'); | ||
} | ||
this.credentials = credentials; | ||
} | ||
|
||
async getAccessToken(): Promise<string> { | ||
return this.credentials.token; | ||
} | ||
|
||
getAuthenticationHeader(token: string): any { | ||
return { | ||
Authorization: `Bearer ${token}`, | ||
}; | ||
} | ||
|
||
areCredentialsSet(): boolean { | ||
return !!(this.credentials && this.credentials.token && this.credentials.instanceUrl); | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
src/v0/destinations/salesforce/salesforce-sdk/src/auth/tokenProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import axios from 'axios'; | ||
import { AuthProvider } from './authContext'; | ||
import { | ||
SalesforceDestinationConfig, | ||
SF_TOKEN_REQUEST_URL, | ||
SF_TOKEN_REQUEST_URL_SANDBOX, | ||
} from '../types/salesforceTypes'; | ||
|
||
/** | ||
* TokenProvider is an implementation of AuthProvider that uses a pre-existing access token. | ||
*/ | ||
export class TokenProvider implements AuthProvider { | ||
private credentials!: SalesforceDestinationConfig; | ||
|
||
// Setter method for credentials to validate before setting | ||
setCredentials(credentials: SalesforceDestinationConfig): void { | ||
if (!credentials.consumerKey || !credentials.password || !credentials.consumerSecret) { | ||
throw new Error('Access token is required for TokenProvider.'); | ||
} | ||
this.credentials = credentials; | ||
} | ||
|
||
constructor(credentials: SalesforceDestinationConfig) { | ||
this.setCredentials(credentials); // Use the setter method | ||
} | ||
|
||
async getAccessToken(): Promise<string> { | ||
let SF_TOKEN_URL; | ||
if (this.credentials.sandbox) { | ||
SF_TOKEN_URL = SF_TOKEN_REQUEST_URL_SANDBOX; | ||
} else { | ||
SF_TOKEN_URL = SF_TOKEN_REQUEST_URL; | ||
} | ||
|
||
try { | ||
const authUrl = `${SF_TOKEN_URL}?username=${ | ||
this.credentials.userName | ||
}&password=${encodeURIComponent(this.credentials.password)}${encodeURIComponent( | ||
this.credentials.initialAccessToken, | ||
)}&client_id=${this.credentials.consumerKey}&client_secret=${ | ||
this.credentials.consumerSecret | ||
}&grant_type=password`; | ||
const response = await axios.post(authUrl); | ||
|
||
if (response.data && response.data.access_token) { | ||
this.credentials.instanceUrl = response.data.instance_url; | ||
return response.data.access_token; | ||
} | ||
throw new Error('Failed to retrieve access token.'); | ||
} catch (error: unknown) { | ||
if (error instanceof Error) { | ||
throw new Error(`Error fetching access token: ${error.message}`); | ||
} else { | ||
throw new Error('Error fetching access token: Unknown error occurred.'); | ||
} | ||
} | ||
} | ||
|
||
getAuthenticationHeader(token: string): any { | ||
return { | ||
Authorization: token, | ||
}; | ||
} | ||
|
||
areCredentialsSet(): boolean { | ||
return !!( | ||
this.credentials && | ||
this.credentials.consumerKey && | ||
this.credentials.password && | ||
this.credentials.consumerSecret && | ||
this.credentials.instanceUrl | ||
); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/v0/destinations/salesforce/salesforce-sdk/src/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { AuthProvider } from './auth/authContext'; | ||
import { TokenProvider } from './auth/tokenProvider'; | ||
import { OAuthProvider } from './auth/oauthProvider'; | ||
import { | ||
SalesforceDestinationConfig, | ||
OAuthCredentials, | ||
LEGACY, | ||
OAUTH, | ||
} from './types/salesforceTypes'; | ||
|
||
export function createAuthProvider( | ||
authType: 'legacy' | 'oauth', | ||
metadata: SalesforceDestinationConfig | OAuthCredentials, | ||
): AuthProvider { | ||
if (authType === LEGACY) { | ||
return new TokenProvider(metadata as SalesforceDestinationConfig); | ||
} | ||
if (authType === OAUTH) { | ||
return new OAuthProvider(metadata as OAuthCredentials); | ||
} | ||
throw new Error(`Unsupported auth type: ${authType}`); | ||
} |
44 changes: 44 additions & 0 deletions
44
src/v0/destinations/salesforce/salesforce-sdk/src/types/salesforceTypes.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
export interface OAuthCredentials { | ||
token: string; | ||
instanceUrl: string; | ||
} | ||
|
||
export interface SalesforceDestinationConfig { | ||
initialAccessToken: string; | ||
consumerKey: string; | ||
consumerSecret: string; | ||
userName: string; | ||
password: string; | ||
sandbox: true; | ||
instanceUrl: string; | ||
} | ||
|
||
export type SalesforceAuth = SalesforceDestinationConfig | OAuthCredentials; | ||
|
||
export interface AuthProvider { | ||
getAccessToken(): Promise<string>; | ||
getAuthenticationHeader(token: string): any; | ||
} | ||
|
||
export interface SalesforceResponse { | ||
id: string; | ||
success: boolean; | ||
errors?: string[]; | ||
} | ||
|
||
export interface SalesforceRecord { | ||
Id: string; | ||
Name: string; | ||
} | ||
|
||
export interface QueryResponse<T> { | ||
totalSize: number; | ||
done: boolean; | ||
records: T[]; | ||
} | ||
|
||
export const SF_TOKEN_REQUEST_URL = 'https://login.salesforce.com/services/oauth2/token'; | ||
export const SF_TOKEN_REQUEST_URL_SANDBOX = 'https://test.salesforce.com/services/oauth2/token'; | ||
|
||
export const LEGACY = 'legacy'; | ||
export const OAUTH = 'oauth'; |
35 changes: 35 additions & 0 deletions
35
src/v0/destinations/salesforce/salesforce-sdk/src/utils/httpClient.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import axios, { AxiosInstance } from 'axios'; | ||
import { AuthProvider } from '../types/salesforceTypes'; | ||
|
||
export class HttpClient { | ||
private client: AxiosInstance; | ||
|
||
private authProvider: AuthProvider; | ||
|
||
constructor(instanceUrl: string, authProvider: AuthProvider) { | ||
this.authProvider = authProvider; | ||
this.client = axios.create({ | ||
baseURL: instanceUrl, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}); | ||
} | ||
|
||
private async addAuthHeader(): Promise<void> { | ||
const token = await this.authProvider.getAccessToken(); | ||
this.client.defaults.headers = this.authProvider.getAuthenticationHeader(token); | ||
} | ||
|
||
async get<T>(url: string): Promise<T> { | ||
// for getting the access token we are not requiring to send any headers | ||
const response = await this.client.get<T>(url); | ||
return response.data; | ||
} | ||
|
||
async post<T>(url: string, data: any): Promise<T> { | ||
await this.addAuthHeader(); | ||
const response = await this.client.post<T>(url, data); | ||
return response.data; | ||
} | ||
} |
Oops, something went wrong.