Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add JSDoc to and list out all available builtin middleware functions in the docs #2136

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/_advanced/middleware_listener.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ order: 6
<div class="section-content">
Listener middleware is used for logic across many listener functions (but usually not all of them). They are added as arguments before the listener function in one of the built-in methods. You can add any number of listener middleware before the listener function.

There’s a collection of built-in listener middleware that you can use like `subtype()` for filtering on a message subtype and `directMention()` which filters out any message that doesn’t directly @-mention your bot at the start of a message.
There’s a collection of [built-in listener middleware](reference#built-in-listener-middleware-functions) that you can use like `subtype` for filtering on a message subtype and `directMention` which filters out any message that doesn’t directly @-mention your bot at the start of a message.

But of course, you can write your own middleware for more custom functionality. While writing your own middleware, your function must call `await next()` to pass control to the next middleware, or `throw` to pass an error back up the previously-executed middleware chain.

Expand Down
33 changes: 33 additions & 0 deletions docs/_tutorials/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This guide is intended to detail the Bolt interface–including listeners and th
- [Listener function arguments](#listener-function-arguments)
- [Body and payload references](#body-and-payload-references)
- [Difference from listener middleware](#difference-from-listener-middleware)
- [Built-in listener middleware functions](#built-in-listener-middleware-functions)
- [Initialization options](#initialization-options)
- [Receiver options](#receiver-options)
- [App options](#app-options)
Expand Down Expand Up @@ -79,6 +80,38 @@ The structure of the `payload` and `body` is detailed on the API site:
### Difference from listener middleware
Listener middleware is used to implement logic across many listener functions (though usually not all of them). Listener middleware has the same arguments as the above listener functions, with one distinction: they also have a `next()` function that **must** be called in order to pass the chain of execution. Learn more about listener middleware [in the documentation](/bolt-js/concepts#listener-middleware).

## Built-in listener middleware functions

Bolt offers a variety of built-in listener middleware functions to help simplify development of your Slack applications. These middleware functions implement common patterns to help filter out or focus your own listener function implementations.

These middleware functions are exported from the main `@slack/bolt` package for you to easily `import` in your applications:

```javascript
import { matchMessage } from '@slack/bolt';
app.message(matchMessage('hello'), async ({ message, logger }) => {
// this function will now only execute if "hello" is present in the message
});
```

A complete list of supported listener middleware functions follows.

- `directMention()`: Filters out any message event whose text does not start with an @-mention of the handling app.
- `ignoreSelf()`: Filters out any event that originates from the app.
filmaj marked this conversation as resolved.
Show resolved Hide resolved
- `matchCommandName(pattern)`: Filters out any command whose name does not match the provided `pattern`; `pattern` can be a string or regular expression.
- `matchConstraints(constraint)`: Filters out any event that does not match the properties of the provided `constraint` object. Supported `constraint` object properties include:
- `block_id` and `action_id`: for filtering out `block_action` events that do not match the provided IDs.
- `callback_id`: for filtering out `view_*` events not matching the provided `callback_id`.
- `type`: for filtering out any event `type`s not matching the provided `type`.
- `matchEventType(pattern)`: filters out any event whose `type` does not match the provided `pattern`. `pattern` can be a string or regular expression.
- `matchMessage(pattern)`: filters out any `message` or `app_mention` events whose message contents do not match the provided `pattern`. `pattern` can be a string or regular expression.
- `onlyActions`: Filters out any event that isn't an action.
- `onlyCommands`: Filters out any event that isn't a command.
- `onlyEvents`: Allows for only events to propagate down the middleware chain.
- `onlyOptions`: Filters out any event that isn't a drop-down-options event.
- `onlyShortcuts`: Filters out any event that isn't a shortcut.
- `onlyViewActions`: Filters out any event that isn't a `view_submission` or `view_closed` event.
- `subtype(type)`: Filters out any message event whose `subtype` does not exactly equal the provided `type`.

## Initialization options
Bolt includes a collection of initialization options to customize apps. There are two primary kinds of options: Bolt app options and receiver options. The receiver options may change based on the receiver your app uses. The following receiver options are for the default `HTTPReceiver` (so they'll work as long as you aren't using a custom receiver).

Expand Down
13 changes: 13 additions & 0 deletions src/middleware/builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ export function matchEventType(pattern: EventTypePattern): Middleware<SlackEvent
};
}

// TODO: breaking change: why does this method have to be invoked as a function with no args, while other similar
// method like the `only*` ones do not require that? should make this consistent.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we rename this to onlyNonSelfEvents or something like that, that sounds good to me too. When we make such a change, perhaps having an alias "ignoreSelf" for backward compatibility for a while would be a good way to go.

/**
* Filters out any event originating from the handling app.
*/
export function ignoreSelf(): Middleware<AnyMiddlewareArgs> {
return async (args) => {
const botId = args.context.botId as string;
Expand Down Expand Up @@ -321,6 +326,9 @@ export function ignoreSelf(): Middleware<AnyMiddlewareArgs> {
};
}

/**
* Filters out any message events whose subtype does not match the provided subtype.
*/
export function subtype(subtype1: string): Middleware<SlackEventMiddlewareArgs<'message'>> {
return async ({ message, next }) => {
if (message.subtype === subtype1) {
Expand All @@ -331,6 +339,11 @@ export function subtype(subtype1: string): Middleware<SlackEventMiddlewareArgs<'

const slackLink = /<(?<type>[@#!])?(?<link>[^>|]+)(?:\|(?<label>[^>]+))?>/;

// TODO: breaking change: why does this method have to be invoked as a function with no args, while other similar
// method like the `only*` ones do not require that? should make this consistent.
/**
* Filters out any message event whose text does not start with an @-mention of the handling app.
*/
export function directMention(): Middleware<SlackEventMiddlewareArgs<'message'>> {
return async ({ message, context, next }) => {
// When context does not have a botUserId in it, then this middleware cannot perform its job. Bail immediately.
Expand Down