import type { Client } from "@notionhq/client" import * as z from "zod" import { notionAccount, notionAction, notionOutput } from "../lib" const FILE_UPLOAD_MODE_SCHEMA = z.enum([ "single_part", "multi_part", "external_url", ]) const FILE_UPLOAD_STATUS_SCHEMA = z.enum([ "pending", "uploaded", "expired", "failed", ]) const SEARCH_INPUT_SCHEMA = z.strictObject({ filter: z .union([ z.strictObject({ in_trash: z.boolean().optional(), property: z.literal("object"), value: z.enum(["page", "data_source"]), }), z.strictObject({ in_trash: z.boolean() }), ]) .optional(), page_size: z.number().int().min(1).max(100).optional(), query: z.string().optional(), sort: z .union([ z.strictObject({ direction: z.enum(["ascending", "descending"]), timestamp: z.literal("last_edited_time"), }), z.strictObject({ property: z.literal("relevance") }), ]) .optional(), start_cursor: z.string().nullable().optional(), }) /** Creates a Notion-hosted or externally imported file upload. */ export const createNotionFileUpload = notionAction< Client["fileUploads"]["create"] >({ account: notionAccount.authenticated, allowedKeys: [ "mode", "filename", "content_type", "number_of_parts", "external_url", ], call: async (client, input) => await client.fileUploads.create(input), description: "Creates a single-part, multi-part, or external URL file upload.", inputSchema: z.strictObject({ content_type: z.string().optional(), external_url: z.string().optional(), filename: z.string().optional(), mode: FILE_UPLOAD_MODE_SCHEMA.optional(), number_of_parts: z.number().finite().optional(), }), name: "Create Notion file upload", replaySafety: "unsafe", output: notionOutput.entity("file_upload"), refine: (input) => { if (input.filename && new TextEncoder().encode(input.filename).length > 900) return false if (input.mode === "external_url") { if (!input.external_url) return false try { return new URL(input.external_url).protocol === "https:" } catch { return false } } if (input.external_url !== undefined) return false if (input.mode !== "multi_part") return true return ( Boolean(input.filename) && Number.isInteger(input.number_of_parts) && (input.number_of_parts ?? 0) >= 1 && (input.number_of_parts ?? 0) <= 10_000 ) }, }) /** Sends one file or multi-part segment to a Notion file upload. */ export const sendNotionFileUpload = notionAction( { account: notionAccount.authenticated, allowedKeys: ["file_upload_id", "file", "part_number"], call: async (client, input) => await client.fileUploads.send(input), description: "Sends file bytes to a pending Notion file upload.", name: "Send Notion file upload", replaySafety: "unsafe", output: notionOutput.entity("file_upload"), refine: (input) => new TextEncoder().encode(input.file.filename).length <= 900 && (input.part_number === undefined || (/^[1-9]\d*$/.test(input.part_number) && Number(input.part_number) <= 10_000)), requiredKeys: ["file_upload_id", "file"], }, ) /** Completes a Notion multi-part file upload. */ export const completeNotionFileUpload = notionAction< Client["fileUploads"]["complete"] >({ account: notionAccount.authenticated, allowedKeys: ["file_upload_id"], call: async (client, input) => await client.fileUploads.complete(input), description: "Completes a multi-part file upload after every part is sent.", name: "Complete Notion file upload", replaySafety: "unsafe", output: notionOutput.entity("file_upload"), requiredKeys: ["file_upload_id"], }) /** Retrieves the status of a Notion file upload. */ export const getNotionFileUpload = notionAction< Client["fileUploads"]["retrieve"] >({ account: notionAccount.authenticated, allowedKeys: ["file_upload_id"], call: async (client, input) => await client.fileUploads.retrieve(input), description: "Retrieves status and metadata for one file upload.", name: "Get Notion file upload", replaySafety: "safe", output: notionOutput.entity("file_upload"), requiredKeys: ["file_upload_id"], }) /** Lists Notion file uploads visible to the connected account. */ export const listNotionFileUploads = notionAction< Client["fileUploads"]["list"] >({ account: notionAccount.authenticated, allowedKeys: ["status", "start_cursor", "page_size"], call: async (client, input) => await client.fileUploads.list(input), description: "Lists file uploads by status with cursor pagination.", inputSchema: z.strictObject({ page_size: z.number().int().min(1).max(100).optional(), start_cursor: z.string().nullable().optional(), status: FILE_UPLOAD_STATUS_SCHEMA.optional(), }), name: "List Notion file uploads", replaySafety: "safe", output: notionOutput.list("file_upload"), }) /** Searches pages and data sources shared with the integration. */ export const searchNotion = notionAction({ account: notionAccount.readContent, allowedKeys: ["sort", "query", "start_cursor", "page_size", "filter"], call: async (client, input) => await client.search(input), description: "Searches accessible pages and data sources by title.", inputSchema: SEARCH_INPUT_SCHEMA, name: "Search Notion", replaySafety: "safe", output: notionOutput.list("page_or_data_source"), }) /** Retrieves the bot user represented by the connected credential. */ export const getCurrentNotionUser = notionAction({ account: notionAccount.authenticated, allowedKeys: [], call: async (client, input) => await client.users.me(input), description: "Retrieves the bot user represented by the connected credential.", name: "Get current Notion user", replaySafety: "safe", output: notionOutput.entity("user"), }) /** Retrieves a Notion user by ID. */ export const getNotionUser = notionAction({ account: notionAccount.userInfo, allowedKeys: ["user_id"], call: async (client, input) => await client.users.retrieve(input), description: "Retrieves one user; personal tokens can retrieve only their owner.", name: "Get Notion user", replaySafety: "safe", output: notionOutput.entity("user"), requiredKeys: ["user_id"], }) /** Lists Notion workspace users through OAuth. */ export const listNotionUsers = notionAction({ account: notionAccount.usersList, allowedKeys: ["start_cursor", "page_size"], call: async (client, input) => await client.users.list(input), description: "Lists workspace users through an OAuth connection.", name: "List Notion users", replaySafety: "safe", output: notionOutput.list("user"), }) /** Lists custom emoji visible to the connected workspace. */ export const listNotionCustomEmojis = notionAction< Client["customEmojis"]["list"] >({ account: notionAccount.authenticated, allowedKeys: ["start_cursor", "page_size", "name"], call: async (client, input) => await client.customEmojis.list(input), description: "Lists custom emoji with optional name filtering.", name: "List Notion custom emoji", replaySafety: "safe", output: notionOutput.list("custom_emoji", { requiredKeys: ["id", "name", "url"], }), })