UNPKG

@slack/bolt

Version:

A framework for building Slack apps, fast.

140 lines 6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.assertNever = exports.isEventTypeToSkipAuthorize = exports.isBodyWithTypeEnterpriseInstall = exports.getTypeAndConversation = exports.IncomingEventType = void 0; /** * Internal data type for capturing the class of event processed in App#onIncomingEvent() */ var IncomingEventType; (function (IncomingEventType) { IncomingEventType[IncomingEventType["Event"] = 0] = "Event"; IncomingEventType[IncomingEventType["Action"] = 1] = "Action"; IncomingEventType[IncomingEventType["Command"] = 2] = "Command"; IncomingEventType[IncomingEventType["Options"] = 3] = "Options"; IncomingEventType[IncomingEventType["ViewAction"] = 4] = "ViewAction"; IncomingEventType[IncomingEventType["Shortcut"] = 5] = "Shortcut"; })(IncomingEventType || (exports.IncomingEventType = IncomingEventType = {})); // ---------------------------- // For skipping authorize with event const eventTypesToSkipAuthorize = ['app_uninstalled', 'tokens_revoked']; /** * Helper which finds the type and channel (if any) that any specific incoming event is related to. * * This is analogous to WhenEventHasChannelContext and the conditional type that checks SlackAction for a channel * context. */ // biome-ignore lint/suspicious/noExplicitAny: response bodies can be anything function getTypeAndConversation(body) { if (body.event !== undefined) { const { event } = body; // Find conversationId const conversationId = (() => { let foundConversationId; if ('channel' in event) { if (typeof event.channel === 'string') { foundConversationId = event.channel; } else if ('id' in event.channel) { foundConversationId = event.channel.id; } } if ('channel_id' in event) { foundConversationId = event.channel_id; } if ('item' in event && 'channel' in event.item) { // no channel for reaction_added, reaction_removed, star_added, or star_removed with file or file_comment items foundConversationId = event.item.channel; } // Using non-null assertion (!) because the alternative is to use `foundConversation: (string | undefined)`, which // impedes the very useful type checker help above that ensures the value is only defined to strings, not // undefined. This is safe when used in combination with the || operator with a default value. // biome-ignore lint/style/noNonNullAssertion: TODO: revisit this and use the types return foundConversationId || undefined; })(); return { conversationId, type: IncomingEventType.Event, }; } if (body.command !== undefined) { return { type: IncomingEventType.Command, conversationId: body.channel_id, }; } if (body.name !== undefined || body.type === 'block_suggestion') { const optionsBody = body; return { type: IncomingEventType.Options, conversationId: optionsBody.channel !== undefined ? optionsBody.channel.id : undefined, }; } // TODO: remove workflow_step stuff in v5 if (body.actions !== undefined || body.type === 'dialog_submission' || body.type === 'workflow_step_edit') { const actionBody = body; return { type: IncomingEventType.Action, conversationId: actionBody.channel !== undefined ? actionBody.channel.id : undefined, }; } if (body.type === 'shortcut') { return { type: IncomingEventType.Shortcut, }; } if (body.type === 'message_action') { const shortcutBody = body; return { type: IncomingEventType.Shortcut, conversationId: shortcutBody.channel !== undefined ? shortcutBody.channel.id : undefined, }; } if (body.type === 'view_submission' || body.type === 'view_closed') { return { type: IncomingEventType.ViewAction, }; } return {}; } exports.getTypeAndConversation = getTypeAndConversation; /** * Helper which determines if the body of a request is enterprise install. * * Providing the type is optional but if you do the execution will be faster */ function isBodyWithTypeEnterpriseInstall(body, type) { const _type = type !== undefined ? type : getTypeAndConversation(body).type; if (_type === IncomingEventType.Event) { const bodyAsEvent = body; if (Array.isArray(bodyAsEvent.authorizations) && bodyAsEvent.authorizations[0] !== undefined) { return !!bodyAsEvent.authorizations[0].is_enterprise_install; } } // command payloads have this property set as a string if (typeof body.is_enterprise_install === 'string') { return body.is_enterprise_install === 'true'; } // all remaining types have a boolean property if (body.is_enterprise_install !== undefined) { return body.is_enterprise_install; } // as a fallback we assume it's a single team installation (but this should never happen) return false; } exports.isBodyWithTypeEnterpriseInstall = isBodyWithTypeEnterpriseInstall; /** * Helper which determines if the event type will skip Authorize. * * Token revocation use cases * https://github.com/slackapi/bolt-js/issues/674 */ function isEventTypeToSkipAuthorize(event) { return eventTypesToSkipAuthorize.includes(event.body.event?.type); } exports.isEventTypeToSkipAuthorize = isEventTypeToSkipAuthorize; /* istanbul ignore next */ /** Helper that should never be called, but is useful for exhaustiveness checking in conditional branches */ function assertNever(x) { throw new Error(`Unexpected object: ${x}`); } exports.assertNever = assertNever; //# sourceMappingURL=helpers.js.map