Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/twilio

src/request.ts

66 lines · 1.8 KB · TypeScript
import { twilioRequest } from './client.ts'
import { mutationPreview } from './helpers.ts'
import {
	inputRecord,
	optionalString,
	requiredString,
	type TwilioAuthOptions,
} from './validation.ts'

function normalizeResource(value: string): string {
	const trimmed = value.trim()
	if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
		throw new Error(
			'Pass pageUri for pagination, or a resource path such as /Messages.json. Do not pass arbitrary https URLs.',
		)
	}
	if (trimmed.startsWith('.') || trimmed.startsWith('/')) return trimmed
	return '/' + trimmed
}

/**
 * Escape hatch for unwrapped 2010-04-01 Account resources.
 * POST (and any write) defaults to dry-run and requires confirm: true to execute.
 */
export default async function request(
	params: TwilioAuthOptions & {
		resource?: string
		pageUri?: string
		method?: 'GET' | 'POST'
		query?: Record<string, unknown>
		body?: Record<string, unknown>
		dryRun?: boolean
		confirm?: boolean
	} = {},
) {
	const input = inputRecord(params)
	const method =
		input.method === 'POST' || input.method === 'GET'
			? input.method
			: 'GET'
	const resource = normalizeResource(
		optionalString(input, 'resource') ??
			(method === 'GET' ? '.json' : requiredString(input, 'resource')),
	)
	const pageUri = optionalString(input, 'pageUri')
	const mutating = method === 'POST'

	if (mutating) {
		const preview = mutationPreview(
			input,
			resource,
			(input.body as Record<string, unknown> | undefined) ?? {},
		)
		if (preview) return preview
	}

	const result = await twilioRequest({
		...input,
		resource,
		href: pageUri,
		method,
		query: (input.query as Record<string, unknown> | undefined) ?? {},
		body: (input.body as Record<string, unknown> | undefined) ?? {},
	})
	return { ok: true, method, resource, result }
}