Skip to content
← Public packages

@kody/salesforce

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

src/update-record.ts

106 lines · 3.0 KB · TypeScript
import { request, salesforceRequestWithResponse } from './request.ts'
import type { JsonRecord } from './types.ts'
import {
	optionalBoolean,
	optionalString,
	requireRecord,
	requireSalesforceId,
	requireSObjectName,
} from './types.ts'

export type UpdateRecordInput = {
	sobject: string
	id: string
	fields: JsonRecord
	instanceUrl?: string
	apiVersion?: string
	/** Saved OAuth integration name. Defaults to `salesforce`. */
	integrationName?: string
	confirm?: boolean
	dryRun?: boolean
}

/**
 * Update a Salesforce record. Requires `confirm: true`, or use `dryRun: true`.
 * @param input.sobject - Salesforce sObject API name.
 * @param input.id - Record id.
 * @param input.fields - Fields to patch.
 * @param input.confirm - Required true to mutate; use dryRun to preview.
 * @returns Update result or dry-run preview.
 * @example
 * import updateRecord from 'kody:@kody/salesforce/update-record'
 * const preview = await updateRecord({
 *   sobject: 'Contact',
 *   id: '003XXXXXXXXXXXXXXX',
 *   fields: { Title: 'Engineer' },
 *   dryRun: true,
 * })
 */
export async function updateRecord(
	input: UpdateRecordInput,
): Promise<JsonRecord> {
	const sobject = requireSObjectName(input.sobject)
	const id = requireSalesforceId(input.id)
	const fields = requireRecord(input.fields, 'fields')

	if (input.dryRun) {
		return request({
			path: `sobjects/${sobject}/${id}`,
			method: 'PATCH',
			body: fields,
			instanceUrl: optionalString(input.instanceUrl, 'instanceUrl'),
			apiVersion: optionalString(input.apiVersion, 'apiVersion'),
			integrationName: optionalString(input.integrationName, 'integrationName'),
			dryRun: true,
		})
	}

	if (input.confirm !== true) {
		throw new Error(
			'Updating a Salesforce record requires confirm: true after explicit user approval, or dryRun: true.',
		)
	}

	const result = await salesforceRequestWithResponse({
		path: `sobjects/${sobject}/${id}`,
		method: 'PATCH',
		body: fields,
		instanceUrl: optionalString(input.instanceUrl, 'instanceUrl'),
		apiVersion: optionalString(input.apiVersion, 'apiVersion'),
		integrationName: optionalString(input.integrationName, 'integrationName'),
		confirm: true,
	})

	return {
		ok: true,
		status: result.status,
		sobject,
		id,
		updatedFields: Object.keys(fields),
	}
}

/**
 * Update a Salesforce record. Requires `confirm: true`, or use `dryRun: true`.
 * @example
 * import updateRecord from 'kody:@kody/salesforce/update-record'
 * const preview = await updateRecord({
 *   sobject: 'Contact',
 *   id: '003XXXXXXXXXXXXXXX',
 *   fields: { Title: 'Engineer' },
 *   dryRun: true,
 * })
 */
export default async function updateRecordEntrypoint(
	params: Partial<UpdateRecordInput> & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'update-record')
	requireSObjectName(input.sobject)
	requireSalesforceId(input.id)
	requireRecord(input.fields, 'fields')
	return updateRecord({
		...(input as UpdateRecordInput),
		confirm: optionalBoolean(input.confirm, 'confirm'),
		dryRun: optionalBoolean(input.dryRun, 'dryRun'),
	})
}