chore: initial commit for @alveojs/common
This commit is contained in:
4
src/constants.ts
Normal file
4
src/constants.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const INJECTABLE_METADATA_KEY = "alveo:injectable";
|
||||
export const INJECT_METADATA_KEY = "alveo:inject";
|
||||
export const MODULE_METADATA_KEY = "alveo:module";
|
||||
export const PARAMTYPES_METADATA_KEY = "design:paramtypes";
|
||||
3
src/decorators/index.ts
Normal file
3
src/decorators/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./inject.decorator";
|
||||
export * from "./injectable.decorator";
|
||||
export * from "./module.decorator";
|
||||
23
src/decorators/inject.decorator.ts
Normal file
23
src/decorators/inject.decorator.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import "reflect-metadata";
|
||||
import { INJECT_METADATA_KEY } from "../constants";
|
||||
import type { ProviderToken } from "../interfaces/provider.interface";
|
||||
|
||||
/**
|
||||
* Decorator that explicitly specifies a token for dependency injection.
|
||||
* Useful when injecting interfaces (via symbols or strings) or when multiple
|
||||
* providers are available for the same type.
|
||||
*
|
||||
* @param token The token to inject
|
||||
*/
|
||||
export function Inject(token: ProviderToken): ParameterDecorator {
|
||||
return (
|
||||
target: object,
|
||||
_propertyKey: string | symbol | undefined,
|
||||
parameterIndex: number,
|
||||
) => {
|
||||
const existingInjections =
|
||||
Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];
|
||||
existingInjections[parameterIndex] = token;
|
||||
Reflect.defineMetadata(INJECT_METADATA_KEY, existingInjections, target);
|
||||
};
|
||||
}
|
||||
14
src/decorators/injectable.decorator.ts
Normal file
14
src/decorators/injectable.decorator.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import "reflect-metadata";
|
||||
import { INJECTABLE_METADATA_KEY } from "../constants";
|
||||
import type { InjectableOptions } from "../interfaces/provider.interface";
|
||||
|
||||
/**
|
||||
* Decorator that marks a class as available to be provided and injected as a dependency.
|
||||
*
|
||||
* @param options Options for the injectable (e.g., scope)
|
||||
*/
|
||||
export function Injectable(options?: InjectableOptions): ClassDecorator {
|
||||
return (target: object) => {
|
||||
Reflect.defineMetadata(INJECTABLE_METADATA_KEY, options || {}, target);
|
||||
};
|
||||
}
|
||||
15
src/decorators/module.decorator.ts
Normal file
15
src/decorators/module.decorator.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import "reflect-metadata";
|
||||
import { MODULE_METADATA_KEY } from "../constants";
|
||||
import type { ModuleOptions } from "../interfaces/provider.interface";
|
||||
|
||||
/**
|
||||
* Decorator that marks a class as an Alveo module.
|
||||
* Modules are used to organize the application structure and define providers, imports, and exports.
|
||||
*
|
||||
* @param options Module configuration options
|
||||
*/
|
||||
export function Module(options: ModuleOptions): ClassDecorator {
|
||||
return (target: object) => {
|
||||
Reflect.defineMetadata(MODULE_METADATA_KEY, options, target);
|
||||
};
|
||||
}
|
||||
47
src/errors/index.ts
Normal file
47
src/errors/index.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
export class AlveoError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProviderNotFoundError extends AlveoError {
|
||||
constructor(token: string, context?: string) {
|
||||
const contextMsg = context ? ` in the "${context}" context` : "";
|
||||
super(
|
||||
`Alveo can't resolve dependencies of the ${token}${contextMsg}. Please make sure that it is available in the current module scope.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class CircularDependencyError extends AlveoError {
|
||||
constructor(stack: string[]) {
|
||||
super(`Circular dependency detected: ${stack.join(" -> ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidModuleError extends AlveoError {
|
||||
constructor(target: string) {
|
||||
super(
|
||||
`The class "${target}" is not a valid Alveo module. Did you forget the @Module() decorator?`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidProviderError extends AlveoError {
|
||||
constructor(provider: unknown) {
|
||||
super(`Invalid provider definition: ${JSON.stringify(provider)}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class LifecycleError extends AlveoError {
|
||||
constructor(hook: string, error: Error) {
|
||||
super(`Error during lifecycle hook "${hook}": ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class BootstrapError extends AlveoError {
|
||||
constructor(message: string) {
|
||||
super(`Application bootstrap failed: ${message}`);
|
||||
}
|
||||
}
|
||||
6
src/index.ts
Normal file
6
src/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from "./constants";
|
||||
export * from "./decorators";
|
||||
export * from "./errors";
|
||||
export * from "./interfaces";
|
||||
export * from "./types";
|
||||
export * from "./utils/forward-ref";
|
||||
2
src/interfaces/index.ts
Normal file
2
src/interfaces/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./lifecycle.interface";
|
||||
export * from "./provider.interface";
|
||||
37
src/interfaces/lifecycle.interface.ts
Normal file
37
src/interfaces/lifecycle.interface.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Interface defining a lifecycle hook that is called once the module has been initialized.
|
||||
* All dependencies have been resolved and instantiated at this point.
|
||||
*/
|
||||
export interface OnModuleInit {
|
||||
onModuleInit(): void | Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface defining a lifecycle hook that is called once all modules have been initialized,
|
||||
* but before the application starts listening for connections.
|
||||
*/
|
||||
export interface OnApplicationBootstrap {
|
||||
onApplicationBootstrap(): void | Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface defining a lifecycle hook that is called when the application is shutting down.
|
||||
* Useful for cleanup logic like closing database connections or stopping intervals.
|
||||
*/
|
||||
export interface OnModuleDestroy {
|
||||
onModuleDestroy(): void | Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface defining a lifecycle hook that is called after all onModuleDestroy() handlers have completed.
|
||||
*/
|
||||
export interface BeforeApplicationShutdown {
|
||||
beforeApplicationShutdown(signal?: string): void | Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface defining a lifecycle hook that is called after connections close (app.close() resolves).
|
||||
*/
|
||||
export interface OnApplicationShutdown {
|
||||
onApplicationShutdown(signal?: string): void | Promise<void>;
|
||||
}
|
||||
69
src/interfaces/provider.interface.ts
Normal file
69
src/interfaces/provider.interface.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import type { Constructor, Type } from "../types";
|
||||
import type { ForwardReference } from "../utils/forward-ref";
|
||||
|
||||
export type ProviderScope = "singleton" | "transient";
|
||||
|
||||
export type ProviderToken<T = unknown> =
|
||||
| Type<T>
|
||||
| string
|
||||
| symbol
|
||||
| ForwardReference<Type<T>>;
|
||||
|
||||
export interface BaseProvider<T = unknown> {
|
||||
provide: ProviderToken<T>;
|
||||
scope?: ProviderScope;
|
||||
}
|
||||
|
||||
export interface ClassProvider<T = unknown> extends BaseProvider<T> {
|
||||
useClass: Constructor<T>;
|
||||
}
|
||||
|
||||
export interface ValueProvider<T = unknown> extends BaseProvider<T> {
|
||||
useValue: T;
|
||||
}
|
||||
|
||||
export interface FactoryProvider<T = unknown> extends BaseProvider<T> {
|
||||
useFactory: (...args: any[]) => T | Promise<T>;
|
||||
inject?: ProviderToken[];
|
||||
}
|
||||
|
||||
export interface ExistingProvider<T = unknown> extends BaseProvider<T> {
|
||||
useExisting: ProviderToken<T>;
|
||||
}
|
||||
|
||||
export type Provider<T = unknown> =
|
||||
| Constructor<T>
|
||||
| ClassProvider<T>
|
||||
| ValueProvider<T>
|
||||
| FactoryProvider<T>
|
||||
| ExistingProvider<T>;
|
||||
|
||||
export interface ResolvedProvider<T = unknown> {
|
||||
token: ProviderToken<T>;
|
||||
scope: ProviderScope;
|
||||
useClass?: Constructor<T>;
|
||||
useValue?: T;
|
||||
useFactory?: (...args: any[]) => T | Promise<T>;
|
||||
useExisting?: ProviderToken<T>;
|
||||
inject?: ProviderToken[];
|
||||
moduleName?: string;
|
||||
}
|
||||
|
||||
export interface InjectableOptions {
|
||||
scope?: ProviderScope;
|
||||
}
|
||||
|
||||
export interface DynamicModule extends ModuleOptions {
|
||||
module: Constructor;
|
||||
}
|
||||
|
||||
export interface ModuleOptions {
|
||||
imports?: (
|
||||
| Constructor
|
||||
| DynamicModule
|
||||
| Promise<DynamicModule>
|
||||
| ForwardReference<Constructor>
|
||||
)[];
|
||||
providers?: Provider[];
|
||||
exports?: ProviderToken[];
|
||||
}
|
||||
10
src/types.ts
Normal file
10
src/types.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// biome-ignore lint/suspicious/noExplicitAny: Required for constructor variance compatibility
|
||||
export type ConstructorArgs = any[];
|
||||
|
||||
export type Constructor<T = unknown> = new (...args: ConstructorArgs) => T;
|
||||
|
||||
export type Abstract<T = unknown> = abstract new (
|
||||
...args: ConstructorArgs
|
||||
) => T;
|
||||
|
||||
export type Type<T = unknown> = Constructor<T> | Abstract<T>;
|
||||
21
src/utils/forward-ref.ts
Normal file
21
src/utils/forward-ref.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Interface for a function that returns a type.
|
||||
*/
|
||||
export type ForwardRefFn<T = any> = () => T;
|
||||
|
||||
/**
|
||||
* Interface for the object returned by forwardRef.
|
||||
*/
|
||||
export interface ForwardReference<T = any> {
|
||||
forwardRef: ForwardRefFn<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to refer to a reference which is not yet defined.
|
||||
* Useful for circular dependencies between classes or modules.
|
||||
*
|
||||
* @param fn A function that returns the reference
|
||||
*/
|
||||
export function forwardRef<T>(fn: ForwardRefFn<T>): ForwardReference<T> {
|
||||
return { forwardRef: fn };
|
||||
}
|
||||
Reference in New Issue
Block a user