diff --git a/src/App.ts b/src/App.ts index c03c0a14d..d4fd855ba 100644 --- a/src/App.ts +++ b/src/App.ts @@ -2,6 +2,7 @@ import type { Agent } from 'node:http'; import type { SecureContextOptions } from 'node:tls'; import util from 'node:util'; import { ConsoleLogger, LogLevel, type Logger } from '@slack/logger'; +import type { SocketModeOptions } from '@slack/socket-mode'; import { type ChatPostMessageArguments, WebClient, type WebClientOptions, addAppMetadata } from '@slack/web-api'; import axios, { type AxiosInstance, type AxiosResponse } from 'axios'; import type { Assistant } from './Assistant'; @@ -106,43 +107,44 @@ const tokenUsage = /** App initialization options */ export interface AppOptions { - signingSecret?: HTTPReceiverOptions['signingSecret']; - endpoints?: HTTPReceiverOptions['endpoints']; - port?: HTTPReceiverOptions['port']; - customRoutes?: HTTPReceiverOptions['customRoutes']; - processBeforeResponse?: HTTPReceiverOptions['processBeforeResponse']; - signatureVerification?: HTTPReceiverOptions['signatureVerification']; - clientId?: HTTPReceiverOptions['clientId']; - clientSecret?: HTTPReceiverOptions['clientSecret']; - stateSecret?: HTTPReceiverOptions['stateSecret']; // required when using default stateStore - redirectUri?: HTTPReceiverOptions['redirectUri']; - installationStore?: HTTPReceiverOptions['installationStore']; // default MemoryInstallationStore - scopes?: HTTPReceiverOptions['scopes']; - installerOptions?: HTTPReceiverOptions['installerOptions']; agent?: Agent; - clientTls?: Pick; - convoStore?: ConversationStore | false; - token?: AuthorizeResult['botToken']; // either token or authorize appToken?: string; // TODO should this be included in AuthorizeResult + attachFunctionToken?: boolean; + authorize?: Authorize; // either token or authorize botId?: AuthorizeResult['botId']; // only used when authorize is not defined, shortcut for fetching botUserId?: AuthorizeResult['botUserId']; // only used when authorize is not defined, shortcut for fetching - authorize?: Authorize; // either token or authorize - receiver?: Receiver; - logger?: Logger; - logLevel?: LogLevel; - ignoreSelf?: boolean; + clientId?: HTTPReceiverOptions['clientId']; /** * Configurations for the web client used to send Slack API method requests. * * See {@link https://docs.slack.dev/tools/node-slack-sdk/reference/web-api/interfaces/WebClientOptions/} for more information. */ clientOptions?: WebClientOptions; - socketMode?: boolean; - developerMode?: boolean; - tokenVerificationEnabled?: boolean; + clientSecret?: HTTPReceiverOptions['clientSecret']; + clientTls?: Pick; + convoStore?: ConversationStore | false; + customRoutes?: HTTPReceiverOptions['customRoutes']; deferInitialization?: boolean; + developerMode?: boolean; + endpoints?: HTTPReceiverOptions['endpoints']; extendedErrorHandler?: boolean; - attachFunctionToken?: boolean; + ignoreSelf?: boolean; + installationStore?: HTTPReceiverOptions['installationStore']; // default MemoryInstallationStore + installerOptions?: HTTPReceiverOptions['installerOptions']; + logger?: Logger; + logLevel?: LogLevel; + port?: HTTPReceiverOptions['port']; + processBeforeResponse?: HTTPReceiverOptions['processBeforeResponse']; + receiver?: Receiver; + redirectUri?: HTTPReceiverOptions['redirectUri']; + scopes?: HTTPReceiverOptions['scopes']; + socketModeOptions?: Omit; + signatureVerification?: HTTPReceiverOptions['signatureVerification']; + signingSecret?: HTTPReceiverOptions['signingSecret']; + socketMode?: boolean; + stateSecret?: HTTPReceiverOptions['stateSecret']; // required when using default stateStore + token?: AuthorizeResult['botToken']; // either token or authorize + tokenVerificationEnabled?: boolean; } export { LogLevel, Logger } from '@slack/logger'; @@ -275,38 +277,39 @@ export default class App private attachFunctionToken: boolean; public constructor({ - signingSecret = undefined, - endpoints = undefined, - port = undefined, - customRoutes = undefined, + authorize = undefined, agent = undefined, - clientTls = undefined, - receiver = undefined, - convoStore = undefined, - token = undefined, appToken = undefined, + attachFunctionToken = true, botId = undefined, botUserId = undefined, - authorize = undefined, + clientId = undefined, + clientOptions = undefined, + clientSecret = undefined, + clientTls = undefined, + convoStore = undefined, + customRoutes = undefined, + deferInitialization = false, + developerMode = false, + endpoints = undefined, + extendedErrorHandler = false, + ignoreSelf = true, + installationStore = undefined, + installerOptions = undefined, logger = undefined, logLevel = undefined, - ignoreSelf = true, - clientOptions = undefined, processBeforeResponse = false, - signatureVerification = true, - clientId = undefined, - clientSecret = undefined, - stateSecret = undefined, + port = undefined, + receiver = undefined, + token = undefined, redirectUri = undefined, - installationStore = undefined, scopes = undefined, - installerOptions = undefined, + signatureVerification = true, + signingSecret = undefined, socketMode = undefined, - developerMode = false, + socketModeOptions = undefined, + stateSecret = undefined, tokenVerificationEnabled = true, - extendedErrorHandler = false, - deferInitialization = false, - attachFunctionToken = true, }: AppOptions = {}) { /* ------------------------ Developer mode ----------------------------- */ this.developerMode = developerMode; @@ -420,6 +423,7 @@ export default class App scopes, appToken, logger, + socketModeOptions, ); /* ------------------------ Set authorize ----------------------------- */ @@ -1267,6 +1271,7 @@ export default class App scopes?: HTTPReceiverOptions['scopes'], appToken?: string, logger?: Logger, + socketModeOptions?: Omit, ): Receiver { if (receiver !== undefined) { // Custom receiver supplied @@ -1286,14 +1291,15 @@ export default class App appToken, clientId, clientSecret, - stateSecret, - redirectUri, + customRoutes, + installerOptions: this.installerOptions, installationStore, + redirectUri, + ...socketModeOptions, + stateSecret, scopes, logger, logLevel: this.logLevel, - installerOptions: this.installerOptions, - customRoutes, }); } if (signatureVerification === true && signingSecret === undefined) { diff --git a/src/receivers/SocketModeReceiver.ts b/src/receivers/SocketModeReceiver.ts index be586f3b9..0edafe3a3 100644 --- a/src/receivers/SocketModeReceiver.ts +++ b/src/receivers/SocketModeReceiver.ts @@ -28,20 +28,24 @@ import { verifyRedirectOpts } from './verify-redirect-opts'; // TODO: we throw away the key names for endpoints, so maybe we should use this interface. is it better for migrations? // if that's the reason, let's document that with a comment. export interface SocketModeReceiverOptions { - logger?: Logger; - logLevel?: LogLevel; + appToken: string; // App Level Token + autoReconnectEnabled?: boolean; clientId?: string; + clientPingTimeout?: number; clientSecret?: string; - stateSecret?: InstallProviderOptions['stateSecret']; // required when using default stateStore - redirectUri?: string; - installationStore?: InstallProviderOptions['installationStore']; // default MemoryInstallationStore - scopes?: InstallURLOptions['scopes']; - installerOptions?: InstallerOptions; - appToken: string; // App Level Token - customRoutes?: CustomRoute[]; // biome-ignore lint/suspicious/noExplicitAny: user-provided custom properties can be anything customPropertiesExtractor?: (args: any) => StringIndexed; + customRoutes?: CustomRoute[]; + installationStore?: InstallProviderOptions['installationStore']; // default MemoryInstallationStore + installerOptions?: InstallerOptions; + logger?: Logger; + logLevel?: LogLevel; + pingPongLoggingEnabled?: boolean; processEventErrorHandler?: (args: SocketModeReceiverProcessEventErrorHandlerArgs) => Promise; + redirectUri?: string; + scopes?: InstallURLOptions['scopes']; + serverPingTimeout?: number; + stateSecret?: InstallProviderOptions['stateSecret']; // required when using default stateStore } export interface CustomRoute { @@ -94,24 +98,32 @@ export default class SocketModeReceiver implements Receiver { public constructor({ appToken, - logger = undefined, - logLevel = LogLevel.INFO, + autoReconnectEnabled = false, clientId = undefined, + clientPingTimeout = undefined, clientSecret = undefined, - stateSecret = undefined, - redirectUri = undefined, - installationStore = undefined, - scopes = undefined, - installerOptions = {}, - customRoutes = [], customPropertiesExtractor = (_args) => ({}), + customRoutes = [], + installerOptions = {}, + installationStore = undefined, + logger = undefined, + logLevel = LogLevel.INFO, + pingPongLoggingEnabled = false, processEventErrorHandler = defaultProcessEventErrorHandler, + redirectUri = undefined, + scopes = undefined, + serverPingTimeout = undefined, + stateSecret = undefined, }: SocketModeReceiverOptions) { this.client = new SocketModeClient({ appToken, - logLevel, - logger, + autoReconnectEnabled, clientOptions: installerOptions.clientOptions, + clientPingTimeout, + logger, + logLevel, + pingPongLoggingEnabled, + serverPingTimeout, }); this.logger =