+}
+
+```
+Make sure its been added:
+```ts title="src/index.ts"
+await makeDependencies({
+ build: root => root
+ .add({ database => new Database() })
+})
+```
+
+
+
diff --git a/docs/guide/walkthrough/first-command.md b/docs/guide/walkthrough/first-command.md
index 0f858891f..a965ba24d 100644
--- a/docs/guide/walkthrough/first-command.md
+++ b/docs/guide/walkthrough/first-command.md
@@ -1,13 +1,41 @@
---
-sidebar_position: 3
+sidebar_position: 4
---
# First Command
+
We will dissect a basic command.
If you installed a new project via the cli, This is the `ping` command located in src/commands folder.
-Typescript
-```typescript
+:::tip
+TLDR: command modules are discord bot commands. There are many types, and each one will correspond to an event from discord.
+For example, CommandType.Slash commands will listen to slash command interactions.
+:::
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+
+
+
+```js
+const { CommandType, commandModule } = require('@sern/handler');
+
+export default commandModule({
+ type: CommandType.Both,
+ plugins: [],
+ description: 'A ping command',
+ // alias : [],
+ execute: async (ctx, args) => {
+ await ctx.reply('Pong 🏓');
+ },
+})
+```
+
+
+
+
+```ts
import { commandModule, CommandType } from '@sern/handler';
export default commandModule({
@@ -19,21 +47,14 @@ export default commandModule({
await ctx.reply({ content: 'Pong 🏓' });
},
});
-```
-Javascript
-```javascript
-const { CommandType, commandModule } = require('@sern/handler');
-exports.default = commandModule({
- type: CommandType.Both,
- plugins: [],
- description: 'A ping command',
- // alias : [],
- execute: async (ctx, args) => {
- await ctx.reply('Pong 🏓');
- },
-})
```
+
+
+
+
+
+
To view what each of these properties mean in depth, visit the [official documentation](https://sern.dev/docs/api/enums/CommandType).
### Types of command modules
Every command module `type` is part of an enum. This field allows type inference for the rest of a module's fields.
@@ -43,7 +64,27 @@ All the command types can be found in the [official documentation](https://sern.
**Note**: Keep in mind you'll need to send a modal with a custom id `dm-me`. This example below is the response to a modal being sent.
-Typescript:
+
+
+
+```javascript
+const { CommandType, commandModule } = require('@sern/handler');
+exports.default = commandModule({
+ name: 'dm-me',
+ type: CommandType.Modal,
+ async execute (modal) {
+ const value = modal.fields.getTextInputValue('message');
+ modal.client.users.fetch('182326315813306368').then( u =>
+ u.send(value + ` from ${modal.user}`)
+ );
+ modal.reply( { ephemeral:true, content: 'Sent' })
+ }
+});
+```
+
+
+
+
```typescript
import { commandModule, CommandType } from '@sern/handler';
export default commandModule({
@@ -58,21 +99,12 @@ export default commandModule({
}
});
```
-Javascript:
-```javascript
-const { CommandType, commandModule } = require('@sern/handler');
-exports.default = commandModule({
- name: 'dm-me',
- type: CommandType.Modal,
- async execute (modal) {
- const value = modal.fields.getTextInputValue('message');
- modal.client.users.fetch('182326315813306368').then( u =>
- u.send(value + ` from ${modal.user}`)
- );
- modal.reply( { ephemeral:true, content: 'Sent' })
- }
-});
-```
+
+
+
+
+
+
Commands are straight forward. Keep in mind, every other property on the commandModule object is
optional **except** the type and execute function.
@@ -85,31 +117,4 @@ The Context class is passed into modules with type:
- `CommandType.Text`
This data structure helps interop between legacy commands and slash commands with ease.
-:::note
-View the [docs](../../api/classes/Context.md)
-:::
-Typescript:
-```typescript
-export default commandModule({
- name: 'ping',
- type: CommandType.Both,
- async execute(ctx: Context) {
- await ctx.reply(`pong ${ctx.user}`)
- // .reply is shared between both message and interaction!
- // So is an User object!
- }
-});
-```
-Javascript:
-```javascript
-exports.default = commandModule({
- name: 'ping',
- type: CommandType.Both,
- async execute(ctx) { //ctx is a Context instance
- await ctx.reply(`pong ${ctx.user}`)
- // .reply is shared between both message and interaction!
- // So is an User object!
- }
-});
-```
diff --git a/docs/guide/walkthrough/first-event.md b/docs/guide/walkthrough/first-event.md
index ac7eedab7..178400b59 100644
--- a/docs/guide/walkthrough/first-event.md
+++ b/docs/guide/walkthrough/first-event.md
@@ -1,21 +1,20 @@
---
-sidebar_position: 4
+sidebar_position: 5
---
# First Event Module
We will dissect a basic event module.
-Typescript:
-```typescript
-export default eventModule({
- type: EventType.Sern,
- plugins : [],
- name: 'module.activate', //name of event.
- execute(event) {
- console.log(event);
- }
-})
-```
-Javascript:
+
+:::tip
+TLDR: event modules are event listeners. there are three types EventType.Discord, EventType.Sern, EventType.External
+:::
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+
+
+
```javascript
exports.default = eventModule({
type: EventType.Sern,
@@ -26,37 +25,52 @@ exports.default = eventModule({
}
})
```
+
+
+
+
+```typescript
+export default eventModule({
+ type: EventType.Sern,
+ plugins : [],
+ name: 'module.activate', //name of event.
+ execute(event) {
+ console.log(event);
+ }
+})
+```
+
+
+
+
+
Like command modules, the `type` property denotes what kind of event it is, which
can be found [here](https://sern.dev/docs/api/enums/EventType).
To view what each of these properties mean in depth, visit the [official documentation](https://sern.dev/docs/api/enums/EventType).
-
-Event modules are laid out similarly to command modules. These listen to any and all event you provide.
+## External
-### Another example of an event module
+In version 2 & 3, any dependency that you have passed into makeDependencies can be registered here as well.
-Typescript:
-```typescript
-export default eventModule({
- type: EventType.Discord,
- plugins : [],
- name: 'guildMemberAdd', //name of event.
- async execute(member: GuildMember) {
- (await member.guild.channels.fetch('channel-id') as TextChannel).send(`Welcome, ${member}`);
- }
+```ts title="src/index.ts"
+await makeDependencies({
+ build: root => root.add({
+ eventlistener: single(() => new EventEmitter())
+ })
})
```
-Javascript:
-```javascript
+```ts title="events/myevent.ts"
+export default eventModule({
+ type: EventType.External,
+ emitter: 'eventlistener',
+ execute: (args) => {
+ console.log('Got event from eventlistener: ', args);
+ }
-exports.default = eventModule({
- type: EventType.Discord,
- plugins : [],
- name: 'guildMemberAdd', //name of event.
- async execute(member) {
- (await member.guild.channels.fetch('channel-id')).send(`Welcome, ${member}`);
- }
})
+
```
+
+
diff --git a/docs/guide/walkthrough/goal.md b/docs/guide/walkthrough/goal.md
index 5a0180fcd..7e6c3976e 100644
--- a/docs/guide/walkthrough/goal.md
+++ b/docs/guide/walkthrough/goal.md
@@ -2,17 +2,50 @@
sidebar_position: 1
---
-:::warning
-Please read the transition page if you are moving from version 2 to version 3.
-:::
-# Walkthrough
+
+# Goal
This walkthrough will be written in [TypeScript](https://www.typescriptlang.org/) but will have JavaScript snippets throughout.
-# Goal
+# Make robust, modular, bots
-sern strives to be minimalist, but with all batteries included. Meaning, this framework provides the necessary tools
-to start up a bot in minutes, and leaves plenty room space to customize your experience and create an amazing project.
-It should include all the tools for any bot at any scale.
+- *Modularity*: sern is built with modularity in mind. You can swap pieces and parts easily.
+- *Familiar*: commands and structures are similar to classic v12 handlers and the official discord.js command handler guide, while packing many features
+- *Concise*: Too much code is a liability. with sern, write more for less 🤯
+
+### Using @sapphire/framework
+```ts title="commands/ping.ts" showLineNumbers
+import { Command } from '@sapphire/framework'
+import type { CommandInteraction } from 'discord.js'
+
+export class PingCommand extends Command {
+ public constructor(context: Command.Context) {
+ super(context, {
+ description: 'Pong!',
+ chatInputCommand: {
+ register: true,
+ },
+ })
+ }
+ public async chatInputRun(interaction: CommandInteraction) {
+ await interaction.reply('Pong!')
+ }
+}
+```
+### Using @sern/handler
+```ts title="commands/ping.ts" showLineNumbers
+import { commandModule, CommandType } from '@sern/handler'
+import { publish } from '../plugins';
+
+export default commandModule({
+ //This acts as both a slash command AND text command
+ type: CommandType.Both,
+ plugins: [publish()],
+ description: 'Pong!',
+ execute: (ctx, args) => {
+ await ctx.reply('Pong!')
+ }
+})
+```
diff --git a/docs/guide/walkthrough/new-project.md b/docs/guide/walkthrough/new-project.md
new file mode 100644
index 000000000..224f7eed9
--- /dev/null
+++ b/docs/guide/walkthrough/new-project.md
@@ -0,0 +1,24 @@
+---
+sidebar_position: 1
+---
+
+# Create a new project
+
+```sh
+npm install -g @sern/cli
+```
+Running this will install our CLI. (you'll probably want to download this)
+ - helps manage your applications
+ - plugs you into the sern ecosystem.
+
+
+
+### Create a new bot
+
+```sh
+npm create @sern/bot
+```
+and follow the interactive prompts.
+
+if somehow you need help, feel free to ask [here](https://sern.dev.discord)
+
diff --git a/docs/guide/walkthrough/plugins.md b/docs/guide/walkthrough/plugins.md
index a72fcf7f6..fee0ef2a0 100644
--- a/docs/guide/walkthrough/plugins.md
+++ b/docs/guide/walkthrough/plugins.md
@@ -1,59 +1,45 @@
---
-sidebar_position: 5
+sidebar_position: 6
---
# Plugins
-As of now, modules seem a little underwhelming. It appears that sern doesn't have all the features of a standard handler,
-which manages permissions, categorizes, cool-downs, publishes application commands, role permissions, etc.
+:::tip
+TLDR: Plugins help reduce code repetition and are installable via `sern plugins`. Put them onto the plugins field of a command/event module.
+:::
+## Installing
+Chances are, you just want your bot to work. Plugins can preprocess and create reusable conditions for modules.
-Many important parts that manage access and help streamline command creation to make are apparently absent.
-Below is an example of an event plugin, one of the types of plugins.
-
-Typescript:
-```typescript
-export function serenOnly(): EventPlugin {
- return {
- type: PluginType.Event,
- async execute([ctx, args], controller) {
- if (ctx.user.id !== "182326315813306368") {
- await ctx.reply({content: "You cannot use this command"})
- return controller.stop()
- }
- return controller.next();
- }
- }
-}
+run:
+```sh
+sern plugins
```
-Javascript:
-```javascript
-export function serenOnly() {
- return {
- type: PluginType.Event,
- async execute([ctx, args], controller) {
- if (ctx.user.id !== "182326315813306368") {
- await ctx.reply({content: "You cannot use this command"})
- return controller.stop()
- }
- return controller.next();
- }
+- Install your favorite(s) (or the ones that look the coolest). In my imaginary mind, I installed the ownerOnly plugin.
+ - This should install in `plugins` directory in `src`.
+- Some plugins only work with specific types. Most are targeted towards slash / both modules.
+- Add to your module.
+
+```ts
+import { commandModule, CommandType } from '@sern/handler'
+import { ownerOnly } from '../plugins'
+
+export default commandModule({
+ type: CommandType.Both,
+ plugins: [ownerOnly(['182326315813306368')],
+ description: 'ping command',
+ execute: (ctx) => {
+ ctx.reply('hello, owner');
}
-}
+})
+
```
+#### ┗|`O′|┛ perfect, your first plugin!
-
As part of being extensibile, plugins make sern just as powerful, if not more powerful than
-standard handlers.
-Plugins modify and add new behavior to standard modules.
+## Creating your own plugins
-
At the moment, there are two types of plugins:
+The controller determines in plugins whether to continue or fail.
-- Init Plugins
-- Control Plugins
-
-## Init Plugins
-All modules are registered into sern's system. Init plugins modify how commands are loaded.
-or do some kind of preprocessing before loaded.
### The controller object
```typescript
export interface Controller {
@@ -61,45 +47,29 @@ export interface Controller {
stop: () => Err;
}
```
+## Init Plugins
+Init plugins modify how commands are loaded or do preprocessing.
An instance of the above object is passed into every plugin.
This controls whether a module is stored into sern.
-Typescript:
+
```typescript
-export function inDir(dir : string) : CommandPlugin {
- return {
- type: PluginType.Init,
- async execute({ absPath, module }) {
- if(path.dirname(absPath) !== dir) {
- console.log(+new Date(), `${module.name} is not in the correct directory!`);
- return controller.stop()
- }
- console.log(+new Date(), `${module.name} is in the correct directory!`);
- return controller.next(); //continue
- }
- }
-}
-```
-Javascript:
-```javascript
-export function inDir(dir : string) {
- return {
- type: PluginType.Init,
- async execute({ absPath, module }) {
- if(path.dirname(absPath) !== dir) {
+import { CommandInitPlugin } from '@sern/handler'
+import path from 'path'
+export const inDir = (dir: string) => {
+ return CommandInitPlugin(({ module, absPath }) => {
+ if(path.dirname(absPath) !== dir) {
console.log(+new Date(), `${module.name} is not in the correct directory!`);
return controller.stop()
- }
- console.log(+new Date(), `${module.name} is in the correct directory!`);
- return controller.next(); //continue
- }
- }
+ }
+ console.log(+new Date(), `${module.name} is in the correct directory!`);
+ return controller.next(); //continue
+ });
}
+
```
+
Above, this simple plugin logs that the module has been loaded along with a timestamp.
-Again, it is up to **you** to define plugin logic! The possibilities to customize your bots are endless.
-:::tip
-Init Plugins are good for ensuring the shape, maintaining location, and preprocessing commands.
-:::
+
## Event Plugins

- An event is emitted by discord.js.
@@ -107,44 +77,8 @@ Init Plugins are good for ensuring the shape, maintaining location, and preproce
- If all are successful,
The command is executed. Calling `controller.stop()` notifies sern that this command should not be run,
-and this event is ignored.
+and command is ignored.
-So, what does a command module look like with plugins?
-
-Typescript:
-```typescript
-import { commandModule, CommandType } from '@sern/handler';
-
-export default commandModule({
- type: CommandType.Both,
- plugins: [
- inDir("other"),
- serenOnly()
- ],
- description: 'A ping command',
- //alias : [],
- execute: async (ctx, args) => {
- await ctx.reply({ content: 'Pong 🏓' });
- },
-});
-```
-Javascript:
-```typescript
-const { commandModule, CommandType } = require('@sern/handler');
-
-exports.default = commandModule({
- type: CommandType.Both,
- plugins: [
- inDir("other"),
- serenOnly() //The plugins in this section applied to this module!
- ],
- description: 'A ping command',
- //alias : [],
- execute: async (ctx, args) => {
- await ctx.reply({ content: 'Pong 🏓' });
- },
-});
-```
Can you predict the behavior of this command?
- Before loading into sern, this command module will check if this module is in the correct directory `other`.
diff --git a/docs/guide/walkthrough/services.md b/docs/guide/walkthrough/services.md
new file mode 100644
index 000000000..523556903
--- /dev/null
+++ b/docs/guide/walkthrough/services.md
@@ -0,0 +1,63 @@
+---
+sidebar_position: 6
+---
+
+:::tip
+This is version 3 api only!!
+:::
+
+# Services
+
+:::tip
+TLDR: The direct upgrade to useContainer. if you set up a bot with create-bot, check dependencies.d.ts.
+Dependencies are the types that Services uses.
+:::
+
+You need someway to use dependencies in your command module. Services to the rescue!
+```ts title="src/dependencies.d.ts"
+import { CoreDependencies, Singleton } from '@sern/handler'
+import { Client } from 'discord.js'
+
+interface Dependencies extends CoreDependencies {
+ '@sern/client': Singleton
+}
+
+```
+Recall, some keys in Dependencies are special.
+
+> Special key dependency must implement its contracts.
+> - `@sern/client`: Your discord client. -> [Emitter](../../api/interfaces/Emitter)
+> - `@sern/logger`: Log data -> [Logging](../../api/interfaces/Logging)
+> - `@sern/errors`: Handling errors and lifetime -> [ErrorHandling](../../api/interfaces/ErrorHandling)
+> - `@sern/modules`: Managing all command modules -> [ModuleManager](../../api/interfaces/ModuleManager)
+> - `@sern/emitter`: is the key to emit events and occurences in a project -> [Emitter](../../api/interfaces/Emitter)
+
+
+Lets try to access the client you provided.
+
+```ts title="src/commands/ping.ts"
+import { Service } from '@sern/handler'
+
+export default commandModule({
+ // ...
+ execute: (ctx) => {
+ //Client!
+ const client = Service('@sern/client');
+ }
+ //
+})
+
+```
+## Safety
+- Services can only be used after sern has made dependencies.
+ - Calling a service before will crash your application.
+- Services can be safely used outside of commandModules.
+ - Be careful to not cause too many side effects.
+
+
+## Related api
+- use `Service` for single dependency.
+- use `Services` for multiple dependencies.
+
+
+
diff --git a/docs/guide/walkthrough/transition.md b/docs/guide/walkthrough/transition.md
index 6efc1e22d..b4dee8722 100644
--- a/docs/guide/walkthrough/transition.md
+++ b/docs/guide/walkthrough/transition.md
@@ -1,21 +1,16 @@
---
-sidebar_position: 1
+sidebar_position: 3
---
+
# transition from v2 to v3
-:::warning
-The "Node" moduleResolution is the only one that has been tested to work with sern.
-:::
-- Sern.makeDependencies -> makeDependencies
- - it is asynchronous and top level function now. Make sure to await it before initing for proper synchronization.
-
-
-```diff
+```diff title="src/index.ts"
- Sern.makeDependencies({ build: () => {} })
+ await makeDependencies({ build: () => {} })
```
-Also, v3 comes with the new Service api. To make sure to enable intellisense
+
+v3 comes with the new [Service api](../walkthrough/services). To make sure to enable intellisense
include a dependencies.d.ts file into compilation. [Click here for all new features](../../../blog/3.0.0)
```ts
/**
@@ -42,13 +37,4 @@ A standard project file tree:

-:::tip
-Usually, you would use the create-bot tool.
-For brand new bots, run
-```sh
-npm create @sern/bot
-```
-
-and follow the interactive prompts.
-:::tip
diff --git a/docs/intro.md b/docs/intro.md
index 30db95bda..5161a62a4 100644
--- a/docs/intro.md
+++ b/docs/intro.md
@@ -4,7 +4,12 @@ sidebar_position: 0
# Welcome!
+:::warning
+Please read the [transition](./transition) page if you are moving from version 2 to version 3.
+:::
+
## Content
+- [transition](../docs/guide/walkthrough/transition.md) for current users to transition bots to version 3.
- [/docs/api](../docs/api) contains autogenerated documentation of our codebase using [typedoc](https://typedoc.org/)
- [/docs/guide](../docs/guide) contains a basic startup guide and details to get started with sern faster!
diff --git a/material-theme.zip b/material-theme.zip
new file mode 100644
index 000000000..d57340646
Binary files /dev/null and b/material-theme.zip differ
diff --git a/src/components/HomepageFeatures/index.js b/src/components/HomepageFeatures/index.js
index bc853ab57..854caf95e 100644
--- a/src/components/HomepageFeatures/index.js
+++ b/src/components/HomepageFeatures/index.js
@@ -4,36 +4,35 @@ import styles from './styles.module.css';
const FeatureList = [
{
- title: 'Batteries included',
- Svg: require('@site/static/img/battery-svgrepo-com.svg').default,
- description: (
- <>
- Start or integrate a new project in minutes.
- >
- ),
- },
- {
- title: 'Customizable',
+ title: 'Modular',
+
Svg: require('@site/static/img/puzzle-svgrepo-com.svg').default,
description: (
<>
- Extend or customize with community-based plugins to provide utilities, filters, and more.
+ Take apart, build, or customize code with ease to create robust bots.
>
),
},
{
- title: 'Modern',
+ title: 'Concise',
Svg: require('@site/static/img/typescript-svgrepo-com.svg').default,
description: (
<>
- Uses modern and powerful tooling such as
- swc,
- tsup,
- typescript, and
- rxjs to future-proof and ensure project quality.
+ Commands are significantly smaller than other competitors.
+ Write impactful, concise code.
>
),
},
+ {
+ title: 'Familiar',
+ Svg: require('@site/static/img/battery-svgrepo-com.svg').default,
+ description: (
+ <>
+ Code like a traditional command handler. Feels and looks like classic v12 command handlers.
+ >
+ ),
+ },
+
];
function Feature({Svg, title, description}) {
diff --git a/src/components/HomepageFeatures/styles.module.css b/src/components/HomepageFeatures/styles.module.css
index b248eb2e5..f06fe436f 100644
--- a/src/components/HomepageFeatures/styles.module.css
+++ b/src/components/HomepageFeatures/styles.module.css
@@ -1,3 +1,4 @@
+
.features {
display: flex;
align-items: center;
diff --git a/src/css/custom.css b/src/css/custom.css
index 41037e1c1..ca43e5897 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -6,20 +6,21 @@
/* You can override the default Infima variables here. */
:root {
- --ifm-color-primary: #3d2d5e;
+ --ifm-color-primary: #ae2a55;
--ifm-color-primary-dark: #372955;
- --ifm-color-primary-darker: #342650;
+ /* darker is secondary color in material */
+ --ifm-color-primary-darker: #385ca9;
--ifm-color-primary-darkest: #2b2042;
--ifm-color-primary-light: #433267;
--ifm-color-primary-lighter: #46346c;
- --ifm-color-primary-lightest: #3a2b59;
- --ifm-background-color: #e7e6e8;
+ --ifm-color-primary-lightest: #d9e2ff;
+ --ifm-background-color: #fffbff;
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(82, 78, 183, 0.2);
--ifm-font-family-monospace: 'Fira Code', 'Meslo NGF', 'JetBrains Mono', 'Menlo', SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
'Courier New', monospace;
--ifm-font-family-base: Mulish, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
- --ifm-navbar-background-color : #F25186
+ --ifm-navbar-background-color: #ffd9df;
}
.footer--dark {
@@ -29,14 +30,15 @@
/* For readability concerns, you should choose a lighter palette in dark mode. */
[data-theme='dark'] {
- --ifm-color-primary: #f7dbf2;
+ --ifm-color-primary: #ffb1c1;
--ifm-color-primary-dark: #efb5e4;
- --ifm-color-primary-darker: #eaa2dd;
+ /* darker is secondary color in material */
+ --ifm-color-primary-darker: #b0c6ff;
--ifm-color-primary-darkest: #de69c9;
--ifm-color-primary-light: #ffffff;
--ifm-color-primary-lighter: #ffffff;
--ifm-color-primary-lightest: #ffffff;
--docusaurus-highlighted-code-line-bg: rgba(82, 78, 183, 0.3);
--ifm-font-family-monospace: 'JetBrains Mono', 'Fira Code', 'Meslo NGF', 'Menlo', SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace;
- --ifm-navbar-background-color : #F25186
+ --ifm-navbar-background-color :#66002a
}
diff --git a/src/pages/index.js b/src/pages/index.js
index 8aab839f0..3a10cdfab 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -10,7 +10,7 @@ import styles from './index.module.css';
function HomepageHeader() {
const { siteConfig } = useDocusaurusContext();
return (
-
+
@@ -52,7 +52,7 @@ export default function Home() {
>
-
+
diff --git a/static/img/R.png b/static/img/R.png
deleted file mode 100644
index ad1a862c5..000000000
Binary files a/static/img/R.png and /dev/null differ