BotMate is a chatbot framework for developers.
🔌 Plugins
Client API

Client API

A BotMate plugin can interact with both the back end and the front end of the application. The Client API is about the front end part, i.e. it allows a plugin to customize the application's dashboard.

A Client API consist the following -

  • an entry point which is client.tsx
  • lifecycle functions
  • and several custom React hooks and variables to interact with the dashboard

Entry file

The entry file for the Client API is [plugin-name]/src/client/client.tsx. This file exports a class that extends the client plugin with the following functions available:

Lifecycle functions

beforeLoad

This function runs every time the plugin is about to load. It usually includes tasks like registering new routes or adding items to the sidebar. When the page loads, the beforeLoad function is called for each plugin.

load

This function runs after all the beforeLoad functions have finished. It can include logic that depends on other plugins being enabled. This allows plugins to create and share plugin hooks that other plugins can use.

Available actions

The Client API provides plugins with access to various small APIs for performing actions. Refer to this table for details:

Sidebar API

The Sidebar API allows a plugin to add a new item to the main sidebar through the addToSidebar() function with the following parameters:

ParameterTypeDescription
labelStringThe text to show when hovered
pathStringLocation to open when clicked
iconLucideIconIcon to show on in sidebar
regex?RegExRegular expression for the path

This by itself does not create a new page, but it adds a new item to the sidebar that can be clicked to open a new page. To create new pages, use the Route API.

Example:

export class MyPlugin extends Plugin {
  beforeLoad() {
    this.addToSidebar({
      label: 'Moderation',
      icon: ShieldIcon,
      path: '/moderation',
      regex: /^\/moderation/,
    });
  }
}
View screenshot

Route API

This API enables you to add register routes to the application, although it is recommended to use this API once throughout your plugin. This allows plugins to add new pages to the dashboard. Unlike the Settings API, the Route API is more flexible and can be used to create complex pages with multiple routes. Here is the list of parameters:

ParameterTypeDescription
pathStringPath to register on the dashboard
elementReactElementComponent to load when the path is visited

Let's say you want to create a moderation plugin with multiple pages like Home, Welcome, Filters, and Anti-Spam. You can use the Route API to achieve this.

Here is an example:

this.addRoute({
  path: '/moderation/*',
  element: (
    <Layout>
      <Routes>
        <Route index element={<HomePage />} />
        <Route path="/welcome" element={<WelcomePage />} />
        <Route path="/filters" element={<FiltersPage />} />
        <Route path="/anti-spam" element={<AntiSpamPage />} />
      </Routes>
    </Layout>
  ),
});

But to open the moderation plugin, you need to add a sidebar item for it. You can do this by using the Sidebar API.

Settings API

The Settings API allows you to provide a settings page for your plugin. This is useful for plugins that require user configuration.

import React from 'react';
import { Plugin } from '@botmate/client';
import SettingsPage from './settings';
 
export class RandomNumberGenerator extends Plugin {
  displayName = 'Random Number Generator';
 
  async beforeLoad() {
    this.provideSettings(<SettingsPage />);
  }
}

The provideSettings function takes a React component as an argument. This component will be rendered when the user clicks on the plugin settings. It is recommended to use settings page for plugins that require less configuration, for more complex configuration and UI, use the Route API.

React hooks

Client API also consists several React hooks which can help you rapidy develop plugins. Here are the list of available hooks.

usePluginConfig

This hook enables the saving and loading of plugin configurations for the bot. By default, it saves configurations to the currently active bot on the dashboard using key-value pairs. These configurations can subsequently be utilized in the Server API, allowing users to customize your plugin with a variety of options.

This hook can be used inside the plugin routes or the settings page.

Example:

function SettingsPage() {
  const config = usePluginConfig();
 
  const inputRef = React.useRef < HTMLInputElement > null;
 
  return (
    <div className="space-y-2">
      <Input
        ref={inputRef}
        defaultValue={config.get('message.start')}
        placeholder="Enter start message"
      />
      <Button
        onClick={async () => {
          const text = inputRef.current?.value;
          if (text) {
            await config.save('message.start', text);
            toast.success('Message saved');
          } else {
            toast.error('Please enter start message');
          }
        }}
      >
        Save
      </Button>
    </div>
  );
}

In the code above, we are reading text from an input field and saving in the database using the config.save function. This saves the value of the input fields with the key message.start in the database.

💡

Note: Uninstalling the plugin will remove all the configurations saved by the plugin.

createPluginRPC

This hook is used to create an RPC object that can be used to call functions defined in the server API of the plugin. It is used to call RPC functions of the plugin on the server with type safety.

Here is an example of using query -

client/page.tsx
import { createPluginRPC } from '@botmate/client';
import type { RPC } from '../server';
 
const rpc = createPluginRPC<RPC>();
 
function Page() {
  const bot = useCurrentBot();
  const [searchParams] = useSearchParams();
  const page = searchParams.get('page') || '1';
 
  const telegramChats = rpc.getTelegramChats.useQuery(parseInt(page));
 
  return (
    <div>
      {telegramChats?.map((chat) => (
        <div key={chat.id}>{chat.title}</div>
      ))}
    </div>
  );
}

usePluginRPC (deprecated)

Note: This hook is deprecated and will be removed in future versions. Use createPluginRPC instead.

This React hook accepts two arguments: the first is the name of the function to be called, and the second is the parameter to pass to that function. It is used to call RPC functions of the plugin on the server. The hook returns the result of the function call, while it's fetching, the result will be undefined.

  • Use this hook to call functions defined in the server API of the plugin.
  • The function name should be the same as the function name defined in the server API.

Example:

// page.tsx
import type { RPC } from '../server';
 
const telegramChats = usePluginRPC<RPC>('getTelegramChats', 1);
 
return (
  <div>
    {telegramChats?.map((chat) => (
      <div key={chat.id}>{chat.title}</div>
    ))}
  </div>
);

In the code above, we are calling the getTelegramChats function defined in the server API of the plugin.

// server.ts
export class MyPlugin extends Plugin {
  rpc = getRPC(this);
  displayName = 'My Plugin';
  ...
}
 
const getRPC = (plugin: Plugin) => ({
  getTelegramChats: async () => {
    const chats = await telegram.repository.find();
    return chats;
  },
});
 
export type RPC = ReturnType<typeof getRPC>;

usePluginRPCMutation (deprecated)

Note: This hook is deprecated and will be removed in future versions. Use createPluginRPC instead.

This hook is used to call RPC functions that modify the state of the plugin on the server. It can also be called dynamically based on user actions, such as on button clicks or form submissions.

  • Use this hook to call functions defined in the server API of the plugin.
  • The hook returns a promise that resolves when the function call is successful.
  • The function name should be the same as the function name defined in the server API.

Example:

// page.tsx
import type { RPC } from '../server';
 
const sendMessage = usePluginRPCMutation<RPC>('sendMessage');
 
return (
  <Button
    onClick={async () => {
      await sendMessage({ text: 'Hello, world!' });
    }}
  >
    Send Message
  </Button>
);

In the code above, we are calling the sendMessage function defined in the server API of the plugin.

// server.ts
export class MyPlugin extends Plugin {
  rpc = getRPC(this);
  displayName = 'My Plugin';
  ...
}
 
const getRPC = (plugin: Plugin) => ({
  sendMessage: async (params: { text: string }) => {
    await telegram.sendMessage(params.text);
  },
});
 
export type RPC = ReturnType<typeof getRPC>;