Socket
Socket
Sign inDemoInstall

@slack/client

Package Overview
Dependencies
142
Maintainers
4
Versions
57
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.3.1 to 4.4.0

1

dist/errors.d.ts

@@ -19,2 +19,3 @@ /// <reference types="node" />

PlatformError = "slackclient_platform_error",
RateLimitedError = "slackclient_rate_limited_error",
RTMSendWhileDisconnectedError = "slackclient_rtmclient_send_while_disconnected_error",

@@ -21,0 +22,0 @@ RTMSendWhileNotReadyError = "slackclient_rtmclient_send_while_not_ready_error",

@@ -14,2 +14,3 @@ "use strict";

ErrorCode["PlatformError"] = "slackclient_platform_error";
ErrorCode["RateLimitedError"] = "slackclient_rate_limited_error";
// RTMClient

@@ -16,0 +17,0 @@ ErrorCode["RTMSendWhileDisconnectedError"] = "slackclient_rtmclient_send_while_disconnected_error";

2

dist/IncomingWebhook.d.ts

@@ -19,3 +19,2 @@ import { CodedError, ErrorCode } from './errors';

* @param message the message (a simple string, or an object describing the message)
* @param callback
*/

@@ -26,3 +25,2 @@ send(message: string | IncomingWebhookSendArguments): Promise<IncomingWebhookResult>;

* Processes an HTTP response into an IncomingWebhookResult.
* @param response
*/

@@ -29,0 +27,0 @@ private buildResult;

@@ -55,3 +55,2 @@ "use strict";

* Processes an HTTP response into an IncomingWebhookResult.
* @param response
*/

@@ -58,0 +57,0 @@ buildResult(response) {

"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });

@@ -13,2 +16,3 @@ var logger_1 = require("./logger");

exports.WebClient = WebClient_1.WebClient;
__export(require("./methods"));
var RTMClient_1 = require("./RTMClient");

@@ -15,0 +19,0 @@ exports.RTMClient = RTMClient_1.RTMClient;

@@ -62,3 +62,2 @@ import { RTMClient } from './';

* Start monitoring the RTMClient. This method should only be called after the client's websocket is already open.
* @param client an RTMClient to monitor
*/

@@ -65,0 +64,0 @@ start(client: RTMClient): void;

@@ -35,3 +35,2 @@ "use strict";

* Start monitoring the RTMClient. This method should only be called after the client's websocket is already open.
* @param client an RTMClient to monitor
*/

@@ -38,0 +37,0 @@ start(client) {

@@ -55,8 +55,6 @@ /**

*/
export declare const getLogger: (name: string) => Logger;
export declare function getLogger(name: string): Logger;
/**
* INTERNAL function for transforming an external LoggerFunc type into the internal Logger interface
* @param name logger name assigned by object creating the logger
* @param loggingFunc a function to call with log data
*/
export declare function loggerFromLoggingFunc(name: string, loggingFunc: LoggingFunc): Logger;

@@ -5,2 +5,3 @@ "use strict";

const util_1 = require("./util");
let instanceCount = 0;
/**

@@ -32,4 +33,9 @@ * Severity levels for log entries

*/
// TODO: implement logger name prefixing (example plugins available on the loglevel package's site)
exports.getLogger = log.getLogger;
function getLogger(name) {
// TODO: implement logger name prefixing (example plugins available on the loglevel package's site)
const instanceNumber = instanceCount;
instanceCount += 1;
return log.getLogger(name + instanceNumber);
}
exports.getLogger = getLogger;
/**

@@ -59,7 +65,7 @@ * Decides whether `level` is more severe than the `threshold` for logging. When this returns true, logs should be

* INTERNAL function for transforming an external LoggerFunc type into the internal Logger interface
* @param name logger name assigned by object creating the logger
* @param loggingFunc a function to call with log data
*/
function loggerFromLoggingFunc(name, loggingFunc) {
const logger = log.getLogger(name);
const instanceNumber = instanceCount;
instanceCount += 1;
const logger = log.getLogger(name + instanceNumber);
logger.methodFactory = function (methodName, logLevel, loggerName) {

@@ -66,0 +72,0 @@ if (isMoreSevere(methodName, logLevel)) {

@@ -17,2 +17,14 @@ /// <reference types="node" />

}
export interface LocaleAware {
include_locale?: boolean;
}
export interface Searchable {
query: string;
highlight?: boolean;
sort: 'score' | 'timestamp';
sort_dir: 'asc' | 'desc';
}
export interface UserPerspectiveEnabled {
on_behalf_of?: string;
}
export interface CursorPaginationEnabled {

@@ -22,2 +34,4 @@ limit?: number;

}
export declare const cursorPaginationOptionKeys: Set<string>;
export declare const cursorPaginationEnabledMethods: Map<string, string>;
export interface TimelinePaginationEnabled {

@@ -28,5 +42,10 @@ oldest?: string;

}
export interface LocaleAware {
include_locale?: boolean;
export declare const timelinePaginationOptionKeys: Set<string>;
export declare const timelinePaginationEnabledMethods: Set<any>;
export interface TraditionalPagingEnabled {
page?: number;
count?: number;
}
export declare const traditionalPagingOptionKeys: Set<string>;
export declare const traditionalPagingEnabledMethods: Set<any>;
export interface Dialog {

@@ -47,3 +66,3 @@ title: string;

data_source?: 'users' | 'channels' | 'conversations' | 'external';
selected_options?: string;
selected_options?: SelectOption[];
options?: SelectOption[];

@@ -312,8 +331,8 @@ option_groups?: {

};
export declare type DndEndDndArguments = TokenOverridable;
export declare type DndEndSnoozeArguments = TokenOverridable;
export declare type DndEndDndArguments = TokenOverridable & UserPerspectiveEnabled;
export declare type DndEndSnoozeArguments = TokenOverridable & UserPerspectiveEnabled;
export declare type DndInfoArguments = TokenOverridable & {
user: string;
};
export declare type DndSetSnoozeArguments = TokenOverridable & {
export declare type DndSetSnoozeArguments = TokenOverridable & UserPerspectiveEnabled & {
num_minutes: number;

@@ -328,3 +347,3 @@ };

};
export declare type FilesInfoArguments = TokenOverridable & {
export declare type FilesInfoArguments = TokenOverridable & CursorPaginationEnabled & {
file: string;

@@ -334,7 +353,5 @@ count?: number;

};
export declare type FilesListArguments = TokenOverridable & {
export declare type FilesListArguments = TokenOverridable & TraditionalPagingEnabled & {
channel?: string;
user?: string;
count?: number;
page?: number;
ts_from?: string;

@@ -382,5 +399,6 @@ ts_to?: string;

};
export declare type GroupsHistoryArguments = TokenOverridable & CursorPaginationEnabled & TimelinePaginationEnabled & {
export declare type GroupsHistoryArguments = TokenOverridable & TimelinePaginationEnabled & {
channel: string;
unreads?: boolean;
count?: number;
};

@@ -401,3 +419,3 @@ export declare type GroupsInfoArguments = TokenOverridable & LocaleAware & {

};
export declare type GroupsListArguments = TokenOverridable & {
export declare type GroupsListArguments = TokenOverridable & CursorPaginationEnabled & {
exclude_archived?: boolean;

@@ -466,3 +484,3 @@ exclude_members?: boolean;

};
export declare type MPIMListArguments = TokenOverridable;
export declare type MPIMListArguments = TokenOverridable & CursorPaginationEnabled;
export declare type MPIMMarkArguments = TokenOverridable & {

@@ -521,6 +539,4 @@ channel: string;

};
export declare type ReactionsListArguments = TokenOverridable & {
export declare type ReactionsListArguments = TokenOverridable & TraditionalPagingEnabled & CursorPaginationEnabled & {
user?: string;
count?: number;
page?: number;
full?: boolean;

@@ -535,3 +551,3 @@ };

};
export declare type RemindersAddArguments = TokenOverridable & {
export declare type RemindersAddArguments = TokenOverridable & UserPerspectiveEnabled & {
text: string;

@@ -541,12 +557,12 @@ time: string | number;

};
export declare type RemindersCompleteArguments = TokenOverridable & {
export declare type RemindersCompleteArguments = TokenOverridable & UserPerspectiveEnabled & {
reminder: string;
};
export declare type RemindersDeleteArguments = TokenOverridable & {
export declare type RemindersDeleteArguments = TokenOverridable & UserPerspectiveEnabled & {
reminder: string;
};
export declare type RemindersInfoArguments = TokenOverridable & {
export declare type RemindersInfoArguments = TokenOverridable & UserPerspectiveEnabled & {
reminder: string;
};
export declare type RemindersListArguments = TokenOverridable;
export declare type RemindersListArguments = TokenOverridable & UserPerspectiveEnabled;
export declare type RTMConnectArguments = TokenOverridable & {

@@ -564,12 +580,5 @@ batch_presence_aware?: boolean;

};
export declare type SearchAllArguments = TokenOverridable & {
query: string;
count?: number;
page?: number;
highlight?: boolean;
sort: 'score' | 'timestamp';
sort_dir: 'asc' | 'desc';
};
export declare type SearchFilesArguments = SearchAllArguments;
export declare type SearchMessagesArguments = SearchAllArguments;
export declare type SearchAllArguments = TokenOverridable & TraditionalPagingEnabled & Searchable;
export declare type SearchFilesArguments = TokenOverridable & TraditionalPagingEnabled & Searchable;
export declare type SearchMessagesArguments = TokenOverridable & TraditionalPagingEnabled & Searchable;
export declare type StarsAddArguments = TokenOverridable & {

@@ -581,6 +590,3 @@ channel?: string;

};
export declare type StarsListArguments = TokenOverridable & {
count?: number;
page?: number;
};
export declare type StarsListArguments = TokenOverridable & TraditionalPagingEnabled & CursorPaginationEnabled;
export declare type StarsRemoveArguments = TokenOverridable & {

@@ -658,3 +664,3 @@ channel?: string;

};
export declare type UsersIdentityArguments = TokenOverridable;
export declare type UsersIdentityArguments = TokenOverridable & UserPerspectiveEnabled;
export declare type UsersInfoArguments = TokenOverridable & LocaleAware & {

@@ -683,3 +689,3 @@ user: string;

};
export declare type UsersProfileSetArguments = TokenOverridable & {
export declare type UsersProfileSetArguments = TokenOverridable & UserPerspectiveEnabled & {
profile?: string;

@@ -686,0 +692,0 @@ user?: string;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cursorPaginationOptionKeys = new Set(['limit', 'cursor']);
exports.cursorPaginationEnabledMethods = new Map(); // method : paginatedResponseProperty
exports.timelinePaginationOptionKeys = new Set(['oldest', 'latest', 'inclusive']);
exports.timelinePaginationEnabledMethods = new Set();
exports.traditionalPagingOptionKeys = new Set(['page', 'count']);
exports.traditionalPagingEnabledMethods = new Set();
exports.cursorPaginationEnabledMethods.set('apps.permissions.resources.list', 'resources');
exports.timelinePaginationEnabledMethods.add('channels.history');
exports.cursorPaginationEnabledMethods.set('channels.list', 'channels');
exports.cursorPaginationEnabledMethods.set('conversations.history', 'messages');
exports.timelinePaginationEnabledMethods.add('conversations.history');
exports.cursorPaginationEnabledMethods.set('conversations.list', 'channels');
exports.cursorPaginationEnabledMethods.set('conversations.members', 'members');
exports.cursorPaginationEnabledMethods.set('conversations.replies', 'messages');
exports.timelinePaginationEnabledMethods.add('conversations.replies');
exports.cursorPaginationEnabledMethods.set('files.info', 'comments');
exports.traditionalPagingEnabledMethods.add('files.list');
exports.timelinePaginationEnabledMethods.add('groups.history');
exports.cursorPaginationEnabledMethods.set('groups.list', 'groups');
exports.timelinePaginationEnabledMethods.add('im.history');
exports.cursorPaginationEnabledMethods.set('im.list', 'ims');
exports.timelinePaginationEnabledMethods.add('mpim.history');
exports.cursorPaginationEnabledMethods.set('mpim.list', 'groups');
exports.cursorPaginationEnabledMethods.set('reactions.list', 'items');
exports.traditionalPagingEnabledMethods.add('reactions.list');
exports.traditionalPagingEnabledMethods.add('search.all');
exports.traditionalPagingEnabledMethods.add('search.files');
exports.traditionalPagingEnabledMethods.add('search.messages');
exports.cursorPaginationEnabledMethods.set('stars.list', 'items');
exports.traditionalPagingEnabledMethods.add('stars.list');
exports.cursorPaginationEnabledMethods.set('users.conversations', 'channels');
exports.cursorPaginationEnabledMethods.set('users.list', 'members');
//# sourceMappingURL=methods.js.map

@@ -107,3 +107,2 @@ /// <reference types="node" />

* be sent or received.
* @param options arguments for the start method
*/

@@ -170,3 +169,2 @@ start(options?: methods.RTMStartArguments | methods.RTMConnectArguments): void;

* Set up method for the client's websocket instance. This method will attach event listeners.
* @param url the websocket url
*/

@@ -181,3 +179,2 @@ private setupWebsocket;

* each incoming message.
* @param websocketMessage an incoming message
*/

@@ -184,0 +181,0 @@ private onWebsocketMessage;

@@ -113,2 +113,3 @@ "use strict";

.on('failure').transitionTo('disconnected')
.on('explicit disconnect').transitionTo('disconnecting')
.state('connected')

@@ -165,10 +166,7 @@ .onEnter(() => {

.onEnter(() => {
// invariant: websocket exists and is open at the start of this state
// Most of the time, a websocket will exist. The only time it does not is when transitioning from connecting,
// before the rtm.start() has finished and the websocket hasn't been set up.
if (this.websocket !== undefined) {
this.websocket.close();
}
else {
this.logger.error('Websocket not found when transitioning into disconnecting state. Please report to ' +
'@slack/client package maintainers.');
}
})

@@ -255,3 +253,2 @@ .on('websocket close').transitionTo('disconnected')

* be sent or received.
* @param options arguments for the start method
*/

@@ -386,3 +383,2 @@ start(options) {

* Set up method for the client's websocket instance. This method will attach event listeners.
* @param url the websocket url
*/

@@ -422,3 +418,2 @@ setupWebsocket(url) {

* each incoming message.
* @param websocketMessage an incoming message
*/

@@ -474,3 +469,2 @@ onWebsocketMessage({ data }) {

* A factory to create RTMWebsocketError objects.
* @param original the original error
*/

@@ -477,0 +471,0 @@ function websocketErrorWithOriginal(original) {

/// <reference types="node" />
import * as util from 'util';
import { Agent } from 'http';

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

* Appends the app metadata into the User-Agent value
* @param appMetadata
* @param appMetadata.name name of tool to be counted in instrumentation

@@ -24,2 +22,35 @@ * @param appMetadata.version version of tool to be counted in instrumentation

/**
* Build a Promise that will resolve after the specified number of milliseconds.
* @param ms milliseconds to wait
* @param value value for eventual resolution
*/
export declare function delay<T>(ms: number, value?: T): Promise<T>;
/**
* Reduce an asynchronous iterable into a single value.
* @param iterable the async iterable to be reduced
* @param callbackfn a function that implements one step of the reduction
* @param initialValue the initial value for the accumulator
*/
export declare function awaitAndReduce<T, U>(iterable: AsyncIterable<T>, callbackfn: (previousValue: U, currentValue: T) => U, initialValue: U): Promise<U>;
/**
* Instead of depending on the util.callbackify type in the `@types/node` package, we're copying the type defintion
* of that function into an interface here. This needs to be manually updated if the type definition in that package
* changes.
*/
interface Callbackify {
(fn: () => Promise<void>): (callback: (err: NodeJS.ErrnoException) => void) => void;
<TResult>(fn: () => Promise<TResult>): (callback: (err: NodeJS.ErrnoException, result: TResult) => void) => void;
<T1, TResult>(fn: (arg1: T1) => Promise<TResult>): (arg1: T1, callback: (err: NodeJS.ErrnoException, result: TResult) => void) => void;
<T1, T2>(fn: (arg1: T1, arg2: T2) => Promise<void>): (arg1: T1, arg2: T2, callback: (err: NodeJS.ErrnoException) => void) => void;
<T1, T2, TResult>(fn: (arg1: T1, arg2: T2) => Promise<TResult>): (arg1: T1, arg2: T2, callback: (err: NodeJS.ErrnoException, result: TResult) => void) => void;
<T1, T2, T3>(fn: (arg1: T1, arg2: T2, arg3: T3) => Promise<void>): (arg1: T1, arg2: T2, arg3: T3, callback: (err: NodeJS.ErrnoException) => void) => void;
<T1, T2, T3, TResult>(fn: (arg1: T1, arg2: T2, arg3: T3) => Promise<TResult>): (arg1: T1, arg2: T2, arg3: T3, callback: (err: NodeJS.ErrnoException, result: TResult) => void) => void;
<T1, T2, T3, T4>(fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => Promise<void>): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, callback: (err: NodeJS.ErrnoException) => void) => void;
<T1, T2, T3, T4, TResult>(fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => Promise<TResult>): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, callback: (err: NodeJS.ErrnoException, result: TResult) => void) => void;
<T1, T2, T3, T4, T5>(fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5) => Promise<void>): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, callback: (err: NodeJS.ErrnoException) => void) => void;
<T1, T2, T3, T4, T5, TResult>(fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5) => Promise<TResult>): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, callback: (err: NodeJS.ErrnoException, result: TResult) => void) => void;
<T1, T2, T3, T4, T5, T6>(fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6) => Promise<void>): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, callback: (err: NodeJS.ErrnoException) => void) => void;
<T1, T2, T3, T4, T5, T6, TResult>(fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6) => Promise<TResult>): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, callback: (err: NodeJS.ErrnoException, result: TResult) => void) => void;
}
/**
* The following is a polyfill of Node >= 8.2.0's util.callbackify method. The source is copied (with some

@@ -31,3 +62,3 @@ * modification) from:

*/
export declare const callbackify: typeof util.callbackify;
export declare const callbackify: Callbackify;
export declare type AgentOption = Agent | {

@@ -44,1 +75,2 @@ http?: Agent;

}
export {};
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -14,3 +29,2 @@ const util = require("util");

* Replaces occurences of '/' with ':' in a string, since '/' is meaningful inside User-Agent strings as a separator.
* @param s
*/

@@ -26,3 +40,2 @@ function replaceSlashes(s) {

* Appends the app metadata into the User-Agent value
* @param appMetadata
* @param appMetadata.name name of tool to be counted in instrumentation

@@ -45,2 +58,43 @@ * @param appMetadata.version version of tool to be counted in instrumentation

/**
* Build a Promise that will resolve after the specified number of milliseconds.
* @param ms milliseconds to wait
* @param value value for eventual resolution
*/
function delay(ms, value) {
return new Promise((resolve) => {
setTimeout(() => resolve(value), ms);
});
}
exports.delay = delay;
/**
* Reduce an asynchronous iterable into a single value.
* @param iterable the async iterable to be reduced
* @param callbackfn a function that implements one step of the reduction
* @param initialValue the initial value for the accumulator
*/
function awaitAndReduce(iterable, callbackfn, initialValue) {
var iterable_1, iterable_1_1;
return __awaiter(this, void 0, void 0, function* () {
var e_1, _a;
// TODO: make initialValue optional (overloads or conditional types?)
let accumulator = initialValue;
try {
for (iterable_1 = __asyncValues(iterable); iterable_1_1 = yield iterable_1.next(), !iterable_1_1.done;) {
const value = iterable_1_1.value;
accumulator = callbackfn(accumulator, value);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (iterable_1_1 && !iterable_1_1.done && (_a = iterable_1.return)) yield _a.call(iterable_1);
}
finally { if (e_1) throw e_1.error; }
}
return accumulator;
});
}
exports.awaitAndReduce = awaitAndReduce;
// tslint:enable:max-line-length
/**
* The following is a polyfill of Node >= 8.2.0's util.callbackify method. The source is copied (with some

@@ -47,0 +101,0 @@ * modification) from:

@@ -0,1 +1,3 @@

/// <reference types="node" />
import { IncomingHttpHeaders } from 'http';
import EventEmitter = require('eventemitter3');

@@ -41,2 +43,10 @@ import { AgentOption, TLSOptions } from './util';

/**
* Automatic pagination page size (limit)
*/
private pageSize;
/**
* Preference for immediately rejecting API calls which result in a rate-limited response
*/
private rejectRateLimitedCalls;
/**
* The name used to prefix all logging generated from this object

@@ -56,3 +66,3 @@ */

*/
constructor(token?: string, { slackApiUrl, logger, logLevel, maxRequestConcurrency, retryConfig, agent, tls, }?: WebClientOptions);
constructor(token?: string, { slackApiUrl, logger, logLevel, maxRequestConcurrency, retryConfig, agent, tls, pageSize, rejectRateLimitedCalls, }?: WebClientOptions);
/**

@@ -165,4 +175,4 @@ * Generic method for calling a Web API method

readonly dnd: {
endDnd: Method<methods.TokenOverridable>;
endSnooze: Method<methods.TokenOverridable>;
endDnd: Method<methods.DndEndDndArguments>;
endSnooze: Method<methods.DndEndDndArguments>;
info: Method<methods.DndInfoArguments>;

@@ -238,3 +248,3 @@ setSnooze: Method<methods.DndSetSnoozeArguments>;

history: Method<methods.MPIMHistoryArguments>;
list: Method<methods.TokenOverridable>;
list: Method<methods.AppsPermissionsResourcesListArguments>;
mark: Method<methods.MPIMMarkArguments>;

@@ -276,3 +286,3 @@ open: Method<methods.MPIMOpenArguments>;

info: Method<methods.RemindersInfoArguments>;
list: Method<methods.TokenOverridable>;
list: Method<methods.DndEndDndArguments>;
};

@@ -335,3 +345,3 @@ /**

getPresence: Method<methods.UsersGetPresenceArguments>;
identity: Method<methods.TokenOverridable>;
identity: Method<methods.DndEndDndArguments>;
info: Method<methods.UsersInfoArguments>;

@@ -373,2 +383,4 @@ list: Method<methods.UsersListArguments>;

tls?: TLSOptions;
pageSize?: number;
rejectRateLimitedCalls?: boolean;
}

@@ -385,2 +397,3 @@ export interface WebAPICallOptions {

warnings?: string[];
next_cursor?: string;
};

@@ -391,3 +404,3 @@ }

}
export declare type WebAPICallError = WebAPIPlatformError | WebAPIRequestError | WebAPIReadError | WebAPIHTTPError;
export declare type WebAPICallError = WebAPIPlatformError | WebAPIRequestError | WebAPIReadError | WebAPIHTTPError | WebAPIRateLimitedError;
export interface WebAPIPlatformError extends CodedError {

@@ -410,2 +423,10 @@ code: ErrorCode.PlatformError;

original: Error;
statusCode: number;
statusMessage: string;
headers: IncomingHttpHeaders;
body?: any;
}
export interface WebAPIRateLimitedError extends CodedError {
code: ErrorCode.RateLimitedError;
retryAfter: number;
}

@@ -10,3 +10,19 @@ "use strict";

};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
Object.defineProperty(exports, "__esModule", { value: true });
// polyfill for async iterable. see: https://stackoverflow.com/a/43694282/305340
if (Symbol['asyncIterator'] === undefined) {
(Symbol['asyncIterator']) = Symbol.for('asyncIterator');
}
const path_1 = require("path");

@@ -19,3 +35,2 @@ const objectEntries = require("object.entries"); // tslint:disable-line:no-require-imports

const pRetry = require("p-retry"); // tslint:disable-line:no-require-imports
const delay = require("delay"); // tslint:disable-line:no-require-imports
// NOTE: to reduce depedency size, consider https://www.npmjs.com/package/got-lite

@@ -28,2 +43,3 @@ const got = require("got"); // tslint:disable-line:no-require-imports

const retry_policies_1 = require("./retry-policies");
const methods = require("./methods"); // tslint:disable-line:import-name
const pkg = require('../package.json'); // tslint:disable-line:no-require-imports no-var-requires

@@ -40,3 +56,3 @@ /**

*/
constructor(token, { slackApiUrl = 'https://slack.com/api/', logger = undefined, logLevel = logger_1.LogLevel.INFO, maxRequestConcurrency = 3, retryConfig = retry_policies_1.default.retryForeverExponentialCappedRandom, agent = undefined, tls = undefined, } = {}) {
constructor(token, { slackApiUrl = 'https://slack.com/api/', logger = undefined, logLevel = logger_1.LogLevel.INFO, maxRequestConcurrency = 3, retryConfig = retry_policies_1.default.retryForeverExponentialCappedRandom, agent = undefined, tls = undefined, pageSize = 200, rejectRateLimitedCalls = false, } = {}) {
super();

@@ -327,2 +343,4 @@ /**

this.tlsConfig = tls !== undefined ? tls : {};
this.pageSize = pageSize;
this.rejectRateLimitedCalls = rejectRateLimitedCalls;
// Logging

@@ -347,59 +365,134 @@ if (logger !== undefined) {

}
const requestBody = this.serializeApiCallOptions(Object.assign({ token: this.token }, options));
// The following thunk encapsulates the task so that it can be coordinated for retries
const task = () => {
this.logger.debug('request attempt');
return got.post(urlJoin(this.slackApiUrl, method),
// @ts-ignore using older definitions for package `got`, can remove when type `@types/got` is updated for v8
Object.assign({
form: !canBodyBeFormMultipart(requestBody),
body: requestBody,
retries: 0,
headers: {
'user-agent': this.userAgent,
},
agent: this.agentConfig,
}, this.tlsConfig))
.then((response) => {
const result = this.buildResult(response);
// log warnings in response metadata
if (result.response_metadata !== undefined && result.response_metadata.warnings !== undefined) {
result.response_metadata.warnings.forEach(this.logger.warn);
// warn for methods whose functionality is deprecated
if (method === 'files.comments.add' || method === 'files.comments.edit') {
this.logger.warn(`File comments are deprecated in favor of file threads. Replace uses of ${method} in your app ` +
'to take advantage of improvements. See https://api.slack.com/changelog/2018-05-file-threads-soon-tread ' +
'to learn more.');
}
// build headers
const headers = {
'user-agent': this.userAgent,
};
if (options !== undefined && optionsAreUserPerspectiveEnabled(options)) {
headers['X-Slack-User'] = options.on_behalf_of;
delete options.on_behalf_of;
}
const methodSupportsCursorPagination = methods.cursorPaginationEnabledMethods.has(method);
const optionsPaginationType = getOptionsPaginationType(options);
// warn in priority of most general pagination problem to most specific pagination problem
if (optionsPaginationType === PaginationType.Mixed) {
this.logger.warn('Options include mixed pagination techniques. ' +
'Always prefer cursor-based pagination when available');
}
else if (optionsPaginationType === PaginationType.Cursor &&
!methodSupportsCursorPagination) {
this.logger.warn('Options include cursor-based pagination while the method cannot support that technique');
}
else if (optionsPaginationType === PaginationType.Timeline &&
!methods.timelinePaginationEnabledMethods.has(method)) {
this.logger.warn('Options include timeline-based pagination while the method cannot support that technique');
}
else if (optionsPaginationType === PaginationType.Traditional &&
!methods.traditionalPagingEnabledMethods.has(method)) {
this.logger.warn('Options include traditional paging while the method cannot support that technique');
}
else if (methodSupportsCursorPagination &&
optionsPaginationType !== PaginationType.Cursor && optionsPaginationType !== PaginationType.None) {
this.logger.warn('Method supports cursor-based pagination and a different tecnique is used in options. ' +
'Always prefer cursor-based pagination when available');
}
const shouldAutoPaginate = methodSupportsCursorPagination && optionsPaginationType === PaginationType.None;
this.logger.debug(`shouldAutoPaginate: ${shouldAutoPaginate}`);
/**
* Generates a result object for each of the HTTP requests for this API call. API calls will generally only
* generate more than one result when automatic pagination is occurring.
*/
function generateResults() {
return __asyncGenerator(this, arguments, function* generateResults_1() {
// when result is undefined, that signals that the first of potentially many calls has not yet been made
let result = undefined;
// paginationOptions stores pagination options not already stored in the options argument
let paginationOptions = {};
if (shouldAutoPaginate) {
// these are the default pagination options
paginationOptions = { limit: this.pageSize };
}
if (!result.ok) {
const error = errors_1.errorWithCode(new Error(`An API error occurred: ${result.error}`), errors_1.ErrorCode.PlatformError);
error.data = result;
throw new pRetry.AbortError(error);
while (result === undefined ||
(shouldAutoPaginate &&
(objectEntries(paginationOptions = paginationOptionsForNextPage(result, this.pageSize)).length > 0))) {
const requestBody = this.serializeApiCallOptions(Object.assign({ token: this.token }, paginationOptions, options));
const task = () => this.requestQueue.add(() => __awaiter(this, void 0, void 0, function* () {
this.logger.debug('will perform http request');
try {
const response = yield got.post(urlJoin(this.slackApiUrl, method),
// @ts-ignore
Object.assign({
headers,
form: !canBodyBeFormMultipart(requestBody),
body: requestBody,
retries: 0,
throwHttpErrors: false,
agent: this.agentConfig,
}, this.tlsConfig));
this.logger.debug('http response received');
if (response.statusCode === 429) {
const retrySec = parseRetryHeaders(response);
if (retrySec !== undefined) {
this.emit('rate_limited', retrySec);
if (this.rejectRateLimitedCalls) {
throw new pRetry.AbortError(rateLimitedErrorWithDelay(retrySec));
}
this.logger.info(`API Call failed due to rate limiting. Will retry in ${retrySec} seconds.`);
// pause the request queue and then delay the rejection by the amount of time in the retry header
this.requestQueue.pause();
// NOTE: if there was a way to introspect the current RetryOperation and know what the next timeout
// would be, then we could subtract that time from the following delay, knowing that it the next
// attempt still wouldn't occur until after the rate-limit header has specified. an even better
// solution would be to subtract the time from only the timeout of this next attempt of the
// RetryOperation. this would result in the staying paused for the entire duration specified in the
// header, yet this operation not having to pay the timeout cost in addition to that.
yield util_1.delay(retrySec * 1000);
// resume the request queue and throw a non-abort error to signal a retry
this.requestQueue.start();
// TODO: turn this into a WebAPIPlatformError
throw Error('A rate limit was exceeded.');
}
else {
throw new pRetry.AbortError(new Error('Retry header did not contain a valid timeout.'));
}
}
// Slack's Web API doesn't use meaningful status codes besides 429 and 200
if (response.statusCode !== 200) {
throw httpErrorFromResponse(response);
}
result = this.buildResult(response);
// log warnings in response metadata
if (result.response_metadata !== undefined && result.response_metadata.warnings !== undefined) {
result.response_metadata.warnings.forEach(this.logger.warn);
}
if (!result.ok) {
const error = errors_1.errorWithCode(new Error(`An API error occurred: ${result.error}`), errors_1.ErrorCode.PlatformError);
error.data = result;
throw new pRetry.AbortError(error);
}
return result;
}
catch (error) {
this.logger.debug('http request failed');
if (error.name === 'RequestError') {
throw requestErrorWithOriginal(error);
}
else if (error.name === 'ReadError') {
throw readErrorWithOriginal(error);
}
throw error;
}
}));
result = yield __await(pRetry(task, this.retryConfig));
yield yield __await(result);
}
return result;
})
.catch((error) => {
// Wrap errors in this packages own error types (abstract the implementation details' types)
if (error.name === 'RequestError') {
throw requestErrorWithOriginal(error);
}
else if (error.name === 'ReadError') {
throw readErrorWithOriginal(error);
}
else if (error.name === 'HTTPError') {
// Special case: retry if 429;
if (error.statusCode === 429) {
const result = this.buildResult(error.response);
const retryAfterMs = result.retryAfter !== undefined ? result.retryAfter : (60 * 1000);
this.emit('rate_limited', retryAfterMs / 1000);
this.logger.info(`API Call failed due to rate limiting. Will retry in ${retryAfterMs / 1000} seconds.`);
// wait and return the result from calling `task` again after the specified number of seconds
return delay(retryAfterMs).then(task);
}
throw httpErrorWithOriginal(error);
}
else {
throw error;
}
});
};
// The following thunk encapsulates the retried task so that it can be coordinated for request queuing
const taskAfterRetries = () => pRetry(task, this.retryConfig);
// The final return value is the resolution of the task after being retried and queued
return this.requestQueue.add(taskAfterRetries);
}
// return a promise that resolves when a reduction of responses finishes
return util_1.awaitAndReduce(generateResults.call(this), createResultMerger(method), {});
});

@@ -464,3 +557,3 @@ // Adapt the interface for callback-based execution or Promise-based execution

}
else {
else if (key !== undefined && value !== undefined) {
form.append(key, value);

@@ -494,4 +587,5 @@ }

// add retry metadata from headers
if (response.headers['retry-after'] !== undefined) {
data.retryAfter = parseInt(response.headers['retry-after'], 10) * 1000;
const retrySec = parseRetryHeaders(response);
if (retrySec !== undefined) {
data.retryAfter = retrySec;
}

@@ -521,2 +615,8 @@ return data;

/**
* Determines whether WebAPICallOptions conform to UserPerspectiveEnabled
*/
function optionsAreUserPerspectiveEnabled(options) {
return options.on_behalf_of !== undefined;
}
/**
* A factory to create WebAPIRequestError objects

@@ -547,9 +647,125 @@ * @param original - original error

*/
function httpErrorWithOriginal(original) {
function httpErrorFromResponse(response) {
const error = errors_1.errorWithCode(
// any cast is used because the got definition file doesn't export the got.HTTPError type
new Error(`An HTTP protocol error occurred: statusCode = ${original.statusCode}`), errors_1.ErrorCode.HTTPError);
error.original = original;
new Error(`An HTTP protocol error occurred: statusCode = ${response.statusCode}`), errors_1.ErrorCode.HTTPError);
error.original = new Error('The WebAPIHTTPError.original property is deprecated. See other properties for details.');
error.statusCode = response.statusCode;
error.statusMessage = response.statusMessage;
error.headers = response.headers;
try {
error.body = JSON.parse(response.body);
}
catch (error) {
error.body = response.body;
}
return error;
}
/**
* A factory to create WebAPIRateLimitedError objects
* @param retrySec - Number of seconds that the request can be retried in
*/
function rateLimitedErrorWithDelay(retrySec) {
const error = errors_1.errorWithCode(new Error(`A rate-limit has been reached, you may retry this request in ${retrySec} seconds`), errors_1.ErrorCode.RateLimitedError);
error.retryAfter = retrySec;
return error;
}
var PaginationType;
(function (PaginationType) {
PaginationType["Cursor"] = "Cursor";
PaginationType["Timeline"] = "Timeline";
PaginationType["Traditional"] = "Traditional";
PaginationType["Mixed"] = "Mixed";
PaginationType["None"] = "None";
})(PaginationType || (PaginationType = {}));
/**
* Determines which pagination type, if any, the supplied options (a.k.a. method arguments) are using. This method is
* also able to determine if the options have mixed different pagination types.
*/
function getOptionsPaginationType(options) {
if (options === undefined) {
return PaginationType.None;
}
let optionsType = PaginationType.None;
for (const option of Object.keys(options)) {
if (optionsType === PaginationType.None) {
if (methods.cursorPaginationOptionKeys.has(option)) {
optionsType = PaginationType.Cursor;
}
else if (methods.timelinePaginationOptionKeys.has(option)) {
optionsType = PaginationType.Timeline;
}
else if (methods.traditionalPagingOptionKeys.has(option)) {
optionsType = PaginationType.Traditional;
}
}
else if (optionsType === PaginationType.Cursor) {
if (methods.timelinePaginationOptionKeys.has(option) || methods.traditionalPagingOptionKeys.has(option)) {
return PaginationType.Mixed;
}
}
else if (optionsType === PaginationType.Timeline) {
if (methods.cursorPaginationOptionKeys.has(option) || methods.traditionalPagingOptionKeys.has(option)) {
return PaginationType.Mixed;
}
}
else if (optionsType === PaginationType.Traditional) {
if (methods.cursorPaginationOptionKeys.has(option) || methods.timelinePaginationOptionKeys.has(option)) {
return PaginationType.Mixed;
}
}
}
return optionsType;
}
/**
* Creates a function that can reduce a result into an accumulated result. This is used for reducing many results from
* automatically paginated API calls into a single result. It depends on metadata in the 'method' import.
* @param method - the API method for which a result merging function is needed
*/
function createResultMerger(method) {
if (methods.cursorPaginationEnabledMethods.has(method)) {
const paginatedResponseProperty = methods.cursorPaginationEnabledMethods.get(method);
return (accumulator, result) => {
for (const resultProperty of Object.keys(result)) {
if (resultProperty === paginatedResponseProperty) {
if (accumulator[resultProperty] === undefined) {
accumulator[resultProperty] = [];
}
accumulator[resultProperty] = accumulator[resultProperty].concat(result[resultProperty]);
}
else {
accumulator[resultProperty] = result[resultProperty];
}
}
return accumulator;
};
}
// For all methods who don't use cursor-pagination, return the identity reduction function
return (_, result) => result;
}
/**
* Determines an appropriate set of cursor pagination options for the next request to a paginated API method.
* @param previousResult - the result of the last request, where the next cursor might be found.
* @param pageSize - the maximum number of additional items to fetch in the next request.
*/
function paginationOptionsForNextPage(previousResult, pageSize) {
const paginationOptions = {};
if (previousResult.response_metadata !== undefined &&
previousResult.response_metadata.next_cursor !== undefined &&
previousResult.response_metadata.next_cursor !== '') {
paginationOptions.limit = pageSize;
paginationOptions.cursor = previousResult.response_metadata.next_cursor;
}
return paginationOptions;
}
/**
* Extract the amount of time (in seconds) the platform has recommended this client wait before sending another request
* from a rate-limited HTTP response (statusCode = 429).
*/
function parseRetryHeaders(response) {
if (response.headers['retry-after'] !== undefined) {
return parseInt(response.headers['retry-after'], 10);
}
return undefined;
}
//# sourceMappingURL=WebClient.js.map
{
"name": "@slack/client",
"version": "4.3.1",
"version": "4.4.0",
"description": "Slack Developer Kit - official clients for the Web API, RTM API, and Incoming Webhooks",

@@ -46,3 +46,2 @@ "author": "Slack Technologies, Inc.",

"dependencies": {
"@types/delay": "^2.0.1",
"@types/form-data": "^2.2.1",

@@ -52,3 +51,3 @@ "@types/got": "^7.1.7",

"@types/loglevel": "^1.5.3",
"@types/node": "^9.4.7",
"@types/node": ">=6.0.0",
"@types/p-cancelable": "^0.3.0",

@@ -60,3 +59,2 @@ "@types/p-queue": "^2.3.1",

"@types/ws": "^5.1.1",
"delay": "^2.0.0",
"eventemitter3": "^3.0.0",

@@ -73,4 +71,4 @@ "finity": "^0.5.4",

"p-queue": "^2.3.0",
"p-retry": "^1.0.0",
"retry": "^0.10.1",
"p-retry": "^2.0.0",
"retry": "^0.12.0",
"url-join": "^4.0.0",

@@ -80,6 +78,6 @@ "ws": "^5.2.0"

"devDependencies": {
"@aoberoi/capture-console": "^1.0.0",
"@types/chai": "^4.1.2",
"@types/mocha": "^2.2.48",
"busboy": "^0.2.14",
"capture-stdout": "^1.0.0",
"chai": "^4.1.2",

@@ -86,0 +84,0 @@ "codecov": "^3.0.0",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc