/ src / server / chat / slash-command-dispatch.ts
slash-command-dispatch.ts
 1  export type SlashCommandWithKind = {
 2    kind: string
 3  }
 4  
 5  export type SlashCommandHandlerMap<
 6    TCommand extends SlashCommandWithKind,
 7    TResult,
 8    TContext,
 9  > = {
10    [Kind in TCommand['kind']]: (input: {
11      command: Extract<TCommand, { kind: Kind }>
12      context: TContext
13    }) => Promise<TResult> | TResult
14  }
15  
16  export async function dispatchSlashCommand<
17    TCommand extends SlashCommandWithKind,
18    TResult,
19    TContext,
20  >(input: {
21    text: string
22    parsedCommand?: TCommand | null
23    parseCommand: (text: string) => TCommand | null
24    context: TContext
25    handlers: SlashCommandHandlerMap<TCommand, TResult, TContext>
26    onUnknownSlash: (input: {
27      rawText: string
28      context: TContext
29    }) => Promise<TResult> | TResult
30  }): Promise<TResult | null> {
31    const command = input.parsedCommand ?? input.parseCommand(input.text)
32    if (!command) {
33      if (input.text.trim().startsWith('/')) {
34        return input.onUnknownSlash({
35          rawText: input.text,
36          context: input.context,
37        })
38      }
39      return null
40    }
41  
42    const handler = input.handlers[command.kind as TCommand['kind']]
43  
44    return handler({
45      command: command as never,
46      context: input.context,
47    })
48  }