feat: rewrite most of the docs pages

This commit is contained in:
DuroCodes
2024-05-08 23:58:28 -04:00
parent b6c9174230
commit 40a2e39fc8
26 changed files with 556 additions and 371 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -6,7 +6,7 @@ export default defineEcConfig({
defaultProps: {
showLineNumbers: false,
overridesByLang: {
'js,javascript,typescript,ts': {
'js,javascript,typescript,ts,json': {
showLineNumbers: true,
},
},

View File

@@ -0,0 +1,60 @@
---
import { Tabs, TabItem, Code } from "@astrojs/starlight/components";
type Command = "add" | "update" | "remove";
type PackageManager = (typeof packageManagers)[number];
const packageManagers = ["NPM", "PNPM", "Yarn", "Bun"] as const;
interface Props {
command: Command;
text: string;
}
const packageManagerCode = (
command: Command,
text: string,
manager: PackageManager,
) => {
const commands = {
add: {
NPM: `npm install ${text}`,
Yarn: `yarn add ${text}`,
PNPM: `pnpm add ${text}`,
Bun: `bun add ${text}`,
},
update: {
NPM: `npm update ${text}`,
Yarn: `yarn upgrade ${text}`,
PNPM: `pnpm update ${text}`,
Bun: `bun update ${text}`,
},
remove: {
NPM: `npm uninstall ${text}`,
Yarn: `yarn remove ${text}`,
PNPM: `pnpm remove ${text}`,
Bun: `bun remove ${text}`,
},
create: {
NPM: `npm create ${text}`,
Yarn: `yarn create ${text}`,
PNPM: `pnpm create ${text}`,
Bun: `bun create ${text}`,
}
};
return commands[command][manager];
};
const { command, text } = Astro.props;
---
<Tabs syncKey="package-manager">
{
packageManagers.map((manager) => (
<TabItem label={manager}>
<Code lang="sh" code={packageManagerCode(command, text, manager)} />
</TabItem>
))
}
</Tabs>

View File

@@ -11,9 +11,9 @@ date: 2022-09-28
Today we're announcing the ability to create class based modules!
To get started, install
```
npm install @sern/handler@latest
```
import PackageManagers from '~/components/PackageManagers.astro';
<PackageManagers command="add" text="@sern/handler@latest" />
Quick List of changes!

View File

@@ -16,13 +16,13 @@ Today I'm going to show you how to get started with sern and all its cool featur
Install the CLI:
```
npm i -g @sern/cli
```
import PackageManagers from '~/components/PackageManagers.astro';
<PackageManagers command="add" text="-g @sern/cli"/>
and then run
```
```sh
sern init
```
@@ -30,7 +30,7 @@ sern init
You can also run `sern init -y` if you want to use the default options.
:::
The CLI is written in Typescript and open-sourced on [Github](https://github.com/sern-handler/cli). (thanks [evo](https://github.com/EvolutionX-10)!)
The CLI is written in TypeScript and open-source on [GitHub](https://github.com/sern-handler/cli). (thanks [evo](https://github.com/EvolutionX-10)!)
### Step 2: Have some way to store secrets.

View File

@@ -6,7 +6,7 @@ Choosing an IDE is a matter of personal preference. They make programming easier
suggestions for choosing an IDE:
- [Visual Studio Code](https://code.visualstudio.com)
- we have an [snippet extension](https://marketplace.visualstudio.com/items?itemName=SrIzan.sern-snippets) to help automate development :)
- We have an [snippet extension](https://marketplace.visualstudio.com/items?itemName=SrIzan.sern-snippets) to help automate development :)
- [Sublime Text](https://www.sublimetext.com/)
- [NotePad++](https://notepad-plus-plus.org/)
- [nvim](https://neovim.io/) (chad)

View File

@@ -2,12 +2,10 @@
title: Preparing to Code
---
After installing an IDE, you need to install node.
After installing an IDE, you need to install `node`. Node is necessary to use `sern`, as it's based on `Discord.js`.
[Click to download the LTS version of node right here](https://nodejs.org/en/download/).
You can download Node from the official website [here](https://nodejs.org/en/download/).
After you downloaded node you will need:
#### [Discord token](https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token)
After you've downloaded Node you will need a [Discord token](https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&-getting-a-token)
CONTINUE 🤓

View File

@@ -4,12 +4,15 @@ sidebar:
order: 9
---
Autocomplete is a special interaction where it can happen on multiple options on a single command. We've handled this with a simple
tree search algorithm in a nested options tree.
Autocomplete is a special interaction which can happen on multiple options can be suggested for a single command.
We've implemented this functionality using a simple tree search algorithm within a nested options tree.
## Example
```ts title="src/commands/cheese.ts" {13-21}
In this example, the option `list` will autocomplete with the cheeses `gouda`, `parmesan`, and `harvarti`.
```ts title="src/commands/cheese.ts" {13-22}
export default commandModule({
type: CommandType.Slash,
description: "show me cheese",
@@ -23,9 +26,10 @@ export default commandModule({
command: {
onEvent: [],
execute: (ctx) => {
// focus can be used to refine the options
const focus = ctx.options.getFocused();
ctx.respond(
["gouda", "parmesan", "harvati"].map((cheese) => ({
["gouda", "parmesan", "harvarti"].map((cheese) => ({
name: cheese,
value: cheese,
})),
@@ -41,4 +45,48 @@ export default commandModule({
});
```
## Using Focus
The `focus` object can be used to refine the options. For example, if the user types `g`, the focus object will be `g`.
We can filter the cheeses based on the focus object, and return only the cheeses that start with the focus object.
You can do a lot more with the focus object, such as performing API calls, or implementing a fuzzy search.
```ts title="src/commands/cheese.ts" {13-23}
export default commandModule({
type: CommandType.Slash,
description: "show me cheese",
options: [
{
name: "list",
type: ApplicationCommandOptionType.String,
description: "pick a cheese to show",
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: (ctx) => {
const focus = ctx.options.getFocused();
ctx.respond(
["gouda", "parmesan", "harvarti"]
.filter((cheese) => cheese.startsWith(focus))
.map((cheese) => ({
name: cheese,
value: cheese,
})),
);
},
},
},
],
execute: (ctx, [, args]) => {
const cheese = args.getString("list", true);
ctx.reply("selected cheese");
},
});
```
:::tip
Sern will handle autocomplete interactions at arbitrary depths and subcommand levels.
:::

View File

@@ -1,37 +0,0 @@
---
title: CLI
sidebar:
order: 3
---
Setting up the [CLI](https://github.com/sern-handler/cli) is easy.
The cli is your plug to the sern ecosystem. This will allow you to install plugins with ease, install extra utilities, and much more.
If you haven't yet:
```sh
npm install -g @sern/cli
```
- To install [plugins](plugins.md) maintained by the community [repository](https://github.com/sern-handler/awesome-plugins),
```sh
sern plugins
```
:::caution
Make sure to have a correct [sern.config.json](../good-to-know.md#sernconfigjson)
:::
This will display a menu selection of all installable plugins.
**Note**: You must have a [sern.config.json](../good-to-know.md) to use this command.
If you want to view plugins, visit the repository linked above.
- To install extra utilities into your project
```sh
sern extra
```
We have a more in depth [guide](../../cli/README.md) of the CLI

View File

@@ -0,0 +1,43 @@
---
title: CLI
sidebar:
order: 3
---
Setting up the [CLI](https://github.com/sern-handler/cli) is easy.
The CLI is your plug to the sern ecosystem. It allows you to install plugins with ease, install extra utilities, and much more.
## Installing the CLI
If you haven't already installed the CLI globally, you can do so by running:
import PackageManagers from '~/components/PackageManagers.astro';
<PackageManagers command="add" text="-g @sern/cli"/>
## Adding Plugins
:::caution
You must have a [sern.config.json](../good-to-know.md#sernconfigjson) to use this command.
:::
To install [plugins](../plugins) maintained by the community [repository](https://github.com/sern-handler/awesome-plugins):
```sh
sern plugins
```
This will display a menu selection of all installable plugins.
If you'd like to view all plugins, check out our [plugins page](../../../plugins).
## Extra Utilities
To install extra utilities into your project, run:
```sh
sern extra
```
We have a more in depth [guide](../../../cli/about) on the CLI if you're interested in learning more.

View File

@@ -1,11 +0,0 @@
---
title: Conclusion
sidebar:
order: 12
---
If you reached this far, thank you for reading! We hope you have learned the necessities you need
to create a bot with the sern framework. If you have any other questions, bugs, feature requests, concerns, please join our
[community server](https://sern.dev/discord), and we'll be glad to answer your questions.
![](/blog/newlogo/paperlogo.png)

View File

@@ -0,0 +1,16 @@
---
title: Conclusion
sidebar:
order: 12
---
If you reached this far, thank you for reading!
We hope you have learned the necessities you need to create a bot with the sern framework.
If you have any other questions, bugs, feature requests, concerns, please join our [community server](https://sern.dev/discord), and we'll be glad to answer your questions!
import { Image } from 'astro:assets';
import paperLogo from '~/assets/blog/paper-logo.png';
<Image src={paperLogo} alt="paper logo" />

View File

@@ -1,113 +0,0 @@
---
title: Dependency Injection
sidebar:
order: 10
---
:::caution
This contains version 2 code. Please view [transitioning to v3](./transition)
:::
Since version 2.0.0, dependency injection, thanks to [iti](https://github.com/molszanski/iti), is a feature to customize your bot's utilities and structures.
Minimal setup for any project.
```ts
const client = new Client({
...options,
});
Sern.makeDependencies<MyDependencies>({
build: (root) =>
root.add({
"@sern/client": single(() => client),
}),
});
```
For any typescript project, you'll need to add an interface to get intellisense and typings.
```typescript
interface MyDependencies extends Dependencies {
"@sern/client": Singleton<Client>;
}
```
Full Dependency Injection setup
```typescript
const client = new Client({
...options,
});
interface MyDependencies extends Dependencies {
"@sern/client": Singleton<Client>;
}
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: (root) =>
root.add({
"@sern/client": single(() => client),
}),
});
```
Everything else is handled. However, you may want customize things.
## Adding dependencies to root
Each sern built dependency must implement its contracts.
- `@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. [SernEmitter](../../api/classes/SernEmitter)
You may also add disposers so that when the application crashes, the targeted dependency calls that function.
```typescript
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: (root) =>
root
.add({
"@sern/client": single(() => client),
})
.addDisposer({ "@sern/client": (client) => client.destroy() }),
});
```
:::tip
Below is v3 api.
:::
## Init
Do you need to perform intializing behavor for a dependency?
```ts
import { Init } from "@sern/handler";
class Database implements Init {
init() {
await this.connect();
console.log("Connected");
}
}
```
Modify you Dependencies interface:
```ts title="src/dependencies.d.ts"
import type { Initializable } from "@sern/handler";
interface Dependencies extends CoreDependencies {
database: Initializable<Database>;
}
```
Make sure its been added:
```ts title="src/index.ts"
await makeDependencies({
build: root => root
.add({ database => new Database() })
})
```

View File

@@ -0,0 +1,128 @@
---
title: Dependency Injection
sidebar:
order: 10
---
:::danger
This contains version 2 code. Please view [transitioning to v3](../transition) for the `Service` API.
:::
Since version 2.0.0, dependency injection, thanks to [iti](https://github.com/molszanski/iti), is a feature to customize your bot's utilities and structures.
For example, a minimal setup for any project might look like this:
```ts title="src/index.ts"
const client = new Client({
...options,
});
Sern.makeDependencies<MyDependencies>({
build: (root) =>
root.add({
"@sern/client": single(() => client),
}),
});
```
For any TypeScript project, you'll need to add an interface to get intellisense and typings.
```ts title="src/dependencies.d.ts"
interface MyDependencies extends Dependencies {
"@sern/client": Singleton<Client>;
}
```
## Full Example
Your full setup may have the following structure:
import { FileTree } from '@astrojs/starlight/components';
<FileTree>
- src/
- index.ts **(your main file and client)**
- dependencies.d.ts **(for intellisense)**
</FileTree>
```ts title="src/index.ts"
const client = new Client({
...options,
});
interface MyDependencies extends Dependencies {
"@sern/client": Singleton<Client>;
}
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: (root) =>
root.add({
"@sern/client": single(() => client),
}),
});
```
Everything else is handled. However, you may want customize things.
## Adding Dependencies to Root
Each sern built dependency must implement its contracts:
- `@sern/logger`: Logging 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`: The key to emit events and occurences in a project → [`Emitter`](../../../api/interfaces/emitter)
You may also add disposers so that when the application crashes, the targeted dependency calls that function.
```ts title="src/index.ts"
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: (root) =>
root
.add({
"@sern/client": single(() => client),
})
.addDisposer({ "@sern/client": (client) => client.destroy() }),
});
```
:::caution
Below is v3 API.
:::
## Init
import { Steps } from '@astrojs/starlight/components';
<Steps>
1. Do you need to perform intializing behavor for a dependency?
```ts title="src/database.ts"
import { Init } from "@sern/handler";
class Database implements Init {
init() {
await this.connect();
console.log("Connected");
}
}
```
2. Modify your `Dependencies` interface:
```ts title="src/dependencies.d.ts" {4}
import type { Initializable } from "@sern/handler";
interface Dependencies extends CoreDependencies {
database: Initializable<Database>;
}
```
3. Make sure its been added:
```ts title="src/index.ts" {3}
await makeDependencies({
build: root => root
.add({ database => new Database() })
})
```
4. Now, when your bot starts, the `init` method will be called. 🎉
</Steps>

View File

@@ -4,19 +4,29 @@ sidebar:
order: 5
---
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.
:::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.
**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.
:::
## Introduction
In this guide, we'll walk you through creating your first command module.
If you installed a new project via the CLI, your file should be here:
import { FileTree } from '@astrojs/starlight/components';
<FileTree>
- src/commands/
- ping.ts **(right here, probably)**
- ...
</FileTree>
import { Tabs, TabItem } from '@astrojs/starlight/components';
<Tabs syncKey="language-preference">
<TabItem value="js" label="JavaScript">
```js
```js title="src/commands/ping.js"
const { CommandType, commandModule } = require("@sern/handler");
export default commandModule({
@@ -30,8 +40,8 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
});
```
</TabItem>
<TabItem value="ts" label="Typescript">
```ts
<TabItem value="ts" label="TypeScript">
```ts title="src/commands/ping.ts"
import { commandModule, CommandType } from "@sern/handler";
export default commandModule({
@@ -47,22 +57,27 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
</TabItem>
</Tabs>
To view what each of these properties mean in depth, visit the [official documentation](https://sern.dev/docs/api/enums/CommandType).
To view what each of these properties mean in depth, visit the docs for [`CommandType`](../../../api/enumerations/commandtype).
### Types of command modules
## Command Module Types
Every command module `type` is part of an enum. This field allows type inference for the rest of a module's fields. <br />
All the command types can be found in the [official documentation](https://sern.dev/docs/api/enums/CommandType)!
Every command module `type` is part of an enum. This field allows type inference for the rest of a module's fields.
<p>So, lets say you want to make a command module that listens to modals. </p>
All the command types can be found in the [`CommandType`](../../../api/enumerations/commandtype) enum!
**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.
<br />
## Example Modal Command
So, lets say you want to make a command module that listens to modals.
:::tip
Keep in mind, you'll need to send a modal with a custom id of `dm-me`. This example below is the response to a modal being sent.
:::
<Tabs syncKey="language-preference">
<TabItem value="js" label="JavaScript">
```javascript
const { CommandType, commandModule } = require("@sern/handler");
exports.default = commandModule({
name: "dm-me",
type: CommandType.Modal,
@@ -76,9 +91,10 @@ All the command types can be found in the [official documentation](https://sern.
});
```
</TabItem>
<TabItem value="ts" label="Typescript">
<TabItem value="ts" label="TypeScript">
```typescript
import { commandModule, CommandType } from "@sern/handler";
export default commandModule({
name: "dm-me",
type: CommandType.Modal,
@@ -94,14 +110,13 @@ All the command types can be found in the [official documentation](https://sern.
</TabItem>
</Tabs>
Commands are straight forward. Keep in mind, every other property on the commandModule object is
optional **except** the type and execute function.
Commands are straight forward. Keep in mind, the only required fields for command modules are the `type` and `execute` function.
# Context class
## Context Class
The provided Context class helps with modules of `CommandType.Both` (A mixture of slash / legacy commands).
The provided [`Context`](../../../api/classes/context) class helps with modules of `CommandType.Both` (A mixture of slash / legacy commands).
The Context class is passed into modules with type:
The `Context` class is passed into modules with type:
- `CommandType.Both`
- `CommandType.Slash`

View File

@@ -4,17 +4,19 @@ sidebar:
order: 6
---
We will dissect a basic event module. <br />
:::tip
TLDR: event modules are event listeners. there are three types EventType.Discord, EventType.Sern, EventType.External
**TLDR:** Event modules are event listeners. There are three types: `EventType.Discord`, `EventType.Sern`, and `EventType.External`.
:::
## Introduction
In this guide, we'll walk you through creating your first event module.
import { Tabs, TabItem } from '@astrojs/starlight/components';
<Tabs syncKey="language-preference">
<TabItem value="js" label="JavaScript">
```javascript
```js title="src/events/activate.js"
exports.default = eventModule({
type: EventType.Sern,
plugins : [],
@@ -25,8 +27,8 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
})
```
</TabItem>
<TabItem value="ts" label="Typescript">
```typescript
<TabItem value="ts" label="TypeScript">
```ts title="src/events/activate.ts"
export default eventModule({
type: EventType.Sern,
plugins : [],
@@ -39,16 +41,15 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
</TabItem>
</Tabs>
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).
Similar to command modules, the `type` property denotes what kind of event it is. You can view [`EventType`](../../../api/enumerations/eventtype) for more information.
To view what each of these properties mean in depth, visit the [official documentation](https://sern.dev/docs/api/enums/EventType).
To view what each of these properties mean in depth, visit the docs for [`EventType`](../../../api/enumerations/eventtype).
## External
## External Events
In version 2 & 3, any dependency that you have passed into makeDependencies can be registered here as well.
In versions 2 & 3, any dependency that you have passed into `makeDependencies` can be registered here as well.
```ts title="src/index.ts"
```ts title="src/index.ts" {3}
await makeDependencies({
build: root => root.add({
eventlistener: single(() => new EventEmitter())
@@ -56,14 +57,18 @@ await makeDependencies({
})
```
```ts title="events/myevent.ts"
In your event module, you can now listen to events from `eventlistener`, which will be emitted from the `EventEmitter`.
```ts title="src/events/myevent.ts" {3}
export default eventModule({
type: EventType.External,
emitter: 'eventlistener',
execute: (args) => {
console.log('Got event from eventlistener: ', args);
console.log('Got event from eventlistener: ', args);
}
})
```
:::note
Make sure that the `emitter` property matches the name of the dependency you passed into `makeDependencies`.
:::

View File

@@ -1,52 +0,0 @@
---
title: Goal
sidebar:
order: 1
---
This walkthrough will be written in [TypeScript](https://www.typescriptlang.org/) but will have JavaScript snippets throughout.
# Make robust, modular, bots
- _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 less for more 🤯
### 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({
type: CommandType.Both,
plugins: [publish()],
description: "Pong!",
execute: (ctx, args) => {
await ctx.reply("Pong!");
},
});
```
Keep in mind the above example acts as both a slash command AND text command

View File

@@ -0,0 +1,57 @@
---
title: Goal
sidebar:
order: 1
---
This walkthrough will be written in [TypeScript](https://www.typescriptlang.org/) but will have JavaScript snippets throughout.
## Make robust, modular, bots
- **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 less for more. 🤯
## Why sern?
import { Tabs, TabItem } from '@astrojs/starlight/components';
<Tabs>
<TabItem value="sapphire" label="Using @sapphire/framework 🤢">
```ts title="commands/ping.ts"
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!");
}
}
```
</TabItem>
<TabItem value="sern" label="Using @sern/handler 💪">
```ts title="commands/ping.ts"
import { commandModule, CommandType } from "@sern/handler";
export default commandModule({
type: CommandType.Both,
description: "Pong!",
execute: async (ctx, args) => {
await ctx.reply("Pong!");
},
});
```
</TabItem>
</Tabs>
Keep in mind the sern example acts as both a slash command AND a text command. The Sapphire example is only a slash command, and it's more code than sern.
## Be smart. Choose sern.

View File

@@ -6,15 +6,15 @@ sidebar:
## sern.config.json
<p>A sern.config.json, although not necessary, allows your project to communicate with our cli.</p>
A `sern.config.json`, although not necessary, allows your project to communicate with our cli.
For example, when installing typescript plugins, the language property is necessary to install from our
[open source repository](https://github.com/sern-handler/awesome-plugins). <br />
For example, when installing TypeScript plugins, the language property is necessary to install from our [open source repository](https://github.com/sern-handler/awesome-plugins).
Using the CLI and running `sern init --sync` on pre-existing projects should install this file in the your project.
Using the cli and running `sern init --sync` on pre-existing projects should install this json file in the root directory given.
Or, if this is a brand-new project, `sern init` automatically installs it.
```json
```json title="sern.config.json"
{
"language": "typescript",
"paths": {

View File

@@ -1,13 +0,0 @@
---
title: New Project
sidebar:
order: 2
---
```sh
npm create @sern/bot
```
and follow the interactive prompts.
if somehow you need help, feel free to ask [here](https://sern.dev/discord)

View File

@@ -0,0 +1,13 @@
---
title: New Project
sidebar:
order: 2
---
import PackageManagers from '~/components/PackageManagers.astro';
<PackageManagers command="create" text="@sern/bot"/>
Once you've used this command, follow the interactive prompts to create your new project.
If you need help, feel free to ask on our [Discord](https://sern.dev/discord).

View File

@@ -5,25 +5,31 @@ sidebar:
---
:::tip
TLDR: Plugins help reduce code repetition and are installable via `sern plugins`. Put them onto the plugins field of a command/event module.
**TLDR:** Plugins help reduce code repetition and are installable via `sern plugins`. Put them into the `plugins` field of a command/event module.
:::
## Installing
## Installation
Chances are, you just want your bot to work. Plugins can preprocess and create reusable conditions for modules.
run:
To install plugins, you can use the CLI:
```sh
sern plugins
```
- 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.
:::caution
Some plugins only work with specific command types. Most, however, are targeted towards slash / both modules.
:::
```ts
import { Steps } from '@astrojs/starlight/components';
<Steps>
1. Install your favorite(s) (or the ones that look the coolest). In my imaginary mind, I installed the `ownerOnly` plugin. (This should install to `src/plugins`)
2. Add the plugin to your module in the `plugins` field.
</Steps>
```ts title="src/commands/ping.ts" {6}
import { commandModule, CommandType } from '@sern/handler'
import { ownerOnly } from '../plugins'
@@ -39,13 +45,17 @@ export default commandModule({
#### ┗| O|┛ perfect, your first plugin!
## Creating your own plugins
## Creating Plugins
The controller determines in plugins whether to continue or fail.
Plugins are essentially functions that use the controller object to determine whether to continue or stop the execution of a command.
### The controller object
### Controller Object
```typescript
The controller object is passed into every plugin. It has two methods: `next` and `stop`.
Plugins use these methods to control the flow of the command. For example, if a plugin fails, it can call `controller.stop()` to prevent the command from executing.
```ts
export interface Controller {
next: () => Ok<void>;
stop: () => Err<void>;
@@ -55,28 +65,31 @@ export interface Controller {
## Init Plugins
Init plugins modify how commands are loaded or do preprocessing.
An instance of the above object is passed into every plugin. <br />
This controls whether a module is stored into sern. <br />
```typescript
An instance of `Controller` (as seen above) is passed into every plugin. This controls whether a module is stored into sern.
```ts title="src/plugins/inDir.ts" {11} {14}
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(),
Date.now(),
`${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(Date.now(), `${module.name} is in the correct directory!`);
return controller.next(); // continue to next plugin
});
};
```
Above, this simple plugin logs that the module has been loaded along with a timestamp. <br />
:::tip
The plugin above simply checks if the module is in the correct directory. If it's not, it logs a message and stops the command from being loaded.
:::
## Event Plugins
@@ -85,20 +98,24 @@ import eventPlugins from '~/assets/docs/event-plugins.png';
<Image src={eventPlugins} alt="control plugins" />
- An event is emitted by discord.js.
- This event is passed to all plugins (**in order!!**),
- If all are successful,
<Steps>
1. An event is emitted by `discord.js`.
2. This event is passed to all plugins (**in order!!**),
3. If all are successful, the command is executed.
</Steps>
The command is executed. Calling `controller.stop()` notifies sern that this command should not be run,
and command is ignored.
:::note
Calling `controller.stop()` notifies sern that this command should not be run, and command is ignored.
:::
Can you predict the behavior of this command?
#### 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`.
- Before an event occurs, this command module will check if the user has the id `182326315813306368`.
<Steps>
1. Before loading into sern, this command module will check if this module is in the correct directory: `other`.
2. Before an event occurs, this command module will check if the user has the id `182326315813306368`.
3. If all plugins return `controller.next()`, this command replies `Pong 🏓`
</Steps>
:::tip
Event Plugins are good for filtering, preconditions, parsing.
:::
If all plugins return `controller.next()`, this command replies `Pong 🏓`
:::

View File

@@ -1,16 +0,0 @@
---
title: Sern Emitter
sidebar:
order: 11
---
You're shipped with the SernEmitter. This EventEmitter listens to
- command modules executing and its status, the `module.activate` event
- command modules registered and its status, the `module.register` event
- On default, sern creates a single SernEmitter for your bot process.
- any error that occurs, the `error` event
- `warn` events, where it is possible to throw errors
You can put these and other event listeners into [event modules](./first-event.md)!
<br/>View all <a href="https://sern.dev/docs/api/modules#serneventsmapping">events</a>

View File

@@ -0,0 +1,21 @@
---
title: Sern Emitter
sidebar:
order: 11
---
You're shipped with the `SernEmitter` class. This `EventEmitter` listens to
import { Steps } from '@astrojs/starlight/components';
<Steps>
1. Command modules executing and its status; the `module.activate` event
2. Command modules registered and its status; the `module.register` event
3. On default, sern creates a single SernEmitter for your bot process.
4. Any error that occurs; the `error` event
5. `warn` events, where it is possible to throw errors
</Steps>
You can put these and other event listeners into [event modules](../first-event)!
You can view all events in the [`SernEventsMapping`](../../../api/interfaces/serneventsmapping) interface.

View File

@@ -4,16 +4,16 @@ sidebar:
order: 8
---
:::tip
:::danger
This is version 3 api only!!
:::
:::tip
TLDR: The direct upgrade to useContainer. if you set up a bot with create-bot, check dependencies.d.ts.
**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!
You need some way to use dependencies in your command module. Services to the rescue!
```ts title="src/dependencies.d.ts"
import { CoreDependencies, Singleton } from "@sern/handler";
@@ -24,28 +24,31 @@ interface Dependencies extends CoreDependencies {
}
```
Recall, some keys in Dependencies are special.
## Special Dependencies
> 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)
Some keys in `Dependencies` are special and are used by sern internally:
- `@sern/client`: Your Discord client. [`Emitter`](../../../api/interfaces/emitter)
- `@sern/logger`: Logging 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`: The key to emit events and occurences in a project [`Emitter`](../../../api/interfaces/emitter)
## Usage
Lets try to access the client you provided.
```ts title="src/commands/ping.ts"
```ts title="src/commands/ping.ts" {8}
import { Service } from "@sern/handler";
export default commandModule({
// ...
execute: (ctx) => {
//Client!
// Type is inferred from the dependencies file.
// → Dependencies['@sern/client']
const client = Service("@sern/client");
},
//
// ...
});
```
@@ -53,16 +56,18 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
## Safety
- Services cannot be called in other services while makeDependencies is forming.
Services cannot be called in other services while `makeDependencies` is forming.
For example, let's pass a logger into our database:
### Example
<Tabs syncKey="good-bad-services">
<TabItem value="good" label="A good example">
Lets pass a logger into our database.
```ts title="index.ts"
await makeDependencies({
build: root => root
//Overriding the default logger provided.
// Overriding the default logger provided.
.upsert({ '@sern/logger': single(() => new Logger()) })
// Wiring our logger into the database.
@@ -77,7 +82,7 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
await makeDependencies({
build: (root) =>
root
//Overriding the default logger provided.
// Overriding the default logger provided.
.upsert({ "@sern/logger": single(() => new Logger()) })
// Wiring our logger into the database.
@@ -89,7 +94,7 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
```ts title="index.ts"
import { Service, makeDependencies } from "@sern/handler";
//Calling Service prematurely!
// Calling Service prematurely!
const logger = Service("@sern/logger");
class Database {
@@ -102,18 +107,12 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
</TabItem>
</Tabs>
- 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.
- You will need to wire dependencies together.
### Another Example
<Tabs syncKey="good-bad-services">
<TabItem value="good" label="A good example">
```ts title="index.ts"
await makeDependencies(...pass your options here)
await makeDependencies(/* ...pass your options here */)
```
```ts title="commands/ping.ts"
@@ -133,12 +132,19 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';
</TabItem>
</Tabs>
- 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.
## Important
## Related api
import { Steps } from '@astrojs/starlight/components';
- use `Service` for single dependency.
- use `Services` for multiple dependencies.
<Steps>
1. Services can only be used after sern has made dependencies. <br />→ Calling a service before will crash your application.
2. Services can be safely used outside of a `commandModule`. <br />→ Be careful to not cause too many side effects.
3. You will need to wire dependencies together. <br />→ This is a good practice to keep your code clean.
4. Services can only be used after sern has made dependencies. <br />→ Calling a service before will crash your application.
5. Services can be safely used outside of a `commandModule`. <br />→ Be careful to not cause too many side effects.
</Steps>
## Related API
- Use `Service` for single dependency.
- Use `Services` for multiple dependencies.

View File

@@ -9,10 +9,10 @@ sidebar:
+ await makeDependencies({ build: () => {} })
```
v3 comes with the new [Service api](../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)
v3 comes with the new [Service API](../services). To make sure to enable intellisense,
include a `dependencies.d.ts` file into compilation. (Check out the [changelog](../../../blog/3.0.0) for all new features)
```ts
```ts title="dependencies.d.ts"
/**
* This file serves as intellisense for sern projects.
* Types are declared here for dependencies to function properly
@@ -48,7 +48,7 @@ import { FileTree } from '@astrojs/starlight/components';
- commands/
- events/
- plugins/
- dependencies.d.ts
- dependencies.d.ts **(add this)**
- index.ts
- .env
- .gitignore