DJS Commandsv2 docs
API Reference@djs-commands/core

Storage

Storage CRUD interface, framework models, helpers, and the conformance suite.

See Concepts → Storage for the narrative.

Storage

interface Storage {
	create<T>(model: string, data: T): Promise<T>;
	findOne<T>(model: string, where: StorageWhere): Promise<T | null>;
	findMany<T>(model: string, opts?: StorageFindOpts): Promise<T[]>;
	update<T>(model: string, where: StorageWhere, data: Partial<T>): Promise<T>;
	delete(model: string, where: StorageWhere): Promise<void>;
	count(model: string, where?: StorageWhere): Promise<number>;
}

Generic CRUD contract that adapters implement once and the framework consumes for every persistent feature. create<T> should return the persisted row (use RETURNING or re-fetch).

StorageWhere

type StorageWhere = Record<string, string | number | null>;

Equality-only filter. Implementations should treat null as IS NULL (or the document equivalent).

StorageFindOpts

interface StorageFindOpts {
	where?: StorageWhere;
	limit?: number;
	offset?: number;
	orderBy?: { field: string; direction: "asc" | "desc" };
}

Pagination + ordering options for findMany.

runStorageConformance(name, factory)

function runStorageConformance(
	name: string,
	factory: () => Storage | Promise<Storage>,
): void;

Shared test suite that exercises every CRUD path the framework relies on. Call from any bun test (or compatible) file:

import { runStorageConformance } from "@djs-commands/core";

runStorageConformance("my-adapter", () => myStorageFactory());

Pass it and your adapter will work for every shipped feature, including upserts, partial updates, and find-with-options.

Framework models

The framework reads/writes three built-in models. All adapters ship schemas for them out of the box.

GuildPrefixModel / GuildPrefixRow

const GuildPrefixModel = "guild_prefix";

interface GuildPrefixRow {
	guild_id: string;
	prefix: string;
}

DisabledCommandsModel / DisabledCommandRow

const DisabledCommandsModel = "disabled_commands";

interface DisabledCommandRow {
	guild_id: string;
	command_name: string;
}

ChannelLocksModel / ChannelLockRow

const ChannelLocksModel = "channel_locks";

interface ChannelLockRow {
	guild_id: string;
	command_name: string;
	channel_id: string;
}

GuildPrefix helpers

function getGuildPrefix(storage: Storage, guildId: string): Promise<string | null>;
function setGuildPrefix(storage: Storage, guildId: string, prefix: string): Promise<void>;
function clearGuildPrefix(storage: Storage, guildId: string): Promise<void>;

Read / upsert / delete a guild's prefix override.

import { getGuildPrefix, setGuildPrefix } from "@djs-commands/core";

const prefix = (await getGuildPrefix(storage, guildId)) ?? "!";
await setGuildPrefix(storage, guildId, "?");

DisabledCommands helpers

function isCommandDisabled(storage: Storage, guildId: string, commandName: string): Promise<boolean>;
function disableCommand(storage: Storage, guildId: string, commandName: string): Promise<void>;
function enableCommand(storage: Storage, guildId: string, commandName: string): Promise<void>;

The dispatcher consults isCommandDisabled automatically — you don't wire it into your validators.

ChannelLocks helpers

function getChannelLocks(storage: Storage, guildId: string, commandName: string): Promise<string[]>;
function lockCommandToChannel(storage: Storage, guildId: string, commandName: string, channelId: string): Promise<void>;
function unlockCommandFromChannel(storage: Storage, guildId: string, commandName: string, channelId: string): Promise<void>;

Empty list = no restriction. Non-empty = command runs only in those channels for that guild.

import { lockCommandToChannel } from "@djs-commands/core";

await lockCommandToChannel(storage, guildId, "music-play", musicChannelId);

Last updated on

On this page