Skip to content
← Public packages

@kody/salesforce

Salesforce REST helpers for identity, SOQL, multi-org routing, and error investigation.

AGENTS.md

144 lines · 4.3 KB · Markdown

@kody/salesforce — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke/dryRun execute snippets, and edge cases. Never paste OAuth client secrets or access tokens. Do not disable live webhooks or jobs.

Auth

ItemValue
Integrationsalesforce (or integrationName / provider=salesforce-*)
Login hostslogin.salesforce.com (prod) / test.salesforce.com (sandbox)
Instance hostexact org host from userinfo (must be added to requiredHosts)
Scopesapi, refresh_token, offline_access (+ more only if needed)

Import paths

ExportImport
root overviewkody:@kody/salesforce
smoke-testkody:@kody/salesforce/smoke-test
get-user-infokody:@kody/salesforce/get-user-info
list-orgskody:@kody/salesforce/list-orgs
resolve-orgkody:@kody/salesforce/resolve-org
querykody:@kody/salesforce/query
list-sobjectskody:@kody/salesforce/list-sobjects
describe-sobjectkody:@kody/salesforce/describe-sobject
get-recordkody:@kody/salesforce/get-record
triage-errorkody:@kody/salesforce/triage-error
create-recordkody:@kody/salesforce/create-record
update-recordkody:@kody/salesforce/update-record
delete-recordkody:@kody/salesforce/delete-record
requestkody:@kody/salesforce/request

Prefer static kody:@kody/salesforce/... imports from execute. Do not lead with packages.invoke.

Smoke test (read-only)

import smokeTest from 'kody:@kody/salesforce/smoke-test'

export default async function main() {
	return await smokeTest()
	// verifies OAuth without returning profile PII
}

Common snippets

import query from 'kody:@kody/salesforce/query'

export default async function main() {
	return await query({
		q: 'SELECT Id, Name, Email FROM Contact ORDER BY LastModifiedDate DESC LIMIT 10',
		// integrationName: 'salesforce-sandbox', // optional; defaults to 'salesforce'
	})
}
import triageError from 'kody:@kody/salesforce/triage-error'

export default async function main() {
	return await triageError({
		error: [
			{
				message: 'Required fields are missing: [LastName]',
				errorCode: 'REQUIRED_FIELD_MISSING',
				fields: ['LastName'],
			},
		],
		sobject: 'Lead',
		organizationId: '00D000000000001AAA',
		orgMap: { '00D000000000001AAA': 'salesforce-acme' },
		dryRun: true,
	})
}
Org map (webhooks / triage)

Persist the map in a private package — live imports of @kody/salesforce cannot use packageStorage:

import { packageStorage } from 'kody:runtime'
import listOrgs from 'kody:@kody/salesforce/list-orgs'
import triageError from 'kody:@kody/salesforce/triage-error'

export async function syncOrgMap() {
	const { map } = await listOrgs()
	await packageStorage().set('org-map', map)
	return map
}

export async function handleWebhook(input) {
	const orgMap = (await packageStorage().get('org-map')) ?? {}
	return triageError({
		error: input.request?.json ?? input,
		orgMap,
	})
}

Prefer one minted webhook URL per client when Salesforce can be pointed per org. One shared URL is fine only if the handler fails closed on unknown org ids.

dryRun / confirm (writes)

Mutating helpers require confirm: true. Pass dryRun: true to inspect a request without sending it. The generic request helper treats GET requests and known read-only paths as safe; all other methods require confirmation. triage-error is read-only: it never writes to Salesforce. Pass dryRun: true to skip org lookups and return the local briefing plus suggested queries.

import createRecord from 'kody:@kody/salesforce/create-record'

export default async function main() {
	return await createRecord({
		sobject: 'Lead',
		fields: {
			FirstName: 'Ada',
			LastName: 'Lovelace',
			Company: 'Analytical Engines',
			Email: 'ada@example.com',
		},
		dryRun: true,
	})
}

Set confirm: true only after the user has explicitly approved the exact mutation target and field values.

Edge cases / fork notes

  • After first successful identity call, add the exact instance host to requiredHosts — wildcards in the connect URL are not expanded.
  • Pass integrationName on every call when more than one org is connected.
  • Never paste Salesforce Connected App secrets or access tokens into chat or logs.