Giter Club home page Giter Club logo

slack-bolt's Introduction

blueprint illustration

Slack Bolt

TypeScript framework to build Slack apps in a flash with the latest platform features. Deno port of @slack/bolt

build status language code size issues license version

View on deno.land

Slack Bolt for Deno - TypeScript framework to build Slack apps with Deno rapidly | Product Hunt




Table of Contents

Usage

import "https://deno.land/x/[email protected]/load.ts"
import { App } from "https://deno.land/x/[email protected]/mod.ts"

const app = new App({
    signingSecret: Deno.env.get("SLACK_SIGNING_SECRET"),
    token: Deno.env.get("SLACK_BOT_TOKEN"),
    ignoreSelf: true,
})

app.event("message", async ({ event, say }) => {
    console.log(event)
    await say("pong")
})

await app.start({ port: 3000 })
console.log("๐Ÿฆ• โšก๏ธ")

API

Quirks

OpineReciever and HTTPReceiver/SocketModeReciever req/res types are not compatible. This causes trouble when providing a custom callback for built-in oauth failure / success (if you're not using built-in oauth / not implementing custom callbacks for failure / success, you don't have to worry about this). This requires a type guard (See simpler alternative below).

import { ServerRequest } from "https://deno.land/[email protected]/http/server.ts"
import {
    ParamsDictionary,
    Request as OpineRequest,
    Response as OpineResponse,
} from "https://deno.land/x/[email protected]/mod.ts"

const customCallbackOptions = {
    failure: async (
        req: ServerRequest | OpineRequest<ParamsDictionary, any, any>,
        res?: OpineResponse<any>,
    ) => {
        if (isOpineRequest(req)) {
            // Your custom code here, req is Request<ParamsDictionary, any, any> and res is Response<any> from deno.land/x/opine
            // Example:
            res?.setStatus(500).send(
                "<html><body><h1>OAuth failed!</h1><div>See stderr for errors.</div></body></html>",
            )
        } else {
            // Your custom code here, req is a std/http ServerRequest, res is undefined
            // Example:
            await req.respond({
                status: 500,
                headers: new Headers({
                    "Content-Type": "text/html",
                }),
                body:
                    `<html><body><h1>OAuth failed!</h1><div></div></body></html>`,
            })
        }

        function isOpineRequest(
            _req: ServerRequest | OpineRequest<ParamsDictionary, any, any>,
            res?: OpineResponse<any>,
        ): _req is OpineRequest<ParamsDictionary, any, any> {
            return !!res // If res exists, OpineReciever is being used since only 'req' exists for HTTPReciever and SocketModeReceiver
        }
    },
}

Alternatively, just specify the correct type according to your Receiver (if you don't specify this, its HTTPReceiver by default)

  • For HTTPReceiver (default) / SocketModeReceiver
import { ServerRequest } from "https://deno.land/[email protected]/http/server.ts"
const customCallbackOptions = {
    failure: async (req: ServerRequest) => {
        // Your custom code here
        // Example:
        await req.respond({
            status: 500,
            headers: new Headers({
                "Content-Type": "text/html",
            }),
            body: `<html><body><h1>OAuth failed!</h1><div></div></body></html>`,
        })
    },
}
  • For OpineReceiver
import {
    ParamsDictionary,
    Request as OpineRequest,
    Response as OpineResponse,
} from "https://deno.land/x/[email protected]/mod.ts"

const customCallbackOptions = {
    failure: async (
        req: OpineRequest<ParamsDictionary, any, any>,
        res: OpineResponse<any>,
    ) => {
        // Your custom code here, req is Request<ParamsDictionary, any, any> and res is Response<any> from deno.land/x/opine
        // Example:
        res?.setStatus(500).send(
            "<html><body><h1>OAuth failed!</h1><div>See stderr for errors.</div></body></html>",
        )
    },
}

Supporters

Stargazers repo roster for @khrj/slack-bolt

Forkers repo roster for @khrj/slack-bolt

Related

slack-bolt's People

Contributors

khrj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

slack-bolt's Issues

[Question] The error message and the conditional expression do not seem to match?

About

I think the condition of this code as written is the opposite.

if (signatureHash === hmac.hex()) {
    throw new Error(`${verifyErrorPrefix}: signature mismatch`)
}

If I'm wrong about any part of this, I'd like to know about it ๐Ÿ™‡

Detail

I'm currently using this Bolt library to create a Slack Bot.
I have a question about this message that I sometimes receive during the development process.

[WARN]   Request verification failed: Failed to verify authenticity: signature mismatch

When I checked where this error message was being output, I noticed that the conditional expression was the opposite.

if (signatureHash === hmac.hex()) {

I checked the relevant part of the library for Node.js and the flow described in the documentation, but it looked different from here.

If this is intentional and caused by me missing something, please don't worry about it.
If not, please respond and provide a new version. I would appreciate it if you could respond.

Thanks.

Unable to catch `app_mention` event

If you use the same token and bolt.js, it works fine.

reproduce

import "https://deno.land/x/[email protected]/load.ts";
import { App, LogLevel } from "https://deno.land/x/[email protected]/mod.ts";

const app = new App({
  appToken: Deno.env.get("SLACK_APP_TOKEN"),
  token: Deno.env.get("SLACK_BOT_TOKEN"),
  socketMode: true,
  logLevel: LogLevel.DEBUG,
  convoStore: false,
});

app.event("message", async ({ event, say }: { event: any; say: any }) => {
  console.log(event);
  await say("ok");
});


app.event("app_mention", async ({ event, say }: { event: any; say: any }) => {
  console.log(event);
  await say("shut up");
});

await app.start({ port: 3000 });
console.log("๐Ÿฆ• โšก๏ธ");
deno run --no-check=remote --allow-read --allow-env --allow-net app.ts

result

When I send @app-name in Slack.

ok

log

type is message.

[DEBUG]  socket-mode:SocketModeClient:0 received a message on the WebSocket
[DEBUG]  socket-mode:SocketModeClient:0 calling ack events_api
[DEBUG]  socket-mode:SocketModeClient:0 send() in state: connected,ready
[DEBUG]  socket-mode:SocketModeClient:0 sending message on websocket: {"envelope_id":"57d95ce2-9e94-4664-8c35-5f5192ea4287","payload":{}}
{
  client_msg_id: "c0362a9b-ca77-4050-9559-f72889726d3a",
  type: "message",
  text: "<@U02U6959XR8>",
  user: "UC734HMC4",
  ts: "1642244168.013100",
  team: "TC7E8TQKX",
  blocks: [ { type: "rich_text", block_id: "YUA", elements: [ [Object] ] } ],
  channel: "C02JD5ATBH7",
  event_ts: "1642244168.013100",
  channel_type: "channel"
}
[DEBUG]  web-api:WebClient:0 apiCall('chat.postMessage') start
[DEBUG]  web-api:WebClient:0 will perform http request
[DEBUG]  web-api:WebClient:0 http response received
[DEBUG]  socket-mode:SocketModeClient:0 received a message on the WebSocket
[DEBUG]  socket-mode:SocketModeClient:0 calling ack events_api
[DEBUG]  socket-mode:SocketModeClient:0 send() in state: connected,ready
[DEBUG]  socket-mode:SocketModeClient:0 sending message on websocket: {"envelope_id":"ac93b96b-8f94-4c99-9e0a-c356aa4ee5ee","payload":{}}
[DEBUG]  socket-mode:SocketModeClient:0 received a message on the WebSocket
[DEBUG]  socket-mode:SocketModeClient:0 calling ack events_api
[DEBUG]  socket-mode:SocketModeClient:0 send() in state: connected,ready
[DEBUG]  socket-mode:SocketModeClient:0 sending message on websocket: {"envelope_id":"cb47e532-cbbf-44a7-8842-e3ec7e201f94","payload":{}}

manifest.yml

_metadata:
  major_version: 1
  minor_version: 1
display_information:
  name: pedri
features:
  bot_user:
    display_name: pedri
    always_online: true
oauth_config:
  scopes:
    bot:
      - app_mentions:read
      - chat:write
settings:
  event_subscriptions:
    bot_events:
      - app_mention
  interactivity:
    is_enabled: true
  org_deploy_enabled: false
  socket_mode_enabled: true
  token_rotation_enabled: false

Demo usage code fails

Running the demonstration usage code with no modifications gives the following errors:

error: TS2612 [ERROR]: Property 'resolve' will overwrite the base property in 'Deferred<undefined>'. If this is intentional, add an initializer. Otherwise, add a 'declare' modifier or remove the redundant declaration.
    public readonly resolve!: () => void;
                    ~~~~~~~
    at https://deno.land/x/[email protected]/tools/Deferred.ts:57:21

TS2322 [ERROR]: Type '{ token: string | undefined; text: string; channel: string; } | { token: string | undefined; channel: string; }' is not assignable to type 'ChatPostMessageArguments'.
  Property 'text' is missing in type '{ token: string | undefined; channel: string; }' but required in type 'ChatPostMessageArguments'.
                const postMessageArguments: ChatPostMessageArguments = typeof message === "string"
                      ~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/src/App.ts:762:23

    'text' is declared here.
        text: string
        ~~~~
        at https://deno.land/x/[email protected]/src/methods.ts:948:5

Found 2 errors.

I'm using the following version of deno:

deno 1.11.4+ed16f43 (canary, x86_64-unknown-linux-gnu)
v8 9.1.269.35
typescript 4.3.2

Unable to catch `app_home_opened` event

SSIA

Reproduce

import "https://deno.land/x/[email protected]/load.ts";
import { App, LogLevel } from "https://deno.land/x/[email protected]/mod.ts";

const app = new App({
  token: Deno.env.get("SLACK_BOT_TOKEN"),
  appToken: Deno.env.get("SLACK_APP_TOKEN"),
  socketMode: true,
  logLevel: LogLevel.DEBUG,
  ignoreSelf: true,
});

app.event("app_home_opened", async ({ event, client, logger }) => {
  logger.info("In app home opened");
  try {
    const result = await client.views.publish({
      user_id: event.user,
      view: {
        "type": "home",
        "blocks": [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": `*Welcome home, <@${event.user}> :house:*`,
            },
          },
        ],
      },
    });
    logger.info(result);
  } catch (error) {
    logger.error(error);
  }
});

await app.start();
console.log("Bolt app is runnning");

Result

When I open App Home in Slack, I only get the following log output.

[DEBUG]  socket-mode:SocketModeClient:0 received a message on the WebSocket
[DEBUG]  socket-mode:SocketModeClient:0 calling ack events_api
[DEBUG]  socket-mode:SocketModeClient:0 send() in state: connected,ready
[DEBUG]  socket-mode:SocketModeClient:0 sending message on websocket: {"envelope_id":"f6d38bb7-6712-4278-9eaf-...","payload":{}}

Expected

When I open App Home in Slack, App Home is updated and the following comment is printed in console.

In app home opened

Environment

Versions

deno 1.23.1 (release, aarch64-apple-darwin)
v8 10.4.132.8
typescript 4.7.2

manifest.yml

display_information:
...
features:
  app_home:
    home_tab_enabled: true
    messages_tab_enabled: false
    messages_tab_read_only_enabled: true
  bot_user:
    display_name: VMOperateTool
    always_online: false
  shortcuts:
    ...
  slash_commands:
    ...
oauth_config:
  scopes:
    bot:
      - channels:history
      - chat:write
      - commands
      - groups:history
      - im:history
      - incoming-webhook
      - channels:read
settings:
  event_subscriptions:
    bot_events:
      - app_home_opened
      - message.channels
      - message.groups
      - message.im
  interactivity:
    is_enabled: true
  org_deploy_enabled: false
  socket_mode_enabled: true
  token_rotation_enabled: false

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.