/**
 * Create a new Fluxject Container for managing dependencies.
 *
 * @example
 * import { fluxject } from "fluxject";
 * import type { InferServiceProvider } from "fluxject";
 * const container = fluxject()
 *    .register(m => m.singleton({ myService: MyService }))
 *    .register(m => m.scoped({ myScopedService: MyScopedService }))
 *    .register(m => m.transient({ myTransientService: MyTransientService }));
 *
 * const provider = container.prepare();
 * provider.myService.doSomething();
 * // CLI prints "doing something else!"
 * const scope = provider.createScope();
 * scope.myScopedService.doScopedSomething();
 * // CLI prints "doing something else!"
 *
 * class MyService {
 *
 *   constructor({ myTransientService }: InferServiceProvider<typeof container, "myService">) {
 *     this.myTransientService = myTransientService;
 *   }
 *
 *   doSomething() {
 *     this.myTransientService.doSomethingElse();
 *   }
 * }
 *
 * class MyTransientService() {
 *   doSomethingElse() {
 *     console.log("doing something else!");
 *   }
 * }
 *
 * class MyScopedService() {
 *   constructor({ myService, myTransientService }: InferServiceProvider<typeof container, "myScopedService">) {
 *     this.myService = myService;
 *     this.myTransientService = myTransientService;
 *   }
 *
 *   doScopedSomething() {
 *     this.myService.doSomething();
 *   }
 * }
 */
export function fluxject(): Container<{}>;
/**
 * Infer the correct service provider that would be passed into the instantiator for the given `TServiceName` from `TContainer`.
 * ```ts
 * const container = fluxject()
 *   .register(m => m.singleton({ myService: MyService }));
 * class MyService {
 *   constructor(services: InferServiceProvider<typeof container, "myService">) { }
 * }
 * ```
 * @template {Container} TContainer
 * Container that holds the service to infer the provider for.
 * @template {keyof Types.InferRegistrationsFromContainer<TContainer>} TServiceName
 * The name of the service that is using this service provider.
 * @typedef {Types.InferRegistrationsFromContainer<TContainer>[TServiceName] extends Types.Registration<*, "scoped">
*   ? Types.Widen<Omit<(FluxjectScopedServiceProvider & Types.InferInstanceTypes<Types.InferRegistrationsFromContainer<TContainer>>), TServiceName|"dispose">>
*   : Types.Widen<Omit<(FluxjectHostServiceProvider<Types.InferRegistrationsFromContainer<TContainer>> & Types.InferInstanceTypes<Types.InferRegistrationsFromContainer<TContainer>, "singleton"|"transient">), TServiceName|"createScope"|"dispose">>
* } InferServiceProvider
*/
/**
 * Infer the Host Service Provider type that would be returned from a container's `prepare` method.
 * @template {Container} TContainer
 * Container to infer the host service provider from
 * @typedef {ReturnType<HostServiceProvider<TContainer>['createScope']>} ScopedServiceProvider
 */
/**
 * Infer the Scoped Service Provider type that would be returned from a `HostServiceProvider`'s `createScope` method.
 * @template {Container} TContainer
 * Container to infer the scoped service provider from
 * @typedef {ReturnType<TContainer['prepare']>} HostServiceProvider
 */
/**
 * Can be used to infer the abstract type of a class or factory function.
 *
 * This would ensure that the type of service inferred by container injection is
 * of a parent type of the actual service.
 * ```ts
 * import { fluxject } from "fluxject";
 * import type { Abstract } from "fluxject";
 *
 * interface IService {
 *   test: string;
 * }
 *
 * class MyService {
 *   hello = "hello";
 *   world = "world";
 * }
 *
 * const provider = fluxject()
 *   .register(m => m.singleton({ myService: MyService as Abstract<IService> }))
 *   .prepare();
 *
 * provider.myService.hello; // OK
 * provider.myService.world; // TypeScript Error: Property 'world' does not exist on type 'IService'
 * ```
 * @template TInterface
 * @typedef {Types.Instantiator<TInterface>} Abstract
 */
/**
 * Can be used to infer the abstract type of a class or factory function.
 *
 * This would ensure that the type of service inferred by container injection is
 * of a parent type of the actual service.
 *
 * __NOTE:__ This is a type-only function and does not have any runtime effect.
 * ```ts
 * import { fluxject, abstract } from "fluxject";
 *
 * interface IService {
 *   test: string;
 * }
 *
 * class MyService {
 *   hello = "hello";
 *   world = "world";
 * }
 *
 * const provider = fluxject()
 *   .register(m => m.singleton({ myService: abstract<IService>(MyService)}))
 *   .prepare();
 *
 * provider.myService.hello; // OK
 * provider.myService.world;
 * // TypeScript Error: Property 'world' does not exist on type 'IService'
 * ```
 * @template TInterface
 * @template [TImplementedType=TInterface]
 * @param {Types.Instantiator<TImplementedType>} registration
 * @returns {Abstract<TInterface>}
 */
export function abstract<TInterface, TImplementedType = TInterface>(registration: Types.Instantiator<TImplementedType>): Abstract<TInterface>;
export { Container };
/**
 * Infer the correct service provider that would be passed into the instantiator for the given `TServiceName` from `TContainer`.
 * ```ts
 * const container = fluxject()
 *   .register(m => m.singleton({ myService: MyService }));
 * class MyService {
 *   constructor(services: InferServiceProvider<typeof container, "myService">) { }
 * }
 * ```
 */
export type InferServiceProvider<TContainer extends Container<any>, TServiceName extends keyof Types.InferRegistrationsFromContainer<TContainer>> = Types.InferRegistrationsFromContainer<TContainer>[TServiceName] extends Types.Registration<any, "scoped"> ? Types.Widen<Omit<(FluxjectScopedServiceProvider<any> & Types.InferInstanceTypes<Types.InferRegistrationsFromContainer<TContainer>>), TServiceName | "dispose">> : Types.Widen<Omit<(FluxjectHostServiceProvider<Types.InferRegistrationsFromContainer<TContainer>> & Types.InferInstanceTypes<Types.InferRegistrationsFromContainer<TContainer>, "singleton" | "transient">), TServiceName | "createScope" | "dispose">>;
/**
 * Infer the Host Service Provider type that would be returned from a container's `prepare` method.
 */
export type ScopedServiceProvider<TContainer extends Container<any>> = ReturnType<HostServiceProvider<TContainer>["createScope"]>;
/**
 * Infer the Scoped Service Provider type that would be returned from a `HostServiceProvider`'s `createScope` method.
 */
export type HostServiceProvider<TContainer extends Container<any>> = ReturnType<TContainer["prepare"]>;
/**
 * Can be used to infer the abstract type of a class or factory function.
 *
 * This would ensure that the type of service inferred by container injection is
 * of a parent type of the actual service.
 * ```ts
 * import { fluxject } from "fluxject";
 * import type { Abstract } from "fluxject";
 *
 * interface IService {
 *   test: string;
 * }
 *
 * class MyService {
 *   hello = "hello";
 *   world = "world";
 * }
 *
 * const provider = fluxject()
 *   .register(m => m.singleton({ myService: MyService as Abstract<IService> }))
 *   .prepare();
 *
 * provider.myService.hello; // OK
 * provider.myService.world; // TypeScript Error: Property 'world' does not exist on type 'IService'
 * ```
 */
export type Abstract<TInterface> = Types.Instantiator<TInterface>;
export type ServiceKey<TContainer extends Container<any>> = keyof Types.InferRegistrationsFromContainer<TContainer>;
export type DisposableService<T> = T & Disposable;
export type AsyncDisposableService<T> = T & AsyncDisposable;
import { Container } from "./container.js";
import type * as Types from "./types.js";
import { FluxjectScopedServiceProvider } from "./provider.js";
import { FluxjectHostServiceProvider } from "./provider.js";
