Skip to content

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

Package listing

@kody/calendly

src/create-invitee.ts

112 lines · 3.6 KB · TypeScript
import { calendlyRequest, calendlyResourceUri } from './client.ts'
import { mapInvitee } from './models.ts'
import type {
	CalendlyAuthInput,
	CalendlyInviteeSummary,
	DryRunResult,
	JsonRecord,
} from './types.ts'
import {
	compactRecord,
	optionalString,
	optionalStringArray,
	requireRecord,
	requireString,
} from './types.ts'
import { requireAuthMode } from './auth.ts'

export type CreateInviteeInput = CalendlyAuthInput & {
	/** Event type uuid or URI. */
	eventType: string
	/** UTC ISO start time. */
	startTime: string
	invitee: {
		name: string
		email: string
		timezone?: string
	}
	eventGuests?: Array<string>
	confirm?: boolean
	dryRun?: boolean
}

/**
 * Create a Calendly invitee (book a time). Requires `confirm: true`, or use
 * `dryRun: true`. Calendly may require a paid plan for `POST /invitees`.
 * @example
 * import createInvitee from 'kody:@kody/calendly/create-invitee'
 * const preview = await createInvitee({
 *   eventType: 'AAAAAAAAAAAAAAAA',
 *   startTime: '2026-06-01T16:00:00Z',
 *   invitee: { name: 'Ada', email: 'ada@example.com', timezone: 'America/Denver' },
 *   dryRun: true,
 * })
 */
export async function createInvitee(
	input: CreateInviteeInput,
): Promise<
	CalendlyInviteeSummary | DryRunResult<{ method: string; path: string; body: JsonRecord }>
> {
	const invitee = requireRecord(input.invitee, 'invitee')
	const body = compactRecord({
		event_type: calendlyResourceUri('event_types', requireString(input.eventType, 'eventType')),
		start_time: requireString(input.startTime, 'startTime'),
		invitee: compactRecord({
			name: requireString(invitee.name, 'invitee.name'),
			email: requireString(invitee.email, 'invitee.email'),
			timezone: optionalString(invitee.timezone, 'invitee.timezone'),
		}),
		event_guests: optionalStringArray(input.eventGuests, 'eventGuests'),
	})
	if (input.dryRun) {
		return { dryRun: true, wouldCall: { method: 'POST', path: '/invitees', body } }
	}
	if (input.confirm !== true) {
		throw new Error(
			'Creating a Calendly invitee requires confirm: true after explicit user approval, or dryRun: true.',
		)
	}
	const result = await calendlyRequest<unknown>({
		...input,
		operation: 'scheduledEvents.write',
		method: 'POST',
		path: '/invitees',
		body,
	})
	return mapInvitee(result.data)
}

/**
 * Create a Calendly invitee (book a time). Requires `confirm: true`, or use `dryRun: true`.
 * @example
 * import createInvitee from 'kody:@kody/calendly/create-invitee'
 * const preview = await createInvitee({
 *   eventType: 'AAA',
 *   startTime: '2026-06-01T16:00:00Z',
 *   invitee: { name: 'Ada', email: 'ada@example.com' },
 *   dryRun: true,
 * })
 */
export default async function createInviteeEntrypoint(
	params: Partial<CreateInviteeInput> & Record<string, unknown> = {},
) {
	const input = requireRecord(params, 'create-invitee')
	const invitee = requireRecord(input.invitee, 'invitee')
	return createInvitee({
		eventType: requireString(input.eventType, 'eventType'),
		startTime: requireString(input.startTime, 'startTime'),
		invitee: {
			name: requireString(invitee.name, 'invitee.name'),
			email: requireString(invitee.email, 'invitee.email'),
			timezone: optionalString(invitee.timezone, 'invitee.timezone'),
		},
		eventGuests: optionalStringArray(input.eventGuests, 'eventGuests'),
		integrationName: optionalString(input.integrationName, 'integrationName'),
		integration: optionalString(input.integration, 'integration'),
		account: optionalString(input.account, 'account'),
		secretName: optionalString(input.secretName, 'secretName'),
		auth: requireAuthMode(input.auth),
		confirm: input.confirm === true,
		dryRun: input.dryRun === true,
	})
}