Socket
Socket
Sign inDemoInstall

@slack/client

Package Overview
Dependencies
68
Maintainers
4
Versions
57
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.9.0 to 3.10.0

docs/_posts/2017-05-25-v3.10.0.md

6

docs/_pages/bots.md

@@ -196,5 +196,7 @@ ---

rtm.on(RTM_EVENTS.MESSAGE, function handleRtmMessage(message) {
var channel = "#general"; //could also be a channel, group, DM, or user ID (C1234), or a username (@don)
rtm.sendMessage("Hello <@" + message.user + ">!", message.channel);
 if (message.text === "Hello.") {
   var channel = "#general"; //could also be a channel, group, DM, or user ID (C1234), or a username (@don)
  rtm.sendMessage("Hello <@" + message.user + ">!", message.channel);
 }
});
```

@@ -12,3 +12,2 @@ ---

* [.transport](#BaseAPIClient+transport) : <code>function</code>
* [.userAgent](#BaseAPIClient+userAgent) : <code>string</code>
* [.retryConfig](#BaseAPIClient+retryConfig)

@@ -31,3 +30,2 @@ * [.logger](#BaseAPIClient+logger) : <code>function</code>

| opts.slackAPIUrl | <code>String</code> | The Slack API URL. |
| opts.userAgent | <code>String</code> | The user-agent to use, defaults to node-slack. |
| opts.transport | <code>function</code> | Function to call to make an HTTP call to the Slack API. |

@@ -47,10 +45,7 @@ | [opts.logLevel] | <code>string</code> | The log level for the logger. |

**Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>
<a name="BaseAPIClient+userAgent"></a>
### baseAPIClient.userAgent : <code>string</code>
**Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>
<a name="BaseAPIClient+retryConfig"></a>
### baseAPIClient.retryConfig
Default to attempting 5 retries within 5 minutes, with exponential backoff.
Default to retrying forever with an exponential backoff, capped at thirty
minutes but with some randomization.

@@ -57,0 +52,0 @@ **Kind**: instance property of <code>[BaseAPIClient](#BaseAPIClient)</code>

@@ -16,4 +16,4 @@ ---

* [.activeTeamId](#RTMClient+activeTeamId) : <code>string</code>
* [.dataStore](#RTMClient+dataStore) : <code>[SlackDataStore](#SlackDataStore)</code>
* [._pingTimer](#RTMClient+_pingTimer) : <code>?</code>
* [.dataStore](#RTMClient+dataStore) : <code>[SlackDataStore](#SlackDataStore)</code>
* [._createFacets()](#RTMClient+_createFacets)

@@ -30,4 +30,5 @@ * [.start(opts)](#RTMClient+start)

* [.handleWsError(err)](#RTMClient+handleWsError)
* [.handleWsClose()](#RTMClient+handleWsClose)
* [.handleWsClose(code, reason)](#RTMClient+handleWsClose)
* [._handlePong(message)](#RTMClient+_handlePong)
* [._maybeKeepAlive(message)](#RTMClient+_maybeKeepAlive)
* [._handleHello()](#RTMClient+_handleHello)

@@ -37,2 +38,3 @@ * [.sendMessage(text, channelId, [optCb])](#RTMClient+sendMessage)

* [.sendTyping(channelId)](#RTMClient+sendTyping)
* [.subscribePresence(userIds)](#RTMClient+subscribePresence)
* [.send(message, [optCb])](#RTMClient+send)

@@ -43,16 +45,20 @@

### new RTMClient(token, opts)
Creates a new instance of RTM client.
| Param | Type | Description |
| --- | --- | --- |
| token | <code>String</code> | |
| opts | <code>object</code> | |
| opts.socketFn | <code>function</code> | A function to call, passing in a websocket URL, that should return a websocket instance connected to that URL. |
| opts.dataStore | <code>object</code> | A store to cache Slack info, e.g. channels, users etc. in. If you don't want a store, pass false or null as the value for this. |
| opts.autoReconnect | <code>boolean</code> | Whether or not to automatically reconnect when the connection closes. |
| opts.maxReconnectionAttempts | <code>number</code> | |
| opts.reconnectionBackoff | <code>number</code> | |
| opts.wsPingInterval | <code>number</code> | |
| opts.maxPongInterval | <code>number</code> | |
| opts.logLevel | <code>string</code> | The log level for the logger. |
| opts.logger | <code>function</code> | Function to use for log calls, takes (logLevel, logString) parameters. |
| token | <code>String</code> | The token to use for connecting |
| opts | <code>Object</code> | |
| opts.socketFn | <code>function</code> | A function to call, passing in a websocket URL, that should return a websocket instance connected to that URL |
| opts.dataStore | <code>Object</code> | A store to cache Slack info, e.g. channels, users etc. in. Pass null or false to use no store |
| opts.autoReconnect | <code>Boolean</code> | Whether or not to automatically reconnect when the connection closes. Defaults to true |
| opts.useRtmConnect | <code>Boolean</code> | True to use rtm.connect rather than rtm.start |
| opts.retryConfig | <code>Object</code> | The retry policy to use, defaults to forever with exponential backoff {@see https://github.com/SEAPUNK/node-retry} |
| opts.maxReconnectionAttempts | <code>Number</code> | DEPRECATED: Use retryConfig instead |
| opts.reconnectionBackoff | <code>Number</code> | DEPRECATED: Use retryConfig instead |
| opts.wsPingInterval | <code>Number</code> | The time to wait between pings with the server |
| opts.maxPongInterval | <code>Number</code> | The max time (in ms) to wait for a pong before reconnecting |
| opts.logLevel | <code>String</code> | The log level for the logger |
| opts.logger | <code>function</code> | Function to use for log calls, takes (logLevel, logString) parameters |

@@ -89,2 +95,6 @@ <a name="RTMClient+_socketFn"></a>

**Kind**: instance property of <code>[RTMClient](#RTMClient)</code>
<a name="RTMClient+dataStore"></a>
### rtmClient.dataStore : <code>[SlackDataStore](#SlackDataStore)</code>
**Kind**: instance property of <code>[RTMClient](#RTMClient)</code>
<a name="RTMClient+_pingTimer"></a>

@@ -96,6 +106,2 @@

**Kind**: instance property of <code>[RTMClient](#RTMClient)</code>
<a name="RTMClient+dataStore"></a>
### rtmClient.dataStore : <code>[SlackDataStore](#SlackDataStore)</code>
**Kind**: instance property of <code>[RTMClient](#RTMClient)</code>
<a name="RTMClient+_createFacets"></a>

@@ -108,2 +114,4 @@

### rtmClient.start(opts)
Begin an RTM session.
**Kind**: instance method of <code>[RTMClient](#RTMClient)</code>

@@ -138,3 +146,3 @@

| --- | --- | --- |
| socketUrl | <code>string</code> | The URL of the websocket to connect to. |
| socketUrl | <code>String</code> | The URL of the websocket to connect to. |

@@ -148,6 +156,6 @@ <a name="RTMClient+disconnect"></a>

| Param |
| --- |
| optReason |
| optCode |
| Param | Type |
| --- | --- |
| optReason | <code>Error</code> |
| optCode | <code>Number</code> |

@@ -157,2 +165,4 @@ <a name="RTMClient+reconnect"></a>

### rtmClient.reconnect()
Attempts to reconnect to the websocket by retrying the start method.
**Kind**: instance method of <code>[RTMClient](#RTMClient)</code>

@@ -202,4 +212,12 @@ <a name="RTMClient+handleWsOpen"></a>

### rtmClient.handleWsClose()
### rtmClient.handleWsClose(code, reason)
Occurs when the websocket closes.
**Kind**: instance method of <code>[RTMClient](#RTMClient)</code>
| Param | Type | Description |
| --- | --- | --- |
| code | <code>String</code> | The error code |
| reason | <code>String</code> | The reason for closing |
<a name="RTMClient+_handlePong"></a>

@@ -216,5 +234,19 @@

<a name="RTMClient+_maybeKeepAlive"></a>
### rtmClient._maybeKeepAlive(message)
If we haven't received a pong in too long, treat any incoming message as a pong
to prevent unnecessary disconnects.
**Kind**: instance method of <code>[RTMClient](#RTMClient)</code>
| Param | Type |
| --- | --- |
| message | <code>Object</code> |
<a name="RTMClient+_handleHello"></a>
### rtmClient._handleHello()
Occurs when the socket connection is opened.
Begin ping-pong with the server.
[hello](https://api.slack.com/events/hello)

@@ -259,2 +291,14 @@

<a name="RTMClient+subscribePresence"></a>
### rtmClient.subscribePresence(userIds)
Subscribes this socket to presence changes for only the given `userIds`.
This requires `presence_sub` to have been passed as an argument to `start`.
**Kind**: instance method of <code>[RTMClient](#RTMClient)</code>
| Param | Type | Description |
| --- | --- | --- |
| userIds | <code>Array</code> | The user IDs to subscribe to |
<a name="RTMClient+send"></a>

@@ -261,0 +305,0 @@

@@ -23,2 +23,3 @@ ---

* [.getDMByName(name)](#SlackDataStore+getDMByName) ⇒ <code>Object</code>
* [.getDMByUserId(id)](#SlackDataStore+getDMByUserId) ⇒ <code>Object</code>
* [.getBotById(botId)](#SlackDataStore+getBotById) ⇒ <code>Object</code>

@@ -191,2 +192,13 @@ * [.getBotByName(name)](#SlackDataStore+getBotByName) ⇒ <code>Object</code>

<a name="SlackDataStore+getDMByUserId"></a>
### slackDataStore.getDMByUserId(id) ⇒ <code>Object</code>
Returns the DM object between the registered user and the user with the supplied id.
**Kind**: instance method of <code>[SlackDataStore](#SlackDataStore)</code>
| Param |
| --- |
| id |
<a name="SlackDataStore+getBotById"></a>

@@ -193,0 +205,0 @@

@@ -26,2 +26,3 @@ ---

* [.getDMByName()](#SlackMemoryDataStore+getDMByName)
* [.getDMByUserId()](#SlackMemoryDataStore+getDMByUserId)
* [.getBotById()](#SlackMemoryDataStore+getBotById)

@@ -119,2 +120,6 @@ * [.getBotByName()](#SlackMemoryDataStore+getBotByName)

**Kind**: instance method of <code>[SlackMemoryDataStore](#SlackMemoryDataStore)</code>
<a name="SlackMemoryDataStore+getDMByUserId"></a>
### slackMemoryDataStore.getDMByUserId()
**Kind**: instance method of <code>[SlackMemoryDataStore](#SlackMemoryDataStore)</code>
<a name="SlackMemoryDataStore+getBotById"></a>

@@ -121,0 +126,0 @@

var events = require('./lib/clients/events');
var retryPolicies = require('./lib/clients/retry-policies');

@@ -8,2 +9,3 @@ module.exports = {

LegacyRtmClient: require('./lib/clients/default/legacy-rtm'),
MemoryDataStore: require('./lib/data-store/memory-data-store'),
CLIENT_EVENTS: {

@@ -15,3 +17,3 @@ WEB: events.CLIENT_EVENTS.WEB,

RTM_MESSAGE_SUBTYPES: events.RTM_MESSAGE_SUBTYPES,
MemoryDataStore: require('./lib/data-store/memory-data-store')
RETRY_POLICIES: retryPolicies
};

@@ -11,2 +11,3 @@ /**

var partial = require('lodash').partial;
var pick = require('lodash').pick;
var retry = require('retry');

@@ -54,5 +55,7 @@

/**
* Default to attempting 5 retries within 5 minutes, with exponential backoff.
* Default to retrying forever with an exponential backoff, capped at thirty
* minutes but with some randomization.
*/
this.retryConfig = clientOpts.retryConfig || retryPolicies.FIVE_RETRIES_IN_FIVE_MINUTES;
this.retryConfig = clientOpts.retryConfig ||
retryPolicies.RETRY_FOREVER_EXPONENTIAL_CAPPED_RANDOM;

@@ -64,3 +67,3 @@ /**

*/
this.requestQueue = async.priorityQueue(
this.requestQueue = async.queue(
bind(this._callTransport, this),

@@ -124,2 +127,3 @@ clientOpts.maxRequestConcurrency || 3

retryOp.attempt(function attemptTransportCall() {
_this.logger('verbose', 'Retrying', pick(task.args, 'url'));
_this.transport(task.args, partial(callTransport.handleTransportResponse, retryArgs));

@@ -134,5 +138,5 @@ });

* @param {String} endpoint The API endpoint to send to.
* @param {Object=} apiArgs
* @param {Object=} apiOptArgs
* @param {function=} optCb The callback to run on completion.
* @param {Object} apiArgs
* @param {Object} apiOptArgs
* @param {Function} optCb The callback to run on completion.
* @private

@@ -139,0 +143,0 @@ */

@@ -79,6 +79,4 @@ /**

optArgs = apiOptArgs;
} else {
if (isFunction(apiOptArgs)) {
cb = apiOptArgs;
}
} else if (isFunction(apiOptArgs)) {
cb = apiOptArgs;
}

@@ -85,0 +83,0 @@

@@ -7,2 +7,33 @@ /**

/**
* Keep retrying forever, with an exponential backoff.
*/
var RETRY_FOREVER_EXPONENTIAL = {
forever: true
};
/**
* Same as {@link RETRY_FOREVER_EXPONENTIAL}, but capped at 30 minutes.
*/
var RETRY_FOREVER_EXPONENTIAL_CAPPED = {
forever: true,
maxTimeout: 30 * 60 * 1000
};
/**
* Same as {@link RETRY_FOREVER_EXPONENTIAL_CAPPED}, but with randomization to
* prevent stampeding herds.
*/
var RETRY_FOREVER_EXPONENTIAL_CAPPED_RANDOM = {
forever: true,
maxTimeout: 30 * 60 * 1000,
randomize: true
};
/**
* Short & sweet, five retries in five minutes and then bail.
*/
var FIVE_RETRIES_IN_FIVE_MINUTES = {

@@ -14,2 +45,5 @@ retries: 5,

/**
* This policy is just to keep the tests running fast.
*/
var TEST_RETRY_POLICY = {

@@ -21,3 +55,20 @@ minTimeout: 0,

module.exports.RETRY_FOREVER_EXPONENTIAL = RETRY_FOREVER_EXPONENTIAL;
module.exports.RETRY_FOREVER_EXPONENTIAL_CAPPED = RETRY_FOREVER_EXPONENTIAL_CAPPED;
module.exports.RETRY_FOREVER_EXPONENTIAL_CAPPED_RANDOM = RETRY_FOREVER_EXPONENTIAL_CAPPED_RANDOM;
module.exports.FIVE_RETRIES_IN_FIVE_MINUTES = FIVE_RETRIES_IN_FIVE_MINUTES;
module.exports.TEST_RETRY_POLICY = TEST_RETRY_POLICY;
/**
* Uses legacy RTM client options to make a retry policy.
* @param {Object} opts
* @param {Number} opts.maxReconnectionAttempts Maximum number of attempts before emitting error
* @param {Number} opts.reconnectionBackoff Time to wait between attempts
*/
module.exports.retryPolicyFromOptions = function retryPolicyFromOptions(opts) {
return opts.maxReconnectionAttempts || opts.reconnectionBackoff ? {
retries: opts.maxReconnectionAttempts || 10,
minTimeout: opts.reconnectionBackoff || 3000,
maxTimeout: opts.reconnectionBackoff || 3000
} : null;
};
/**
*
* See [the RTM client events](../events/client) for details of the client event lifecycle.

@@ -38,20 +37,24 @@ */

var wsSocketFn = require('../transports/ws');
var retryPolicyFromOptions = require('../retry-policies').retryPolicyFromOptions;
/**
*
* @param {String} token
* @param {object?} opts
* @param {Function} opts.socketFn A function to call, passing in a websocket URL, that should
* return a websocket instance connected to that URL.
* @param {object} opts.dataStore A store to cache Slack info, e.g. channels, users etc. in.
* If you don't want a store, pass false or null as the value for this.
* @param {boolean} opts.autoReconnect Whether or not to automatically reconnect when the connection
* closes.
* @param {number} opts.maxReconnectionAttempts
* @param {number} opts.reconnectionBackoff
* @param {number} opts.wsPingInterval
* @param {number} opts.maxPongInterval
* @param {string} opts.logLevel The log level for the logger.
* @param {Function} opts.logger Function to use for log calls, takes (logLevel, logString)
* parameters.
* Creates a new instance of RTM client.
* @param {String} token The token to use for connecting
* @param {Object} opts
* @param {Function} opts.socketFn A function to call, passing in a websocket URL, that should
* return a websocket instance connected to that URL
* @param {Object} opts.dataStore A store to cache Slack info, e.g. channels, users etc. in.
* Pass null or false to use no store
* @param {Boolean} opts.autoReconnect Whether or not to automatically reconnect when the connection
* closes. Defaults to true
* @param {Boolean} opts.useRtmConnect True to use rtm.connect rather than rtm.start
* @param {Object} opts.retryConfig The retry policy to use, defaults to forever with exponential
* backoff {@see https://github.com/SEAPUNK/node-retry}
* @param {Number} opts.maxReconnectionAttempts DEPRECATED: Use retryConfig instead
* @param {Number} opts.reconnectionBackoff DEPRECATED: Use retryConfig instead
* @param {Number} opts.wsPingInterval The time to wait between pings with the server
* @param {Number} opts.maxPongInterval The max time (in ms) to wait for a pong before reconnecting
* @param {String} opts.logLevel The log level for the logger
* @param {Function} opts.logger Function to use for log calls, takes (logLevel, logString)
* parameters
* @constructor

@@ -66,2 +69,7 @@ */

// Migrate deprecated parameters to a retry policy.
if (!clientOpts.retryConfig) {
clientOpts.retryConfig = retryPolicyFromOptions(clientOpts);
}
BaseAPIClient.call(this, token, clientOpts);

@@ -107,2 +115,9 @@

/**
* If true, we'll use rtm.connect everywhere in place of rtm.start
* @type {boolean}
* @private
*/
this._useRtmConnect = clientOpts.useRtmConnect;
if (clientOpts.dataStore instanceof DataStore) {

@@ -117,8 +132,6 @@ this.registerDataStore(clientOpts.dataStore);

this.MAX_RECONNECTION_ATTEMPTS = clientOpts.maxReconnectionAttempts || 10;
this.RECONNECTION_BACKOFF = clientOpts.reconnectionBackoff || 3000;
// NOTE: see the "Ping and Pong" section of https://api.slack.com/rtm
// these are to do with the RTM API level connection and not the underlying ws connection.
this.MAX_PONG_INTERVAL = clientOpts.maxPongInterval || 10000;
// See the "Ping and Pong" section of https://api.slack.com/rtm
// These are to do with the RTM API level connection and not the underlying
// socket connection.
this.MAX_PONG_INTERVAL = clientOpts.maxPongInterval || 20000;
this.WS_PING_INTERVAL = clientOpts.wsPingInterval || 5000;

@@ -159,2 +172,8 @@

/**
* @type {SlackDataStore}
*/
RTMClient.prototype.dataStore = undefined;
/**
* The timer repeatedly pinging the server to let it know the client is still alive.

@@ -175,3 +194,3 @@ * @type {?}

/**
*
* A running count of socket connection attempts.
* @type {number}

@@ -192,13 +211,15 @@ * @private

/**
* Whether the server is currently re-connecting.
* @type {boolean}
* Options passed to `start`, for use when reconnecting.
* @type {object}
* @private
*/
RTMClient.prototype._reconnecting = false;
RTMClient.prototype._startOpts = null;
/**
* @type {SlackDataStore}
* Whether the server is currently reconnecting.
* @type {boolean}
* @private
*/
RTMClient.prototype.dataStore = undefined;
RTMClient.prototype._reconnecting = false;

@@ -227,3 +248,3 @@

/**
*
* Begin an RTM session.
* @param {object} opts

@@ -234,7 +255,12 @@ */

if (!this._connecting) {
this.logger('verbose', 'attempting to connect via the RTM API');
this.logger('verbose', 'Attempting to connect via the RTM API');
this.emit(CLIENT_EVENTS.CONNECTING);
this._connecting = true;
this._startOpts = opts;
this._rtm.start(opts, bind(this._onStart, this));
if (this._useRtmConnect) {
this._rtm.connect(opts, bind(this._onStart, this));
} else {
this._rtm.start(opts, bind(this._onStart, this));
}
}

@@ -263,29 +289,41 @@ };

/**
*
* @param err
* @param data
* Occurs when we've received a response to the API call made in start.
* Connect to the socket using the URL from the response, or if it went wrong,
* check the error and potentially retry or permanently disconnect.
* @param requestError - An error that occurred during the request
* @param data - The response data
* @private
*/
RTMClient.prototype._onStart = function _onStart(err, data) {
var errMsg;
RTMClient.prototype._onStart = function _onStart(requestError, data) {
// There may have been an HTTP error or an error returned from the Slack API
var error = requestError || data.error;
var startMethod = this._useRtmConnect ? 'rtm.connect' : 'rtm.start';
var disconnectWithReason = bind(function disconnectWithReason(reason) {
this.logger('error', 'Disconnecting because ' + reason);
this.logger('error', error);
this.disconnect(reason, error);
}, this);
this._connecting = false;
this._reconnecting = false;
if (err || !data.url) {
this.emit(CLIENT_EVENTS.UNABLE_TO_RTM_START, err || data.error);
if (error || (!data || !data.url)) {
this.emit(CLIENT_EVENTS.UNABLE_TO_RTM_START, error);
// Any of these mean this client is unusable, so don't attempt to auto-reconnect
if (data && includes(UNRECOVERABLE_RTM_START_ERRS, data.error)) {
errMsg = 'unrecoverable failure connecting to the RTM API';
this.logger('error', errMsg + ': ' + data.error);
this.disconnect(errMsg, data.error);
disconnectWithReason(data.error + ' is not recoverable');
} else {
this.logger('info', 'unable to RTM start, attempting reconnect: ' + err || data.error);
this.authenticated = false;
if (this.autoReconnect) {
this.logger('info', 'Unable to ' + startMethod + ', attempting reconnect');
this.reconnect();
} else {
disconnectWithReason('auto-reconnect is disabled');
}
}
} else {
this.logger('verbose', 'rtm.start successful, attempting to open websocket URL');
this.logger('verbose', startMethod + ' successful, attempting to open websocket URL');
this.authenticated = true;

@@ -326,3 +364,3 @@ this.activeUserId = data.self.id;

* Connects to the RTM API.
* @param {string} socketUrl The URL of the websocket to connect to.
* @param {String} socketUrl The URL of the websocket to connect to.
*/

@@ -342,4 +380,4 @@ RTMClient.prototype.connect = function connect(socketUrl) {

* Disconnects from the RTM API.
* @param optReason
* @param optCode
* @param {Error} optReason
* @param {Number} optCode
*/

@@ -354,3 +392,3 @@ RTMClient.prototype.disconnect = function disconnect(optErr, optCode) {

/**
*
* Attempts to reconnect to the websocket by retrying the start method.
*/

@@ -363,31 +401,7 @@ RTMClient.prototype.reconnect = function reconnect() {

// TODO(leah): Update this to remove the reconn logic in the RTM client as it should be covered
// by the web client policy
this._connAttempts++;
if (this._connAttempts > this.MAX_RECONNECTION_ATTEMPTS) {
this.emit(
CLIENT_EVENTS.UNABLE_TO_RTM_START,
'unable to connect to Slack RTM API, failed after max reconnection attempts'
);
}
setTimeout(bind(this.start, this), this._connAttempts * this.RECONNECTION_BACKOFF);
}
};
this.logger('warn', 'Reconnecting, on attempt', this._connAttempts);
/**
* Pings the remote server to let it know the client is still alive.
* @private
*/
RTMClient.prototype._pingServer = function _pingServer() {
var pongInterval;
if (this.connected) {
// If the last pong was more than MAX_PONG_INTERVAL, force a reconnect
pongInterval = Date.now() - this._lastPong;
if (pongInterval > this.MAX_PONG_INTERVAL) {
this.reconnect();
} else {
this.send({ type: 'ping' }, noop);
}
// Ensure we use the same arguments to `start` when reconnecting
this.start(this._startOpts);
}

@@ -403,9 +417,2 @@ };

this.emit(CLIENT_EVENTS.WS_OPENED);
this._lastPong = Date.now();
this._connAttempts = 0;
if (this._pingTimer) {
clearInterval(this._pingTimer);
} else {
this._pingTimer = setInterval(bind(this._pingServer, this), this.WS_PING_INTERVAL);
}
};

@@ -426,4 +433,3 @@

} catch (err) {
// TODO(leah): Emit an event here?
this.logger('debug', 'unable to parse message: ' + err);
this.logger('error', 'Unable to parse message: ' + err);
return;

@@ -435,2 +441,3 @@ }

} else {
this._maybeKeepAlive(message);
this._handleWsMessageViaEventHandler(message.type, message);

@@ -442,3 +449,3 @@ }

/**
*
* Handler for messages we need to deal with internally.
* @param {String} messageType

@@ -609,3 +616,5 @@ * @param {Object} message

/**
*
* Occurs when the websocket closes.
* @param {String} code The error code
* @param {String} reason The reason for closing
*/

@@ -637,6 +646,54 @@ RTMClient.prototype.handleWsClose = function handleWsClose(code, reason) {

/** {@link https://api.slack.com/events/hello|hello} */
/**
* Pings the remote server to let it know the client is still alive.
* @private
*/
RTMClient.prototype._pingServer = function _pingServer() {
var pongInterval;
if (this.connected) {
// Get the delta between ping sent & pong received, remember this timer
// fires sometime later so deduct that to get the real latency
pongInterval = Math.abs(Date.now() - this._lastPong - this.WS_PING_INTERVAL);
this.logger('debug', 'waited ' + pongInterval + ' ms for a pong');
// If we didn't receive a response to the last pong in some duration,
// force a reconnect
if (pongInterval > this.MAX_PONG_INTERVAL) {
this.reconnect();
} else {
this.send({ type: 'ping' }, noop);
}
}
};
/**
* If we haven't received a pong in too long, treat any incoming message as a pong
* to prevent unnecessary disconnects.
* @param {Object} message
*/
RTMClient.prototype._maybeKeepAlive = function _maybeKeepAlive(message) {
var pongInterval = Date.now() - this._lastPong;
if (pongInterval > this.MAX_PONG_INTERVAL) {
this.logger('warn', 'No pong in ' + pongInterval +
'ms, treating ' + message.type + ' as keep-alive');
this._lastPong = Date.now();
}
};
/**
* Occurs when the socket connection is opened.
* Begin ping-pong with the server.
* {@link https://api.slack.com/events/hello|hello}
*/
RTMClient.prototype._handleHello = function _handleHello() {
this.connected = true;
this.emit(CLIENT_EVENTS.RTM_CONNECTION_OPENED);
this._lastPong = Date.now();
this._connAttempts = 0;
if (this._pingTimer) clearInterval(this._pingTimer);
this._pingTimer = setInterval(bind(this._pingServer, this), this.WS_PING_INTERVAL);
};

@@ -659,2 +716,3 @@

/**

@@ -670,2 +728,3 @@ * Helper for updating a sent message via the 'chat.update' API call

/**

@@ -684,2 +743,15 @@ * Sends a typing indicator to indicate that the user with `activeUserId` is typing.

/**
* Subscribes this socket to presence changes for only the given `userIds`.
* This requires `presence_sub` to have been passed as an argument to `start`.
* @param {Array} userIds The user IDs to subscribe to
*/
RTMClient.prototype.subscribePresence = function subscribePresence(userIds) {
this.send({
type: 'presence_sub',
ids: userIds
}, noop);
};
/**
* Sends a message over the websocket to the server.

@@ -686,0 +758,0 @@ * @param {*} message The message to send back to the server.

@@ -58,4 +58,2 @@ // For some reason, I can't turn this off only for functions, so suppress all cases

/**
*
*
* If this is reached, it means an error outside the normal error logic was received. These

@@ -72,3 +70,3 @@ * should be very unusual as standard errors come back with a 200 code and an "error"

var handleHttpErr = function handleHttpErr(retryOp, apiCb, statusCode) {
var httpErr = new Error('Unable to process request, received bad ' + statusCode + ' error');
var httpErr = new Error('Unable to process request, received status ' + statusCode);
if (!retryOp.retry(httpErr)) {

@@ -108,3 +106,3 @@ apiCb(httpErr, null);

jsonError = new Error(jsonResponse.error);
client.logger('error', jsonResponse.error);
client.logger('error', 'Response not OK: ', jsonResponse.error);
}

@@ -111,0 +109,0 @@

@@ -133,5 +133,7 @@ /**

* @param {string} unfurls - a map of URLs to structured message attachments
* @param {Object=} opts
* @param {?} opts.user_auth_required - Pass true to require user authorization.
* @param {function=} optCb Optional callback, if not using promises.
*/
ChatFacet.prototype.unfurl = function unfurl(ts, channel, unfurls, optCb) {
ChatFacet.prototype.unfurl = function unfurl(ts, channel, unfurls, opts, optCb) {
var requiredArgs = {

@@ -143,5 +145,5 @@ ts: ts,

return this.makeAPICall('chat.unfurl', requiredArgs, {}, optCb);
return this.makeAPICall('chat.unfurl', requiredArgs, opts, optCb);
};
module.exports = ChatFacet;

@@ -10,2 +10,3 @@ /**

* - open: {@link https://api.slack.com/methods/im.open|im.open}
* - replies: {@link https://api.slack.com/methods/im.replies|im.replies}
*

@@ -103,3 +104,20 @@ */

/**
* Returns an entire thread (a message plus all the messages in reply to it).
* @see {@link https://api.slack.com/methods/im.replies|im.replies}
*
* @param {?} channel - Direct message channel to get replies from.
* @param {?} thread_ts - Timestamp of the parent message.
* @param {function=} optCb Optional callback, if not using promises.
*/
ImFacet.prototype.replies = function replies(channel, threadTs, optCb) {
var requiredArgs = {
channel: channel,
thread_ts: threadTs
};
return this.makeAPICall('im.replies', requiredArgs, null, optCb);
};
module.exports = ImFacet;

@@ -6,3 +6,3 @@ /**

* - start: {@link https://api.slack.com/methods/rtm.start|rtm.start}
*
* - connect: {@link https://api.slack.com/methods/rtm.connect|rtm.connect}
*/

@@ -21,8 +21,9 @@

*
* @param {Object=} opts
* @param {?} opts.simple_latest - Return timestamp only for latest message object of each channel
* (improves performance).
* @param {?} opts.no_unreads - Skip unread counts for each channel (improves performance).
* @param {?} opts.mpim_aware - Returns MPIMs to the client in the API response.
* @param {function=} optCb Optional callback, if not using promises.
* @param {Object} opts
* @param {Boolean} opts.simple_latest Return timestamp only for latest message object of each
* channel (improves performance).
* @param {Boolean} opts.no_unreads Skip unread counts for each channel (improves performance).
* @param {Boolean} opts.mpim_aware Returns MPIMs to the client in the API response.
* @param {Boolean} opts.presence_sub Support presence subscriptions on this socket connection.
* @param {Function} optCb Optional callback, if not using promises.
*/

@@ -34,2 +35,16 @@ RtmFacet.prototype.start = function start(opts, optCb) {

/**
* Starts a Real Time Messaging session using the lighter-weight rtm.connect.
* This will give us a WebSocket URL without the payload of `rtm.start`.
* @see {@link https://api.slack.com/methods/rtm.connect|rtm.connect}
*
* @param {Object} opts
* @param {Boolean} opts.presence_sub Support presence subscriptions on this socket connection.
* @param {Function} optCb Optional callback, if not using promises.
*/
RtmFacet.prototype.connect = function connect(opts, optCb) {
return this.makeAPICall('rtm.connect', null, opts, optCb);
};
module.exports = RtmFacet;

@@ -397,2 +397,3 @@ /* eslint no-unused-vars: 0 */

SlackDataStore.prototype.cacheRtmStart = function cacheRtmStart(data) {
var self;
this.clear();

@@ -417,3 +418,9 @@

this.getUserById(data.self.id).update(data.self);
self = this.getUserById(data.self.id);
if (self) {
self.update(data.self);
} else {
// If we got here from an rtm.connect, we may not have any users
this.setUser(new models.User(data.self));
}
this.setTeam(data.team);

@@ -420,0 +427,0 @@ };

@@ -135,3 +135,3 @@ /**

var user = this.getUserByName(name);
return find(this.dms, ['user', user.id]);
return (user) ? find(this.dms, ['user', user.id]) : undefined;
};

@@ -138,0 +138,0 @@

{
"name": "@slack/client",
"version": "3.9.0",
"version": "3.10.0",
"description": "A library for creating a Slack client",

@@ -39,3 +39,3 @@ "main": "./index",

"devDependencies": {
"chai": "^3.3.0",
"chai": "^3.5.0",
"codecov": "^1.0.1",

@@ -46,3 +46,3 @@ "eslint": "^2.2.0",

"jsdoc-to-markdown": "^1.3.7",
"mocha": "~2.3.3",
"mocha": "^3.4.1",
"mocha-lcov-reporter": "^1.0.0",

@@ -49,0 +49,0 @@ "nock": "^7.2.2",

@@ -10,3 +10,3 @@ # Node Library for the Slack APIs

So you want to build a Slack app with Node.js? We've got you covered. {{ site.product_name }} is aimed at making
So you want to build a Slack app with Node.js? We've got you covered. `node-slack-sdk` is aimed at making
building Slack apps ridiculously easy. This module will help you build on all aspects of the Slack platform,

@@ -28,3 +28,3 @@ from dropping notifications in channels to fully interactive bots.

Most Slack apps are interested in posting messages into Slack channels, and generally working with our [Web API](https://api.slack.com/web). Read on
to learn how to use {{ site.product_name }} to accomplish these tasks. Bots, on the other hand, are a bit more complex,
to learn how to use `node-slack-sdk` to accomplish these tasks. Bots, on the other hand, are a bit more complex,
so we have them covered in [Building Bots](https://slackapi.github.io/node-slack-sdk/bots).

@@ -52,7 +52,7 @@

webhook.send('Hello there', function(err, res) {
if (err) {
console.log('Error:', err);
} else {
console.log('Message sent: ', res);
}
if (err) {
console.log('Error:', err);
} else {
console.log('Message sent: ', res);
}
});

@@ -76,7 +76,7 @@ ```

web.chat.postMessage('C1232456', 'Hello there', function(err, res) {
if (err) {
console.log('Error:', err);
} else {
console.log('Message sent: ', res);
}
if (err) {
console.log('Error:', err);
} else {
console.log('Message sent: ', res);
}
});

@@ -100,4 +100,9 @@ ```

// The client will emit an RTM.AUTHENTICATED event on successful connection, with the `rtm.start` payload if you want to cache it
rtm.on(CLIENT_EVENTS.RTM.AUTHENTICATED, function (rtmStartData) {
let channel;
// The client will emit an RTM.AUTHENTICATED event on successful connection, with the `rtm.start` payload
rtm.on(CLIENT_EVENTS.RTM.AUTHENTICATED, (rtmStartData) => {
for (const c of rtmStartData.channels) {
if (c.is_member && c.name ==='general') { channel = c.id }
}
console.log(`Logged in as ${rtmStartData.self.name} of team ${rtmStartData.team.name}, but not yet connected to a channel`);

@@ -104,0 +109,0 @@ });

@@ -75,2 +75,33 @@ var expect = require('chai').expect;

it('should make API calls in the order they are executed', function (done) {
var args1 = {
headers: {},
statusCode: 200,
body: '{"test": 10}'
};
var args2 = {
headers: {},
statusCode: 200,
body: '{"test": 20}'
};
var client = new WebAPIClient('test-token', { transport: mockTransport });
sinon.spy(client, 'transport');
client._makeAPICall('test', args1, null, function () {
expect(client.transport.callCount).to.equal(1);
expect(client.transport.args[0][0].data.body).to.equal('{"test": 10}');
expect(client.transport.args.length).to.equal(1);
});
client._makeAPICall('test', args2, null, function () {
expect(client.transport.callCount).to.equal(2);
expect(client.transport.args[0][0].data.body).to.equal('{"test": 10}');
expect(client.transport.args[1][0].data.body).to.equal('{"test": 20}');
expect(client.transport.args.length).to.equal(2);
});
done();
});
it('should not crash when no callback is supplied to an API request', function () {

@@ -77,0 +108,0 @@ var client = new WebAPIClient('test-token', { transport: mockTransport });

@@ -8,5 +8,10 @@ var expect = require('chai').expect;

describe('RTM API Message Handlers: Raw Events', function () {
var rtmClient;
afterEach(function () {
rtmClient.disconnect();
});
it('emits raw messages with all lower case keys unchanged', function (done) {
var rtmClient = getRtmClient();
rtmClient = getRtmClient();
rtmClient.on('raw_message', function (rawMsg) {

@@ -13,0 +18,0 @@ expect(rawMsg).to.equal(JSON.stringify(getRTMMessageFixture('im_open')));

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc