Skip to content
This repository was archived by the owner on Jul 24, 2019. It is now read-only.

Commit 0414d8f

Browse files
author
Shane DeWael
authored
Merge pull request #67 from shanedewael/fix-export-issues
Fix export issues
2 parents 909fe40 + 4fb1c59 commit 0414d8f

File tree

9 files changed

+150
-77
lines changed

9 files changed

+150
-77
lines changed

.github/maintainers_guide.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,21 @@ documentation is written manually in markdown in `docs/reference.md`.
4646
### Releasing
4747

4848
1. Create the commit for the release:
49+
* Create and checkout a new branch for the release, for example `rel-v1.0.8`.
4950
* Bump the version number in adherence to [Semantic Versioning](http://semver.org/) in `package.json`.
5051
* Commit with a message including the new version number. For example `v1.0.8`.
51-
* Tag the commit with the version number. For example `v1.0.8`.
52+
* Push the branch to your fork (`git push username rel-v1.0.8`).
53+
* Open the PR from your fork to the origin repo. Get code review. Merge the PR.
5254

5355
2. Distribute the release
54-
* Publish to the appropriate package manager. Once you have permission to publish on npm, you
55-
can run `npm publish`.
56-
* Create a GitHub Release. This will also serve as a Changelog for the project. Add a
57-
description of changes to the Changelog. Mention Issue and PR #'s and @-mention
58-
contributors.
56+
* In your local working copy, make sure you fetch from the repo, checkout and update your master branch.
57+
* Make sure the project has been built locally (`npm run build`). It is a good idea to reset the
58+
`/node_modules` directory and use a low LTS version of node (e.g. v4.x).
59+
* Publish to npm. Once you have permission to publish on npm, you can run `npm publish`.
60+
* Create a GitHub Release and the associated git tag. When creating a new release, make sure to
61+
select the commit with the version number as the commit messsage (e.g. `v1.0.8`). This will also
62+
serve as a Changelog for the project. Add a description of changes to the Changelog. Mention Issue
63+
and PR #'s and @-mention contributors.
5964

6065
3. (Slack Internal) Communicate the release internally. Include a link to the GitHub Release.
6166

README.md

Lines changed: 94 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
# Slack Events API adapter for Node and Express
1+
# Slack Events API adapter for Node
22

33
[![Build Status](https://travis-ci.org/slackapi/node-slack-events-api.svg?branch=master)](https://travis-ci.org/slackapi/node-slack-events-api)
44
[![codecov](https://codecov.io/gh/slackapi/node-slack-events-api/branch/master/graph/badge.svg)](https://codecov.io/gh/slackapi/node-slack-events-api)
55

6-
This adapter enhances and simplifies Slack's Events API by incorporating useful best practices,
7-
patterns, and opportunities to abstract out common tasks.
6+
Build your Slack apps by reacting to messages, emojis, files, and many more types of interesting
7+
events in the [Events API](https://api.slack.com/events-api). This package will help you start
8+
with sensible and secure defaults.
89

9-
We wrote a blog that [explains how](https://medium.com/@SlackAPI/enhancing-slacks-events-api-7535827829ab)
10-
the Events API can help you, why we built these tools, and how you can use them to build
11-
production-ready Slack apps.
10+
The adapter gives you a simple and highly configurable Node-style [EventEmitter](https://nodejs.org/dist/latest/docs/api/events.html#events_class_eventemitter) to attach functions
11+
to handle events.
12+
13+
* [Installation](#installation)
14+
* [Configuration](#configuration)
15+
* [Usage](#usage)
16+
* [Examples](#examples)
17+
* [Reference Documentation](#reference_documentation)
18+
* [Support](#support)
19+
20+
---
1221

1322
## Installation
1423

@@ -18,58 +27,91 @@ $ npm install --save @slack/events-api
1827

1928
## Configuration
2029

21-
Before you can use the [Events API](https://api.slack.com/events-api) you must
22-
[create a Slack App](https://api.slack.com/apps/new), and turn on
23-
[Event Subscriptions](https://api.slack.com/events-api#subscriptions).
30+
Get started by [creating a Slack App](https://api.slack.com/apps/new) if you haven't already.
31+
On the **Basic Information** page, in the section for **App Credentials**, note the
32+
**Signing Secret**. You will need it to initialize the adapter.
33+
34+
> ⚠️ As of `v2.0.0`, the Events API adapter no longer accepts legacy verification tokens.
35+
You must pass a signing secret [to verify requests from Slack](https://api.slack.com/docs/verifying-requests-from-slack).
36+
37+
Select the **Event Subscriptions** feature, and enable it. Input a **Request URL**.
38+
39+
![Configuring a request URL](support/event-subscriptions.gif)
40+
41+
<details>
42+
<summary><strong>What's a request URL? How can I get one for development?</strong></summary>
43+
44+
Slack will send requests to your app server each time an event from a subscription is triggered.
45+
In order to reach your server, you have to tell Slack where your app is listening for those
46+
requests. This location is the request URL.
2447

25-
In order to complete the subscription, you will need a **Request URL** that can already respond to a
26-
verification request. This module, combined with the use of a development proxy, can make this
27-
easier for you.
48+
If you're just getting started with development, you may not have a publicly accessible URL for
49+
your app. We recommend using a development proxy, such as [ngrok](https://ngrok.com/) or
50+
[localtunnel](https://localtunnel.github.io/www/), to generate a URL that can forward requests to
51+
your local machine. Once you've installed the development proxy of your choice, run it to begin
52+
forwarding requests to a specific port (for example, 3000).
2853

29-
0. Force the generation of a Signing Secret: If you just created your Slack App, the Basic
30-
Information section of your configuration will not yet have a Signing Secret under App
31-
Credentials. By visiting the Event Subscriptions section and putting a dummy URL into Request
32-
URL, you will get a verification failure, but also there will now be a **Signing Secret**
33-
available in the Basic Information section.
54+
> ngrok: `ngrok http 3000`
3455
35-
> ⚠️ As of `v2.0.0`, the Events API adapter no longer accepts legacy verification tokens. You must pass a signing secret [to verify requests from Slack](https://api.slack.com/docs/verifying-requests-from-slack).
56+
> localtunnel: `lt --port 3000`
3657
37-
1. Start the verification tool:
38-
`./node_modules/.bin/slack-verify --token <signing-secret> [--path=/slack/events] [--port=3000]`. You will
39-
need to substitute your own Verification Token for `<signing-secret>`. You may also want to choose your own
40-
`path` and/or `port`.
58+
![Starting a development proxy](support/ngrok.gif)
4159

42-
2. Start your development proxy. We recommend using [ngrok](https://ngrok.com/) for its stability,
43-
but using a custom subdomain will require a paid plan. Otherwise,
44-
[localtunnel](https://localtunnel.github.io/www/) is an alternative that gives you custom subdomains
45-
for free.
60+
The output should show you a newly generated URL that you can use (ngrok will actually show you two
61+
and we recommend the one that begins with "https"). Let's call this the base URL (for example,
62+
`https://e0e88971.ngrok.io`)
4663

47-
> With ngrok: `ngrok http -subdomain=<projectname> 3000`
64+
To create the request URL, we add the path where our app listens for events onto the end of
65+
the base URL. If you are using the built-in HTTP server it is set to `/slack/events`. In this
66+
example the request URL would be `https://e0e88971.ngrok.io/slack/events`. If you are using the
67+
Express middlware, you can set whichever path you like, just remember to make the path you mount the
68+
middleware into the application the same as the one you configure in Slack.
69+
</details>
4870

49-
> With localtunnel: `lt --port 3000 --subdomain <projectname>`
71+
<br/>
5072

51-
3. Input your Request URL into the Slack App configuration settings, in the Event Subscriptions
52-
section. This URL depends on how you used the previous two commands. For example, using the
53-
default path and the subdomain name "mybot":
73+
<details>
74+
<summary><strong>I'm getting an error about the `challenge` parameter. Help?</strong></summary>
5475

55-
> With ngrok: `https://mybot.ngrok.io/slack/events`
76+
Before you can save the subscription, your app will need to respond to a challenge at your chosen
77+
request URL. I know what you're thinking: 🤔 _How can I respond if I haven't written my app yet?_
78+
This package comes with a command line tool which starts a server that can properly respond to the
79+
challenge. If you're using the development proxy as described above, you can run the tool from
80+
inside your project directory (after this package has been installed) with the following command:
5681

57-
> With localtunnel: `https://mybot.localtunnel.me/slack/events`
82+
```bash
83+
./node_modules/.bin/slack-verify --secret <signing_secret> [--path=/slack/events] [--port=3000]
84+
```
85+
86+
You'll need to substitute your own signing secret for `<signing_secret>`. The path and port values
87+
are optional. If your request URL includes a different path, you should specify it with
88+
`--path=/my/path/here` (no brackets). Similarly, if your development proxy is forwarding requests to
89+
a different port, you should specify it with `--port=8888` (no brackets). If you're using the
90+
defaults, you can ignore everything after `<signing_secret>`. You should **only use the command line
91+
tool in development**. If your app is up and running, the adapter will automatically respond to
92+
challenges.
93+
94+
You might need to click "Retry" in the Request URL input to ask Slack to send the challenge
95+
again. Once the request URL is verified, you can terminate the two processes (command line tool and
96+
development server) with Ctrl+C.
97+
</details>
98+
99+
<br/>
58100

59-
4. Once the verification is complete, you can terminate the two processes (verification tool and
60-
development server). You can proceed to selecting the event types your App needs.
101+
Add each event type your app requires. In the tables below, you may add Workspace events and Bot events.
102+
Once you've selected all the event types, be sure to **Save Changes**.
61103

62-
**NOTE:** This method of responding to the verification request should only be used
63-
**in development**. After you deploy your application to production, you should come back and modify
64-
your Request URL appropriately.
104+
Lastly, if you've added event types that require scopes your app did not previously have, you'll need to
105+
reinstall the app into the workspace(s) from where you'd like Slack to send your app new events. To quickly
106+
install the app to your Development Workspace, visit the **Install App** page.
65107

66108
## Usage
67109

68110
The easiest way to start using the Events API is by using the built-in HTTP server.
69111

70112
```javascript
71-
// Initialize using verification token from environment variables
72-
const createSlackEventAdapter = require('@slack/events-api').createSlackEventAdapter;
113+
// Initialize using signing secret from environment variables
114+
const { createSlackEventAdapter } = require('@slack/events-api');
73115
const slackEvents = createSlackEventAdapter(process.env.SLACK_SIGNING_SECRET);
74116
const port = process.env.PORT || 3000;
75117

@@ -87,7 +129,7 @@ slackEvents.start(port).then(() => {
87129
});
88130
```
89131

90-
**NOTE**: To use the example above, you need to add a Team Event such as `message.im` in the Event
132+
**NOTE**: To use the example above, you need to add a Workspace Event such as `message.im` in the Event
91133
Subscriptions section of your Slack App configuration settings.
92134

93135
### Using with Express
@@ -98,8 +140,8 @@ middleware by calling the `expressMiddleware()` method;
98140
```javascript
99141
const http = require('http');
100142

101-
// Initialize using verification token from environment variables
102-
const createSlackEventAdapter = require('@slack/events-api').createSlackEventAdapter;
143+
// Initialize using signing secret from environment variables
144+
const { createSlackEventAdapter } = require('@slack/events-api');
103145
const slackEvents = createSlackEventAdapter(process.env.SLACK_SIGNING_SECRET);
104146
const port = process.env.PORT || 3000;
105147

@@ -125,18 +167,24 @@ http.createServer(app).listen(port, () => {
125167
});
126168
```
127169

128-
> ⚠️ As of `v2.0.0`, the Events API adapter parses raw request bodies while performing request signing verification. This means developers no longer need to use `body-parser` middleware to parse JSON-encoded requests.
170+
> ⚠️ As of `v2.0.0`, the Events API adapter parses raw request bodies while performing request signing verification. This means apps no longer need to use `body-parser` middleware to parse JSON-encoded requests.
129171
130172
**NOTE**: To use the example above, you need to add a Team Event such as `message.im` in the Event
131173
Subscriptions section of your Slack App configuration settings.
132174

133-
## Documentation
175+
## Examples
176+
177+
* [Greet And React](examples/greet-and-react) - A ready to run sample app that listens for messages and
178+
emoji reactions, and responds to them. It is built on top of the [Express](https://expressjs.com) web framework. It also implements [OAuth](https://api.slack.com/docs/oauth) to demonstate how an app can handle
179+
installation to additional workspaces and be structured to handle events from multiple workspaces.
180+
181+
## Reference Documentation
134182

135183
To learn more, see the [reference documentation](docs/reference.md).
136184

137185
## Support
138186

139-
Need help? Join the [Bot Developer Hangout](http://dev4slack.xoxco.com/) team and talk to us in
187+
Need help? Join the [Bot Developer Hangout](https://community.botkit.ai) team and talk to us in
140188
[#slack-api](https://dev4slack.slack.com/messages/slack-api/).
141189

142190
You can also [create an Issue](https://github.com/slackapi/node-slack-events-api/issues/new)

docs/reference.md

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Reference Documentation
22

3-
#### createSlackEventAdapter(_verificationToken_, [_options_])
3+
#### createSlackEventAdapter(_signingSecret_, [_options_])
44

55
A factory method for creating a new `SlackEventAdapter` instance.
66

7-
The `verificationToken` is a required String parameter which you can find in your Slack App
8-
configuration once you've assigned a Request URL.
7+
The `signingSecret` is a required string parameter which you can find in your Slack app's Basic
8+
Information.
99

1010
If `options.waitForResponse` is truthy then your SlackEventAdapter will emit a callback function
1111
with each event so you can control more details about the HTTP response sent back to Slack. See
@@ -21,20 +21,19 @@ details.
2121

2222
### SlackEventAdapter
2323

24-
This object is responsible for consuming HTTP requests from the Slack Events API (via middleware or
24+
This object is responsible for consuming HTTP requests from the Slack Events API (via a request handler or
2525
by creating its own HTTP Server) and emitting events to your application. It inherits from
2626
[`EventEmitter`](https://nodejs.org/dist/latest-v4.x/docs/api/events.html#events_class_eventemitter),
27-
whose methods are used for managing listeners. You can also rely on it to process token verification
27+
whose methods are used for managing listeners. You can also rely on it to verify request signatures
2828
and other less interesting tasks so you can just focus on handling the events.
2929

3030
As with any EventEmitter, you should attach a handler for the `'error'` event in order to be
31-
notified of errors. Each error is identified with a `code` property. The dictionary of error codes
32-
produced by this module can be found at the top level named export `errorCodes`.
31+
notified of errors.
3332

3433
All other events come from the Slack Events API [Event Types](https://api.slack.com/events/api).
3534
The signature for your event handler would be `handler(event, [body, ] [headers, ] [respond])`.
3635
The first argument your handler receives is the event object as described in documentation linked.
37-
If you initialized the adapter using the `includeBody` option, the next argument will be the entire
36+
If you initialized the adapter using the `includeBody` option, then next argument will be the entire
3837
parsed body of the HTTP request. This can be useful to get additional context such as `team_id`,
3938
`api_app_id`, and more. Similarly, if you initialized the adapter using the `includeHeaders` option,
4039
the next argument will be an object with key-value pairs for the headers in the HTTP request.
@@ -47,19 +46,29 @@ to HTTP requests until you have invoked the callback. The callback has a signatu
4746
that Slack should not retry that request, you should set `responseOptions.failWithNoRetry` to a
4847
truthy value. If you want Slack to send the request to a different URL, you should set the
4948
value of `responseOptions.redirectLocation` to the URL you want. Lastly, if you'd like to
50-
set the body of the response, you should set the `responseOptions.content` value to a String of
49+
set the body of the response, you should set the `responseOptions.content` value to a string of
5150
body content. EventEmitters allow you to add many handlers, but it's recommended when using the
52-
`waitForResponse` option that you only have one handler on each event type. You should always handle
53-
the `error` event too. It's your application's responsibility to make sure that the `respond()`
54-
callback is invoked exactly once.
51+
`waitForResponse` option that you only have one handler on each event type. It's your application's
52+
responsibility to make sure that the `respond()` callback is invoked exactly once. You should always
53+
handle the `error` event too - otherwise unhandled errors will crash your app.
5554

56-
#### expressMiddleware([_options_])
55+
#### requestListener()
56+
57+
This method returns a function that can be attached to the
58+
[`request` event of an `http.Server`](https://nodejs.org/dist/latest/docs/api/http.html#http_event_request)
59+
instance. The function also works as the `requestListener` parameter of
60+
[`http.createServer()`](https://nodejs.org/dist/latest/docs/api/http.html#http_http_createserver_options_requestlistener). This
61+
function is the primary way to plug the adapter into your own HTTP server, no matter which framework (or not)
62+
you choose.
63+
64+
#### expressMiddleware()
5765

5866
This method returns a middleware function that can be mounted into your own Express application.
5967
Remember to mount it at a path that would resolve to your Slack App's Request URL setting.
6068

61-
If `options.propagateErrors` is truthy then the middleware does not send an HTTP response for
62-
errors, but instead invokes `next(error)` so that your next route handler can service that request.
69+
If a request is recieved with a body that has already been parsed, this middleware will forward
70+
an error to the next middleware in the express app. The error will have its `code` property set
71+
to the value `errorCodes.BODY_PARSER_NOT_PERMITTED`.
6372

6473
#### start(_port_)
6574

@@ -74,3 +83,11 @@ This method returns a Promise for an
7483
server will already be setup to receive requests from the Slack Events API at the default path of
7584
`/slack/events`. A specific path can be set using the `path` argument. You can start it by calling
7685
the `listen()` method on the server.
86+
87+
### errorCodes
88+
89+
A dictionary of values that this package assigns to the `code` property if errors.
90+
91+
* `errorCodes.BODY_PARSER_NOT_PERMITTED`: An incoming request's body had already been parsed before
92+
the adapter's express middleware was able to process it. You should remove the `body-parser` middleware from
93+
the app or router.

src/adapter.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const errorCodes = {
1010
BODY_PARSER_NOT_PERMITTED: 'SLACKADAPTER_BODY_PARSER_NOT_PERMITTED_FAILURE',
1111
};
1212

13-
export default class SlackEventAdapter extends EventEmitter {
13+
export class SlackEventAdapter extends EventEmitter {
1414
constructor(signingSecret, options = {}) {
1515
if (!isString(signingSecret)) {
1616
throw new TypeError('SlackEventAdapter needs a verification token');
@@ -84,5 +84,9 @@ export default class SlackEventAdapter extends EventEmitter {
8484
requestListener(middlewareOptions = {}) {
8585
return createHTTPHandler(this, middlewareOptions);
8686
}
87-
8887
}
88+
89+
/**
90+
* @alias module:adapter
91+
*/
92+
export default SlackEventAdapter;

src/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { errorCodes as requestListenerErrorCodes } from './http-handler';
2-
import SlackEventAdapter from './adapter';
1+
import { errorCodes as adapterErrorCodes, SlackEventAdapter } from './adapter';
32

4-
export const errorCodes = requestListenerErrorCodes;
3+
export const errorCodes = adapterErrorCodes;
54

65
export function createSlackEventAdapter(signingSecret, options) {
76
return new SlackEventAdapter(signingSecret, options);

0 commit comments

Comments
 (0)