npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@abdosaiko20/tg-sdk

v1.0.1

Published

Lightweight, production-ready, comprehensive Telegram SDK for Bots and Mini Apps

Readme


🌟 Why @abdosaiko20/tg-sdk?


📦 Installation

# npm
npm install @abdosaiko20/tg-sdk

# yarn
yarn add @abdosaiko20/tg-sdk

# pnpm
pnpm add @abdosaiko20/tg-sdk

# bun
bun add @abdosaiko20/tg-sdk

🏗️ Architecture

@abdosaiko20/tg-sdk/
├── 🤖 Bot API          →  Full Telegram Bot API with 100+ methods
├── 📱 Mini Apps        →  Complete WebApp API for Telegram Mini Apps
├── 🎨 Keyboards        →  Fluent builders for Inline & Reply keyboards
├── 📝 Formatters       →  MarkdownV2 & HTML safe builders
├── 🔄 Middleware        →  Express-like middleware engine
├── 🛣️ Router           →  Command, hears, action, event routing
├── 💾 Sessions          →  Built-in session with custom storage adapters
├── 🔌 Plugins          →  Extensible plugin architecture
├── ⭐ Payments          →  Telegram Stars & invoice management
├── 📡 Broadcast        →  Message broadcasting with concurrency control
└── ⚛️ React             →  First-class React hooks

🚀 Quick Start

🤖 Telegram Bot (Polling)

import { BotClient, inlineKeyboard, markdown } from '@abdosaiko20/tg-sdk';

// Initialize bot
const bot = new BotClient({ 
  token: 'YOUR_BOT_TOKEN'
});

// Handle /start command
bot.on('message', async (msg) => {
  if (msg.text === '/start') {
    // Create beautiful inline keyboard
    const keyboard = inlineKeyboard()
      .text('🚀 Get Started', 'start')
      .url('🌐 Website', 'https://example.com')
      .row()
      .text('ℹ️ Help', 'help')
      .text('⭐ Premium', 'premium')
      .build();
    
    // Build formatted message
    const welcomeMsg = markdown()
      .bold('Welcome to My Bot!')
      .newLine()
      .text('Choose an option below:')
      .toString();

    await bot.sendMessage(msg.chat.id, welcomeMsg, {
      parse_mode: 'MarkdownV2',
      reply_markup: keyboard
    });
  }
});

// Start polling for updates
bot.startPolling();
console.log('🤖 Bot is running...');

🌐 Telegram Bot (Webhook)

import { BotClient, Router, Context } from '@abdosaiko20/tg-sdk';

const bot = new BotClient({ token: process.env.BOT_TOKEN! });
const router = new Router();

// Define routes
router.command('start', async (ctx) => {
  const c = ctx as Context;
  await c.replyWithMarkdown(
    markdown()
      .bold('Welcome!')
      .newLine()
      .text('I am a webhook-powered bot.')
      .toString()
  );
});

router.hears(/hello|hi|hey/i, async (ctx) => {
  const c = ctx as Context;
  await c.reply(`Hello, ${c.user?.first_name || 'there'}! 👋`);
});

router.action('premium', async (ctx) => {
  const c = ctx as Context;
  await c.answer('Opening premium features...');
  await c.edit('🌟 Premium features unlocked!');
});

// Connect router to bot
bot.on('message', async (update) => {
  const ctx = new Context({ update_id: 0, message: update } as any, bot);
  await router.middleware()(ctx, async () => {
    await bot.sendMessage(ctx.chatId!, 'Command not recognized. Try /start');
  });
});

// Setup webhook
await bot.setWebhook('https://your-domain.com/api/telegram', {
  secret_token: 'your-secret-token'
});

// Start webhook server
await bot.startWebhook({ 
  port: 3000, 
  path: '/api/telegram',
  secretToken: 'your-secret-token'
});

console.log('🌐 Webhook server running on port 3000');

📱 Telegram Mini App

import tg from '@abdosaiko20/tg-sdk';

// Initialize Mini App
tg.ready();
tg.expand();

// Get user information
const user = tg.user();
console.log(`👤 User: ${user?.first_name} ${user?.last_name}`);

// Theme support
const isDark = tg.isDark();
document.body.className = isDark ? 'dark-theme' : 'light-theme';

// Main Button with progress
tg.MainButton.setText('💾 Save Settings');
tg.MainButton.setColor('#4CAF50');
tg.MainButton.setTextColor('#FFFFFF');
tg.MainButton.show();

tg.MainButton.onClick(async () => {
  tg.MainButton.showProgress();
  
  try {
    // Save to cloud storage
    await tg.CloudStorage.set('settings', JSON.stringify({
      theme: isDark ? 'dark' : 'light',
      notifications: true
    }));
    
    tg.HapticFeedback.notificationOccurred('success');
    await tg.showAlert('✅ Settings saved successfully!');
  } catch (error) {
    tg.HapticFeedback.notificationOccurred('error');
    await tg.showAlert('❌ Failed to save settings');
  } finally {
    tg.MainButton.hideProgress();
  }
});

// Back button
tg.BackButton.show();
tg.BackButton.onClick(() => {
  tg.close();
});

⚛️ React Integration

import { useState } from 'react';
import {
  useTelegram,
  useTelegramUser,
  useTelegramTheme,
  useTelegramMainButton,
  useTelegramPopup,
  useTelegramHapticFeedback,
} from '@abdosaiko20/tg-sdk';

export default function MiniApp() {
  const { isMiniApp, platform } = useTelegram();
  const user = useTelegramUser();
  const { isDark, params } = useTelegramTheme();
  const mainButton = useTelegramMainButton();
  const popup = useTelegramPopup();
  const haptic = useTelegramHapticFeedback();
  const [count, setCount] = useState(0);

  // Configure main button
  useEffect(() => {
    if (isMiniApp) {
      mainButton.setText(`🎯 Clicks: ${count}`);
      mainButton.setColor(isDark ? '#8774E1' : '#6C5CE7');
      mainButton.show();
      
      mainButton.onClick(async () => {
        haptic.impactOccurred('light');
        setCount(prev => prev + 1);
        
        if (count >= 10) {
          const confirmed = await popup.confirm('🏆 Reset counter?');
          if (confirmed) setCount(0);
        }
      });
    }
  }, [isMiniApp, count, isDark]);

  if (!isMiniApp) {
    return <div>Please open in Telegram</div>;
  }

  return (
    <div style={{
      backgroundColor: isDark ? params.bg_color : '#FFFFFF',
      color: isDark ? params.text_color : '#000000',
      minHeight: '100vh',
      padding: '24px',
      fontFamily: '-apple-system, BlinkMacSystemFont, sans-serif'
    }}>
      <header style={{ textAlign: 'center', marginBottom: '40px' }}>
        <h1 style={{ fontSize: '2rem', margin: '0 0 8px' }}>
          👋 Hello, {user?.first_name || 'User'}!
        </h1>
        <p style={{ opacity: 0.7 }}>
          Platform: {platform} • Theme: {isDark ? '🌙 Dark' : '☀️ Light'}
        </p>
      </header>

      <main style={{ textAlign: 'center' }}>
        <div style={{
          background: isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.05)',
          borderRadius: '20px',
          padding: '40px',
          marginBottom: '20px'
        }}>
          <h2 style={{ fontSize: '4rem', margin: '0' }}>{count}</h2>
          <p style={{ opacity: 0.6 }}>Button Clicks</p>
        </div>
      </main>
    </div>
  );
}

💰 Telegram Stars (Payments)

import { BotClient } from '@abdosaiko20/tg-sdk';

const bot = new BotClient({ token: 'YOUR_BOT_TOKEN' });

// Handle invoice creation
bot.on('message', async (msg) => {
  if (msg.text === '/premium') {
    await bot.sendStarsInvoice(msg.chat.id, {
      title: '⭐ Premium Access',
      description: 'Unlock all premium features for 1 month',
      payload: 'premium_monthly',
      prices: [{ label: 'Premium', amount: 100 }],
      max_tip_amount: 200,
      suggested_tip_amounts: [100, 150, 200],
      photo_url: 'https://example.com/premium-banner.jpg',
      need_name: true,
      need_email: true,
    });
  }
});

// Handle pre-checkout
bot.on('pre_checkout_query', async (query) => {
  await bot.answerPreCheckoutQuery(query.id, true);
});

// Handle successful payment
bot.on('message', async (msg) => {
  if (msg.successful_payment) {
    await bot.sendMessage(
      msg.chat.id,
      '🎉 Thank you for your purchase! Premium features activated.'
    );
    
    // Refund example (if needed)
    // await bot.refundStarPayment(
    //   msg.from!.id,
    //   msg.successful_payment.telegram_payment_charge_id
    // );
  }
});

📡 Broadcast System

const results = await bot.broadcast(
  'sendMessage',
  { 
    text: '🔔 Important Announcement!',
    parse_mode: 'HTML'
  },
  {
    chatIds: [123456789, 987654321, 555555555],
    concurrency: 10,
    delay: 500,
    stopOnError: false,
    onStart: (total) => {
      console.log(`📡 Broadcasting to ${total} users...`);
    },
    onProgress: (current, total) => {
      const percent = ((current / total) * 100).toFixed(1);
      console.log(`Progress: ${current}/${total} (${percent}%)`);
    },
    onSuccess: (chatId, result) => {
      console.log(`✅ Sent to ${chatId}`);
    },
    onError: (chatId, error) => {
      console.error(`❌ Failed for ${chatId}:`, error.message);
    },
    onFinish: (results) => {
      const success = results.filter(r => r.success).length;
      const failed = results.length - success;
      console.log(`
📊 Broadcast Complete:
  ✅ Success: ${success}
  ❌ Failed: ${failed}
  📈 Success Rate: ${((success / results.length) * 100).toFixed(1)}%
      `);
    }
  }
);

🔧 Advanced Examples

Session Management with Redis

import { BotClient, SessionManager, Context } from '@abdosaiko20/tg-sdk';
import Redis from 'ioredis';

const redis = new Redis();
const bot = new BotClient({ token: 'TOKEN' });

// Redis session storage
const session = new SessionManager({
  get: async (key) => {
    const data = await redis.get(`session:${key}`);
    return data ? JSON.parse(data) : null;
  },
  set: async (key, data) => {
    await redis.set(`session:${key}`, JSON.stringify(data), 'EX', 3600);
  },
  delete: async (key) => {
    await redis.del(`session:${key}`);
  }
});

// Apply session middleware
bot.use(session.middleware());

// Use sessions in handlers
bot.on('message', async (update) => {
  const ctx = new Context({ update_id: 0, message: update } as any, bot);
  
  // Initialize session
  ctx.session = ctx.session || {};
  ctx.session.visits = (ctx.session.visits || 0) + 1;
  ctx.session.lastVisit = Date.now();
  
  await ctx.reply(
    `📊 Visit #${ctx.session.visits}\n` +
    `🕐 Last visit: ${new Date(ctx.session.lastVisit).toLocaleString()}`
  );
});

bot.startPolling();

Custom Plugin System

import { PluginSystem, MiddlewareContext } from '@abdosaiko20/tg-sdk';

const plugins = new PluginSystem();

// Analytics plugin
plugins.use(async (ctx: MiddlewareContext, next) => {
  const startTime = Date.now();
  const user = (ctx as any).user;
  
  console.log(`📊 [Analytics] User ${user?.id} started`);
  
  await next();
  
  const duration = Date.now() - startTime;
  console.log(`📊 [Analytics] Completed in ${duration}ms`);
  
  // Send to your analytics service
  await fetch('https://analytics.example.com/track', {
    method: 'POST',
    body: JSON.stringify({
      userId: user?.id,
      duration,
      timestamp: Date.now()
    })
  });
});

// Rate limiter plugin
plugins.use(async (ctx: MiddlewareContext, next) => {
  const user = (ctx as any).user;
  const userId = user?.id?.toString() || 'anonymous';
  
  // Simple in-memory rate limiting
  const key = `rate_limit:${userId}`;
  const requests = (globalThis as any).__rateLimitCache?.get(key) || 0;
  
  if (requests > 30) {
    throw new Error('Rate limit exceeded');
  }
  
  if (!(globalThis as any).__rateLimitCache) {
    (globalThis as any).__rateLimitCache = new Map();
  }
  
  (globalThis as any).__rateLimitCache.set(key, requests + 1);
  setTimeout(() => {
    (globalThis as any).__rateLimitCache.delete(key);
  }, 60000);
  
  await next();
});

// Apply plugins
bot.use(plugins.middleware());

Next.js Route Handler (Full Example)

// app/api/telegram/route.ts
import { BotClient, Router, Context } from '@abdosaiko20/tg-sdk';
import { NextResponse } from 'next/server';

const bot = new BotClient({ token: process.env.TELEGRAM_BOT_TOKEN! });
const router = new Router();

// Setup routes
router.command('start', async (ctx) => {
  const c = ctx as Context;
  await c.reply('Welcome to Next.js Telegram Bot! 🚀');
});

router.hears('status', async (ctx) => {
  const c = ctx as Context;
  const me = await bot.getMe();
  await c.reply(`Bot Status:\n• Name: ${me.first_name}\n• Username: @${me.username}`);
});

// Webhook handler
export async function POST(request: Request) {
  try {
    const update = await request.json();
    
    // Create context and process
    const ctx = new Context(update, bot);
    await router.middleware()(ctx, async () => {
      // Default handler
      if (update.message?.chat?.id) {
        await bot.sendMessage(update.message.chat.id, 'Command not recognized');
      }
    });
    
    return NextResponse.json({ ok: true });
  } catch (error) {
    console.error('Webhook error:', error);
    return NextResponse.json({ ok: false }, { status: 500 });
  }
}

// Webhook setup
export async function GET() {
  const webhookUrl = `${process.env.VERCEL_URL}/api/telegram`;
  
  await bot.setWebhook(webhookUrl, {
    secret_token: process.env.WEBHOOK_SECRET
  });
  
  return NextResponse.json({ 
    ok: true, 
    webhook: webhookUrl 
  });
}

📚 Complete API Reference

BotClient Methods

| Method | Description | Options | |--------|-------------|---------| | sendMessage(chatId, text, options?) | Send text message | parse_mode, reply_markup, disable_notification, etc. | | sendPhoto(chatId, photo, options?) | Send photo | caption, has_spoiler, reply_markup | | sendVideo(chatId, video, options?) | Send video | duration, width, height, supports_streaming | | sendAudio(chatId, audio, options?) | Send audio | performer, title, thumbnail | | sendDocument(chatId, document, options?) | Send document | thumbnail, disable_content_type_detection | | sendAnimation(chatId, animation, options?) | Send animation/GIF | duration, has_spoiler | | sendVoice(chatId, voice, options?) | Send voice note | duration | | sendVideoNote(chatId, videoNote, options?) | Send video note | duration, length | | sendMediaGroup(chatId, media, options?) | Send media group | Array of InputMedia | | sendLocation(chatId, lat, lon, options?) | Send location | live_period, heading | | sendVenue(chatId, lat, lon, title, addr) | Send venue | foursquare_id, google_place_id | | sendContact(chatId, phone, name, options?) | Send contact | vcard | | sendPoll(chatId, question, options) | Send poll | type, allows_multiple_answers | | sendDice(chatId, options?) | Send dice/emoji | emoji (🎲, 🎯, 🏀, ⚽, 🎳, 🎰) | | sendSticker(chatId, sticker, options?) | Send sticker | emoji | | sendChatAction(chatId, action) | Send typing/broadcast action | typing, upload_photo, etc. |

| Method | Description | |--------|-------------| | editMessageText(chatId, msgId, text, options?) | Edit message text | | editMessageCaption(chatId, msgId, options?) | Edit media caption | | editMessageMedia(chatId, msgId, media) | Edit message media | | editMessageReplyMarkup(chatId, msgId, markup) | Edit inline keyboard | | deleteMessage(chatId, msgId) | Delete message | | deleteMessages(chatId, msgIds[]) | Delete multiple messages | | stopPoll(chatId, msgId) | Stop a running poll |

| Method | Description | |--------|-------------| | getChat(chatId) | Get chat information | | getChatAdministrators(chatId) | Get chat admins | | getChatMemberCount(chatId) | Get member count | | getChatMember(chatId, userId) | Get specific member | | banChatMember(chatId, userId) | Ban member | | unbanChatMember(chatId, userId) | Unban member | | restrictChatMember(chatId, userId, perms) | Restrict member | | promoteChatMember(chatId, userId, opts) | Promote to admin | | setChatPermissions(chatId, permissions) | Set default permissions | | setChatTitle(chatId, title) | Change chat title | | setChatDescription(chatId, desc) | Change description | | setChatPhoto(chatId, photo) | Change chat photo | | deleteChatPhoto(chatId) | Remove chat photo | | pinChatMessage(chatId, msgId) | Pin message | | unpinChatMessage(chatId, msgId?) | Unpin message | | leaveChat(chatId) | Bot leaves chat |

| Method | Description | |--------|-------------| | sendInvoice(chatId, ...) | Send payment invoice | | createInvoiceLink(...) | Create invoice link | | answerShippingQuery(id, ok, opts) | Answer shipping query | | answerPreCheckoutQuery(id, ok, opts) | Answer pre-checkout | | createStarsInvoice(params) | Create Stars invoice link | | sendStarsInvoice(chatId, params) | Send Stars invoice | | refundStarPayment(userId, chargeId) | Refund Stars payment |

| Method | Description | |--------|-------------| | startPolling(options?) | Start long polling | | stopPolling() | Stop polling | | setWebhook(url, options?) | Set webhook URL | | deleteWebhook(options?) | Remove webhook | | getWebhookInfo() | Get webhook status | | startWebhook(options?) | Start webhook server | | stopWebhook() | Stop webhook server |


🎨 Keyboard Builders

Inline Keyboard

import { inlineKeyboard } from '@abdosaiko20/tg-sdk';

const keyboard = inlineKeyboard()
  .text('🚀 Action', 'action_1')
  .url('🌐 Visit Site', 'https://example.com')
  .row()
  .webApp('📱 Open App', 'https://app.example.com')
  .login('🔑 Login', { url: 'https://auth.example.com' })
  .row()
  .switchInline('📤 Share', 'check this out')
  .switchInlineCurrentChat('💬 Share Here', 'look')
  .row()
  .pay('⭐ Pay 100 Stars')
  .build();

Reply Keyboard

import { replyKeyboard, removeKeyboard, forceReply } from '@abdosaiko20/tg-sdk';

const keyboard = replyKeyboard()
  .text('📊 Stats')
  .text('⚙️ Settings')
  .row()
  .requestContact('📞 Share Contact')
  .requestLocation('📍 Share Location')
  .row()
  .requestPoll('📋 Create Poll')
  .webApp('🚀 Launch App', 'https://app.example.com')
  .resize()
  .oneTime()
  .placeholder('Choose an option...')
  .build();

// Remove keyboard
const remove = removeKeyboard();

// Force reply
const force = forceReply('Enter your name...');

📝 Formatters

MarkdownV2

import { markdown, ParseMode } from '@abdosaiko20/tg-sdk';

const message = markdown()
  .bold('Important Announcement')
  .newLine()
  .newLine()
  .text('We are excited to share ')
  .italic('amazing news')
  .text(' with you!')
  .newLine()
  .newLine()
  .spoiler('Spoiler: Something big is coming!')
  .newLine()
  .newLine()
  .link('👉 Learn More', 'https://example.com')
  .toString();

await bot.sendMessage(chatId, message, {
  parse_mode: ParseMode.MarkdownV2
});

HTML

import { html } from '@abdosaiko20/tg-sdk';

const message = html()
  .bold('Welcome!')
  .newLine()
  .text('This is ')
  .italic('italic')
  .text(' and this is ')
  .underline('underlined')
  .text('.')
  .newLine()
  .newLine()
  .pre('const greeting = "Hello World";\nconsole.log(greeting);', 'javascript')
  .newLine()
  .link('🔗 Documentation', 'https://docs.example.com')
  .toString();

await bot.sendMessage(chatId, message, {
  parse_mode: 'HTML'
});

⚛️ React Hooks Reference

| Hook | Description | Returns | |------|-------------|---------| | useTelegram() | Core Telegram info | { isTelegram, isMiniApp, platform, version } | | useTelegramUser() | Current user data | TelegramUser \| null | | useTelegramTheme() | Theme information | { params, isDark } | | useTelegramMainButton() | Main button controls | { show, hide, setText, onClick, ... } | | useTelegramBackButton() | Back button controls | { show, hide, onClick } | | useTelegramSettingsButton() | Settings button | { show, hide, onClick } | | useTelegramViewport() | Viewport info | { height, width, isExpanded, ... } | | useTelegramPopup() | Popup dialogs | { show, alert, confirm } | | useTelegramHapticFeedback() | Haptic feedback | { impactOccurred, notificationOccurred } | | useTelegramCloudStorage() | Cloud storage | { get, set, remove, loading, error } | | useTelegramClipboard() | Clipboard access | { copy, read } | | useTelegramEvent(event, cb) | Event listener | void |


🌐 Platform Support

| Platform | Support | Notes | |----------|---------|-------| | Node.js 18+ | ✅ Full | All features supported | | Node.js 20+ | ✅ Full | Recommended | | Node.js 22+ | ✅ Full | Latest LTS | | Deno | ✅ Full | Import from npm | | Bun | ✅ Full | Native support | | Cloudflare Workers | ✅ | Webhook mode only | | Vercel Edge | ✅ | Route handlers | | React 16.8+ | ✅ | All hooks | | Next.js 13+ | ✅ | App & Pages Router | | Vue 3 | ✅ | Composition API | | Svelte/SvelteKit | ✅ | Full support | | Angular 12+ | ✅ | Services | | Nuxt 3 | ✅ | Auto-import |


💖 Support the Project


📄 License

MIT © @abdosaiko20


🔗 Links