import * as z from "zod" import { defineAction } from "../../../automation/actions" import { getGmailApi } from "@automate.ax/integration-contracts/gmail" import { GMAIL_READ_REQUIREMENT } from "../lib/scopes" import { MESSAGE_IDENTIFIER_SCHEMA } from "@automate.ax/integration-contracts/gmail" /** * Searches Gmail messages using Gmail's standard query syntax. * * Pagination is handled internally until the requested total limit is reached. */ export const searchGmailMessages = defineAction("Search Gmail messages") .describe("Searches Gmail and returns matching message and thread IDs.") .account("google", GMAIL_READ_REQUIREMENT) .input( z.object({ /** Whether messages in Spam and Trash may match. */ includeSpamTrash: z.boolean().optional(), /** Label IDs that every returned message must carry. */ labelIds: z.string().min(1).array().optional(), /** Maximum total results returned across internally fetched pages. */ limit: z.number().int().min(1).max(10_000).optional(), /** Standard Gmail search-box query. */ query: z.string().optional(), }), ) .output(MESSAGE_IDENTIFIER_SCHEMA.array()) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { const gmailApi = getGmailApi(account.secret) const limit = input.limit ?? 100 const messages: { messageId: string; threadId: string }[] = [] let pageToken: string | undefined do { const { data } = await gmailApi.users.messages.list({ includeSpamTrash: input.includeSpamTrash ?? false, labelIds: input.labelIds, maxResults: Math.min(500, limit - messages.length), pageToken, q: input.query, userId: "me", }) messages.push( ...(data.messages ?? []).flatMap((message) => message.id && message.threadId ? [{ messageId: message.id, threadId: message.threadId }] : [], ), ) pageToken = data.nextPageToken ?? undefined } while (pageToken && messages.length < limit) return messages.slice(0, limit) })