Skip to content

Commit

Permalink
Fixes and polish for stable release
Browse files Browse the repository at this point in the history
  • Loading branch information
misscoded committed Aug 7, 2024
1 parent 87730ef commit f7966e7
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 13 deletions.
16 changes: 12 additions & 4 deletions src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
SlashCommand,
WorkflowStepEdit,
SlackOptions,
FunctionInputs,
} from './types';
import { IncomingEventType, getTypeAndConversation, assertNever, isBodyWithTypeEnterpriseInstall, isEventTypeToSkipAuthorize } from './helpers';
import { CodedError, asCodedError, AppInitializationError, MultipleListenerError, ErrorCode, InvalidCustomPropertyError } from './errors';
Expand Down Expand Up @@ -964,9 +965,12 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
retryReason: event.retryReason,
};

// Extract function-related information and augment to context
const { functionExecutionId, functionBotAccessToken } = extractFunctionContext(body);
if (functionExecutionId) { context.functionExecutionId = functionExecutionId; }
// Extract function-related information and augment context
const { functionExecutionId, functionBotAccessToken, functionInputs } = extractFunctionContext(body);
if (functionExecutionId) {
context.functionExecutionId = functionExecutionId;

Check warning on line 971 in src/App.ts

View check run for this annotation

Codecov / codecov/patch

src/App.ts#L971

Added line #L971 was not covered by tests
if (functionInputs) { context.functionInputs = functionInputs; }
}

if (this.attachFunctionToken) {
if (functionBotAccessToken) { context.functionBotAccessToken = functionBotAccessToken; }
Expand Down Expand Up @@ -1029,6 +1033,7 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
ack?: AckFn<any>;
complete?: FunctionCompleteFn;
fail?: FunctionFailFn;
inputs?: FunctionInputs;
} = {
body: bodyArg,
payload,
Expand Down Expand Up @@ -1088,6 +1093,7 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
if (type === IncomingEventType.Action && context.functionExecutionId !== undefined) {
listenerArgs.complete = CustomFunction.createFunctionComplete(context, client);
listenerArgs.fail = CustomFunction.createFunctionFail(context, client);
listenerArgs.inputs = context.functionInputs;

Check warning on line 1096 in src/App.ts

View check run for this annotation

Codecov / codecov/patch

src/App.ts#L1096

Added line #L1096 was not covered by tests
}

if (token !== undefined) {
Expand Down Expand Up @@ -1599,6 +1605,7 @@ function escapeHtml(input: string | undefined | null): string {
function extractFunctionContext(body: StringIndexed) {
let functionExecutionId;
let functionBotAccessToken;
let functionInputs;

// function_executed event
if (body.event && body.event.type === 'function_executed' && body.event.function_execution_id) {
Expand All @@ -1610,9 +1617,10 @@ function extractFunctionContext(body: StringIndexed) {
if (body.function_data) {
functionExecutionId = body.function_data.execution_id;
functionBotAccessToken = body.bot_access_token;
functionInputs = body.function_data.inputs;

Check warning on line 1620 in src/App.ts

View check run for this annotation

Codecov / codecov/patch

src/App.ts#L1620

Added line #L1620 was not covered by tests
}

return { functionExecutionId, functionBotAccessToken };
return { functionExecutionId, functionBotAccessToken, functionInputs };
}

// ----------------------------
Expand Down
3 changes: 2 additions & 1 deletion src/CustomFunction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('CustomFunction class', () => {
assert(fakeNext.called);
});

it('should call next if not a workflow step event', async () => {
it('should call next if not a function executed event', async () => {
const fn = new CustomFunction('test_view_callback_id', MOCK_MIDDLEWARE_SINGLE);
const middleware = fn.getMiddleware();
const fakeViewArgs = createFakeViewEvent() as unknown as
Expand Down Expand Up @@ -215,6 +215,7 @@ function createFakeFunctionExecutedEvent() {
},
context: {
functionBotAccessToken: 'xwfp-123',
functionExecutionId: 'test_executed_callback_id',
},
};
}
Expand Down
16 changes: 13 additions & 3 deletions src/CustomFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
FunctionExecutedEvent,
} from './types';
import processMiddleware from './middleware/process';
import { CustomFunctionInitializationError } from './errors';
import { CustomFunctionCompleteFailError, CustomFunctionCompleteSuccessError, CustomFunctionInitializationError } from './errors';

/** Interfaces */

Expand Down Expand Up @@ -105,6 +105,11 @@ export class CustomFunction {
const token = selectToken(context);
const { functionExecutionId } = context;

if (!functionExecutionId) {
const errorMsg = 'No function_execution_id found';
throw new CustomFunctionCompleteSuccessError(errorMsg);

Check warning on line 110 in src/CustomFunction.ts

View check run for this annotation

Codecov / codecov/patch

src/CustomFunction.ts#L109-L110

Added lines #L109 - L110 were not covered by tests
}

return (params: Parameters<FunctionCompleteFn>[0] = {}) => client.functions.completeSuccess({
token,
outputs: params.outputs || {},
Expand All @@ -123,6 +128,11 @@ export class CustomFunction {
const { error } = params ?? {};
const { functionExecutionId } = context;

if (!functionExecutionId) {
const errorMsg = 'No function_execution_id found';
throw new CustomFunctionCompleteFailError(errorMsg);

Check warning on line 133 in src/CustomFunction.ts

View check run for this annotation

Codecov / codecov/patch

src/CustomFunction.ts#L132-L133

Added lines #L132 - L133 were not covered by tests
}

return client.functions.completeError({
token,
error,
Expand Down Expand Up @@ -158,8 +168,8 @@ export function validate(callbackId: string, middleware: CustomFunctionExecuteMi
}

/**
* `processFunctionMiddleware()` invokes each callback for lifecycle event
* @param args workflow_step_edit action
* `processFunctionMiddleware()` invokes each listener middleware
* @param args function_executed event
*/
export async function processFunctionMiddleware(
args: AllCustomFunctionMiddlewareArgs,
Expand Down
10 changes: 10 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export enum ErrorCode {
WorkflowStepInitializationError = 'slack_bolt_workflow_step_initialization_error',

CustomFunctionInitializationError = 'slack_bolt_custom_function_initialization_error',
CustomFunctionCompleteSuccessError = 'slack_bolt_custom_function_complete_success_error',
CustomFunctionCompleteFailError = 'slack_bolt_custom_function_complete_fail_error',
}

export class UnknownError extends Error implements CodedError {
Expand Down Expand Up @@ -149,3 +151,11 @@ export class WorkflowStepInitializationError extends Error implements CodedError
export class CustomFunctionInitializationError extends Error implements CodedError {
public code = ErrorCode.CustomFunctionInitializationError;
}

export class CustomFunctionCompleteSuccessError extends Error implements CodedError {
public code = ErrorCode.CustomFunctionCompleteSuccessError;

Check warning on line 156 in src/errors.ts

View check run for this annotation

Codecov / codecov/patch

src/errors.ts#L156

Added line #L156 was not covered by tests
}

export class CustomFunctionCompleteFailError extends Error implements CodedError {
public code = ErrorCode.CustomFunctionCompleteFailError;

Check warning on line 160 in src/errors.ts

View check run for this annotation

Codecov / codecov/patch

src/errors.ts#L160

Added line #L160 was not covered by tests
}
8 changes: 4 additions & 4 deletions src/types/events/base-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,11 @@ export interface FileUnsharedEvent {
}

export interface FunctionParams {
type?: string;
name?: string;
type: string;
name: string;
description?: string;
title?: string;
is_required?: boolean;
is_required: boolean;
}

export interface FunctionInputs {
Expand All @@ -451,7 +451,7 @@ export interface FunctionExecutedEvent {
id: string;
callback_id: string;
title: string;
description: string;
description?: string;
type: string;
input_parameters: FunctionParams[];
output_parameters: FunctionParams[];
Expand Down
22 changes: 21 additions & 1 deletion src/types/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { WebClient } from '@slack/web-api';
import { Logger } from '@slack/logger';
import { StringIndexed } from './helpers';
import { SlackEventMiddlewareArgs } from './events';
import { FunctionInputs, SlackEventMiddlewareArgs } from './events';
import { SlackActionMiddlewareArgs } from './actions';
import { SlackCommandMiddlewareArgs } from './command';
import { SlackOptionsMiddlewareArgs } from './options';
Expand Down Expand Up @@ -73,6 +73,23 @@ export interface Context extends StringIndexed {
*/
isEnterpriseInstall: boolean,

/**
* A JIT and function-specific token that, when used to make API calls,
* creates an association between a function's execution and subsequent actions
* (e.g., buttons and other interactivity)
*/
functionBotAccessToken?: string;

/**
* Function execution ID associated with the event
*/
functionExecutionId?: string;

/**
* Inputs that were provided to a function when it was executed
*/
functionInputs?: FunctionInputs;

/**
* Retry count of an Events API request (this property does not exist for other requests)
*/
Expand All @@ -90,6 +107,9 @@ export const contextBuiltinKeys: string[] = [
'botUserId',
'teamId',
'enterpriseId',
'functionBotAccessToken',
'functionExecutionId',
'functionInputs',
'retryNum',
'retryReason',
];
Expand Down

0 comments on commit f7966e7

Please sign in to comment.