slack-edge
Version:
Slack app development framework for edge functions with streamlined TypeScript support
932 lines • 46.2 kB
JavaScript
"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _SlackApp_instances, _SlackApp_slashCommands, _SlackApp_events, _SlackApp_globalShorcuts, _SlackApp_messageShorcuts, _SlackApp_blockActions, _SlackApp_blockSuggestions, _SlackApp_viewSubmissions, _SlackApp_viewClosed, _SlackApp_assistantEnabled, _SlackApp_assistantEvent, _SlackApp_callAuthorize;
Object.defineProperty(exports, "__esModule", { value: true });
exports.noopLazyHandler = exports.SlackApp = void 0;
const request_parser_1 = require("./request/request-parser");
const request_verification_1 = require("./request/request-verification");
const response_1 = require("./response/response");
const slack_web_api_client_1 = require("slack-web-api-client");
const context_1 = require("./context/context");
const slack_web_api_client_2 = require("slack-web-api-client");
const built_in_middleware_1 = require("./middleware/built-in-middleware");
const errors_1 = require("./errors");
const single_team_authorize_1 = require("./authorization/single-team-authorize");
const execution_context_1 = require("./execution-context");
const payload_types_1 = require("./request/payload-types");
const message_events_1 = require("./utility/message-events");
const socket_mode_client_1 = require("./socket-mode/socket-mode-client");
const function_executed_event_1 = require("./utility/function-executed-event");
const assistant_1 = require("./assistant/assistant");
const thread_context_store_1 = require("./assistant/thread-context-store");
const authorize_error_handler_1 = require("./authorization/authorize-error-handler");
/**
* The class representing a Slack app process that handles requests from Slack's API server.
*/
class SlackApp {
// --------------------------
constructor(options) {
_SlackApp_instances.add(this);
/**
* The custom middleware that are called before authorize() function.
*/
// deno-lint-ignore no-explicit-any
this.preAuthorizeMiddleware = [built_in_middleware_1.urlVerification];
/**
* The custom middleware that are called after authorize() function.
*/
// deno-lint-ignore no-explicit-any
this.postAuthorizeMiddleware = [];
this.eventsToSkipAuthorize = ["app_uninstalled", "tokens_revoked"];
// --------------------------
// Enabled listener functions
// --------------------------
_SlackApp_slashCommands.set(this, []);
_SlackApp_events.set(this, []);
_SlackApp_globalShorcuts.set(this, []);
_SlackApp_messageShorcuts.set(this, []);
_SlackApp_blockActions.set(this, []);
_SlackApp_blockSuggestions.set(this, []);
_SlackApp_viewSubmissions.set(this, []);
_SlackApp_viewClosed.set(this, []);
_SlackApp_assistantEnabled.set(this, void 0);
if (options.env.SLACK_BOT_TOKEN === undefined && (options.authorize === undefined || options.authorize === single_team_authorize_1.singleTeamAuthorize)) {
throw new errors_1.ConfigError("When you don't pass env.SLACK_BOT_TOKEN, your own authorize function, which supplies a valid token to use, needs to be passed instead.");
}
this.env = options.env;
// Note that options.env.SLACK_BOT_TOKEN is absent for SlackOAuthApp
this.client = new slack_web_api_client_1.SlackAPIClient(options.env.SLACK_BOT_TOKEN, {
logLevel: this.env.SLACK_LOGGING_LEVEL,
});
// Socket Mode settings
this.appLevelToken = options.env.SLACK_APP_TOKEN;
this.socketMode = options.socketMode ?? this.appLevelToken !== undefined;
if (this.socketMode) {
// Socket Mode does not require request signature verification
// because the underlying WS connection are securely established.
this.signingSecret = "";
}
else {
if (!this.env.SLACK_SIGNING_SECRET) {
throw new errors_1.ConfigError("env.SLACK_SIGNING_SECRET is required to run your app on edge functions!");
}
this.signingSecret = this.env.SLACK_SIGNING_SECRET;
}
this.startLazyListenerAfterAck = options.startLazyListenerAfterAck ?? false;
this.ignoreSelfEvents = options.ignoreSelfEvents ?? true;
if (this.ignoreSelfEvents) {
const middleware = (0, built_in_middleware_1.ignoringSelfEvents)(options.ignoreSelfAssistantMessageEvents ?? true);
this.postAuthorizeMiddleware.push(middleware);
}
this.authorize = options.authorize ?? single_team_authorize_1.singleTeamAuthorize;
this.authorizeErrorHandler = options.authorizeErrorHandler ?? (0, authorize_error_handler_1.buildDefaultAuthorizeErrorHanlder)();
this.routes = { events: options.routes?.events };
this.assistantThreadContextStore = options.assistantThreadContextStore;
__classPrivateFieldSet(this, _SlackApp_assistantEnabled, options.assistantThreadContextStore !== undefined, "f");
}
/**
* Registers a pre-authorize middleware.
* @param middleware middleware
* @returns this instance
*/
beforeAuthorize(middleware) {
this.preAuthorizeMiddleware.push(middleware);
return this;
}
/**
* Registers a post-authorize middleware. This naming is for consistency with bolt-js.
* @param middleware middleware
* @returns this instance
*/
middleware(middleware) {
return this.afterAuthorize(middleware);
}
/**
* Registers a post-authorize middleware. This naming is for consistency with bolt-js.
* @param middleware middleware
* @returns this instance
*/
use(middleware) {
return this.afterAuthorize(middleware);
}
/**
* Registers a post-authorize middleware.
* @param middleware middleware
* @returns this instance
*/
afterAuthorize(middleware) {
this.postAuthorizeMiddleware.push(middleware);
return this;
}
/**
* Registers a listener that handles slash command executions.
* @param pattern the pattern to match slash command name
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
command(pattern, ack, lazy = exports.noopLazyHandler) {
const handler = { ack, lazy };
__classPrivateFieldGet(this, _SlackApp_slashCommands, "f").push((body) => {
if (body.type || !body.command) {
return null;
}
if (typeof pattern === "string" && body.command === pattern) {
return handler;
}
else if (typeof pattern === "object" && pattern instanceof RegExp && body.command.match(pattern)) {
return handler;
}
return null;
});
return this;
}
/**
* Registers a listener that handles custom function calls within Workflow Builder.
* Please be aware that this feature is still in beta as of April 2024.
* @param callbackId the pattern to match callback_id in a payload
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
function(callbackId, lazy) {
__classPrivateFieldGet(this, _SlackApp_events, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.EventsAPI || !body.event || body.event.type !== "function_executed") {
return null;
}
if ((0, function_executed_event_1.isFunctionExecutedEvent)(body.event)) {
let matched = true;
if (callbackId !== undefined) {
if (typeof callbackId === "string") {
matched = body.event.function.callback_id.includes(callbackId);
}
if (typeof callbackId === "object") {
matched = body.event.function.callback_id.match(callbackId) !== null;
}
}
if (matched) {
// deno-lint-ignore require-await
return { ack: async (_) => "", lazy };
}
}
return null;
});
return this;
}
/**
* Registers a listener that handles Events API request.
* @param event the pattern to match event type in a payload
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
event(event, lazy) {
__classPrivateFieldGet(this, _SlackApp_events, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.EventsAPI || !body.event) {
return null;
}
if (body.event.type === event) {
// deno-lint-ignore require-await
return { ack: async () => "", lazy };
}
return null;
});
return this;
}
assistant(assistant) {
__classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "assistant_thread_started", assistant.threadStartedHandler);
__classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "assistant_thread_context_changed", assistant.threadContextChangedHandler);
__classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "message", assistant.userMessageHandler, false);
__classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "message", assistant.botMessageHandler, true);
if (assistant.threadContextStore) {
this.assistantThreadContextStore = assistant.threadContextStore;
}
return this;
}
assistantThreadStarted(lazy) {
return __classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "assistant_thread_started", new assistant_1.Assistant({
threadContextStore: this.assistantThreadContextStore,
threadStarted: lazy,
}).threadStartedHandler);
}
assistantThreadContextChanged(lazy) {
return __classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "assistant_thread_context_changed", new assistant_1.Assistant({
threadContextStore: this.assistantThreadContextStore,
threadContextChanged: lazy,
}).threadContextChangedHandler);
}
assistantUserMessage(lazy) {
return __classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "message", new assistant_1.Assistant({
threadContextStore: this.assistantThreadContextStore,
userMessage: lazy,
}).userMessageHandler, false);
}
assistantBotMessage(lazy) {
return __classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_assistantEvent).call(this, "message", new assistant_1.Assistant({
threadContextStore: this.assistantThreadContextStore,
botMessage: lazy,
}).botMessageHandler, true);
}
/**
* Registers a listener that handles all newly posted message events.
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
anyMessage(lazy) {
return this.message(undefined, lazy);
}
/**
* Registers a listener that handles newly posted message events that matches the pattern.
* @param pattern the pattern to match a message event's text
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
message(pattern, lazy) {
__classPrivateFieldGet(this, _SlackApp_events, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.EventsAPI || !body.event || body.event.type !== "message") {
return null;
}
if ((0, message_events_1.isPostedMessageEvent)(body.event)) {
let matched = true;
if (pattern !== undefined) {
if (typeof pattern === "string") {
matched = body.event.text.includes(pattern);
}
if (typeof pattern === "object") {
matched = body.event.text.match(pattern) !== null;
}
}
if (matched) {
// deno-lint-ignore require-await
return { ack: async (_) => "", lazy };
}
}
return null;
});
return this;
}
/**
* Registers a listener that handles global/message shortcut executions.
* @param callbackId the pattern to match callback_id in a payload
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
shortcut(callbackId, ack, lazy = exports.noopLazyHandler) {
return this.globalShortcut(callbackId, ack, lazy).messageShortcut(callbackId, ack, lazy);
}
/**
* Registers a listener that handles global shortcut executions.
* @param callbackId the pattern to match callback_id in a payload
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
globalShortcut(callbackId, ack, lazy = exports.noopLazyHandler) {
const handler = { ack, lazy };
__classPrivateFieldGet(this, _SlackApp_globalShorcuts, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.GlobalShortcut || !body.callback_id) {
return null;
}
if (typeof callbackId === "string" && body.callback_id === callbackId) {
return handler;
}
else if (typeof callbackId === "object" && callbackId instanceof RegExp && body.callback_id.match(callbackId)) {
return handler;
}
return null;
});
return this;
}
/**
* Registers a listener that handles message shortcut executions.
* @param callbackId the pattern to match callback_id in a payload
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
messageShortcut(callbackId, ack, lazy = exports.noopLazyHandler) {
const handler = { ack, lazy };
__classPrivateFieldGet(this, _SlackApp_messageShorcuts, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.MessageShortcut || !body.callback_id) {
return null;
}
if (typeof callbackId === "string" && body.callback_id === callbackId) {
return handler;
}
else if (typeof callbackId === "object" && callbackId instanceof RegExp && body.callback_id.match(callbackId)) {
return handler;
}
return null;
});
return this;
}
/**
* Registers a listener that handles type: "block_actions" requests.
* @param constraints the constraints to match block_id/action_id in a payload
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
action(constraints, ack, lazy = exports.noopLazyHandler) {
const handler = { ack, lazy };
__classPrivateFieldGet(this, _SlackApp_blockActions, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.BlockAction || !body.actions || !body.actions[0]) {
return null;
}
const action = body.actions[0];
if (typeof constraints === "string" && action.action_id === constraints) {
return handler;
}
else if (typeof constraints === "object") {
if (constraints instanceof RegExp) {
if (action.action_id.match(constraints)) {
return handler;
}
}
else if (constraints.type) {
if (action.type === constraints.type) {
if (action.action_id === constraints.action_id) {
if (constraints.block_id && action.block_id !== constraints.block_id) {
return null;
}
return handler;
}
}
}
}
return null;
});
return this;
}
/**
* Registers a listener that handles type: "block_suggestion" requests.
* Note that your app must return the options/option_groups within 3 seconds,
* so slack-edge intentionally does not accept lazy here.
* @param constraints the constraints to match block_id/action_id in a payload
* @param ack ack function that must complete within 3 seconds
* @returns this instance
*/
options(constraints, ack) {
// Note that block_suggestion response must be done within 3 seconds.
// So, we don't support the lazy handler for it.
const handler = { ack };
__classPrivateFieldGet(this, _SlackApp_blockSuggestions, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.BlockSuggestion || !body.action_id) {
return null;
}
if (typeof constraints === "string" && body.action_id === constraints) {
return handler;
}
else if (typeof constraints === "object") {
if (constraints instanceof RegExp) {
if (body.action_id.match(constraints)) {
return handler;
}
}
else {
if (body.action_id === constraints.action_id) {
if (body.block_id && body.block_id !== constraints.block_id) {
return null;
}
return handler;
}
}
}
return null;
});
return this;
}
/**
* Registers a listener that handles type: "view_submission"/"view_closed" requests.
* @param callbackId the constraints to match callback_id in a payload
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
view(callbackId, ack, lazy = exports.noopLazyHandler) {
return this.viewSubmission(callbackId, ack, lazy).viewClosed(callbackId, ack, lazy);
}
/**
* Registers a listener that handles type: "view_submission" requests.
* @param callbackId the constraints to match callback_id in a payload
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
viewSubmission(callbackId, ack, lazy = exports.noopLazyHandler) {
const handler = { ack, lazy };
__classPrivateFieldGet(this, _SlackApp_viewSubmissions, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.ViewSubmission || !body.view) {
return null;
}
if (typeof callbackId === "string" && body.view.callback_id === callbackId) {
return handler;
}
else if (typeof callbackId === "object" && callbackId instanceof RegExp && body.view.callback_id.match(callbackId)) {
return handler;
}
return null;
});
return this;
}
/**
* Registers a listener that handles type: "view_closed" requests.
* @param callbackId the constraints to match callback_id in a payload
* @param ack ack function that must complete within 3 seconds
* @param lazy lazy function that can do anything asynchronously
* @returns this instance
*/
viewClosed(callbackId, ack, lazy = exports.noopLazyHandler) {
const handler = { ack, lazy };
__classPrivateFieldGet(this, _SlackApp_viewClosed, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.ViewClosed || !body.view) {
return null;
}
if (typeof callbackId === "string" && body.view.callback_id === callbackId) {
return handler;
}
else if (typeof callbackId === "object" && callbackId instanceof RegExp && body.view.callback_id.match(callbackId)) {
return handler;
}
return null;
});
return this;
}
/**
* Handles an http request and returns a response to it.
* @param request request
* @param ctx execution context
* @returns response
*/
async run(request, ctx = new execution_context_1.NoopExecutionContext()) {
return await this.handleEventRequest(request, ctx);
}
/**
* Establishes a WebSocket connection for Socket Mode.
*/
async connect() {
if (!this.socketMode) {
throw new errors_1.ConfigError("Both env.SLACK_APP_TOKEN and socketMode: true are required to start a Socket Mode connection!");
}
this.socketModeClient = new socket_mode_client_1.SocketModeClient(this);
await this.socketModeClient.connect();
}
/**
* Disconnect a WebSocket connection for Socket Mode.
*/
async disconnect() {
if (this.socketModeClient) {
await this.socketModeClient.disconnect();
}
}
/**
* Handles an HTTP request from Slack's API server and returns a response to it.
* @param request request
* @param ctx execution context
* @returns response
*/
async handleEventRequest(request, ctx) {
// If the routes.events is missing, any URLs can work for handing requests from Slack
if (this.routes.events) {
const { pathname } = new URL(request.url);
if (pathname !== this.routes.events) {
return new Response("Not found", { status: 404 });
}
}
// To avoid the following warning by Cloudflware, parse the body as Blob first
// Called .text() on an HTTP body which does not appear to be text ..
const blobRequestBody = await request.blob();
// We can safely assume the incoming request body is always text data
const rawBody = await blobRequestBody.text();
// For Request URL verification
if (rawBody.includes("ssl_check=")) {
// Slack does not send the x-slack-signature header for this pattern.
// Thus, we need to check the pattern before verifying a request.
const bodyParams = new URLSearchParams(rawBody);
if (bodyParams.get("ssl_check") === "1" && bodyParams.get("token")) {
return new Response("", { status: 200 });
}
}
// Verify the request headers and body
const isRequestSignatureVerified = this.socketMode || (await (0, request_verification_1.verifySlackRequest)(this.signingSecret, request.headers, rawBody));
if (isRequestSignatureVerified) {
// deno-lint-ignore no-explicit-any
const body = await (0, request_parser_1.parseRequestBody)(request.headers, rawBody);
let retryNum = undefined;
try {
const retryNumHeader = request.headers.get("x-slack-retry-num");
if (retryNumHeader) {
retryNum = Number.parseInt(retryNumHeader);
}
else if (this.socketMode && body.retry_attempt) {
retryNum = Number.parseInt(body.retry_attempt);
}
// deno-lint-ignore no-unused-vars
}
catch (e) {
// Ignore an exception here
}
const retryReason = request.headers.get("x-slack-retry-reason") ?? body.retry_reason;
const preAuthorizeRequest = {
body,
rawBody,
retryNum,
retryReason,
context: (0, context_1.builtBaseContext)(body),
env: this.env,
headers: request.headers,
};
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Received request body ***\n ${(0, slack_web_api_client_2.prettyPrint)(body)}`);
}
for (const middlware of this.preAuthorizeMiddleware) {
const response = await middlware(preAuthorizeRequest);
if (response) {
return (0, response_1.toCompleteResponse)(response);
}
}
let authorizeResult;
try {
authorizeResult = await __classPrivateFieldGet(this, _SlackApp_instances, "m", _SlackApp_callAuthorize).call(this, preAuthorizeRequest);
}
catch (
// deno-lint-ignore no-explicit-any
error) {
if ("name" in error && error.name === "AuthorizeError") {
const responseOrError = await this.authorizeErrorHandler({
request: preAuthorizeRequest,
error,
});
if ("name" in responseOrError && responseOrError.name === "AuthorizeError") {
throw responseOrError; // AuthorizeError
}
else {
return responseOrError; // Response
}
}
else {
// The authorize() function should not throw any other exceptions than AuthorizeError
throw error;
}
}
const primaryToken = preAuthorizeRequest.context.functionBotAccessToken || authorizeResult.botToken;
const authorizedContext = {
...preAuthorizeRequest.context,
authorizeResult,
client: new slack_web_api_client_1.SlackAPIClient(primaryToken, {
logLevel: this.env.SLACK_LOGGING_LEVEL,
}),
botToken: authorizeResult.botToken,
botId: authorizeResult.botId,
botUserId: authorizeResult.botUserId,
userToken: authorizeResult.userToken,
};
if (authorizedContext.channelId) {
const context = authorizedContext;
const primaryToken = context.functionBotAccessToken || context.botToken;
const client = new slack_web_api_client_1.SlackAPIClient(primaryToken);
if (__classPrivateFieldGet(this, _SlackApp_assistantEnabled, "f") && authorizedContext.isAssistantThreadEvent) {
const assistantContext = authorizedContext;
const { channelId: channel_id, threadTs: thread_ts } = assistantContext;
// setStatus
assistantContext.setStatus = async ({ status }) => await client.assistant.threads.setStatus({ channel_id, thread_ts, status });
// setTitle
assistantContext.setTitle = async ({ title }) => await client.assistant.threads.setTitle({ channel_id, thread_ts, title });
// setSuggestedPrompts
assistantContext.setSuggestedPrompts = async ({ title, prompts }) => {
const promptsArgs = [];
for (const p of prompts) {
if (typeof p === "string") {
promptsArgs.push({ message: p, title: p });
}
else {
promptsArgs.push(p);
}
}
return await client.assistant.threads.setSuggestedPrompts({ channel_id, thread_ts, prompts: promptsArgs, title });
};
// threadContextStore
const threadContextStore = this.assistantThreadContextStore ??
new thread_context_store_1.DefaultAssistantThreadContextStore({
client,
thisBotUserId: context.botUserId,
});
assistantContext.threadContextStore = threadContextStore;
// saveThreadContextStore
assistantContext.saveThreadContextStore = async (newContext) => {
await threadContextStore.save({ channel_id, thread_ts }, newContext);
};
// threadContext
const threadContext = (await threadContextStore.find({ channel_id, thread_ts })) ||
(body.event.assistant_thread?.context && Object.keys(body.event.assistant_thread.context).length > 0
? body.event.assistant_thread?.context
: undefined);
if (threadContext) {
assistantContext.threadContext = threadContext;
}
// say
context.say = async (params) => await client.chat.postMessage({
channel: channel_id,
thread_ts,
metadata: threadContext
? {
event_type: "assistant_thread_context",
event_payload: { ...threadContext },
}
: undefined,
...params,
});
}
else {
context.say = async (params) => await client.chat.postMessage({
channel: context.channelId,
thread_ts: context.threadTs, // for assistant apps
...params,
});
}
}
if (authorizedContext.responseUrl) {
const responseUrl = authorizedContext.responseUrl;
// deno-lint-ignore require-await
authorizedContext.respond = async (params) => {
return new slack_web_api_client_1.ResponseUrlSender(responseUrl).call(params);
};
}
const baseRequest = {
...preAuthorizeRequest,
context: authorizedContext,
};
for (const middlware of this.postAuthorizeMiddleware) {
const response = await middlware(baseRequest);
if (response) {
return (0, response_1.toCompleteResponse)(response);
}
}
const payload = body;
if (body.type === payload_types_1.PayloadType.EventsAPI) {
// Events API
const slackRequest = {
payload: body.event,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_events, "f")) {
const handler = matcher(payload);
if (handler) {
if (!this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
if (this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
if (payload.event?.type === "assistant_thread_context_changed") {
// When a developer does not register their customer listener for this event,
// SlackApp automatically calls the built-in one for ease of development.
const handler = new assistant_1.Assistant({ threadContextStore: this.assistantThreadContextStore }).threadContextChangedHandler;
if (!this.startLazyListenerAfterAck) {
const req = slackRequest;
ctx.waitUntil(handler(req));
return (0, response_1.toCompleteResponse)();
}
}
}
else if (!body.type && body.command) {
// Slash commands
const slackRequest = {
payload: body,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_slashCommands, "f")) {
const handler = matcher(payload);
if (handler) {
if (!this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
if (this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
}
else if (body.type === payload_types_1.PayloadType.GlobalShortcut) {
// Global shortcuts
const slackRequest = {
payload: body,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_globalShorcuts, "f")) {
const handler = matcher(payload);
if (handler) {
if (!this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
if (this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
}
else if (body.type === payload_types_1.PayloadType.MessageShortcut) {
// Message shortcuts
const slackRequest = {
payload: body,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_messageShorcuts, "f")) {
const handler = matcher(payload);
if (handler) {
if (!this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
if (this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
}
else if (body.type === payload_types_1.PayloadType.BlockAction) {
// Block actions
// deno-lint-ignore no-explicit-any
const slackRequest = {
// deno-lint-ignore no-explicit-any
payload: body,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_blockActions, "f")) {
const handler = matcher(payload);
if (handler) {
if (!this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
if (this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
}
else if (body.type === payload_types_1.PayloadType.BlockSuggestion) {
// Block suggestions
const slackRequest = {
payload: body,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_blockSuggestions, "f")) {
const handler = matcher(payload);
if (handler) {
// Note that the only way to respond to a block_suggestion request
// is to send an HTTP response with options/option_groups.
// Thus, we don't support lazy handlers for this pattern.
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
}
else if (body.type === payload_types_1.PayloadType.ViewSubmission) {
// View submissions
const slackRequest = {
payload: body,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_viewSubmissions, "f")) {
const handler = matcher(payload);
if (handler) {
if (!this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
if (this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
}
else if (body.type === payload_types_1.PayloadType.ViewClosed) {
// View closed
const slackRequest = {
payload: body,
...baseRequest,
};
for (const matcher of __classPrivateFieldGet(this, _SlackApp_viewClosed, "f")) {
const handler = matcher(payload);
if (handler) {
if (!this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
const slackResponse = await handler.ack(slackRequest);
if ((0, slack_web_api_client_2.isDebugLogEnabled)(this.env.SLACK_LOGGING_LEVEL)) {
console.log(`*** Slack response ***\n${(0, slack_web_api_client_2.prettyPrint)(slackResponse)}`);
}
if (this.startLazyListenerAfterAck) {
ctx.waitUntil(handler.lazy(slackRequest));
}
return (0, response_1.toCompleteResponse)(slackResponse);
}
}
}
// TODO: Add code suggestion here
console.log(`*** No listener found ***\n${JSON.stringify(baseRequest.body)}`);
return new Response("No listener found", { status: 404 });
}
return new Response("Invalid signature", { status: 401 });
}
}
exports.SlackApp = SlackApp;
_SlackApp_slashCommands = new WeakMap(), _SlackApp_events = new WeakMap(), _SlackApp_globalShorcuts = new WeakMap(), _SlackApp_messageShorcuts = new WeakMap(), _SlackApp_blockActions = new WeakMap(), _SlackApp_blockSuggestions = new WeakMap(), _SlackApp_viewSubmissions = new WeakMap(), _SlackApp_viewClosed = new WeakMap(), _SlackApp_assistantEnabled = new WeakMap(), _SlackApp_instances = new WeakSet(), _SlackApp_assistantEvent = function _SlackApp_assistantEvent(event, lazy, handleSelfBotMessageEvents = false) {
__classPrivateFieldSet(this, _SlackApp_assistantEnabled, true, "f");
__classPrivateFieldGet(this, _SlackApp_events, "f").push((body) => {
if (body.type !== payload_types_1.PayloadType.EventsAPI || !body.event) {
return null;
}
if (body.event.type === event && __classPrivateFieldGet(this, _SlackApp_assistantEnabled, "f") && (0, context_1.isAssitantThreadEvent)(body)) {
if (event === "message" && "bot_profile" in body.event) {
if (handleSelfBotMessageEvents) {
// this app's bot message events
// The botMessageHandler acknowledges this pattern
// Note that ignoreSelfAssistantMessageEvents must be set to false
// deno-lint-ignore require-await
return { ack: async () => "", lazy };
}
else {
// userMessageHandler does not acknowledge
return null;
}
}
else {
// assistant_thread_started events
// assistant_thread_context_changed events
// user message events
// deno-lint-ignore require-await
return { ack: async () => "", lazy };
}
}
return null;
});
return this;
}, _SlackApp_callAuthorize = async function _SlackApp_callAuthorize(request) {
const body = request.body;
if (body.type === payload_types_1.PayloadType.EventsAPI && body.event && this.eventsToSkipAuthorize.includes(body.event.type)) {
// this pattern does not need AuthorizeResult at all
return {
enterpriseId: request.context.actorEnterpriseId,
teamId: request.context.actorTeamId,
team: request.context.actorTeamId,
botId: request.context.botId || "N/A",
botUserId: request.context.botUserId || "N/A",
botToken: "N/A",
botScopes: [],
userId: request.context.actorUserId,
user: request.context.actorUserId,
userToken: "N/A",
userScopes: [],
};
}
return await this.authorize(request);
};
/**
* Singleton lazy listener that does not do anything
*/
const noopLazyHandler = async () => { };
exports.noopLazyHandler = noopLazyHandler;
//# sourceMappingURL=app.js.map