Skip to content

Commit f7966e7

Browse files
committed
Fixes and polish for stable release
1 parent 87730ef commit f7966e7

File tree

6 files changed

+62
-13
lines changed

6 files changed

+62
-13
lines changed

src/App.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import {
5454
SlashCommand,
5555
WorkflowStepEdit,
5656
SlackOptions,
57+
FunctionInputs,
5758
} from './types';
5859
import { IncomingEventType, getTypeAndConversation, assertNever, isBodyWithTypeEnterpriseInstall, isEventTypeToSkipAuthorize } from './helpers';
5960
import { CodedError, asCodedError, AppInitializationError, MultipleListenerError, ErrorCode, InvalidCustomPropertyError } from './errors';
@@ -964,9 +965,12 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
964965
retryReason: event.retryReason,
965966
};
966967

967-
// Extract function-related information and augment to context
968-
const { functionExecutionId, functionBotAccessToken } = extractFunctionContext(body);
969-
if (functionExecutionId) { context.functionExecutionId = functionExecutionId; }
968+
// Extract function-related information and augment context
969+
const { functionExecutionId, functionBotAccessToken, functionInputs } = extractFunctionContext(body);
970+
if (functionExecutionId) {
971+
context.functionExecutionId = functionExecutionId;
972+
if (functionInputs) { context.functionInputs = functionInputs; }
973+
}
970974

971975
if (this.attachFunctionToken) {
972976
if (functionBotAccessToken) { context.functionBotAccessToken = functionBotAccessToken; }
@@ -1029,6 +1033,7 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
10291033
ack?: AckFn<any>;
10301034
complete?: FunctionCompleteFn;
10311035
fail?: FunctionFailFn;
1036+
inputs?: FunctionInputs;
10321037
} = {
10331038
body: bodyArg,
10341039
payload,
@@ -1088,6 +1093,7 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
10881093
if (type === IncomingEventType.Action && context.functionExecutionId !== undefined) {
10891094
listenerArgs.complete = CustomFunction.createFunctionComplete(context, client);
10901095
listenerArgs.fail = CustomFunction.createFunctionFail(context, client);
1096+
listenerArgs.inputs = context.functionInputs;
10911097
}
10921098

10931099
if (token !== undefined) {
@@ -1599,6 +1605,7 @@ function escapeHtml(input: string | undefined | null): string {
15991605
function extractFunctionContext(body: StringIndexed) {
16001606
let functionExecutionId;
16011607
let functionBotAccessToken;
1608+
let functionInputs;
16021609

16031610
// function_executed event
16041611
if (body.event && body.event.type === 'function_executed' && body.event.function_execution_id) {
@@ -1610,9 +1617,10 @@ function extractFunctionContext(body: StringIndexed) {
16101617
if (body.function_data) {
16111618
functionExecutionId = body.function_data.execution_id;
16121619
functionBotAccessToken = body.bot_access_token;
1620+
functionInputs = body.function_data.inputs;
16131621
}
16141622

1615-
return { functionExecutionId, functionBotAccessToken };
1623+
return { functionExecutionId, functionBotAccessToken, functionInputs };
16161624
}
16171625

16181626
// ----------------------------

src/CustomFunction.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ describe('CustomFunction class', () => {
6565
assert(fakeNext.called);
6666
});
6767

68-
it('should call next if not a workflow step event', async () => {
68+
it('should call next if not a function executed event', async () => {
6969
const fn = new CustomFunction('test_view_callback_id', MOCK_MIDDLEWARE_SINGLE);
7070
const middleware = fn.getMiddleware();
7171
const fakeViewArgs = createFakeViewEvent() as unknown as
@@ -215,6 +215,7 @@ function createFakeFunctionExecutedEvent() {
215215
},
216216
context: {
217217
functionBotAccessToken: 'xwfp-123',
218+
functionExecutionId: 'test_executed_callback_id',
218219
},
219220
};
220221
}

src/CustomFunction.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
FunctionExecutedEvent,
1414
} from './types';
1515
import processMiddleware from './middleware/process';
16-
import { CustomFunctionInitializationError } from './errors';
16+
import { CustomFunctionCompleteFailError, CustomFunctionCompleteSuccessError, CustomFunctionInitializationError } from './errors';
1717

1818
/** Interfaces */
1919

@@ -105,6 +105,11 @@ export class CustomFunction {
105105
const token = selectToken(context);
106106
const { functionExecutionId } = context;
107107

108+
if (!functionExecutionId) {
109+
const errorMsg = 'No function_execution_id found';
110+
throw new CustomFunctionCompleteSuccessError(errorMsg);
111+
}
112+
108113
return (params: Parameters<FunctionCompleteFn>[0] = {}) => client.functions.completeSuccess({
109114
token,
110115
outputs: params.outputs || {},
@@ -123,6 +128,11 @@ export class CustomFunction {
123128
const { error } = params ?? {};
124129
const { functionExecutionId } = context;
125130

131+
if (!functionExecutionId) {
132+
const errorMsg = 'No function_execution_id found';
133+
throw new CustomFunctionCompleteFailError(errorMsg);
134+
}
135+
126136
return client.functions.completeError({
127137
token,
128138
error,
@@ -158,8 +168,8 @@ export function validate(callbackId: string, middleware: CustomFunctionExecuteMi
158168
}
159169

160170
/**
161-
* `processFunctionMiddleware()` invokes each callback for lifecycle event
162-
* @param args workflow_step_edit action
171+
* `processFunctionMiddleware()` invokes each listener middleware
172+
* @param args function_executed event
163173
*/
164174
export async function processFunctionMiddleware(
165175
args: AllCustomFunctionMiddlewareArgs,

src/errors.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export enum ErrorCode {
4141
WorkflowStepInitializationError = 'slack_bolt_workflow_step_initialization_error',
4242

4343
CustomFunctionInitializationError = 'slack_bolt_custom_function_initialization_error',
44+
CustomFunctionCompleteSuccessError = 'slack_bolt_custom_function_complete_success_error',
45+
CustomFunctionCompleteFailError = 'slack_bolt_custom_function_complete_fail_error',
4446
}
4547

4648
export class UnknownError extends Error implements CodedError {
@@ -149,3 +151,11 @@ export class WorkflowStepInitializationError extends Error implements CodedError
149151
export class CustomFunctionInitializationError extends Error implements CodedError {
150152
public code = ErrorCode.CustomFunctionInitializationError;
151153
}
154+
155+
export class CustomFunctionCompleteSuccessError extends Error implements CodedError {
156+
public code = ErrorCode.CustomFunctionCompleteSuccessError;
157+
}
158+
159+
export class CustomFunctionCompleteFailError extends Error implements CodedError {
160+
public code = ErrorCode.CustomFunctionCompleteFailError;
161+
}

src/types/events/base-events.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,11 +432,11 @@ export interface FileUnsharedEvent {
432432
}
433433

434434
export interface FunctionParams {
435-
type?: string;
436-
name?: string;
435+
type: string;
436+
name: string;
437437
description?: string;
438438
title?: string;
439-
is_required?: boolean;
439+
is_required: boolean;
440440
}
441441

442442
export interface FunctionInputs {
@@ -451,7 +451,7 @@ export interface FunctionExecutedEvent {
451451
id: string;
452452
callback_id: string;
453453
title: string;
454-
description: string;
454+
description?: string;
455455
type: string;
456456
input_parameters: FunctionParams[];
457457
output_parameters: FunctionParams[];

src/types/middleware.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { WebClient } from '@slack/web-api';
22
import { Logger } from '@slack/logger';
33
import { StringIndexed } from './helpers';
4-
import { SlackEventMiddlewareArgs } from './events';
4+
import { FunctionInputs, SlackEventMiddlewareArgs } from './events';
55
import { SlackActionMiddlewareArgs } from './actions';
66
import { SlackCommandMiddlewareArgs } from './command';
77
import { SlackOptionsMiddlewareArgs } from './options';
@@ -73,6 +73,23 @@ export interface Context extends StringIndexed {
7373
*/
7474
isEnterpriseInstall: boolean,
7575

76+
/**
77+
* A JIT and function-specific token that, when used to make API calls,
78+
* creates an association between a function's execution and subsequent actions
79+
* (e.g., buttons and other interactivity)
80+
*/
81+
functionBotAccessToken?: string;
82+
83+
/**
84+
* Function execution ID associated with the event
85+
*/
86+
functionExecutionId?: string;
87+
88+
/**
89+
* Inputs that were provided to a function when it was executed
90+
*/
91+
functionInputs?: FunctionInputs;
92+
7693
/**
7794
* Retry count of an Events API request (this property does not exist for other requests)
7895
*/
@@ -90,6 +107,9 @@ export const contextBuiltinKeys: string[] = [
90107
'botUserId',
91108
'teamId',
92109
'enterpriseId',
110+
'functionBotAccessToken',
111+
'functionExecutionId',
112+
'functionInputs',
93113
'retryNum',
94114
'retryReason',
95115
];

0 commit comments

Comments
 (0)