Skip to content

Commit 92c03b8

Browse files
authored
improvement(salesforce): fixed refresh and added endpoints (#2177)
* added salesforce other tools * modified scope and change salesforce refresh * fixed refresh * remove dup code
1 parent e9d5304 commit 92c03b8

File tree

10 files changed

+1446
-4
lines changed

10 files changed

+1446
-4
lines changed

apps/sim/blocks/blocks/salesforce.ts

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@ export const SalesforceBlock: BlockConfig<SalesforceResponse> = {
4444
{ label: 'Create Task', id: 'create_task' },
4545
{ label: 'Update Task', id: 'update_task' },
4646
{ label: 'Delete Task', id: 'delete_task' },
47+
{ label: 'List Reports', id: 'list_reports' },
48+
{ label: 'Get Report', id: 'get_report' },
49+
{ label: 'Run Report', id: 'run_report' },
50+
{ label: 'List Report Types', id: 'list_report_types' },
51+
{ label: 'List Dashboards', id: 'list_dashboards' },
52+
{ label: 'Get Dashboard', id: 'get_dashboard' },
53+
{ label: 'Refresh Dashboard', id: 'refresh_dashboard' },
54+
{ label: 'Run SOQL Query', id: 'query' },
55+
{ label: 'Get More Query Results', id: 'query_more' },
56+
{ label: 'Describe Object', id: 'describe_object' },
57+
{ label: 'List Objects', id: 'list_objects' },
4758
],
4859
value: () => 'get_accounts',
4960
},
@@ -52,7 +63,7 @@ export const SalesforceBlock: BlockConfig<SalesforceResponse> = {
5263
title: 'Salesforce Account',
5364
type: 'oauth-input',
5465
serviceId: 'salesforce',
55-
requiredScopes: ['api', 'refresh_token', 'openid'],
66+
requiredScopes: ['api', 'refresh_token', 'openid', 'offline_access'],
5667
placeholder: 'Select Salesforce account',
5768
required: true,
5869
},
@@ -367,6 +378,77 @@ export const SalesforceBlock: BlockConfig<SalesforceResponse> = {
367378
placeholder: 'Account or Opportunity ID',
368379
condition: { field: 'operation', value: ['create_task'] },
369380
},
381+
// Report fields
382+
{
383+
id: 'reportId',
384+
title: 'Report ID',
385+
type: 'short-input',
386+
placeholder: 'Report ID',
387+
condition: { field: 'operation', value: ['get_report', 'run_report'] },
388+
required: true,
389+
},
390+
{
391+
id: 'folderName',
392+
title: 'Folder Name',
393+
type: 'short-input',
394+
placeholder: 'Filter by folder name',
395+
condition: { field: 'operation', value: ['list_reports', 'list_dashboards'] },
396+
},
397+
{
398+
id: 'searchTerm',
399+
title: 'Search Term',
400+
type: 'short-input',
401+
placeholder: 'Search reports by name',
402+
condition: { field: 'operation', value: ['list_reports'] },
403+
},
404+
{
405+
id: 'includeDetails',
406+
title: 'Include Details',
407+
type: 'short-input',
408+
placeholder: 'Include detail rows (true/false)',
409+
condition: { field: 'operation', value: ['run_report'] },
410+
},
411+
{
412+
id: 'filters',
413+
title: 'Report Filters',
414+
type: 'long-input',
415+
placeholder: 'JSON array of report filters',
416+
condition: { field: 'operation', value: ['run_report'] },
417+
},
418+
// Dashboard fields
419+
{
420+
id: 'dashboardId',
421+
title: 'Dashboard ID',
422+
type: 'short-input',
423+
placeholder: 'Dashboard ID',
424+
condition: { field: 'operation', value: ['get_dashboard', 'refresh_dashboard'] },
425+
required: true,
426+
},
427+
// Query fields
428+
{
429+
id: 'query',
430+
title: 'SOQL Query',
431+
type: 'long-input',
432+
placeholder: 'SELECT Id, Name FROM Account LIMIT 10',
433+
condition: { field: 'operation', value: ['query'] },
434+
required: true,
435+
},
436+
{
437+
id: 'nextRecordsUrl',
438+
title: 'Next Records URL',
439+
type: 'short-input',
440+
placeholder: 'URL from previous query response',
441+
condition: { field: 'operation', value: ['query_more'] },
442+
required: true,
443+
},
444+
{
445+
id: 'objectName',
446+
title: 'Object Name',
447+
type: 'short-input',
448+
placeholder: 'API name (e.g., Account, Lead, Custom_Object__c)',
449+
condition: { field: 'operation', value: ['describe_object'] },
450+
required: true,
451+
},
370452
// Long-input fields at the bottom
371453
{
372454
id: 'description',
@@ -418,6 +500,17 @@ export const SalesforceBlock: BlockConfig<SalesforceResponse> = {
418500
'salesforce_create_task',
419501
'salesforce_update_task',
420502
'salesforce_delete_task',
503+
'salesforce_list_reports',
504+
'salesforce_get_report',
505+
'salesforce_run_report',
506+
'salesforce_list_report_types',
507+
'salesforce_list_dashboards',
508+
'salesforce_get_dashboard',
509+
'salesforce_refresh_dashboard',
510+
'salesforce_query',
511+
'salesforce_query_more',
512+
'salesforce_describe_object',
513+
'salesforce_list_objects',
421514
],
422515
config: {
423516
tool: (params) => {
@@ -470,6 +563,28 @@ export const SalesforceBlock: BlockConfig<SalesforceResponse> = {
470563
return 'salesforce_update_task'
471564
case 'delete_task':
472565
return 'salesforce_delete_task'
566+
case 'list_reports':
567+
return 'salesforce_list_reports'
568+
case 'get_report':
569+
return 'salesforce_get_report'
570+
case 'run_report':
571+
return 'salesforce_run_report'
572+
case 'list_report_types':
573+
return 'salesforce_list_report_types'
574+
case 'list_dashboards':
575+
return 'salesforce_list_dashboards'
576+
case 'get_dashboard':
577+
return 'salesforce_get_dashboard'
578+
case 'refresh_dashboard':
579+
return 'salesforce_refresh_dashboard'
580+
case 'query':
581+
return 'salesforce_query'
582+
case 'query_more':
583+
return 'salesforce_query_more'
584+
case 'describe_object':
585+
return 'salesforce_describe_object'
586+
case 'list_objects':
587+
return 'salesforce_list_objects'
473588
default:
474589
throw new Error(`Unknown operation: ${params.operation}`)
475590
}

apps/sim/lib/auth/auth.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,32 @@ export const auth = betterAuth({
9898
},
9999
},
100100
},
101+
account: {
102+
create: {
103+
after: async (account) => {
104+
// Salesforce doesn't return expires_in in its token response (unlike other OAuth providers).
105+
// We set a default 2-hour expiration so token refresh logic works correctly.
106+
if (account.providerId === 'salesforce' && !account.accessTokenExpiresAt) {
107+
const twoHoursFromNow = new Date(Date.now() + 2 * 60 * 60 * 1000)
108+
try {
109+
await db
110+
.update(schema.account)
111+
.set({ accessTokenExpiresAt: twoHoursFromNow })
112+
.where(eq(schema.account.id, account.id))
113+
logger.info(
114+
'[databaseHooks.account.create.after] Set default expiration for Salesforce token',
115+
{ accountId: account.id, expiresAt: twoHoursFromNow }
116+
)
117+
} catch (error) {
118+
logger.error(
119+
'[databaseHooks.account.create.after] Failed to set Salesforce token expiration',
120+
{ accountId: account.id, error }
121+
)
122+
}
123+
}
124+
},
125+
},
126+
},
101127
session: {
102128
create: {
103129
before: async (session) => {
@@ -841,9 +867,10 @@ export const auth = betterAuth({
841867
authorizationUrl: 'https://login.salesforce.com/services/oauth2/authorize',
842868
tokenUrl: 'https://login.salesforce.com/services/oauth2/token',
843869
userInfoUrl: 'https://login.salesforce.com/services/oauth2/userinfo',
844-
scopes: ['api', 'refresh_token', 'openid'],
870+
scopes: ['api', 'refresh_token', 'openid', 'offline_access'],
845871
pkce: true,
846872
prompt: 'consent',
873+
accessType: 'offline',
847874
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/salesforce`,
848875
getUserInfo: async (tokens) => {
849876
try {

apps/sim/lib/oauth/oauth.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
840840
providerId: 'salesforce',
841841
icon: (props) => SalesforceIcon(props),
842842
baseProviderIcon: (props) => SalesforceIcon(props),
843-
scopes: ['api', 'refresh_token', 'openid'],
843+
scopes: ['api', 'refresh_token', 'openid', 'offline_access'],
844844
},
845845
},
846846
defaultService: 'salesforce',
@@ -1427,7 +1427,7 @@ function getProviderAuthConfig(provider: string): ProviderAuthConfig {
14271427
clientId,
14281428
clientSecret,
14291429
useBasicAuth: false,
1430-
supportsRefreshTokenRotation: false,
1430+
supportsRefreshTokenRotation: true,
14311431
}
14321432
}
14331433
case 'shopify': {
@@ -1546,9 +1546,15 @@ export async function refreshOAuthToken(
15461546

15471547
logger.error('Token refresh failed:', {
15481548
status: response.status,
1549+
statusText: response.statusText,
15491550
error: errorText,
15501551
parsedError: errorData,
15511552
providerId,
1553+
tokenEndpoint: config.tokenEndpoint,
1554+
hasClientId: !!config.clientId,
1555+
hasClientSecret: !!config.clientSecret,
1556+
hasRefreshToken: !!refreshToken,
1557+
refreshTokenPrefix: refreshToken ? `${refreshToken.substring(0, 10)}...` : 'none',
15521558
})
15531559
throw new Error(`Failed to refresh token: ${response.status} ${errorText}`)
15541560
}

apps/sim/tools/registry.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,12 +928,23 @@ import {
928928
salesforceDeleteLeadTool,
929929
salesforceDeleteOpportunityTool,
930930
salesforceDeleteTaskTool,
931+
salesforceDescribeObjectTool,
931932
salesforceGetAccountsTool,
932933
salesforceGetCasesTool,
933934
salesforceGetContactsTool,
935+
salesforceGetDashboardTool,
934936
salesforceGetLeadsTool,
935937
salesforceGetOpportunitiesTool,
938+
salesforceGetReportTool,
936939
salesforceGetTasksTool,
940+
salesforceListDashboardsTool,
941+
salesforceListObjectsTool,
942+
salesforceListReportsTool,
943+
salesforceListReportTypesTool,
944+
salesforceQueryMoreTool,
945+
salesforceQueryTool,
946+
salesforceRefreshDashboardTool,
947+
salesforceRunReportTool,
937948
salesforceUpdateAccountTool,
938949
salesforceUpdateCaseTool,
939950
salesforceUpdateContactTool,
@@ -2275,6 +2286,17 @@ export const tools: Record<string, ToolConfig> = {
22752286
salesforce_create_task: salesforceCreateTaskTool,
22762287
salesforce_update_task: salesforceUpdateTaskTool,
22772288
salesforce_delete_task: salesforceDeleteTaskTool,
2289+
salesforce_list_reports: salesforceListReportsTool,
2290+
salesforce_get_report: salesforceGetReportTool,
2291+
salesforce_run_report: salesforceRunReportTool,
2292+
salesforce_list_report_types: salesforceListReportTypesTool,
2293+
salesforce_list_dashboards: salesforceListDashboardsTool,
2294+
salesforce_get_dashboard: salesforceGetDashboardTool,
2295+
salesforce_refresh_dashboard: salesforceRefreshDashboardTool,
2296+
salesforce_query: salesforceQueryTool,
2297+
salesforce_query_more: salesforceQueryMoreTool,
2298+
salesforce_describe_object: salesforceDescribeObjectTool,
2299+
salesforce_list_objects: salesforceListObjectsTool,
22782300
pylon_list_issues: pylonListIssuesTool,
22792301
pylon_create_issue: pylonCreateIssueTool,
22802302
pylon_get_issue: pylonGetIssueTool,

0 commit comments

Comments
 (0)