Skip to content

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

Package listing

@kody/airtable

src/request.ts

88 lines · 2.8 KB · TypeScript
import { pickAuthInput } from './auth.ts'
import { airtableRequest, airtableUrl, inferOperationFromPath, isMutatingMethod } from './client.ts'
import { AIRTABLE_API_BASE_URL } from './setup.ts'
import type { AirtableAuthInput, JsonRecord } from './types.ts'
import { optionalBoolean, optionalString, requireRecord, requireString } from './types.ts'

export type AirtableRawRequestInput = AirtableAuthInput & {
	path: string
	method?: string
	query?: JsonRecord
	body?: JsonRecord
	confirm?: boolean
	dryRun?: boolean
}

/**
 * Call the Airtable REST API with a saved OAuth integration or personal access
 * token. Unknown and mutating operations require `confirm: true`; use
 * `dryRun: true` to preview.
 * @example
 * import request from 'kody:@kody/airtable/request'
 * const result = await request({ path: '/meta/bases' })
 */
export async function request(input: AirtableRawRequestInput) {
	const path = requireString(input.path, 'path')
	const method = (input.method ?? 'GET').toUpperCase()
	const operation = inferOperationFromPath(method, path)
	const integrationName =
		optionalString(input.integrationName, 'integrationName') ??
		optionalString(input.integration, 'integration')
	const secretName = optionalString(input.secretName, 'secretName')
	const account = optionalString(input.account, 'account')
	const mutating = isMutatingMethod(method)

	if (input.dryRun) {
		return {
			dryRun: true,
			url: airtableUrl(path, input.query),
			apiBaseUrl: AIRTABLE_API_BASE_URL,
			method,
			operation,
			path,
			query: input.query ?? {},
			body: input.body ?? null,
			integrationName: integrationName ?? null,
			secretName: secretName ?? null,
			account: account ?? null,
			readOnly: !mutating,
		}
	}

	if (mutating && input.confirm !== true) {
		throw new Error(
			'This Airtable request may mutate data. Pass confirm: true only after explicit user approval, or use dryRun: true.',
		)
	}

	return airtableRequest({
		path,
		method,
		query: input.query,
		body: input.body,
		operation,
		...pickAuthInput(input),
	})
}

/**
 * Call the Airtable REST API with a saved OAuth integration or personal access
 * token. Mutating methods require `confirm: true`; use `dryRun: true` to preview.
 * @example
 * import request from 'kody:@kody/airtable/request'
 * const result = await request({ path: '/meta/whoami' })
 */
export default async function requestEntrypoint(
	params: Partial<AirtableRawRequestInput> & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'request')
	return request({
		path: requireString(input.path, 'path'),
		method: optionalString(input.method, 'method'),
		query: input.query as JsonRecord | undefined,
		body: input.body as JsonRecord | undefined,
		...pickAuthInput(input),
		confirm: optionalBoolean(input.confirm, 'confirm'),
		dryRun: optionalBoolean(input.dryRun, 'dryRun'),
	})
}