npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

prizebox

v1.2.0

Published

Complete Discord giveaway management system with advanced features and statistics tracking

Readme

PrizeBox

🎉 Complete Discord Giveaway Management System 🎉

The ultimate solution for managing Discord giveaways with advanced features

Discord NPM License NPM Version Downloads


📋 Table of Contents


🎯 About

PrizeBox is a powerful and flexible Discord giveaway management system built on top of discord.js. It provides everything you need to run professional giveaways in your Discord server with advanced features like user statistics tracking, flexible entry methods, and comprehensive management tools.

Why Choose PrizeBox?

  • 🎪 Dual Entry Methods: Support for both reactions and interactive buttons
  • 📊 Advanced Statistics: Track user participation and wins across all giveaways
  • 🔧 Flexible Management: Start, pause, resume, edit, extend, and reroll giveaways
  • 💾 Persistent Storage: INFINITY lose giveaway data with JSON-based storage
  • 🏆 Leaderboards: Built-in leaderboard system for most active participants
  • ⚡ Real-time Updates: Live participant count updates and last-chance notifications
  • 🛡️ Production Ready: Comprehensive error handling and data validation

✨ Key Features

🎮 Giveaway Management

  • Create reaction or button-based giveaways
  • Pause and resume functionality
  • Edit prizes and winner counts on-the-fly
  • Reroll winners after completion
  • Last-chance notifications

📈 Analytics & Tracking

  • User participation statistics
  • Win/loss tracking per user
  • Guild-based statistics storage
  • Comprehensive leaderboards
  • Entry count monitoring
  • Historical data preservation

🎛️ Management Operations

| Operation | Description | Method | | ---------- | -------------------------- | ------------------ | | Start | Create new giveaway | manager.start() | | End | Finish and pick winners | manager.end() | | Pause | Temporarily stop giveaway | manager.pause() | | Resume | Continue paused giveaway | manager.resume() | | Edit | Modify giveaway details | manager.edit() | | Extend | Add more time | manager.extend() | | Reroll | Pick new winners | manager.reroll() | | Delete | Remove giveaway completely | manager.delete() |


🚀 Quick Start

Prerequisites

  • Node.js 16.9.0 or higher
  • Discord.js v14 or higher
  • A Discord bot with proper permissions

Basic Setup

const { Client, GatewayIntentBits } = require('discord.js');
const { GiveawaysManager } = require('prizebox');

// Create Discord client
const client = new Client({
  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.MessageContent],
});

// Initialize PrizeBox
const giveawayManager = new GiveawaysManager(client, {
  storage: './giveaways.json',
  defaults: {
    botsCanWin: false,
    embedColor: '#FF6B6B',
    embedColorEnd: '#2C2F33',
    type: 'reaction',
    emoji: '🎉',
  },
});

// Start a giveaway
client.on('messageCreate', async message => {
  if (message.content === '!start-giveaway') {
    const channel = message.channel;

    await giveawayManager.start(channel, {
      prize: 'Discord Nitro',
      duration: 60000, // 1 minute
      winnerCount: 1,
      hostId: message.author.id,
    });

    message.reply('✅ Giveaway started!');
  }
});

client.login('YOUR_BOT_TOKEN');

📥 Installation

NPM Installation

npm install prizebox

Yarn Installation

yarn add prizebox

Development Installation

git clone https://github.com/Boda335/prizebox.git
cd prizebox
npm install
npm run dev

⚙️ Configuration

Manager Options

const manager = new GiveawaysManager(client, {
  // Storage configuration
  storage: './data/giveaways.json',

  // Default settings for all giveaways
  defaults: {
    botsCanWin: false,
    embedColor: '#FF6B6B',
    embedColorEnd: '#2C2F33',
    checkInterval: 5000,
    type: 'button', // 'reaction' or 'button'
    emoji: '🎁',
  },

  // Custom messages
  messages: {
    giveaway: '🎉 **GIVEAWAY** 🎉',
    giveawayEnded: '🎉 **GIVEAWAY ENDED** 🎉',
    inviteToParticipate: 'React with 🎉 to enter!',
    winMessage: 'Congratulations {winners}! You won **{this.prize}**!',
    noWinner: 'No valid participants for **{this.prize}**.',
    hostedBy: 'Hosted by: {this.hostedBy}',
    embedFooter: '{this.winnerCount} winner(s)',
  },

  // Last chance notification
  lastChance: {
    enabled: true,
    content: '⚠️ **LAST CHANCE TO ENTER!** ⚠️',
    threshold: 10000, // 10 seconds before end
    embedColor: '#FFFF00',
  },

  // Pause options
  pauseOptions: {
    isPaused: false,
    content: '⏸️ **THIS GIVEAWAY IS PAUSED!** ⏸️',
    unpauseAfter: null,
    embedColor: '#FFFF00',
    infiniteDurationText: '`INFINITY`',
  },
});

Event Handling

// Listen to giveaway events
manager.on('giveawayJoin', (participant, giveaway) => {
  console.log(`${participant.username} joined ${giveaway.data.prize}!`);
});

manager.on('giveawayLeave', (participant, giveaway) => {
  console.log(`${participant.username} left ${giveaway.data.prize}!`);
});

manager.on('giveawayInvalidEntry', (userId, giveaway) => {
  console.log(`Invalid entry attempt by ${userId} for ${giveaway.data.prize}`);
});

🎪 Giveaway Management

Starting Giveaways

// Basic giveaway
await manager.start(channel, {
  prize: 'Discord Nitro',
  duration: 24 * 60 * 60 * 1000, // 24 hours
  winnerCount: 2,
  hostId: interaction.user.id,
});

// Advanced giveaway with custom settings
await manager.start(
  channel,
  {
    prize: 'Steam Gift Card',
    duration: 60 * 60 * 1000, // 1 hour
    winnerCount: 3,
    hostId: interaction.user.id,
    type: 'button',
    emoji: '🎁',
  },
  {
    // Override default settings for this giveaway
    defaults: {
      embedColor: '#00FF00',
      botsCanWin: true,
    },
    messages: {
      inviteToParticipate: 'Click the button to join this exclusive giveaway!',
    },
  }
);

Managing Active Giveaways

// End a giveaway early
const giveaway = await manager.end(messageId);
console.log(`Giveaway ended! Winners: ${giveaway.getWinners()}`);

// Pause a giveaway
await manager.pause(messageId);

// Resume a paused giveaway
await manager.resume(messageId);

// Edit giveaway details
await manager.edit(messageId, {
  prize: 'Updated Prize Name',
  winnerCount: 5,
  addTime: 30 * 60 * 1000, // Add 30 minutes
});

// Reroll winners
const newWinners = await manager.reroll(messageId, 2); // Pick 2 new winners

// Delete giveaway
await manager.delete(messageId);

Listing Giveaways

// Get all giveaways
const allGiveaways = manager.list();

// Get only active giveaways
const activeGiveaways = manager.list('active');

// Get paused giveaways
const pausedGiveaways = manager.list('paused');

// Get ended giveaways
const endedGiveaways = manager.list('ended');

📊 Statistics & Leaderboards

User Statistics

// Get leaderboard data
const topParticipants = manager.leaderboard('entries', 10);
const topWinners = manager.leaderboard('wins', 10);

// Send leaderboard to channel
await manager.sendLeaderboard(channel, 'entries', 15);
await manager.sendLeaderboard(channel, 'wins', 10);

Leaderboard Output Example

[
  {
    rank: 1,
    id: '123456789',
    username: 'john_doe',
    avatar: 'https://cdn.discordapp.com/avatars/...',
    entries: 25,
    wins: 3,
  },
  {
    rank: 2,
    id: '987654321',
    username: 'jane_smith',
    avatar: 'https://cdn.discordapp.com/avatars/...',
    entries: 18,
    wins: 2,
  },
];

💾 Storage System

JSON Storage Structure

{
  "giveaways": [
    {
      "messageId": "1234567890",
      "channelId": "0987654321",
      "guildId": "1122334455",
      "prize": "Discord Nitro",
      "startAt": 1640995200000,
      "endAt": 1641081600000,
      "ended": false,
      "paused": false,
      "winnerIds": [],
      "participants": [
        {
          "id": "user123",
          "username": "participant1",
          "globalName": "Participant One",
          "avatar": "https://cdn.discordapp.com/avatars/..."
        }
      ],
      "hostId": "host123",
      "winnerCount": 1,
      "type": "reaction",
      "emoji": "🎉"
    }
  ],
  "userStats": {
    "guildId123": {
      "userId123": {
        "entries": 10,
        "wins": 2
      }
    }
  }
}

Custom Storage Implementation

class CustomStorage {
  constructor(options) {
    // Your custom storage setup
  }

  all() {
    // Return all giveaways
  }

  saveAll(giveaways) {
    // Save giveaways array
  }

  updateUserStats(guildId, userId, changes) {
    // Update user statistics
  }

  getAllUserStats() {
    // Return all user statistics
  }
}

const manager = new GiveawaysManager(client, {
  storage: new CustomStorage({
    /* options */
  }),
});

💡 Examples

Complete Bot Example

const { Client, GatewayIntentBits, SlashCommandBuilder } = require('discord.js');
const { GiveawaysManager } = require('prizebox');

const client = new Client({
  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.MessageContent],
});

const manager = new GiveawaysManager(client, {
  storage: './giveaways.json',
  defaults: {
    botsCanWin: false,
    embedColor: '#FF6B6B',
    type: 'button',
  },
});

// Slash command handling
client.on('interactionCreate', async interaction => {
  if (!interaction.isChatInputCommand()) return;

  if (interaction.commandName === 'giveaway') {
    const subcommand = interaction.options.getSubcommand();

    switch (subcommand) {
      case 'start': {
        const prize = interaction.options.getString('prize');
        const duration = interaction.options.getInteger('duration') * 60 * 1000;
        const winners = interaction.options.getInteger('winners');

        await manager.start(interaction.channel, {
          prize,
          duration,
          winnerCount: winners,
          hostId: interaction.user.id,
        });

        await interaction.reply('✅ Giveaway started successfully!');
        break;
      }

      case 'end': {
        const messageId = interaction.options.getString('message-id');
        await manager.end(messageId);
        await interaction.reply('✅ Giveaway ended!');
        break;
      }

      case 'reroll': {
        const messageId = interaction.options.getString('message-id');
        await manager.reroll(messageId);
        await interaction.reply('✅ Winners rerolled!');
        break;
      }

      case 'leaderboard': {
        await manager.sendLeaderboard(interaction.channel);
        await interaction.reply('📊 Leaderboard posted!');
        break;
      }
    }
  }
});

client.login('YOUR_BOT_TOKEN');

Advanced Giveaway with Requirements

// Custom validation for giveaway entries
manager.on('giveawayJoin', (participant, giveaway) => {
  // Custom logic for entry validation
  const member = giveaway.manager.client.guilds.cache.get(giveaway.data.guildId).members.cache.get(participant.id);

  // Check if member has required role
  const hasRequiredRole = member.roles.cache.has('REQUIRED_ROLE_ID');

  if (!hasRequiredRole) {
    // Remove participant if they don't meet requirements
    giveaway.removeParticipant(participant.id);
    manager.emit('giveawayInvalidEntry', participant.id, giveaway);
  }
});

📚 API Reference

GiveawaysManager Class

Constructor

new GiveawaysManager(client: Client, options: ManagerOptions)

Methods

| Method | Parameters | Returns | Description | | ------------------- | ------------------------------ | ------------------------ | ------------------ | | start() | channel, options, overrides? | Promise<Giveaway> | Start new giveaway | | end() | messageId | Promise<Giveaway> | End giveaway | | pause() | messageId | Promise<Giveaway> | Pause giveaway | | resume() | messageId, newEndAt? | Promise<Giveaway> | Resume giveaway | | edit() | messageId, options | Promise<Giveaway> | Edit giveaway | | reroll() | messageId, winnerCount? | Promise<Participant[]> | Reroll winners | | delete() | messageId | Promise<boolean> | Delete giveaway | | list() | status? | Giveaway[] | List giveaways | | leaderboard() | type?, top? | LeaderboardEntry[] | Get leaderboard | | sendLeaderboard() | channel, type?, top? | Promise<void> | Send leaderboard |

Giveaway Class

Methods

| Method | Parameters | Returns | Description | | --------------------- | ---------- | --------------- | -------------------- | | addParticipant() | user | void | Add participant | | removeParticipant() | userId | void | Remove participant | | getParticipants() | | Participant[] | Get all participants | | getWinners() | | string[] | Get winner IDs | | setWinners() | winners | void | Set winners |

Events

| Event | Parameters | Description | | ---------------------- | ----------------------- | ----------------------- | | giveawayJoin | participant, giveaway | User joins giveaway | | giveawayLeave | participant, giveaway | User leaves giveaway | | giveawayInvalidEntry | userId, giveaway | Invalid entry attempt | | giveawayInvalidEntry | userId, giveaway | Invalid entry aص ttempt |


🤝 Contributing

We welcome contributions from the community! Here's how you can help:

Getting Started

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes with proper documentation
  4. Add tests for new functionality
  5. Commit your changes: git commit -m 'Add amazing feature'
  6. Push to the branch: git push origin feature/amazing-feature
  7. Open a Pull Request

Development Setup

git clone https://github.com/Boda335/prizebox.git
cd prizebox
npm install
npm run test
npm run dev

Contribution Guidelines

  • Follow TypeScript best practices
  • Write comprehensive tests
  • Update documentation for new features
  • Use conventional commit messages
  • Ensure backward compatibility

💬 Support & Community

💬 Discord Server

Join our community for support and discussion

Discord

📚 Documentation

Comprehensive guides and examples

Docs

🐛 Bug Reports

Found a bug? Report it here

Issues

💡 Feature Requests

Suggest new features

Features

Getting Help

  • Discord Support: Real-time help from maintainers and community
  • GitHub Issues: Bug reports and technical questions
  • Documentation: Step-by-step guides and API reference
  • Examples Repository: Working code examples and templates

🌟 Star us on GitHub!

If PrizeBox helped you create amazing giveaways, please consider giving us a star ⭐

Made with ❤️ for the Discord community

GitHub NPM