Skip to content

Devtools ​

@vibegram/devtools records sanitized update snapshots, middleware timing spans, outgoing Telegram API call logs, and replay fixtures for local debugging.

Use it when a bug only happens with real Telegram updates, when you need a minimal fixture for a regression test, or when middleware performance needs a simple timing trail.

Official Telegram Mapping ​

This plugin records Telegram Update-like objects already delivered to your bot and can replay those objects into a bot-like handleUpdate(update) target.

It does not call Telegram by itself. It wraps ctx.client.callApi() during the current update to log method names, sanitized request payloads, duration, success/failure, and optionally sanitized responses.

References: Telegram Bot API Update, getUpdates, and Making requests.

Install ​

When this official plugin package is published, install it from npm:

bash
npm install vibegram @vibegram/devtools

Today, use the repository package as a local file dependency:

json
{
  "dependencies": {
    "vibegram": "^2.5.0",
    "@vibegram/devtools": "file:../vibegram/plugins/devtools"
  }
}

Minimal Usage ​

typescript
import { Bot } from 'vibegram';
import { devtools } from '@vibegram/devtools';

const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) throw new Error('TELEGRAM_BOT_TOKEN is required');

const bot = new Bot(token);

bot.use(devtools({
    capture: process.env.NODE_ENV !== 'production',
    jsonlPath: '.vibegram/events.jsonl',
    redact: ['session', 'authorization'],
}));

await bot.launch();

If capture is omitted, devtools records outside production and does nothing when NODE_ENV=production.

Captured Events ​

Devtools writes JSON events to a sink. The built-in JSONL sink writes one event per line:

typescript
bot.use(devtools({
    capture: true,
    jsonlPath: '.vibegram/events.jsonl',
}));

Common event types:

TypeMeaning
updateSanitized update snapshot
apiTelegram API method, request, duration, and result status
timingMiddleware timing span
errorSanitized thrown error metadata

The default redacted keys include token, bot_token, access_token, authorization, secret_token, cookie, password, api_key, secret, and prompt.

Timing Spans ​

Use ctx.devtools.time() inside handlers:

typescript
bot.command('report', async ctx => {
    const data = await ctx.devtools.time('load-report-data', () => loadReport(ctx.from.id));
    await ctx.reply(renderReport(data));
});

Or wrap a middleware:

typescript
import { withDevtoolsTiming } from '@vibegram/devtools';

bot.use(withDevtoolsTiming('auth', authMiddleware));

Every captured update also emits a timing event named update.

API Logs ​

Devtools wraps the scoped ctx.client.callApi() for the current update:

typescript
bot.use(devtools({
    capture: true,
    includeApiResult: false,
}));

includeApiResult defaults to false because Telegram responses can include user data. Enable it only while debugging and rely on sanitizer redaction.

Replay ​

Use createReplayFixture() to export one sanitized update for a test:

typescript
import { createReplayFixture, replayUpdates } from '@vibegram/devtools';

const fixture = createReplayFixture(ctx.update);

await replayUpdates(bot, [fixture]);

replayUpdates() accepts either a function:

typescript
await replayUpdates(update => bot.handleUpdate(update), [fixture]);

or a bot-like object:

typescript
await replayUpdates(bot, [fixture]);

For JSONL files captured by the sink:

typescript
import { replayJsonl } from '@vibegram/devtools';

await replayJsonl(bot, '.vibegram/events.jsonl');

Options ​

OptionTypeDefaultDescription
captureboolean | (ctx) => boolean | Promise<boolean>disabled in productionControls whether an update is captured
envstringprocess.env.NODE_ENVUsed for production default detection
sinkDevtoolsSinkconsole sinkCustom event sink
jsonlPathstringnoneWrites events to JSONL when sink is omitted
redactstring[]sensitive defaultsAdditional keys to redact
replacementstring[REDACTED]Replacement for redacted values
maxDepthnumber12Maximum sanitizer traversal depth
includeApiResultbooleanfalseInclude sanitized API responses
failOnSinkErrorbooleanfalseThrow if sink writing fails
clock() => numberDate.nowCustom clock for tests

TypeScript ​

Use DevtoolsFlavor when custom context code accesses ctx.devtools:

typescript
import type { DevtoolsFlavor } from '@vibegram/devtools';

type MyContext = DevtoolsFlavor<Context>;

async function profile(ctx: MyContext) {
    return ctx.devtools.time('profile', () => loadProfile(ctx.from.id));
}

The package also exports DevtoolsSink, DevtoolsLogEvent, DevtoolsUpdate, MemoryDevtoolsSink, createJsonlSink(), createConsoleSink(), readJsonlReplay(), replayJsonl(), and sanitizeValue().

Failure Modes ​

  • Sink write failures are ignored by default so debug tooling does not break bot handling.
  • Set failOnSinkError: true in tests when the sink itself must be validated.
  • Captured fixtures are sanitized clones; non-JSON values such as functions become markers.
  • Replay does not contact Telegram. It only feeds saved update objects back into local code.

Security Notes ​

Do not store raw production updates unless you have a retention policy and explicit user-data handling rules. Telegram updates can contain names, usernames, message text, file IDs, locations, and payment-related data.

Keep capture disabled in production unless a debugging window is intentional. Add project-specific redaction keys for sessions, auth headers, prompts, internal IDs, and business payloads before writing JSONL files.

Validation ​

The package includes tests for sanitized update capture, replay fixtures, middleware timing, API log redaction, production capture defaults, JSONL writing, and timing wrappers.

bash
npm run plugins:validate
npm run docs:build

Released under the ISC License.