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

inbash-search

v1.0.0

Published

Full Telegram search and indexing engine for inbash — indexes messages, channels, topics, hashtags, and media via MTProto with real-time updates

Readme

inbash-search

Full Telegram search and indexing engine for inbash.

Indexes all accessible Telegram content — messages, channels, groups, forum topics, hashtags, and media captions — entirely over MTProto. No external database required.


Overview

Telegram messages    →  inverted full-text index
Hashtags (#python)   →  tag index
Channels / Chats     →  chat index
Users                →  user index
───────────────────────────────────────
Ranking              →  recency × relevance × frequency × channel weight
Stats                →  live aggregates from in-memory index

Installation

npm install inbash inbash-search
# or
pnpm add inbash inbash-search

Node.js ≥ 18 required. inbash is a peer dependency.


Quick Start

import { InbashCore } from "inbash";
import { InbashSearch } from "inbash-search";

const shell = new InbashCore({
  sessions: [
    {
      id: "primary",
      kind: "user",
      credential: process.env.TG_SESSION!,
      apiId: Number(process.env.TG_API_ID),
      apiHash: process.env.TG_API_HASH!,
    },
  ],
});

const search = new InbashSearch(shell);

await shell.connect();

// Crawl all accessible dialogs and build the index
await search.startIndexing();

// Full-text search
const results = await search.search("typescript tutorial");
for (const { record, score, highlights } of results.results) {
  console.log(`[${score.toFixed(3)}] ${record.chatTitle}: ${highlights[0]}`);
}

// Search by hashtag
const tagged = await search.searchTag("#python");

// Search within a channel
const channel = await search.searchChannel("-1001234567890", "deployment");

// Search by user
const byUser = await search.searchUser("123456789");

// Index statistics
const stats = await search.getStats();
console.log(`Indexed ${stats.totalMessages} messages across ${stats.totalChats} chats`);

Integration with inbash Shell

const shell = new InbashCore({ sessions: [...] });
const search = new InbashSearch(shell);

await shell.connect();
await search.startIndexing();

// Use the shell to navigate the FS
const { output } = await shell.exec("ls /");
console.log(output);

// Use search to find content across all chats
const results = await search.search("python asyncio");

Real-Time Indexing

startIndexing() automatically listens to new messages via InbashCore's event bus and indexes them as they arrive — no polling required.

await search.startIndexing();

// New messages are indexed automatically as they come in
shell.events.on("message", (event) => {
  console.log(`Indexed new message ${event.messageId} from chat ${event.chatId}`);
});

// Stop when done
search.stopIndexing();

Pagination

All search methods support limit and offset for lazy loading:

const page1 = await search.search({ text: "crypto", limit: 10, offset: 0 });
const page2 = await search.search({ text: "crypto", limit: 10, offset: 10 });

if (page1.hasMore) {
  // fetch next page
}

Combined Filters

const results = await search.search({
  text: "release",
  tag: "python",
  chatId: "-1001234567890",
  after: Math.floor(Date.now() / 1000) - 7 * 86400,  // last 7 days
  limit: 20,
  offset: 0,
});

Statistics

const stats = await search.getStats();
// {
//   totalMessages: 42183,
//   totalChats: 87,
//   totalChannels: 23,
//   totalGroups: 64,
//   totalTags: 312,
//   topTags: [{ tag: "python", count: 1024 }, ...],
//   topChats: [{ chatId: "-100...", chatTitle: "TypeScript News", count: 5821 }, ...],
//   oldestMessage: 1680000000,
//   newestMessage: 1748390400,
// }
// Per-chat activity over last 14 days
const activity = search.stats.getChatActivity("-1001234567890", 14);
// [{ day: "2026-05-14", count: 42 }, ...]

// Command usage stats
const cmdStats = search.stats.getCommandStats();
// { ls: 12, cd: 7, fetch: 31, ... }

Custom Ranking Weights

import { InbashSearch } from "inbash-search";

const search = new InbashSearch(shell, {
  ranking: {
    recency:           0.50,  // prioritise recent messages
    relevance:         0.35,
    frequency:         0.05,
    channelImportance: 0.10,
  },
});

Weights are normalised at runtime — they don't need to sum to 1.0 but will be applied as-is.


External Cache Adapter

By default, results are memoised in an LRU memory cache (30s TTL). You can plug in any external store:

import type { CacheAdapter } from "inbash-search";
import Redis from "ioredis";

const redis = new Redis();

const redisAdapter: CacheAdapter = {
  async get(key)             { const v = await redis.get(key); return v ? JSON.parse(v) : null; },
  async set(key, value, ttl) { await redis.set(key, JSON.stringify(value), "PX", ttl ?? 30000); },
  async del(key)             { await redis.del(key); },
  async clear()              { await redis.flushdb(); },
};

const search = new InbashSearch(shell, { cacheAdapter: redisAdapter });

API Reference

InbashSearch / SearchEngine

| Method | Returns | Description | |--------|---------|-------------| | startIndexing() | Promise<void> | Crawl all dialogs + start real-time indexing | | stopIndexing() | void | Stop real-time indexing | | search(query) | Promise<SearchResponse> | Full-text + filter search | | searchTag(tag, opts?) | Promise<PaginatedResponse> | Hashtag search | | searchChannel(chatId, text?, opts?) | Promise<PaginatedResponse> | Channel-scoped search | | searchUser(userId, text?, opts?) | Promise<PaginatedResponse> | User-scoped search | | getStats() | Promise<IndexStats> | Aggregate index statistics | | clearCache() | Promise<void> | Invalidate all cached results |

Indexer

| Method | Description | |--------|-------------| | indexAll() | Crawl all dialogs | | indexDialog(client, dialog) | Index a single dialog | | ingestMessage(msg, chatId, ...) | Ingest a single message | | upsert(record) | Insert/update a record | | lookupTokens(tokens) | Inverted index lookup | | lookupTag(tag) | Tag index lookup | | lookupChat(chatId) | Chat index lookup | | lookupUser(fromId) | User index lookup |

RankingEngine

| Method | Description | |--------|-------------| | rank(records, query) | Score and sort records | | setWeights(weights) | Update ranking weights at runtime | | getWeights() | Return current weights |

StatsEngine

| Method | Description | |--------|---------| | getStats() | Full statistics snapshot | | getChatActivity(chatId, windowDays?) | Per-day message count | | getCommandStats(commands?) | Command usage counts |


Environment Variables

| Variable | Description | |----------|-------------| | TG_API_ID | Telegram API ID from my.telegram.org | | TG_API_HASH | Telegram API hash | | TG_SESSION | GramJS StringSession string |


License

MIT