@slack/bolt 3.7.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +4 -2
  2. package/dist/package.json +88 -0
  3. package/package.json +4 -4
  4. package/dist/App.d.ts +0 -159
  5. package/dist/App.d.ts.map +0 -1
  6. package/dist/App.js +0 -758
  7. package/dist/App.js.map +0 -1
  8. package/dist/WorkflowStep.d.ts +0 -106
  9. package/dist/WorkflowStep.d.ts.map +0 -1
  10. package/dist/WorkflowStep.js +0 -198
  11. package/dist/WorkflowStep.js.map +0 -1
  12. package/dist/conversation-store.d.ts +0 -31
  13. package/dist/conversation-store.d.ts.map +0 -1
  14. package/dist/conversation-store.js +0 -74
  15. package/dist/conversation-store.js.map +0 -1
  16. package/dist/errors.d.ts +0 -75
  17. package/dist/errors.d.ts.map +0 -1
  18. package/dist/errors.js +0 -112
  19. package/dist/errors.js.map +0 -1
  20. package/dist/helpers.d.ts +0 -24
  21. package/dist/helpers.d.ts.map +0 -1
  22. package/dist/helpers.js +0 -100
  23. package/dist/helpers.js.map +0 -1
  24. package/dist/index.d.ts +0 -13
  25. package/dist/index.d.ts.map +0 -1
  26. package/dist/index.js +0 -43
  27. package/dist/index.js.map +0 -1
  28. package/dist/middleware/builtin.d.ts +0 -52
  29. package/dist/middleware/builtin.d.ts.map +0 -1
  30. package/dist/middleware/builtin.js +0 -337
  31. package/dist/middleware/builtin.js.map +0 -1
  32. package/dist/middleware/process.d.ts +0 -5
  33. package/dist/middleware/process.d.ts.map +0 -1
  34. package/dist/middleware/process.js +0 -25
  35. package/dist/middleware/process.js.map +0 -1
  36. package/dist/receivers/AwsLambdaReceiver.d.ts +0 -50
  37. package/dist/receivers/AwsLambdaReceiver.d.ts.map +0 -1
  38. package/dist/receivers/AwsLambdaReceiver.js +0 -184
  39. package/dist/receivers/AwsLambdaReceiver.js.map +0 -1
  40. package/dist/receivers/ExpressReceiver.d.ts +0 -74
  41. package/dist/receivers/ExpressReceiver.d.ts.map +0 -1
  42. package/dist/receivers/ExpressReceiver.js +0 -440
  43. package/dist/receivers/ExpressReceiver.js.map +0 -1
  44. package/dist/receivers/HTTPReceiver.d.ts +0 -72
  45. package/dist/receivers/HTTPReceiver.d.ts.map +0 -1
  46. package/dist/receivers/HTTPReceiver.js +0 -431
  47. package/dist/receivers/HTTPReceiver.js.map +0 -1
  48. package/dist/receivers/SocketModeReceiver.d.ts +0 -57
  49. package/dist/receivers/SocketModeReceiver.d.ts.map +0 -1
  50. package/dist/receivers/SocketModeReceiver.js +0 -163
  51. package/dist/receivers/SocketModeReceiver.js.map +0 -1
  52. package/dist/receivers/custom-routes.d.ts +0 -14
  53. package/dist/receivers/custom-routes.d.ts.map +0 -1
  54. package/dist/receivers/custom-routes.js +0 -33
  55. package/dist/receivers/custom-routes.js.map +0 -1
  56. package/dist/receivers/render-html-for-install-path.d.ts +0 -3
  57. package/dist/receivers/render-html-for-install-path.d.ts.map +0 -1
  58. package/dist/receivers/render-html-for-install-path.js +0 -25
  59. package/dist/receivers/render-html-for-install-path.js.map +0 -1
  60. package/dist/receivers/verify-redirect-opts.d.ts +0 -7
  61. package/dist/receivers/verify-redirect-opts.d.ts.map +0 -1
  62. package/dist/receivers/verify-redirect-opts.js +0 -23
  63. package/dist/receivers/verify-redirect-opts.js.map +0 -1
  64. package/dist/receivers/verify-request.d.ts +0 -41
  65. package/dist/receivers/verify-request.d.ts.map +0 -1
  66. package/dist/receivers/verify-request.js +0 -98
  67. package/dist/receivers/verify-request.js.map +0 -1
  68. package/dist/types/actions/block-action.d.ts +0 -224
  69. package/dist/types/actions/block-action.d.ts.map +0 -1
  70. package/dist/types/actions/block-action.js +0 -3
  71. package/dist/types/actions/block-action.js.map +0 -1
  72. package/dist/types/actions/dialog-action.d.ts +0 -47
  73. package/dist/types/actions/dialog-action.d.ts.map +0 -1
  74. package/dist/types/actions/dialog-action.js +0 -3
  75. package/dist/types/actions/dialog-action.js.map +0 -1
  76. package/dist/types/actions/index.d.ts +0 -46
  77. package/dist/types/actions/index.d.ts.map +0 -1
  78. package/dist/types/actions/index.js +0 -17
  79. package/dist/types/actions/index.js.map +0 -1
  80. package/dist/types/actions/interactive-message.d.ts +0 -66
  81. package/dist/types/actions/interactive-message.d.ts.map +0 -1
  82. package/dist/types/actions/interactive-message.js +0 -3
  83. package/dist/types/actions/interactive-message.js.map +0 -1
  84. package/dist/types/actions/workflow-step-edit.d.ts +0 -49
  85. package/dist/types/actions/workflow-step-edit.d.ts.map +0 -1
  86. package/dist/types/actions/workflow-step-edit.js +0 -3
  87. package/dist/types/actions/workflow-step-edit.js.map +0 -1
  88. package/dist/types/command/index.d.ts +0 -36
  89. package/dist/types/command/index.d.ts.map +0 -1
  90. package/dist/types/command/index.js +0 -3
  91. package/dist/types/command/index.js.map +0 -1
  92. package/dist/types/events/base-events.d.ts +0 -699
  93. package/dist/types/events/base-events.d.ts.map +0 -1
  94. package/dist/types/events/base-events.js +0 -5
  95. package/dist/types/events/base-events.js.map +0 -1
  96. package/dist/types/events/index.d.ts +0 -63
  97. package/dist/types/events/index.d.ts.map +0 -1
  98. package/dist/types/events/index.js +0 -14
  99. package/dist/types/events/index.js.map +0 -1
  100. package/dist/types/events/message-events.d.ts +0 -312
  101. package/dist/types/events/message-events.d.ts.map +0 -1
  102. package/dist/types/events/message-events.js +0 -3
  103. package/dist/types/events/message-events.js.map +0 -1
  104. package/dist/types/helpers.d.ts +0 -17
  105. package/dist/types/helpers.d.ts.map +0 -1
  106. package/dist/types/helpers.js +0 -3
  107. package/dist/types/helpers.js.map +0 -1
  108. package/dist/types/index.d.ts +0 -10
  109. package/dist/types/index.d.ts.map +0 -1
  110. package/dist/types/index.js +0 -22
  111. package/dist/types/index.js.map +0 -1
  112. package/dist/types/middleware.d.ts +0 -56
  113. package/dist/types/middleware.d.ts.map +0 -1
  114. package/dist/types/middleware.js +0 -3
  115. package/dist/types/middleware.js.map +0 -1
  116. package/dist/types/options/index.d.ts +0 -192
  117. package/dist/types/options/index.d.ts.map +0 -1
  118. package/dist/types/options/index.js +0 -3
  119. package/dist/types/options/index.js.map +0 -1
  120. package/dist/types/receiver.d.ts +0 -13
  121. package/dist/types/receiver.d.ts.map +0 -1
  122. package/dist/types/receiver.js +0 -3
  123. package/dist/types/receiver.js.map +0 -1
  124. package/dist/types/shortcuts/global-shortcut.d.ts +0 -29
  125. package/dist/types/shortcuts/global-shortcut.d.ts.map +0 -1
  126. package/dist/types/shortcuts/global-shortcut.js +0 -3
  127. package/dist/types/shortcuts/global-shortcut.js.map +0 -1
  128. package/dist/types/shortcuts/index.d.ts +0 -23
  129. package/dist/types/shortcuts/index.d.ts.map +0 -1
  130. package/dist/types/shortcuts/index.js +0 -16
  131. package/dist/types/shortcuts/index.js.map +0 -1
  132. package/dist/types/shortcuts/message-shortcut.d.ts +0 -43
  133. package/dist/types/shortcuts/message-shortcut.d.ts.map +0 -1
  134. package/dist/types/shortcuts/message-shortcut.js +0 -3
  135. package/dist/types/shortcuts/message-shortcut.js.map +0 -1
  136. package/dist/types/utilities.d.ts +0 -23
  137. package/dist/types/utilities.d.ts.map +0 -1
  138. package/dist/types/utilities.js +0 -3
  139. package/dist/types/utilities.js.map +0 -1
  140. package/dist/types/view/index.d.ts +0 -175
  141. package/dist/types/view/index.d.ts.map +0 -1
  142. package/dist/types/view/index.js +0 -3
  143. package/dist/types/view/index.js.map +0 -1
package/dist/App.js DELETED
@@ -1,758 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.LogLevel = void 0;
7
- const util_1 = __importDefault(require("util"));
8
- const web_api_1 = require("@slack/web-api");
9
- const logger_1 = require("@slack/logger");
10
- const axios_1 = __importDefault(require("axios"));
11
- const SocketModeReceiver_1 = __importDefault(require("./receivers/SocketModeReceiver"));
12
- const HTTPReceiver_1 = __importDefault(require("./receivers/HTTPReceiver"));
13
- const builtin_1 = require("./middleware/builtin");
14
- const process_1 = __importDefault(require("./middleware/process"));
15
- const conversation_store_1 = require("./conversation-store");
16
- const helpers_1 = require("./helpers");
17
- const errors_1 = require("./errors");
18
- // eslint-disable-next-line import/order
19
- const allSettled = require("promise.allsettled"); // eslint-disable-line @typescript-eslint/no-require-imports
20
- // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-commonjs
21
- const packageJson = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires
22
- // ----------------------------
23
- // For listener registration methods
24
- const validViewTypes = ['view_closed', 'view_submission'];
25
- // ----------------------------
26
- // For the constructor
27
- const tokenUsage = 'Apps used in one workspace should be initialized with a token. Apps used in many workspaces ' +
28
- 'should be initialized with oauth installer or authorize.';
29
- var logger_2 = require("@slack/logger");
30
- Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return logger_2.LogLevel; } });
31
- class WebClientPool {
32
- constructor() {
33
- this.pool = {};
34
- }
35
- getOrCreate(token, clientOptions) {
36
- const cachedClient = this.pool[token];
37
- if (typeof cachedClient !== 'undefined') {
38
- return cachedClient;
39
- }
40
- const client = new web_api_1.WebClient(token, clientOptions);
41
- this.pool[token] = client;
42
- return client;
43
- }
44
- }
45
- /**
46
- * A Slack App
47
- */
48
- class App {
49
- constructor({ signingSecret = undefined, endpoints = undefined, customRoutes = undefined, agent = undefined, clientTls = undefined, receiver = undefined, convoStore = undefined, token = undefined, appToken = undefined, botId = undefined, botUserId = undefined, authorize = undefined, logger = undefined, logLevel = undefined, ignoreSelf = true, clientOptions = undefined, processBeforeResponse = false, signatureVerification = true, clientId = undefined, clientSecret = undefined, stateSecret = undefined, redirectUri = undefined, installationStore = undefined, scopes = undefined, installerOptions = undefined, socketMode = undefined, developerMode = false, tokenVerificationEnabled = true, } = {}) {
50
- // Some payloads don't have teamId anymore. So we use EnterpriseId in those scenarios
51
- this.clients = {};
52
- // this.logLevel = logLevel;
53
- this.developerMode = developerMode;
54
- if (developerMode) {
55
- // Set logLevel to Debug in Developer Mode if one wasn't passed in
56
- this.logLevel = logLevel !== null && logLevel !== void 0 ? logLevel : logger_1.LogLevel.DEBUG;
57
- // Set SocketMode to true if one wasn't passed in
58
- this.socketMode = socketMode !== null && socketMode !== void 0 ? socketMode : true;
59
- }
60
- else {
61
- // If devs aren't using Developer Mode or Socket Mode, set it to false
62
- this.socketMode = socketMode !== null && socketMode !== void 0 ? socketMode : false;
63
- // Set logLevel to Info if one wasn't passed in
64
- this.logLevel = logLevel !== null && logLevel !== void 0 ? logLevel : logger_1.LogLevel.INFO;
65
- }
66
- // Set up logger
67
- if (typeof logger === 'undefined') {
68
- // Initialize with the default logger
69
- const consoleLogger = new logger_1.ConsoleLogger();
70
- consoleLogger.setName('bolt-app');
71
- this.logger = consoleLogger;
72
- }
73
- else {
74
- this.logger = logger;
75
- }
76
- if (typeof this.logLevel !== 'undefined' && this.logger.getLevel() !== this.logLevel) {
77
- this.logger.setLevel(this.logLevel);
78
- }
79
- this.errorHandler = defaultErrorHandler(this.logger);
80
- // Set up client options
81
- this.clientOptions = clientOptions !== undefined ? clientOptions : {};
82
- if (agent !== undefined && this.clientOptions.agent === undefined) {
83
- this.clientOptions.agent = agent;
84
- }
85
- if (clientTls !== undefined && this.clientOptions.tls === undefined) {
86
- this.clientOptions.tls = clientTls;
87
- }
88
- if (logLevel !== undefined && logger === undefined) {
89
- // only logLevel is passed
90
- this.clientOptions.logLevel = logLevel;
91
- }
92
- else {
93
- // Since v3.4, WebClient starts sharing logger with App
94
- this.clientOptions.logger = this.logger;
95
- }
96
- // The public WebClient instance (app.client)
97
- // Since v3.4, it can have the passed token in the case of single workspace installation.
98
- this.client = new web_api_1.WebClient(token, this.clientOptions);
99
- this.axios = axios_1.default.create({
100
- httpAgent: agent,
101
- httpsAgent: agent,
102
- // disabling axios' automatic proxy support:
103
- // axios would read from envvars to configure a proxy automatically, but it doesn't support TLS destinations.
104
- // for compatibility with https://api.slack.com, and for a larger set of possible proxies (SOCKS or other
105
- // protocols), users of this package should use the `agent` option to configure a proxy.
106
- proxy: false,
107
- ...clientTls,
108
- });
109
- this.middleware = [];
110
- this.listeners = [];
111
- // Add clientOptions to InstallerOptions to pass them to @slack/oauth
112
- this.installerOptions = {
113
- clientOptions: this.clientOptions,
114
- ...installerOptions,
115
- };
116
- if (this.developerMode &&
117
- this.installerOptions &&
118
- (typeof this.installerOptions.callbackOptions === 'undefined' ||
119
- (typeof this.installerOptions.callbackOptions !== 'undefined' &&
120
- typeof this.installerOptions.callbackOptions.failure === 'undefined'))) {
121
- // add a custom failure callback for Developer Mode in case they are using OAuth
122
- this.logger.debug('adding Developer Mode custom OAuth failure handler');
123
- this.installerOptions.callbackOptions = {
124
- failure: (error, _installOptions, _req, res) => {
125
- this.logger.debug(error);
126
- res.writeHead(500, { 'Content-Type': 'text/html' });
127
- res.end(`<html><body><h1>OAuth failed!</h1><div>${error}</div></body></html>`);
128
- },
129
- };
130
- }
131
- // Initialize receiver
132
- if (receiver !== undefined) {
133
- // Custom receiver
134
- if (this.socketMode) {
135
- throw new errors_1.AppInitializationError('receiver cannot be passed when socketMode is set to true');
136
- }
137
- this.receiver = receiver;
138
- }
139
- else if (this.socketMode) {
140
- if (appToken === undefined) {
141
- throw new errors_1.AppInitializationError('You must provide an appToken when using Socket Mode');
142
- }
143
- this.logger.debug('Initializing SocketModeReceiver');
144
- // Create default SocketModeReceiver
145
- this.receiver = new SocketModeReceiver_1.default({
146
- appToken,
147
- clientId,
148
- clientSecret,
149
- stateSecret,
150
- redirectUri,
151
- installationStore,
152
- scopes,
153
- logger,
154
- logLevel: this.logLevel,
155
- installerOptions: this.installerOptions,
156
- customRoutes,
157
- });
158
- }
159
- else if (signatureVerification && signingSecret === undefined) {
160
- // No custom receiver
161
- throw new errors_1.AppInitializationError('Signing secret not found, so could not initialize the default receiver. Set a signing secret or use a ' +
162
- 'custom receiver.');
163
- }
164
- else {
165
- this.logger.debug('Initializing HTTPReceiver');
166
- // Create default HTTPReceiver
167
- this.receiver = new HTTPReceiver_1.default({
168
- signingSecret: signingSecret || '',
169
- endpoints,
170
- customRoutes,
171
- processBeforeResponse,
172
- signatureVerification,
173
- clientId,
174
- clientSecret,
175
- stateSecret,
176
- redirectUri,
177
- installationStore,
178
- scopes,
179
- logger,
180
- logLevel: this.logLevel,
181
- installerOptions: this.installerOptions,
182
- });
183
- }
184
- let usingOauth = false;
185
- const httpReceiver = this.receiver;
186
- if (httpReceiver.installer !== undefined &&
187
- httpReceiver.installer.authorize !== undefined) {
188
- // This supports using the built in HTTPReceiver, declaring your own HTTPReceiver
189
- // and theoretically, doing a fully custom (non express) receiver that implements OAuth
190
- usingOauth = true;
191
- }
192
- if (token !== undefined) {
193
- if (authorize !== undefined || usingOauth) {
194
- throw new errors_1.AppInitializationError(`token as well as authorize or oauth installer options were provided. ${tokenUsage}`);
195
- }
196
- this.authorize = singleAuthorization(this.client, {
197
- botId,
198
- botUserId,
199
- botToken: token,
200
- }, tokenVerificationEnabled);
201
- }
202
- else if (authorize === undefined && !usingOauth) {
203
- throw new errors_1.AppInitializationError(`No token, no authorize, and no oauth installer options provided. ${tokenUsage}`);
204
- }
205
- else if (authorize !== undefined && usingOauth) {
206
- throw new errors_1.AppInitializationError(`Both authorize options and oauth installer options provided. ${tokenUsage}`);
207
- }
208
- else if (authorize === undefined && usingOauth) {
209
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
210
- this.authorize = httpReceiver.installer.authorize;
211
- }
212
- else if (authorize !== undefined && !usingOauth) {
213
- this.authorize = authorize;
214
- }
215
- else {
216
- this.logger.error('Never should have reached this point, please report to the team');
217
- (0, helpers_1.assertNever)();
218
- }
219
- // Conditionally use a global middleware that ignores events (including messages) that are sent from this app
220
- if (ignoreSelf) {
221
- this.use((0, builtin_1.ignoreSelf)());
222
- }
223
- // Use conversation state global middleware
224
- if (convoStore !== false) {
225
- // Use the memory store by default, or another store if provided
226
- const store = convoStore === undefined ? new conversation_store_1.MemoryStore() : convoStore;
227
- this.use((0, conversation_store_1.conversationContext)(store));
228
- }
229
- // Should be last to avoid exposing partially initialized app
230
- this.receiver.init(this);
231
- }
232
- /**
233
- * Register a new middleware, processed in the order registered.
234
- *
235
- * @param m global middleware function
236
- */
237
- use(m) {
238
- this.middleware.push(m);
239
- return this;
240
- }
241
- /**
242
- * Register WorkflowStep middleware
243
- *
244
- * @param workflowStep global workflow step middleware function
245
- */
246
- step(workflowStep) {
247
- const m = workflowStep.getMiddleware();
248
- this.middleware.push(m);
249
- return this;
250
- }
251
- /**
252
- * Convenience method to call start on the receiver
253
- *
254
- * TODO: should replace HTTPReceiver in type definition with a generic that is constrained to Receiver
255
- *
256
- * @param args receiver-specific start arguments
257
- */
258
- start(...args) {
259
- // TODO: HTTPReceiver['start'] should be the actual receiver's return type
260
- return this.receiver.start(...args);
261
- }
262
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
263
- stop(...args) {
264
- return this.receiver.stop(...args);
265
- }
266
- event(eventNameOrPattern, ...listeners) {
267
- let invalidEventName = false;
268
- if (typeof eventNameOrPattern === 'string') {
269
- const name = eventNameOrPattern;
270
- invalidEventName = name.startsWith('message.');
271
- }
272
- else if (eventNameOrPattern instanceof RegExp) {
273
- const name = eventNameOrPattern.source;
274
- invalidEventName = name.startsWith('message\\.');
275
- }
276
- if (invalidEventName) {
277
- throw new errors_1.AppInitializationError(`Although the document mentions "${eventNameOrPattern}",` +
278
- 'it is not a valid event type. Use "message" instead. ' +
279
- 'If you want to filter message events, you can use event.channel_type for it.');
280
- }
281
- this.listeners.push([
282
- builtin_1.onlyEvents,
283
- (0, builtin_1.matchEventType)(eventNameOrPattern),
284
- ...listeners,
285
- ]);
286
- }
287
- message(...patternsOrMiddleware) {
288
- const messageMiddleware = patternsOrMiddleware.map((patternOrMiddleware) => {
289
- if (typeof patternOrMiddleware === 'string' || util_1.default.types.isRegExp(patternOrMiddleware)) {
290
- return (0, builtin_1.matchMessage)(patternOrMiddleware);
291
- }
292
- return patternOrMiddleware;
293
- });
294
- this.listeners.push([
295
- builtin_1.onlyEvents,
296
- (0, builtin_1.matchEventType)('message'),
297
- ...messageMiddleware,
298
- ]);
299
- }
300
- shortcut(callbackIdOrConstraints, ...listeners) {
301
- const constraints = typeof callbackIdOrConstraints === 'string' || util_1.default.types.isRegExp(callbackIdOrConstraints) ?
302
- { callback_id: callbackIdOrConstraints } :
303
- callbackIdOrConstraints;
304
- // Fail early if the constraints contain invalid keys
305
- const unknownConstraintKeys = Object.keys(constraints).filter((k) => k !== 'callback_id' && k !== 'type');
306
- if (unknownConstraintKeys.length > 0) {
307
- this.logger.error(`Slack listener cannot be attached using unknown constraint keys: ${unknownConstraintKeys.join(', ')}`);
308
- return;
309
- }
310
- this.listeners.push([
311
- builtin_1.onlyShortcuts,
312
- (0, builtin_1.matchConstraints)(constraints),
313
- ...listeners,
314
- ]);
315
- }
316
- action(actionIdOrConstraints, ...listeners) {
317
- // Normalize Constraints
318
- const constraints = typeof actionIdOrConstraints === 'string' || util_1.default.types.isRegExp(actionIdOrConstraints) ?
319
- { action_id: actionIdOrConstraints } :
320
- actionIdOrConstraints;
321
- // Fail early if the constraints contain invalid keys
322
- const unknownConstraintKeys = Object.keys(constraints).filter((k) => k !== 'action_id' && k !== 'block_id' && k !== 'callback_id' && k !== 'type');
323
- if (unknownConstraintKeys.length > 0) {
324
- this.logger.error(`Action listener cannot be attached using unknown constraint keys: ${unknownConstraintKeys.join(', ')}`);
325
- return;
326
- }
327
- this.listeners.push([builtin_1.onlyActions, (0, builtin_1.matchConstraints)(constraints), ...listeners]);
328
- }
329
- command(commandName, ...listeners) {
330
- this.listeners.push([builtin_1.onlyCommands, (0, builtin_1.matchCommandName)(commandName), ...listeners]);
331
- }
332
- // TODO: reflect the type in constraits to Source
333
- options(actionIdOrConstraints, ...listeners) {
334
- const constraints = typeof actionIdOrConstraints === 'string' || util_1.default.types.isRegExp(actionIdOrConstraints) ?
335
- { action_id: actionIdOrConstraints } :
336
- actionIdOrConstraints;
337
- this.listeners.push([builtin_1.onlyOptions, (0, builtin_1.matchConstraints)(constraints), ...listeners]);
338
- }
339
- view(callbackIdOrConstraints, ...listeners) {
340
- const constraints = typeof callbackIdOrConstraints === 'string' || util_1.default.types.isRegExp(callbackIdOrConstraints) ?
341
- { callback_id: callbackIdOrConstraints, type: 'view_submission' } :
342
- callbackIdOrConstraints;
343
- // Fail early if the constraints contain invalid keys
344
- const unknownConstraintKeys = Object.keys(constraints).filter((k) => k !== 'callback_id' && k !== 'type');
345
- if (unknownConstraintKeys.length > 0) {
346
- this.logger.error(`View listener cannot be attached using unknown constraint keys: ${unknownConstraintKeys.join(', ')}`);
347
- return;
348
- }
349
- if (constraints.type !== undefined && !validViewTypes.includes(constraints.type)) {
350
- this.logger.error(`View listener cannot be attached using unknown view event type: ${constraints.type}`);
351
- return;
352
- }
353
- this.listeners.push([
354
- builtin_1.onlyViewActions,
355
- (0, builtin_1.matchConstraints)(constraints),
356
- ...listeners,
357
- ]);
358
- }
359
- error(errorHandler) {
360
- this.errorHandler = errorHandler;
361
- }
362
- /**
363
- * Handles events from the receiver
364
- */
365
- async processEvent(event) {
366
- const { body, ack } = event;
367
- if (this.developerMode) {
368
- // log the body of the event
369
- // this may contain sensitive info like tokens
370
- this.logger.debug(JSON.stringify(body));
371
- }
372
- // TODO: when generating errors (such as in the say utility) it may become useful to capture the current context,
373
- // or even all of the args, as properties of the error. This would give error handling code some ability to deal
374
- // with "finally" type error situations.
375
- // Introspect the body to determine what type of incoming event is being handled, and any channel context
376
- const { type, conversationId } = (0, helpers_1.getTypeAndConversation)(body);
377
- // If the type could not be determined, warn and exit
378
- if (type === undefined) {
379
- this.logger.warn('Could not determine the type of an incoming event. No listeners will be called.');
380
- return;
381
- }
382
- // From this point on, we assume that body is not just a key-value map, but one of the types of bodies we expect
383
- const bodyArg = body;
384
- // Check if type event with the authorizations object or if it has a top level is_enterprise_install property
385
- const isEnterpriseInstall = isBodyWithTypeEnterpriseInstall(bodyArg, type);
386
- const source = buildSource(type, conversationId, bodyArg, isEnterpriseInstall);
387
- let authorizeResult;
388
- try {
389
- if (source.isEnterpriseInstall) {
390
- authorizeResult = await this.authorize(source, bodyArg);
391
- }
392
- else {
393
- authorizeResult = await this.authorize(source, bodyArg);
394
- }
395
- }
396
- catch (error) {
397
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
398
- const e = error;
399
- this.logger.warn('Authorization of incoming event did not succeed. No listeners will be called.');
400
- e.code = errors_1.ErrorCode.AuthorizationError;
401
- // disabling due to https://github.com/typescript-eslint/typescript-eslint/issues/1277
402
- // eslint-disable-next-line consistent-return
403
- return this.handleError(e);
404
- }
405
- // Try to set teamId from AuthorizeResult before using one from source
406
- if (authorizeResult.teamId === undefined && source.teamId !== undefined) {
407
- authorizeResult.teamId = source.teamId;
408
- }
409
- // Try to set enterpriseId from AuthorizeResult before using one from source
410
- if (authorizeResult.enterpriseId === undefined && source.enterpriseId !== undefined) {
411
- authorizeResult.enterpriseId = source.enterpriseId;
412
- }
413
- const context = { ...authorizeResult };
414
- // Factory for say() utility
415
- const createSay = (channelId) => {
416
- const token = selectToken(context);
417
- return (message) => {
418
- const postMessageArguments = typeof message === 'string' ?
419
- { token, text: message, channel: channelId } :
420
- { ...message, token, channel: channelId };
421
- return this.client.chat.postMessage(postMessageArguments);
422
- };
423
- };
424
- // Set body and payload
425
- // TODO: this value should eventually conform to AnyMiddlewareArgs
426
- let payload;
427
- switch (type) {
428
- case helpers_1.IncomingEventType.Event:
429
- payload = bodyArg.event;
430
- break;
431
- case helpers_1.IncomingEventType.ViewAction:
432
- payload = bodyArg.view;
433
- break;
434
- case helpers_1.IncomingEventType.Shortcut:
435
- payload = bodyArg;
436
- break;
437
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
438
- // @ts-ignore: Fallthrough case in switch
439
- case helpers_1.IncomingEventType.Action:
440
- if (isBlockActionOrInteractiveMessageBody(bodyArg)) {
441
- const { actions } = bodyArg;
442
- [payload] = actions;
443
- break;
444
- }
445
- // If above conditional does not hit, fall through to fallback payload in default block below
446
- default:
447
- payload = bodyArg;
448
- break;
449
- }
450
- // NOTE: the following doesn't work because... distributive?
451
- // const listenerArgs: Partial<AnyMiddlewareArgs> = {
452
- const listenerArgs = {
453
- body: bodyArg,
454
- payload,
455
- };
456
- // Set aliases
457
- if (type === helpers_1.IncomingEventType.Event) {
458
- const eventListenerArgs = listenerArgs;
459
- eventListenerArgs.event = eventListenerArgs.payload;
460
- if (eventListenerArgs.event.type === 'message') {
461
- const messageEventListenerArgs = eventListenerArgs;
462
- messageEventListenerArgs.message = messageEventListenerArgs.payload;
463
- }
464
- }
465
- else if (type === helpers_1.IncomingEventType.Action) {
466
- const actionListenerArgs = listenerArgs;
467
- actionListenerArgs.action = actionListenerArgs.payload;
468
- }
469
- else if (type === helpers_1.IncomingEventType.Command) {
470
- const commandListenerArgs = listenerArgs;
471
- commandListenerArgs.command = commandListenerArgs.payload;
472
- }
473
- else if (type === helpers_1.IncomingEventType.Options) {
474
- const optionListenerArgs = listenerArgs;
475
- optionListenerArgs.options = optionListenerArgs.payload;
476
- }
477
- else if (type === helpers_1.IncomingEventType.ViewAction) {
478
- const viewListenerArgs = listenerArgs;
479
- viewListenerArgs.view = viewListenerArgs.payload;
480
- }
481
- else if (type === helpers_1.IncomingEventType.Shortcut) {
482
- const shortcutListenerArgs = listenerArgs;
483
- shortcutListenerArgs.shortcut = shortcutListenerArgs.payload;
484
- }
485
- // Set say() utility
486
- if (conversationId !== undefined && type !== helpers_1.IncomingEventType.Options) {
487
- listenerArgs.say = createSay(conversationId);
488
- }
489
- // Set respond() utility
490
- if (body.response_url) {
491
- listenerArgs.respond = buildRespondFn(this.axios, body.response_url);
492
- }
493
- else if (typeof body.response_urls !== 'undefined' && body.response_urls.length > 0) {
494
- // This can exist only when view_submission payloads - response_url_enabled: true
495
- listenerArgs.respond = buildRespondFn(this.axios, body.response_urls[0].response_url);
496
- }
497
- // Set ack() utility
498
- if (type !== helpers_1.IncomingEventType.Event) {
499
- listenerArgs.ack = ack;
500
- }
501
- else {
502
- // Events API requests are acknowledged right away, since there's no data expected
503
- await ack();
504
- }
505
- // Get the client arg
506
- let { client } = this;
507
- const token = selectToken(context);
508
- if (token !== undefined) {
509
- let pool;
510
- const clientOptionsCopy = { ...this.clientOptions };
511
- if (authorizeResult.teamId !== undefined) {
512
- pool = this.clients[authorizeResult.teamId];
513
- if (pool === undefined) {
514
- // eslint-disable-next-line no-multi-assign
515
- pool = this.clients[authorizeResult.teamId] = new WebClientPool();
516
- }
517
- // Add teamId to clientOptions so it can be automatically added to web-api calls
518
- clientOptionsCopy.teamId = authorizeResult.teamId;
519
- }
520
- else if (authorizeResult.enterpriseId !== undefined) {
521
- pool = this.clients[authorizeResult.enterpriseId];
522
- if (pool === undefined) {
523
- // eslint-disable-next-line no-multi-assign
524
- pool = this.clients[authorizeResult.enterpriseId] = new WebClientPool();
525
- }
526
- }
527
- if (pool !== undefined) {
528
- client = pool.getOrCreate(token, clientOptionsCopy);
529
- }
530
- }
531
- // Dispatch event through the global middleware chain
532
- try {
533
- await (0, process_1.default)(this.middleware, listenerArgs, context, client, this.logger, async () => {
534
- // Dispatch the event through the listener middleware chains and aggregate their results
535
- // TODO: change the name of this.middleware and this.listeners to help this make more sense
536
- const listenerResults = this.listeners.map(async (origListenerMiddleware) => {
537
- // Copy the array so modifications don't affect the original
538
- const listenerMiddleware = [...origListenerMiddleware];
539
- // Don't process the last item in the listenerMiddleware array - it shouldn't get a next fn
540
- const listener = listenerMiddleware.pop();
541
- if (listener === undefined) {
542
- return undefined;
543
- }
544
- return (0, process_1.default)(listenerMiddleware, listenerArgs, context, client, this.logger,
545
- // When the listener middleware chain is done processing, call the listener without a next fn
546
- async () => listener({
547
- ...listenerArgs,
548
- context,
549
- client,
550
- logger: this.logger,
551
- }));
552
- });
553
- const settledListenerResults = await allSettled(listenerResults);
554
- const rejectedListenerResults = settledListenerResults.filter((lr) => lr.status === 'rejected');
555
- if (rejectedListenerResults.length === 1) {
556
- throw rejectedListenerResults[0].reason;
557
- }
558
- else if (rejectedListenerResults.length > 1) {
559
- throw new errors_1.MultipleListenerError(rejectedListenerResults.map((rlr) => rlr.reason));
560
- }
561
- });
562
- }
563
- catch (error) {
564
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
565
- const e = error;
566
- // disabling due to https://github.com/typescript-eslint/typescript-eslint/issues/1277
567
- // eslint-disable-next-line consistent-return
568
- return this.handleError(e);
569
- }
570
- }
571
- /**
572
- * Global error handler. The final destination for all errors (hopefully).
573
- */
574
- handleError(error) {
575
- return this.errorHandler((0, errors_1.asCodedError)(error));
576
- }
577
- }
578
- exports.default = App;
579
- function defaultErrorHandler(logger) {
580
- return (error) => {
581
- logger.error(error);
582
- return Promise.reject(error);
583
- };
584
- }
585
- // -----------
586
- // singleAuthorization
587
- function runAuthTestForBotToken(client, authorization) {
588
- // TODO: warn when something needed isn't found
589
- return authorization.botUserId !== undefined && authorization.botId !== undefined ?
590
- Promise.resolve({ botUserId: authorization.botUserId, botId: authorization.botId }) :
591
- client.auth.test({ token: authorization.botToken }).then((result) => ({
592
- botUserId: result.user_id,
593
- botId: result.bot_id,
594
- }));
595
- }
596
- async function buildAuthorizeResult(isEnterpriseInstall, authTestResult, authorization) {
597
- return { isEnterpriseInstall, botToken: authorization.botToken, ...(await authTestResult) };
598
- }
599
- function singleAuthorization(client, authorization, tokenVerificationEnabled) {
600
- // As Authorize function has a reference to this local variable,
601
- // this local variable can behave as auth.test call result cache for the function
602
- let cachedAuthTestResult;
603
- if (tokenVerificationEnabled) {
604
- // call auth.test immediately
605
- cachedAuthTestResult = runAuthTestForBotToken(client, authorization);
606
- return async ({ isEnterpriseInstall }) => buildAuthorizeResult(isEnterpriseInstall, cachedAuthTestResult, authorization);
607
- }
608
- return async ({ isEnterpriseInstall }) => {
609
- // hold off calling auth.test API until the first access to authorize function
610
- cachedAuthTestResult = runAuthTestForBotToken(client, authorization);
611
- return buildAuthorizeResult(isEnterpriseInstall, cachedAuthTestResult, authorization);
612
- };
613
- }
614
- // ----------------------------
615
- // For processEvent method
616
- /**
617
- * Helper which builds the data structure the authorize hook uses to provide tokens for the context.
618
- */
619
- function buildSource(type, channelId, body, isEnterpriseInstall) {
620
- // NOTE: potentially something that can be optimized, so that each of these conditions isn't evaluated more than once.
621
- // if this makes it prettier, great! but we should probably check perf before committing to any specific optimization.
622
- const teamId = (() => {
623
- if (type === helpers_1.IncomingEventType.Event) {
624
- const bodyAsEvent = body;
625
- if (Array.isArray(bodyAsEvent.authorizations) &&
626
- bodyAsEvent.authorizations[0] !== undefined &&
627
- bodyAsEvent.authorizations[0].team_id !== null) {
628
- return bodyAsEvent.authorizations[0].team_id;
629
- }
630
- return bodyAsEvent.team_id;
631
- }
632
- if (type === helpers_1.IncomingEventType.Command) {
633
- return body.team_id;
634
- }
635
- if (type === helpers_1.IncomingEventType.Action ||
636
- type === helpers_1.IncomingEventType.Options ||
637
- type === helpers_1.IncomingEventType.ViewAction ||
638
- type === helpers_1.IncomingEventType.Shortcut) {
639
- const bodyAsActionOrOptionsOrViewActionOrShortcut = body;
640
- // When the app is installed using org-wide deployment, team property will be null
641
- if (typeof bodyAsActionOrOptionsOrViewActionOrShortcut.team !== 'undefined' &&
642
- bodyAsActionOrOptionsOrViewActionOrShortcut.team !== null) {
643
- return bodyAsActionOrOptionsOrViewActionOrShortcut.team.id;
644
- }
645
- // This is the only place where this function might return undefined
646
- return bodyAsActionOrOptionsOrViewActionOrShortcut.user.team_id;
647
- }
648
- return (0, helpers_1.assertNever)(type);
649
- })();
650
- const enterpriseId = (() => {
651
- if (type === helpers_1.IncomingEventType.Event) {
652
- const bodyAsEvent = body;
653
- if (Array.isArray(bodyAsEvent.authorizations) && bodyAsEvent.authorizations[0] !== undefined) {
654
- // The enteprise_id here can be null when the workspace is not in an Enterprise Grid
655
- const theId = bodyAsEvent.authorizations[0].enterprise_id;
656
- return theId !== null ? theId : undefined;
657
- }
658
- return bodyAsEvent.enterprise_id;
659
- }
660
- if (type === helpers_1.IncomingEventType.Command) {
661
- return body.enterprise_id;
662
- }
663
- if (type === helpers_1.IncomingEventType.Action ||
664
- type === helpers_1.IncomingEventType.Options ||
665
- type === helpers_1.IncomingEventType.ViewAction ||
666
- type === helpers_1.IncomingEventType.Shortcut) {
667
- // NOTE: no type system backed exhaustiveness check within this group of incoming event types
668
- const bodyAsActionOrOptionsOrViewActionOrShortcut = body;
669
- if (typeof bodyAsActionOrOptionsOrViewActionOrShortcut.enterprise !== 'undefined' &&
670
- bodyAsActionOrOptionsOrViewActionOrShortcut.enterprise !== null) {
671
- return bodyAsActionOrOptionsOrViewActionOrShortcut.enterprise.id;
672
- }
673
- // When the app is installed using org-wide deployment, team property will be null
674
- if (typeof bodyAsActionOrOptionsOrViewActionOrShortcut.team !== 'undefined' &&
675
- bodyAsActionOrOptionsOrViewActionOrShortcut.team !== null) {
676
- return bodyAsActionOrOptionsOrViewActionOrShortcut.team.enterprise_id;
677
- }
678
- return undefined;
679
- }
680
- return (0, helpers_1.assertNever)(type);
681
- })();
682
- const userId = (() => {
683
- if (type === helpers_1.IncomingEventType.Event) {
684
- // NOTE: no type system backed exhaustiveness check within this incoming event type
685
- const { event } = body;
686
- if ('user' in event) {
687
- if (typeof event.user === 'string') {
688
- return event.user;
689
- }
690
- if (typeof event.user === 'object') {
691
- return event.user.id;
692
- }
693
- }
694
- if ('channel' in event && typeof event.channel !== 'string' && 'creator' in event.channel) {
695
- return event.channel.creator;
696
- }
697
- if ('subteam' in event && event.subteam.created_by !== undefined) {
698
- return event.subteam.created_by;
699
- }
700
- return undefined;
701
- }
702
- if (type === helpers_1.IncomingEventType.Action ||
703
- type === helpers_1.IncomingEventType.Options ||
704
- type === helpers_1.IncomingEventType.ViewAction ||
705
- type === helpers_1.IncomingEventType.Shortcut) {
706
- // NOTE: no type system backed exhaustiveness check within this incoming event type
707
- const bodyAsActionOrOptionsOrViewActionOrShortcut = body;
708
- return bodyAsActionOrOptionsOrViewActionOrShortcut.user.id;
709
- }
710
- if (type === helpers_1.IncomingEventType.Command) {
711
- return body.user_id;
712
- }
713
- return (0, helpers_1.assertNever)(type);
714
- })();
715
- return {
716
- userId,
717
- isEnterpriseInstall,
718
- teamId: teamId,
719
- enterpriseId: enterpriseId,
720
- conversationId: channelId,
721
- };
722
- }
723
- function isBodyWithTypeEnterpriseInstall(body, type) {
724
- if (type === helpers_1.IncomingEventType.Event) {
725
- const bodyAsEvent = body;
726
- if (Array.isArray(bodyAsEvent.authorizations) && bodyAsEvent.authorizations[0] !== undefined) {
727
- return !!bodyAsEvent.authorizations[0].is_enterprise_install;
728
- }
729
- }
730
- // command payloads have this property set as a string
731
- if (typeof body.is_enterprise_install === 'string') {
732
- return body.is_enterprise_install === 'true';
733
- }
734
- // all remaining types have a boolean property
735
- if (body.is_enterprise_install !== undefined) {
736
- return body.is_enterprise_install;
737
- }
738
- // as a fallback we assume it's a single team installation (but this should never happen)
739
- return false;
740
- }
741
- function isBlockActionOrInteractiveMessageBody(body) {
742
- return body.actions !== undefined;
743
- }
744
- // Returns either a bot token or a user token for client, say()
745
- function selectToken(context) {
746
- return context.botToken !== undefined ? context.botToken : context.userToken;
747
- }
748
- function buildRespondFn(axiosInstance, responseUrl) {
749
- return async (message) => {
750
- const normalizedArgs = typeof message === 'string' ? { text: message } : message;
751
- return axiosInstance.post(responseUrl, normalizedArgs);
752
- };
753
- }
754
- // ----------------------------
755
- // Instrumentation
756
- // Don't change the position of the following code
757
- (0, web_api_1.addAppMetadata)({ name: packageJson.name, version: packageJson.version });
758
- //# sourceMappingURL=App.js.map