API Reference
Data & Storage
Persist plugin data across Discord sessions using Plexcord's DataStore API. Key-value storage with TypeScript generics.
Data & Storage
Plexcord provides DataStore, an async key-value store that persists data across Discord restarts.
Import
import { DataStore } from "@api/DataStore";Core Methods
DataStore.get<T>(key)
Retrieve a stored value. Returns undefined if the key doesn't exist.
async function loadData() {
const value = await DataStore.get<string>("myPlugin_username");
// value is string | undefined
console.log(value ?? "No username saved");
}DataStore.set(key, value)
Store a value. Overwrites any existing value for that key.
async function saveData() {
await DataStore.set("myPlugin_username", "Alice");
await DataStore.set("myPlugin_count", 42);
await DataStore.set("myPlugin_list", ["a", "b", "c"]);
}DataStore.update<T>(key, updater)
Atomically update a value in-place. The updater receives the current value (or undefined) and returns the new value.
// Increment a counter safely
await DataStore.update<number>("myPlugin_visitCount", (current = 0) => current + 1);
// Add to a list safely
await DataStore.update<string[]>("myPlugin_log", (list = []) => {
return [...list, `Entry at ${new Date().toISOString()}`];
});DataStore.del(key)
Delete a stored value.
await DataStore.del("myPlugin_username");DataStore.keys()
Get all keys (across all plugins). Filter by your prefix:
const allKeys = await DataStore.keys();
const myKeys = allKeys.filter(k => k.startsWith("myPlugin_"));DataStore.getMany<T>(keys)
Get multiple values at once:
const [username, count] = await DataStore.getMany([
"myPlugin_username",
"myPlugin_count"
]) as [string | undefined, number | undefined];DataStore.setMany(entries)
Set multiple values at once:
await DataStore.setMany([
["myPlugin_username", "Bob"],
["myPlugin_count", 0],
["myPlugin_lastSeen", Date.now()]
]);Naming Keys
Always prefix your keys with your plugin name to avoid collisions:
// ✅ Good
DataStore.set("KeywordAlert_watchedWords", [...]);
DataStore.set("VoiceLogger_log", [...]);
// ❌ Bad: may collide with other plugins
DataStore.set("watchedWords", [...]);
DataStore.set("log", [...]);Data Types
DataStore uses localforage internally and can store:
- Primitives:
string,number,boolean,null - Complex: plain objects, arrays
- Not supported:
class instances,functions,undefined(usenullinstead)
// ✅ Supported
await DataStore.set("key", { name: "Alice", count: 5 });
await DataStore.set("key", [1, 2, 3]);
await DataStore.set("key", "text");
// ❌ Not supported
await DataStore.set("key", new Map()); // Map → {}
await DataStore.set("key", undefined); // Use nullComplete Example: Persistent Message Log
import definePlugin from "@utils/types";
import { DataStore } from "@api/DataStore";
import { Logger } from "@utils/Logger";
const logger = new Logger("MessageLog", "#4A90D9");
const STORAGE_KEY = "MessageLog_entries";
const MAX_ENTRIES = 100;
interface LogEntry {
content: string;
authorId: string;
channelId: string;
timestamp: number;
}
export default definePlugin({
name: "MessageLog",
description: "Persists a log of recent messages",
authors: [{ name: "You", id: 0n }],
async start() {
const existing = await DataStore.get<LogEntry[]>(STORAGE_KEY);
logger.info(`Loaded ${existing?.length ?? 0} existing log entries`);
},
flux: {
async MESSAGE_CREATE({ message, channelId }) {
if (message.author.bot) return;
const entry: LogEntry = {
content: message.content,
authorId: message.author.id,
channelId,
timestamp: Date.now()
};
await DataStore.update<LogEntry[]>(STORAGE_KEY, (log = []) => {
const updated = [...log, entry];
// Keep only last 100 entries
return updated.slice(-MAX_ENTRIES);
});
}
},
stop() {
logger.info("Plugin stopped. Log preserved in storage.");
}
});