Sapphire SDK
npm install @mochi-analytics/core @mochi-analytics/sapphireQuick start
import { SapphireClient } from "@sapphire/framework";
import { GatewayIntentBits } from "discord.js";
import { MochiClient } from "@mochi-analytics/core";
import { attachMochi } from "@mochi-analytics/sapphire";
const mochi = new MochiClient({
url: "https://mochi.example.com", // your Mochi instance
apiKey: process.env.MOCHI_API_KEY!, // from the bot's settings page
});
const client = new SapphireClient({ intents: [GatewayIntentBits.Guilds] });
attachMochi(client, mochi);
client.login(process.env.DISCORD_TOKEN);
process.on("SIGTERM", async () => {
await mochi.shutdown(); // flush remaining events
client.destroy();
});That’s it. Mochi now records slash/context-menu command usage, guild joins and leaves, and an hourly server-count snapshot.
Duration & success come for free
There is no wrapHandler here. Sapphire reports the outcome and wall time of
every command through its chatInputCommandFinish and
contextMenuCommandFinish events, so success and durationMs are recorded
without touching your handlers.
Options
attachMochi(client, mochi, {
includeGuildNames: true, // put guild names in join/leave metadata
ignoreCommands: ["ping"], // skip noisy commands
snapshotIntervalMs: 30 * 60e3, // default 1 hour
autoTrackCommands: false, // stop recording commands entirely
trackErrors: true, // see below; default false
});trackErrors
With trackErrors: true, a rejected command also emits a Mochi error event
carrying the thrown message, in addition to the command event that already
reports success: false. It is off by default so event volume matches the other
adapters.
Guild events and snapshots
SapphireClient extends the discord.js Client, so guild joins/leaves and
hourly snapshots are handled by @mochi-analytics/discordjs under the hood — it
is installed as a dependency, not something you wire up yourself.
Custom events
mochi.track({
type: "custom",
name: "premium_purchased",
userId: interaction.user.id,
guildId: interaction.guildId ?? undefined,
meta: { tier: "gold" },
});Design guarantees
- Events are batched (flushed every 5 s or 100 events) and sent in the
background —
track()never blocks or throws. - Transient failures retry with backoff; the queue is bounded (oldest dropped first), so a dead Mochi instance can never leak memory or crash the bot.
- Raw user ids are hashed server-side with a per-bot salt and never stored.
Everything above is a thin wrapper over two HTTP endpoints — see the Ingest API to integrate from any other framework.