alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
60 lines (52 loc) • 1.69 kB
text/typescript
import { Primitive } from "../helpers/primitive.ts";
import type { InstantiableClass, Service } from "../interfaces/Service.ts";
import { $context } from "./$context.ts";
/**
* Get the instance of the specified type from the context.
*
* ```ts
* class A { }
* class B {
* a = $inject(A);
* }
* ```
*/
export const $inject = <T extends object>(
type: Service<T>,
opts: InjectOptions<T> = {},
): T => {
const { alepha, service } = $context();
// _ = $inject(Alepha)
if (type === alepha.constructor) {
return alepha as T;
}
return alepha.inject(type, {
// keep the parent for better error messages and circular dependencies detection
parent: service ?? (alepha.constructor as Service),
...opts,
});
};
export class InjectPrimitive extends Primitive {}
export interface InjectOptions<T extends object = any> {
/**
* - 'transient' → Always a new instance on every inject. Zero caching.
* - 'singleton' → One instance per Alepha runtime (per-thread). Never disposed until Alepha shuts down. (default)
* - 'scoped' → One instance per AsyncLocalStorage context.
* - A new scope is created when Alepha handles a request, a scheduled job, a queue worker task...
* - You can also start a manual scope via alepha.context.run(() => { ... }).
* - When the scope ends, the scoped registry is discarded.
*
* @default "singleton"
*/
lifetime?: "transient" | "singleton" | "scoped";
/**
* Constructor arguments to pass when creating a new instance.
*/
args?: ConstructorParameters<InstantiableClass<T>>;
/**
* Parent that requested the instance.
*
* @internal
*/
parent?: Service | null;
}