Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"files": {
"ignore": ["examples/**/dist"]
"includes": ["**", "!**/examples/**/dist"]
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"ignore": [],
"includes": ["**"],
"attributePosition": "auto",
"indentStyle": "space",
"indentWidth": 2,
Expand All @@ -24,9 +24,26 @@
"recommended": true
}
},
"organizeImports": {
"enabled": true
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
},
"overrides": [
{
"includes": ["examples/**"],
"linter": {
"rules": {
"correctness": {
"noUnusedFunctionParameters": "off",
"noUnusedVariables": "off"
}
}
}
}
],
Comment on lines +34 to +46
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📚 note: Our examples use handfuls of unused variables with intention so we ignore some rule for now to avoid more changes:

// Message Shortcut example
app.shortcut('launch_msg_shortcut', async ({ shortcut, body, ack, context, client, logger }) => {
await ack();
logger.info(shortcut);
});

"vcs": {
"enabled": true,
"clientKind": "git",
Expand Down
11 changes: 3 additions & 8 deletions examples/custom-receiver/src/FastifyReceiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import {
type BufferedIncomingMessage,
type CodedError,
HTTPResponseAck,
HTTPModuleFunctions as httpFunc,
type InstallProviderOptions,
type InstallURLOptions,
type Receiver,
type ReceiverEvent,
ReceiverInconsistentStateError,
type ReceiverProcessEventErrorHandlerArgs,
type ReceiverUnhandledRequestHandlerArgs,
HTTPModuleFunctions as httpFunc,
} from '@slack/bolt';
import { ConsoleLogger, type LogLevel, type Logger } from '@slack/logger';
import { ConsoleLogger, type Logger, type LogLevel } from '@slack/logger';
import { type CallbackOptions, type InstallPathOptions, InstallProvider } from '@slack/oauth';
import Fastify, { type FastifyInstance } from 'fastify';

Expand Down Expand Up @@ -163,12 +163,7 @@ export default class FastifyReceiver implements Receiver {

public init(app: App): void {
this.app = app;
if (
this.installer &&
this.installerOptions &&
this.installerOptions.installPath &&
this.installerOptions.redirectUriPath
) {
if (this.installer && this.installerOptions?.installPath && this.installerOptions.redirectUriPath) {
this.fastify.get(this.installerOptions.installPath, async (req, res) => {
await this.installer?.handleInstallPath(req.raw, res.raw, this.installerOptions?.installPathOptions);
});
Expand Down
13 changes: 4 additions & 9 deletions examples/custom-receiver/src/KoaReceiver.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { type Server, createServer } from 'node:http';
import { createServer, type Server } from 'node:http';
import Router from '@koa/router';
import {
type App,
type BufferedIncomingMessage,
type CodedError,
HTTPResponseAck,
HTTPModuleFunctions as httpFunc,
type InstallProviderOptions,
type InstallURLOptions,
type Receiver,
type ReceiverEvent,
ReceiverInconsistentStateError,
type ReceiverProcessEventErrorHandlerArgs,
type ReceiverUnhandledRequestHandlerArgs,
HTTPModuleFunctions as httpFunc,
} from '@slack/bolt';
import { ConsoleLogger, type LogLevel, type Logger } from '@slack/logger';
import { ConsoleLogger, type Logger, type LogLevel } from '@slack/logger';
import { type CallbackOptions, type InstallPathOptions, InstallProvider } from '@slack/oauth';
import Koa from 'koa';

Expand Down Expand Up @@ -158,12 +158,7 @@ export default class KoaReceiver implements Receiver {

public init(app: App): void {
this.app = app;
if (
this.installer &&
this.installerOptions &&
this.installerOptions.installPath &&
this.installerOptions.redirectUriPath
) {
if (this.installer && this.installerOptions?.installPath && this.installerOptions.redirectUriPath) {
this.router.get(this.installerOptions.installPath, async (ctx) => {
await this.installer?.handleInstallPath(ctx.req, ctx.res, this.installerOptions?.installPathOptions);
});
Expand Down
69 changes: 36 additions & 33 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"tsscmp": "^1.0.6"
},
"devDependencies": {
"@biomejs/biome": "^1.9.0",
"@biomejs/biome": "^2.4.15",
"@changesets/cli": "^2.29.8",
"@tsconfig/node18": "^18.2.4",
"@types/chai": "^4.1.7",
Expand Down
41 changes: 21 additions & 20 deletions src/App.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Agent } from 'node:http';
import type { SecureContextOptions } from 'node:tls';
import util from 'node:util';
import { ConsoleLogger, LogLevel, type Logger } from '@slack/logger';
import { WebClient, type WebClientOptions, addAppMetadata } from '@slack/web-api';
import { ConsoleLogger, type Logger, LogLevel } from '@slack/logger';
import { addAppMetadata, WebClient, type WebClientOptions } from '@slack/web-api';
import axios, { type AxiosInstance } from 'axios';
import type { Assistant } from './Assistant';
import {
Expand All @@ -11,32 +11,32 @@ import {
type FunctionFailFn,
type SlackCustomFunctionMiddlewareArgs,
} from './CustomFunction';
import type { WorkflowStep } from './WorkflowStep';
import {
createFunctionComplete,
createFunctionFail,
createRespond,
createSay,
createSayStream,
createSetStatus,
type SayStreamFn,
type SetStatusFn,
} from './context';
import type { SayStreamFn, SetStatusFn } from './context';
import { type ConversationStore, MemoryStore, conversationContext } from './conversation-store';
import { type ConversationStore, conversationContext, MemoryStore } from './conversation-store';
import {
AppInitializationError,
asCodedError,
type CodedError,
ErrorCode,
InvalidCustomPropertyError,
MultipleListenerError,
asCodedError,
} from './errors';
import {
IncomingEventType,
assertNever,
extractEventChannelId,
extractEventThreadTs,
extractEventTs,
getTypeAndConversation,
IncomingEventType,
isBodyWithTypeEnterpriseInstall,
isEventTypeToSkipAuthorize,
} from './helpers';
Expand Down Expand Up @@ -96,7 +96,9 @@ import type {
WorkflowStepEdit,
} from './types';
import { contextBuiltinKeys } from './types';
import { type StringIndexed, isRejected } from './types/utilities';
import { isRejected, type StringIndexed } from './types/utilities';
import type { WorkflowStep } from './WorkflowStep';

const packageJson = require('../package.json');

export type { ActionConstraints, OptionsConstraints, ShortcutConstraints, ViewConstraints } from './types';
Expand Down Expand Up @@ -154,7 +156,7 @@ export interface AppOptions {
attachFunctionToken?: boolean;
}

export { LogLevel, Logger } from '@slack/logger';
export { Logger, LogLevel } from '@slack/logger';

/** Authorization function - seeds the middleware processing and listeners with an authorization context */
export type Authorize<IsEnterpriseInstall extends boolean = false> = (
Expand Down Expand Up @@ -1083,7 +1085,7 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>

// TODO: this logic should be isolated and tested according to the expected behavior
if (token !== undefined) {
let pool: WebClientPool | undefined = undefined;
let pool: WebClientPool | undefined;
const clientOptionsCopy = { ...this.clientOptions };
if (authorizeResult.teamId !== undefined) {
pool = this.clients[authorizeResult.teamId];
Expand Down Expand Up @@ -1228,7 +1230,6 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
const rejectedListenerResults = settledListenerResults.filter(isRejected);
if (rejectedListenerResults.length === 1) {
throw rejectedListenerResults[0].reason;
// biome-ignore lint/style/noUselessElse: I think this is a biome issue actually...
} else if (rejectedListenerResults.length > 1) {
throw new MultipleListenerError(rejectedListenerResults.map((rlr) => rlr.reason));
}
Expand Down Expand Up @@ -1355,15 +1356,15 @@ export default class App<AppCustomContext extends StringIndexed = StringIndexed>
throw new AppInitializationError(
`${tokenUsage} \n\nSince you have not provided a token or authorize, you might be missing one or more required oauth installer options. See https://docs.slack.dev/tools/bolt-js/concepts/authenticating-oauth/ for these required fields.\n`,
);
// biome-ignore lint/style/noUselessElse: I think this is a biome issue actually...
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌲 praise: Thanks latest update!

} else if (authorize !== undefined && usingOauth) {
}
if (authorize !== undefined && usingOauth) {
throw new AppInitializationError(`You cannot provide both authorize and oauth installer options. ${tokenUsage}`);
// biome-ignore lint/style/noUselessElse: I think this is a biome issue actually...
} else if (authorize === undefined && usingOauth) {
}
if (authorize === undefined && usingOauth) {
// biome-ignore lint/style/noNonNullAssertion: we know installer is truthy here
return httpReceiver.installer!.authorize;
// biome-ignore lint/style/noUselessElse: I think this is a biome issue actually...
} else if (authorize !== undefined && !usingOauth) {
}
if (authorize !== undefined && !usingOauth) {
return authorize as Authorize<boolean>;
}
return undefined;
Expand Down Expand Up @@ -1647,9 +1648,9 @@ function escapeHtml(input: string | undefined | null): string {
}

function extractFunctionContext(body: StringIndexed) {
let functionExecutionId: string | undefined = undefined;
let functionBotAccessToken: string | undefined = undefined;
let functionInputs: FunctionInputs | undefined = undefined;
let functionExecutionId: string | undefined;
let functionBotAccessToken: string | undefined;
let functionInputs: FunctionInputs | undefined;

// function_executed event
if (body.event && body.event.type === 'function_executed' && body.event.function_execution_id) {
Expand Down
4 changes: 1 addition & 3 deletions src/Assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import {
type AssistantThreadContextStore,
DefaultThreadContextStore,
} from './AssistantThreadContextStore';
import { createSayStream, createSetStatus } from './context';
import type { SayStreamFn } from './context';
import type { SetStatusFn } from './context';
import { createSayStream, createSetStatus, type SayStreamFn, type SetStatusFn } from './context';
import { AssistantInitializationError, AssistantMissingPropertyError } from './errors';
import { extractEventChannelId, extractEventThreadTs, isRecord } from './helpers';
import processMiddleware from './middleware/process';
Expand Down
Loading