Slack Edge
The slack-edge library is a Slack app development framework designed specifically for the following runtimes:
Not only does it work with the above, but it also functions with the latest versions of Deno, Bun, and Node.js.
This framework draws significant inspiration from Slack's Bolt framework, but its design does not strictly follow the bolt-js blueprint. Key differences include:
- Edge function ready: Out-of-the-box edge function (e.g., Cloudflare Workers) support
- TypeScript focused: Enhances type safety and clarifies typings for developers
- Lazy listener enabled: bolt-python's lazy listener feature is provided out of the box
- Zero additional dependencies: No other dependencies required beyond TypeScript types and slack-web-api-client (our fetch-function-based Slack API client)
Getting Started
Run with Deno
import {
SlackApp,
SlackEdgeAppEnv,
} from "https://deno.land/x/slack_edge@1.0.0/mod.ts";
const app = new SlackApp<SlackEdgeAppEnv>({
env: {
SLACK_SIGNING_SECRET: Deno.env.get("SLACK_SIGNING_SECRET")!,
SLACK_BOT_TOKEN: Deno.env.get("SLACK_BOT_TOKEN"),
SLACK_LOGGING_LEVEL: "DEBUG",
},
});
// Add listeners here
await Deno.serve({ port: 3000 }, async (request) => {
return await app.run(request);
});
You can run the app by:
# Terminal A
deno run --watch --allow-net --allow-env my-app.ts
# Terminal B
brew install cloudflare/cloudflare/cloudflared
cloudflared tunnel --url http://localhost:3000
Run with Deno (Socket Mode: Experimental)
Important Notice: The Socket Mode support provided by slack-edge is still experimental and is not designed to handle reconnections for production-grade applications. It is recommended to use this mode only for local development and testing purposes.
Thanks to Deno's built-in WebSocket implementation, you can quickly and easily run a Socket Mode app as below:
import {
SlackApp,
SlackSocketModeAppEnv,
} from "https://deno.land/x/slack_edge@1.0.0/mod.ts";
const app = new SlackApp<SlackSocketModeAppEnv>({
env: {
SLACK_APP_TOKEN: Deno.env.get("SLACK_APP_TOKEN")!,
SLACK_BOT_TOKEN: Deno.env.get("SLACK_BOT_TOKEN"),
SLACK_LOGGING_LEVEL: "DEBUG",
},
});
// Add listeners here
await app.connect();
setTimeout(() => {}, Number.MAX_SAFE_INTEGER);
You can run this app by deno run --watch --allow-net --allow-env my-app.ts
.
Reference
Middleware
This framework offers ways to globally customize your app's behavior, like you
do when developing web apps. A common example is to attach extra data to the
context
object for following listeners.
Pattern | Description |
---|---|
app.beforeAuthorize | The passed function does something before calling authorize() function. If this method returns SlackResponse , the following middleware and listeners won't be executed. |
app.afterAuthorize / app.use / app.middleware | The passed function does something right after calling authorize() function. If this method returns SlackResponse , the following middleware and listeners won't be executed. |
ack
/ lazy
Functions
You may be unfamiliar with the "lazy listener" concept in this framework. To learn more about it, please read bolt-python's documentation: https://slack.dev/bolt-python/concepts#lazy-listeners
The ack
function must complete within 3 seconds, while the lazy
function can
perform time-consuming tasks. It's important to note that not all request
handlers support the ack or lazy functions. For more information, please refer
to the following table, which covers all the patterns in detail.
Starting from v0.9, if desired, you can execute lazy listeners after the
completion of their ack function. To customize the behavior in this manner, you
can pass startLazyListenerAfterAck: true
as one of the arguments in the App
constructor.
Pattern | Description | ack function |
lazy function |
---|---|---|---|
app.command | The passed function handles a slash command request pattern. If the function returns a message, the message will be posted in the channel where the end-user invoked the command. | ◯ | ◯ |
app.event | The passed function asynchronously does something when an Events API request that matches the constraints comes in. Please note that manually acknowledge a request is unsupported. You can pass only one function, which can be executed as a lazy listener. | x | ◯ |
app.function [experimental] | The passed function asynchronously does something when a "function_executed" event request that matches the constraints comes in. Please note that manually acknowledge a request is unsupported. You can pass only one function, which can be executed as a lazy listener. Also, this feature is still in beta so that the details could be changed on the Slack plaform side until it's GAed. | x | ◯ |
app.message / app.anyMessage | The passed function asynchronously does something when an a message event comes in. Please note that manually acknowledge a request is unsupported. You can pass only one function, which can be executed as a lazy listener. If the message pattern argument can be any of string, regexp, and undefined. When you pass undefined, the listener matches all messages. | x | ◯ |
app.shortcut / app.globalShortcut / app.messageShortcut | The passed function handles a global/message shortcut request pattern. Please note that returning a message text in the ack function does not work for shortcuts. Instead, you can use context.respond for it. |
◯ | ◯ |
app.action | The passed function handles a user interaction on a Block Kit component such as button clicks, item selection in a select menu, and so on. | ◯ | ◯ |
app.options | The passed function handles an external data source reqeust for Block Kit select menus. You cannnot respond to this request pattern asynchronously, so slack-edge enables developers to pass only ack function, which must complete within 3 seconds, here. |
◯ | x |
app.view / app.viewSubmission / app.viewClosed | The passed function handles either a modal data submission or the "Close" button click event. ack function can return various response_action s (errors, update, push, clear) and their associated data. If you want to simply close the modal, you don't need to return anything. |
◯ | ◯ |