import { type MiddlewareFn } from "../composer.js"; import { type Context } from "../context.js"; type MaybePromise = Promise | T; /** * A session flavor is a context flavor that holds session data under * `ctx.session`. * * Session middleware will load the session data of a specific chat from your * storage solution, and make it available to you on the context object. Check * out the * [documentation](https://doc.deno.land/https://deno.land/x/grammy/mod.ts/~/session) * on session middleware to know more, and read the section about sessions on * the [website](https://grammy.dev/plugins/session.html). */ export interface SessionFlavor { /** * Session data on the context object. * * **WARNING:** You have to make sure that your session data is not * undefined by _providing an initial value to the session middleware_, or by * making sure that `ctx.session` is assigned if it is empty! The type * system does not include `| undefined` because this is really annoying to * work with. * * Accessing `ctx.session` by reading or writing will throw if * `getSessionKey(ctx) === undefined` for the respective context object * `ctx`. */ get session(): S; set session(session: S | null | undefined); } /** * A lazy session flavor is a context flavor that holds a promise of some * session data under `ctx.session`. * * Lazy session middleware will provide this promise lazily on the context * object. Once you access `ctx.session`, the storage will be queried and the * session data becomes available. If you access `ctx.session` again for the * same context object, the cached value will be used. Check out the * [documentation](https://doc.deno.land/https://deno.land/x/grammy/mod.ts/~/lazySession) * on lazy session middleware to know more, and read the section about lazy * sessions on the * [website](https://grammy.dev/plugins/session.html#lazy-sessions). */ export interface LazySessionFlavor { /** * Session data on the context object, potentially a promise. * * **WARNING:** You have to make sure that your session data is not * undefined by _providing a default value to the session middleware_, or by * making sure that `ctx.session` is assigned if it is empty! The type * system does not include `| undefined` because this is really annoying to * work with. * * Accessing `ctx.session` by reading or writing will throw iff * `getSessionKey(ctx) === undefined` holds for the respective context * object `ctx`. */ get session(): MaybePromise; set session(session: MaybePromise); } /** * A storage adapter is an abstraction that provides read, write, and delete * access to a storage solution of any kind. Storage adapters are used to keep * session middleware independent of your database provider, and they allow you * to pass your own storage solution. */ export interface StorageAdapter { /** * Reads a value for the given key from the storage. May return the value or * undefined, or a promise of either. */ read: (key: string) => MaybePromise; /** * Writes a value for the given key to the storage. */ write: (key: string, value: T) => MaybePromise; /** * Deletes a value for the given key from the storage. */ delete: (key: string) => MaybePromise; /** * Checks whether a key exists in the storage. */ has?: (key: string) => MaybePromise; /** * Lists all keys. */ readAllKeys?: () => Iterable | AsyncIterable; /** * Lists all values. */ readAllValues?: () => Iterable | AsyncIterable; /** * Lists all keys with their values. */ readAllEntries?: () => Iterable<[key: string, value: T]> | AsyncIterable<[key: string, value: T]>; } /** * Options for session middleware. */ export interface SessionOptions { type?: "single"; /** * **Recommended to use.** * * A function that produces an initial value for `ctx.session`. This * function will be called every time the storage solution returns undefined * for a given session key. Make sure to create a new value every time, such * that different context objects do that accidentally share the same * session data. */ initial?: () => S; /** * This option lets you generate your own session keys per context object. * The session key determines how to map the different session objects to * your chats and users. Check out the * [documentation](https://grammy.dev/plugins/session.html#how-to-use-sessions) * on the website about how to use session middleware to know how session * keys are used. * * The default implementation will store sessions per chat, as determined by * `ctx.chat?.id`. */ getSessionKey?: (ctx: Omit) => MaybePromise; /** * A storage adapter to your storage solution. Provides read, write, and * delete access to the session middleware. * * Consider using a [known storage * adapter](https://grammy.dev/plugins/session.html#known-storage-adapters) * instead of rolling your own implementation of this. * * The default implementation will store session in memory. The data will be * lost whenever your bot restarts. */ storage?: StorageAdapter; } /** * Options for session middleware if multi sessions are used. Specify `"type": * "multi"` in the options to use multi sessions. */ export type MultiSessionOptions = S extends Record ? { type: "multi"; } & MultiSessionOptionsRecord : never; type MultiSessionOptionsRecord, C extends Context> = { [K in keyof S]: SessionOptions; }; /** * Session middleware provides a persistent data storage for your bot. You can * use it to let your bot remember any data you want, for example the messages * it sent or received in the past. This is done by attaching _session data_ to * every chat. The stored data is then provided on the context object under * `ctx.session`. * * > **What is a session?** Simply put, the session of a chat is a little * > persistent storage that is attached to it. As an example, your bot can send * > a message to a chat and store the ID of that message in the corresponding * > session. The next time your bot receives an update from that chat, the * > session will still contain that ID. * > * > Session data can be stored in a database, in a file, or simply in memory. * > grammY only supports memory sessions out of the box, but you can use * > third-party session middleware to connect to other storage solutions. Note * > that memory sessions will be lost when you stop your bot and the process * > exits, so they are usually not useful in production. * * Whenever your bot receives an update, the first thing the session middleware * will do is to load the correct session from your storage solution. This * object is then provided on `ctx.session` while your other middleware is * running. As soon as your bot is done handling the update, the middleware * takes over again and writes back the session object to your storage. This * allows you to modify the session object arbitrarily in your middleware, and * to stop worrying about the database. * * ```ts * bot.use(session()) * * bot.on('message', ctx => { * // The session object is persisted across updates! * const session = ctx.session * }) * ``` * * It is recommended to make use of the `initial` option in the configuration * object, which correctly initializes session objects for new chats. * * You can delete the session data by setting `ctx.session` to `null` or * `undefined`. * * Check out the [documentation](https://grammy.dev/plugins/session.html) on the * website to know more about how sessions work in grammY. * * @param options Optional configuration to pass to the session middleware */ export declare function session(options?: SessionOptions | MultiSessionOptions): MiddlewareFn>; /** * > This is an advanced function of grammY. * * Generally speaking, lazy sessions work just like normal sessions—just they * are loaded on demand. Except for a few `async`s and `await`s here and there, * their usage looks 100 % identical. * * Instead of directly querying the storage every time an update arrives, lazy * sessions quickly do this _once you access_ `ctx.session`. This can * significantly reduce the database traffic (especially when your bot is added * to group chats), because it skips a read and a wrote operation for all * updates that the bot does not react to. * * ```ts * // The options are identical * bot.use(lazySession({ storage: ... })) * * bot.on('message', async ctx => { * // The session object is persisted across updates! * const session = await ctx.session * // ^ * // | * // This plain property access (no function call) will trigger the database query! * }) * ``` * * Check out the * [documentation](https://grammy.dev/plugins/session.html#lazy-sessions) on the * website to know more about how lazy sessions work in grammY. * * @param options Optional configuration to pass to the session middleware */ export declare function lazySession(options?: SessionOptions): MiddlewareFn>; /** * When enhancing a storage adapter, it needs to be able to store additional * information. It does this by wrapping the actual data inside an object, and * adding more properties to this wrapper. * * This interface defines the additional properties that need to be stored by a * storage adapter that supports enhanced sessions. */ export interface Enhance { /** Version */ v?: number; /** Data */ __d: T; /** Expiry date */ e?: number; } /** Options for enhanced sessions */ export interface MigrationOptions { /** The original storage adapter that will be enhanced */ storage: StorageAdapter>; /** * A set of session migrations, defined as an object mapping from version * numbers to migration functions that transform data to the respective * version. */ migrations?: Migrations; /** * Number of milliseconds after the last write operation until the session * data expires. */ millisecondsToLive?: number; } /** * A mapping from version numbers to session migration functions. Each entry in * this object has a version number as a key, and a function as a value. * * For a key `n`, the respective value should be a function that takes the * previous session data and migrates it to conform with the data that is used * by version `n`. The previous session data is defined by the next key less * than `n`, such as `n-1`. Versions don't have to be integers, nor do all * versions have to be adjacent. For example, you can use `[1, 1.5, 4]` as * versions. If `n` is the lowest value in the set of keys, the function stored * for `n` can be used to migrate session data that was stored before migrations * were used. */ export interface Migrations { [version: number]: (old: any) => any; } /** * You can use this function to transform an existing storage adapter, and add * more features to it. Currently, you can add session migrations and expiry * dates. * * You can use this function like so: * ```ts * const storage = ... // define your storage adapter * const enhanced = enhanceStorage({ storage, millisecondsToLive: 500 }) * bot.use(session({ storage: enhanced })) * ``` * * @param options Session enhancing options * @returns The enhanced storage adapter */ export declare function enhanceStorage(options: MigrationOptions): StorageAdapter; /** * The memory session storage is a built-in storage adapter that saves your * session data in RAM using a regular JavaScript `Map` object. If you use this * storage adapter, all sessions will be lost when your process terminates or * restarts. Hence, you should only use it for short-lived data that is not * important to persist. * * This class is used as default if you do not provide a storage adapter, e.g. * to your database. * * This storage adapter features expiring sessions. When instantiating this class * yourself, you can pass a time to live in milliseconds that will be used for * each session object. If a session for a user expired, the session data will * be discarded on its first read, and a fresh session object as returned by the * `initial` option (or undefined) will be put into place. */ export declare class MemorySessionStorage implements StorageAdapter { private readonly timeToLive?; /** * Internally used `Map` instance that stores the session data */ protected readonly storage: Map; /** * Constructs a new memory session storage with the given time to live. Note * that this storage adapter will not store your data permanently. * * @param timeToLive TTL in milliseconds, default is `Infinity` */ constructor(timeToLive?: number | undefined); read(key: string): S | undefined; /** * @deprecated Use {@link readAllValues} instead */ readAll(): S[]; readAllKeys(): string[]; readAllValues(): S[]; readAllEntries(): [string, S][]; has(key: string): boolean; write(key: string, value: S): void; delete(key: string): void; } export {};