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

@decogram/framework

v0.0.11

Published

Meta-based Telegram Bot Programming

Readme

Decogram Framework

Decogram is a meta-based framework for building Telegram bots with TypeScript. It’s designed to be declarative, modular, and developer-friendly, leveraging decorators, dependency injection, and Telegraf under the hood.


📚 Table of Contents


📘 Introduction

Decogram is a modern and declarative framework for Telegram bot development in TypeScript. It wraps around Telegraf and introduces decorators, dependency injection, and modular architecture to simplify and structure your bot logic.


🚀 Key Features

  • Decorator-Driven configuration
  • 🔧 Dependency Injection with lifecycle management
  • 📦 Modular Handlers for commands, messages, and buttons
  • 🔐 Middleware Support (global and scoped)
  • 🧠 Hierarchical Session Contexts
  • 🧰 Error Handling at method and class level
  • 🖨️ Structured Logging via pino
  • 🔄 Polling/Webhook update strategies

Getting Started

Prerequisites

  • Node.js 20+
  • npm or Yarn
  • Telegram Bot Token from @BotFather

Project Setup

mkdir my-decogram-bot
cd my-decogram-bot
npm init -y

Installation

npm install @decogram/framework telegraf express pino pino-pretty reflect-metadata
npm install -D typescript @types/node resolve-tspaths

TypeScript Configuration

// tsconfig.json
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "baseUrl": "./",
    "paths": {
      "@handlers/*": ["src/handlers/*"],
      "@services/*": ["src/services/*"]
    }
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}

Project Structure

my-decogram-bot/
├── src/
│   ├── handlers/
│   │   ├── message/
│   │   │   └── hello.handler.ts
│   │   └── error/
│   │       └── global.handler.ts
│   ├── middleware/
│   │   └── auth.middleware.ts
│   ├── services/
│   │   └── example.service.ts
│   ├── sessions/
│   │   └── user.context.ts
│   └── index.ts
├── package.json
├── tsconfig.json

Obtaining Your Bot Token

  1. Open Telegram.
  2. Search for @BotFather.
  3. Send /newbot and follow the instructions.
  4. Copy and store the token securely.

Running Your First Bot

npx tsc
npx resolve-tspaths --project tsconfig.json
node dist/index.js

Create Initial Setup With CLI

  npx @decogram/framework new my-new-project

It'll create a new project with the initial setup for you in order to skip the manual installation process

🧠 Core Concepts

@TelegramMaster

Defines the bot's main configuration.

@TelegramMaster({
  updatedFetchStrategy: {
    type: "POLLING",
    data: { botToken: "YOUR_BOT_TOKEN" }
  },
  messageListeners: [HelloHandler],
  callbackQueryListeners: [],
  sessionContexts: [],
  middlewares: []
})
class Master {}

@MessageHandler

Marks a class as a Handler of type MessageHandler:

@MessageHandler()
export class HelloHandler {
  constructor(@SendMessage private readonly send: TSendMessage) {}

  @OnCommand("/start")
  start(@Message msg: Context["message"]) {
    this.send("Hello, " + (msg?.from?.first_name ?? "Guest"));
  }
}

@CallbackHandler

Marks a class as a Handler of type CallbackHandler:

@CallbackHandler()
export class HelloHandler {
  constructor(@SendMessage private readonly send: TSendMessage) {}

  @OnClick("start")
  start(@Message msg: Context["message"]) {
    this.send("Hello, " + (msg?.from?.first_name ?? "Guest"));
  }
}

Message Handlers

  • @OnMessage(predicates?): Matches any message
  • @OnCommand("/start"): Matches a specific command
  • @OnAnything: Matches all messages (fallback)

Callback Query Handlers

  • @OnCallbackQuery(predicates?): Matches button callbacks
  • @OnClick("button_data"): Exact match for button data

Context Predicates

const onlyHumans: ContextPredicate = ctx => !ctx.from?.is_bot;

Use them in @OnMessage([predicate1, predicate2]).


Dependency Injection

Supports DI in classes and methods.

@Service()
export class MyService {
  hello() {
    return "Hello from service";
  }
}

@MessageHandler()
export class SomeHandler {
  constructor(@Autowired private readonly svc: MyService) {}

  @OnCommand("/hi")
  hi(@SendMessage send: TSendMessage) {
    send(this.svc.hello());
  }
}

Parameter Injection

  • @SendMessage: Sends a message
  • @Message: Gets the raw message
  • @Session: Injects a session context

Middleware

@Middleware()
export class AuthMiddleware implements MiddlewareHandler {
  async reject(ctx: Context): Promise<boolean> {
    if (ctx.from?.id !== 123456789) {
      ctx.reply("Not authorized.");
      return true;
    }
    return false;
  }
}

Apply globally via @TelegramMaster or locally via @Handler.


Middleware Chaining

@Middleware({ next: RateLimitMiddleware })
export class LoggingMiddleware implements MiddlewareHandler {
  async reject(ctx: Context) {
    console.log("User:", ctx.from?.id);
    return false;
  }
}

Session Contexts

@SessionContext
export class UserContext implements ISessionContext {
  private userId!: number;

  loadContext(ctx: Context) {
    this.userId = ctx.from?.id ?? -1;
  }

  getUserId() {
    return this.userId;
  }
}

Hierarchical Session Contexts

You can inject one session context into another:

@SessionContext
export class SettingsContext implements ISessionContext {
  constructor(@Session private readonly user: UserContext) {}

  loadContext(ctx: Context) {
    const id = this.user.getUserId();
    // Load user settings from DB...
  }
}

Error Handling

@ErrorHandler((ctx, err) => {
  console.error("Error:", err);
  ctx.reply("Something went wrong.");
})
@MessageHandler()
export class SafeHandler {
  @OnCommand("/fail")
  fail() {
    throw new Error("Failure");
  }
}

Use @MethodErrorHandler() for method-specific errors.


Logging

Decogram uses pino. You can extend or replace loggers if needed. By default, all core events are logged.


Update Fetching Strategies

// Polling
type: "POLLING",
data: { botToken: "YOUR_TOKEN" }

// Webhook
type: "WEBHOOK",
data: {
  botToken: "YOUR_TOKEN",
  listenOnPort: 3000,
  callbackAfterRegister: async (token, port) => {
    await bot.telegram.setWebhook(`https://your-domain.com/telegram/${token}`);
  }
}

📦 Basic Example: The Hello Bot

import { bootstrap } from "decogram/core/bootstrap";
import { CallbackHandler, TelegramMaster } from "decogram/core/decorators/io/class";
import { OnCommand } from "decogram/core/decorators/io/method";
import { SendMessage } from "decogram/core/decorators/io/parameter";
import { TSendMessage } from "decogram/core/types";
import { Context } from "telegraf";

@MessageHandler()
class HelloHandler {
  constructor(@SendMessage private readonly send: TSendMessage) {}

  @OnCommand("/start")
  start(@Message msg: Context["message"]) {
    this.send("Hello, " + (msg?.from?.first_name ?? "Guest") + "!");
  }
}

@TelegramMaster({
  updatedFetchStrategy: {
    type: "POLLING",
    data: { botToken: "YOUR_BOT_TOKEN" }
  },
  messageListeners: [HelloHandler]
})
class Master {}

bootstrap(Master);

📖 API Reference

| Decorator / Interface | Type | Description | |-------------------------|------------|---------------------------------------------| | @TelegramMaster | Class | Root bot configuration | | @Handler | Class | Registers a handler | | @OnMessage | Method | Handles messages with optional predicates | | @OnCommand | Method | Handles /command messages | | @OnAnything | Method | Catch-all message handler | | @OnCallbackQuery | Method | Handles callback queries | | @OnClick | Method | Handles inline button clicks | | @SendMessage | Parameter | Injects reply method | | @Message | Parameter | Injects raw message | | @Session | Parameter | Injects session context | | @Service | Class | Declares a DI service | | @Autowired | Parameter | Injects a DI service | | @Middleware | Class | Declares middleware | | @ErrorHandler | Class | Class/Method-level error handling |


Happy coding with Decogram! 🚀
Want to contribute? Open a PR or star the project!