permify
v1.0.1
Published
An enterprise-grade utility for simplified Discord permission management with built-in support for multiple storage backends.
Maintainers
Readme
🛡️ Permify
A robust, enterprise-grade utility for handling permissions and custom access rules in your discord.js bot. This package provides a single, flexible solution for simplifying command logic and ensuring users have the correct access, with support for multiple persistent storage backends.
✨ Key Features
Modular Storage Backends: Seamlessly integrate with In-Memory, SQLite, MySQL, or MongoDB for persistent custom permissions. The storage layer is fully pluggable and easy to extend.
Intuitive API: The
checkAndRespond()method streamlines permission checks, handling denial responses in a single, clean line of code.Advanced Custom Permissions: Easily add or remove custom permissions for specific users and roles, perfect for creating "premium" or staff-only commands. Permissions are stored persistently across bot restarts.
Extensive Error Handling: Every critical operation is wrapped in a
try...catchblock with clear console logging to help you debug and maintain your application in production.Comprehensive Documentation: With detailed JSDoc comments and this
README, the package is easy to use for developers of all skill levels.
📦 Installation
To install the core package, run the following command in your project directory:
npm install permifyFor persistent storage, you must also install the relevant database library:
- SQLite:
npm install sqlite3 - MySQL:
npm install mysql2 - MongoDB:
npm install mongodb
📂 Project Structure
The package is now organized for better clarity and maintenance.
permify/
├── index.js # Main entry point and PermissionsManager class
└── lib/
└── storages/
├── baseStorage.js # Abstract base class for all storage providers
├── inMemoryStorage.js # In-memory storage implementation
├── sqliteStorage.js # SQLite storage implementation
├── mysqlStorage.js # MySQL storage implementation
└── mongoStorage.js # MongoDB storage implementation🚀 Getting Started
To begin, you need to import the PermissionsManager and initialize it with your chosen storage backend. This should be done once when your bot starts up.
1. In-Memory (Default)
This option is perfect for testing or simple bots that do not require permission persistence.
const { PermissionsManager } = require('permify');
// No storageOptions are needed for In-Memory.
const permManager = new PermissionsManager();
// You still need to call initialize() to set up the base provider.
await permManager.initialize();2. SQLite
Ideal for single-process applications, SQLite is a simple, file-based database.
const { PermissionsManager } = require('permify');
const permManager = new PermissionsManager({
storage: 'sqlite',
storageOptions: {
// Optional path to your database file.
path: './permissions.sqlite'
}
});
await permManager.initialize();3. MySQL
Use this for full-fledged relational database support in a multi-process environment.
const { PermissionsManager } = require('permify');
const permManager = new PermissionsManager({
storage: 'mysql',
storageOptions: {
host: 'localhost',
user: 'root',
password: 'your_db_password',
database: 'my_bot_db'
}
});
await permManager.initialize();4. MongoDB
A great choice for a document-based NoSQL database, often used for its flexibility.
const { PermissionsManager } = require('permify');
const permManager = new PermissionsManager({
storage: 'mongodb',
storageOptions: {
uri: 'mongodb://localhost:27017/my_bot_db'
}
});
await permManager.initialize();📝 Command Examples
Example 1: Basic Permission Checking
Use checkAndRespond() to easily check for Discord permissions and send a denial message if the user lacks them.
// A simple slash command to kick a member
if (interaction.commandName === 'kick') {
// Define the required permissions using Discord.js's built-in bitfields
const requiredPerms = [
PermissionsBitField.Flags.KickMembers,
PermissionsBitField.Flags.ViewChannel
];
// The checkAndRespond() method handles the permission check and denial message.
const hasPermissions = await permManager.checkAndRespond(interaction, requiredPerms);
if (!hasPermissions) {
return; // Stop execution if the user doesn't have permissions
}
// If we reach this point, the member has the required permissions.
// Proceed with your command logic here.
const memberToKick = interaction.options.getMember('user');
await memberToKick.kick();
await interaction.reply({ content: `Successfully kicked ${memberToKick.user.username}.`, ephemeral: true });
}Example 2: Custom "Premium" Command System
Create commands that are only accessible to specific users or roles that you manually grant access to. This is perfect for a "premium" feature or a staff-only command.
Step 1: Create a command to grant the custom permission. This should be an administrative command restricted to bot owners or specific roles.
if (interaction.commandName === 'grant-premium') {
const userToGrant = interaction.options.getUser('user');
await permManager.addCustomPermission('premium-command', userToGrant.id);
await interaction.reply({ content: `Successfully granted premium access to ${userToGrant.username}!`, ephemeral: true });
}Step 2: In your premium-command logic, use hasCustomPermission() to check for access.
if (interaction.commandName === 'premium-command') {
const hasPremiumAccess = await permManager.hasCustomPermission(interaction.member, 'premium-command');
if (!hasPremiumAccess) {
return interaction.reply({ content: 'This is a premium-only command!', ephemeral: true });
}
// Only users with custom permission will reach this point.
await interaction.reply({ content: 'Welcome, premium user! This is your special content.', ephemeral: true });
}📚 API Reference
new PermissionsManager(options)
options.storage(string, default:'inmemory'): The storage provider to use. Supported values:'inmemory','sqlite','mysql','mongodb'.options.storageOptions(object, optional): Configuration for the chosen storage.options.ephemeralResponse(boolean, default:true): Sets the default reply visibility for denial messages.
📖 Methods
| Method | Parameters | Return Type | Description |
| :--- | :--- | :--- | :--- |
| initialize() | None | Promise<void> | Connects to the configured storage backend. Must be called before any other methods. |
| hasAllPermissions() | member: GuildMember, permissions: PermissionResolvable | Promise<boolean> | Checks if a member has all the required Discord permissions. |
| hasAnyPermission() | member: GuildMember, permissions: PermissionResolvable | Promise<boolean> | Checks if a member has at least one of the required Discord permissions. |
| getMissingPermissions() | member: GuildMember, requiredPermissions: PermissionResolvable | Promise<string[]> | Returns an array of the permission names that the member is missing. |
| checkAndRespond() | interaction: Interaction, requiredPermissions: PermissionResolvable, customMessage?: string | Promise<boolean> | Checks permissions and responds to the user if they are missing. Returns false if permissions are missing. |
| addCustomPermission() | commandName: string, entityId: string | Promise<void> | Grants a custom permission for a specific user or role. |
| removeCustomPermission() | commandName: string, entityId: string | Promise<void> | Removes a custom permission from a user or role. |
| hasCustomPermission() | member: GuildMember, commandName: string | Promise<boolean> | Checks if a member has a specific custom permission. |
| getCustomPermissionsForCommand() | commandName: string | Promise<string[]> | Retrieves all entities (users/roles) that have a specific custom permission. |
🤝 Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
