permify
Version:
An enterprise-grade utility for simplified Discord permission management with built-in support for multiple storage backends.
211 lines (153 loc) ⢠8.94 kB
Markdown
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.
* **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...catch` block 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.
-----
To install the core package, run the following command in your project directory:
```
npm install permify
```
For persistent storage, you **must also install the relevant database library**:
* **SQLite:** `npm install sqlite3`
* **MySQL:** `npm install mysql2`
* **MongoDB:** `npm install mongodb`
-----
The package is now organized for better clarity and maintenance.
```
permify/
āāā index.js
āāā lib/
āāā storages/
āāā baseStorage.js
āāā inMemoryStorage.js
āāā sqliteStorage.js
āāā mysqlStorage.js
āāā mongoStorage.js
```
-----
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.
This option is perfect for testing or simple bots that do not require permission persistence.
```javascript
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();
```
Ideal for single-process applications, SQLite is a simple, file-based database.
```javascript
const { PermissionsManager } = require('permify');
const permManager = new PermissionsManager({
storage: 'sqlite',
storageOptions: {
// Optional path to your database file.
path: './permissions.sqlite'
}
});
await permManager.initialize();
```
Use this for full-fledged relational database support in a multi-process environment.
```javascript
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();
```
A great choice for a document-based NoSQL database, often used for its flexibility.
```javascript
const { PermissionsManager } = require('permify');
const permManager = new PermissionsManager({
storage: 'mongodb',
storageOptions: {
uri: 'mongodb://localhost:27017/my_bot_db'
}
});
await permManager.initialize();
```
-----
Use `checkAndRespond()` to easily check for Discord permissions and send a denial message if the user lacks them.
```javascript
// 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 });
}
```
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.
```javascript
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.**
```javascript
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 });
}
```
-----
* **`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.
| 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.
-----
## āļø License
[MIT](https://choosealicense.com/licenses/mit/)
A robust, enterprise-grade utility