diff --git a/src/App.spec.ts b/src/App.spec.ts index aee109e35..f69b27e27 100644 --- a/src/App.spec.ts +++ b/src/App.spec.ts @@ -14,7 +14,7 @@ import { WebClientOptions, WebClient } from '@slack/web-api'; // TODO: swap out rewiremock for proxyquire to see if it saves execution time // Utility functions const noop = (() => Promise.resolve(undefined)); -const noopMiddleware = async ({ next }: { next: NextFn; }) => { await next!(); }; +const noopMiddleware = async ({ next }: { next: NextFn; }) => { await next(); }; const noopAuthorize = (() => Promise.resolve({})); // Dummies (values that have no real behavior but pass through the system opaquely) @@ -347,8 +347,8 @@ describe('App', () => { // Arrange app.use(fakeFirstMiddleware); app.use(async ({ next }) => { - await next!(); - await next!(); + await next(); + await next(); }); app.use(fakeSecondMiddleware); app.error(fakeErrorHandler); @@ -367,7 +367,7 @@ describe('App', () => { await delay(100); changed = true; - await next!(); + await next(); }); await fakeReceiver.sendEvent(dummyReceiverEvent); @@ -381,7 +381,7 @@ describe('App', () => { app.use(async ({ next }) => { try { - await next!(); + await next(); } catch (err) { caughtError = err; } @@ -713,7 +713,7 @@ describe('App', () => { app.use(async ({ next }) => { await ackFn(); - await next!(); + await next(); }); app.shortcut({ callback_id: 'message_action_callback_id' }, async ({ }) => { await shortcutFn(); }); app.shortcut( @@ -857,7 +857,7 @@ describe('App', () => { }); app.use(async ({ logger, body, next }) => { logger.info(body); - await next!(); + await next(); }); app.event('app_home_opened', async ({ logger, event }) => { @@ -905,7 +905,7 @@ describe('App', () => { }); app.use(async ({ logger, body, next }) => { logger.info(body); - await next!(); + await next(); }); app.event('app_home_opened', async ({ logger, event }) => { @@ -971,7 +971,7 @@ describe('App', () => { }); app.use(async ({ client, next }) => { await client.auth.test(); - await next!(); + await next(); }); const clients: WebClient[] = []; app.event('app_home_opened', async ({ client }) => { diff --git a/src/App.ts b/src/App.ts index c299e2e1e..7377f5e75 100644 --- a/src/App.ts +++ b/src/App.ts @@ -49,6 +49,7 @@ import { RespondArguments, } from './types'; import { IncomingEventType, getTypeAndConversation, assertNever } from './helpers'; +import { NonListenerMiddlewareArgs, NonListenerMiddleware } from './types/middleware'; import { CodedError, asCodedError, @@ -275,8 +276,18 @@ export default class App { * * @param m global middleware function */ - public use(m: Middleware): this { - this.middleware.push(m); + public use(m: NonListenerMiddleware): this { + const middleware: Middleware = (args) => { + const _args: NonListenerMiddlewareArgs = { + context: args.context, + logger: args.logger, + client: args.client, + next: args.next!, + ...args, + }; + return m(_args); + }; + this.middleware.push(middleware); return this; } diff --git a/src/conversation-store.ts b/src/conversation-store.ts index 0a1454f26..ec17d80fd 100644 --- a/src/conversation-store.ts +++ b/src/conversation-store.ts @@ -1,6 +1,7 @@ -import { Middleware, AnyMiddlewareArgs } from './types'; +import { Middleware } from './types'; import { Logger } from '@slack/logger'; import { getTypeAndConversation } from './helpers'; +import { NonListenerMiddlewareArgs } from './types/middleware'; /** * Storage backend used by the conversation context middleware @@ -54,7 +55,7 @@ export class MemoryStore implements ConversationStore( store: ConversationStore, logger: Logger, -): Middleware { +): Middleware { return async (args) => { const { body, context, next } = args; const { conversationId } = getTypeAndConversation(body as any); @@ -74,7 +75,7 @@ export function conversationContext( } else { logger.debug('No conversation ID for incoming event'); // TODO: remove the non-null assertion operator - await next!(); + await next(); } }; } diff --git a/src/middleware/builtin.ts b/src/middleware/builtin.ts index 655ffa7c3..d0f5426ff 100644 --- a/src/middleware/builtin.ts +++ b/src/middleware/builtin.ts @@ -23,6 +23,7 @@ import { } from '../types'; import { ActionConstraints, ViewConstraints, ShortcutConstraints } from '../App'; import { ContextMissingPropertyError } from '../errors'; +import { NonListenerMiddlewareArgs } from '../types/middleware'; /** * Middleware that filters out any event that isn't an action @@ -263,7 +264,7 @@ export function matchEventType(type: string): Middleware { +export function ignoreSelf(): Middleware { return async (args) => { // When context does not have a botId in it, then this middleware cannot perform its job. Bail immediately. if (args.context.botId === undefined) { @@ -384,7 +385,7 @@ function isViewBody( } function isEventArgs( - args: AnyMiddlewareArgs, -): args is SlackEventMiddlewareArgs { + args: NonListenerMiddlewareArgs, +): args is NonListenerMiddlewareArgs & SlackEventMiddlewareArgs { return (args as SlackEventMiddlewareArgs).event !== undefined; } diff --git a/src/types/middleware.ts b/src/types/middleware.ts index 373f5e227..9f68c190c 100644 --- a/src/types/middleware.ts +++ b/src/types/middleware.ts @@ -27,6 +27,20 @@ export interface Middleware { (args: Args & AllMiddlewareArgs): Promise; } +interface NextForSure { + body: any; + context: Context; + logger: Logger; + client: WebClient; + next: NextFn; +} + +export type NonListenerMiddlewareArgs = AnyMiddlewareArgs & NextForSure; + +export interface NonListenerMiddleware { + (args: NonListenerMiddlewareArgs): Promise; +} + export interface Context extends StringIndexed { }