Skip to content

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

Package listing

@kentcdodds/google

src/calendar.ts

81 lines · 8.8 KB · TypeScript
import { requestGoogle } from './core.ts'
import type { JsonObject } from './types.ts'
export type CalendarListParams = { account: string; maxResults?: number; pageToken?: string; minAccessRole?: string; showDeleted?: boolean; showHidden?: boolean; fields?: string }
export type CalendarEventsParams = { account: string; calendarId?: string; timeMin?: string; timeMax?: string; maxResults?: number; q?: string; singleEvents?: boolean; orderBy?: string; pageToken?: string; fields?: string }
export type CalendarEventsAcrossCalendarsParams = CalendarEventsParams & { calendarMaxResults?: number; showHiddenCalendars?: boolean }
export type CalendarEventMutationParams = { account: string; calendarId?: string; event?: JsonObject; dryRun?: boolean; sendUpdates?: string }
export type CalendarEventDeleteParams = { account: string; calendarId?: string; eventId: string; sendUpdates?: string }
export type CalendarEventGetParams = { account: string; calendarId?: string; eventId: string; fields?: string }
export type CalendarEventMoveParams = { account: string; calendarId?: string; eventId: string; destination: string; sendUpdates?: string }
export type CalendarEventQuickAddParams = { account: string; calendarId?: string; text: string; sendUpdates?: string }
export type CalendarAclListParams = { account: string; calendarId?: string; maxResults?: number; pageToken?: string; showDeleted?: boolean; syncToken?: string; fields?: string }
export type CalendarGetParams = { account: string; calendarId?: string; fields?: string }
export type CalendarFreeBusyParams = { account: string; request?: JsonObject; items?: Array<{ id: string }>; timeMin?: string; timeMax?: string; timeZone?: string; groupExpansionMax?: number; calendarExpansionMax?: number; fields?: string }
export async function listCalendars(params: CalendarListParams): Promise<JsonObject> { const { maxResults = 50, pageToken, minAccessRole, showDeleted, showHidden, fields } = params; return await requestGoogle({ ...params, api: 'google', path: '/calendar/v3/users/me/calendarList', query: { maxResults, pageToken, minAccessRole, showDeleted, showHidden, fields } }) as JsonObject }
export async function getCalendar(params: CalendarGetParams): Promise<JsonObject> { const { calendarId = 'primary', fields } = params; return await requestGoogle({ ...params, api: 'google', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId), query: { fields } }) as JsonObject }
export async function listEvents(params: CalendarEventsParams): Promise<JsonObject> { const { calendarId = 'primary', timeMin, timeMax, maxResults = 10, q, singleEvents = true, orderBy = singleEvents ? 'startTime' : undefined, pageToken, fields } = params; return await requestGoogle({ ...params, api: 'google', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/events', query: { timeMin, timeMax, maxResults, q, singleEvents, orderBy, pageToken, fields } }) as JsonObject }
export async function listEventsAcrossCalendars(params: CalendarEventsAcrossCalendarsParams): Promise<JsonObject> {
	const { account, calendarMaxResults = 250, showHiddenCalendars = true } = params
	const calendars: Array<{ id: string; summary: string }> = []
	const failures: string[] = []
	let calendarPageToken: string | undefined
	try {
		do {
			const result = await listCalendars({
				account,
				maxResults: calendarMaxResults,
				pageToken: calendarPageToken,
				showHidden: showHiddenCalendars,
			})
			for (const calendar of (result.items || []) as Array<JsonObject>) {
				if (!calendar.id) continue
				calendars.push({
					id: String(calendar.id),
					summary: String(calendar.summary || calendar.id),
				})
			}
			calendarPageToken = result.nextPageToken ? String(result.nextPageToken) : undefined
		} while (calendarPageToken)
	} catch (error) {
		failures.push(error instanceof Error ? error.message : String(error))
	}
	if (!calendars.length) calendars.push({ id: 'primary', summary: 'Primary' })
	const items: JsonObject[] = []
	for (const calendar of calendars) {
		let eventPageToken: string | undefined
		do {
			const result = await listEvents({
				...params,
				calendarId: calendar.id,
				maxResults: params.maxResults ?? 250,
				pageToken: eventPageToken,
			})
			for (const event of (result.items || []) as Array<JsonObject>) {
				items.push({
					...event,
					calendarId: calendar.id,
					calendarSummary: calendar.summary,
				})
			}
			eventPageToken = result.nextPageToken ? String(result.nextPageToken) : undefined
		} while (eventPageToken)
	}
	return { items, calendars, failures }
}
export async function createEvent(params: CalendarEventMutationParams): Promise<JsonObject> { const { calendarId = 'primary', event, dryRun = false, sendUpdates } = params; if (!event || typeof event !== 'object') throw new Error('createEvent requires event.'); if (dryRun) return { dryRun: true, account: params.account, calendarId, event }; return await requestGoogle({ ...params, api: 'google', method: 'POST', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/events', query: { sendUpdates }, body: event }) as JsonObject }
export async function getEvent(params: CalendarEventGetParams): Promise<JsonObject> { const { calendarId = 'primary', eventId, fields } = params; if (!eventId) throw new Error('getEvent requires eventId.'); return await requestGoogle({ ...params, api: 'google', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/events/' + encodeURIComponent(eventId), query: { fields } }) as JsonObject }
export async function updateEvent(params: CalendarEventMutationParams & { eventId: string }): Promise<JsonObject> { const { calendarId = 'primary', eventId, event, dryRun = false, sendUpdates } = params; if (!eventId) throw new Error('updateEvent requires eventId.'); if (!event || typeof event !== 'object') throw new Error('updateEvent requires event.'); if (dryRun) return { dryRun: true, account: params.account, calendarId, eventId, event }; return await requestGoogle({ ...params, api: 'google', method: 'PATCH', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/events/' + encodeURIComponent(eventId), query: { sendUpdates }, body: event }) as JsonObject }
export async function deleteEvent(params: CalendarEventDeleteParams): Promise<void> { const { calendarId = 'primary', eventId, sendUpdates } = params; if (!eventId) throw new Error('deleteEvent requires eventId.'); await requestGoogle({ ...params, api: 'google', method: 'DELETE', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/events/' + encodeURIComponent(eventId), query: { sendUpdates } }) }
export async function moveEvent(params: CalendarEventMoveParams): Promise<JsonObject> { const { calendarId = 'primary', eventId, destination, sendUpdates } = params; if (!eventId) throw new Error('moveEvent requires eventId.'); if (!destination) throw new Error('moveEvent requires destination.'); return await requestGoogle({ ...params, api: 'google', method: 'POST', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/events/' + encodeURIComponent(eventId) + '/move', query: { destination, sendUpdates } }) as JsonObject }
export async function quickAddEvent(params: CalendarEventQuickAddParams): Promise<JsonObject> { const { calendarId = 'primary', text, sendUpdates } = params; if (!text) throw new Error('quickAddEvent requires text.'); return await requestGoogle({ ...params, api: 'google', method: 'POST', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/events/quickAdd', query: { text, sendUpdates } }) as JsonObject }
export async function listCalendarAcl(params: CalendarAclListParams): Promise<JsonObject> { const { calendarId = 'primary', maxResults, pageToken, showDeleted, syncToken, fields } = params; return await requestGoogle({ ...params, api: 'google', path: '/calendar/v3/calendars/' + encodeURIComponent(calendarId) + '/acl', query: { maxResults, pageToken, showDeleted, syncToken, fields } }) as JsonObject }
export async function queryFreeBusy(params: CalendarFreeBusyParams): Promise<JsonObject> { const { request, items, timeMin, timeMax, timeZone, groupExpansionMax, calendarExpansionMax, fields } = params; const body = request || { timeMin, timeMax, timeZone, groupExpansionMax, calendarExpansionMax, items }; if (!request && !items) throw new Error('queryFreeBusy requires request or items.'); return await requestGoogle({ ...params, api: 'google', method: 'POST', path: '/calendar/v3/freeBusy', query: { fields }, body }) as JsonObject }

/**
 * Return the Google Calendar helper namespace for calendars, events, ACL, and free/busy.
 * @example
 * import calendar from 'kody:@kentcdodds/google/calendar'
 * const events = await calendar().listEvents({ account: 'business', maxResults: 5 })
 * // => { items: [...], summary: '...' }
 */
export default function calendar() { return { listCalendars, getCalendar, listEvents, listEventsAcrossCalendars, createEvent, getEvent, updateEvent, deleteEvent, moveEvent, quickAddEvent, listCalendarAcl, queryFreeBusy } }