import { CALENDLY_CANCELLATION_SCHEMA, CALENDLY_DATE_TIME_SCHEMA, CALENDLY_INVITEE_NO_SHOW_SCHEMA, CALENDLY_INVITEE_SCHEMA, CALENDLY_SCHEDULED_EVENT_SCHEMA, CALENDLY_URI_SCHEMA, CALENDLY_UUID_SCHEMA, } from "@automate.ax/integration-contracts/calendly" import * as z from "zod" import { defineAction } from "../../../automation/actions" import { CALENDLY_ACCOUNT, CALENDLY_PAGE_INFO_SCHEMA, CALENDLY_PAGE_INPUT_SCHEMA, calendlyAccountRequirement, collectionResponse, compactCalendlyInput, compactCalendlyQuery, getCalendlyApi, resourceResponse, toPage, } from "./lib" const READ_ACCOUNT = calendlyAccountRequirement("scheduled_events:read") const WRITE_ACCOUNT = calendlyAccountRequirement("scheduled_events:write") const INVITEE_INPUT_SCHEMA = z .object({ email: z.email(), firstName: z.string().trim().min(1).optional(), lastName: z.string().trim().min(1).optional(), name: z.string().trim().min(1).optional(), textReminderNumber: z.string().trim().min(1).optional(), timezone: z.string().trim().min(1), }) .refine(({ firstName, name }) => Boolean(firstName || name), { message: "Provide name or firstName.", path: ["name"], }) const QUESTION_AND_ANSWER_INPUT_SCHEMA = z.object({ answer: z.string(), position: z.number().int().min(0), question: z.string(), }) const TRACKING_INPUT_SCHEMA = z.object({ salesforceUuid: z.string().optional(), utmCampaign: z.string().optional(), utmContent: z.string().optional(), utmMedium: z.string().optional(), utmSource: z.string().optional(), utmTerm: z.string().optional(), }) const INVITEE_LOCATION_INPUT_SCHEMA = z.discriminatedUnion("kind", [ z.object({ kind: z.literal("physical"), location: z.string().min(1) }), z.object({ kind: z.literal("inbound_call") }), z.object({ kind: z.literal("outbound_call"), location: z.string().min(1) }), z.object({ kind: z.literal("zoom_conference") }), z.object({ kind: z.literal("google_conference") }), z.object({ kind: z.literal("gotomeeting_conference") }), z.object({ kind: z.literal("microsoft_teams_conference") }), z.object({ kind: z.literal("webex_conference") }), z.object({ kind: z.literal("ask_invitee"), location: z.string().min(1) }), z.object({ kind: z.literal("custom"), location: z.string().min(1) }), ]) export const listCalendlyScheduledEvents = defineAction( "List Calendly scheduled events", ) .describe( "Lists scheduled events for an explicit user, organization, or group.", ) .account(CALENDLY_ACCOUNT, READ_ACCOUNT) .input( CALENDLY_PAGE_INPUT_SCHEMA.extend({ group: CALENDLY_URI_SCHEMA.optional(), inviteeEmail: z.email().optional(), maxStartTime: CALENDLY_DATE_TIME_SCHEMA.optional(), minStartTime: CALENDLY_DATE_TIME_SCHEMA.optional(), organization: CALENDLY_URI_SCHEMA.optional(), sort: z.enum(["start_time:asc", "start_time:desc"]).optional(), status: z.enum(["active", "canceled"]).optional(), user: CALENDLY_URI_SCHEMA.optional(), }).refine( ({ group, organization, user }) => Boolean(group || organization || user), { message: "Provide group, organization, or user.", path: ["user"], }, ), ) .output( z.object({ items: CALENDLY_SCHEDULED_EVENT_SCHEMA.array(), pageInfo: CALENDLY_PAGE_INFO_SCHEMA, }), ) .retry({ replaySafety: "safe" }) .handler(({ account, input }) => getCalendlyApi(account) .request("scheduled_events", { query: compactCalendlyQuery(input), responseSchema: collectionResponse(CALENDLY_SCHEDULED_EVENT_SCHEMA), }) .then(toPage), ) export const getCalendlyScheduledEvent = defineAction( "Get Calendly scheduled event", ) .describe("Retrieves one Calendly scheduled event by UUID.") .account(CALENDLY_ACCOUNT, READ_ACCOUNT) .input(z.object({ eventId: CALENDLY_UUID_SCHEMA })) .output(CALENDLY_SCHEDULED_EVENT_SCHEMA) .retry({ replaySafety: "safe" }) .handler(({ account, input }) => getCalendlyApi(account) .request(`scheduled_events/${encodeURIComponent(input.eventId)}`, { responseSchema: resourceResponse(CALENDLY_SCHEDULED_EVENT_SCHEMA), }) .then(({ resource }) => resource), ) export const listCalendlyEventInvitees = defineAction( "List Calendly event invitees", ) .describe("Lists invitees for one Calendly scheduled event.") .account(CALENDLY_ACCOUNT, READ_ACCOUNT) .input( CALENDLY_PAGE_INPUT_SCHEMA.extend({ email: z.email().optional(), eventId: CALENDLY_UUID_SCHEMA, sort: z .enum(["created_at:asc", "created_at:desc"]) .prefault("created_at:asc"), status: z.enum(["active", "canceled"]).optional(), }), ) .output( z.object({ items: CALENDLY_INVITEE_SCHEMA.array(), pageInfo: CALENDLY_PAGE_INFO_SCHEMA, }), ) .retry({ replaySafety: "safe" }) .handler(({ account, input: { eventId, ...query } }) => getCalendlyApi(account) .request(`scheduled_events/${encodeURIComponent(eventId)}/invitees`, { query: compactCalendlyQuery(query), responseSchema: collectionResponse(CALENDLY_INVITEE_SCHEMA), }) .then(toPage), ) export const getCalendlyEventInvitee = defineAction( "Get Calendly event invitee", ) .describe( "Retrieves an invitee, including Calendly cancel and reschedule URLs.", ) .account(CALENDLY_ACCOUNT, READ_ACCOUNT) .input( z.object({ eventId: CALENDLY_UUID_SCHEMA, inviteeId: CALENDLY_UUID_SCHEMA, }), ) .output(CALENDLY_INVITEE_SCHEMA) .retry({ replaySafety: "safe" }) .handler(({ account, input }) => getCalendlyApi(account) .request( `scheduled_events/${encodeURIComponent(input.eventId)}/invitees/${encodeURIComponent(input.inviteeId)}`, { responseSchema: resourceResponse(CALENDLY_INVITEE_SCHEMA) }, ) .then(({ resource }) => resource), ) export const createCalendlyEventInvitee = defineAction( "Create Calendly event invitee", ) .describe( "Books an invitee directly into a Calendly event type on Standard or above.", ) .account(CALENDLY_ACCOUNT, WRITE_ACCOUNT) .input( z.object({ eventGuests: z.email().array().max(10).optional(), eventType: CALENDLY_URI_SCHEMA, invitee: INVITEE_INPUT_SCHEMA, location: INVITEE_LOCATION_INPUT_SCHEMA.optional(), questionsAndAnswers: QUESTION_AND_ANSWER_INPUT_SCHEMA.array().optional(), startTime: CALENDLY_DATE_TIME_SCHEMA, tracking: TRACKING_INPUT_SCHEMA.optional(), }), ) .output(CALENDLY_INVITEE_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(({ account, input }) => getCalendlyApi(account) .request("invitees", { body: compactCalendlyInput(input), method: "POST", responseSchema: resourceResponse(CALENDLY_INVITEE_SCHEMA), }) .then(({ resource }) => resource), ) export const cancelCalendlyScheduledEvent = defineAction( "Cancel Calendly scheduled event", ) .describe( "Cancels a Calendly event for all invitees and optionally records a reason.", ) .account(CALENDLY_ACCOUNT, WRITE_ACCOUNT) .input( z.object({ eventId: CALENDLY_UUID_SCHEMA, reason: z.string().max(10_000).optional(), }), ) .output(CALENDLY_CANCELLATION_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(({ account, input }) => getCalendlyApi(account) .request( `scheduled_events/${encodeURIComponent(input.eventId)}/cancellation`, { body: compactCalendlyInput({ reason: input.reason }), method: "POST", responseSchema: resourceResponse(CALENDLY_CANCELLATION_SCHEMA), }, ) .then(({ resource }) => resource), ) export const createCalendlyInviteeNoShow = defineAction( "Create Calendly invitee no-show", ) .describe("Marks one Calendly invitee as a no-show.") .account(CALENDLY_ACCOUNT, WRITE_ACCOUNT) .input(z.object({ invitee: CALENDLY_URI_SCHEMA })) .output(CALENDLY_INVITEE_NO_SHOW_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(({ account, input }) => getCalendlyApi(account) .request("invitee_no_shows", { body: input, method: "POST", responseSchema: resourceResponse(CALENDLY_INVITEE_NO_SHOW_SCHEMA), }) .then(({ resource }) => resource), ) export const getCalendlyInviteeNoShow = defineAction( "Get Calendly invitee no-show", ) .describe("Retrieves one Calendly invitee no-show record.") .account(CALENDLY_ACCOUNT, READ_ACCOUNT) .input(z.object({ noShowId: CALENDLY_UUID_SCHEMA })) .output(CALENDLY_INVITEE_NO_SHOW_SCHEMA) .retry({ replaySafety: "safe" }) .handler(({ account, input }) => getCalendlyApi(account) .request(`invitee_no_shows/${encodeURIComponent(input.noShowId)}`, { responseSchema: resourceResponse(CALENDLY_INVITEE_NO_SHOW_SCHEMA), }) .then(({ resource }) => resource), ) export const deleteCalendlyInviteeNoShow = defineAction( "Delete Calendly invitee no-show", ) .describe("Removes the no-show mark from one Calendly invitee.") .account(CALENDLY_ACCOUNT, WRITE_ACCOUNT) .input(z.object({ noShowId: CALENDLY_UUID_SCHEMA })) .output(z.void()) .retry({ replaySafety: "unsafe" }) .handler(({ account, input }) => getCalendlyApi(account).request( `invitee_no_shows/${encodeURIComponent(input.noShowId)}`, { method: "DELETE", responseSchema: z.unknown().transform(() => undefined), }, ), )