npm.io
0.4.2 • Published 2d ago

@codecast-duo/codecast-duo-telegrambot

Licence
ISC
Version
0.4.2
Deps
1
Size
644 kB
Vulns
0
Weekly
0

CodeCast-Duo Telegram Bot API

Content

  1. Introduction
  2. Features
  3. Installation
  4. Telegram API - Usage Guide
    1. Creating an Instance
    2. Configuring TelegramOptions
      1. TelegramOptions Table
      2. OptionsUpdate Sub-Table
      3. OptionsPollingWaitManage Sub-Table
  5. API Methods
    1. sendMessage Method
    2. sendRequest Method
    3. register Method
    4. startUpdater Method
    5. stopUpdater Method
  6. Predicates
    1. predicates.and Method
    2. predicates.or Method
    3. predicates.not Method
  7. Examples
  8. Advanced Topics
    1. Error types
    2. Error handling
    3. Description TelegramError class
      1. Properties Table TelegramError
  9. Polling Wait Manager
    1. Using Polling Wait Manager
    2. Polling Wait Manager Methods

Introduction

Welcome to the Telegram Bot API from CodeCast-Duo. We developed this project as a straightforward, lightweight approach to working with the Telegram Bot API free from needless complication or additional dependencies.

The package's concept is simple: start from the Telegram Bot API documentation itself. Generated methods, types, and documentation-based definitions form the foundation of this project so that the library remains as near as feasible to the original Telegram Bot API.

Consequently, the package offers complete capability for engaging with Telegram bots in the same manner the official Telegram Bot documentation outlines. It keeps the project simple and understandable while giving you typed access to methods, update structures, and core bot interactions. The library uses only the zod package as an external dependent for validation and safer data handling; it is purposefully clean.

This documentation explains how the package works and how to use it effectively in real projects.

Features

  • Offers generated methods, types, and structures that are derived from the Telegram Bot API documentation.
  • Maintains the interaction model near the official Telegram Bot API, thereby simplifying the library's comprehension and functionality.
  • Enables complete interaction with Telegram bots, including event-driven handling, updates, and requests.
  • Provides a more dependable development experience by providing typed request and response objects.
  • A clean event registration system is included to facilitate the organization of bot behavior.
  • Relies solely on the zod package as an external dependency to maintain its simplicity and lightweight nature

Compatibility

Package Version Telegram Bot API Version
0.4.1 9.5
0.4.2 10.2

Installation

To install the package, simply run the following command in your project directory:

npm i @codecast-duo/codecast-duo-telegrambot

This command installs the CodeCast-Duo Telegram Bot package, adding it to your project's dependencies.

Telegram API - Usage Guide

Creating an Instance of TelegramAPI

To start using the Telegram API, you need to create an instance of the TelegramAPI class. This is done using the constructor, which takes an object of type TelegramOptions as its argument. This object contains several configurations that determine how your API instance will behave.

Example
const { Telegram, TelegramError } = require('@codecast-duo/codecast-duo-telegrambot');

// Create a new instance of the Telegram bot
const bot = new Telegram({
    telegramToken: "TELEGRAM_TOKEN",
    // Other TelegramOptions fields as needed
});
Configuring TelegramOptions

The TelegramOptions object contains various settings that are crucial for the operation of your Telegram bot. Here are the key options you need to configure:

TelegramOptions Table
Option Type Description Default Value
telegramToken string The unique token for your Telegram bot, provided by BotFather. None (Mandatory)
telegramApi string Optional. The URL of the Telegram API. If not specified, the default URL is used. 'https://api.telegram.org'
start boolean Optional. Determines whether the bot starts processing messages immediately after instantiation. If false use startUpdaters to start polling updates. true
optionUpdate OptionsUpdate Optional. Configuration for receiving updates, including offset, allowed updates, and limit on updates. OptionsUpdate Sub-Table
optionPollingWaitManager OptionsPollingWaitManage Optional. Settings for managing the wait time between polling, including max wait time and timeout action. OptionsPollingWaitManage Sub-Table
OptionsUpdate Sub-Table
Option Type Description Default Value
offset number Optional. Identifier of the first update to be returned. 0
allowed_updates Array<keyof UpdateTypes> Optional. List of update fields name to be received. Specify an empty list to receive all update types except chat_member, message_reaction, and message_reaction_count (default). If not specified, the previous setting will be used. Please note that this parameter doesn't affect updates created before the call to the getUpdates, so unwanted updates may be received for a short period of time. []
limit number Optional. Limits the number of updates to be retrieved. 100
OptionsPollingWaitManage Sub-Table
Option Type Description Default Value
maxWaitTime number Optional. The maximum waiting time (in milliseconds) allowed before considering the polling process as too long and taking action. 60000 (60 seconds)
onWait number Optional. A callback function that gets executed when the waiting time exceeds maxWaitTime. It allows you to define custom actions or error handling when polling takes too long. Empty function (() => {})
Example
const options = {
    telegramToken: 'YOUR_TELEGRAM_BOT_TOKEN',
    telegramApi: 'https://api.telegram.org',
    start: true,
    optionUpdate: {
        offset: 0,
        allowed_updates: ['message', 'callback_query'],
        limitUpdates: 100
    },
    optionPollingWaitManager: {
        maxWaitTime: 3000,
        onWaitTooLong: () => { /* Handle long wait times */ }
    }
};

API Methods

sendMessage Method
  • sendMessage(params: TelegramTypes.MethodRequest<'sendMessage'>): Promise<TelegramTypes.Message>: This method is used to send a message to a specific chat through the Telegram Bot API. It acts as a convenience wrapper around Telegram's sendMessage method and is useful when you want to quickly send text messages without calling the lower-level request method directly.
await bot.sendMessage({
  chat_id: 123456789,
  text: 'Hello from CodeCast-Duo Telegram Bot',
});

Parameters:

Parameter Type Description
params TelegramTypes.MethodRequest<'sendMessage'> The request payload for the Telegram Bot API 'sendMessage' method
sendRequest Method
  • sendRequest<M extends MethodName>(method: M, params: MethodRequest<M>): Promise<MethodResult<M>>: This method is used to send a typed request to any Telegram Bot API method. It is particularly useful when there is no dedicated convenience method available in the Telegram class, allowing you to access the full Telegram API while preserving type safety.
await bot.sendRequest('editMessageText', {
  chat_id: 123456789,
  message_id: 10,
  text: 'Updated text',
});

Parameters:

Parameter Type Description
method M extends TelegramTypes.MethodName The name of the Telegram Bot API method you want to call
params TelegramTypes.MethodRequest<M> The request payload for the selected Telegram Bot API method
register Method
  • register<K extends UpdateKey, S extends UpdatePayload<K>>( key: K, match: Predicate<UpdatePayload<K>>, handler: Handler<UpdatePayload<K>> ): TelegramEventRegistry: This method is used to register a handler for a specific top-level Telegram update field. It allows you to define a predicate that decides whether a handler should run for a given update payload, making it useful for filtering and processing only the updates that match your bot logic.
bot.register(
        'message',
        (message) => message.text.startsWith('/start'),
        async (message) => {
           console.log(message.text);
        },
);

Parameters:

Parameter Type Description
key string Any top-level key from TelegramTypes.Update except update_id, for example message, edited_message, callback_query, channel_post, poll
match Predicate<UpdatePayload<K>> Predicate or type guard (payload, update) => boolean used to decide whether the handler should run
handler Handler<UpdatePayload<K>> Handler (payload, update) => void | Promise<void> executed when the predicate matches
startUpdater Method
  • startUpdater(): void: This method is used to start the polling process for updates. It initiates the bot's ability to listen for incoming updates from Telegram. This is particularly useful when your bot is set up to not start automatically, or if you've previously stopped the update polling and need to restart it.
stopUpdater Method
  • stopUpdater(): Promise<void>: The stopUpdaters method is used to stop the polling process. This is useful when you want to temporarily halt your bot from listening to incoming updates, without shutting down the entire bot. This can be handy during maintenance, updating bot logic, or handling unexpected behavior.

Predicates

The predicates object provides a set of helper methods for building reusable conditions when working with the register method. These helpers are useful for combining multiple conditions, negating conditions, checking alternative matches, and narrowing object properties such as text for safer TypeScript usage.

In future versions, predicates will be improved to make working with optional fields more convenient. Right now, simple checks such as verifying whether a message starts with /start may require additional fallback logic like (message) => message.text?.startsWith('/start') || false.


predicates.and Method
  • predicates.and<T, A extends T>( ...predicates: Predicate<A>[] ): Predicate<T>: This method is used to combine multiple predicates into a single condition using logical AND. It returns true only when all provided predicates return true. This is particularly useful when you want to check several conditions before executing a handler, such as verifying that a message has text and that the text starts with a specific command.
bot.register(
  'message',
  predicates.and(
    (message) => message.id == 123456789,
    (message) => message.text?.startsWith('/start') || false,
  ),
  async (message) => {
    console.log(message.text);
  },
);

Parameters:

Parameter Type Description
predicates Predicate<A>[] Additional predicates that must all return true

predicates.or Method
  • predicates.or<T>(...predicates: Predicate<T>[]): Predicate<T>: This method is used to combine multiple predicates into a single condition using logical OR. It returns true when at least one of the provided predicates returns true. This is useful when your handler should run for several possible cases instead of only one strict condition.
bot.register(
  'message',
  predicates.or(
    (message) => message.text === '/start',
    (message) => message.text === '/help',
  ),
  async (message) => {
    console.log(message.text);
  },
);

Parameters:

Parameter Type Description
predicates Predicate<T>[] A list of predicates where at least one must return true

predicates.not Method
  • predicates.not<T>(predicate: Predicate<T>): Predicate<T>: This method is used to invert the result of a predicate. It returns true when the provided predicate returns false, and false when the provided predicate returns true. This is useful when you want to exclude a specific condition from your handler logic.
bot.register(
  'message',
  predicates.not((message) => message.text === '/start'),
  async (message) => {
    console.log(message.text);
  },
);

Parameters:

Parameter Type Description
predicate Predicate<T> The predicate whose result should be inverted

Examples

Here's a basic guide on how to use the CodeCast-Duo Telegram Bot API in your project:

// Import the required Telegram bot library
import {
   Telegram,
   TelegramError,
   predicates,
} from '@codecast-duo/codecast-duo-telegrambot';

// Create a new instance of the Telegram bot
const bot = new Telegram({
   telegramToken: 'TELEGRAM_TOKEN',
});

// Register a handler for text messages
bot.register(
        'message',
        (message) => !!message.text,
        async (message) => {
           // Define the structure of the inline keyboard markup
           const inlineKeyboardMarkup = {
              reply_markup: {
                 inline_keyboard: [
                    [{ text: 'Test1', callback_data: 'Callback data test1' }],
                    [{ text: 'Test2', callback_data: 'Callback data test2' }]
                 ]
              }
           };

           try {
              // Send a message back to the chat with the inline keyboard
              const sentMessage = await bot.sendMessage({
                 chat_id: message.chat.id,
                 text: message.text || 'if parameter empty',
                 ...inlineKeyboardMarkup,
              });

              setTimeout(() => {
                 bot.sendRequest('editMessageText', {
                    text: 'Test',
                    chat_id: sentMessage.chat.id,
                    message_id: sentMessage.message_id,
                    reply_markup: {
                       inline_keyboard: [
                          [{ text: 'TestNew1', callback_data: 'Callback data testNew1' }],
                          [{ text: 'TestNew2', callback_data: 'Callback data testNew2' }]
                       ]
                    }
                 }).catch((error: unknown) => {
                    // Handle errors specifically related to Telegram
                    if (error instanceof TelegramError) {
                       console.log(error.message);
                    } else {
                       // Handle any other generic errors
                       console.log('is default error');
                    }
                 });
              }, 1000);
           } catch (error: unknown) {
              // Handle errors specifically related to Telegram
              if (error instanceof TelegramError) {
                 console.log(error.message);
              } else {
                 // Handle any other generic errors
                 console.log('is default error');
              }
           }
        }
);

// Register a handler for callback queries (e.g., when an inline button is pressed)
bot.register(
        'callback_query',
        (callback) => !!callback.data,
        async (callback) => {
           // Respond to the callback query
           await bot.sendMessage({
              chat_id: callback.from.id,
              text: callback.data || 'if callback.data empty',
           });

           console.log(callback.data);
        }
);

// Register a handler for text commands (e.g., "/echo some text")
bot.register(
        'message',
        (message) => /^\/echo (.+)/.test(message.text || ''),
        async (message) => {
           // Log the text following the echo command
           console.log(message.text);
        }
);

// Register a handler using composed predicates
bot.register(
        'message',
        predicates.and(
                (message) => message.text?.startsWith('/start') || false,
        ),
        async (message) => {
           await bot.sendMessage({
              chat_id: message.chat.id,
              text: 'Welcome!',
           });
        }
);

// Check the bot's information (e.g., username)
bot.getMe({}).then(user => {
   // Log success if user data is retrieved
   if (user) {
      console.log('connected');
   }
});

// Global error event listener
bot.on('error', (error) => {
   // Log any errors encountered
   console.error(error);
});

// Specific error event listener for network-related errors
bot.on('error-NetworkError', (error) => {
   // Log network errors separately
   console.error(error);
});

Advanced Topics

Error types

Below is a table describing the different types of errors (TelegramErrorTypes) that can occur when interacting with the Telegram API, along with a brief description of each error type:

Error Type Description
NetworkError Occurs when there is a problem with the network connection, such as a failure to reach the Telegram servers.
ApiError This error is thrown when there is an issue with the API request, such as invalid parameters or authentication issues.
TimeoutError Occurs when a request to the Telegram API takes too long to respond, exceeding the predefined timeout limit.
InternalServerError Indicates a problem on the Telegram server side, such as a server malfunction or maintenance.
ParsingError This error is encountered when there is an issue in parsing the response from the Telegram API.
UnhandledPromiseRejection Occurs when a Promise in the code is rejected but not properly handled with a catch block.
UnknownError Used as a catch-all for any errors that do not fit into the other predefined categories.
Error handling

In your Telegram bot implementation, you can set up error handling in two primary ways:

  1. Catch All Errors: Use bot.on('error', (error) => {}); to handle all types of errors. This is a general error handler that will catch any error thrown by the bot, regardless of its type. It's useful for logging or handling errors in a generic way.

    bot.on('error', (error) => {
        console.error('An error occurred:', error);
        // Additional error handling logic can go here
    });
  2. Catch Specific Types of Errors: Use bot.on('error-TelegramErrorTypes', (error) => {}); to handle specific types of errors. This allows for more granular error handling based on the error type. For example, you can have different handlers for NetworkError, ApiError, etc.

    // Handling NetworkError specifically
    bot.on('error-NetworkError', (error) => {
        console.error('Network Error:', error);
        // Specific handling for network errors
    });
    
    // Handling ApiError specifically
    bot.on('error-ApiError', (error) => {
        console.error('API Error:', error);
        // Specific handling for API errors
    });
    
    // ... similarly for other error types
  3. Catch from onMessage(), onUpdate(), onText (): In the context of Telegram bot development using the described library, methods like onMessage, onUpdate, and onText typically return a Promise. The resolution of these promises is usually void, meaning they do not return any value upon successful completion. However, in case of an error, these methods can throw an exception, which is caught in the catch block.

When you use these methods, it's a good practice to handle potential errors that might occur during their execution. This error handling is usually done by attaching a catch block to the promise. The error caught is typically an instance of the TelegramError class, which provides details about what went wrong.

Here's how you might structure your code to include error handling with these methods:

// Handling incoming text messages
 bot.onMessage('text', (parameter, message) => {
     // Logic to handle the message
     // ...
 }).catch(error => {
     if (error instanceof TelegramError) {
         console.error('TelegramError occurred:', error.message);
     } else {
         console.error('Unknown error occurred:', error);
     }
 });
Description TelegramError

The TelegramError class provides a structured way to handle errors encountered during Telegram bot operations. It encapsulates details about the error, including its type and, if available, a specific error code. This class can handle different types of errors, such as network issues or API-related problems, and can be instantiated with detailed information about the underlying error.

Properties Table TelegramError
Parameter Type Description
error_code string | undefined An optional code that provides additional information about the error. This is typically specific to the type of error encountered.
type TelegramErrorTypes The type of the error, categorized as one of the predefined TelegramErrorTypes, such as NetworkError, ApiError, etc.
message string Inherited from the base Error class, this property contains a message describing the error.
stack string | undefined Also inherited from the base Error class, this property provides a stack trace at the point where the error was instantiated, if available.

Polling Wait Manager

The "Polling Wait Manager" is a crucial component utilized for the efficient management of the polling process in applications that communicate with a remote server through polling. Polling involves sending periodic requests to a server to retrieve updates or data. The Polling Wait Manager plays a pivotal role in ensuring the effective control of this polling process and handling pauses in the operation of an application.

Using Polling Wait Manager

The Polling Wait Manager proves to be invaluable in applications that depend on polling to receive updates or data from a remote server. It serves to guarantee the efficient and optimal management of polling, dynamically turning it off when not required. This not only conserves valuable resources but also prevents excessive server load.

TelegramAPI Class and Polling Wait Manager

The TelegramAPI class offers a seamless integration with the Polling Wait Manager, empowering you to take charge of the polling process. Here is an overview of the available methods along with their descriptions:

Polling Wait Manager Methods
  • getPollingWaitManager(): PollingWaitManager | undefined: The getPollingWaitManager method provides the means to fetch the current Polling Wait Manager object or returns undefined if it hasn't been initialized.

  • setPollingWaitManager(name: string, func: () => boolean): void: With the setPollingWaitManager method, you can effortlessly create or modify a function within the Polling Wait Manager. This function requires the name of the function and a callback function that should return a boolean value. If the Polling Wait Manager doesn't exist, this method will create it dynamically.

  • removePollingWaitManager(name: string): void The removePollingWaitManager method allows you to selectively remove a function from the Polling Wait Manager by specifying its name. This function deletion process is seamless and effective.

These methods are instrumental in efficiently managing the polling process within your application by defining conditions under which polling should continue or cease. They serve as invaluable tools for optimizing the operation of applications reliant on polling to receive updates or data.

Examples 1: Initializing and Using Polling Wait Manager

Here's a basic guide on how to use the CodeCast-Duo Telegram Bot API in your project:

const { Telegram } = require('@codecast-duo/codecast-duo-telegrambot');

const bot = new Telegram({
    telegramToken: "TELEGRAM_TOKEN",
});

const pollingWaitManager = bot.getPollingWaitManager();

let continuePolling= false;

function shouldContinuePolling() {
    return continuePolling;
}

setTimeout(() => {
        continuePolling = true;
    }, 30000);

bot.setPollingWaitManager("exampleFunction", shouldContinuePolling);

In this example, we initialize the TelegramAPI instance, retrieve the Polling Wait Manager, define a function (shouldContinuePolling) that determines whether polling should continue, set this function in the Polling Wait Manager.

Examples 2: Removing a Polling Function
bot.removePollingWaitManager("exampleFunction");

In this example, we remove a polling function named "exampleFunction" from the Polling Wait Manager. This function will no longer be used to determine whether polling should continue.

Keywords