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
Maintainers
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 indexInstallation
npm install inbash inbash-search
# or
pnpm add inbash inbash-searchNode.js ≥ 18 required.
inbashis 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
