Skip to content
This repository was archived by the owner on Oct 5, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions code-samples/sapphire/args/commands/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { Command } = require('@sapphire/framework');

module.exports = class AddCommand extends Command {
constructor(context) {
super(context, {
description: 'Adds two numbers',
});
}

async run(message, args) {
const a = await args.pick('number');
const b = await args.pick('number');
return message.channel.send(`The result is... ${a + b}!`);
}
};
15 changes: 15 additions & 0 deletions code-samples/sapphire/args/commands/add.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Command } from '@sapphire/framework';

export class AddCommand extends Command {
constructor(context) {
super(context, {
description: 'Adds two numbers',
});
}

async run(message, args) {
const a = await args.pick('number');
const b = await args.pick('number');
return message.channel.send(`The result is... ${a + b}!`);
}
}
21 changes: 21 additions & 0 deletions code-samples/sapphire/args/commands/ban.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const { Command } = require('@sapphire/framework');

module.exports = class BanCommand extends Command {
constructor(context) {
super(context, {
description: 'Bans up to 5 members with optionally a reason',
});
}

async run(message, args) {
const members = await args.repeat('member', { times: 5 });
const reason = args.finished ? null : args.rest('string');

// De-duplicate members:
for (const member of new Set(members)) {
await member.ban({ reason });
}

await message.channel.send('Done!');
}
};
21 changes: 21 additions & 0 deletions code-samples/sapphire/args/commands/ban.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Command } from '@sapphire/framework';

export class BanCommand extends Command {
constructor(context) {
super(context, {
description: 'Bans up to 5 members with optionally a reason',
});
}

async run(message, args) {
const members = await args.repeat('member', { times: 5 });
const reason = args.finished ? null : args.rest('string');

// De-duplicate members:
for (const member of new Set(members)) {
await member.ban({ reason });
}

await message.channel.send('Done!');
}
};
14 changes: 14 additions & 0 deletions code-samples/sapphire/args/commands/max.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { Command } = require('@sapphire/framework');

module.exports = class MaxCommand extends Command {
constructor(context) {
super(context, {
description: 'Gets the maximum between a number of numbers',
});
}

async run(message, args) {
const numbers = await args.repeat('number');
return message.channel.send(`The highest number is ${Math.max(...numbers)}!`);
}
};
14 changes: 14 additions & 0 deletions code-samples/sapphire/args/commands/max.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Command } from '@sapphire/framework';

export class MaxCommand extends Command {
constructor(context) {
super(context, {
description: 'Gets the maximum between a number of numbers',
});
}

async run(message, args) {
const numbers = await args.repeat('number');
return message.channel.send(`The highest number is ${Math.max(...numbers)}!`);
}
}
15 changes: 15 additions & 0 deletions code-samples/sapphire/args/commands/pow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { Command } = require('@sapphire/framework');

module.exports = class PowCommand extends Command {
constructor(context) {
super(context, {
description: 'Calculates the exponent of a number with an exponent',
});
}

async run(message, args) {
const base = await args.pick('number');
const exponent = args.finished ? 2 : await args.pick('number');
return message.channel.send(`The result is... ${Math.pow(base, exponent)}!`);
}
};
15 changes: 15 additions & 0 deletions code-samples/sapphire/args/commands/pow.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Command } from '@sapphire/framework';

export class PowCommand extends Command {
constructor(context) {
super(context, {
description: 'Calculates the exponent of a number with an exponent',
});
}

async run(message, args) {
const base = await args.pick('number');
const exponent = args.finished ? 2 : await args.pick('number');
return message.channel.send(`The result is... ${Math.pow(base, exponent)}!`);
}
}
16 changes: 16 additions & 0 deletions code-samples/sapphire/first-command/commands/ping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { Command } = require('@sapphire/framework');

module.exports = class PingCommand extends Command {
constructor(context) {
super(context, {
aliases: ['pong'],
description: 'Tests the latency.',
});
}

async run(message) {
const response = await message.channel.send('Ping...');
const latency = response.createdTimestamp - message.createdTimestamp;
await response.edit(`Pong! Took me ${latency}ms.`);
}
};
16 changes: 16 additions & 0 deletions code-samples/sapphire/first-command/commands/ping.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Command } from '@sapphire/framework';

export class PingCommand extends Command {
constructor(context) {
super(context, {
aliases: ['pong'],
description: 'Tests the latency.',
});
}

async run(message) {
const response = await message.channel.send('Ping...');
const latency = response.createdTimestamp - message.createdTimestamp;
await response.edit(`Pong! Took me ${latency}ms.`);
}
}
5 changes: 5 additions & 0 deletions code-samples/sapphire/getting-started/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { SapphireClient } = require('@sapphire/framework');

const client = new SapphireClient({ intents: ['GUILDS', 'GUILD_MESSAGES'] });

client.login('your-token-goes-here');
5 changes: 5 additions & 0 deletions code-samples/sapphire/getting-started/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SapphireClient } from '@sapphire/framework';

const client = new SapphireClient({ intents: ['GUILDS', 'GUILD_MESSAGES'] });

client.login('your-token-goes-here');
4 changes: 4 additions & 0 deletions guide/.vuepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ const config = defineUserConfig<DefaultThemeOptions, ViteBundlerOptions>({
text: 'Voice',
link: '/voice/',
},
{
text: 'Sapphire',
link: '/sapphire/',
},
{
text: 'Documentation',
link: 'https://discord.js.org/#/docs/main/stable/general/welcome',
Expand Down
49 changes: 49 additions & 0 deletions guide/.vuepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,55 @@ export default {
'/voice/voice-connections.md',
'/voice/audio-player.md',
'/voice/audio-resources.md',
]
}
],
'/sapphire/': [
{
text: 'Home',
children: [
'/',
'/requesting-more-content.md',
'/whats-new.md',
],
},
{
text: 'Getting Started',
children: [
'/sapphire/',
'/sapphire/creating-commands.md',
],
},
{
text: 'Command Preconditions',
children: [
'/sapphire/cooldown.md',
'/sapphire/nsfw.md',
'/sapphire/permissions.md',
'/sapphire/run-in.md',
'/sapphire/creating-preconditions.md',
],
},
{
text: 'Arguments',
children: [
'/sapphire/args.md',
'/sapphire/built-in-arguments.md',
'/sapphire/creating-arguments.md',
],
},
{
text: 'Listeners',
children: [
'/sapphire/creating-listeners.md',
]
},
{
text: 'Additional Information',
children: [
'/sapphire/client-values.md',
'/sapphire/container.md',
'/sapphire/custom-stores.md',
],
},
],
Expand Down
67 changes: 67 additions & 0 deletions guide/sapphire/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Getting started with Sapphire

When installing the Sapphire Framework, you need to install both discord.js and the framework. You can do this by running the following command:

```sh-session
npm install discord.js @sapphire/framework
```

::: warning
You need at least Node.js version 14.0 to use Sapphire.
:::

## Creating an index.js file

While it doesn't have to be called `index.js`, this file is the main file for your bot, which will handle the bot's setup and login. You can also place it inside a folder, such as `src`.

::: warning
Make sure that the `main` property in your `package.json` points to the right path, such as `index.js` or `src/index.js`.
:::

To begin, require `@sapphire/framework` and create a new `SapphireClient`. This is where you can customize Sapphire's behavior, as well as discord.js'. The Sapphire client extends discord.js', so everything from `Client` is available in `SapphireClient`!

:::: code-group
::: code-group-item CommonJS
```js
const { SapphireClient } = require('@sapphire/framework');

const client = new SapphireClient({ intents: ['GUILDS', 'GUILD_MESSAGES'] });

client.login('your-token-goes-here');
```
:::
::: code-group-item ESM
```js
import { SapphireClient } from '@sapphire/framework';

const client = new SapphireClient({ intents: ['GUILDS', 'GUILD_MESSAGES'] });

client.login('your-token-goes-here');
```
:::
::::


Sapphire uses mention prefix (`@bot command`), but you can optionally define a default prefix (or prefixes) with the `defaultPrefix` option, as well as `regexPrefix` if you are familiar with regexes.

There is also the advanced option `baseUserDirectory`, which allows you to define the base directory for Sapphire to scan. By default, Sapphire will register this as the directory where your `main` file is at, joined by the store's name. As such, if the root directory is `src`, it will register `src/commands` as one of the command directories.


::: danger
You should use environment variables or a `config.json` for your token instead of passing it directly!
You can read more about why you should [here](/preparations/setting-up-a-bot-application.html#keeping-your-token-safe).
:::

And that's it for your `index.js` file! In the end, your file structure should look like this, along with whatever `.gitignore` or `config.json` files you may have:

```:no-line-numbers
node_modules/
src/
└── index.js
package-lock.json
package.json
```

## Resulting code

<ResultingCode />
Loading