From fa3dd11b116ee131dcbf5e482383bad63fc551ab Mon Sep 17 00:00:00 2001 From: Alissa Renz Date: Wed, 14 Aug 2024 10:12:47 -0700 Subject: [PATCH] Initial submission --- env.sample => .env.sample | 0 .gitignore | 2 +- LICENSE | 2 +- README.md | 105 +++++++++++++++---------- app-oauth.ts | 74 ----------------- app.ts | 69 +++++++++++++--- listeners/actions/index.ts | 8 -- listeners/actions/sample-action.ts | 68 ---------------- listeners/commands/index.ts | 8 -- listeners/commands/sample-command.ts | 13 --- listeners/events/app-home-opened.ts | 35 --------- listeners/events/index.ts | 8 -- listeners/index.ts | 18 ----- listeners/messages/index.ts | 8 -- listeners/messages/sample-message.ts | 12 --- listeners/shortcuts/index.ts | 8 -- listeners/shortcuts/sample-shortcut.ts | 72 ----------------- listeners/views/index.ts | 8 -- listeners/views/sample-view.ts | 21 ----- manifest.json | 64 ++++++++------- package-lock.json | 30 +++---- package.json | 2 +- 22 files changed, 175 insertions(+), 460 deletions(-) rename env.sample => .env.sample (100%) delete mode 100644 app-oauth.ts delete mode 100644 listeners/actions/index.ts delete mode 100644 listeners/actions/sample-action.ts delete mode 100644 listeners/commands/index.ts delete mode 100644 listeners/commands/sample-command.ts delete mode 100644 listeners/events/app-home-opened.ts delete mode 100644 listeners/events/index.ts delete mode 100644 listeners/index.ts delete mode 100644 listeners/messages/index.ts delete mode 100644 listeners/messages/sample-message.ts delete mode 100644 listeners/shortcuts/index.ts delete mode 100644 listeners/shortcuts/sample-shortcut.ts delete mode 100644 listeners/views/index.ts delete mode 100644 listeners/views/sample-view.ts diff --git a/env.sample b/.env.sample similarity index 100% rename from env.sample rename to .env.sample diff --git a/.gitignore b/.gitignore index 85f41f3..aa2699d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules .DS_Store -.env* +.env dist \ No newline at end of file diff --git a/LICENSE b/LICENSE index 3bd622d..fcaabcc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Slack Technologies, Inc. +Copyright (c) 2024 Slack Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ec71b32..129d54d 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,92 @@ -# Bolt for JavaScript (TypeScript) Template App +# Bolt for JavaScript (TypeScript) Custom Function Template -This is a generic Bolt for JavaScript (TypeScript) template app used to build out Slack apps. +This is a Bolt for JavaScript (TypeScript) template app used to build custom functions for +use in [Workflow Builder](https://api.slack.com/start#workflow-builder). -Before getting started, make sure you have a development workspace where you have permissions to install apps. If you don’t have one setup, go ahead and [create one](https://slack.com/create). +## Setup + +Before getting started, first make sure you have a development workspace where +you have permission to install apps. **Please note that the features in this +project require that the workspace be part of +[a Slack paid plan](https://slack.com/pricing).** + +### Developer Program + +Join the [Slack Developer Program](https://api.slack.com/developer-program) for +exclusive access to sandbox environments for building and testing your apps, +tooling, and resources created to help developers build and grow. ## Installation -#### Create a Slack App +### Create a Slack App -1. Open [https://api.slack.com/apps/new](https://api.slack.com/apps/new) and choose "From an app manifest" +1. Open [https://api.slack.com/apps/new](https://api.slack.com/apps/new) and + choose "From an app manifest" 2. Choose the workspace you want to install the application to -3. Copy the contents of [manifest.json](./manifest.json) into the text box that says `*Paste your manifest code here*` (within the JSON tab) and click _Next_ +3. Copy the contents of [manifest.json](./manifest.json) into the text box that + says `*Paste your manifest code here*` (within the JSON tab) and click _Next_ 4. Review the configuration and click _Create_ -5. Click _Install to Workspace_ and _Allow_ on the screen that follows. You'll then be redirected to the App Configuration dashboard. +5. Click _Install_ button and _Allow_ on the screen that follows. You'll then be + redirected to the App Settings dashboard. -#### Environment Variables +### Environment Variables Before you can run the app, you'll need to store some environment variables. -1. Copy `env.sample` to `.env` -2. Open your apps configuration page from [this list](https://api.slack.com/apps), click _OAuth & Permissions_ in the left hand menu, then copy the _Bot User OAuth Token_ into your `.env` file under `SLACK_BOT_TOKEN` -3. Click _Basic Information_ from the left hand menu and follow the steps in the _App-Level Tokens_ section to create an app-level token with the `connections:write` scope. Copy that token into your `.env` as `SLACK_APP_TOKEN`. +1. Rename `.env.sample` to `.env` +2. Open your apps setting page from + [this list](https://api.slack.com/apps), click _OAuth & Permissions_ in the + left hand menu, then copy the _Bot User OAuth Token_ into your `.env` file + under `SLACK_BOT_TOKEN` +3. Click _Basic Information_ from the left hand menu and follow the steps in the + _App-Level Tokens_ section to create an app-level token with the + `connections:write` scope. Copy that token into your `.env` as + `SLACK_APP_TOKEN`. -#### Install Dependencies +### Local Project -`npm install` +```zsh +# Clone this project onto your machine +git clone https://github.com/slack-samples/bolt-ts-custom-function-template.git -#### Run Bolt Server +# Change into this project directory +cd bolt-ts-custom-function-template -`npm start` +# Install dependencies +npm install -## Project Structure - -### `manifest.json` - -`manifest.json` is a configuration for Slack apps. With a manifest, you can create an app with a pre-defined configuration, or adjust the configuration of an existing app. - -### `app.ts` - -`app.ts` is the entry point for the application and is the file you'll run to start the server. This project aims to keep this file as thin as possible, primarily using it as a way to route inbound requests. +# Run Bolt server +npm start +``` -### `/listeners` +### Linting -Every incoming request is routed to a "listener". Inside this directory, we group each listener based on the Slack Platform feature used, so `/listeners/shortcuts` handles incoming [Shortcuts](https://api.slack.com/interactivity/shortcuts) requests, `/listeners/views` handles [View submissions](https://api.slack.com/reference/interaction-payloads/views#view_submission) and so on. +Run ESLint for code formatting and linting: -## App Distribution / OAuth +```zsh +npm run lint +``` -Only implement OAuth if you plan to distribute your application across multiple workspaces. A separate `app-oauth.ts` file can be found with relevant OAuth settings. +## Using Steps in Workflow Builder -When using OAuth, Slack requires a public URL where it can send requests. In this template app, we've used [`ngrok`](https://ngrok.com/download). Checkout [this guide](https://ngrok.com/docs#getting-started-expose) for setting it up. +With your server running, your function is now ready for use in +[Workflow Builder](https://api.slack.com/start#workflow-builder)! Add it as a +custom step in a new or existing workflow, then run the workflow while your app +is running. -Start `ngrok` to access the app on an external network and create a redirect URL for OAuth. +For more information on creating workflows and adding custom steps, read more +[here](https://slack.com/help/articles/17542172840595-Create-a-new-workflow-in-Slack). -``` -ngrok http 3000 -``` +## Project Structure -This output should include a forwarding address for `http` and `https` (we'll use `https`). It should look something like the following: +### `app.ts` -``` -Forwarding https://3cb89939.ngrok.io -> http://localhost:3000 -``` +`app.ts` is the entry point for the application and is the file you'll run to +start the server. This project aims to keep this file as thin as possible, +primarily using it as a way to route inbound requests. -Navigate to **OAuth & Permissions** in your app configuration and click **Add a Redirect URL**. The redirect URL should be set to your `ngrok` forwarding address with the `slack/oauth_redirect` path appended. For example: +### `manifest.json` -``` -https://3cb89939.ngrok.io/slack/oauth_redirect -``` +`manifest.json` is a configuration for Slack apps. With a manifest, you can +create an app with a pre-defined configuration, or adjust the configuration of +an existing app. diff --git a/app-oauth.ts b/app-oauth.ts deleted file mode 100644 index 9376bcb..0000000 --- a/app-oauth.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { App, LogLevel } from '@slack/bolt'; -import { config } from 'dotenv'; -import registerListeners from './listeners'; - -config(); - -// For development purposes only -const tempDB = new Map(); - -const app = new App({ - logLevel: LogLevel.DEBUG, - signingSecret: process.env.SLACK_SIGNING_SECRET, - clientId: process.env.SLACK_CLIENT_ID, - clientSecret: process.env.SLACK_CLIENT_SECRET, - stateSecret: 'my-state-secret', - scopes: ['channels:history', 'chat:write', 'commands'], - installationStore: { - storeInstallation: async (installation) => { - // Org-wide installation - if (installation.isEnterpriseInstall && installation.enterprise !== undefined) { - tempDB.set(installation.enterprise.id, installation); - return; - } - // Single team installation - if (installation.team !== undefined) { - tempDB.set(installation.team.id, installation); - return; - } - throw new Error('Failed saving installation data to installationStore'); - }, - fetchInstallation: async (installQuery) => { - // Org-wide installation lookup - if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) { - return tempDB.get(installQuery.enterpriseId); - } - // Single team installation lookup - if (installQuery.teamId !== undefined) { - return tempDB.get(installQuery.teamId); - } - throw new Error('Failed fetching installation'); - }, - deleteInstallation: async (installQuery) => { - // Org-wide installation deletion - if (installQuery.isEnterpriseInstall && installQuery.enterpriseId !== undefined) { - tempDB.delete(installQuery.enterpriseId); - return; - } - // Single team installation deletion - if (installQuery.teamId !== undefined) { - tempDB.delete(installQuery.teamId); - return; - } - throw new Error('Failed to delete installation'); - }, - }, - installerOptions: { - // If true, /slack/install redirects installers to the Slack Authorize URL - // without rendering the web page with "Add to Slack" button - directInstall: false, - }, -}); - -/** Register Listeners */ -registerListeners(app); - -/** Start Bolt App */ -(async () => { - try { - await app.start(process.env.PORT || 3000); - console.log('⚡️ Bolt app is running! ⚡️'); - } catch (error) { - console.error('Unable to start App', error); - } -})(); diff --git a/app.ts b/app.ts index ee73246..003f1eb 100644 --- a/app.ts +++ b/app.ts @@ -1,8 +1,7 @@ -import { App, LogLevel } from '@slack/bolt'; -import * as dotenv from 'dotenv'; -import registerListeners from './listeners'; +import { App, BlockAction, LogLevel } from '@slack/bolt'; +import { config } from 'dotenv'; -dotenv.config(); +config(); /** Initialization */ const app = new App({ @@ -12,15 +11,65 @@ const app = new App({ logLevel: LogLevel.DEBUG, }); -/** Register Listeners */ -registerListeners(app); +/** Sample Function Listener */ +app.function('sample_function', async ({ client, inputs, fail }) => { + try { + const { user_id } = inputs; + + await client.chat.postMessage({ + channel: user_id as string, + text: 'Click the button to signal the function has completed', + blocks: [ + { + type: 'section', + text: { + type: 'mrkdwn', + text: 'Click the button to signal the function has completed', + }, + accessory: { + type: 'button', + text: { + type: 'plain_text', + text: 'Complete function', + }, + action_id: 'sample_button', + }, + }, + ], + }); + } catch (error) { + console.error(error); + fail({ error: `Failed to handle a function request: ${error}` }); + } +}); + +/** Sample Action Listener */ +app.action('sample_button', async ({ body, client, complete, fail }) => { + const { channel, message, user } = body; + + try { + // Functions should be marked as successfully completed using `complete` or + // as having failed using `fail`, else they'll remain in an 'In progress' state. + // Learn more at https://api.slack.com/automation/interactive-messages + await complete!({ outputs: { user_id: user.id } }); + + await client.chat.update({ + channel: channel!.id, + ts: message!.ts, + text: 'Function completed successfully!', + }); + } catch (error) { + console.error(error); + fail!({ error: `Failed to handle a function request: ${error}` }); + } +}); -/** Start Bolt App */ +/** Start the Bolt App */ (async () => { try { - await app.start(process.env.PORT || 3000); - console.log('⚡️ Bolt app is running! ⚡️'); + await app.start(); + console.log('⚡️ Bolt app is running!'); } catch (error) { - console.error('Unable to start App', error); + console.error('Failed to start the app', error); } })(); diff --git a/listeners/actions/index.ts b/listeners/actions/index.ts deleted file mode 100644 index 8e33899..0000000 --- a/listeners/actions/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { App } from '@slack/bolt'; -import sampleActionCallback from './sample-action'; - -const register = (app: App) => { - app.action('sample_action_id', sampleActionCallback); -}; - -export default { register }; diff --git a/listeners/actions/sample-action.ts b/listeners/actions/sample-action.ts deleted file mode 100644 index 1faa950..0000000 --- a/listeners/actions/sample-action.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { AllMiddlewareArgs, BlockAction, SlackActionMiddlewareArgs } from '@slack/bolt'; - -const sampleActionCallback = async ({ ack, client, body }: - AllMiddlewareArgs & SlackActionMiddlewareArgs) => { - try { - await ack(); - await client.views.update({ - view_id: body.view!.id, - hash: body.view!.hash, - view: { - type: 'modal', - callback_id: 'sample_view_id', - title: { - type: 'plain_text', - text: 'Updated modal title', - }, - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: 'Nice! You updated the modal! :tada:', - }, - }, - { - type: 'image', - image_url: 'https://media.giphy.com/media/SVZGEcYt7brkFUyU90/giphy.gif', - alt_text: 'Yay! The modal was updated', - }, - { - type: 'input', - block_id: 'input_block_id', - label: { - type: 'plain_text', - text: 'What are your hopes and dreams?', - }, - element: { - type: 'plain_text_input', - action_id: 'sample_input_id', - multiline: true, - }, - }, - { - block_id: 'select_channel_block_id', - type: 'input', - label: { - type: 'plain_text', - text: 'Select a channel to message the result to', - }, - element: { - type: 'conversations_select', - action_id: 'sample_dropdown_id', - response_url_enabled: true, - }, - }, - ], - submit: { - type: 'plain_text', - text: 'Submit', - }, - }, - }); - } catch (error) { - console.error(error); - } -}; - -export default sampleActionCallback; diff --git a/listeners/commands/index.ts b/listeners/commands/index.ts deleted file mode 100644 index 8332b9a..0000000 --- a/listeners/commands/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { App } from '@slack/bolt'; -import sampleCommandCallback from './sample-command'; - -const register = (app: App) => { - app.command('/sample-command', sampleCommandCallback); -}; - -export default { register }; diff --git a/listeners/commands/sample-command.ts b/listeners/commands/sample-command.ts deleted file mode 100644 index c736df8..0000000 --- a/listeners/commands/sample-command.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { AllMiddlewareArgs, SlackCommandMiddlewareArgs } from '@slack/bolt'; - -const sampleCommandCallback = async ({ ack, respond }: - AllMiddlewareArgs & SlackCommandMiddlewareArgs) => { - try { - await ack(); - await respond('Responding to the sample command!'); - } catch (error) { - console.error(error); - } -}; - -export default sampleCommandCallback; diff --git a/listeners/events/app-home-opened.ts b/listeners/events/app-home-opened.ts deleted file mode 100644 index acefbee..0000000 --- a/listeners/events/app-home-opened.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AllMiddlewareArgs, SlackEventMiddlewareArgs } from '@slack/bolt'; - -const appHomeOpenedCallback = async ({ client, event }: AllMiddlewareArgs & SlackEventMiddlewareArgs<'app_home_opened'>) => { - // Ignore the `app_home_opened` event for anything but the Home tab - if (event.tab !== 'home') return; - - try { - await client.views.publish({ - user_id: event.user, - view: { - type: 'home', - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: `*Welcome home, <@${event.user}> :house:*`, - }, - }, - { - type: 'section', - text: { - type: 'mrkdwn', - text: 'Learn how home tabs can be more useful and interactive .', - }, - }, - ], - }, - }); - } catch (error) { - console.error(error); - } -}; - -export default appHomeOpenedCallback; diff --git a/listeners/events/index.ts b/listeners/events/index.ts deleted file mode 100644 index 8f3d786..0000000 --- a/listeners/events/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { App } from '@slack/bolt'; -import appHomeOpenedCallback from './app-home-opened'; - -const register = (app: App) => { - app.event('app_home_opened', appHomeOpenedCallback); -}; - -export default { register }; diff --git a/listeners/index.ts b/listeners/index.ts deleted file mode 100644 index fd72673..0000000 --- a/listeners/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { App } from '@slack/bolt'; -import actions from './actions'; -import commands from './commands'; -import events from './events'; -import messages from './messages'; -import shortcuts from './shortcuts'; -import views from './views'; - -const registerListeners = (app: App) => { - actions.register(app); - commands.register(app); - events.register(app); - messages.register(app); - shortcuts.register(app); - views.register(app); -}; - -export default registerListeners; diff --git a/listeners/messages/index.ts b/listeners/messages/index.ts deleted file mode 100644 index 58c8316..0000000 --- a/listeners/messages/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { App } from '@slack/bolt'; -import sampleMessageCallback from './sample-message'; - -const register = (app: App) => { - app.message(/^(hi|hello|hey).*/, sampleMessageCallback); -}; - -export default { register }; diff --git a/listeners/messages/sample-message.ts b/listeners/messages/sample-message.ts deleted file mode 100644 index 7f55198..0000000 --- a/listeners/messages/sample-message.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { AllMiddlewareArgs, SlackEventMiddlewareArgs } from '@slack/bolt'; - -const sampleMessageCallback = async ({ context, say }: AllMiddlewareArgs & SlackEventMiddlewareArgs<'message'>) => { - try { - const greeting = context.matches[0]; - await say(`${greeting}, how are you?`); - } catch (error) { - console.error(error); - } -}; - -export default sampleMessageCallback; diff --git a/listeners/shortcuts/index.ts b/listeners/shortcuts/index.ts deleted file mode 100644 index 1cb9026..0000000 --- a/listeners/shortcuts/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { App } from '@slack/bolt'; -import sampleShortcutCallback from './sample-shortcut'; - -const register = (app: App) => { - app.shortcut('sample_shortcut_id', sampleShortcutCallback); -}; - -export default { register }; diff --git a/listeners/shortcuts/sample-shortcut.ts b/listeners/shortcuts/sample-shortcut.ts deleted file mode 100644 index a055824..0000000 --- a/listeners/shortcuts/sample-shortcut.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { AllMiddlewareArgs, SlackShortcutMiddlewareArgs } from '@slack/bolt'; - -const sampleShortcutCallback = async ({ shortcut, ack, client }: - AllMiddlewareArgs & SlackShortcutMiddlewareArgs) => { - try { - const { trigger_id } = shortcut; - - await ack(); - await client.views.open({ - trigger_id, - view: { - type: 'modal', - callback_id: 'sample_view_id', - title: { - type: 'plain_text', - text: 'Sample modal title', - }, - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: 'Click the button to update the modal', - }, - accessory: { - type: 'button', - text: { - type: 'plain_text', - text: 'Update modal', - }, - action_id: 'sample_action_id', - }, - }, - { - type: 'input', - block_id: 'input_block_id', - label: { - type: 'plain_text', - text: 'What are your hopes and dreams?', - }, - element: { - type: 'plain_text_input', - action_id: 'sample_input_id', - multiline: true, - }, - }, - { - block_id: 'select_channel_block_id', - type: 'input', - label: { - type: 'plain_text', - text: 'Select a channel to message the result to', - }, - element: { - type: 'conversations_select', - action_id: 'sample_dropdown_id', - response_url_enabled: true, - }, - }, - ], - submit: { - type: 'plain_text', - text: 'Submit', - }, - }, - }); - } catch (error) { - console.error(error); - } -}; - -export default sampleShortcutCallback; diff --git a/listeners/views/index.ts b/listeners/views/index.ts deleted file mode 100644 index 2ba3b6a..0000000 --- a/listeners/views/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { App } from '@slack/bolt'; -import sampleViewCallback from './sample-view'; - -const register = (app: App) => { - app.view('sample_view_id', sampleViewCallback); -}; - -export default { register }; diff --git a/listeners/views/sample-view.ts b/listeners/views/sample-view.ts deleted file mode 100644 index ea19bb8..0000000 --- a/listeners/views/sample-view.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AllMiddlewareArgs, SlackViewMiddlewareArgs } from '@slack/bolt'; - -const sampleViewCallback = async ({ ack, view, body, client }: - AllMiddlewareArgs & SlackViewMiddlewareArgs) => { - await ack(); - - try { - const { input_block_id, select_channel_block_id } = view.state.values; - const sampleInputValue = input_block_id.sample_input_id.value; - const sampleConvoValue = select_channel_block_id.sample_dropdown_id.selected_conversation; - - client.chat.postMessage({ - channel: sampleConvoValue || body.user.id, - text: `<@${body.user.id}> submitted the following :sparkles: hopes and dreams :sparkles:: \n\n ${sampleInputValue}`, - }); - } catch (error) { - console.error(error); - } -}; - -export default sampleViewCallback; diff --git a/manifest.json b/manifest.json index dfbe309..750b939 100644 --- a/manifest.json +++ b/manifest.json @@ -1,58 +1,62 @@ { - "_metadata": { - "major_version": 1, - "minor_version": 1 - }, "display_information": { - "name": "Bolt Template App" + "name": "Bolt Custom Function" }, "features": { "app_home": { "home_tab_enabled": true, - "messages_tab_enabled": false, + "messages_tab_enabled": true, "messages_tab_read_only_enabled": true }, "bot_user": { - "display_name": "Bolt Template App", + "display_name": "Bolt Custom Function", "always_online": false - }, - "shortcuts": [ - { - "name": "Run sample shortcut", - "type": "global", - "callback_id": "sample_shortcut_id", - "description": "Runs a sample shortcut" - } - ], - "slash_commands": [ - { - "command": "/sample-command", - "description": "Runs a sample command", - "should_escape": false - } - ] + } }, "oauth_config": { "scopes": { "bot": [ - "channels:history", - "chat:write", - "commands" + "chat:write" ] } }, "settings": { "event_subscriptions": { "bot_events": [ - "app_home_opened", - "message.channels" + "function_executed" ] }, "interactivity": { "is_enabled": true }, - "org_deploy_enabled": false, + "org_deploy_enabled": true, "socket_mode_enabled": true, - "token_rotation_enabled": false + "token_rotation_enabled": false, + "function_runtime": "remote" + }, + "functions": { + "sample_function": { + "title": "Sample function", + "description": "Runs sample function", + "input_parameters": { + "user_id": { + "type": "slack#/types/user_id", + "title": "User", + "description": "Message recipient", + "is_required": true, + "hint": "Select a user in the workspace", + "name": "user_id" + } + }, + "output_parameters": { + "user_id": { + "type": "slack#/types/user_id", + "title": "User", + "description": "User that completed the function", + "is_required": true, + "name": "user_id" + } + } + } } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1b0c1cb..c3de40f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -132,19 +132,19 @@ } }, "@slack/bolt": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/@slack/bolt/-/bolt-3.19.0.tgz", - "integrity": "sha512-P5Yup/PbO8sE5xsuqkBkpSPkxEkfWZ6yo5ZlmBGxRhhoU1usUSU2w0bgZoiDX4WFm7ZX+3x2Dyf4VMa9kzfmVQ==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@slack/bolt/-/bolt-3.21.0.tgz", + "integrity": "sha512-hpE62YRD5SkcMuhSRZgCzHQTT6xyRKw+EDIvC6Dq/d0J1lL8I+OQPTDge55Jd32S8T+vjP/zSiTNJpsH4dGCrA==", "requires": { "@slack/logger": "^4.0.0", "@slack/oauth": "^2.6.2", "@slack/socket-mode": "^1.3.3", "@slack/types": "^2.11.0", - "@slack/web-api": "^6.11.2", + "@slack/web-api": "^6.12.0", "@types/express": "^4.16.1", "@types/promise.allsettled": "^1.0.3", "@types/tsscmp": "^1.0.0", - "axios": "^1.6.0", + "axios": "^1.7.4", "express": "^4.16.4", "path-to-regexp": "^6.2.1", "please-upgrade-node": "^3.2.0", @@ -324,11 +324,11 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "@types/node": { - "version": "20.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", - "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", + "version": "22.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.3.0.tgz", + "integrity": "sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==", "requires": { - "undici-types": "~5.26.4" + "undici-types": "~6.18.2" } }, "@types/promise.allsettled": { @@ -1294,9 +1294,9 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "requires": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -3746,9 +3746,9 @@ } }, "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.18.2.tgz", + "integrity": "sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==" }, "unpipe": { "version": "1.0.0", diff --git a/package.json b/package.json index 7fc3d30..f585793 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "url": "https://github.com/slack-samples/bolt-ts-starter-template/issues" }, "dependencies": { - "@slack/bolt": "^3.19.0", + "@slack/bolt": "^3.21.0", "dotenv": "~16.4.5" }, "devDependencies": {