const SF_ACCESS_TOKEN = process.env.SALESFORCE_ACCESS_TOKEN; const SF_CONSUMER_KEY = process.env.SALESFORCE_CONSUMER_KEY; const SF_CONSUMER_SECRET = process.env.SALESFORCE_CONSUMER_SECRET; const SF_INSTANCE_URL = process.env.SALESFORCE_INSTANCE_URL || "https://snokam.my.salesforce.com"; const SF_API_VERSION = "v62.0"; let accessToken: string | null = SF_ACCESS_TOKEN ?? null; async function getAccessToken(): Promise { if (accessToken) { return accessToken; } if (!SF_CONSUMER_KEY || !SF_CONSUMER_SECRET) { throw new Error( "Set SALESFORCE_ACCESS_TOKEN, or SALESFORCE_CONSUMER_KEY + SALESFORCE_CONSUMER_SECRET" ); } const params = new URLSearchParams({ client_id: SF_CONSUMER_KEY, client_secret: SF_CONSUMER_SECRET, grant_type: "client_credentials", }); const response = await fetch(`${SF_INSTANCE_URL}/services/oauth2/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: params, }); if (!response.ok) { const error = await response.text(); throw new Error( `Failed to get access token: ${response.status} - ${error}` ); } const data = await response.json(); accessToken = data.access_token; return accessToken!; } export async function sfQuery(soql: string): Promise { const token = await getAccessToken(); const url = `${SF_INSTANCE_URL}/services/data/${SF_API_VERSION}/query?q=${encodeURIComponent(soql)}`; const response = await fetch(url, { headers: { Authorization: `Bearer ${token}` }, }); if (!response.ok) { const error = await response.text(); throw new Error(`Salesforce query failed: ${response.status} - ${error}`); } const data = await response.json(); return data.records as T[]; }