Skip to main content
Glama
block-validators.ts4.79 kB
import { z } from 'zod'; import type { Block, SectionBlock, DividerBlock, HeaderBlock, ImageBlock, ContextBlock, ActionsBlock, InputBlock, RichTextBlock, VideoBlock, FileBlock, } from '@slack/types'; // Text composition object schemas const plainTextSchema = z.object({ type: z.literal('plain_text'), text: z.string().max(3000), emoji: z.boolean().optional(), }); const mrkdwnTextSchema = z.object({ type: z.literal('mrkdwn'), text: z.string().max(3000), verbatim: z.boolean().optional(), }); const textObjectSchema = z.union([plainTextSchema, mrkdwnTextSchema]); // Common block elements (simplified validation for complex elements) const elementSchema = z.object({ type: z.string(), }).passthrough(); // Strict validation for common blocks export const sectionBlockSchema = z.object({ type: z.literal('section'), text: textObjectSchema.optional(), block_id: z.string().max(255).optional(), fields: z.array(textObjectSchema).max(10).optional(), accessory: z.any().optional(), }) as z.ZodType<SectionBlock>; export const dividerBlockSchema = z.object({ type: z.literal('divider'), block_id: z.string().max(255).optional(), }) satisfies z.ZodType<DividerBlock>; export const headerBlockSchema = z.object({ type: z.literal('header'), text: plainTextSchema, block_id: z.string().max(255).optional(), }) satisfies z.ZodType<HeaderBlock>; export const imageBlockSchema = z.object({ type: z.literal('image'), image_url: z.string().url().max(3000), alt_text: z.string().max(2000), title: plainTextSchema.optional(), block_id: z.string().max(255).optional(), }) satisfies z.ZodType<ImageBlock>; export const contextBlockSchema = z.object({ type: z.literal('context'), elements: z.array(z.any()).min(1).max(10), block_id: z.string().max(255).optional(), }) as z.ZodType<ContextBlock>; // Loose validation for complex blocks export const actionsBlockSchema = z.object({ type: z.literal('actions'), elements: z.array(z.any()).min(1).max(25), block_id: z.string().max(255).optional(), }) as z.ZodType<ActionsBlock>; export const inputBlockSchema = z.object({ type: z.literal('input'), label: plainTextSchema, element: z.any(), dispatch_action: z.boolean().optional(), block_id: z.string().max(255).optional(), hint: plainTextSchema.optional(), optional: z.boolean().optional(), }) as z.ZodType<InputBlock>; export const richTextBlockSchema = z.object({ type: z.literal('rich_text'), elements: z.array(z.any()), block_id: z.string().max(255).optional(), }) as z.ZodType<RichTextBlock>; export const videoBlockSchema = z.object({ type: z.literal('video'), video_url: z.string().url().max(3000), thumbnail_url: z.string().url().max(3000), alt_text: z.string().max(2000), title: plainTextSchema, title_url: z.string().url().max(3000).optional(), author_name: z.string().max(50).optional(), provider_name: z.string().max(50).optional(), provider_icon_url: z.string().url().max(3000).optional(), description: plainTextSchema.optional(), block_id: z.string().max(255).optional(), }) satisfies z.ZodType<VideoBlock>; export const fileBlockSchema = z.object({ type: z.literal('file'), external_id: z.string(), source: z.literal('remote'), block_id: z.string().max(255).optional(), }) satisfies z.ZodType<FileBlock>; // Discriminated union for all block types - cast to satisfy discriminatedUnion requirements const baseSectionBlock = z.object({ type: z.literal('section'), text: textObjectSchema.optional(), block_id: z.string().max(255).optional(), fields: z.array(textObjectSchema).max(10).optional(), accessory: z.any().optional(), }); const baseContextBlock = z.object({ type: z.literal('context'), elements: z.array(z.any()).min(1).max(10), block_id: z.string().max(255).optional(), }); const baseActionsBlock = z.object({ type: z.literal('actions'), elements: z.array(z.any()).min(1).max(25), block_id: z.string().max(255).optional(), }); const baseInputBlock = z.object({ type: z.literal('input'), label: plainTextSchema, element: z.any(), dispatch_action: z.boolean().optional(), block_id: z.string().max(255).optional(), hint: plainTextSchema.optional(), optional: z.boolean().optional(), }); const baseRichTextBlock = z.object({ type: z.literal('rich_text'), elements: z.array(z.any()), block_id: z.string().max(255).optional(), }); export const blockSchema = z.discriminatedUnion('type', [ baseSectionBlock, dividerBlockSchema, headerBlockSchema, imageBlockSchema, baseContextBlock, baseActionsBlock, baseInputBlock, baseRichTextBlock, videoBlockSchema, fileBlockSchema, ]); // Array of blocks with max limit export const blocksArraySchema = z.array(blockSchema).max(50) as z.ZodType<Block[]>;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Hais/slack-bot-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server