Application framework for TypeScript to build robust, and simple services
Lilith is Noelware's framework to build JavaScript-based microservices with TypeScript! It is used to build robust applications with TypeScript with the tools you need to build it! Lilith comes with pre-built libraries that makes it easy to work with:
@noelware/lilith-logging
~ Package to handle logging scenarios, combined with the@noelware/lilith-config
package also!@noelware/lilith-config
~ Package to handle different configuration sources, that are easily injectable with the@Variable
decorator.
Warning β Lilith v6 and above is not compatible with older versions of Lilith, so you will need to refractor your whole application that was built upon Lilith. You can read up on the migration section.
$ npm install @noelware/lilith
$ yarn add @noelware/lilith
$ pnpm install @noelware/lilith
import { createLilith, singleton, service, inject } from '@noelware/lilith';
const container = createLilith({
singletons: [
// Defines a path to load singletons from
{ path: './path/to/singletons' },
singleton<Logger>({
provide() { return Logger.create(); }
onLoad(logger /*: Logger */) { /* ran once singleton is loaded into the container */ },
onDestroy(logger /*: Logger */) { /* destroy singleton */ }
})
],
services: [
// Defines a path to load services from
{ path: './path/to/services' },
service({
name: 'myservice',
children: [/* list of children that this service has control over */],
onLoad() { /* called for loading the service (i.e, start http server/load config) */ },
onDestroy() { /* called for destroying the service (i.e, stopping http service) */ },
onChildLoad(child /*: any */) { /* called for loading children into the service scope */ },
onChildDestroy(child /*: any */) { /* called for destroying children into the service scope */ },
})
]
});
const logger = inject('logger');
// => Logger
const service = inject('myservice');
// => Service
@noelware/lilith is the main library that ties together with the new packages like @noelware/lilith-logging. You use @noelware/lilith to manage the lifecycle of the managed IoC container to do dependency injection out of the box.
@noelware/lilith doesn't need any peer dependencies, but you will need to have reflect-metadata
loaded before using @noelware/lilith because it depends on it!
$ npm install @noelware/lilith
$ yarn add @noelware/lilith
$ pnpm install @noelware/lilith
import { Service, Inject, createLilith } from '@noelware/lilith';
@Service({ name: 'a name' })
class MyService {
@Inject
private readonly other!: OtherService;
onLoad() {
console.log('I have loaded!');
}
}
@Service({ name: 'another name', priority: 10 })
class OtherService {
private readonly lucky: number = 42;
get luckyNumber() {
return this.lucky;
}
}
const container = createLilith({
services: [MyService, OtherService]
});
container.start();
- Lilith will construct the container as a export of Container,
- When you call start, the IoC hooks will be attached to the services in this minimal example,
- Since services can be a higher priority, the services that have a high priority will be initialized first
- You can't inject components that are even a higher priority in a high priority service since services are not lazily constructed (i.e, needed when it needs to be used). They're loaded automatically, only singletons are lazily loaded.
- You can't have service names with the same name, you will get a
TypeError
thrown.
| ~~~~~~~~~~~~~~ | /----> | another name |
| ioc container | - / \
| ~~~~~~~~~~~~~~ | \----> | a name |
@noelware/lilith-logging is a service package that lets you inject a LoggerFactoryService
into your services and creates a Logger for using logging. This package requires a peer dependency on winston:
$ npm install @noelware/lilith @noelware/lilith-logging @noelware/lilith-logging-winston winston
$ yarn add @noelware/lilith @noelware/lilith-logging @noelware/lilith-logging-winston winston
$ pnpm install @noelware/lilith @noelware/lilith-logging @noelware/lilith-logging-winston winston
import { Service, Inject, createLilith } from '@noelware/lilith';
import { LogService, type Logger } from '@noelware/lilith-logging';
import { WinstonBackend } from '@noelware/lilith-logging-winston';
import winston from 'winston';
@Service({ name: 'my service name' })
class MyService {
@Inject
private readonly logging!: LogService<WinstonBackend>;
private readonly logger!: Logger;
onLoad() {
this.logger = this.logging.loggerFactory.get('my', 'service', 'info');
this.logger.info('I am loading stuff!');
}
}
const container = createLilith({
services: [
new LogService({
defaultLevel: 'debug',
backend: new WinstonBackend({
transports: [new winston.transports.Console()]
})
}),
MyService
]
});
container.start();
@noelware/lilith-config is a service that gives you a way to simplify configuration files with a Zod schema. It has loaders for:
- YAML (requires
js-yaml
) - JSON (no extra dependencies)
- TOML (requires
@ltd/j-toml
)
@noelware/lilith-config has a peer dependency on zod if you wish to have schema validation. It is not required to have zod installed, it'll just ignore the configuration schema if provided.
$ npm install @noelware/lilith @noelware/lilith-config zod
$ yarn add @noelware/lilith @noelware/lilith-config zod
$ pnpm install @noelware/lilith @noelware/lilith-config zod
import { Service, Inject, createLilith } from '@noelware/lilith';
import { ConfigService, YamlLoader } from '@noelware/lilith-config';
import z from 'zod';
export interface Config {
lol: boolean;
}
@Service({ name: 'my service' })
class MyService {
@Inject
private readonly config!: ConfigService<Config>;
onLoad() {
const shouldLol = this.config.get('lol');
if (shouldLol) {
console.log('lol!!!!');
}
}
}
const container = createLilith({
services: [
new ConfigService<Config>({
schema: z
.object({
lol: z.boolean()
})
.strict(),
loader: new YamlLoader()
}),
MyService
]
});
container.start();
const service = container.inject(MyService);
Thanks for considering contributing to Lilith! Before you boop your heart out on your keyboard β§ β=β‘Ξ£((( γ€β’ΜΟβ’Μ)γ€, we recommend you to do the following:
- Read the Code of Conduct
- Read the Contributing Guide
If you read both if you're a new time contributor, now you can do the following:
- Fork me! οΌ*β‘( βα΅α΄α΅β οΌ
- Clone your fork on your machine:
git clone https://github.com/your-username/Lilith
- Create a new branch:
git checkout -b some-branch-name
- BOOP THAT KEYBOARD!!!! β‘βΛΝ (β γ° β)ΛΛββ‘
- Commit your changes onto your branch:
git commit -am "add features οΌο½‘>βΏβΏ<q οΌ"
- Push it to the fork you created:
git push -u origin some-branch-name
- Submit a Pull Request and then cry! qο½₯οΎοΎο½₯(ΰ°₯ Π ΰ°₯γ)ο½₯οΎοΎο½₯q
Lilith is released under the MIT License with love by Noelware. :3