Popii - v0.5.1
    Preparing search index...

    The Pop Context

    Every command, snap, and event handler receives a pop (or EventPop) object as its first argument. This is your main interface to everything Popii provides.

    pop.user          // discord.js User — who triggered the command
    pop.member // GuildMember | null — the member in this server
    pop.guild // Guild | null — the server, if applicable
    pop.channel // TextBasedChannel | null — the channel
    pop.client // PopiiClient — the bot client
    pop.locale // string — the user's Discord locale (e.g. "en-US")
    await pop.reply("Hello!");
    await pop.reply({ content: "Hello!", ephemeral: true });
    await pop.reply({ embeds: [myEmbed], components: [actionRow] });

    await pop.defer({ ephemeral: true }); // acknowledge within 3s, reply later
    await pop.reply("Done!"); // follow-up after defer
    const name = pop.options.getString("name");      // string | null
    const target = pop.options.getUser("user"); // User | null
    const count = pop.options.getInteger("count"); // number | null
    const channel = pop.options.getChannel("chan"); // TextBasedChannel | null
    const role = pop.options.getRole("role"); // Role | null
    const flag = pop.options.getBoolean("enabled"); // boolean | null

    With a schema, use pop.input for fully-typed values instead.

    Cache the result of an async call for a given TTL. Subsequent calls within the TTL return the cached value without re-fetching:

    const user = await pop.cache(`user:${pop.user.id}`, 60_000, async () => {
    return db.query("SELECT * FROM users WHERE id = ?").get(pop.user.id);
    });

    The Cooler is a shared key-value store backed by Redis (if configured) or an in-process Map. Use it for state that needs to persist across commands and restarts:

    await pop.cooler.set("last_seen:" + pop.user.id, Date.now(), 86_400_000); // 24h TTL
    const lastSeen = await pop.cooler.get<number>("last_seen:" + pop.user.id);
    await pop.cooler.delete("last_seen:" + pop.user.id);
    // pop.t() is shorthand for pop.translate()
    const msg = pop.t("welcome_message", { username: pop.user.username });
    // looks up the key in the locale file for pop.locale

    Locale files live in src/locales/<locale>.json (e.g. en-US.json, fr.json).

    Trigger a named background task immediately or with a delay:

    await pop.schedule("send-report");                     // run now
    await pop.schedule("send-report", { userId: "123" }, 60_000); // run after 1 minute
    const data = await pop.fetchJSON<MyType>("https://api.example.com/data");
    const text = await pop.fetchText("https://example.com/readme");
    const buf = await pop.fetchBuffer("https://example.com/image.png");
    await pop.reply({
    content: "Here's your image:",
    files: [pop.createAttachment("./assets/banner.png", "banner.png")]
    });

    Encode structured data into a Discord customId string (max 100 chars):

    // In a command — create a button with embedded data
    const customId = pop.pack("confirm-ban", { targetId: member.id, reason: "spam" });
    // → "confirm-ban:eyJ0YXJnZXRJZCI6Ii4..."

    // In the matching snap
    export default snap({
    prefix: "confirm-ban",
    do(pop) {
    const { targetId, reason } = pop.snapData;
    // ...
    }
    });

    pop.locals is the per-request scratch pad populated by your middlewares. Augment the global PopiiLocals interface to get type safety across your entire project:

    // src/types.d.ts
    declare module "popii" {
    interface PopiiLocals {
    dbUser: { id: string; balance: number; premium: boolean };
    guildConfig: Record<string, string>;
    }
    }

    After that, pop.locals.dbUser is typed in every command and middleware.

    Provide a typed state object in popiiClient() for global mutable bot state:

    const client = popiiClient({
    token: process.env.DISCORD_TOKEN!,
    state: { totalCommandsRun: 0 }
    });

    // In any command:
    pop.state.totalCommandsRun++;

    Emit and listen to custom events across your bot (useful for plugin communication):

    // Emit from anywhere:
    await pop.client.global.emit("xp-gained", { userId: pop.user.id, amount: 50 });

    // Listen from anywhere (e.g. in a plugin's setup):
    client.global.on("xp-gained", ({ userId, amount }) => {
    console.log(`${userId} gained ${amount} XP`);
    });