Хранилища
Это специальные хранилища данных. Их основное применение — в плагинах (например, сессии).
Адаптеры
GramIO имеет множество готовых адаптеров, но вы также можете написать свой собственный!
В памяти (In Memory) (
@gramio/storage)Redis (
@gramio/storage-redis)
Как написать свой собственный адаптер хранилища
Написать свой адаптер очень просто!
Достаточно вернуть объект с необходимыми методами и использовать методы выбранного вами решения для адаптера (например, ioredis).
import type { Storage } from "@gramio/storage";
import ThirdPartyStorage, { type ThirdPartyStorageOptions } from "some-library";
export interface MyOwnStorageOptions extends ThirdPartyStorageOptions {
/** добавить новое свойство в параметры */
some?: number;
}
export function myOwnStorage(options: MyOwnStorageOptions = {}): Storage {
const storage = new ThirdPartyStorage(options);
return {
async get(key) {
const data = await storage.get(key);
return data ? JSON.parse(data) : undefined;
},
async has(key) {
return storage.has(key);
},
async set(key, value) {
await storage.set(key, JSON.stringify(value));
},
async delete(key) {
return storage.delete(key);
},
};
}IMPORTANT
Если вы хотите опубликовать свой адаптер, мы рекомендуем следовать соглашению и назвать его начиная с gramio-storage и добавить ключевые слова gramio + gramio-storage в ваш package.json
Как использовать адаптеры хранилища в своем плагине
Работать с адаптерами хранилища в вашем плагине также очень просто!
Всё, что нам нужно, уже есть в @gramio/storage.
import { Plugin } from "gramio";
import { type Storage, inMemoryStorage } from "@gramio/storage";
export interface MyOwnPluginOptions {
storage?: Storage;
}
export function myOwnPlugin(options: MyOwnPluginOptions = {}) {
// используем хранилище в памяти по умолчанию
const storage = options.storage ?? inMemoryStorage();
return new Plugin("gramio-example");
}IMPORTANT
Вы можете создать шаблон этого примера с помощью create-gramio-plugin
Типобезопасное хранилище с дженериками
Все адаптеры хранилищ поддерживают параметр обобщенного типа Storage<Data>, который обеспечивает типобезопасность для ключей и значений. Это позволяет TypeScript автоматически определять правильный тип значения на основе ключа, к которому вы обращаетесь.
Базовое использование
import { inMemoryStorage } from "@gramio/storage";
interface UserData {
username: string;
email: string;
age: number;
}
const storage = inMemoryStorage<UserData>();
await storage.set("username", "john_doe");
await storage.set("email", "john@example.com");
const username = await storage.get("username"); // string | undefined
Шаблонные литеральные типы
Storage<Data> отлично работает с шаблонными литеральными типами TypeScript, позволяя определять динамические паттерны ключей:
import { inMemoryStorage } from "@gramio/storage";
type Data = Record<`user:${number}`, { name: string; age: number }> &
Record<`session:${string}`, { token: string; expires: number }>;
const storage = inMemoryStorage<Data>();
await storage.set("user:1", { name: "Alice", age: 30 });
await storage.set("session:abc123", { token: "xyz", expires: 1234567890 });
const user = await storage.get("user:1"); // { name: string; age: number } | undefined
const session = await storage.get("session:abc123"); // { token: string; expires: number } | undefined
Сложные объединения типов
Вы можете комбинировать несколько типов записей для различных паттернов ключей:
import { inMemoryStorage } from "@gramio/storage";
type StorageSchema = Record<`counter:${string}`, number> &
Record<`flag:${string}`, boolean> &
Record<`data:${string}`, { value: string; timestamp: number }>;
const storage = inMemoryStorage<StorageSchema>();
await storage.set("counter:views", 42);
await storage.set("flag:enabled", true);
await storage.set("data:config", { value: "test", timestamp: Date.now() });
const views = await storage.get("counter:views"); // number | undefined
Эта типобезопасность работает во всех адаптерах хранилищ (в памяти, Redis, Cloudflare KV и т.д.) и помогает предотвратить ошибки во время выполнения, выявляя несоответствия типов на этапе компиляции.
Список
В памяти
Установка
npm install @gramio/storageyarn add @gramio/storagepnpm add @gramio/storagebun install @gramio/storageИспользование
- С использованием стандартного Map
import { inMemoryStorage } from "@gramio/storage";
const storage = inMemoryStorage();- Предоставление своего собственного Map
import { inMemoryStorage, type InMemoryStorageMap } from "@gramio/storage";
const map: InMemoryStorageMap = new Map();
const storage = inMemoryStorage(map);Redis
Установка
npm install @gramio/storage-redisyarn add @gramio/storage-redispnpm add @gramio/storage-redisbun install @gramio/storage-redisИспользование
- Предоставление параметров ioredis для функции
redisStorage
import { redisStorage } from "@gramio/storage-redis";
const storage = redisStorage({
host: process.env.REDIS_HOST,
});- Предоставление экземпляра ioredis для функции
redisStorage
import { redisStorage } from "@gramio/storage-redis";
import { Redis } from "ioredis";
const redis = new Redis({
host: process.env.REDIS_HOST,
});
const storage = redisStorage(redis);Советы
- Вы можете установить переменную окружения
DEBUGвioredis:*для вывода отладочной информации:
DEBUG=ioredis:* npm run startи это будет выглядеть так:
ioredis:redis write command[::1:6379]: 0 -> get([ '@gramio/scenes:617580375' ]) +187ms
ioredis:redis write command[::1:6379]: 0 -> set([ '@gramio/scenes:617580375', '{"name":"scene-name","state":{},"stepId":0,"previousStepId":0,"firstTime":false}' ]) +1ms- Для проверки того, какие данные хранятся в Redis, мы рекомендуем использовать графические клиенты, такие как AnotherRedisDesktopManager.

Cloudflare KV
Установка
npm install @gramio/storage-cloudflareyarn add @gramio/storage-cloudflarepnpm add @gramio/storage-cloudflarebun install @gramio/storage-cloudflareИспользование
Предоставьте пространство имен Cloudflare KV функции
cloudflareStorage
import { cloudflareStorage } from "@gramio/storage-cloudflare";
const storage = cloudflareStorage(Env.CLOUDFLARE_KV_NAMESPACE);