-
Notifications
You must be signed in to change notification settings - Fork 379
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
Add support for remote functions #2026
base: main
Are you sure you want to change the base?
Conversation
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.
This is awesome 💯 first pass everything looks good! I left some comments on naming alignment
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.
Looking good!
One higher-level API that bolt needs to consider (and that the deno SDK does not) is token selection when creating the helper API client and other convenience utility functions like say
. Some bolt apps implement OAuth and ask for user scopes, so a user token may come into play. While the function complete/fail helpers should always use the JIT / workflow / function-execution-specific token, that is not so clear for say
or for the general API client
available in certain event handlers. We need to think about how to expose the option of which token to use in these situations.
src/WorkflowFunction.ts
Outdated
|
||
function selectToken(context: Context): string | undefined { | ||
// If attachFunctionToken = false, fallback to botToken or userToken | ||
return context.functionBotToken ? context.functionBotToken : context.botToken || context.userToken; |
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.
To @WilliamBergamin's earlier point, this area may need to be exposed as an API to the dev. Here we are making an assumption that for non-function-scoped events, the dev will want to use a bot token over a user token - that will not always be the case.
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.
This is how WorkflowStep
was implemented, so merely a carry over. That was long ago, but is there a reality where an app has both present -- a bot token and a user token? In my mind, I've always thought of it as one or the other (either it's a bot, or an app acting on behalf of the user), but you bringing this up makes me think that's a faulty mental model.
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.
Yes, an app can ask for scopes of both types (if you head to the OAuth & Permissions app config page, you can subscribe to both).
Just this week I was helping someone who was using a user token for one API (uploading files) but a bot token in another (posting a message containing the uploaded file).
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.
So, for any event that currently comes in, when we run selectToken
when that event is processed, we opt for botToken
first, followed by userToken
. I think it's always been this way, or has for the last 4+ years.
@seratch your name is attached to one of those implementation lines. Can you advise here?
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.
I've always found this area to be poorly documented on our part and glossed over. For example bolt-js only mentions user scopes if you REALLY dig deep: you gotta scroll to the end of the OAuth docs, expand the hidden "Customizing OAuth options" section and then piece together the pieces based on the example and the one-line description of the userScopes
field.
I believe, but may be wrong on this, that this has always been a userland concern that we don't provide guidance on. Like, for an app that is installable on-demand to workspace (implements OAuth) and collects both bot and user tokens, I'm pretty sure it is up to the installation store implementation (so userland code) to both: figure out which token to store as well as which token to select and return when doing the 'authorization' process that bolt exposes APIs for.
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.
Sorry, I overlooked this thread last week. The logic to select a primary token for context object from bot / user tokens is by design from the beginning, and all Bolt frameworks align.
We basically encourage developers to have a bot token, but technically it still should be allowed to go with only a user token (I don't think this is a common use case though). Thus, when a bot token is missing, setting a user token instead is a reassonable design for supporting such a scenario.
I don't think bolt should expose a way to customize this because:
- we've never received such feature request in the last few years because most apps have their bot token
- developers still can accesss both a bot and user token
As for the documentation topic, indeed this could be improved in the advanced topic section although the number of devs who need it is not so large.
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.
OK good to know and thanks for that context Kaz 🙇
If Kaz says so then I defer to his suggestion / feel free to ignore my point
c63f1f4
to
1b79873
Compare
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #2026 +/- ##
==========================================
- Coverage 81.97% 81.40% -0.58%
==========================================
Files 18 19 +1
Lines 1531 1613 +82
Branches 440 456 +16
==========================================
+ Hits 1255 1313 +58
- Misses 178 193 +15
- Partials 98 107 +9 ☔ View full report in Codecov by Sentry. |
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
|
||
// Making calls with a functionBotAccessToken establishes continuity between | ||
// a function_executed event and subsequent interactive events (actions) | ||
const client = new WebClient(token, { ...functionArgs.client }); |
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.
This is the first time to see this way to initialize a new instance. Other code in bolt-js uses clientOptions for the second argument instead. I haven't verified on my end yet but have you confirmed this code can make the same effect with new WebClient(token, clientOptions)
?
@@ -425,6 +426,42 @@ export interface FileUnsharedEvent { | |||
event_ts: string; | |||
} | |||
|
|||
export interface FunctionParams { |
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.
FYI: here is my investigation result: https://github.com/seratch/slack-edge/blob/0.10.1/src/request/payload/event.ts#L420-L427
type, name, is_required cannot be optional for sure.
There are a few more optional ones such as maximum, minimum, maxLength, and minLength. But you don't need to cover all the things this time.
id: string; | ||
callback_id: string; | ||
title: string; | ||
description: string; |
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.
description: string; | |
description?: string; |
Summary
This PR adds support for remote (i.e., remotely hosted) functions for use in Workflow Builder.
What's New
A shiny new listener:
.function()
Support of remote functions brings a new
.function()
listener that featurescomplete
andfail
utilities to quickly and easily signal if the function has successfully executed or not.Function-specific interactivity support
We've beefed up the existing
action
listener to automatically determine if the action/interactivity event being received is associated with a function. If so, the callback will make available thecomplete
andfail
utility functions. Note: this requires that the interactivity call was made with the incoming JIT token. See below for details.Automatic use of JIT token (with opt-out option)
When a function-related event is received, a JIT token is included in the payload. The subsequent use of this token when making API calls is what allows for interactivity to be associated with that function (and eventually see the function through to
complete
orfail
). Out of respect for all of our developers and their individual setups, we've provided an easy way to opt-out of this JIT token attachment with theattachFunctionToken
property inAppOptions
.Outstanding / To Do
complete
/fail
utility logic (App.ts
/WorkflowFunction.ts
)Requirements (place an
x
in each[ ]
)