CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-slack--bolt

A framework for building Slack apps, fast.

Pending
Overview
Eval results
Files

middleware.mddocs/

Built-in Middleware

Slack Bolt provides built-in middleware functions for filtering events, matching patterns, and processing requests. These middleware functions help route requests to appropriate handlers and provide common functionality.

Capabilities

Event Filtering Middleware

Filter incoming requests to specific event types for focused request processing.

/**
 * Middleware that filters out any event that isn't an action
 * Only allows interactive component actions to pass through
 */
const onlyActions: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that filters out any event that isn't a command
 * Only allows slash commands to pass through
 */
const onlyCommands: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that filters out any event that isn't a Slack event
 * Only allows Events API events to pass through
 */
const onlyEvents: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that filters out any event that isn't an options request
 * Only allows external select menu option requests to pass through
 */
const onlyOptions: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that filters out any event that isn't a shortcut
 * Only allows global and message shortcuts to pass through
 */
const onlyShortcuts: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that filters out any event that isn't a view action
 * Only allows modal view submissions and closures to pass through
 */
const onlyViewActions: Middleware<AnyMiddlewareArgs>;

Utility Middleware

General-purpose middleware for common functionality and request processing.

/**
 * Middleware that automatically acknowledges requests
 * Calls ack() immediately when the middleware is invoked
 */
const autoAcknowledge: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that ignores events from the bot itself
 * Filters out messages and events where the user is the bot
 */
const ignoreSelf: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that only allows direct mentions of the bot
 * Useful for filtering message events to only direct mentions
 */
const directMention: Middleware<SlackEventMiddlewareArgs<'message'>>;

Usage Examples:

import { App, onlyActions, onlyCommands } from "@slack/bolt";

const app = new App({ 
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET 
});

// Use filtering middleware globally
app.use(onlyActions);

// Or use in specific listeners
app.use(onlyCommands, async ({ command, ack, respond }) => {
  await ack();
  await respond(`Received command: ${command.command}`);
});

Pattern Matching Middleware

Match requests against specific patterns for conditional processing.

/**
 * Middleware that matches message text against a pattern
 * @param pattern - String or RegExp pattern to match against message text
 * @returns Middleware that only processes matching messages
 */
function matchMessage(
  pattern: string | RegExp
): Middleware<SlackEventMiddlewareArgs<'message'>>;

/**
 * Middleware that matches slash command names against a pattern
 * @param pattern - String or RegExp pattern to match against command name
 * @returns Middleware that only processes matching commands
 */
function matchCommandName(
  pattern: string | RegExp
): Middleware<SlackCommandMiddlewareArgs>;

/**
 * Middleware that matches event types against a pattern
 * @param pattern - Event type pattern to match
 * @returns Middleware that only processes matching event types
 */
function matchEventType(
  pattern: EventTypePattern
): Middleware<SlackEventMiddlewareArgs>;

/**
 * Middleware that matches actions against constraint criteria
 * @param constraints - Action constraints to match against
 * @returns Middleware that only processes matching actions
 */
function matchConstraints<T>(
  constraints: ActionConstraints
): Middleware<SlackActionMiddlewareArgs>;

/**
 * Middleware that filters messages by subtype
 * @param subtypeValue - Message subtype to match
 * @returns Middleware that only processes messages with matching subtype
 */
function subtype(
  subtypeValue: string
): Middleware<SlackEventMiddlewareArgs<'message'>>;

Usage Examples:

import { App, matchMessage, matchCommandName } from "@slack/bolt";

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET
});

// Match messages containing "hello"
app.use(matchMessage("hello"), async ({ message, say }) => {
  await say(`Hello <@${message.user}>!`);
});

// Match messages with regex pattern
app.use(matchMessage(/ticket-(\d+)/), async ({ message, say, context }) => {
  const ticketId = context.matches?.[1];
  await say(`Looking up ticket ${ticketId}`);
});

// Match specific command names
app.use(matchCommandName("/deploy"), async ({ command, ack, respond }) => {
  await ack();
  await respond("Starting deployment...");
});

// Match multiple command patterns
app.use(matchCommandName(/^\/(help|info)$/), async ({ command, ack, respond }) => {
  await ack();
  await respond("Here's some helpful information...");
});

Utility Middleware

General-purpose middleware for common functionality.

/**
 * Middleware that ignores events from the bot itself
 * Prevents infinite loops when the bot responds to its own messages
 */
const ignoreSelf: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that auto acknowledges the request received
 * Automatically calls ack() if available, then continues to next middleware
 */
const autoAcknowledge: Middleware<AnyMiddlewareArgs>;

/**
 * Middleware that filters out messages that don't start with a direct mention
 * Only allows messages that begin with @bot_user_id
 * @returns Middleware that only processes direct mentions
 */
const directMention: Middleware<SlackEventMiddlewareArgs<'message'>>;

/**
 * Middleware that filters messages by subtype
 * @param subtype - Message subtype to match (e.g., "bot_message", "file_share")
 * @returns Middleware that only processes messages with matching subtype
 */
function subtype(subtype: string): Middleware<SlackEventMiddlewareArgs<'message'>>;

/**
 * Type guard to check if options object contains event middleware options
 * @param optionOrListener - Options object or listener function
 * @returns True if input is SlackEventMiddlewareArgsOptions
 */
function isSlackEventMiddlewareArgsOptions<EventType extends string = string>(
  optionOrListener: SlackEventMiddlewareArgsOptions | Middleware<SlackEventMiddlewareArgs<EventType>>
): optionOrListener is SlackEventMiddlewareArgsOptions;

Usage Examples:

import { 
  App, 
  ignoreSelf, 
  autoAcknowledge, 
  directMention, 
  subtype 
} from "@slack/bolt";

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET
});

// Add ignoreSelf middleware globally
app.use(ignoreSelf);

// Now the bot won't respond to its own messages
app.message("hello", async ({ message, say }) => {
  await say("Hello there!"); // Won't trigger itself
});

// Auto-acknowledge all interactions
app.use(autoAcknowledge);

// Handle direct mentions only
app.message(directMention, async ({ message, say }) => {
  await say(`You mentioned me, <@${message.user}>!`);
});

// Handle only bot messages
app.message(subtype("bot_message"), async ({ message, say }) => {
  // This will only process messages from other bots
  console.log("Received bot message:", message.text);
});

// Handle file share messages
app.message(subtype("file_share"), async ({ message, client }) => {
  // Process file sharing events
  console.log("File shared:", message.files);
});

// Custom ignore middleware example
app.use(async ({ context, body, next }) => {
  // Skip if this is a bot message (alternative to ignoreSelf)
  if (body.event?.bot_id) {
    return;
  }
  await next();
});

Custom Middleware Creation

Create custom middleware functions for specific application needs.

/**
 * Custom middleware function type
 * @param args - Middleware arguments including context, logger, client, and next
 */
type Middleware<Args, CustomContext = StringIndexed> = (
  args: Args & AllMiddlewareArgs<CustomContext>
) => Promise<void>;

interface AllMiddlewareArgs<CustomContext = StringIndexed> {
  /** Request context with bot tokens and user information */
  context: Context & CustomContext;
  /** Logger instance for debugging and monitoring */
  logger: Logger;
  /** Slack Web API client for making API calls */
  client: WebClient;
  /** Function to call next middleware in the chain */
  next: NextFn;
}

Usage Examples:

import { App, Middleware, AnyMiddlewareArgs } from "@slack/bolt";

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET
});

// Custom logging middleware
const loggingMiddleware: Middleware<AnyMiddlewareArgs> = async ({ 
  logger, 
  body, 
  next 
}) => {
  const startTime = Date.now();
  
  logger.info(`Processing ${body.type || 'unknown'} event`);
  
  await next();
  
  const duration = Date.now() - startTime;
  logger.info(`Completed processing in ${duration}ms`);
};

// Custom authorization middleware
const authMiddleware: Middleware<AnyMiddlewareArgs> = async ({
  context,
  client,
  next
}) => {
  // Add custom user data to context
  if (context.userId) {
    context.userData = await getUserData(context.userId);
  }
  
  await next();
};

// Rate limiting middleware
const rateLimitMiddleware: Middleware<AnyMiddlewareArgs> = async ({
  context,
  logger,
  next
}) => {
  const userId = context.userId;
  if (!userId) {
    await next();
    return;
  }
  
  const isAllowed = await checkRateLimit(userId);
  if (!isAllowed) {
    logger.warn(`Rate limit exceeded for user ${userId}`);
    return; // Don't call next(), stopping the middleware chain
  }
  
  await next();
};

// Apply custom middleware
app.use(loggingMiddleware);
app.use(authMiddleware);
app.use(rateLimitMiddleware);

// Conditional middleware
const adminOnlyMiddleware: Middleware<AnyMiddlewareArgs> = async ({
  context,
  client,
  next
}) => {
  const isAdmin = await checkIfAdmin(context.userId);
  if (!isAdmin) {
    return; // Stop processing if not admin
  }
  
  await next();
};

// Use conditional middleware for specific commands
app.command("/admin", adminOnlyMiddleware, async ({ command, ack, respond }) => {
  await ack();
  await respond("Admin command executed!");
});

Middleware Processing

Understanding how middleware chains work in Slack Bolt.

/**
 * Next function type for calling the next middleware in the chain
 */
type NextFn = () => Promise<void>;

/**
 * Middleware execution follows this pattern:
 * 1. Global middleware (added with app.use())
 * 2. Built-in filtering middleware (if applicable)
 * 3. Listener-specific middleware
 * 4. Final listener function
 */

Middleware Chain Example:

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET
});

// 1. Global middleware - runs for all requests
app.use(async ({ logger, next }) => {
  logger.info("Global middleware start");
  await next();
  logger.info("Global middleware end");
});

// 2. Event listener with middleware chain
app.message(
  // Built-in pattern matching middleware
  "hello",
  // Custom middleware for this listener
  async ({ logger, next }) => {
    logger.info("Message middleware start");
    await next();
    logger.info("Message middleware end");
  },
  // Final listener function
  async ({ message, say, logger }) => {
    logger.info("Processing message");
    await say(`Hello <@${message.user}>!`);
  }
);

// Execution order for "hello" message:
// 1. Global middleware start
// 2. Built-in message matching
// 3. Message middleware start  
// 4. Processing message
// 5. Message middleware end
// 6. Global middleware end

Constraint Types

Type definitions for matching constraints used in middleware.

interface ActionConstraints {
  type?: string;
  action_id?: string | RegExp;
  block_id?: string | RegExp;
  callback_id?: string | RegExp;
}

interface OptionsConstraints {
  action_id?: string | RegExp;
  block_id?: string | RegExp;
  callback_id?: string | RegExp;
}

interface ShortcutConstraints {
  type?: 'shortcut' | 'message_action';
  callback_id?: string | RegExp;
}

interface ViewConstraints {
  callback_id?: string | RegExp;
  type?: 'view_submission' | 'view_closed';
}

type EventTypePattern = string | RegExp;

Install with Tessl CLI

npx tessl i tessl/npm-slack--bolt

docs

advanced-features.md

core-application.md

index.md

middleware.md

receivers.md

request-verification.md

tile.json