Skip to content

Commit c63f1f4

Browse files
committed
Incorporate PR comments
1 parent 27738f9 commit c63f1f4

File tree

4 files changed

+110
-131
lines changed

4 files changed

+110
-131
lines changed

src/App.ts

+17-28
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ import { AllMiddlewareArgs, contextBuiltinKeys } from './types/middleware';
6161
import { StringIndexed } from './types/helpers';
6262
// eslint-disable-next-line import/order
6363
import allSettled = require('promise.allsettled'); // eslint-disable-line @typescript-eslint/no-require-imports
64-
import { FunctionCompleteFn, FunctionFailFn, WorkflowFunction, WorkflowFunctionMiddleware } from './WorkflowFunction';
64+
import { FunctionCompleteFn, FunctionFailFn, CustomFunction, CustomFunctionMiddleware } from './CustomFunction';
6565
// eslint-disable-next-line @typescript-eslint/no-require-imports, import/no-commonjs
6666
const packageJson = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires
6767

@@ -337,7 +337,7 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
337337
this.errorHandler = defaultErrorHandler(this.logger) as AnyErrorHandler;
338338
this.extendedErrorHandler = extendedErrorHandler;
339339

340-
// Override token with functionBotToken in function-related handlers
340+
// Override token with functionBotAccessToken in function-related handlers
341341
this.attachFunctionToken = attachFunctionToken;
342342

343343
/* ------------------------ Set client options ------------------------*/
@@ -526,10 +526,10 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
526526
}
527527

528528
/**
529-
* Register WorkflowFunction middleware
529+
* Register CustomFunction middleware
530530
*/
531-
public function(callbackId: string, ...listeners: WorkflowFunctionMiddleware): this {
532-
const fn = new WorkflowFunction(callbackId, listeners);
531+
public function(callbackId: string, ...listeners: CustomFunctionMiddleware): this {
532+
const fn = new CustomFunction(callbackId, listeners);
533533
const m = fn.getMiddleware();
534534
this.middleware.push(m);
535535
return this;
@@ -964,10 +964,12 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
964964
retryReason: event.retryReason,
965965
};
966966

967+
// Extract function-related information and augment to context
968+
const { functionExecutionId, functionBotAccessToken } = extractFunctionContext(body);
969+
if (functionExecutionId) { context.functionExecutionId = functionExecutionId; }
970+
967971
if (this.attachFunctionToken) {
968-
const { functionExecutionId, functionBotToken } = extractFunctionContext(body);
969-
if (functionExecutionId) { context.functionExecutionId = functionExecutionId; }
970-
if (functionBotToken) { context.functionBotToken = functionBotToken; }
972+
if (functionBotAccessToken) { context.functionBotAccessToken = functionBotAccessToken; }
971973
}
972974

973975
// Factory for say() utility
@@ -1082,23 +1084,10 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
10821084
let { client } = this;
10831085
const token = selectToken(context);
10841086

1085-
// TODO :: WorkflowFunction owns these same utilities. Rework TS to allow for reuse.
1086-
// Set complete() and fail() utilities for function-related interactivity
1087+
// Add complete() and fail() utilities for function-related interactivity
10871088
if (type === IncomingEventType.Action && context.functionExecutionId !== undefined) {
1088-
listenerArgs.complete = (params: Parameters<FunctionCompleteFn>[0] = {}) => client.functions.completeSuccess({
1089-
token: context.functionBotToken,
1090-
outputs: params.outputs || {},
1091-
function_execution_id: context.functionExecutionId,
1092-
});
1093-
listenerArgs.fail = (params: Parameters<FunctionFailFn>[0]) => {
1094-
const { error } = params ?? {};
1095-
1096-
return client.functions.completeError({
1097-
token: context.functionBotToken,
1098-
error,
1099-
function_execution_id: context.functionExecutionId,
1100-
});
1101-
};
1089+
listenerArgs.complete = CustomFunction.createFunctionComplete(context, client);
1090+
listenerArgs.fail = CustomFunction.createFunctionFail(context, client);
11021091
}
11031092

11041093
if (token !== undefined) {
@@ -1609,21 +1598,21 @@ function escapeHtml(input: string | undefined | null): string {
16091598

16101599
function extractFunctionContext(body: StringIndexed) {
16111600
let functionExecutionId;
1612-
let functionBotToken;
1601+
let functionBotAccessToken;
16131602

16141603
// function_executed event
16151604
if (body.event && body.event.type === 'function_executed' && body.event.function_execution_id) {
16161605
functionExecutionId = body.event.function_execution_id;
1617-
functionBotToken = body.event.bot_access_token;
1606+
functionBotAccessToken = body.event.bot_access_token;
16181607
}
16191608

16201609
// interactivity (block_actions)
16211610
if (body.function_data) {
16221611
functionExecutionId = body.function_data.execution_id;
1623-
functionBotToken = body.bot_access_token;
1612+
functionBotAccessToken = body.bot_access_token;
16241613
}
16251614

1626-
return { functionExecutionId, functionBotToken };
1615+
return { functionExecutionId, functionBotAccessToken };
16271616
}
16281617

16291618
// ----------------------------

src/WorkflowFunction.ts src/CustomFunction.ts

+65-77
Original file line numberDiff line numberDiff line change
@@ -12,59 +12,59 @@ import {
1212
Context,
1313
} from './types';
1414
import processMiddleware from './middleware/process';
15-
import { WorkflowFunctionInitializationError } from './errors';
15+
import { CustomFunctionInitializationError } from './errors';
1616

1717
/** Interfaces */
1818

19-
export interface FunctionCompleteArguments {
19+
interface FunctionCompleteArguments {
2020
outputs?: {
2121
[key: string]: any;
2222
};
2323
}
2424

25-
export interface FunctionFailArguments {
26-
error: string;
27-
}
28-
2925
export interface FunctionCompleteFn {
3026
(params?: FunctionCompleteArguments): Promise<FunctionsCompleteSuccessResponse>;
3127
}
3228

29+
interface FunctionFailArguments {
30+
error: string;
31+
}
32+
3333
export interface FunctionFailFn {
3434
(params: FunctionFailArguments): Promise<FunctionsCompleteErrorResponse>;
3535
}
3636

37-
export interface WorkflowFunctionExecuteMiddlewareArgs extends SlackEventMiddlewareArgs<'function_executed'> {
37+
export interface CustomFunctionExecuteMiddlewareArgs extends SlackEventMiddlewareArgs<'function_executed'> {
3838
complete: FunctionCompleteFn;
3939
fail: FunctionFailFn;
4040
}
4141

4242
/** Types */
4343

44-
export type SlackWorkflowFunctionMiddlewareArgs = WorkflowFunctionExecuteMiddlewareArgs;
44+
export type SlackCustomFunctionMiddlewareArgs = CustomFunctionExecuteMiddlewareArgs;
4545

46-
export type WorkflowFunctionExecuteMiddleware = Middleware<WorkflowFunctionExecuteMiddlewareArgs>;
46+
type CustomFunctionExecuteMiddleware = Middleware<CustomFunctionExecuteMiddlewareArgs>;
4747

48-
export type WorkflowFunctionMiddleware = WorkflowFunctionExecuteMiddleware[];
48+
export type CustomFunctionMiddleware = CustomFunctionExecuteMiddleware[];
4949

50-
export type AllWorkflowFunctionMiddlewareArgs
51-
<T extends SlackWorkflowFunctionMiddlewareArgs = SlackWorkflowFunctionMiddlewareArgs> = T & AllMiddlewareArgs;
50+
export type AllCustomFunctionMiddlewareArgs
51+
<T extends SlackCustomFunctionMiddlewareArgs = SlackCustomFunctionMiddlewareArgs> = T & AllMiddlewareArgs;
5252

5353
/** Constants */
5454

5555
const VALID_PAYLOAD_TYPES = new Set(['function_executed']);
5656

5757
/** Class */
5858

59-
export class WorkflowFunction {
59+
export class CustomFunction {
6060
/** Function callback_id */
6161
public callbackId: string;
6262

63-
private middleware: WorkflowFunctionMiddleware;
63+
private middleware: CustomFunctionMiddleware;
6464

6565
public constructor(
6666
callbackId: string,
67-
middleware: WorkflowFunctionMiddleware,
67+
middleware: CustomFunctionMiddleware,
6868
) {
6969
validate(callbackId, middleware);
7070

@@ -81,35 +81,69 @@ export class WorkflowFunction {
8181
};
8282
}
8383

84-
private matchesConstraints(args: SlackWorkflowFunctionMiddlewareArgs): boolean {
84+
private matchesConstraints(args: SlackCustomFunctionMiddlewareArgs): boolean {
8585
return args.payload.function.callback_id === this.callbackId;
8686
}
8787

88-
private async processEvent(args: AllWorkflowFunctionMiddlewareArgs): Promise<void> {
88+
private async processEvent(args: AllCustomFunctionMiddlewareArgs): Promise<void> {
8989
const functionArgs = prepareFunctionArgs(args);
9090
const stepMiddleware = this.getStepMiddleware();
9191
return processStepMiddleware(functionArgs, stepMiddleware);
9292
}
9393

94-
private getStepMiddleware(): WorkflowFunctionMiddleware {
94+
private getStepMiddleware(): CustomFunctionMiddleware {
9595
return this.middleware;
9696
}
97+
98+
/**
99+
* Factory for `complete()` utility
100+
* @param args function_executed event
101+
*/
102+
public static createFunctionComplete(context: Context, client: WebClient): FunctionCompleteFn {
103+
const token = selectToken(context);
104+
const { functionExecutionId } = context;
105+
106+
return (params: Parameters<FunctionCompleteFn>[0] = {}) => client.functions.completeSuccess({
107+
token,
108+
outputs: params.outputs || {},
109+
function_execution_id: functionExecutionId,
110+
});
111+
}
112+
113+
/**
114+
* Factory for `fail()` utility
115+
* @param args function_executed event
116+
*/
117+
public static createFunctionFail(context: Context, client: WebClient): FunctionFailFn {
118+
const token = selectToken(context);
119+
120+
return (params: Parameters<FunctionFailFn>[0]) => {
121+
const { error } = params ?? {};
122+
const { functionExecutionId } = context;
123+
124+
return client.functions.completeError({
125+
token,
126+
error,
127+
function_execution_id: functionExecutionId,
128+
});
129+
};
130+
}
97131
}
98132

99133
/** Helper Functions */
100134

101-
export function validate(callbackId: string, listeners: WorkflowFunctionMiddleware): void {
135+
export function validate(callbackId: string, listeners: CustomFunctionMiddleware): void {
102136
// Ensure callbackId is valid
103137
if (typeof callbackId !== 'string') {
104-
const errorMsg = 'WorkflowFunction expects a callback_id as the first argument';
105-
throw new WorkflowFunctionInitializationError(errorMsg);
138+
const errorMsg = 'CustomFunction expects a callback_id as the first argument';
139+
throw new CustomFunctionInitializationError(errorMsg);
106140
}
107141

108142
// Ensure all listeners are functions
109143
listeners.forEach((listener) => {
110144
if (!(listener instanceof Function)) {
111-
const errorMsg = 'All WorkflowFunction listeners must be functions';
112-
throw new WorkflowFunctionInitializationError(errorMsg);
145+
const errorMsg = 'All CustomFunction listeners must be functions';
146+
throw new CustomFunctionInitializationError(errorMsg);
113147
}
114148
});
115149
}
@@ -119,8 +153,8 @@ export function validate(callbackId: string, listeners: WorkflowFunctionMiddlewa
119153
* @param args workflow_step_edit action
120154
*/
121155
export async function processStepMiddleware(
122-
args: AllWorkflowFunctionMiddlewareArgs,
123-
middleware: WorkflowFunctionMiddleware,
156+
args: AllCustomFunctionMiddlewareArgs,
157+
middleware: CustomFunctionMiddleware,
124158
): Promise<void> {
125159
const { context, client, logger } = args;
126160
const callbacks = [...middleware] as Middleware<AnyMiddlewareArgs>[];
@@ -134,59 +168,13 @@ export async function processStepMiddleware(
134168
}
135169
}
136170

137-
export function isFunctionEvent(args: AnyMiddlewareArgs): args is AllWorkflowFunctionMiddlewareArgs {
171+
function isFunctionEvent(args: AnyMiddlewareArgs): args is AllCustomFunctionMiddlewareArgs {
138172
return VALID_PAYLOAD_TYPES.has(args.payload.type);
139173
}
140174

141175
function selectToken(context: Context): string | undefined {
142176
// If attachFunctionToken = false, fallback to botToken or userToken
143-
return context.functionBotToken ? context.functionBotToken : context.botToken || context.userToken;
144-
}
145-
146-
/**
147-
* Factory for `complete()` utility
148-
* @param args function_executed event
149-
*/
150-
export function createFunctionComplete(
151-
args: AllWorkflowFunctionMiddlewareArgs<WorkflowFunctionExecuteMiddlewareArgs>,
152-
): FunctionCompleteFn {
153-
const {
154-
context,
155-
client,
156-
payload: { function_execution_id },
157-
} = args;
158-
const token = selectToken(context);
159-
160-
return (params: Parameters<FunctionCompleteFn>[0] = {}) => client.functions.completeSuccess({
161-
token,
162-
outputs: params.outputs || {},
163-
function_execution_id,
164-
});
165-
}
166-
167-
/**
168-
* Factory for `fail()` utility
169-
* @param args function_executed event
170-
*/
171-
export function createFunctionFail(
172-
args: AllWorkflowFunctionMiddlewareArgs<WorkflowFunctionExecuteMiddlewareArgs>,
173-
): FunctionFailFn {
174-
const {
175-
context,
176-
client,
177-
payload: { function_execution_id },
178-
} = args;
179-
const token = selectToken(context);
180-
181-
return (params: Parameters<FunctionFailFn>[0]) => {
182-
const { error } = params ?? {};
183-
184-
return client.functions.completeError({
185-
token,
186-
error,
187-
function_execution_id,
188-
});
189-
};
177+
return context.functionBotAccessToken ? context.functionBotAccessToken : context.botToken || context.userToken;
190178
}
191179

192180
/**
@@ -195,20 +183,20 @@ export function createFunctionFail(
195183
* - events will *not* continue down global middleware chain to subsequent listeners
196184
* 2. augments args with step lifecycle-specific properties/utilities
197185
* */
198-
export function prepareFunctionArgs(args: any): AllWorkflowFunctionMiddlewareArgs {
186+
function prepareFunctionArgs(args: any): AllCustomFunctionMiddlewareArgs {
199187
const { next: _next, ...functionArgs } = args;
200188
const preparedArgs: any = { ...functionArgs };
201189
const token = selectToken(functionArgs.context);
202190

203-
// Making calls with a functionBotToken establishes continuity between
191+
// Making calls with a functionBotAccessToken establishes continuity between
204192
// a function_executed event and subsequent interactive events (actions)
205193
const client = new WebClient(token, { ...functionArgs.client });
206194
preparedArgs.client = client;
207195

208196
// Utility args
209197
preparedArgs.inputs = preparedArgs.event.inputs;
210-
preparedArgs.complete = createFunctionComplete(preparedArgs);
211-
preparedArgs.fail = createFunctionFail(preparedArgs);
198+
preparedArgs.complete = CustomFunction.createFunctionComplete(preparedArgs.context, client);
199+
preparedArgs.fail = CustomFunction.createFunctionFail(preparedArgs.context, client);
212200

213201
return preparedArgs;
214202
}

src/errors.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export enum ErrorCode {
3535

3636
WorkflowStepInitializationError = 'slack_bolt_workflow_step_initialization_error',
3737

38-
WorkflowFunctionInitializationError = 'slack_bolt_workflow_function_initialization_error',
38+
CustomFunctionInitializationError = 'slack_bolt_workflow_function_initialization_error',
3939
}
4040

4141
export class UnknownError extends Error implements CodedError {
@@ -141,6 +141,6 @@ export class WorkflowStepInitializationError extends Error implements CodedError
141141
public code = ErrorCode.WorkflowStepInitializationError;
142142
}
143143

144-
export class WorkflowFunctionInitializationError extends Error implements CodedError {
145-
public code = ErrorCode.WorkflowFunctionInitializationError;
144+
export class CustomFunctionInitializationError extends Error implements CodedError {
145+
public code = ErrorCode.CustomFunctionInitializationError;
146146
}

0 commit comments

Comments
 (0)