-
Notifications
You must be signed in to change notification settings - Fork 393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bolt v4 #2254
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2254 +/- ##
===========================================
+ Coverage 81.21% 92.47% +11.26%
===========================================
Files 21 36 +15
Lines 1799 7453 +5654
Branches 498 646 +148
===========================================
+ Hits 1461 6892 +5431
- Misses 218 553 +335
+ Partials 120 8 -112 ☔ View full report in Codecov by Sentry. |
// Filter out any non-actions | ||
if (action === undefined) { | ||
return; | ||
export const onlyActions: Middleware<AnyMiddlewareArgs> = async (args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Breaking change: no longer need to call this as onlyActions()
, instead, it is a middleware itself and can be simply passed as onlyActions
. The wrapping closure within was unnecessary. This lines it up with other, non-parameterized middleware in this module.
if (action === undefined) { | ||
return; | ||
export const onlyActions: Middleware<AnyMiddlewareArgs> = async (args) => { | ||
if ('action' in args && args.action) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of casting, in TS we should be using more of 'property' in object
style checks and let TS do the type narrowing for us.
// Filter out any non-shortcuts | ||
if (shortcut === undefined) { | ||
return; | ||
export const onlyShortcuts: Middleware<AnyMiddlewareArgs> = async (args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another breaking change: this is a middleware, no need for extra internal closure.
// Filter out any non-commands | ||
if (command === undefined) { | ||
return; | ||
export const onlyCommands: Middleware<AnyMiddlewareArgs> = async (args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same deal! This is middleware, remove internal closure.
// Filter out any non-options requests | ||
if (options === undefined) { | ||
return; | ||
export const onlyOptions: Middleware<AnyMiddlewareArgs> = async (args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken record: middleware, remove internal closure.
// Filter out any non-events | ||
if (event === undefined) { | ||
return; | ||
export const onlyEvents: Middleware<AnyMiddlewareArgs> = async (args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You guessed it: middleware, 🔪 closure
// Filter out anything that doesn't have a view | ||
if (view === undefined) { | ||
return; | ||
export const onlyViewActions: Middleware<AnyMiddlewareArgs> = async (args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Samesame
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 🧠 Big fan of it all!
return; | ||
} | ||
} | ||
export const ignoreSelf: Middleware<AnyMiddlewareArgs> = async (args) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same: 🔪 internal closure since we don't use any of the outer function's parameters.
if (isMessageEventArgs(args)) { | ||
const { message } = args; | ||
// Look for an event that is identified as a bot message from the same bot ID as this app, and return to skip | ||
if (message.subtype === 'bot_message' && message.bot_id === botId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The combination of cleaning up the middleware types and use of type predicates lets us clean up the type casting and simplify the logic in this method ❤️
| GlobalShortcut | ||
| InteractiveMessageSuggestion | ||
| DialogSuggestion; | ||
export const directMention: Middleware<SlackEventMiddlewareArgs<'message'>> = async ({ message, context, next }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔪 closure, straight middleware
@@ -529,7 +529,7 @@ describe('ExpressReceiver', function () { | |||
// Act | |||
const req = { body: { }, url: 'http://localhost/slack/oauth_redirect', method: 'GET' } as Request; | |||
const resp = { send: () => { } } as Response; | |||
(receiver.router as any).handle(req, resp); | |||
(receiver.router as any).handle(req, resp, () => {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A change that was required as part of the move from express v4 -> v5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work; Left a few comments!
…e invoked as a method to return middleware; instead, they are directly middleware, like other built-in middleware functions.
…e `message` parameter. THIS FIXES SO MUCH! shouts to jcalz on stackoverflow
…ntMiddlewareArgs when event contains channel information.
…ionMiddlewareArgs when a non-dialog or step from app action
…rtcutMiddlewareArgs when a non-dialog or step from app action. also TODOs
… flat map of strings to strings
…inder removal todos for eventual removal
Summary
bolt-js v4 release PR. Breaking changes are planned for this release!
This PR is currently published under the
4.0.0-rc.4
version on npm. Feel free to give it a spin and give us feedback!Breaking Changes
Middleware Type Changes
This one I'm particularly excited about! In bolt we have a set of
Slack*MiddlewareArgs
types: for events, shortcuts, commands, and so on. They 'wrap' the underlying event payloads with additional middleware-relevant bits like anext()
method, acontext
object for devs to augment, and so on.Many of these types, for example the
SlackEventMiddlewareArgs
type, previously used a conditional to sometimes define particular additional helper utilities on the middleware arguments. For example, thesay
utility, or tacking on a conveniencemessage
property for message-event-related payloads. This was problematic in practice in TypeScript situations, not just internally (this change fixes #2135) within the bolt codebase but for developers as well: when the payload was not of a type that required the extra utility, these properties would be required to exist on the middleware arguments but have a value ofundefined
. Those of us trying to build generic middleware utilities would have to deal with TS compilation errors and needing to liberally type-cast to avoid these conditional mismatches withundefined
.Instead, these
MiddlewareArgs
types now conditionally create a type intersection when appropriate in order to provide this conditional-utility-extension mechanism. In practice that looks something like:With the above, now when a message payload is wrapped up into middleware arguments, it will contain an appropriate
message
property, whereas a non-message payload will be intersected withunknown
- effectively a type "noop." No more e.g.say: undefined
ormessage: undefined
to deal with!Other Breaking Changes
express
to v4->v5;ExpressReceiver
users will be exposed to express v4 -> v5 breaking changes@slack/socket-mode
v2;SocketModeReceiver
users who have attached custom event listeners to the publicsocketModeClient
directly should read the v1 -> v2 migration guide in case the major upgrade could affect them@slack/web-api
v7; all users should read the web-api v6->v7 migration guide to see what the scope of breaking changes theclient
within listeners is affected byKnownKeys
@slack/types
now exist under a named exporttypes
.SocketModeFunctions
class that had a single static method on it and instead directly exposed thedefaultProcessEventErrorHandler
method from it.ignoreSelf
anddirectMention
now no longer must be invoked as a method in order to return middleware; instead they are middleware to be used directly. this lines up the API for these built-in middlewares to match the other builtins.AwsEvent
interface now models event payloads a bit differently; we now properly model AWS API Gateway v1 and v2 payloads separately.OptionsRequest
interfaceauthed_users
andauthed_teams
from event payload enveloperender-html-for-install-path
moduleverify
andVerifyOptions
from theverify-request
modulesrc/receivers/http-utils.ts
moduleNon-breaking Changes
tsconfig.json
switch
statements, removed that fromtsconfig.json
; the alternative of using@ts-ignore
comments in places where we do is dangerous, as non-fallthrough-in-switch type errors are also ignored from itmap
)processEvent
@slack/web-api
dependency under thewebApi
named exportraw-body
to v3@slack/oauth
to v3promise.allsettled
since that is natively supported in node since v14@types/tsscmp
to dev dependencies since that is not exposed to developersTODO
Post-release TODO