From 424cb6752d69bacac9341b7d3320145847b2a0c0 Mon Sep 17 00:00:00 2001 From: shrouti1507 Date: Mon, 23 Dec 2024 20:51:31 +0530 Subject: [PATCH] feat: salesforce sdk restructured --- .../src/api/salesforceClient.ts | 35 +++ .../salesforce-sdk/src/auth/authContext.ts | 15 ++ .../salesforce-sdk/src/auth/oauthProvider.ts | 30 +++ .../salesforce-sdk/src/auth/tokenProvider.ts | 74 ++++++ .../salesforce/salesforce-sdk/src/index.ts | 22 ++ .../src/types/salesforceTypes.ts | 44 +++ .../salesforce-sdk/src/utils/httpClient.ts | 35 +++ src/v0/destinations/salesforce/sdk/index.ts | 251 +++++++++--------- src/v0/destinations/salesforce/transform.js | 117 ++++---- src/v0/destinations/salesforce/utils.js | 16 +- 10 files changed, 448 insertions(+), 191 deletions(-) create mode 100644 src/v0/destinations/salesforce/salesforce-sdk/src/api/salesforceClient.ts create mode 100644 src/v0/destinations/salesforce/salesforce-sdk/src/auth/authContext.ts create mode 100644 src/v0/destinations/salesforce/salesforce-sdk/src/auth/oauthProvider.ts create mode 100644 src/v0/destinations/salesforce/salesforce-sdk/src/auth/tokenProvider.ts create mode 100644 src/v0/destinations/salesforce/salesforce-sdk/src/index.ts create mode 100644 src/v0/destinations/salesforce/salesforce-sdk/src/types/salesforceTypes.ts create mode 100644 src/v0/destinations/salesforce/salesforce-sdk/src/utils/httpClient.ts diff --git a/src/v0/destinations/salesforce/salesforce-sdk/src/api/salesforceClient.ts b/src/v0/destinations/salesforce/salesforce-sdk/src/api/salesforceClient.ts new file mode 100644 index 0000000000..10d595a2d9 --- /dev/null +++ b/src/v0/destinations/salesforce/salesforce-sdk/src/api/salesforceClient.ts @@ -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 { + let targetEndpoint = `/services/data/v50.0/sobjects/${objectType}`; + if (salesforceId) { + targetEndpoint += `/${salesforceId}?_HttpMethod=PATCH`; + } + return this.httpClient.post(targetEndpoint, record); + } + + async search(objectType: string, identifierValue: string, identifierType: string): Promise> { + return this.httpClient.get>(`/services/data/v50.0/parameterizedSearch/?q=${identifierValue}&sobject=${objectType}&in=${identifierType}&${objectType}.fields=id,${identifierType}`); + } +} diff --git a/src/v0/destinations/salesforce/salesforce-sdk/src/auth/authContext.ts b/src/v0/destinations/salesforce/salesforce-sdk/src/auth/authContext.ts new file mode 100644 index 0000000000..4ba291f146 --- /dev/null +++ b/src/v0/destinations/salesforce/salesforce-sdk/src/auth/authContext.ts @@ -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; + + getAuthenticationHeader(token: string): any; + + areCredentialsSet(): boolean; +} diff --git a/src/v0/destinations/salesforce/salesforce-sdk/src/auth/oauthProvider.ts b/src/v0/destinations/salesforce/salesforce-sdk/src/auth/oauthProvider.ts new file mode 100644 index 0000000000..335b1e4e5d --- /dev/null +++ b/src/v0/destinations/salesforce/salesforce-sdk/src/auth/oauthProvider.ts @@ -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 { + return this.credentials.token; + } + + getAuthenticationHeader(token: string): any { + return { + Authorization: `Bearer ${token}`, + }; + } + + areCredentialsSet(): boolean { + return !!(this.credentials && this.credentials.token && this.credentials.instanceUrl); + } +} diff --git a/src/v0/destinations/salesforce/salesforce-sdk/src/auth/tokenProvider.ts b/src/v0/destinations/salesforce/salesforce-sdk/src/auth/tokenProvider.ts new file mode 100644 index 0000000000..c7b148c765 --- /dev/null +++ b/src/v0/destinations/salesforce/salesforce-sdk/src/auth/tokenProvider.ts @@ -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 { + 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 + ); + } +} diff --git a/src/v0/destinations/salesforce/salesforce-sdk/src/index.ts b/src/v0/destinations/salesforce/salesforce-sdk/src/index.ts new file mode 100644 index 0000000000..1dd9e8973c --- /dev/null +++ b/src/v0/destinations/salesforce/salesforce-sdk/src/index.ts @@ -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}`); +} diff --git a/src/v0/destinations/salesforce/salesforce-sdk/src/types/salesforceTypes.ts b/src/v0/destinations/salesforce/salesforce-sdk/src/types/salesforceTypes.ts new file mode 100644 index 0000000000..03b417eac9 --- /dev/null +++ b/src/v0/destinations/salesforce/salesforce-sdk/src/types/salesforceTypes.ts @@ -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; + getAuthenticationHeader(token: string): any; +} + +export interface SalesforceResponse { + id: string; + success: boolean; + errors?: string[]; +} + +export interface SalesforceRecord { + Id: string; + Name: string; +} + +export interface QueryResponse { + 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'; diff --git a/src/v0/destinations/salesforce/salesforce-sdk/src/utils/httpClient.ts b/src/v0/destinations/salesforce/salesforce-sdk/src/utils/httpClient.ts new file mode 100644 index 0000000000..ddc74adca4 --- /dev/null +++ b/src/v0/destinations/salesforce/salesforce-sdk/src/utils/httpClient.ts @@ -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 { + const token = await this.authProvider.getAccessToken(); + this.client.defaults.headers = this.authProvider.getAuthenticationHeader(token); + } + + async get(url: string): Promise { + // for getting the access token we are not requiring to send any headers + const response = await this.client.get(url); + return response.data; + } + + async post(url: string, data: any): Promise { + await this.addAuthHeader(); + const response = await this.client.post(url, data); + return response.data; + } +} diff --git a/src/v0/destinations/salesforce/sdk/index.ts b/src/v0/destinations/salesforce/sdk/index.ts index fd2c7a756e..999b44b982 100644 --- a/src/v0/destinations/salesforce/sdk/index.ts +++ b/src/v0/destinations/salesforce/sdk/index.ts @@ -1,138 +1,139 @@ type AuthData = { - instanceUrl: string; - accessToken: string; + instanceUrl: string; + accessToken: string; }; type AuthFlow = 'OAUTH' | 'OTHER'; type AuthOverride = { - accessToken: string; - authorizationFlow: AuthFlow; + accessToken: string; + authorizationFlow: AuthFlow; }; -class SalesforceSDK { - private authorizationData: AuthData; - private apiVersion: string; - private authorizationFlow: AuthFlow; - - constructor(auth: AuthData & { authorizationFlow: AuthFlow }, apiVersion: string) { - this.authorizationData = { - instanceUrl: auth.instanceUrl, - accessToken: auth.accessToken, - }; - this.apiVersion = apiVersion; - this.authorizationFlow = auth.authorizationFlow; +export class SalesforceSDK { + private authorizationData: AuthData; + + private apiVersion: string; + + private authorizationFlow: AuthFlow; + + constructor(auth: AuthData & { authorizationFlow: AuthFlow }, apiVersion: string) { + this.authorizationData = { + instanceUrl: auth.instanceUrl, + accessToken: auth.accessToken, + }; + this.apiVersion = apiVersion; + this.authorizationFlow = auth.authorizationFlow; + } + + public setAuth(auth: AuthData & { authorizationFlow: AuthFlow }): void { + this.authorizationData = { + instanceUrl: auth.instanceUrl, + accessToken: auth.accessToken, + }; + this.authorizationFlow = auth.authorizationFlow; + } + + private getAuthHeader(authOverride?: AuthOverride): Record { + const flow = authOverride?.authorizationFlow || this.authorizationFlow; + const token = authOverride?.accessToken || this.authorizationData.accessToken; + + return flow === 'OAUTH' ? { Authorization: `Bearer ${token}` } : { Authorization: token }; + } + + private buildHeaders( + customHeaders: Record = {}, + authOverride?: AuthOverride, + ): Record { + return { + ...this.getAuthHeader(authOverride), + 'Content-Type': 'application/json', + ...customHeaders, + }; + } + + private async apiCall( + url: string, + method: 'GET' | 'POST' | 'PATCH', + body?: any, + customHeaders?: Record, + authOverride?: AuthOverride, + ): Promise { + const options: RequestInit = { + method, + headers: this.buildHeaders(customHeaders, authOverride), + }; + + if (body) { + options.body = JSON.stringify(body); } - public setAuth(auth: AuthData & { authorizationFlow: AuthFlow }): void { - this.authorizationData = { - instanceUrl: auth.instanceUrl, - accessToken: auth.accessToken, - }; - this.authorizationFlow = auth.authorizationFlow; - } - - private getAuthHeader(authOverride?: AuthOverride): Record { - const flow = authOverride?.authorizationFlow || this.authorizationFlow; - const token = authOverride?.accessToken || this.authorizationData.accessToken; - - return flow === 'OAUTH' - ? { Authorization: `Bearer ${token}` } - : { Authorization: token }; - } - - private buildHeaders(customHeaders: Record = {}, authOverride?: AuthOverride): Record { - return { - ...this.getAuthHeader(authOverride), - 'Content-Type': 'application/json', - ...customHeaders, - }; - } - - private async apiCall( - url: string, - method: 'GET' | 'POST' | 'PATCH', - body?: any, - customHeaders?: Record, - authOverride?: AuthOverride - ): Promise { - const options: RequestInit = { - method, - headers: this.buildHeaders(customHeaders, authOverride), - }; - - if (body) { - options.body = JSON.stringify(body); - } - - const response = await fetch(url, options); - - if (!response.ok) { - throw new Error(`Salesforce API call failed: ${response.status} ${response.statusText}`); - } - - return response.json(); - } - - public async parameterizedSearch( - query: string, - sObject: string, - fields: string[], - customHeaders?: Record, - authOverride?: AuthOverride - ): Promise { - const url = `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/parameterizedSearch/?q=${encodeURIComponent(query)}&sobject=${sObject}&${sObject}.fields=${fields.join(',')}`; - return this.apiCall(url, 'GET', undefined, customHeaders, authOverride); - } - - public async upsertSObject( - salesforceType: string, - recordId: string | null, - data: Record, - customHeaders?: Record, - authOverride?: AuthOverride - ): Promise { - const url = recordId - ? `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}/${recordId}` - : `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}`; - - const method = recordId ? 'PATCH' : 'POST'; - return this.apiCall(url, method, data, customHeaders, authOverride); - } + const response = await fetch(url, options); - public async upsertCustomSObject( - salesforceType: string, - recordId: string | null, - data: Record, - customHeaders?: Record, - authOverride?: AuthOverride - ): Promise { - const url = recordId - ? `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}/${recordId}` - : `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}`; - - const method = recordId ? 'PATCH' : 'POST'; - return this.apiCall(url, method, data, customHeaders, authOverride); + if (!response.ok) { + throw new Error(`Salesforce API call failed: ${response.status} ${response.statusText}`); } - public parseResponse(response: any) { - - } - - public parseSearchResponse(response: any): any { - return response.searchRecords.map((record: any) => ({ - id: record.Id, - isConverted: record.IsConverted, - convertedContactId: record.ConvertedContactId, - isDeleted: record.IsDeleted, - })); - } - - public parseSObjectResponse(response: any): any { - return { - id: response.id, - success: response.success, - errors: response.errors || [], - }; - } -} \ No newline at end of file + return response.json(); + } + + public async parameterizedSearch( + query: string, + sObject: string, + fields: string[], + customHeaders?: Record, + authOverride?: AuthOverride, + ): Promise { + const url = `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/parameterizedSearch/?q=${encodeURIComponent(query)}&sobject=${sObject}&${sObject}.fields=${fields.join(',')}`; + return this.apiCall(url, 'GET', undefined, customHeaders, authOverride); + } + + public async upsertSObject( + salesforceType: string, + recordId: string | null, + data: Record, + customHeaders?: Record, + authOverride?: AuthOverride, + ): Promise { + const url = recordId + ? `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}/${recordId}` + : `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}`; + + const method = recordId ? 'PATCH' : 'POST'; + return this.apiCall(url, method, data, customHeaders, authOverride); + } + + // public async upsertCustomSObject( + // salesforceType: string, + // recordId: string | null, + // data: Record, + // customHeaders?: Record, + // authOverride?: AuthOverride, + // ): Promise { + // const url = recordId + // ? `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}/${recordId}` + // : `${this.authorizationData.instanceUrl}/services/data/v${this.apiVersion}/sobjects/${salesforceType}`; + + // const method = recordId ? 'PATCH' : 'POST'; + // return this.apiCall(url, method, data, customHeaders, authOverride); + // } + + // public parseResponse(response: any) {} + + public parseSearchResponse(response: any): any { + return response.searchRecords.map((record: any) => ({ + id: record.Id, + isConverted: record.IsConverted, + convertedContactId: record.ConvertedContactId, + isDeleted: record.IsDeleted, + })); + } + + public parseSObjectResponse(response: any): any { + return { + id: response.id, + success: response.success, + errors: response.errors || [], + }; + } +} diff --git a/src/v0/destinations/salesforce/transform.js b/src/v0/destinations/salesforce/transform.js index 7e66dd8810..d050d3feca 100644 --- a/src/v0/destinations/salesforce/transform.js +++ b/src/v0/destinations/salesforce/transform.js @@ -7,7 +7,7 @@ const { } = require('@rudderstack/integrations-lib'); const { EventType, MappedToDestinationKey } = require('../../../constants'); const { - SF_API_VERSION, + // SF_API_VERSION, identifyLeadMappingJson, identifyContactMappingJson, ignoredLeadTraits, @@ -15,8 +15,8 @@ const { } = require('./config'); const { removeUndefinedValues, - defaultRequestConfig, - defaultPostRequestConfig, + // defaultRequestConfig, + // defaultPostRequestConfig, getFieldValueFromMessage, constructPayload, getFirstAndLastName, @@ -27,9 +27,12 @@ const { generateErrorObject, isHttpStatusSuccess, } = require('../../util'); -const { salesforceResponseHandler, collectAuthorizationInfo, getAuthHeader } = require('./utils'); -const { handleHttpRequest } = require('../../../adapters/network'); -const { JSON_MIME_TYPE } = require('../../util/constant'); +const { salesforceResponseHandler, collectAuthorizationInfo, + // getAuthHeader +} = require('./utils'); +// const { handleHttpRequest } = require('../../../adapters/network'); +// const { JSON_MIME_TYPE } = require('../../util/constant'); +const { processAxiosResponse } = require('../../../adapters/utils/networkUtils'); // Basic response builder // We pass the parameterMap with any processing-specific key-value pre-populated @@ -38,19 +41,20 @@ const { JSON_MIME_TYPE } = require('../../util/constant'); function responseBuilderSimple( traits, salesforceMap, - authorizationData, + salesforceInstance, mapProperty, mappedToDestination, - authorizationFlow, + // authorizationFlow, ) { + let response; const { salesforceType, salesforceId } = salesforceMap; // if id is valid, do update else create the object // POST for create, PATCH for update - let targetEndpoint = `${authorizationData.instanceUrl}/services/data/v${SF_API_VERSION}/sobjects/${salesforceType}`; - if (salesforceId) { - targetEndpoint += `/${salesforceId}?_HttpMethod=PATCH`; - } + // let targetEndpoint = `${authorizationData.instanceUrl}/services/data/v${SF_API_VERSION}/sobjects/${salesforceType}`; + // if (salesforceId) { + // targetEndpoint += `/${salesforceId}?_HttpMethod=PATCH`; + // } // First name and last name need to be extracted from the name field // get traits from the message @@ -87,44 +91,37 @@ function responseBuilderSimple( delete rawPayload.Id; } - const response = defaultRequestConfig(); + // const response = defaultRequestConfig(); - response.method = defaultPostRequestConfig.requestMethod; - response.headers = { - 'Content-Type': JSON_MIME_TYPE, - ...getAuthHeader({ authorizationFlow, authorizationData }), - }; - response.body.JSON = removeUndefinedValues(rawPayload); - response.endpoint = targetEndpoint; + // response.method = defaultPostRequestConfig.requestMethod; + // response.headers = { + // 'Content-Type': JSON_MIME_TYPE, + // ...getAuthHeader({ authorizationFlow, authorizationData }), + // }; + // response.body.JSON = removeUndefinedValues(rawPayload); + // response.endpoint = targetEndpoint; + + if(salesforceId) { + response = await salesforceInstance.create(salesforceType,removeUndefinedValues(rawPayload),salesforceId); + } + response = await salesforceInstance.create(salesforceType,removeUndefinedValues(rawPayload),null); return response; } // Look up to salesforce using details passed as external id through payload async function getSaleforceIdForRecord( - authorizationData, + salesforceInstance, objectType, identifierType, identifierValue, - { destination, metadata }, + { destination }, authorizationFlow, ) { - const objSearchUrl = `${authorizationData.instanceUrl}/services/data/v${SF_API_VERSION}/parameterizedSearch/?q=${identifierValue}&sobject=${objectType}&in=${identifierType}&${objectType}.fields=id,${identifierType}`; - const { processedResponse: processedsfSearchResponse } = await handleHttpRequest( - 'get', - objSearchUrl, - { - headers: getAuthHeader({ authorizationFlow, authorizationData }), - }, - { - metadata, - destType: 'salesforce', - feature: 'transformation', - endpointPath: '/parameterizedSearch', - requestMethod: 'GET', - module: 'router', - }, - ); + // const objSearchUrl = `${authorizationData.instanceUrl}/services/data/v${SF_API_VERSION}/parameterizedSearch/?q=${identifierValue}&sobject=${objectType}&in=${identifierType}&${objectType}.fields=id,${identifierType}`; + const sfSearchResponse = salesforceInstance.search(objectType, identifierValue, identifierType); + + const processedsfSearchResponse = processAxiosResponse(sfSearchResponse); if (!isHttpStatusSuccess(processedsfSearchResponse.status)) { salesforceResponseHandler( processedsfSearchResponse, @@ -161,7 +158,7 @@ async function getSaleforceIdForRecord( // Default Object type will be "Lead" for backward compatibility async function getSalesforceIdFromPayload( { message, destination, metadata }, - authorizationData, + salesforceInstance, authorizationFlow, ) { // define default map @@ -201,7 +198,7 @@ async function getSalesforceIdFromPayload( // Fetch the salesforce Id if the identifierType is not ID if (identifierType.toUpperCase() !== 'ID') { salesforceId = await getSaleforceIdForRecord( - authorizationData, + salesforceInstance, objectType, identifierType, id, @@ -227,25 +224,17 @@ async function getSalesforceIdFromPayload( if (!email) { throw new InstrumentationError('Invalid Email address for Lead Objet'); } - const leadQueryUrl = `${authorizationData.instanceUrl}/services/data/v${SF_API_VERSION}/parameterizedSearch/?q=${email}&sobject=Lead&Lead.fields=id,IsConverted,ConvertedContactId,IsDeleted`; + // const leadQueryUrl = `${authorizationData.instanceUrl}/services/data/v${SF_API_VERSION}/parameterizedSearch/?q=${email}&sobject=Lead&Lead.fields=id,IsConverted,ConvertedContactId,IsDeleted`; // request configuration will be conditional - const { processedResponse: processedLeadQueryResponse } = await handleHttpRequest( - 'get', - leadQueryUrl, - { - headers: getAuthHeader({ authorizationFlow, authorizationData }), - }, - { - metadata, - destType: 'salesforce', - feature: 'transformation', - endpointPath: '/parameterizedSearch', - requestMethod: 'GET', - module: 'router', - }, + const leadQueryResponse = salesforceInstance.search( + 'Lead', + email, + 'IsConverted,ConvertedContactId,IsDeleted', ); + const processedLeadQueryResponse = processAxiosResponse(leadQueryResponse); + if (!isHttpStatusSuccess(processedLeadQueryResponse.status)) { salesforceResponseHandler( processedLeadQueryResponse, @@ -290,7 +279,7 @@ async function getSalesforceIdFromPayload( // Function for handling identify events async function processIdentify( { message, destination, metadata }, - authorizationData, + salesforceInstance, authorizationFlow, ) { const { Name } = destination.DestinationDefinition; @@ -316,7 +305,7 @@ async function processIdentify( // get salesforce object map const salesforceMaps = await getSalesforceIdFromPayload( { message, destination, metadata }, - authorizationData, + salesforceInstance, authorizationFlow, ); @@ -327,10 +316,10 @@ async function processIdentify( responseBuilderSimple( traits, salesforceMap, - authorizationData, + salesforceInstance, mapProperty, mappedToDestination, - authorizationFlow, + // authorizationFlow, ), ); }); @@ -342,14 +331,14 @@ async function processIdentify( // and event type where applicable async function processSingleMessage( { message, destination, metadata }, - authorizationData, + salesforceInstance, authorizationFlow, ) { let response; if (message.type === EventType.IDENTIFY) { response = await processIdentify( { message, destination, metadata }, - authorizationData, + salesforceInstance, authorizationFlow, ); } else { @@ -393,7 +382,11 @@ const processRouterDest = async (inputs, reqMetadata) => { // unprocessed payload return getSuccessRespEvents( - await processSingleMessage(input, authInfo.authorizationData, authInfo.authorizationFlow), + await processSingleMessage( + input, + authInfo.salesforceInstance, + authInfo.authorizationFlow, + ), [input.metadata], input.destination, ); diff --git a/src/v0/destinations/salesforce/utils.js b/src/v0/destinations/salesforce/utils.js index bbd5216c5b..7f38705aee 100644 --- a/src/v0/destinations/salesforce/utils.js +++ b/src/v0/destinations/salesforce/utils.js @@ -1,3 +1,9 @@ +import { SalesforceClient } from './salesforce-sdk/src/api/salesforceClient'; // Your main SDK entry point +// import { +// SalesforceDestinationConfig, +// OAuthCredentials, +// } from './salesforce-sdk/src/types/salesforceTypes'; + const { RetryableError, ThrottledError, @@ -206,17 +212,19 @@ const getAccessToken = async ({ destination, metadata }) => { const collectAuthorizationInfo = async (event) => { let authorizationFlow; - let authorizationData; + let salesforceInstance; const { Name } = event.destination.DestinationDefinition; const lowerCaseName = Name?.toLowerCase?.(); if (isDefinedAndNotNull(event?.metadata?.secret) || lowerCaseName === SALESFORCE_OAUTH_SANDBOX) { authorizationFlow = OAUTH; - authorizationData = getAccessTokenOauth(event.metadata); + salesforceInstance = new SalesforceClient(event?.metadata?.secret); + // authorizationData = createAuthProvider('oauth', getAccessTokenOauth(event.metadata)); } else { authorizationFlow = LEGACY; - authorizationData = await getAccessToken(event); + salesforceInstance = new SalesforceClient(event?.destination?.Config); + // authorizationData = createAuthProvider('legacy', await getAccessToken()); } - return { authorizationFlow, authorizationData }; + return { authorizationFlow, salesforceInstance }; }; const getAuthHeader = (authInfo) => {