@slack/bolt 3.6.0 → 3.9.0-hermesBeta.2

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 (110) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +4 -2
  3. package/dist/App.d.ts +67 -4
  4. package/dist/App.d.ts.map +1 -1
  5. package/dist/App.js +219 -106
  6. package/dist/App.js.map +1 -1
  7. package/dist/Subscription.d.ts +61 -0
  8. package/dist/Subscription.d.ts.map +1 -0
  9. package/dist/Subscription.js +169 -0
  10. package/dist/Subscription.js.map +1 -0
  11. package/dist/WorkflowStep.d.ts.map +1 -1
  12. package/dist/WorkflowStep.js +25 -28
  13. package/dist/WorkflowStep.js.map +1 -1
  14. package/dist/conversation-store.d.ts.map +1 -1
  15. package/dist/conversation-store.js +5 -6
  16. package/dist/conversation-store.js.map +1 -1
  17. package/dist/errors.d.ts +13 -5
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/errors.js +25 -9
  20. package/dist/errors.js.map +1 -1
  21. package/dist/helpers.d.ts +2 -1
  22. package/dist/helpers.d.ts.map +1 -1
  23. package/dist/helpers.js +9 -0
  24. package/dist/helpers.js.map +1 -1
  25. package/dist/index.js +2 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/middleware/builtin.d.ts.map +1 -1
  28. package/dist/middleware/builtin.js +0 -20
  29. package/dist/middleware/builtin.js.map +1 -1
  30. package/dist/middleware/process.d.ts +1 -1
  31. package/dist/middleware/process.d.ts.map +1 -1
  32. package/dist/middleware/process.js +1 -2
  33. package/dist/middleware/process.js.map +1 -1
  34. package/dist/receivers/AwsLambdaReceiver.d.ts +4 -1
  35. package/dist/receivers/AwsLambdaReceiver.d.ts.map +1 -1
  36. package/dist/receivers/AwsLambdaReceiver.js +15 -20
  37. package/dist/receivers/AwsLambdaReceiver.js.map +1 -1
  38. package/dist/receivers/ExpressReceiver.d.ts +20 -7
  39. package/dist/receivers/ExpressReceiver.d.ts.map +1 -1
  40. package/dist/receivers/ExpressReceiver.js +167 -87
  41. package/dist/receivers/ExpressReceiver.js.map +1 -1
  42. package/dist/receivers/HTTPReceiver.d.ts +54 -4
  43. package/dist/receivers/HTTPReceiver.d.ts.map +1 -1
  44. package/dist/receivers/HTTPReceiver.js +240 -94
  45. package/dist/receivers/HTTPReceiver.js.map +1 -1
  46. package/dist/receivers/SocketModeReceiver.d.ts +18 -1
  47. package/dist/receivers/SocketModeReceiver.d.ts.map +1 -1
  48. package/dist/receivers/SocketModeReceiver.js +109 -41
  49. package/dist/receivers/SocketModeReceiver.js.map +1 -1
  50. package/dist/receivers/custom-routes.d.ts +14 -0
  51. package/dist/receivers/custom-routes.d.ts.map +1 -0
  52. package/dist/receivers/custom-routes.js +33 -0
  53. package/dist/receivers/custom-routes.js.map +1 -0
  54. package/dist/receivers/http-utils.d.ts +5 -0
  55. package/dist/receivers/http-utils.d.ts.map +1 -0
  56. package/dist/receivers/http-utils.js +35 -0
  57. package/dist/receivers/http-utils.js.map +1 -0
  58. package/dist/receivers/render-html-for-install-path.d.ts +1 -0
  59. package/dist/receivers/render-html-for-install-path.d.ts.map +1 -1
  60. package/dist/receivers/render-html-for-install-path.js +6 -1
  61. package/dist/receivers/render-html-for-install-path.js.map +1 -1
  62. package/dist/receivers/verify-redirect-opts.d.ts +7 -0
  63. package/dist/receivers/verify-redirect-opts.d.ts.map +1 -0
  64. package/dist/receivers/verify-redirect-opts.js +23 -0
  65. package/dist/receivers/verify-redirect-opts.js.map +1 -0
  66. package/dist/receivers/verify-request.d.ts +1 -0
  67. package/dist/receivers/verify-request.d.ts.map +1 -1
  68. package/dist/receivers/verify-request.js +8 -4
  69. package/dist/receivers/verify-request.js.map +1 -1
  70. package/dist/types/actions/block-action.d.ts +8 -1
  71. package/dist/types/actions/block-action.d.ts.map +1 -1
  72. package/dist/types/actions/index.d.ts +4 -4
  73. package/dist/types/actions/index.d.ts.map +1 -1
  74. package/dist/types/actions/index.js.map +1 -1
  75. package/dist/types/actions/notification-subscription.d.ts +59 -0
  76. package/dist/types/actions/notification-subscription.d.ts.map +1 -0
  77. package/dist/types/actions/notification-subscription.js +3 -0
  78. package/dist/types/actions/notification-subscription.js.map +1 -0
  79. package/dist/types/actions/workflow-step-edit.d.ts.map +1 -1
  80. package/dist/types/events/base-events.d.ts +5 -5
  81. package/dist/types/events/base-events.d.ts.map +1 -1
  82. package/dist/types/events/base-events.js.map +1 -1
  83. package/dist/types/events/index.d.ts +4 -4
  84. package/dist/types/events/index.d.ts.map +1 -1
  85. package/dist/types/events/index.js.map +1 -1
  86. package/dist/types/events/message-events.d.ts.map +1 -1
  87. package/dist/types/helpers.d.ts +2 -2
  88. package/dist/types/helpers.d.ts.map +1 -1
  89. package/dist/types/index.d.ts +1 -0
  90. package/dist/types/index.d.ts.map +1 -1
  91. package/dist/types/index.js +1 -0
  92. package/dist/types/index.js.map +1 -1
  93. package/dist/types/middleware.d.ts +12 -2
  94. package/dist/types/middleware.d.ts.map +1 -1
  95. package/dist/types/middleware.js +11 -0
  96. package/dist/types/middleware.js.map +1 -1
  97. package/dist/types/options/index.d.ts +2 -2
  98. package/dist/types/options/index.d.ts.map +1 -1
  99. package/dist/types/receiver.d.ts +3 -0
  100. package/dist/types/receiver.d.ts.map +1 -1
  101. package/dist/types/shortcuts/index.d.ts +2 -2
  102. package/dist/types/shortcuts/index.d.ts.map +1 -1
  103. package/dist/types/shortcuts/index.js.map +1 -1
  104. package/dist/types/shortcuts/message-shortcut.d.ts.map +1 -1
  105. package/dist/types/subscription/index.d.ts +80 -0
  106. package/dist/types/subscription/index.d.ts.map +1 -0
  107. package/dist/types/subscription/index.js +3 -0
  108. package/dist/types/subscription/index.js.map +1 -0
  109. package/dist/types/utilities.d.ts.map +1 -1
  110. package/package.json +18 -20
package/dist/App.js CHANGED
@@ -11,14 +11,23 @@ const axios_1 = __importDefault(require("axios"));
11
11
  const SocketModeReceiver_1 = __importDefault(require("./receivers/SocketModeReceiver"));
12
12
  const HTTPReceiver_1 = __importDefault(require("./receivers/HTTPReceiver"));
13
13
  const builtin_1 = require("./middleware/builtin");
14
- const process_1 = require("./middleware/process");
14
+ const process_1 = __importDefault(require("./middleware/process"));
15
15
  const conversation_store_1 = require("./conversation-store");
16
+ const Subscription_1 = require("./Subscription");
16
17
  const helpers_1 = require("./helpers");
17
18
  const errors_1 = require("./errors");
19
+ const middleware_1 = require("./types/middleware");
18
20
  // eslint-disable-next-line import/order
19
21
  const allSettled = require("promise.allsettled"); // eslint-disable-line @typescript-eslint/no-require-imports
20
- // eslint-disable-next-line @typescript-eslint/no-require-imports
22
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-commonjs
21
23
  const packageJson = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires
24
+ // ----------------------------
25
+ // For listener registration methods
26
+ const validViewTypes = ['view_closed', 'view_submission'];
27
+ // ----------------------------
28
+ // For the constructor
29
+ const tokenUsage = 'Apps used in a single workspace can be initialized with a token. Apps used in many workspaces ' +
30
+ 'should be initialized with oauth installer options or authorize.';
22
31
  var logger_2 = require("@slack/logger");
23
32
  Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return logger_2.LogLevel; } });
24
33
  class WebClientPool {
@@ -39,10 +48,11 @@ class WebClientPool {
39
48
  * A Slack App
40
49
  */
41
50
  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, } = {}) {
51
+ constructor({ signingSecret = undefined, endpoints = undefined, port = 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, extendedErrorHandler = false, } = {}) {
52
+ // this.logLevel = logLevel;
43
53
  // Some payloads don't have teamId anymore. So we use EnterpriseId in those scenarios
44
54
  this.clients = {};
45
- // this.logLevel = logLevel;
55
+ /* ------------------------ Developer mode ----------------------------- */
46
56
  this.developerMode = developerMode;
47
57
  if (developerMode) {
48
58
  // Set logLevel to Debug in Developer Mode if one wasn't passed in
@@ -56,6 +66,7 @@ class App {
56
66
  // Set logLevel to Info if one wasn't passed in
57
67
  this.logLevel = logLevel !== null && logLevel !== void 0 ? logLevel : logger_1.LogLevel.INFO;
58
68
  }
69
+ /* ------------------------ Set logger ----------------------------- */
59
70
  if (typeof logger === 'undefined') {
60
71
  // Initialize with the default logger
61
72
  const consoleLogger = new logger_1.ConsoleLogger();
@@ -68,7 +79,11 @@ class App {
68
79
  if (typeof this.logLevel !== 'undefined' && this.logger.getLevel() !== this.logLevel) {
69
80
  this.logger.setLevel(this.logLevel);
70
81
  }
82
+ // Error-related properties used to later determine args passed into the error handler
83
+ this.hasCustomErrorHandler = false;
71
84
  this.errorHandler = defaultErrorHandler(this.logger);
85
+ this.extendedErrorHandler = extendedErrorHandler;
86
+ /* ------------------------ Set client options ------------------------*/
72
87
  this.clientOptions = clientOptions !== undefined ? clientOptions : {};
73
88
  if (agent !== undefined && this.clientOptions.agent === undefined) {
74
89
  this.clientOptions.agent = agent;
@@ -81,11 +96,7 @@ class App {
81
96
  this.clientOptions.logLevel = logLevel;
82
97
  }
83
98
  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
99
+ // Since v3.4, WebClient starts sharing logger with App
89
100
  this.clientOptions.logger = this.logger;
90
101
  }
91
102
  // The public WebClient instance (app.client)
@@ -108,6 +119,11 @@ class App {
108
119
  clientOptions: this.clientOptions,
109
120
  ...installerOptions,
110
121
  };
122
+ if (socketMode && port !== undefined && this.installerOptions.port === undefined) {
123
+ // SocketModeReceiver only uses a custom port number when listening for the OAuth flow.
124
+ // Therefore only installerOptions.port is available in the constructor arguments.
125
+ this.installerOptions.port = port;
126
+ }
111
127
  if (this.developerMode &&
112
128
  this.installerOptions &&
113
129
  (typeof this.installerOptions.callbackOptions === 'undefined' ||
@@ -123,43 +139,54 @@ class App {
123
139
  },
124
140
  };
125
141
  }
126
- // Check for required arguments of HTTPReceiver
142
+ /* --------------------- Initialize receiver ---------------------- */
127
143
  if (receiver !== undefined) {
144
+ // Custom receiver supplied
145
+ if (this.socketMode === true) {
146
+ // socketMode = true should result in SocketModeReceiver being used as receiver
147
+ // TODO: Add case for when socketMode = true and receiver = SocketModeReceiver
148
+ // as this should not result in an error
149
+ throw new errors_1.AppInitializationError('You cannot supply a custom receiver when socketMode is set to true.');
150
+ }
128
151
  this.receiver = receiver;
129
152
  }
130
- else if (this.socketMode) {
153
+ else if (this.socketMode === true) {
131
154
  if (appToken === undefined) {
132
- throw new errors_1.AppInitializationError('You must provide an appToken when using Socket Mode');
155
+ throw new errors_1.AppInitializationError('You must provide an appToken when socketMode is set to true. To generate an appToken see: https://api.slack.com/apis/connections/socket#token');
133
156
  }
134
157
  this.logger.debug('Initializing SocketModeReceiver');
135
- // Create default SocketModeReceiver
136
158
  this.receiver = new SocketModeReceiver_1.default({
137
159
  appToken,
138
160
  clientId,
139
161
  clientSecret,
140
162
  stateSecret,
163
+ redirectUri,
141
164
  installationStore,
142
165
  scopes,
143
166
  logger,
144
167
  logLevel: this.logLevel,
145
168
  installerOptions: this.installerOptions,
169
+ customRoutes,
146
170
  });
147
171
  }
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.');
172
+ else if (signatureVerification === true && signingSecret === undefined) {
173
+ // Using default receiver HTTPReceiver, signature verification enabled, missing signingSecret
174
+ throw new errors_1.AppInitializationError('signingSecret is required to initialize the default receiver. Set signingSecret or use a ' +
175
+ 'custom receiver. You can find your Signing Secret in your Slack App Settings.');
152
176
  }
153
177
  else {
154
178
  this.logger.debug('Initializing HTTPReceiver');
155
- // Create default HTTPReceiver
156
179
  this.receiver = new HTTPReceiver_1.default({
157
- signingSecret,
180
+ signingSecret: signingSecret || '',
158
181
  endpoints,
182
+ port,
183
+ customRoutes,
159
184
  processBeforeResponse,
185
+ signatureVerification,
160
186
  clientId,
161
187
  clientSecret,
162
188
  stateSecret,
189
+ redirectUri,
163
190
  installationStore,
164
191
  scopes,
165
192
  logger,
@@ -167,16 +194,19 @@ class App {
167
194
  installerOptions: this.installerOptions,
168
195
  });
169
196
  }
197
+ /* ------------------------ Set authorize ----------------------------- */
170
198
  let usingOauth = false;
171
- if (this.receiver.installer !== undefined &&
172
- this.receiver.installer.authorize !== undefined) {
199
+ const httpReceiver = this.receiver;
200
+ if (httpReceiver.installer !== undefined &&
201
+ httpReceiver.installer.authorize !== undefined) {
173
202
  // This supports using the built in HTTPReceiver, declaring your own HTTPReceiver
174
203
  // and theoretically, doing a fully custom (non express) receiver that implements OAuth
175
204
  usingOauth = true;
176
205
  }
177
206
  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}`);
207
+ // If a token is supplied, the app is installed in at least one workspace
208
+ if (usingOauth || authorize !== undefined) {
209
+ throw new errors_1.AppInitializationError(`You cannot provide a token along with either oauth installer options or authorize. ${tokenUsage}`);
180
210
  }
181
211
  this.authorize = singleAuthorization(this.client, {
182
212
  botId,
@@ -185,31 +215,33 @@ class App {
185
215
  }, tokenVerificationEnabled);
186
216
  }
187
217
  else if (authorize === undefined && !usingOauth) {
188
- throw new errors_1.AppInitializationError(`No token, no authorize, and no oauth installer options provided. ${tokenUsage}`);
218
+ throw new errors_1.AppInitializationError(`${tokenUsage} \n\nSince you have not provided a token or authorize, you might be missing one or more required oauth installer options. See https://slack.dev/bolt-js/concepts#authenticating-oauth for these required fields.\n`);
189
219
  }
190
220
  else if (authorize !== undefined && usingOauth) {
191
- throw new errors_1.AppInitializationError(`Both authorize options and oauth installer options provided. ${tokenUsage}`);
221
+ throw new errors_1.AppInitializationError(`You cannot provide both authorize and oauth installer options. ${tokenUsage}`);
192
222
  }
193
223
  else if (authorize === undefined && usingOauth) {
194
- this.authorize = this.receiver.installer.authorize;
224
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
225
+ this.authorize = httpReceiver.installer.authorize;
195
226
  }
196
227
  else if (authorize !== undefined && !usingOauth) {
197
228
  this.authorize = authorize;
198
229
  }
199
230
  else {
200
- this.logger.error('Never should have reached this point, please report to the team');
201
- helpers_1.assertNever();
231
+ this.logger.error('Something has gone wrong. Please report this issue to the maintainers. https://github.com/slackapi/bolt-js/issues');
232
+ (0, helpers_1.assertNever)();
202
233
  }
203
234
  // Conditionally use a global middleware that ignores events (including messages) that are sent from this app
204
235
  if (ignoreSelf) {
205
- this.use(builtin_1.ignoreSelf());
236
+ this.use((0, builtin_1.ignoreSelf)());
206
237
  }
207
238
  // Use conversation state global middleware
208
239
  if (convoStore !== false) {
209
240
  // Use the memory store by default, or another store if provided
210
241
  const store = convoStore === undefined ? new conversation_store_1.MemoryStore() : convoStore;
211
- this.use(conversation_store_1.conversationContext(store));
242
+ this.use((0, conversation_store_1.conversationContext)(store));
212
243
  }
244
+ /* ------------------------ Initialize receiver ------------------------ */
213
245
  // Should be last to avoid exposing partially initialized app
214
246
  this.receiver.init(this);
215
247
  }
@@ -243,9 +275,26 @@ class App {
243
275
  // TODO: HTTPReceiver['start'] should be the actual receiver's return type
244
276
  return this.receiver.start(...args);
245
277
  }
278
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
246
279
  stop(...args) {
247
280
  return this.receiver.stop(...args);
248
281
  }
282
+ /**
283
+ * Register subcription middleware
284
+ *
285
+ * @param listeners middleware that process and react to subscription payloads
286
+ */
287
+ subscription(options) {
288
+ /*
289
+ * TODO If it becomes possible for users to set a custom unique resource id,
290
+ * custom id should be supplied in place of the default.
291
+ * */
292
+ const defaultId = 'DEFAULTID';
293
+ const s = new Subscription_1.Subscription(defaultId, options);
294
+ const m = s.getMiddleware();
295
+ this.middleware.push(m);
296
+ return this;
297
+ }
249
298
  event(eventNameOrPattern, ...listeners) {
250
299
  let invalidEventName = false;
251
300
  if (typeof eventNameOrPattern === 'string') {
@@ -263,27 +312,27 @@ class App {
263
312
  }
264
313
  this.listeners.push([
265
314
  builtin_1.onlyEvents,
266
- builtin_1.matchEventType(eventNameOrPattern),
315
+ (0, builtin_1.matchEventType)(eventNameOrPattern),
267
316
  ...listeners,
268
317
  ]);
269
318
  }
270
319
  message(...patternsOrMiddleware) {
271
320
  const messageMiddleware = patternsOrMiddleware.map((patternOrMiddleware) => {
272
321
  if (typeof patternOrMiddleware === 'string' || util_1.default.types.isRegExp(patternOrMiddleware)) {
273
- return builtin_1.matchMessage(patternOrMiddleware);
322
+ return (0, builtin_1.matchMessage)(patternOrMiddleware);
274
323
  }
275
324
  return patternOrMiddleware;
276
325
  });
277
326
  this.listeners.push([
278
327
  builtin_1.onlyEvents,
279
- builtin_1.matchEventType('message'),
328
+ (0, builtin_1.matchEventType)('message'),
280
329
  ...messageMiddleware,
281
330
  ]);
282
331
  }
283
332
  shortcut(callbackIdOrConstraints, ...listeners) {
284
- const constraints = typeof callbackIdOrConstraints === 'string' || util_1.default.types.isRegExp(callbackIdOrConstraints)
285
- ? { callback_id: callbackIdOrConstraints }
286
- : callbackIdOrConstraints;
333
+ const constraints = typeof callbackIdOrConstraints === 'string' || util_1.default.types.isRegExp(callbackIdOrConstraints) ?
334
+ { callback_id: callbackIdOrConstraints } :
335
+ callbackIdOrConstraints;
287
336
  // Fail early if the constraints contain invalid keys
288
337
  const unknownConstraintKeys = Object.keys(constraints).filter((k) => k !== 'callback_id' && k !== 'type');
289
338
  if (unknownConstraintKeys.length > 0) {
@@ -292,37 +341,37 @@ class App {
292
341
  }
293
342
  this.listeners.push([
294
343
  builtin_1.onlyShortcuts,
295
- builtin_1.matchConstraints(constraints),
344
+ (0, builtin_1.matchConstraints)(constraints),
296
345
  ...listeners,
297
346
  ]);
298
347
  }
299
348
  action(actionIdOrConstraints, ...listeners) {
300
349
  // Normalize Constraints
301
- const constraints = typeof actionIdOrConstraints === 'string' || util_1.default.types.isRegExp(actionIdOrConstraints)
302
- ? { action_id: actionIdOrConstraints }
303
- : actionIdOrConstraints;
350
+ const constraints = typeof actionIdOrConstraints === 'string' || util_1.default.types.isRegExp(actionIdOrConstraints) ?
351
+ { action_id: actionIdOrConstraints } :
352
+ actionIdOrConstraints;
304
353
  // Fail early if the constraints contain invalid keys
305
354
  const unknownConstraintKeys = Object.keys(constraints).filter((k) => k !== 'action_id' && k !== 'block_id' && k !== 'callback_id' && k !== 'type');
306
355
  if (unknownConstraintKeys.length > 0) {
307
356
  this.logger.error(`Action listener cannot be attached using unknown constraint keys: ${unknownConstraintKeys.join(', ')}`);
308
357
  return;
309
358
  }
310
- this.listeners.push([builtin_1.onlyActions, builtin_1.matchConstraints(constraints), ...listeners]);
359
+ this.listeners.push([builtin_1.onlyActions, (0, builtin_1.matchConstraints)(constraints), ...listeners]);
311
360
  }
312
361
  command(commandName, ...listeners) {
313
- this.listeners.push([builtin_1.onlyCommands, builtin_1.matchCommandName(commandName), ...listeners]);
362
+ this.listeners.push([builtin_1.onlyCommands, (0, builtin_1.matchCommandName)(commandName), ...listeners]);
314
363
  }
315
364
  // TODO: reflect the type in constraits to Source
316
365
  options(actionIdOrConstraints, ...listeners) {
317
- const constraints = typeof actionIdOrConstraints === 'string' || util_1.default.types.isRegExp(actionIdOrConstraints)
318
- ? { action_id: actionIdOrConstraints }
319
- : actionIdOrConstraints;
320
- this.listeners.push([builtin_1.onlyOptions, builtin_1.matchConstraints(constraints), ...listeners]);
366
+ const constraints = typeof actionIdOrConstraints === 'string' || util_1.default.types.isRegExp(actionIdOrConstraints) ?
367
+ { action_id: actionIdOrConstraints } :
368
+ actionIdOrConstraints;
369
+ this.listeners.push([builtin_1.onlyOptions, (0, builtin_1.matchConstraints)(constraints), ...listeners]);
321
370
  }
322
371
  view(callbackIdOrConstraints, ...listeners) {
323
- const constraints = typeof callbackIdOrConstraints === 'string' || util_1.default.types.isRegExp(callbackIdOrConstraints)
324
- ? { callback_id: callbackIdOrConstraints, type: 'view_submission' }
325
- : callbackIdOrConstraints;
372
+ const constraints = typeof callbackIdOrConstraints === 'string' || util_1.default.types.isRegExp(callbackIdOrConstraints) ?
373
+ { callback_id: callbackIdOrConstraints, type: 'view_submission' } :
374
+ callbackIdOrConstraints;
326
375
  // Fail early if the constraints contain invalid keys
327
376
  const unknownConstraintKeys = Object.keys(constraints).filter((k) => k !== 'callback_id' && k !== 'type');
328
377
  if (unknownConstraintKeys.length > 0) {
@@ -335,12 +384,13 @@ class App {
335
384
  }
336
385
  this.listeners.push([
337
386
  builtin_1.onlyViewActions,
338
- builtin_1.matchConstraints(constraints),
387
+ (0, builtin_1.matchConstraints)(constraints),
339
388
  ...listeners,
340
389
  ]);
341
390
  }
342
391
  error(errorHandler) {
343
392
  this.errorHandler = errorHandler;
393
+ this.hasCustomErrorHandler = true;
344
394
  }
345
395
  /**
346
396
  * Handles events from the receiver
@@ -356,7 +406,7 @@ class App {
356
406
  // or even all of the args, as properties of the error. This would give error handling code some ability to deal
357
407
  // with "finally" type error situations.
358
408
  // Introspect the body to determine what type of incoming event is being handled, and any channel context
359
- const { type, conversationId } = helpers_1.getTypeAndConversation(body);
409
+ const { type, conversationId } = (0, helpers_1.getTypeAndConversation)(body);
360
410
  // If the type could not be determined, warn and exit
361
411
  if (type === undefined) {
362
412
  this.logger.warn('Could not determine the type of an incoming event. No listeners will be called.');
@@ -377,9 +427,18 @@ class App {
377
427
  }
378
428
  }
379
429
  catch (error) {
430
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
431
+ const e = error;
380
432
  this.logger.warn('Authorization of incoming event did not succeed. No listeners will be called.');
381
- error.code = 'slack_bolt_authorization_error';
382
- return this.handleError(error);
433
+ e.code = errors_1.ErrorCode.AuthorizationError;
434
+ // disabling due to https://github.com/typescript-eslint/typescript-eslint/issues/1277
435
+ // eslint-disable-next-line consistent-return
436
+ return this.handleError({
437
+ error: e,
438
+ logger: this.logger,
439
+ body: bodyArg,
440
+ context: {},
441
+ });
383
442
  }
384
443
  // Try to set teamId from AuthorizeResult before using one from source
385
444
  if (authorizeResult.teamId === undefined && source.teamId !== undefined) {
@@ -389,32 +448,60 @@ class App {
389
448
  if (authorizeResult.enterpriseId === undefined && source.enterpriseId !== undefined) {
390
449
  authorizeResult.enterpriseId = source.enterpriseId;
391
450
  }
392
- const context = { ...authorizeResult };
451
+ if (typeof event.customProperties !== 'undefined') {
452
+ const customProps = event.customProperties;
453
+ const builtinKeyDetected = middleware_1.contextBuiltinKeys.find((key) => key in customProps);
454
+ if (typeof builtinKeyDetected !== 'undefined') {
455
+ throw new errors_1.InvalidCustomPropertyError('customProperties cannot have the same names with the built-in ones');
456
+ }
457
+ }
458
+ const context = {
459
+ ...authorizeResult,
460
+ ...event.customProperties,
461
+ retryNum: event.retryNum,
462
+ retryReason: event.retryReason,
463
+ };
393
464
  // Factory for say() utility
394
465
  const createSay = (channelId) => {
395
466
  const token = selectToken(context);
396
467
  return (message) => {
397
- const postMessageArguments = typeof message === 'string'
398
- ? { token, text: message, channel: channelId }
399
- : { ...message, token, channel: channelId };
468
+ const postMessageArguments = typeof message === 'string' ?
469
+ { token, text: message, channel: channelId } :
470
+ { ...message, token, channel: channelId };
400
471
  return this.client.chat.postMessage(postMessageArguments);
401
472
  };
402
473
  };
403
- // Set body and payload (this value will eventually conform to AnyMiddlewareArgs)
474
+ // Set body and payload
475
+ // TODO: this value should eventually conform to AnyMiddlewareArgs
476
+ let payload;
477
+ switch (type) {
478
+ case helpers_1.IncomingEventType.Event:
479
+ payload = bodyArg.event;
480
+ break;
481
+ case helpers_1.IncomingEventType.ViewAction:
482
+ payload = bodyArg.view;
483
+ break;
484
+ case helpers_1.IncomingEventType.Shortcut:
485
+ payload = bodyArg;
486
+ break;
487
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
488
+ // @ts-ignore: Fallthrough case in switch
489
+ case helpers_1.IncomingEventType.Action:
490
+ if (isBlockActionOrInteractiveMessageBody(bodyArg)) {
491
+ const { actions } = bodyArg;
492
+ [payload] = actions;
493
+ break;
494
+ }
495
+ // If above conditional does not hit, fall through to fallback payload in default block below
496
+ default:
497
+ payload = bodyArg;
498
+ break;
499
+ }
404
500
  // NOTE: the following doesn't work because... distributive?
405
501
  // const listenerArgs: Partial<AnyMiddlewareArgs> = {
406
502
  const listenerArgs = {
407
503
  body: bodyArg,
408
- payload: type === helpers_1.IncomingEventType.Event
409
- ? bodyArg.event
410
- : type === helpers_1.IncomingEventType.ViewAction
411
- ? bodyArg.view
412
- : type === helpers_1.IncomingEventType.Shortcut
413
- ? bodyArg
414
- : type === helpers_1.IncomingEventType.Action &&
415
- isBlockActionOrInteractiveMessageBody(bodyArg)
416
- ? bodyArg.actions[0]
417
- : bodyArg,
504
+ payload,
418
505
  };
419
506
  // Set aliases
420
507
  if (type === helpers_1.IncomingEventType.Event) {
@@ -493,7 +580,7 @@ class App {
493
580
  }
494
581
  // Dispatch event through the global middleware chain
495
582
  try {
496
- await process_1.processMiddleware(this.middleware, listenerArgs, context, client, this.logger, async () => {
583
+ await (0, process_1.default)(this.middleware, listenerArgs, context, client, this.logger, async () => {
497
584
  // Dispatch the event through the listener middleware chains and aggregate their results
498
585
  // TODO: change the name of this.middleware and this.listeners to help this make more sense
499
586
  const listenerResults = this.listeners.map(async (origListenerMiddleware) => {
@@ -501,11 +588,19 @@ class App {
501
588
  const listenerMiddleware = [...origListenerMiddleware];
502
589
  // Don't process the last item in the listenerMiddleware array - it shouldn't get a next fn
503
590
  const listener = listenerMiddleware.pop();
504
- if (listener !== undefined) {
505
- return process_1.processMiddleware(listenerMiddleware, listenerArgs, context, client, this.logger, async () =>
506
- // When the listener middleware chain is done processing, call the listener without a next fn
507
- listener({ ...listenerArgs, context, client, logger: this.logger }));
591
+ if (listener === undefined) {
592
+ return undefined;
508
593
  }
594
+ return (0, process_1.default)(listenerMiddleware, listenerArgs, context, client, this.logger,
595
+ // When all of the listener middleware are done processing,
596
+ // `listener` here will be called without a `next` execution
597
+ async () => listener({
598
+ ...listenerArgs,
599
+ context,
600
+ client,
601
+ logger: this.logger,
602
+ // `next` is already set in the outer processMiddleware
603
+ }));
509
604
  });
510
605
  const settledListenerResults = await allSettled(listenerResults);
511
606
  const rejectedListenerResults = settledListenerResults.filter((lr) => lr.status === 'rejected');
@@ -518,21 +613,29 @@ class App {
518
613
  });
519
614
  }
520
615
  catch (error) {
521
- return this.handleError(error);
616
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
617
+ const e = error;
618
+ // disabling due to https://github.com/typescript-eslint/typescript-eslint/issues/1277
619
+ // eslint-disable-next-line consistent-return
620
+ return this.handleError({
621
+ context,
622
+ error: e,
623
+ logger: this.logger,
624
+ body: bodyArg,
625
+ });
522
626
  }
523
627
  }
524
628
  /**
525
629
  * Global error handler. The final destination for all errors (hopefully).
526
630
  */
527
- handleError(error) {
528
- return this.errorHandler(errors_1.asCodedError(error));
631
+ handleError(args) {
632
+ const { error, ...rest } = args;
633
+ return this.extendedErrorHandler && this.hasCustomErrorHandler ?
634
+ this.errorHandler({ error: (0, errors_1.asCodedError)(error), ...rest }) :
635
+ this.errorHandler((0, errors_1.asCodedError)(error));
529
636
  }
530
637
  }
531
638
  exports.default = App;
532
- // ----------------------------
533
- // For the constructor
534
- const tokenUsage = 'Apps used in one workspace should be initialized with a token. Apps used in many workspaces ' +
535
- 'should be initialized with oauth installer or authorize.';
536
639
  function defaultErrorHandler(logger) {
537
640
  return (error) => {
538
641
  logger.error(error);
@@ -543,14 +646,12 @@ function defaultErrorHandler(logger) {
543
646
  // singleAuthorization
544
647
  function runAuthTestForBotToken(client, authorization) {
545
648
  // TODO: warn when something needed isn't found
546
- return authorization.botUserId !== undefined && authorization.botId !== undefined
547
- ? Promise.resolve({ botUserId: authorization.botUserId, botId: authorization.botId })
548
- : client.auth.test({ token: authorization.botToken }).then((result) => {
549
- return {
550
- botUserId: result.user_id,
551
- botId: result.bot_id,
552
- };
553
- });
649
+ return authorization.botUserId !== undefined && authorization.botId !== undefined ?
650
+ Promise.resolve({ botUserId: authorization.botUserId, botId: authorization.botId }) :
651
+ client.auth.test({ token: authorization.botToken }).then((result) => ({
652
+ botUserId: result.user_id,
653
+ botId: result.bot_id,
654
+ }));
554
655
  }
555
656
  async function buildAuthorizeResult(isEnterpriseInstall, authTestResult, authorization) {
556
657
  return { isEnterpriseInstall, botToken: authorization.botToken, ...(await authTestResult) };
@@ -562,9 +663,7 @@ function singleAuthorization(client, authorization, tokenVerificationEnabled) {
562
663
  if (tokenVerificationEnabled) {
563
664
  // call auth.test immediately
564
665
  cachedAuthTestResult = runAuthTestForBotToken(client, authorization);
565
- return async ({ isEnterpriseInstall }) => {
566
- return buildAuthorizeResult(isEnterpriseInstall, cachedAuthTestResult, authorization);
567
- };
666
+ return async ({ isEnterpriseInstall }) => buildAuthorizeResult(isEnterpriseInstall, cachedAuthTestResult, authorization);
568
667
  }
569
668
  return async ({ isEnterpriseInstall }) => {
570
669
  // hold off calling auth.test API until the first access to authorize function
@@ -593,6 +692,10 @@ function buildSource(type, channelId, body, isEnterpriseInstall) {
593
692
  if (type === helpers_1.IncomingEventType.Command) {
594
693
  return body.team_id;
595
694
  }
695
+ if (type === helpers_1.IncomingEventType.Subscription) {
696
+ const bodyAsSubscriptionInteraction = body;
697
+ return bodyAsSubscriptionInteraction.team.id;
698
+ }
596
699
  if (type === helpers_1.IncomingEventType.Action ||
597
700
  type === helpers_1.IncomingEventType.Options ||
598
701
  type === helpers_1.IncomingEventType.ViewAction ||
@@ -606,7 +709,7 @@ function buildSource(type, channelId, body, isEnterpriseInstall) {
606
709
  // This is the only place where this function might return undefined
607
710
  return bodyAsActionOrOptionsOrViewActionOrShortcut.user.team_id;
608
711
  }
609
- return helpers_1.assertNever(type);
712
+ return (0, helpers_1.assertNever)(type);
610
713
  })();
611
714
  const enterpriseId = (() => {
612
715
  if (type === helpers_1.IncomingEventType.Event) {
@@ -621,6 +724,10 @@ function buildSource(type, channelId, body, isEnterpriseInstall) {
621
724
  if (type === helpers_1.IncomingEventType.Command) {
622
725
  return body.enterprise_id;
623
726
  }
727
+ if (type === helpers_1.IncomingEventType.Subscription) {
728
+ const bodyAsSubscriptionInteraction = body;
729
+ return bodyAsSubscriptionInteraction.team.enterprise_id;
730
+ }
624
731
  if (type === helpers_1.IncomingEventType.Action ||
625
732
  type === helpers_1.IncomingEventType.Options ||
626
733
  type === helpers_1.IncomingEventType.ViewAction ||
@@ -638,7 +745,7 @@ function buildSource(type, channelId, body, isEnterpriseInstall) {
638
745
  }
639
746
  return undefined;
640
747
  }
641
- return helpers_1.assertNever(type);
748
+ return (0, helpers_1.assertNever)(type);
642
749
  })();
643
750
  const userId = (() => {
644
751
  if (type === helpers_1.IncomingEventType.Event) {
@@ -660,6 +767,10 @@ function buildSource(type, channelId, body, isEnterpriseInstall) {
660
767
  }
661
768
  return undefined;
662
769
  }
770
+ if (type === helpers_1.IncomingEventType.Subscription) {
771
+ const bodyAsSubscriptionInteraction = body;
772
+ return bodyAsSubscriptionInteraction.user.id;
773
+ }
663
774
  if (type === helpers_1.IncomingEventType.Action ||
664
775
  type === helpers_1.IncomingEventType.Options ||
665
776
  type === helpers_1.IncomingEventType.ViewAction ||
@@ -671,7 +782,7 @@ function buildSource(type, channelId, body, isEnterpriseInstall) {
671
782
  if (type === helpers_1.IncomingEventType.Command) {
672
783
  return body.user_id;
673
784
  }
674
- return helpers_1.assertNever(type);
785
+ return (0, helpers_1.assertNever)(type);
675
786
  })();
676
787
  return {
677
788
  userId,
@@ -688,13 +799,18 @@ function isBodyWithTypeEnterpriseInstall(body, type) {
688
799
  return !!bodyAsEvent.authorizations[0].is_enterprise_install;
689
800
  }
690
801
  }
691
- // command payloads have this property set as a string
692
- if (typeof body.is_enterprise_install === 'string') {
693
- return body.is_enterprise_install === 'true';
802
+ if (type === helpers_1.IncomingEventType.Subscription) {
803
+ return body.team.enterprise_id !== undefined;
694
804
  }
695
- // all remaining types have a boolean property
696
- if (body.is_enterprise_install !== undefined) {
697
- return body.is_enterprise_install;
805
+ if ('is_enterprise_install' in body) {
806
+ // command payloads have this property set as a string
807
+ if (typeof body.is_enterprise_install === 'string') {
808
+ return body.is_enterprise_install === 'true';
809
+ }
810
+ // all remaining types have a boolean property
811
+ if (body.is_enterprise_install !== undefined) {
812
+ return body.is_enterprise_install;
813
+ }
698
814
  }
699
815
  // as a fallback we assume it's a single team installation (but this should never happen)
700
816
  return false;
@@ -706,17 +822,14 @@ function isBlockActionOrInteractiveMessageBody(body) {
706
822
  function selectToken(context) {
707
823
  return context.botToken !== undefined ? context.botToken : context.userToken;
708
824
  }
709
- function buildRespondFn(axiosInstance, response_url) {
825
+ function buildRespondFn(axiosInstance, responseUrl) {
710
826
  return async (message) => {
711
827
  const normalizedArgs = typeof message === 'string' ? { text: message } : message;
712
- return axiosInstance.post(response_url, normalizedArgs);
828
+ return axiosInstance.post(responseUrl, normalizedArgs);
713
829
  };
714
830
  }
715
831
  // ----------------------------
716
- // For listener registration methods
717
- const validViewTypes = ['view_closed', 'view_submission'];
718
- // ----------------------------
719
832
  // Instrumentation
720
833
  // Don't change the position of the following code
721
- web_api_1.addAppMetadata({ name: packageJson.name, version: packageJson.version });
834
+ (0, web_api_1.addAppMetadata)({ name: packageJson.name, version: packageJson.version });
722
835
  //# sourceMappingURL=App.js.map