Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions docs/extend/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,14 @@ const bot = new Bot(process.env.BOT_TOKEN as string)
## Build-Time Conditionals: when()

::: info Composer-level API
`when()` is available on `Composer` from `@gramio/composer`. Create your pipeline as a `Composer`, then pass it to `bot.extend()`.
`when()` is available on `Composer` from `gramio`. Create your pipeline as a `Composer`, then pass it to `bot.extend()`.
:::

Register middleware conditionally at **startup** (not per-request) using `when()`. The middleware is either registered or not — there's no runtime overhead:

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const pipeline = new Composer()
.when(
Expand All @@ -206,7 +206,7 @@ The real power comes when you extract common middleware into a **`Composer`** an

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

// ── shared middleware ─────────────────────────────────────────────────
const db = {
Expand All @@ -232,15 +232,15 @@ const bot = new Bot(process.env.BOT_TOKEN as string)
});
```

`Composer` from `@gramio/composer` is the building block for reusable middleware. Think of it as a named, extractable pipeline segment.
`Composer` from `gramio` is the building block for reusable middleware. Think of it as a named, extractable pipeline segment.

### Middleware order matters

Middleware runs in **registration order**. A `Composer` injects its middleware at the point where you call `.extend()`:

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const logger = new Composer().use(async (ctx, next) => {
console.log("before:", ctx.updateType);
Expand All @@ -261,7 +261,7 @@ Handlers defined inline always have correct types inferred. But when you extract

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const userMiddleware = new Composer().derive(() => ({
user: { name: "Alice", premium: true as boolean },
Expand Down Expand Up @@ -290,7 +290,7 @@ For simple handlers, keeping them inline in the chain is the most ergonomic —

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const db = {
getUser: (id: number) =>
Expand All @@ -314,7 +314,7 @@ const bot = new Bot(process.env.BOT_TOKEN as string)

```ts
// middleware/user.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
export const withUser = new Composer()
.derive(async (ctx) => ({ user: await db.getUser(ctx.from?.id ?? 0) }));

Expand All @@ -329,7 +329,7 @@ const bot = new Bot(TOKEN)

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const FEATURES = {
betaAnalytics: process.env.FEATURE_ANALYTICS === "true",
Expand Down Expand Up @@ -369,7 +369,7 @@ Name your shared Composer and mark it `.as("scoped")`. Both matter:

```ts
// middleware/user.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

export const db = {
getUser: (id: number) =>
Expand All @@ -394,7 +394,7 @@ export const withUser = new Composer({ name: "withUser" })

```ts
// routers/admin.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { withUser } from "../middleware/user";

export const adminRouter = new Composer({ name: "adminRouter" })
Expand All @@ -415,7 +415,7 @@ TypeScript infers `ctx.user` and `ctx.db` because `adminRouter` extends `withUse

```ts
// routers/chat.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { db, withUser } from "../middleware/user";

const withChat = new Composer({ name: "withChat" })
Expand Down Expand Up @@ -490,7 +490,7 @@ It only bites when two routers both call `next()` for the same update, which is
One DB query per update, `ctx.user` available everywhere.

::: tip `guard()` lives on Composer
`guard()` is available on `Composer` from `@gramio/composer`, not on `Bot` directly. That's why `adminRouter` is a `Composer` — it gets the full composition API — and is then passed to `bot.extend()`.
`guard()` is available on `Composer` from `gramio`, not on `Bot` directly. That's why `adminRouter` is a `Composer` — it gets the full composition API — and is then passed to `bot.extend()`.
:::

## Summary
Expand Down
21 changes: 11 additions & 10 deletions docs/guides/composer.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const bot = new Bot(token)
The difference: a `Composer` isn't a bot. It has no token, no API connection. It's a pipeline segment you compose into a bot with `.extend()`.

```ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

// A self-contained feature module
const adminRouter = new Composer()
Expand All @@ -72,7 +72,7 @@ The most common use: one file per feature.

```ts
// src/features/start.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

export const startRouter = new Composer()
.command("start", (ctx) => ctx.send("Hello! 👋"))
Expand All @@ -81,7 +81,7 @@ export const startRouter = new Composer()

```ts
// src/features/admin.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const ADMIN_ID = Number(process.env.ADMIN_ID);

Expand Down Expand Up @@ -113,7 +113,7 @@ Often multiple modules need the same data — a user record, config, a database

```ts
// src/middleware/user.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

export const withUser = new Composer()
.derive(async (ctx) => ({
Expand All @@ -126,7 +126,7 @@ Extend it in your feature module to get the type:

```ts
// src/features/profile.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { withUser } from "../middleware/user";

export const profileRouter = new Composer()
Expand Down Expand Up @@ -164,7 +164,8 @@ When you extract a handler to a standalone function, TypeScript needs a type ann

```ts
// src/middleware/user.ts
import { Composer, type ContextOf } from "@gramio/composer";
import { Composer } from "gramio";
import type { ContextOf } from "@gramio/composer";

export const withUser = new Composer()
.derive(() => ({
Expand All @@ -187,7 +188,7 @@ export async function handleProfile(ctx: WithUser) {

```ts
// src/features/profile.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { withUser } from "../middleware/user";
import { handleProfile } from "../handlers/profile";

Expand All @@ -204,7 +205,7 @@ For things that don't change per request — database clients, config, service i

```ts
// src/middleware/deps.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { db } from "../db";
import { config } from "../config";

Expand All @@ -215,7 +216,7 @@ export const withDeps = new Composer()

```ts
// src/features/admin.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { withDeps } from "../middleware/deps";

export const adminRouter = new Composer()
Expand Down Expand Up @@ -287,7 +288,7 @@ export const rateLimitPlugin = new Plugin("rate-limit")
});

// ✅ Composer — for everything else inside your own bot
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
const adminRouter = new Composer()
.guard((ctx) => ctx.from?.id === ADMIN_ID)
.command("ban", (ctx) => ctx.send("Banned!"));
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const bot = new Bot(process.env.BOT_TOKEN as string)

```ts [Composer]
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

// Shared middleware — typed context available in every module
const withUser = new Composer()
Expand Down
24 changes: 12 additions & 12 deletions docs/ru/extend/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,14 @@ const bot = new Bot(process.env.BOT_TOKEN as string)
## Условная регистрация: when()

::: info API уровня Composer
`when()` доступен на `Composer` из `@gramio/composer`. Создайте конвейер как `Composer`, затем подключите его через `bot.extend()`.
`when()` доступен на `Composer` из `gramio`. Создайте конвейер как `Composer`, затем подключите его через `bot.extend()`.
:::

Регистрируйте middleware условно при **запуске** (не на каждом запросе) с помощью `when()`. Middleware либо регистрируется, либо нет — накладных расходов в рантайме нет:

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const pipeline = new Composer()
.when(
Expand All @@ -187,11 +187,11 @@ const bot = new Bot(process.env.BOT_TOKEN as string)

## Компоновка и переиспользование: Composer

Для переиспользования middleware-групп используйте `Composer` из `@gramio/composer`:
Для переиспользования middleware-групп используйте `Composer` из `gramio`:

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

// ── Переиспользуемый middleware с derive ───────────────────────────────
const userMiddleware = new Composer()
Expand All @@ -218,7 +218,7 @@ Middleware выполняется **в порядке регистрации**.

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const logger = new Composer().use(async (ctx, next) => {
console.log("до:", ctx.updateType);
Expand All @@ -239,7 +239,7 @@ const bot = new Bot(process.env.BOT_TOKEN as string)

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const db = {
getUser: (id: number) =>
Expand All @@ -263,7 +263,7 @@ const bot = new Bot(process.env.BOT_TOKEN as string)

```ts
// middleware/user.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
export const withUser = new Composer()
.derive(async (ctx) => ({ user: await db.getUser(ctx.from?.id ?? 0) }));

Expand All @@ -278,7 +278,7 @@ const bot = new Bot(TOKEN)

```ts
import { Bot } from "gramio";
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

const FEATURES = {
debugMode: process.env.NODE_ENV !== "production",
Expand Down Expand Up @@ -316,7 +316,7 @@ bot

```ts
// middleware/user.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";

export const db = {
getUser: (id: number) =>
Expand All @@ -341,7 +341,7 @@ export const withUser = new Composer({ name: "withUser" })

```ts
// routers/admin.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { withUser } from "../middleware/user";

export const adminRouter = new Composer({ name: "adminRouter" })
Expand All @@ -362,7 +362,7 @@ TypeScript выводит `ctx.user` и `ctx.db` потому что `adminRoute

```ts
// routers/chat.ts
import { Composer } from "@gramio/composer";
import { Composer } from "gramio";
import { db, withUser } from "../middleware/user";

const withChat = new Composer({ name: "withChat" })
Expand Down Expand Up @@ -437,7 +437,7 @@ TypeScript-типы корректны; рантайм — нет. Это еди
Один DB-запрос на обновление, `ctx.user` доступен везде.

::: tip `guard()` — это уровень Composer
`guard()` доступен на `Composer` из `@gramio/composer`, а не напрямую на `Bot`. Именно поэтому `adminRouter` — это `Composer`: он получает полный composition API, а затем передаётся в `bot.extend()`.
`guard()` доступен на `Composer` из `gramio`, а не напрямую на `Bot`. Именно поэтому `adminRouter` — это `Composer`: он получает полный composition API, а затем передаётся в `bot.extend()`.
:::

## Итог
Expand Down
Loading
Loading