@vercel/slack-bolt 1.3.0 → 1.4.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.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Receiver, StringIndexed, App } from '@slack/bolt';
2
2
  import { Logger, LogLevel } from '@slack/logger';
3
+ import { StateStore, InstallProviderOptions, InstallPathOptions, CallbackOptions, InstallProvider } from '@slack/oauth';
3
4
 
4
5
  /**
5
6
  * A function to handle the request from the Slack app.
@@ -15,6 +16,30 @@ type VercelHandler = (req: Request) => Promise<Response>;
15
16
  * @property logLevel - The log level to use for the VercelReceiver.
16
17
  * @property customPropertiesExtractor - A function to extract custom properties from the request.
17
18
  */
19
+ /**
20
+ * Options for customizing the OAuth installer behavior.
21
+ * Mirrors the relevant subset of HTTPReceiverInstallerOptions,
22
+ * excluding path-related options (serverless uses file-based routing).
23
+ */
24
+ interface VercelInstallerOptions {
25
+ directInstall?: boolean;
26
+ renderHtmlForInstallPath?: (url: string) => string;
27
+ stateStore?: StateStore;
28
+ stateVerification?: boolean;
29
+ legacyStateVerification?: boolean;
30
+ stateCookieName?: string;
31
+ stateCookieExpirationSeconds?: number;
32
+ authVersion?: "v1" | "v2";
33
+ clientOptions?: InstallProviderOptions["clientOptions"];
34
+ authorizationUrl?: string;
35
+ metadata?: string;
36
+ userScopes?: string[];
37
+ installPathOptions?: InstallPathOptions;
38
+ callbackOptions?: CallbackOptions;
39
+ }
40
+ /**
41
+ * Configuration options for the VercelReceiver.
42
+ */
18
43
  interface VercelReceiverOptions {
19
44
  /**
20
45
  * The signing secret for the Slack app.
@@ -47,6 +72,41 @@ interface VercelReceiverOptions {
47
72
  * @default 3001
48
73
  */
49
74
  ackTimeoutMs?: number;
75
+ /**
76
+ * Your app's client ID, found under Basic Information on api.slack.com.
77
+ * Required for OAuth.
78
+ * @default process.env.SLACK_CLIENT_ID
79
+ */
80
+ clientId?: string;
81
+ /**
82
+ * Your app's client secret, found under Basic Information on api.slack.com.
83
+ * Required for OAuth.
84
+ * @default process.env.SLACK_CLIENT_SECRET
85
+ */
86
+ clientSecret?: string;
87
+ /**
88
+ * Secret used to generate and verify the state parameter for OAuth CSRF protection.
89
+ * Required unless a custom stateStore or stateVerification: false is provided.
90
+ * @default process.env.SLACK_STATE_SECRET
91
+ */
92
+ stateSecret?: string;
93
+ /**
94
+ * The bot scopes to request during the OAuth flow.
95
+ */
96
+ scopes?: string[];
97
+ /**
98
+ * The redirect URI registered with your Slack app for OAuth callbacks.
99
+ */
100
+ redirectUri?: string;
101
+ /**
102
+ * Storage backend for OAuth installations (tokens, team info, etc.).
103
+ * Required for OAuth in serverless -- the default in-memory store does not persist.
104
+ */
105
+ installationStore?: InstallProviderOptions["installationStore"];
106
+ /**
107
+ * Advanced options for the OAuth installer.
108
+ */
109
+ installerOptions?: VercelInstallerOptions;
50
110
  }
51
111
  /**
52
112
  * A Slack Bolt receiver implementation designed for Vercel's serverless environment.
@@ -75,6 +135,11 @@ declare class VercelReceiver implements Receiver {
75
135
  private readonly customPropertiesExtractor?;
76
136
  private readonly ackTimeoutMs;
77
137
  private app?;
138
+ installer?: InstallProvider;
139
+ private installUrlOptions?;
140
+ private installCallbackOptions?;
141
+ private installPathOptions?;
142
+ private stateVerification?;
78
143
  /**
79
144
  * Gets the logger instance used by this receiver.
80
145
  * @returns The logger instance
@@ -91,7 +156,7 @@ declare class VercelReceiver implements Receiver {
91
156
  * const receiver = new VercelReceiver();
92
157
  * ```
93
158
  */
94
- constructor({ signingSecret, signatureVerification, logger, logLevel, customPropertiesExtractor, ackTimeoutMs, }?: VercelReceiverOptions);
159
+ constructor({ signingSecret, signatureVerification, logger, logLevel, customPropertiesExtractor, ackTimeoutMs, clientId, clientSecret, stateSecret, scopes, redirectUri, installationStore, installerOptions, }?: VercelReceiverOptions);
95
160
  /**
96
161
  * Initializes the receiver with a Slack Bolt app instance.
97
162
  * This method is called automatically by the Bolt framework.
@@ -110,6 +175,16 @@ declare class VercelReceiver implements Receiver {
110
175
  * Stops the receiver. This method is called automatically by the Bolt framework.
111
176
  */
112
177
  stop(): Promise<void>;
178
+ /**
179
+ * Handles requests to the OAuth install path.
180
+ * Renders an "Add to Slack" page or redirects directly to Slack's authorize URL.
181
+ */
182
+ handleInstall: (req: Request) => Promise<Response>;
183
+ /**
184
+ * Handles the OAuth redirect callback from Slack.
185
+ * Exchanges the authorization code for tokens and stores the installation.
186
+ */
187
+ handleCallback: (req: Request) => Promise<Response>;
113
188
  /**
114
189
  * Creates a handler function that processes incoming Slack requests.
115
190
  * This is the main entry point for handling Slack events in Vercel.
@@ -151,4 +226,4 @@ declare class VercelReceiver implements Receiver {
151
226
  */
152
227
  declare function createHandler(app: App, receiver: VercelReceiver): VercelHandler;
153
228
 
154
- export { type VercelHandler, VercelReceiver, type VercelReceiverOptions, createHandler };
229
+ export { type VercelHandler, type VercelInstallerOptions, VercelReceiver, type VercelReceiverOptions, createHandler };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Receiver, StringIndexed, App } from '@slack/bolt';
2
2
  import { Logger, LogLevel } from '@slack/logger';
3
+ import { StateStore, InstallProviderOptions, InstallPathOptions, CallbackOptions, InstallProvider } from '@slack/oauth';
3
4
 
4
5
  /**
5
6
  * A function to handle the request from the Slack app.
@@ -15,6 +16,30 @@ type VercelHandler = (req: Request) => Promise<Response>;
15
16
  * @property logLevel - The log level to use for the VercelReceiver.
16
17
  * @property customPropertiesExtractor - A function to extract custom properties from the request.
17
18
  */
19
+ /**
20
+ * Options for customizing the OAuth installer behavior.
21
+ * Mirrors the relevant subset of HTTPReceiverInstallerOptions,
22
+ * excluding path-related options (serverless uses file-based routing).
23
+ */
24
+ interface VercelInstallerOptions {
25
+ directInstall?: boolean;
26
+ renderHtmlForInstallPath?: (url: string) => string;
27
+ stateStore?: StateStore;
28
+ stateVerification?: boolean;
29
+ legacyStateVerification?: boolean;
30
+ stateCookieName?: string;
31
+ stateCookieExpirationSeconds?: number;
32
+ authVersion?: "v1" | "v2";
33
+ clientOptions?: InstallProviderOptions["clientOptions"];
34
+ authorizationUrl?: string;
35
+ metadata?: string;
36
+ userScopes?: string[];
37
+ installPathOptions?: InstallPathOptions;
38
+ callbackOptions?: CallbackOptions;
39
+ }
40
+ /**
41
+ * Configuration options for the VercelReceiver.
42
+ */
18
43
  interface VercelReceiverOptions {
19
44
  /**
20
45
  * The signing secret for the Slack app.
@@ -47,6 +72,41 @@ interface VercelReceiverOptions {
47
72
  * @default 3001
48
73
  */
49
74
  ackTimeoutMs?: number;
75
+ /**
76
+ * Your app's client ID, found under Basic Information on api.slack.com.
77
+ * Required for OAuth.
78
+ * @default process.env.SLACK_CLIENT_ID
79
+ */
80
+ clientId?: string;
81
+ /**
82
+ * Your app's client secret, found under Basic Information on api.slack.com.
83
+ * Required for OAuth.
84
+ * @default process.env.SLACK_CLIENT_SECRET
85
+ */
86
+ clientSecret?: string;
87
+ /**
88
+ * Secret used to generate and verify the state parameter for OAuth CSRF protection.
89
+ * Required unless a custom stateStore or stateVerification: false is provided.
90
+ * @default process.env.SLACK_STATE_SECRET
91
+ */
92
+ stateSecret?: string;
93
+ /**
94
+ * The bot scopes to request during the OAuth flow.
95
+ */
96
+ scopes?: string[];
97
+ /**
98
+ * The redirect URI registered with your Slack app for OAuth callbacks.
99
+ */
100
+ redirectUri?: string;
101
+ /**
102
+ * Storage backend for OAuth installations (tokens, team info, etc.).
103
+ * Required for OAuth in serverless -- the default in-memory store does not persist.
104
+ */
105
+ installationStore?: InstallProviderOptions["installationStore"];
106
+ /**
107
+ * Advanced options for the OAuth installer.
108
+ */
109
+ installerOptions?: VercelInstallerOptions;
50
110
  }
51
111
  /**
52
112
  * A Slack Bolt receiver implementation designed for Vercel's serverless environment.
@@ -75,6 +135,11 @@ declare class VercelReceiver implements Receiver {
75
135
  private readonly customPropertiesExtractor?;
76
136
  private readonly ackTimeoutMs;
77
137
  private app?;
138
+ installer?: InstallProvider;
139
+ private installUrlOptions?;
140
+ private installCallbackOptions?;
141
+ private installPathOptions?;
142
+ private stateVerification?;
78
143
  /**
79
144
  * Gets the logger instance used by this receiver.
80
145
  * @returns The logger instance
@@ -91,7 +156,7 @@ declare class VercelReceiver implements Receiver {
91
156
  * const receiver = new VercelReceiver();
92
157
  * ```
93
158
  */
94
- constructor({ signingSecret, signatureVerification, logger, logLevel, customPropertiesExtractor, ackTimeoutMs, }?: VercelReceiverOptions);
159
+ constructor({ signingSecret, signatureVerification, logger, logLevel, customPropertiesExtractor, ackTimeoutMs, clientId, clientSecret, stateSecret, scopes, redirectUri, installationStore, installerOptions, }?: VercelReceiverOptions);
95
160
  /**
96
161
  * Initializes the receiver with a Slack Bolt app instance.
97
162
  * This method is called automatically by the Bolt framework.
@@ -110,6 +175,16 @@ declare class VercelReceiver implements Receiver {
110
175
  * Stops the receiver. This method is called automatically by the Bolt framework.
111
176
  */
112
177
  stop(): Promise<void>;
178
+ /**
179
+ * Handles requests to the OAuth install path.
180
+ * Renders an "Add to Slack" page or redirects directly to Slack's authorize URL.
181
+ */
182
+ handleInstall: (req: Request) => Promise<Response>;
183
+ /**
184
+ * Handles the OAuth redirect callback from Slack.
185
+ * Exchanges the authorization code for tokens and stores the installation.
186
+ */
187
+ handleCallback: (req: Request) => Promise<Response>;
113
188
  /**
114
189
  * Creates a handler function that processes incoming Slack requests.
115
190
  * This is the main entry point for handling Slack events in Vercel.
@@ -151,4 +226,4 @@ declare class VercelReceiver implements Receiver {
151
226
  */
152
227
  declare function createHandler(app: App, receiver: VercelReceiver): VercelHandler;
153
228
 
154
- export { type VercelHandler, VercelReceiver, type VercelReceiverOptions, createHandler };
229
+ export { type VercelHandler, type VercelInstallerOptions, VercelReceiver, type VercelReceiverOptions, createHandler };
package/dist/index.js CHANGED
@@ -3,13 +3,17 @@
3
3
  require('./chunk-QHMZVK6J.js');
4
4
  var bolt = require('@slack/bolt');
5
5
  var logger = require('@slack/logger');
6
+ var oauth = require('@slack/oauth');
6
7
  var functions = require('@vercel/functions');
8
+ var http = require('http');
9
+ var net = require('net');
7
10
 
8
11
  // src/errors.ts
9
12
  var ERROR_MESSAGES = {
10
13
  // VercelReceiver errors
11
14
  SIGNING_SECRET_REQUIRED: "SLACK_SIGNING_SECRET is required for VercelReceiver",
12
15
  APP_NOT_INITIALIZED: "App not initialized",
16
+ OAUTH_NOT_CONFIGURED: "OAuth is not configured. Provide clientId, clientSecret, and stateSecret to enable OAuth.",
13
17
  REQUEST_TIMEOUT: "Request timeout",
14
18
  EVENT_NOT_ACKNOWLEDGED: "Event not acknowledged within timeout period",
15
19
  // Header validation errors
@@ -78,6 +82,80 @@ function getErrorType(error) {
78
82
  }
79
83
  return ERROR_MESSAGES.TYPES.UNEXPECTED_ERROR;
80
84
  }
85
+ function toIncomingMessage(req) {
86
+ const url = new URL(req.url);
87
+ const msg = new http.IncomingMessage(new net.Socket());
88
+ msg.url = url.pathname + url.search;
89
+ msg.method = req.method;
90
+ for (const [key, value] of req.headers.entries()) {
91
+ msg.headers[key.toLowerCase()] = value;
92
+ }
93
+ if (req.body) {
94
+ req.arrayBuffer().then((buf) => {
95
+ msg.push(Buffer.from(buf));
96
+ msg.push(null);
97
+ }).catch(() => msg.destroy());
98
+ } else {
99
+ msg.push(null);
100
+ }
101
+ return msg;
102
+ }
103
+ function createResponseCapture() {
104
+ let statusCode = 200;
105
+ const capturedHeaders = {};
106
+ const chunks = [];
107
+ const res = new http.ServerResponse(new http.IncomingMessage(new net.Socket()));
108
+ const originalSetHeader = res.setHeader.bind(res);
109
+ res.setHeader = (name, value) => {
110
+ const key = name.toLowerCase();
111
+ if (Array.isArray(value)) {
112
+ capturedHeaders[key] = [...value];
113
+ } else {
114
+ capturedHeaders[key] = String(value);
115
+ }
116
+ return originalSetHeader(name, value);
117
+ };
118
+ const originalGetHeader = res.getHeader.bind(res);
119
+ res.getHeader = (name) => {
120
+ const val = capturedHeaders[name.toLowerCase()];
121
+ if (val !== void 0) return val;
122
+ return originalGetHeader(name);
123
+ };
124
+ const originalWriteHead = res.writeHead.bind(res);
125
+ res.writeHead = (code, ...args) => {
126
+ statusCode = code;
127
+ const headersArg = args.find(
128
+ (a) => a !== void 0 && typeof a === "object" && !Array.isArray(a)
129
+ );
130
+ if (headersArg) {
131
+ for (const [key, value] of Object.entries(headersArg)) {
132
+ const lower = key.toLowerCase();
133
+ capturedHeaders[lower] = value;
134
+ }
135
+ }
136
+ return originalWriteHead(code, ...args);
137
+ };
138
+ const originalEnd = res.end.bind(res);
139
+ res.end = (chunk, ...args) => {
140
+ if (chunk !== void 0 && chunk !== null) {
141
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
142
+ }
143
+ return originalEnd(chunk, ...args);
144
+ };
145
+ res.toResponse = () => {
146
+ const body = chunks.length > 0 ? Buffer.concat(chunks).toString() : null;
147
+ const webHeaders = new Headers();
148
+ for (const [key, value] of Object.entries(capturedHeaders)) {
149
+ if (Array.isArray(value)) {
150
+ for (const v of value) webHeaders.append(key, v);
151
+ } else {
152
+ webHeaders.set(key, value);
153
+ }
154
+ }
155
+ return new Response(body, { status: statusCode, headers: webHeaders });
156
+ };
157
+ return res;
158
+ }
81
159
 
82
160
  // src/index.ts
83
161
  var LOG_PREFIX = "[@vercel/slack-bolt]";
@@ -93,6 +171,11 @@ var VercelReceiver = class {
93
171
  customPropertiesExtractor;
94
172
  ackTimeoutMs;
95
173
  app;
174
+ installer;
175
+ installUrlOptions;
176
+ installCallbackOptions;
177
+ installPathOptions;
178
+ stateVerification;
96
179
  /**
97
180
  * Gets the logger instance used by this receiver.
98
181
  * @returns The logger instance
@@ -117,7 +200,14 @@ var VercelReceiver = class {
117
200
  logger: logger$1,
118
201
  logLevel = logger.LogLevel.INFO,
119
202
  customPropertiesExtractor,
120
- ackTimeoutMs = ACK_TIMEOUT_MS
203
+ ackTimeoutMs = ACK_TIMEOUT_MS,
204
+ clientId = process.env.SLACK_CLIENT_ID,
205
+ clientSecret = process.env.SLACK_CLIENT_SECRET,
206
+ stateSecret = process.env.SLACK_STATE_SECRET,
207
+ scopes,
208
+ redirectUri,
209
+ installationStore,
210
+ installerOptions = {}
121
211
  } = {}) {
122
212
  if (!signingSecret) {
123
213
  throw new VercelReceiverError(ERROR_MESSAGES.SIGNING_SECRET_REQUIRED);
@@ -130,6 +220,35 @@ var VercelReceiver = class {
130
220
  );
131
221
  this.customPropertiesExtractor = customPropertiesExtractor;
132
222
  this.ackTimeoutMs = ackTimeoutMs;
223
+ this.stateVerification = installerOptions.stateVerification;
224
+ if (clientId !== void 0 && clientSecret !== void 0 && (installerOptions.stateVerification === false || stateSecret !== void 0 || installerOptions.stateStore !== void 0)) {
225
+ this.installer = new oauth.InstallProvider({
226
+ clientId,
227
+ clientSecret,
228
+ stateSecret,
229
+ installationStore,
230
+ logger: logger$1,
231
+ logLevel,
232
+ directInstall: installerOptions.directInstall,
233
+ stateStore: installerOptions.stateStore,
234
+ stateVerification: installerOptions.stateVerification,
235
+ legacyStateVerification: installerOptions.legacyStateVerification,
236
+ stateCookieName: installerOptions.stateCookieName,
237
+ stateCookieExpirationSeconds: installerOptions.stateCookieExpirationSeconds,
238
+ renderHtmlForInstallPath: installerOptions.renderHtmlForInstallPath,
239
+ authVersion: installerOptions.authVersion ?? "v2",
240
+ clientOptions: installerOptions.clientOptions,
241
+ authorizationUrl: installerOptions.authorizationUrl
242
+ });
243
+ this.installUrlOptions = {
244
+ scopes: scopes ?? [],
245
+ userScopes: installerOptions.userScopes,
246
+ metadata: installerOptions.metadata,
247
+ redirectUri
248
+ };
249
+ this.installCallbackOptions = installerOptions.callbackOptions ?? {};
250
+ this.installPathOptions = installerOptions.installPathOptions ?? {};
251
+ }
133
252
  this.logger.debug("VercelReceiver initialized");
134
253
  }
135
254
  /**
@@ -158,6 +277,50 @@ var VercelReceiver = class {
158
277
  async stop() {
159
278
  this.logger.debug("VercelReceiver stopped");
160
279
  }
280
+ /**
281
+ * Handles requests to the OAuth install path.
282
+ * Renders an "Add to Slack" page or redirects directly to Slack's authorize URL.
283
+ */
284
+ handleInstall = async (req) => {
285
+ if (!this.installer) {
286
+ throw new VercelReceiverError(ERROR_MESSAGES.OAUTH_NOT_CONFIGURED);
287
+ }
288
+ const nodeReq = toIncomingMessage(req);
289
+ const capture = createResponseCapture();
290
+ await this.installer.handleInstallPath(
291
+ nodeReq,
292
+ capture,
293
+ this.installPathOptions,
294
+ this.installUrlOptions
295
+ );
296
+ return capture.toResponse();
297
+ };
298
+ /**
299
+ * Handles the OAuth redirect callback from Slack.
300
+ * Exchanges the authorization code for tokens and stores the installation.
301
+ */
302
+ handleCallback = async (req) => {
303
+ if (!this.installer) {
304
+ throw new VercelReceiverError(ERROR_MESSAGES.OAUTH_NOT_CONFIGURED);
305
+ }
306
+ const nodeReq = toIncomingMessage(req);
307
+ const capture = createResponseCapture();
308
+ if (this.stateVerification === false) {
309
+ await this.installer.handleCallback(
310
+ nodeReq,
311
+ capture,
312
+ this.installCallbackOptions,
313
+ this.installUrlOptions
314
+ );
315
+ } else {
316
+ await this.installer.handleCallback(
317
+ nodeReq,
318
+ capture,
319
+ this.installCallbackOptions
320
+ );
321
+ }
322
+ return capture.toResponse();
323
+ };
161
324
  /**
162
325
  * Creates a handler function that processes incoming Slack requests.
163
326
  * This is the main entry point for handling Slack events in Vercel.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/index.ts"],"names":["logger","LogLevel","ConsoleLogger","ReceiverMultipleAckError","body","waitUntil","ReceiverAuthenticityError","verifySlackRequest"],"mappings":"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","file":"index.js","sourcesContent":["// Error messages constants\nexport const ERROR_MESSAGES = {\n // VercelReceiver errors\n SIGNING_SECRET_REQUIRED:\n \"SLACK_SIGNING_SECRET is required for VercelReceiver\",\n APP_NOT_INITIALIZED: \"App not initialized\",\n REQUEST_TIMEOUT: \"Request timeout\",\n EVENT_NOT_ACKNOWLEDGED: \"Event not acknowledged within timeout period\",\n\n // Header validation errors\n MISSING_REQUIRED_HEADER: (header: string) =>\n `Missing required header: ${header}`,\n\n // Generic fallback errors\n REQUEST_VERIFICATION_FAILED: \"Request verification failed\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n INTERNAL_SERVER_ERROR_HANDLER: \"Internal Server Error\",\n ACKNOWLEDGMENT_ERROR: \"Error in acknowledgment handler\",\n CREATE_HANDLER_ERROR: \"Error in createHandler:\",\n\n // Error type names\n TYPES: {\n VERCEL_RECEIVER_ERROR: \"VercelReceiverError\",\n SIGNATURE_VERIFICATION_ERROR: \"SignatureVerificationError\",\n REQUEST_PARSING_ERROR: \"RequestParsingError\",\n UNEXPECTED_ERROR: \"UnexpectedError\",\n HANDLER_ERROR: \"HandlerError\",\n },\n} as const;\n\nexport class VercelReceiverError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number = 500,\n ) {\n super(message);\n this.name = ERROR_MESSAGES.TYPES.VERCEL_RECEIVER_ERROR;\n }\n}\n\nexport class RequestParsingError extends VercelReceiverError {\n constructor(message: string = \"Failed to parse request\") {\n super(message, 400);\n this.name = ERROR_MESSAGES.TYPES.REQUEST_PARSING_ERROR;\n }\n}\n\n/**\n * Determines the appropriate HTTP status code for a given error.\n * @param error The error to get status code for\n * @returns HTTP status code\n */\nexport function getStatusCode(error: unknown): number {\n if (error instanceof VercelReceiverError) {\n return error.statusCode;\n }\n\n // External error types from @slack/bolt\n if (error && typeof error === \"object\") {\n const errorName =\n error.constructor?.name || (error as { name?: string }).name;\n switch (errorName) {\n case \"ReceiverAuthenticityError\":\n return 401;\n case \"ReceiverMultipleAckError\":\n return 500;\n case \"RequestParsingError\":\n return 400;\n case \"SignatureVerificationError\":\n return 400;\n default:\n return 500;\n }\n }\n\n return 500;\n}\n\n/**\n * Gets the error message for response.\n * @param error The error to get message for\n * @returns Error message string\n */\nexport function getErrorMessage(error: unknown): string {\n if (error && typeof error === \"object\" && \"message\" in error) {\n return String(error.message);\n }\n return ERROR_MESSAGES.INTERNAL_SERVER_ERROR;\n}\n\n/**\n * Gets the error type for response.\n * @param error The error to get type for\n * @returns Error type string\n */\nexport function getErrorType(error: unknown): string {\n if (error && typeof error === \"object\") {\n const ctorName = (error as { constructor?: { name?: string } }).constructor\n ?.name;\n const nameProp = (error as { name?: string }).name;\n const errorName =\n ctorName ?? nameProp ?? ERROR_MESSAGES.TYPES.UNEXPECTED_ERROR;\n // Use \"UnexpectedError\" for generic Error instances, otherwise use the actual name\n return errorName === \"Error\"\n ? ERROR_MESSAGES.TYPES.UNEXPECTED_ERROR\n : errorName;\n }\n return ERROR_MESSAGES.TYPES.UNEXPECTED_ERROR;\n}\n","import {\n type AckFn,\n type App,\n type Receiver,\n ReceiverAuthenticityError,\n type ReceiverEvent,\n ReceiverMultipleAckError,\n type StringIndexed,\n verifySlackRequest,\n} from \"@slack/bolt\";\nimport { ConsoleLogger, type Logger, LogLevel } from \"@slack/logger\";\nimport { waitUntil } from \"@vercel/functions\";\nimport {\n ERROR_MESSAGES,\n getErrorMessage,\n getErrorType,\n getStatusCode,\n RequestParsingError,\n VercelReceiverError,\n} from \"./errors\";\n\n// Types\n/**\n * A function to handle the request from the Slack app.\n * @param req - The request from the Slack app.\n * @returns A response object.\n */\nexport type VercelHandler = (req: Request) => Promise<Response>;\n\n/**\n * Configuration options for the VercelReceiver.\n * @property signingSecret - The signing secret for the Slack app.\n * @property signatureVerification - If true, verifies the Slack request signature.\n * @property logger - The logger to use for the VercelReceiver.\n * @property logLevel - The log level to use for the VercelReceiver.\n * @property customPropertiesExtractor - A function to extract custom properties from the request.\n */\nexport interface VercelReceiverOptions {\n /**\n * The signing secret for the Slack app.\n * @default process.env.SLACK_SIGNING_SECRET\n */\n signingSecret?: string;\n /**\n * If true, verifies the Slack request signature.\n * @default true\n */\n signatureVerification?: boolean;\n /**\n * The logger to use for the VercelReceiver.\n * @default new ConsoleLogger()\n */\n logger?: Logger;\n /**\n * The log level to use for the VercelReceiver.\n * @default LogLevel.INFO\n */\n logLevel?: LogLevel;\n /**\n * A function to extract custom properties from incoming events.\n * @default undefined\n * @returns An object with custom properties.\n */\n customPropertiesExtractor?: (req: Request) => StringIndexed;\n /**\n * The timeout in milliseconds for event acknowledgment.\n * @default 3001\n */\n ackTimeoutMs?: number;\n}\n\nconst LOG_PREFIX = \"[@vercel/slack-bolt]\";\nconst ACK_TIMEOUT_MS = 3001;\nconst SLACK_RETRY_NUM_HEADER = \"x-slack-retry-num\";\nconst SLACK_RETRY_REASON_HEADER = \"x-slack-retry-reason\";\nconst SLACK_TIMESTAMP_HEADER = \"x-slack-request-timestamp\";\nconst SLACK_SIGNATURE_HEADER = \"x-slack-signature\";\n\n/**\n * A Slack Bolt receiver implementation designed for Vercel's serverless environment.\n * Handles Slack events, interactions, and slash commands with automatic request verification,\n * background processing, and timeout management.\n *\n * @example\n * ```typescript\n * import { App } from '@slack/bolt';\n * import { VercelReceiver, createHandler } from '@vercel/slack-bolt';\n *\n * const receiver = new VercelReceiver();\n *\n * const app = new App({\n * receiver,\n * token: process.env.SLACK_BOT_TOKEN,\n * signingSecret: process.env.SLACK_SIGNING_SECRET,\n * });\n * ```\n *\n */\nexport class VercelReceiver implements Receiver {\n private readonly signingSecret: string;\n private readonly signatureVerification: boolean;\n private readonly logger: Logger;\n private readonly customPropertiesExtractor?: (req: Request) => StringIndexed;\n private readonly ackTimeoutMs: number;\n private app?: App;\n\n /**\n * Gets the logger instance used by this receiver.\n * @returns The logger instance\n */\n public getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Creates a new VercelReceiver instance.\n *\n * @param options - Configuration options for the receiver\n * @throws {VercelReceiverError} When signing secret is not provided\n *\n * @example\n * ```typescript\n * const receiver = new VercelReceiver();\n * ```\n */\n public constructor({\n signingSecret = process.env.SLACK_SIGNING_SECRET,\n signatureVerification = true,\n logger,\n logLevel = LogLevel.INFO,\n customPropertiesExtractor,\n ackTimeoutMs = ACK_TIMEOUT_MS,\n }: VercelReceiverOptions = {}) {\n if (!signingSecret) {\n throw new VercelReceiverError(ERROR_MESSAGES.SIGNING_SECRET_REQUIRED);\n }\n\n this.signingSecret = signingSecret;\n this.signatureVerification = signatureVerification;\n this.logger = this.createScopedLogger(\n logger ?? new ConsoleLogger(),\n logLevel,\n );\n this.customPropertiesExtractor = customPropertiesExtractor;\n this.ackTimeoutMs = ackTimeoutMs;\n\n this.logger.debug(\"VercelReceiver initialized\");\n }\n\n /**\n * Initializes the receiver with a Slack Bolt app instance.\n * This method is called automatically by the Bolt framework.\n *\n * @param app - The Slack Bolt app instance\n */\n public init(app: App): void {\n this.app = app;\n this.logger.debug(\"App initialized in VercelReceiver\");\n }\n\n /**\n * Starts the receiver and returns a handler function for processing requests.\n * This method is called automatically by the Bolt framework.\n *\n * @returns A handler function that processes incoming Slack requests\n */\n public async start(): Promise<VercelHandler> {\n this.logger.debug(\"VercelReceiver started\");\n return this.toHandler();\n }\n\n /**\n * Stops the receiver. This method is called automatically by the Bolt framework.\n */\n public async stop(): Promise<void> {\n this.logger.debug(\"VercelReceiver stopped\");\n }\n\n /**\n * Creates a handler function that processes incoming Slack requests.\n * This is the main entry point for handling Slack events in Vercel.\n * It is called automatically by the Bolt framework in the start() method.\n *\n * @returns A handler function compatible with Vercel's function signature\n */\n public toHandler(): VercelHandler {\n return async (req: Request): Promise<Response> => {\n try {\n const rawBody = await req.text();\n\n if (this.signatureVerification) {\n this.verifyRequest(req, rawBody);\n }\n\n const body = await this.parseRequestBody(req, rawBody);\n\n if (body.type === \"url_verification\") {\n this.logger.debug(\"Handling URL verification challenge\");\n return Response.json({ challenge: body.challenge });\n }\n\n return await this.handleSlackEvent(req, body);\n } catch (error) {\n return this.handleError(error);\n }\n };\n }\n\n private async parseRequestBody(\n req: Request,\n rawBody: string,\n ): Promise<StringIndexed> {\n const contentType = req.headers.get(\"content-type\");\n\n try {\n if (contentType === \"application/x-www-form-urlencoded\") {\n const parsedBody: StringIndexed = {};\n const params = new URLSearchParams(rawBody);\n\n for (const [key, value] of params.entries()) {\n parsedBody[key] = value;\n }\n\n if (typeof parsedBody.payload === \"string\") {\n return JSON.parse(parsedBody.payload);\n }\n return parsedBody;\n }\n if (contentType === \"application/json\") {\n return JSON.parse(rawBody);\n }\n\n this.logger.warn(`Unexpected content-type detected: ${contentType}`);\n\n return JSON.parse(rawBody);\n } catch (e) {\n throw new RequestParsingError(\n `Failed to parse body as JSON data for content-type: ${contentType}. Error: ${\n e instanceof Error ? e.message : String(e)\n }`,\n );\n }\n }\n\n private async handleSlackEvent(\n req: Request,\n body: StringIndexed,\n ): Promise<Response> {\n if (!this.app) {\n throw new VercelReceiverError(ERROR_MESSAGES.APP_NOT_INITIALIZED, 500);\n }\n\n let isAcknowledged = false;\n let responseResolver: (value: Response) => void;\n let responseRejecter: (error: Error) => void;\n\n const responsePromise = new Promise<Response>((resolve, reject) => {\n responseResolver = resolve;\n responseRejecter = reject;\n });\n\n // Slack requires an acknowledgment from your app within 3 seconds\n const timeoutId = setTimeout(() => {\n if (!isAcknowledged) {\n isAcknowledged = true;\n this.logger.error(ERROR_MESSAGES.EVENT_NOT_ACKNOWLEDGED);\n const error = new VercelReceiverError(\n ERROR_MESSAGES.REQUEST_TIMEOUT,\n 408,\n );\n responseRejecter(error);\n }\n }, this.ackTimeoutMs);\n\n // Create acknowledgment function\n const ackFn: AckFn<StringIndexed> = async (responseBody) => {\n this.logger.debug(`ack() call begins (body: ${responseBody})`);\n if (isAcknowledged) {\n throw new ReceiverMultipleAckError();\n }\n\n isAcknowledged = true;\n clearTimeout(timeoutId);\n\n try {\n let body: string | undefined;\n if (typeof responseBody === \"undefined\") {\n body = undefined;\n } else if (typeof responseBody === \"string\") {\n body = responseBody;\n } else {\n body = JSON.stringify(responseBody);\n }\n const response = new Response(body, {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n\n responseResolver(response);\n } catch (error) {\n this.logger.error(ERROR_MESSAGES.ACKNOWLEDGMENT_ERROR, error);\n responseRejecter(\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n };\n\n const event = this.createSlackReceiverEvent({\n body,\n headers: req.headers,\n ack: ackFn,\n request: req,\n });\n\n // Process event in background using waitUntil from Vercel Functions\n // https://vercel.com/docs/functions/functions-api-reference/vercel-functions-package#waituntil\n waitUntil(\n this.app.processEvent(event).catch((error) => {\n return this.handleError(error);\n }),\n );\n\n try {\n return await responsePromise;\n } catch (error) {\n return this.handleError(error);\n }\n }\n\n private verifyRequest(req: Request, body: string): void {\n const timestamp = req.headers.get(SLACK_TIMESTAMP_HEADER);\n const signature = req.headers.get(SLACK_SIGNATURE_HEADER);\n\n if (!signature) {\n throw new ReceiverAuthenticityError(\n ERROR_MESSAGES.MISSING_REQUIRED_HEADER(SLACK_SIGNATURE_HEADER),\n );\n }\n\n if (!timestamp) {\n throw new ReceiverAuthenticityError(\n ERROR_MESSAGES.MISSING_REQUIRED_HEADER(SLACK_TIMESTAMP_HEADER),\n );\n }\n\n try {\n verifySlackRequest({\n signingSecret: this.signingSecret,\n body,\n headers: {\n \"x-slack-signature\": signature,\n \"x-slack-request-timestamp\": Number.parseInt(timestamp, 10),\n },\n logger: this.logger,\n });\n } catch (error) {\n throw new ReceiverAuthenticityError(\n error instanceof Error\n ? error.message\n : \"Failed to verify request signature\",\n );\n }\n }\n\n private createSlackReceiverEvent({\n body,\n headers,\n ack,\n request,\n }: {\n body: StringIndexed;\n headers: Headers;\n ack: AckFn<StringIndexed>;\n request: Request;\n }): ReceiverEvent {\n const customProperties = this.customPropertiesExtractor\n ? this.customPropertiesExtractor(request)\n : {};\n\n const retryNum = headers.get(SLACK_RETRY_NUM_HEADER) || \"0\";\n\n const retryReason = headers.get(SLACK_RETRY_REASON_HEADER) || \"\";\n\n return {\n body,\n ack,\n retryNum: Number(retryNum),\n retryReason,\n customProperties,\n };\n }\n\n public handleError(error: unknown): Response {\n const errorMessage = getErrorMessage(error);\n const errorType = getErrorType(error);\n const errorStatusCode = getStatusCode(error);\n\n this.logger.error(error);\n return new Response(\n JSON.stringify({\n error: errorMessage,\n type: errorType,\n }),\n {\n status: errorStatusCode,\n headers: { \"content-type\": \"application/json\" },\n },\n );\n }\n\n private createScopedLogger(logger: Logger, logLevel: LogLevel): Logger {\n logger.setLevel(logLevel);\n\n return {\n ...logger,\n error: (...args) => logger.error?.(LOG_PREFIX, ...args),\n warn: (...args) => logger.warn?.(LOG_PREFIX, ...args),\n info: (...args) => logger.info?.(LOG_PREFIX, ...args),\n debug: (...args) => logger.debug?.(LOG_PREFIX, ...args),\n setLevel: logger.setLevel,\n getLevel: logger.getLevel,\n };\n }\n}\n\n/**\n * Creates a Vercel-compatible handler function for a Slack Bolt app.\n * This is the recommended way to create handlers for deployment on Vercel.\n *\n * @param {App} app - The initialized Slack Bolt app instance.\n * @param {VercelReceiver} receiver - The VercelReceiver instance.\n * @returns {VercelHandler} A handler function compatible with Vercel's function signature.\n *\n * @example\n * ```typescript\n * // api/events.ts\n * import { createHandler } from '@vercel/slack-bolt';\n * import { app, receiver } from '../app';\n *\n * const handler = createHandler(app, receiver);\n *\n * export const POST = async (req: Request) => {\n * return handler(req);\n * };\n * ```\n *\n * @throws {Error} If app initialization fails.\n * @throws {VercelReceiverError} If request processing fails.\n */\nexport function createHandler(\n app: App,\n receiver: VercelReceiver,\n): VercelHandler {\n let initPromise: Promise<void> | null = null;\n\n return async (req: Request) => {\n try {\n if (!initPromise) {\n initPromise = app.init().catch((error) => {\n // Reset initPromise so subsequent requests can retry initialization\n initPromise = null;\n throw error;\n });\n }\n await initPromise;\n\n receiver.init(app);\n const handler = await receiver.start();\n return handler(req);\n } catch (error) {\n // if app.init fails, we use console.error instead of logger.error because the logger is not available\n console.error(ERROR_MESSAGES.CREATE_HANDLER_ERROR, error);\n return new Response(\n JSON.stringify({\n error: ERROR_MESSAGES.INTERNAL_SERVER_ERROR_HANDLER,\n type: ERROR_MESSAGES.TYPES.HANDLER_ERROR,\n }),\n { status: 500, headers: { \"content-type\": \"application/json\" } },\n );\n }\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/oauth-adapters.ts","../src/index.ts"],"names":["IncomingMessage","Socket","ServerResponse","logger","LogLevel","ConsoleLogger","InstallProvider","ReceiverMultipleAckError","body","waitUntil","ReceiverAuthenticityError","verifySlackRequest"],"mappings":"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","file":"index.js","sourcesContent":["// Error messages constants\nexport const ERROR_MESSAGES = {\n // VercelReceiver errors\n SIGNING_SECRET_REQUIRED:\n \"SLACK_SIGNING_SECRET is required for VercelReceiver\",\n APP_NOT_INITIALIZED: \"App not initialized\",\n OAUTH_NOT_CONFIGURED:\n \"OAuth is not configured. Provide clientId, clientSecret, and stateSecret to enable OAuth.\",\n REQUEST_TIMEOUT: \"Request timeout\",\n EVENT_NOT_ACKNOWLEDGED: \"Event not acknowledged within timeout period\",\n\n // Header validation errors\n MISSING_REQUIRED_HEADER: (header: string) =>\n `Missing required header: ${header}`,\n\n // Generic fallback errors\n REQUEST_VERIFICATION_FAILED: \"Request verification failed\",\n INTERNAL_SERVER_ERROR: \"Internal server error\",\n INTERNAL_SERVER_ERROR_HANDLER: \"Internal Server Error\",\n ACKNOWLEDGMENT_ERROR: \"Error in acknowledgment handler\",\n CREATE_HANDLER_ERROR: \"Error in createHandler:\",\n\n // Error type names\n TYPES: {\n VERCEL_RECEIVER_ERROR: \"VercelReceiverError\",\n SIGNATURE_VERIFICATION_ERROR: \"SignatureVerificationError\",\n REQUEST_PARSING_ERROR: \"RequestParsingError\",\n UNEXPECTED_ERROR: \"UnexpectedError\",\n HANDLER_ERROR: \"HandlerError\",\n },\n} as const;\n\nexport class VercelReceiverError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number = 500,\n ) {\n super(message);\n this.name = ERROR_MESSAGES.TYPES.VERCEL_RECEIVER_ERROR;\n }\n}\n\nexport class RequestParsingError extends VercelReceiverError {\n constructor(message: string = \"Failed to parse request\") {\n super(message, 400);\n this.name = ERROR_MESSAGES.TYPES.REQUEST_PARSING_ERROR;\n }\n}\n\n/**\n * Determines the appropriate HTTP status code for a given error.\n * @param error The error to get status code for\n * @returns HTTP status code\n */\nexport function getStatusCode(error: unknown): number {\n if (error instanceof VercelReceiverError) {\n return error.statusCode;\n }\n\n // External error types from @slack/bolt\n if (error && typeof error === \"object\") {\n const errorName =\n error.constructor?.name || (error as { name?: string }).name;\n switch (errorName) {\n case \"ReceiverAuthenticityError\":\n return 401;\n case \"ReceiverMultipleAckError\":\n return 500;\n case \"RequestParsingError\":\n return 400;\n case \"SignatureVerificationError\":\n return 400;\n default:\n return 500;\n }\n }\n\n return 500;\n}\n\n/**\n * Gets the error message for response.\n * @param error The error to get message for\n * @returns Error message string\n */\nexport function getErrorMessage(error: unknown): string {\n if (error && typeof error === \"object\" && \"message\" in error) {\n return String(error.message);\n }\n return ERROR_MESSAGES.INTERNAL_SERVER_ERROR;\n}\n\n/**\n * Gets the error type for response.\n * @param error The error to get type for\n * @returns Error type string\n */\nexport function getErrorType(error: unknown): string {\n if (error && typeof error === \"object\") {\n const ctorName = (error as { constructor?: { name?: string } }).constructor\n ?.name;\n const nameProp = (error as { name?: string }).name;\n const errorName =\n ctorName ?? nameProp ?? ERROR_MESSAGES.TYPES.UNEXPECTED_ERROR;\n // Use \"UnexpectedError\" for generic Error instances, otherwise use the actual name\n return errorName === \"Error\"\n ? ERROR_MESSAGES.TYPES.UNEXPECTED_ERROR\n : errorName;\n }\n return ERROR_MESSAGES.TYPES.UNEXPECTED_ERROR;\n}\n","/**\n * Minimal Web <-> Node HTTP adapters for @slack/oauth InstallProvider.\n *\n * These do NOT implement the full IncomingMessage/ServerResponse contract.\n * Only the methods actually called by InstallProvider are intercepted.\n * Do not reuse for other Node libraries without verifying which methods\n * they call.\n *\n * Targets @slack/oauth\\@3.0.5 InstallProvider internals.\n * Do not upgrade without running the integration tests.\n */\n\nimport { IncomingMessage, ServerResponse } from \"node:http\";\nimport { Socket } from \"node:net\";\n\nexport type ResponseCapture = ServerResponse & { toResponse(): Response };\n\n/**\n * Wraps a Web API Request as a minimal Node.js IncomingMessage\n * so it can be passed to @slack/oauth's InstallProvider methods.\n */\nexport function toIncomingMessage(req: Request): IncomingMessage {\n const url = new URL(req.url);\n // Dummy socket — satisfies the IncomingMessage constructor but is never connected.\n const msg = new IncomingMessage(new Socket());\n msg.url = url.pathname + url.search;\n msg.method = req.method;\n for (const [key, value] of req.headers.entries()) {\n msg.headers[key.toLowerCase()] = value;\n }\n\n if (req.body) {\n req\n .arrayBuffer()\n .then((buf) => {\n msg.push(Buffer.from(buf));\n msg.push(null);\n })\n .catch(() => msg.destroy());\n } else {\n msg.push(null);\n }\n\n return msg;\n}\n\n/**\n * Creates a fake ServerResponse that captures setHeader/writeHead/end calls\n * and converts them into a Web API Response.\n *\n * InstallProvider uses res.setHeader() for Location, Set-Cookie, Content-Type\n * and res.getHeader() to read back Set-Cookie before appending.\n */\nexport function createResponseCapture(): ResponseCapture {\n let statusCode = 200;\n const capturedHeaders: Record<string, string | string[]> = {};\n const chunks: Buffer[] = [];\n\n // Dummy socket/message pair — never connected, just satisfies the constructor.\n const res = new ServerResponse(new IncomingMessage(new Socket()));\n\n const originalSetHeader = res.setHeader.bind(res);\n res.setHeader = (\n name: string,\n value: string | number | readonly string[],\n ) => {\n const key = name.toLowerCase();\n if (Array.isArray(value)) {\n capturedHeaders[key] = [...value];\n } else {\n capturedHeaders[key] = String(value);\n }\n return originalSetHeader(name, value);\n };\n\n const originalGetHeader = res.getHeader.bind(res);\n res.getHeader = (name: string): string | number | string[] | undefined => {\n const val = capturedHeaders[name.toLowerCase()];\n if (val !== undefined) return val;\n return originalGetHeader(name);\n };\n\n const originalWriteHead = res.writeHead.bind(res);\n // writeHead has four overloads: (code), (code, message), (code, headers),\n // and (code, message, headers). We sniff for the first non-array object arg\n // to find the headers object in all cases.\n // biome-ignore lint/suspicious/noExplicitAny: writeHead has many overloads\n res.writeHead = (code: number, ...args: any[]) => {\n statusCode = code;\n const headersArg = args.find(\n (a) => a !== undefined && typeof a === \"object\" && !Array.isArray(a),\n ) as Record<string, string | string[]> | undefined;\n if (headersArg) {\n for (const [key, value] of Object.entries(headersArg)) {\n const lower = key.toLowerCase();\n capturedHeaders[lower] = value;\n }\n }\n return originalWriteHead(code, ...args);\n };\n\n const originalEnd = res.end.bind(res);\n // biome-ignore lint/suspicious/noExplicitAny: end has many overloads\n res.end = (chunk?: any, ...args: any[]) => {\n if (chunk !== undefined && chunk !== null) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n return originalEnd(chunk, ...args);\n };\n\n (res as ResponseCapture).toResponse = () => {\n const body = chunks.length > 0 ? Buffer.concat(chunks).toString() : null;\n const webHeaders = new Headers();\n for (const [key, value] of Object.entries(capturedHeaders)) {\n if (Array.isArray(value)) {\n for (const v of value) webHeaders.append(key, v);\n } else {\n webHeaders.set(key, value);\n }\n }\n return new Response(body, { status: statusCode, headers: webHeaders });\n };\n\n return res as ResponseCapture;\n}\n","import {\n type AckFn,\n type App,\n type HTTPReceiverOptions,\n type Receiver,\n ReceiverAuthenticityError,\n type ReceiverEvent,\n ReceiverMultipleAckError,\n type StringIndexed,\n verifySlackRequest,\n} from \"@slack/bolt\";\nimport { ConsoleLogger, type Logger, LogLevel } from \"@slack/logger\";\nimport {\n type CallbackOptions,\n type InstallPathOptions,\n InstallProvider,\n type InstallProviderOptions,\n type InstallURLOptions,\n type StateStore,\n} from \"@slack/oauth\";\nimport { waitUntil } from \"@vercel/functions\";\nimport {\n ERROR_MESSAGES,\n getErrorMessage,\n getErrorType,\n getStatusCode,\n RequestParsingError,\n VercelReceiverError,\n} from \"./errors\";\nimport { createResponseCapture, toIncomingMessage } from \"./oauth-adapters\";\n\n// Types\n/**\n * A function to handle the request from the Slack app.\n * @param req - The request from the Slack app.\n * @returns A response object.\n */\nexport type VercelHandler = (req: Request) => Promise<Response>;\n\n/**\n * Configuration options for the VercelReceiver.\n * @property signingSecret - The signing secret for the Slack app.\n * @property signatureVerification - If true, verifies the Slack request signature.\n * @property logger - The logger to use for the VercelReceiver.\n * @property logLevel - The log level to use for the VercelReceiver.\n * @property customPropertiesExtractor - A function to extract custom properties from the request.\n */\n/**\n * Options for customizing the OAuth installer behavior.\n * Mirrors the relevant subset of HTTPReceiverInstallerOptions,\n * excluding path-related options (serverless uses file-based routing).\n */\nexport interface VercelInstallerOptions {\n directInstall?: boolean;\n renderHtmlForInstallPath?: (url: string) => string;\n stateStore?: StateStore;\n stateVerification?: boolean;\n legacyStateVerification?: boolean;\n stateCookieName?: string;\n stateCookieExpirationSeconds?: number;\n authVersion?: \"v1\" | \"v2\";\n clientOptions?: InstallProviderOptions[\"clientOptions\"];\n authorizationUrl?: string;\n metadata?: string;\n userScopes?: string[];\n installPathOptions?: InstallPathOptions;\n callbackOptions?: CallbackOptions;\n}\n\n/**\n * Configuration options for the VercelReceiver.\n */\nexport interface VercelReceiverOptions {\n /**\n * The signing secret for the Slack app.\n * @default process.env.SLACK_SIGNING_SECRET\n */\n signingSecret?: string;\n /**\n * If true, verifies the Slack request signature.\n * @default true\n */\n signatureVerification?: boolean;\n /**\n * The logger to use for the VercelReceiver.\n * @default new ConsoleLogger()\n */\n logger?: Logger;\n /**\n * The log level to use for the VercelReceiver.\n * @default LogLevel.INFO\n */\n logLevel?: LogLevel;\n /**\n * A function to extract custom properties from incoming events.\n * @default undefined\n * @returns An object with custom properties.\n */\n customPropertiesExtractor?: (req: Request) => StringIndexed;\n /**\n * The timeout in milliseconds for event acknowledgment.\n * @default 3001\n */\n ackTimeoutMs?: number;\n /**\n * Your app's client ID, found under Basic Information on api.slack.com.\n * Required for OAuth.\n * @default process.env.SLACK_CLIENT_ID\n */\n clientId?: string;\n /**\n * Your app's client secret, found under Basic Information on api.slack.com.\n * Required for OAuth.\n * @default process.env.SLACK_CLIENT_SECRET\n */\n clientSecret?: string;\n /**\n * Secret used to generate and verify the state parameter for OAuth CSRF protection.\n * Required unless a custom stateStore or stateVerification: false is provided.\n * @default process.env.SLACK_STATE_SECRET\n */\n stateSecret?: string;\n /**\n * The bot scopes to request during the OAuth flow.\n */\n scopes?: string[];\n /**\n * The redirect URI registered with your Slack app for OAuth callbacks.\n */\n redirectUri?: string;\n /**\n * Storage backend for OAuth installations (tokens, team info, etc.).\n * Required for OAuth in serverless -- the default in-memory store does not persist.\n */\n installationStore?: InstallProviderOptions[\"installationStore\"];\n /**\n * Advanced options for the OAuth installer.\n */\n installerOptions?: VercelInstallerOptions;\n}\n\n// ---------------------------------------------------------------------------\n// Compile-time shape assertions\n// Verify our types match Bolt's underlying shapes without coupling optionality.\n// If Bolt changes a type upstream, tsc breaks here -- not in user-land at runtime.\n// ---------------------------------------------------------------------------\ntype AssertShape<Source, Target> =\n NonNullable<Source> extends NonNullable<Target> ? true : never;\n\ntype _S1 = AssertShape<\n VercelReceiverOptions[\"clientId\"],\n HTTPReceiverOptions[\"clientId\"]\n>;\ntype _S2 = AssertShape<\n VercelReceiverOptions[\"clientSecret\"],\n HTTPReceiverOptions[\"clientSecret\"]\n>;\ntype _S3 = AssertShape<\n VercelReceiverOptions[\"stateSecret\"],\n HTTPReceiverOptions[\"stateSecret\"]\n>;\ntype _S4 = AssertShape<\n VercelReceiverOptions[\"scopes\"],\n HTTPReceiverOptions[\"scopes\"]\n>;\ntype _S5 = AssertShape<\n VercelReceiverOptions[\"redirectUri\"],\n HTTPReceiverOptions[\"redirectUri\"]\n>;\ntype _S6 = AssertShape<\n VercelReceiverOptions[\"installationStore\"],\n HTTPReceiverOptions[\"installationStore\"]\n>;\ntype _S7 = AssertShape<\n VercelInstallerOptions[\"stateVerification\"],\n InstallProviderOptions[\"stateVerification\"]\n>;\ntype _S8 = AssertShape<\n VercelInstallerOptions[\"callbackOptions\"],\n CallbackOptions\n>;\ntype _S9 = AssertShape<\n VercelInstallerOptions[\"stateStore\"],\n InstallProviderOptions[\"stateStore\"]\n>;\ntype _S10 = AssertShape<\n VercelInstallerOptions[\"authVersion\"],\n InstallProviderOptions[\"authVersion\"]\n>;\ntype _S11 = AssertShape<\n VercelInstallerOptions[\"userScopes\"],\n InstallURLOptions[\"userScopes\"]\n>;\ntype _S12 = AssertShape<\n VercelInstallerOptions[\"metadata\"],\n InstallURLOptions[\"metadata\"]\n>;\n\nconst LOG_PREFIX = \"[@vercel/slack-bolt]\";\nconst ACK_TIMEOUT_MS = 3001;\nconst SLACK_RETRY_NUM_HEADER = \"x-slack-retry-num\";\nconst SLACK_RETRY_REASON_HEADER = \"x-slack-retry-reason\";\nconst SLACK_TIMESTAMP_HEADER = \"x-slack-request-timestamp\";\nconst SLACK_SIGNATURE_HEADER = \"x-slack-signature\";\n\n/**\n * A Slack Bolt receiver implementation designed for Vercel's serverless environment.\n * Handles Slack events, interactions, and slash commands with automatic request verification,\n * background processing, and timeout management.\n *\n * @example\n * ```typescript\n * import { App } from '@slack/bolt';\n * import { VercelReceiver, createHandler } from '@vercel/slack-bolt';\n *\n * const receiver = new VercelReceiver();\n *\n * const app = new App({\n * receiver,\n * token: process.env.SLACK_BOT_TOKEN,\n * signingSecret: process.env.SLACK_SIGNING_SECRET,\n * });\n * ```\n *\n */\nexport class VercelReceiver implements Receiver {\n private readonly signingSecret: string;\n private readonly signatureVerification: boolean;\n private readonly logger: Logger;\n private readonly customPropertiesExtractor?: (req: Request) => StringIndexed;\n private readonly ackTimeoutMs: number;\n private app?: App;\n\n public installer?: InstallProvider;\n private installUrlOptions?: InstallURLOptions;\n private installCallbackOptions?: CallbackOptions;\n private installPathOptions?: InstallPathOptions;\n private stateVerification?: boolean;\n\n /**\n * Gets the logger instance used by this receiver.\n * @returns The logger instance\n */\n public getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Creates a new VercelReceiver instance.\n *\n * @param options - Configuration options for the receiver\n * @throws {VercelReceiverError} When signing secret is not provided\n *\n * @example\n * ```typescript\n * const receiver = new VercelReceiver();\n * ```\n */\n public constructor({\n signingSecret = process.env.SLACK_SIGNING_SECRET,\n signatureVerification = true,\n logger,\n logLevel = LogLevel.INFO,\n customPropertiesExtractor,\n ackTimeoutMs = ACK_TIMEOUT_MS,\n clientId = process.env.SLACK_CLIENT_ID,\n clientSecret = process.env.SLACK_CLIENT_SECRET,\n stateSecret = process.env.SLACK_STATE_SECRET,\n scopes,\n redirectUri,\n installationStore,\n installerOptions = {},\n }: VercelReceiverOptions = {}) {\n if (!signingSecret) {\n throw new VercelReceiverError(ERROR_MESSAGES.SIGNING_SECRET_REQUIRED);\n }\n\n this.signingSecret = signingSecret;\n this.signatureVerification = signatureVerification;\n this.logger = this.createScopedLogger(\n logger ?? new ConsoleLogger(),\n logLevel,\n );\n this.customPropertiesExtractor = customPropertiesExtractor;\n this.ackTimeoutMs = ackTimeoutMs;\n\n this.stateVerification = installerOptions.stateVerification;\n\n if (\n clientId !== undefined &&\n clientSecret !== undefined &&\n (installerOptions.stateVerification === false ||\n stateSecret !== undefined ||\n installerOptions.stateStore !== undefined)\n ) {\n this.installer = new InstallProvider({\n clientId,\n clientSecret,\n stateSecret,\n installationStore,\n logger,\n logLevel,\n directInstall: installerOptions.directInstall,\n stateStore: installerOptions.stateStore,\n stateVerification: installerOptions.stateVerification,\n legacyStateVerification: installerOptions.legacyStateVerification,\n stateCookieName: installerOptions.stateCookieName,\n stateCookieExpirationSeconds:\n installerOptions.stateCookieExpirationSeconds,\n renderHtmlForInstallPath: installerOptions.renderHtmlForInstallPath,\n authVersion: installerOptions.authVersion ?? \"v2\",\n clientOptions: installerOptions.clientOptions,\n authorizationUrl: installerOptions.authorizationUrl,\n });\n\n this.installUrlOptions = {\n scopes: scopes ?? [],\n userScopes: installerOptions.userScopes,\n metadata: installerOptions.metadata,\n redirectUri,\n };\n this.installCallbackOptions = installerOptions.callbackOptions ?? {};\n this.installPathOptions = installerOptions.installPathOptions ?? {};\n }\n\n this.logger.debug(\"VercelReceiver initialized\");\n }\n\n /**\n * Initializes the receiver with a Slack Bolt app instance.\n * This method is called automatically by the Bolt framework.\n *\n * @param app - The Slack Bolt app instance\n */\n public init(app: App): void {\n this.app = app;\n this.logger.debug(\"App initialized in VercelReceiver\");\n }\n\n /**\n * Starts the receiver and returns a handler function for processing requests.\n * This method is called automatically by the Bolt framework.\n *\n * @returns A handler function that processes incoming Slack requests\n */\n public async start(): Promise<VercelHandler> {\n this.logger.debug(\"VercelReceiver started\");\n return this.toHandler();\n }\n\n /**\n * Stops the receiver. This method is called automatically by the Bolt framework.\n */\n public async stop(): Promise<void> {\n this.logger.debug(\"VercelReceiver stopped\");\n }\n\n /**\n * Handles requests to the OAuth install path.\n * Renders an \"Add to Slack\" page or redirects directly to Slack's authorize URL.\n */\n public handleInstall = async (req: Request): Promise<Response> => {\n if (!this.installer) {\n throw new VercelReceiverError(ERROR_MESSAGES.OAUTH_NOT_CONFIGURED);\n }\n\n const nodeReq = toIncomingMessage(req);\n const capture = createResponseCapture();\n\n await this.installer.handleInstallPath(\n nodeReq,\n capture,\n this.installPathOptions,\n this.installUrlOptions,\n );\n\n return capture.toResponse();\n };\n\n /**\n * Handles the OAuth redirect callback from Slack.\n * Exchanges the authorization code for tokens and stores the installation.\n */\n public handleCallback = async (req: Request): Promise<Response> => {\n if (!this.installer) {\n throw new VercelReceiverError(ERROR_MESSAGES.OAUTH_NOT_CONFIGURED);\n }\n\n const nodeReq = toIncomingMessage(req);\n const capture = createResponseCapture();\n\n if (this.stateVerification === false) {\n await this.installer.handleCallback(\n nodeReq,\n capture,\n this.installCallbackOptions,\n this.installUrlOptions,\n );\n } else {\n await this.installer.handleCallback(\n nodeReq,\n capture,\n this.installCallbackOptions,\n );\n }\n\n return capture.toResponse();\n };\n\n /**\n * Creates a handler function that processes incoming Slack requests.\n * This is the main entry point for handling Slack events in Vercel.\n * It is called automatically by the Bolt framework in the start() method.\n *\n * @returns A handler function compatible with Vercel's function signature\n */\n public toHandler(): VercelHandler {\n return async (req: Request): Promise<Response> => {\n try {\n const rawBody = await req.text();\n\n if (this.signatureVerification) {\n this.verifyRequest(req, rawBody);\n }\n\n const body = await this.parseRequestBody(req, rawBody);\n\n if (body.type === \"url_verification\") {\n this.logger.debug(\"Handling URL verification challenge\");\n return Response.json({ challenge: body.challenge });\n }\n\n return await this.handleSlackEvent(req, body);\n } catch (error) {\n return this.handleError(error);\n }\n };\n }\n\n private async parseRequestBody(\n req: Request,\n rawBody: string,\n ): Promise<StringIndexed> {\n const contentType = req.headers.get(\"content-type\");\n\n try {\n if (contentType === \"application/x-www-form-urlencoded\") {\n const parsedBody: StringIndexed = {};\n const params = new URLSearchParams(rawBody);\n\n for (const [key, value] of params.entries()) {\n parsedBody[key] = value;\n }\n\n if (typeof parsedBody.payload === \"string\") {\n return JSON.parse(parsedBody.payload);\n }\n return parsedBody;\n }\n if (contentType === \"application/json\") {\n return JSON.parse(rawBody);\n }\n\n this.logger.warn(`Unexpected content-type detected: ${contentType}`);\n\n return JSON.parse(rawBody);\n } catch (e) {\n throw new RequestParsingError(\n `Failed to parse body as JSON data for content-type: ${contentType}. Error: ${\n e instanceof Error ? e.message : String(e)\n }`,\n );\n }\n }\n\n private async handleSlackEvent(\n req: Request,\n body: StringIndexed,\n ): Promise<Response> {\n if (!this.app) {\n throw new VercelReceiverError(ERROR_MESSAGES.APP_NOT_INITIALIZED, 500);\n }\n\n let isAcknowledged = false;\n let responseResolver: (value: Response) => void;\n let responseRejecter: (error: Error) => void;\n\n const responsePromise = new Promise<Response>((resolve, reject) => {\n responseResolver = resolve;\n responseRejecter = reject;\n });\n\n // Slack requires an acknowledgment from your app within 3 seconds\n const timeoutId = setTimeout(() => {\n if (!isAcknowledged) {\n isAcknowledged = true;\n this.logger.error(ERROR_MESSAGES.EVENT_NOT_ACKNOWLEDGED);\n const error = new VercelReceiverError(\n ERROR_MESSAGES.REQUEST_TIMEOUT,\n 408,\n );\n responseRejecter(error);\n }\n }, this.ackTimeoutMs);\n\n // Create acknowledgment function\n const ackFn: AckFn<StringIndexed> = async (responseBody) => {\n this.logger.debug(`ack() call begins (body: ${responseBody})`);\n if (isAcknowledged) {\n throw new ReceiverMultipleAckError();\n }\n\n isAcknowledged = true;\n clearTimeout(timeoutId);\n\n try {\n let body: string | undefined;\n if (typeof responseBody === \"undefined\") {\n body = undefined;\n } else if (typeof responseBody === \"string\") {\n body = responseBody;\n } else {\n body = JSON.stringify(responseBody);\n }\n const response = new Response(body, {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n\n responseResolver(response);\n } catch (error) {\n this.logger.error(ERROR_MESSAGES.ACKNOWLEDGMENT_ERROR, error);\n responseRejecter(\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n };\n\n const event = this.createSlackReceiverEvent({\n body,\n headers: req.headers,\n ack: ackFn,\n request: req,\n });\n\n // Process event in background using waitUntil from Vercel Functions\n // https://vercel.com/docs/functions/functions-api-reference/vercel-functions-package#waituntil\n waitUntil(\n this.app.processEvent(event).catch((error) => {\n return this.handleError(error);\n }),\n );\n\n try {\n return await responsePromise;\n } catch (error) {\n return this.handleError(error);\n }\n }\n\n private verifyRequest(req: Request, body: string): void {\n const timestamp = req.headers.get(SLACK_TIMESTAMP_HEADER);\n const signature = req.headers.get(SLACK_SIGNATURE_HEADER);\n\n if (!signature) {\n throw new ReceiverAuthenticityError(\n ERROR_MESSAGES.MISSING_REQUIRED_HEADER(SLACK_SIGNATURE_HEADER),\n );\n }\n\n if (!timestamp) {\n throw new ReceiverAuthenticityError(\n ERROR_MESSAGES.MISSING_REQUIRED_HEADER(SLACK_TIMESTAMP_HEADER),\n );\n }\n\n try {\n verifySlackRequest({\n signingSecret: this.signingSecret,\n body,\n headers: {\n \"x-slack-signature\": signature,\n \"x-slack-request-timestamp\": Number.parseInt(timestamp, 10),\n },\n logger: this.logger,\n });\n } catch (error) {\n throw new ReceiverAuthenticityError(\n error instanceof Error\n ? error.message\n : \"Failed to verify request signature\",\n );\n }\n }\n\n private createSlackReceiverEvent({\n body,\n headers,\n ack,\n request,\n }: {\n body: StringIndexed;\n headers: Headers;\n ack: AckFn<StringIndexed>;\n request: Request;\n }): ReceiverEvent {\n const customProperties = this.customPropertiesExtractor\n ? this.customPropertiesExtractor(request)\n : {};\n\n const retryNum = headers.get(SLACK_RETRY_NUM_HEADER) || \"0\";\n\n const retryReason = headers.get(SLACK_RETRY_REASON_HEADER) || \"\";\n\n return {\n body,\n ack,\n retryNum: Number(retryNum),\n retryReason,\n customProperties,\n };\n }\n\n public handleError(error: unknown): Response {\n const errorMessage = getErrorMessage(error);\n const errorType = getErrorType(error);\n const errorStatusCode = getStatusCode(error);\n\n this.logger.error(error);\n return new Response(\n JSON.stringify({\n error: errorMessage,\n type: errorType,\n }),\n {\n status: errorStatusCode,\n headers: { \"content-type\": \"application/json\" },\n },\n );\n }\n\n private createScopedLogger(logger: Logger, logLevel: LogLevel): Logger {\n logger.setLevel(logLevel);\n\n return {\n ...logger,\n error: (...args) => logger.error?.(LOG_PREFIX, ...args),\n warn: (...args) => logger.warn?.(LOG_PREFIX, ...args),\n info: (...args) => logger.info?.(LOG_PREFIX, ...args),\n debug: (...args) => logger.debug?.(LOG_PREFIX, ...args),\n setLevel: logger.setLevel,\n getLevel: logger.getLevel,\n };\n }\n}\n\n/**\n * Creates a Vercel-compatible handler function for a Slack Bolt app.\n * This is the recommended way to create handlers for deployment on Vercel.\n *\n * @param {App} app - The initialized Slack Bolt app instance.\n * @param {VercelReceiver} receiver - The VercelReceiver instance.\n * @returns {VercelHandler} A handler function compatible with Vercel's function signature.\n *\n * @example\n * ```typescript\n * // api/events.ts\n * import { createHandler } from '@vercel/slack-bolt';\n * import { app, receiver } from '../app';\n *\n * const handler = createHandler(app, receiver);\n *\n * export const POST = async (req: Request) => {\n * return handler(req);\n * };\n * ```\n *\n * @throws {Error} If app initialization fails.\n * @throws {VercelReceiverError} If request processing fails.\n */\nexport function createHandler(\n app: App,\n receiver: VercelReceiver,\n): VercelHandler {\n let initPromise: Promise<void> | null = null;\n\n return async (req: Request) => {\n try {\n if (!initPromise) {\n initPromise = app.init().catch((error) => {\n // Reset initPromise so subsequent requests can retry initialization\n initPromise = null;\n throw error;\n });\n }\n await initPromise;\n\n receiver.init(app);\n const handler = await receiver.start();\n return handler(req);\n } catch (error) {\n // if app.init fails, we use console.error instead of logger.error because the logger is not available\n console.error(ERROR_MESSAGES.CREATE_HANDLER_ERROR, error);\n return new Response(\n JSON.stringify({\n error: ERROR_MESSAGES.INTERNAL_SERVER_ERROR_HANDLER,\n type: ERROR_MESSAGES.TYPES.HANDLER_ERROR,\n }),\n { status: 500, headers: { \"content-type\": \"application/json\" } },\n );\n }\n };\n}\n"]}