Services
You need some way to use dependencies in your command module. Services to the rescue!
1import { CoreDependencies, Singleton } from "@sern/handler";2import { Client } from "discord.js";3
4interface Dependencies extends CoreDependencies {5 "@sern/client": Singleton<Client>;6}
Special Dependencies
Some keys in Dependencies
are special and are used by sern internally:
@sern/client
: Your Discord client. →Emitter
@sern/logger
: Logging data →Logging
@sern/errors
: Handling errors and lifetime →ErrorHandling
@sern/modules
: Managing all command modules →ModuleManager
@sern/emitter
: The key to emit events and occurences in a project →Emitter
Usage
Lets try to access the client you provided.
1import { Service } from "@sern/handler";2
3export default commandModule({4 // ...5 execute: (ctx) => {6 // Type is inferred from the dependencies file.7 // → Dependencies['@sern/client']8 const client = Service("@sern/client");9 },10 // ...11});
Safety
Services cannot be called in other services while makeDependencies
is forming.
For example, let’s pass a logger into our database:
Example
1await makeDependencies({2 build: root => root3 // Overriding the default logger provided.4 .upsert({ '@sern/logger': single(() => new Logger()) })5
6 // Wiring our logger into the database.7 .add(ctx => {8 return { database: single(() => new Database(ctx['sern/logger']))) }9 })10})
1await makeDependencies({2 build: (root) =>3 root4 // Overriding the default logger provided.5 .upsert({ "@sern/logger": single(() => new Logger()) })6
7 // Wiring our logger into the database.8 // We wire our database incorrectly. Logger should be passed INTO the constructor9 .add({ database: single(() => new Database()) }),10});
1import { Service, makeDependencies } from "@sern/handler";2
3// Calling Service prematurely!4const logger = Service("@sern/logger");5
6class Database {7 constructor() {8 this.logger = logger;9 }10}
This is a code smell anyway. It breaks encapsulation and defeats the purpose of wiring dependencies
Another Example
1await makeDependencies(/* ...pass your options here */)
1// This is guaranteed to be defined if configured correctly2import { Service } from "@sern/handler";3const client = Service("@sern/client");
1import { Service, makeDependencies } from "@sern/handler";2/* DON'T USE SERVICES BEFORE CALLING makeDependencies */3const logger = Service("@sern/logger");4
5await makeDependencies();
Important
- 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 a
commandModule
.
→ Be careful to not cause too many side effects. - You will need to wire dependencies together.
→ This is a good practice to keep your code clean. - 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 a
commandModule
.
→ Be careful to not cause too many side effects.
Related API
- Use
Service
for single dependency. - Use
Services
for multiple dependencies.