Skip to content

Commit

Permalink
Merge branch 'v3' into add-http-receiver
Browse files Browse the repository at this point in the history
  • Loading branch information
aoberoi committed Jan 13, 2021
2 parents f834c2b + ad6a32f commit 197353f
Show file tree
Hide file tree
Showing 11 changed files with 428 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .github/maintainers_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ When documentation is in a beta state, it requires a new, distinct collection of

2. Merge into main repository
* Create a pull request with the commit that was just made. Be certain to include the tag. For
example: `git push username main:rel-v1.0.8 && git push --tags username`.
example: `git push username main --tags`.
* Once tests pass and a reviewer has approved, merge the pull request. You will also want to
update your local `main` branch.
* Push the new tag up to origin `git push --tags origin`.
Expand Down
65 changes: 65 additions & 0 deletions docs/_basic/ja_socket_mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
title: ソケットモードの使用
lang: ja
slug: socket-mode
order: 16
---

<div class="section-content">
[ソケットモード](https://api.slack.com/socket-mode) は、アプリに WebSocket での接続と、そのコネクション経由でのデータ受信を可能とします。コネクションをハンドリングするために @slack/bolt@3.0.0` 以上では `SokcetModeReceiver` というレシーバーが提供されています。ソケットモードを使う前に、アプリの管理画面でソケットモードの機能が有効になっているコオを確認しておいてください。

`SocketModeReceiver` を使う方法は `App` インスタンスの初期化時にコンストラクターに `socketMode: true``appToken: YOUR_APP_TOKEN` を渡すだけです。App Level Token は、アプリ管理画面の **Basic Information** セクションから取得できます。
</div>

```javascript
const { App } = require('@slack/bolt');

const app = new App({
token: process.env.BOT_TOKEN,
socketMode: true,
appToken: process.env.APP_TOKEN,
});

(async () => {
await app.start();
console.log('⚡️ Bolt app started');
})();
```

<details class="secondary-wrapper">
<summary class="section-head" markdown="0">
<h4 class="section-head">ソケットモードレシーバーのカスタム初期化</h4>
</summary>

<div class="secondary-content" markdown="0">

以下のように `@slack/bolt` から `SocketModeReceiver` を import して、カスタムされたインスタンスとして定義することができます。

</div>

```javascript
const { App, SocketModeReceiver } = require('@slack/bolt');

const socketModeReceiver = new SocketModeReceiver({
appToken: process.env.APP_TOKEN,

// OAuth フローの実装を合わせて使う場合は、以下を有効にしてください
// clientId: process.env.CLIENT_ID,
// clientSecret: process.env.CLIENT_SECRET,
// stateSecret: 'my-state-secret',
// scopes: ['channels:read', 'chat:write', 'app_mentions:read', 'channels:manage', 'commands'],
});

const app = new App({
receiver: socketModeReceiver,
// OAuth を使うなら以下の token 指定は不要です
token: process.env.BOT_TOKEN
});

(async () => {
await app.start();
console.log('⚡️ Bolt app started');
})();
```

</details>
4 changes: 2 additions & 2 deletions docs/_basic/socket_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ order: 16
---

<div class="section-content">
[Socket Mode](https://api.slack.com/socket-mode) allows your app to connect and receive data from Slack via a WebSocket connection. To handle the connection, Bolt for JavaScript includes a `SocketModeReceiver` (in `@slack/[email protected]` and higher). Before using Socket Mode, be sure to enable it within your app configuration.
[Socket Mode](https://api.slack.com/socket-mode) allows your app to connect and receive data from Slack via a WebSocket connection. To handle the connection, Bolt for JavaScript includes a `SocketModeReceiver` (in `@slack/[email protected]` and higher). Before using Socket Mode, be sure to enable it within your app configuration.

To use the `SocketModeReceiver`, just pass in `socketMode:true` and `appToken:YOUR_APP_TOKEN` when initializing `App`. You can get your App Level Token in your app configuration under the **Basic Information** section.
</div>
Expand All @@ -15,7 +15,7 @@ To use the `SocketModeReceiver`, just pass in `socketMode:true` and `appToken:YO
const { App } = require('@slack/bolt');

const app = new App({
token: process.env.BOT_TOKEN
token: process.env.BOT_TOKEN,
socketMode: true,
appToken: process.env.APP_TOKEN,
});
Expand Down
2 changes: 1 addition & 1 deletion docs/_tutorials/ja_using-typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ permalink: /ja-jp/tutorial/using-typescript

### 最低必須バージョン

`@slack/bolt` の最新のメジャーバージョンは TypeScript 3.7 以上での利用をサポートしています。
`@slack/bolt` の最新のメジャーバージョンは TypeScript 4.1 以上での利用をサポートしています。
2 changes: 1 addition & 1 deletion examples/socket-mode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"author": "Slack Technologies, Inc.",
"license": "MIT",
"dependencies": {
"@slack/bolt": "feat-socket-mode"
"@slack/bolt": "3.0.0"
}
}
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@
"url": "https://github.com/slackapi/bolt-js/issues"
},
"dependencies": {
"@slack/logger": "^2.0.0",
"@slack/oauth": "^1.4.0",
"@slack/socket-mode": "feat-socket-mode",
"@slack/types": "^1.9.0",
"@slack/web-api": "^5.14.0",
"@slack/logger": "^3.0.0",
"@slack/oauth": "^2.0.0",
"@slack/socket-mode": "1.0.0",
"@slack/types": "^2.0.0",
"@slack/web-api": "^6.0.0",
"@types/express": "^4.16.1",
"@types/node": ">=12",
"@types/promise.allsettled": "^1.0.3",
Expand Down
38 changes: 20 additions & 18 deletions src/App.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import App, { ViewConstraints } from './App';
import { WebClientOptions, WebClient } from '@slack/web-api';
import { WorkflowStep } from './WorkflowStep';

// TODO: swap out rewiremock for proxyquire to see if it saves execution time
// Utility functions
const noop = () => Promise.resolve(undefined);
const noopMiddleware = async ({ next }: { next: NextFn }) => {
Expand Down Expand Up @@ -68,7 +67,7 @@ describe('App', () => {
assert(authorizeCallback.notCalled, 'Should not call the authorize callback on instantiation');
assert.instanceOf(app, App);
});
it('should fail without a token for single team authorization or authorize callback or oauth installer', async () => {
it('should fail without a token for single team authorization, authorize callback, nor oauth installer', async () => {
// Arrange
const App = await importApp(); // eslint-disable-line @typescript-eslint/naming-convention, no-underscore-dangle, id-blacklist, id-match

Expand Down Expand Up @@ -243,22 +242,25 @@ describe('App', () => {
});

describe('#start', () => {
it('should pass calls through to receiver', async () => {
// Arrange
const dummyReturn = Symbol();
const dummyParams = [Symbol(), Symbol()];
const fakeReceiver = new FakeReceiver();
const App = await importApp(); // eslint-disable-line @typescript-eslint/naming-convention, no-underscore-dangle, id-blacklist, id-match
const app = new App({ receiver: fakeReceiver, authorize: noopAuthorize });
fakeReceiver.start = sinon.fake.returns(dummyReturn);

// Act
const actualReturn = await app.start(...dummyParams);

// Assert
assert.deepEqual(actualReturn, dummyReturn);
assert.deepEqual(dummyParams, fakeReceiver.start.firstCall.args);
});
// The following test case depends on a definition of App that is generic on its Receiver type. This will be
// addressed in the future. It cannot even be left uncommented with the `it.skip()` global because it will fail
// TypeScript compilation as written.
// it('should pass calls through to receiver', async () => {
// // Arrange
// const dummyReturn = Symbol();
// const dummyParams = [Symbol(), Symbol()];
// const fakeReceiver = new FakeReceiver();
// const App = await importApp(); // eslint-disable-line @typescript-eslint/naming-convention, no-underscore-dangle, id-blacklist, id-match
// const app = new App({ receiver: fakeReceiver, authorize: noopAuthorize });
// fakeReceiver.start = sinon.fake.returns(dummyReturn);
// // Act
// const actualReturn = await app.start(...dummyParams);
// // Assert
// assert.deepEqual(actualReturn, dummyReturn);
// assert.deepEqual(dummyParams, fakeReceiver.start.firstCall.args);
// });
// TODO: another test case to take the place of the one above (for coverage until the definition of App is made
// generic).
});

describe('#stop', () => {
Expand Down
6 changes: 3 additions & 3 deletions src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,12 @@ export default class App {
/**
* Convenience method to call start on the receiver
*
* TODO: args could be defined using a generic constraint from the receiver type
* TODO: should replace ExpressReceiver in type definition with a generic that is constrained to Receiver
*
* @param args receiver-specific start arguments
*/
public start(...args: any[]): Promise<unknown> {
return this.receiver.start(...args);
public start(...args: Parameters<ExpressReceiver['start']>): ReturnType<ExpressReceiver['start']> {
return this.receiver.start(...args) as ReturnType<ExpressReceiver['start']>;
}

public stop(...args: any[]): Promise<unknown> {
Expand Down
5 changes: 5 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum ErrorCode {

ReceiverMultipleAckError = 'slack_bolt_receiver_ack_multiple_error',
ReceiverAuthenticityError = 'slack_bolt_receiver_authenticity_error',
ReceiverInconsistentStateError = 'slack_bolt_receiver_inconsistent_state_error',

MultipleListenerError = 'slack_bolt_multiple_listener_error',

Expand Down Expand Up @@ -70,6 +71,10 @@ export class ReceiverAuthenticityError extends Error implements CodedError {
public code = ErrorCode.ReceiverAuthenticityError;
}

export class ReceiverInconsistentStateError extends Error implements CodedError {
public code = ErrorCode.ReceiverInconsistentStateError;
}

export class MultipleListenerError extends Error implements CodedError {
public code = ErrorCode.MultipleListenerError;

Expand Down
Loading

0 comments on commit 197353f

Please sign in to comment.