/** * `ctx.payments` derive — the per-event ctx decoration. * * Extracted from `plugin.ts` to keep that file pure wiring per the * `bot/CLAUDE.md` plugin file convention. Everything that reads or * mutates session state inside an event handler goes through one of * the methods this module attaches: * * - `ctx.payments.atLeast(id)` — tier gate (lazy expiry) * - `ctx.payments.tier()` — current rung (`'free' | 'vip.N'`) * - `ctx.payments.tier.level()` — integer rank * - `ctx.payments.tier.label()` — resolved Polyglot label * - `ctx.payments.credits.*` — balance / consume / tryConsume * - `ctx.payments.has(perkId)` — perk ownership boolean * - `ctx.payments.require(...)` — gate + localized upgrade prompt * - `ctx.payments.invoice(key)` — purchase entry (waiver-gated) * * Returned shape is a function so `plugin.ts` can drop it directly * into `.derive(["message", "callback_query", "inline_query", "chosen_inline_result"], buildPaymentsDerive({...}))`. */ import { type BotPaymentsConfig, type ProductCatalog } from "./types.js"; type TierKey = "free" | `vip.${number}`; /** * Callable `tier` namespace. Matches `PaymentsCtx['tier']` from `plugin.ts` * — exported there as the public surface. Repeated minimally here so * derive.ts isn't import-cycle dependent on plugin.ts. */ export type TierFn = (() => TierKey) & { level: () => number; label: () => string | undefined; }; export type CreditsApi = { balance: () => number; consume: (n: number) => void; tryConsume: (n: number) => boolean; }; /** Display label for a gated feature: a Polyglot pair or a plain string. */ type FeatureLabel = { en: string; es: string; } | string; export type RequireOpts = { feature?: FeatureLabel; }; /** * What `buildPaymentsDerive` attaches under `ctx.payments`. Plugin.ts * casts this to the typed `PaymentsCtx` (with positional ladder * narrowing) before exposing it to bot authors — TypeScript can't * preserve the generic narrowing through a function-shaped derive * factory cleanly, so the strict type lives at the public surface. */ export type PaymentsDerived = { atLeast: (id: string) => boolean; tier: TierFn; has: (perkId: string) => boolean; credits: CreditsApi; require: (id: string, opts?: RequireOpts) => Promise; invoice: (productKey: string) => Promise<"invoice_sent" | "waiver_prompt_sent" | "unknown_product">; }; export type BuildPaymentsDeriveArgs = { /** Resolved product catalogue (rungs, packs, perks). */ catalog: ProductCatalog; /** * Full config — currently only consulted inside `invoice()` for the * waiver wording + product display strings via `presentInvoice`. */ cfg: BotPaymentsConfig; }; /** * Returns the function you pass to gramio's `.derive([events], fn)`. * The returned function takes ctx, returns `{ payments }`. */ export declare const buildPaymentsDerive: ({ cfg, catalog, }: BuildPaymentsDeriveArgs) => (ctx: unknown) => { payments: PaymentsDerived; }; export {}; //# sourceMappingURL=derive.d.ts.map