media-cache

reuse a file_id instead of re-uploading the same file. the first send uploads the local file and stores the returned file_id; every subsequent send under the same key skips the upload entirely.

installation

terminal
pnpm add @yaebal/media-cache

basic usage

create a MediaCache instance with mediaCache(), then call cache.photo or cache.document instead of ctx.sendPhoto / ctx.sendDocument directly. supply a stable string key to identify each asset.

bot.ts
import { Bot } from "@yaebal/core";
import { mediaCache } from "@yaebal/media-cache";
import { media } from "@yaebal/core";

const bot = new Bot(token);
const cache = mediaCache(); // defaults to in-memory storage

bot.command("logo", async (ctx) => {
  // first call: uploads the file and stores its file_id under "logo"
  // subsequent calls: skips the upload, sends the cached file_id instead
  await cache.photo(ctx, "logo", media.path("./assets/logo.png"));
});

how caching works

on the first call for a key the source is sent as-is (a path, url, or buffer). telegram returns a message containing the uploaded file's file_id. media-cache stores that id under your key. on the next call it calls media.fileId(cached) instead — no upload, just the id.

for photos, the last (largest) size in the array is cached — that's the highest-quality variant telegram returns.

persistent storage

the default storage is in-memory and lost on restart. pass any StorageAdapter<string> from @yaebal/session to persist across restarts.

bot.ts
import { mediaCache } from "@yaebal/media-cache";
import { RedisStorage } from "./my-redis-storage.js"; // your StorageAdapter<string>

const cache = mediaCache({ storage: new RedisStorage() });

documents

send-doc.ts
import { media } from "@yaebal/core";

// send a PDF and cache it under "report-2024"
await cache.document(ctx, "report-2024", media.path("./report.pdf"), {
  caption: "Q4 report",
});

independent keys

keys are caller-supplied strings. distinct keys always cache independently — useful for per-locale or per-variant assets.

keys.ts
// "logo-en" and "logo-ru" are independent — distinct keys cache independently
await cache.photo(ctx, "logo-en", media.path("./logo-en.png"));
await cache.photo(ctx, "logo-ru", media.path("./logo-ru.png"));

api

exportkinddescription
mediaCache(options?)functioncreates a MediaCache instance
MediaCacheinterfacethe object returned by mediaCache()
MediaCacheOptionsinterfacestorage?: StorageAdapter<string>

MediaCache methods

methoddescription
photo(ctx, key, source, extra?)send a photo, caching the file_id under key
document(ctx, key, source, extra?)send a document, caching its file_id under key
source accepts anything @yaebal/core's MediaSource accepts — media.path(), media.url(), media.buffer(), or a bare file_id string. extra is forwarded as send options (caption, parse_mode, etc.).