Stores
Bring your own storage for prefixes and cooldowns.
Both built-in stores keep data in memory. That is great for a small bot and ephemeral state; persistence or multiple workers call for your own implementations.
PrefixStore
interface PrefixStore {
getPrefix(guildId: string): string | undefined | Promise<string | undefined>;
setPrefix(guildId: string, prefix: string): void | Promise<void>;
}Pass prefixStore to SWAG.create(). The message router asks it for a guild prefix and falls back to defaultPrefix when it returns undefined. DMs use the default. The shipped MemoryPrefixStore is an easy starting point.
CooldownStore
interface CooldownClaim {
acquired: boolean;
expiresAt: number;
}
interface CooldownStore {
getCooldown(id: string): number | undefined | Promise<number | undefined>;
setCooldown(id: string, expiresAt: number): void | Promise<void>;
deleteCooldown(id: string): void | Promise<void>;
claimCooldown(
id: string,
expiresAt: number,
now: number,
): CooldownClaim | Promise<CooldownClaim>;
}The timestamps are Unix time in milliseconds. claimCooldown must atomically acquire a missing or expired bucket and return { acquired: true, expiresAt }, or reject a live bucket with { acquired: false, expiresAt: activeExpiration }. This atomic step prevents concurrent invocations from both entering the callback. MemoryCooldownStore implements this in one process; distributed stores must use their backend's atomic primitive.
const swag = await SWAG.create({
client,
prefixStore: new MyPrefixStore(),
cooldownStore: new MyCooldownStore(),
});These interfaces accept synchronous or asynchronous methods. Prefixes and Cooldowns show how the stores affect command behavior.