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