import { C as Class, U as UnknownArgs, a as UnknownClass, N as NonEmptyArray } from './types-C31Pn_8-.js'; /** * # @application * * The `@application` decorator marks the entry point of your aspectra-based * application. It instantiates the class it decorates and calls its `start` * method automatically. * * * Lack of `start` method will result in a compile-time error. * * * #### Example * * ```typescript filename='src/index.ts' * import { application } from 'aspectra' * * @application * class Application { * public start() { * console.log('Hello, world!') * } * } * ``` * * This is functionally equivalent to: * * ```javascript * const app = new Application() * app.start() * ``` * * #### Running the Application * * ```bash * tsx src/index.ts * ``` */ declare function application(target: Class, _: ClassDecoratorContext): void; declare enum Scope { SINGLETON = "singleton", TRANSIENT = "transient", ISOALTED = "isolated", DEFAULT = "singleton" } interface InjectionKeys { origin?: PropertyKey; } declare class Metadata { private static readonly namespace; readonly contexts: Set; scope: Scope; readonly injectionKeys: InjectionKeys; static fromClass(target: Class): Metadata; static fromContext(context: DecoratorContext): Metadata; } type ProviderClassType = Class; declare abstract class Provider { readonly classType: ProviderClassType; protected readonly metadata: Metadata; protected constructor(classType: ProviderClassType); static fromClassType(classType: ProviderClassType): Provider; abstract provide(context: Context): T; protected createInstance(context: Context): T; } declare class Container { private readonly providers; register(provider: Provider, context: Context): Provider; resolve(providerClass: ProviderClassType, context: Context): T | undefined; } type ContextId = PropertyKey; declare class Context { readonly id: ContextId; static readonly global: Context; private static readonly contexts; readonly container: Container; private constructor(); static of(classType: UnknownClass): ReadonlySet; static getOrRegister(contextId: ContextId): Context; } /** * Injects the current set of registered contexts into the decorated class field. * * @example * ```typescript * class Global { * @contexts * public readonly contexts!: ReadonlySet // Global context * } * * @contextualize('a', 'b') * class Contextualized { * @contexts * public readonly contexts!: ReadonlySet // 'a' and 'b' * } * ``` */ declare function contexts(_: unknown, context: ClassFieldDecoratorContext>): void; /** * # @contextualize * * Contexts serve as containers for managing providers. By default, providers * are stored in the global context (`Context.global`) and can be injected * anywhere using `@provide`. To limit provider availability to specific areas, * use the `@contextualize` decorator. * * This decorator enables precise control over dependency injection, supporting * modularity, security, and organized management by keeping certain providers * accessible only within designated contexts. * * #### Example * * In this example, we define two contexts: `DATABASE` and `ORDER`. * * ```typescript * import { application, contextualize, provide, provider } from 'aspectra' * * enum ContextId { * DATABASE = 'database', * ORDER = 'order', * } * * @contextualize(ContextId.DATABASE) * @provider * class DatabaseProvider { * public getById(id: number) { * // run sql query * } * } * * @contextualize(ContextId.DATABASE, ContextId.ORDER) * @provider * class OrderProvider { * @provide(DatabaseProvider) * private readonly database!: DatabaseProvider * * public process(id: number) { * const product = this.database.getById(id) * // process order * } * } * * @contextualize(ContextId.ORDER) * @application * class CommerceApplication { * @provide(OrderProvider) * private readonly order!: OrderProvider * * // This will fail as `CommerceApplication` and `DatabaseProvider` have no shared contexts * // @provide(DatabaseProvider) * // private readonly database!: DatabaseProvider * * public start() { * this.order.process(1) * } * } * ``` * * ```mermaid * flowchart LR * A[DatabaseProvider] <--> C0{DATABASE} * C0 <--> B[OrderProvider] * B <--> C1{ORDER} * C1 <--> C[CommerceApplication] * ``` * * * By assigning `DatabaseProvider` and `CommerceApplication` to different * contexts, only `OrderProvider` can access `DatabaseProvider`, preserving * strict boundaries between providers. * */ declare function contextualize(...args: NonEmptyArray): (target: Class, context: ClassDecoratorContext) => void; /** * # Isolated * * Scope-modifier decorator. Marks a provider as `isolated`, ensuring a unique * instance of the provider is created for each associated context. * * Useful for scenarios where the same provider class must yield distinct * instances based on different contexts. * * * Only one scope-modifier can be applied to a provider class. Multiple * scope-modifier will result in a `MultipleScopeModifierError`. * * * ```typescript * import { * application, * Context, * contextualize, * isolated, * provide, * provider * } from 'aspectra' * import { randomUUID } from 'node:crypto' * * @isolated * @provider * class Logger { * public readonly id = randomUUID() * } * * @contextualize('database', Context.global) * @provider * class Database { * @provide(Logger) * public readonly logger!: Logger // First instance * } * * @contextualize('printer', Context.global) * @provider * class Printer { * @provide(Logger) * public readonly logger!: Logger // New instance * } * * @contextualize('printer', Context.global) * @provider * class OtherPrinter { * @provide(Logger) * public readonly logger!: Logger // Same instance as `Printer` * } * * @application * class Application { * @provide(Database) * private readonly database!: Database * * @provide(Printer) * private readonly printer!: Printer * * @provide(OtherPrinter) * private readonly otherPrinter!: OtherPrinter * * public start() { * console.table({ * database: this.database.logger.id, * printer: this.printer.logger.id, * otherPrinter: this.otherPrinter.logger.id * }) * } * } * ``` */ declare function isolated(target: ProviderClassType, context: ClassDecoratorContext): void; /** * # Origin * * Injects the context where it was instantiated. Powerful when combined with * `@isolated`. * * ```typescript * import { application, contextualize, origin, provide, provider } from 'aspectra' * import { type Context, isolated } from 'aspectra' * * enum ContextId { * DATABASE = 'database', * APPLICATION = 'application', * } * * @isolated * @provider * class LoggerProvider { * @origin * private readonly origin!: Context * * public log(message: string) { * console.log(`[${this.origin.id.toString()}]:`, message) * } * } * * @contextualize(ContextId.DATABASE) * @provider * class DatabaseProvider { * @provide(LoggerProvider) * private readonly logger!: LoggerProvider * * public connect() { * this.logger.log('Connected to database') * } * } * * @contextualize(ContextId.APPLICATION, ContextId.DATABASE) * @application * class Application { * @provide(LoggerProvider) * private readonly logger!: LoggerProvider * * @provide(DatabaseProvider) * private readonly database!: DatabaseProvider * * public start() { * this.logger.log('Starting application') * this.database.connect() * } * } * ``` */ declare function origin(_: unknown, context: ClassFieldDecoratorContext): void; /** * # Transient * * Scope-modifier decorator. Defines a provider as `@transient`, ensuring a new * instance each time the provider is injected. * * By default, providers are singletons, meaning a single instance is reused. * With `@transient`, a new instance is created upon each injection, which is * useful for stateless or temporary dependencies. * * Comparing `@transient` vs `@isolated`: * - `@transient` creates a new instance each time it's requested. * - `@isolated` creates one instance per context ("different context, * different instance"). * * ```typescript * import { * application, * Context, * contextualize, * provide, * provider, * transient, * } from 'aspectra' * import { randomUUID } from 'node:crypto' * * @transient * @provider * class Logger { * public readonly id = randomUUID() * } * * @application * class Application { * @provide(Logger) * private readonly first!: Logger * * @provide(Logger) * private readonly second!: Logger * * @provide(Logger) * private readonly third!: Logger * * public start() { * console.table({ * first: this.first.id, * second: this.second.id, * third: this.third.id, * }) * } * } * ``` */ declare function transient(target: ProviderClassType, context: ClassDecoratorContext): void; /** * # @provide * * The `@provide` decorator injects providers into the class field as a * "singleton", meaning the same instance is shared across all injections. This * allows you to inject the provider wherever needed, without having to worry * about creating multiple instances. * * * You can customize this behavior using scope-modifier decorators, such as * `@transient` and `@isolated`, which allow more granular control over the * lifecycle and scope of injected instances. These will be covered in a * later section. * * * #### Example * * ```typescript filename='src/index.ts' * import { application, provide, provider } from 'aspectra' * * @provider * export class Database { * private constructor() { * console.log(`I'm only called once!`) * } * * public getAll() { * return ['item1', 'item2'] * } * } * * @application * class Application { * @provide(Database) * private readonly database!: Database * * @provide(Database) * private readonly other!: Database // same instance as `database` * * public start() { * console.log(this.database.getAll()) * } * } * ``` */ declare function provide(provider: ProviderClassType

): (_: unknown, context: ClassFieldDecoratorContext) => void; /** * # @provider * * The `@provider` decorator registers a class as a service provider within the * application. Providers encapsulate functionality, such as a database * connection, which can be injected wherever needed using the `@provide` * decorator. * * #### Example * * ```typescript filename="src/providers/database.ts" * import { provider } from 'aspectra' * * @provider * export class Database { * public connect() { * console.log('Connecting to the database') * } * * public getAll() { * return ['item1', 'item2'] * } * * public close() { * console.log('Closing the database connection') * } * } * ``` */ declare function provider(target: Class, context: ClassDecoratorContext): void; /** * [Symbol.metadata] polyfill */ declare global { interface SymbolConstructor { readonly metadata: unique symbol; } } export { Context, application, contexts, contextualize, isolated, origin, provide, provider, transient };