inwire 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/domain/lifecycle.ts","../src/domain/types.ts","../src/domain/errors.ts","../src/domain/validation.ts","../src/infrastructure/transient.ts","../src/infrastructure/proxy-handler.ts","../src/application/introspection.ts","../src/application/scope.ts","../src/application/create-container.ts"],"sourcesContent":["/**\n * inwire — AI-First dependency injection.\n * Zero ceremony, full TypeScript inference, no decorators, no tokens.\n *\n * @example\n * ```typescript\n * import { createContainer, transient } from 'inwire';\n *\n * const container = createContainer({\n * logger: () => new LoggerService(),\n * db: () => new Database(process.env.DB_URL!),\n * userRepo: (c): UserRepository => new PgUserRepo(c.db),\n * userService: (c) => new UserService(c.userRepo, c.logger),\n * });\n *\n * container.userService; // lazy, singleton, fully typed\n * ```\n *\n * @packageDocumentation\n */\n\n// Core API\nexport { createContainer } from './application/create-container.js';\nexport { transient } from './infrastructure/transient.js';\n\n// Types\nexport type {\n Container,\n ContainerGraph,\n ContainerHealth,\n ContainerWarning,\n DepsDefinition,\n Factory,\n IContainer,\n ProviderInfo,\n ResolvedDeps,\n ScopeOptions,\n} from './domain/types.js';\n\n// Lifecycle interfaces\nexport type { OnInit, OnDestroy } from './domain/lifecycle.js';\n\n// Errors (classes, so exported as values)\nexport {\n ContainerError,\n ContainerConfigError,\n ReservedKeyError,\n ProviderNotFoundError,\n CircularDependencyError,\n UndefinedReturnError,\n FactoryError,\n ScopeMismatchWarning,\n} from './domain/errors.js';\n\n// Validation utilities\nexport { detectDuplicateKeys } from './domain/validation.js';\n","/**\n * Implement this interface (or just add an `onInit` method) to run\n * initialization logic when the dependency is first resolved.\n *\n * @example\n * ```typescript\n * class Database implements OnInit {\n * async onInit() { await this.connect(); }\n * }\n * ```\n */\nexport interface OnInit {\n onInit(): void | Promise<void>;\n}\n\n/**\n * Implement this interface (or just add an `onDestroy` method) to run\n * cleanup logic when `container.dispose()` is called.\n *\n * @example\n * ```typescript\n * class Database implements OnDestroy {\n * async onDestroy() { await this.disconnect(); }\n * }\n * ```\n */\nexport interface OnDestroy {\n onDestroy(): void | Promise<void>;\n}\n\n/** Duck-type check: does the value have an `onInit` method? */\nexport function hasOnInit(value: unknown): value is OnInit {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'onInit' in value &&\n typeof (value as any).onInit === 'function'\n );\n}\n\n/** Duck-type check: does the value have an `onDestroy` method? */\nexport function hasOnDestroy(value: unknown): value is OnDestroy {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'onDestroy' in value &&\n typeof (value as any).onDestroy === 'function'\n );\n}\n","/**\n * A factory function that receives the container and returns an instance.\n *\n * @example\n * ```typescript\n * const factory: Factory<MyService> = (c) => new MyService(c.db);\n * ```\n */\nexport type Factory<T = any> = (container: any) => T;\n\n/**\n * An object of factory functions — the definition of a container.\n * Each key maps to a factory that produces the dependency.\n *\n * @example\n * ```typescript\n * const deps: DepsDefinition = {\n * logger: () => new LoggerService(),\n * db: () => new Database(process.env.DB_URL!),\n * userRepo: (c) => new PgUserRepo(c.db),\n * };\n * ```\n */\nexport type DepsDefinition = Record<string, Factory>;\n\n/**\n * Extracts the resolved types from a deps definition.\n * Maps each key to the return type of its factory function.\n *\n * @example\n * ```typescript\n * type Resolved = ResolvedDeps<{ logger: () => LoggerService }>;\n * // { logger: LoggerService }\n * ```\n */\nexport type ResolvedDeps<T extends DepsDefinition> = {\n readonly [K in keyof T]: ReturnType<T[K]>;\n};\n\n/**\n * Reserved method names on the container that cannot be used as dependency keys.\n */\nexport const RESERVED_KEYS = [\n 'scope',\n 'extend',\n 'preload',\n 'reset',\n 'inspect',\n 'describe',\n 'health',\n 'dispose',\n 'toString',\n] as const;\n\nexport type ReservedKey = (typeof RESERVED_KEYS)[number];\n\n/**\n * Options for creating a scoped container.\n */\nexport interface ScopeOptions {\n /** Optional name for the scope, useful for debugging and introspection. */\n name?: string;\n}\n\n/**\n * Full container type exposed to the user.\n * Combines resolved dependencies with container methods.\n *\n * @example\n * ```typescript\n * const container: Container<{ logger: LoggerService }> = createContainer({\n * logger: () => new LoggerService(),\n * });\n * container.logger; // LoggerService\n * container.inspect(); // ContainerGraph\n * ```\n */\nexport type Container<T extends Record<string, any> = Record<string, any>> =\n T & IContainer<T>;\n\n/**\n * Container methods interface. Defines the API available on every container.\n */\nexport interface IContainer<T extends Record<string, any> = Record<string, any>> {\n /**\n * Creates a child container with additional dependencies.\n * Child inherits all parent singletons and can add/override deps.\n *\n * @example\n * ```typescript\n * const request = app.scope({\n * requestId: () => crypto.randomUUID(),\n * currentUser: () => extractUser(req),\n * });\n * request.requestId; // scoped singleton\n * request.logger; // inherited from parent\n * ```\n */\n scope<E extends DepsDefinition>(extra: E, options?: ScopeOptions): Container<T & ResolvedDeps<E>>;\n\n /**\n * Returns a new container with additional dependencies.\n * Existing singletons are shared. The original container is not modified.\n *\n * @example\n * ```typescript\n * const appWithAuth = app.extend(authDeps);\n * ```\n */\n extend<E extends DepsDefinition>(extra: E): Container<T & ResolvedDeps<E>>;\n\n /**\n * Pre-resolves dependencies (warm-up).\n * Call with specific keys to resolve only those, or without arguments to resolve all.\n *\n * @example\n * ```typescript\n * await container.preload('db', 'cache'); // specific deps\n * await container.preload(); // all deps\n * ```\n */\n preload(...keys: (keyof T)[]): Promise<void>;\n\n /**\n * Returns the full dependency graph as a serializable JSON object.\n * Useful for AI analysis of the architecture.\n *\n * @example\n * ```typescript\n * container.inspect();\n * // { providers: { logger: { key: 'logger', resolved: true, deps: [], scope: 'singleton' } } }\n * ```\n */\n inspect(): ContainerGraph;\n\n /**\n * Returns detailed information about a specific provider.\n *\n * @example\n * ```typescript\n * container.describe('userService');\n * // { key: 'userService', resolved: true, deps: ['userRepo', 'logger'], scope: 'singleton' }\n * ```\n */\n describe(key: keyof T): ProviderInfo;\n\n /**\n * Returns container health status and warnings.\n *\n * @example\n * ```typescript\n * container.health();\n * // { totalProviders: 12, resolved: ['db', 'logger'], unresolved: ['cache'], warnings: [] }\n * ```\n */\n health(): ContainerHealth;\n\n /**\n * Invalidates cached singletons, forcing re-creation on next access.\n * Does not affect parent scopes.\n *\n * @example\n * ```typescript\n * container.reset('db'); // reset one\n * container.reset('db', 'cache'); // reset multiple\n * ```\n */\n reset(...keys: (keyof T)[]): void;\n\n /**\n * Disposes the container. Calls `onDestroy()` on all resolved instances\n * that implement it, in reverse resolution order.\n *\n * @example\n * ```typescript\n * await container.dispose();\n * ```\n */\n dispose(): Promise<void>;\n}\n\n/**\n * Full dependency graph of the container.\n */\nexport interface ContainerGraph {\n name?: string;\n providers: Record<string, ProviderInfo>;\n}\n\n/**\n * Detailed information about a single provider/dependency.\n */\nexport interface ProviderInfo {\n key: string;\n resolved: boolean;\n deps: string[];\n scope: 'singleton' | 'transient';\n}\n\n/**\n * Container health status with warnings.\n */\nexport interface ContainerHealth {\n totalProviders: number;\n resolved: string[];\n unresolved: string[];\n warnings: ContainerWarning[];\n}\n\n/**\n * A warning detected by the container's runtime analysis.\n */\nexport interface ContainerWarning {\n type: 'scope_mismatch' | 'duplicate_key';\n message: string;\n details: Record<string, unknown>;\n}\n\n/**\n * Interface for the resolver — the core engine behind the Proxy.\n */\nexport interface IResolver<T extends DepsDefinition = DepsDefinition> {\n resolve(key: string): unknown;\n isResolved(key: string): boolean;\n getDepGraph(): Map<string, string[]>;\n getResolvedKeys(): string[];\n getFactories(): Map<string, Factory>;\n getCache(): Map<string, unknown>;\n}\n\n/**\n * Interface for config and runtime validation.\n */\nexport interface IValidator {\n validateConfig(config: Record<string, unknown>): void;\n suggestKey(key: string, registered: string[]): string | undefined;\n}\n","/**\n * Base class for all container errors.\n * Every error includes a human-readable `hint` and structured `details`\n * so that AI tools and developers can auto-correct issues.\n *\n * @example\n * ```typescript\n * try { container.userService; }\n * catch (e) {\n * if (e instanceof ContainerError) {\n * console.log(e.hint); // actionable fix\n * console.log(e.details); // structured context\n * }\n * }\n * ```\n */\nexport abstract class ContainerError extends Error {\n abstract readonly hint: string;\n abstract readonly details: Record<string, unknown>;\n\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n/**\n * Thrown when a non-function value is passed in the deps definition.\n *\n * @example\n * ```typescript\n * createContainer({ apiKey: 'sk-123' });\n * // ContainerConfigError: 'apiKey' must be a factory function, got string.\n * // hint: \"Wrap it: apiKey: () => 'sk-123'\"\n * ```\n */\nexport class ContainerConfigError extends ContainerError {\n readonly hint: string;\n readonly details: Record<string, unknown>;\n\n constructor(key: string, actualType: string) {\n super(`'${key}' must be a factory function, got ${actualType}.`);\n this.hint = `Wrap it: ${key}: () => ${JSON.stringify(key === key ? `<your ${actualType} value>` : key)}`;\n this.details = { key, actualType };\n }\n}\n\n/**\n * Thrown when a reserved container method name is used as a dependency key.\n *\n * @example\n * ```typescript\n * createContainer({ inspect: () => 'foo' });\n * // ReservedKeyError: 'inspect' is a reserved container method.\n * // hint: \"Rename this dependency, e.g. 'inspectService' or 'dataInspector'.\"\n * ```\n */\nexport class ReservedKeyError extends ContainerError {\n readonly hint: string;\n readonly details: Record<string, unknown>;\n\n constructor(key: string, reserved: readonly string[]) {\n super(`'${key}' is a reserved container method.`);\n this.hint = `Rename this dependency, e.g. '${key}Service' or 'my${key[0].toUpperCase()}${key.slice(1)}'.`;\n this.details = { key, reserved: [...reserved] };\n }\n}\n\n/**\n * Thrown when a dependency cannot be found during resolution.\n * Includes fuzzy suggestion if a similar key exists.\n *\n * @example\n * ```typescript\n * container.userService;\n * // ProviderNotFoundError: Cannot resolve 'userService': dependency 'userRepo' not found.\n * // hint: \"Did you mean 'userRepository'?\"\n * ```\n */\nexport class ProviderNotFoundError extends ContainerError {\n readonly hint: string;\n readonly details: Record<string, unknown>;\n\n constructor(\n key: string,\n chain: string[],\n registered: string[],\n suggestion?: string,\n ) {\n const chainStr =\n chain.length > 0\n ? `\\n\\nResolution chain: ${[...chain, `${key} (not found)`].join(' -> ')}`\n : '';\n const registeredStr = `\\nRegistered keys: [${registered.join(', ')}]`;\n const suggestionStr = suggestion ? `\\n\\nDid you mean '${suggestion}'?` : '';\n\n super(\n `Cannot resolve '${chain[0] ?? key}': dependency '${key}' not found.${chainStr}${registeredStr}${suggestionStr}`,\n );\n\n this.hint = suggestion\n ? `Did you mean '${suggestion}'? Or add '${key}' to your container:\\n createContainer({\\n ...existing,\\n ${key}: (c) => new Your${key[0].toUpperCase()}${key.slice(1)}(/* deps */),\\n });`\n : `Add '${key}' to your container:\\n createContainer({\\n ...existing,\\n ${key}: (c) => new Your${key[0].toUpperCase()}${key.slice(1)}(/* deps */),\\n });`;\n this.details = { key, chain, registered, suggestion };\n }\n}\n\n/**\n * Thrown when a circular dependency is detected.\n *\n * @example\n * ```typescript\n * // CircularDependencyError: Circular dependency detected while resolving 'authService'.\n * // Cycle: authService -> userService -> authService\n * ```\n */\nexport class CircularDependencyError extends ContainerError {\n readonly hint: string;\n readonly details: Record<string, unknown>;\n\n constructor(key: string, chain: string[]) {\n const cycle = [...chain, key].join(' -> ');\n super(\n `Circular dependency detected while resolving '${chain[0]}'.\\n\\nCycle: ${cycle}`,\n );\n this.hint = [\n 'To fix:',\n ' 1. Extract shared logic into a new dependency both can use',\n ' 2. Restructure so one doesn\\'t depend on the other',\n ' 3. Use a mediator/event pattern to decouple them',\n ].join('\\n');\n this.details = { key, chain, cycle };\n }\n}\n\n/**\n * Thrown when a factory function returns `undefined`.\n *\n * @example\n * ```typescript\n * container.db;\n * // UndefinedReturnError: Factory 'db' returned undefined.\n * // hint: \"Did you forget a return statement?\"\n * ```\n */\nexport class UndefinedReturnError extends ContainerError {\n readonly hint: string;\n readonly details: Record<string, unknown>;\n\n constructor(key: string, chain: string[]) {\n const chainStr =\n chain.length > 1\n ? `\\n\\nResolution chain: ${chain.join(' -> ')}`\n : '';\n super(`Factory '${key}' returned undefined.${chainStr}`);\n this.hint =\n 'Your factory function returned undefined. Did you forget a return statement?';\n this.details = { key, chain };\n }\n}\n\n/**\n * Thrown when a factory function throws an error during resolution.\n * Wraps the original error with resolution context.\n *\n * @example\n * ```typescript\n * container.db;\n * // FactoryError: Factory 'db' threw an error: \"Connection refused\"\n * ```\n */\nexport class FactoryError extends ContainerError {\n readonly hint: string;\n readonly details: Record<string, unknown>;\n readonly originalError: unknown;\n\n constructor(key: string, chain: string[], originalError: unknown) {\n const origMessage =\n originalError instanceof Error\n ? originalError.message\n : String(originalError);\n const chainStr =\n chain.length > 1\n ? `\\n\\nResolution chain: ${[...chain.slice(0, -1), `${key} (factory threw)`].join(' -> ')}`\n : '';\n super(`Factory '${key}' threw an error: \"${origMessage}\"${chainStr}`);\n this.hint = `Check the factory function for '${key}'. The error occurred during instantiation.`;\n this.details = { key, chain, originalError: origMessage };\n this.originalError = originalError;\n }\n}\n\n/**\n * Warning emitted when a singleton depends on a transient dependency.\n * The transient value gets frozen inside the singleton — almost always a bug.\n *\n * @example\n * ```typescript\n * // ScopeMismatchWarning: Singleton 'userService' depends on transient 'requestId'.\n * ```\n */\nexport class ScopeMismatchWarning {\n readonly type = 'scope_mismatch' as const;\n readonly message: string;\n readonly hint: string;\n readonly details: Record<string, unknown>;\n\n constructor(singletonKey: string, transientKey: string) {\n this.message = `Singleton '${singletonKey}' depends on transient '${transientKey}'.`;\n this.hint = [\n 'The transient value was resolved once and is now frozen inside the singleton.',\n 'This is almost always a bug.',\n '',\n 'To fix:',\n ` 1. Make '${singletonKey}' transient too: transient((c) => new ${singletonKey[0].toUpperCase()}${singletonKey.slice(1)}(c.${transientKey}))`,\n ` 2. Make '${transientKey}' singleton if it doesn't need to change`,\n ` 3. Inject a factory instead: ${transientKey}Factory: () => () => <your value>`,\n ].join('\\n');\n this.details = { singleton: singletonKey, transient: transientKey };\n }\n}\n","import type { IValidator } from './types.js';\nimport { RESERVED_KEYS } from './types.js';\nimport { ContainerConfigError, ReservedKeyError } from './errors.js';\n\n/**\n * Validates container configuration and provides fuzzy key matching.\n *\n * @example\n * ```typescript\n * const validator = new Validator();\n * validator.validateConfig({ apiKey: 'sk-123' });\n * // throws ContainerConfigError\n * ```\n */\nexport class Validator implements IValidator {\n /**\n * Validates that all values in the config are factory functions\n * and that no reserved keys are used.\n */\n validateConfig(config: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(config)) {\n if (RESERVED_KEYS.includes(key as any)) {\n throw new ReservedKeyError(key, RESERVED_KEYS);\n }\n if (typeof value !== 'function') {\n throw new ContainerConfigError(key, typeof value);\n }\n }\n }\n\n /**\n * Finds the closest registered key to a missing key using Levenshtein distance.\n * Returns `undefined` if no close match is found (threshold: 3).\n *\n * @example\n * ```typescript\n * validator.suggestKey('userRepo', ['userRepository', 'logger', 'db']);\n * // 'userRepository'\n * ```\n */\n suggestKey(key: string, registered: string[]): string | undefined {\n let bestMatch: string | undefined;\n let bestDistance = Infinity;\n\n for (const candidate of registered) {\n const distance = levenshtein(key, candidate);\n if (distance < bestDistance) {\n bestDistance = distance;\n bestMatch = candidate;\n }\n }\n\n // Only suggest if the distance is reasonable relative to the longer string\n if (!bestMatch) return undefined;\n const maxLen = Math.max(key.length, bestMatch.length);\n const similarity = 1 - bestDistance / maxLen;\n // Require at least 50% similarity\n return similarity >= 0.5 ? bestMatch : undefined;\n }\n}\n\n/**\n * Detects duplicate keys across multiple modules (spread objects).\n * Returns an array of keys that appear in more than one source.\n */\nexport function detectDuplicateKeys(\n ...modules: Record<string, unknown>[]\n): string[] {\n const seen = new Map<string, number>();\n const duplicates: string[] = [];\n\n for (const mod of modules) {\n for (const key of Object.keys(mod)) {\n const count = (seen.get(key) ?? 0) + 1;\n seen.set(key, count);\n if (count === 2) {\n duplicates.push(key);\n }\n }\n }\n\n return duplicates;\n}\n\n/**\n * Levenshtein distance between two strings.\n * Used for fuzzy key suggestion in error messages.\n */\nfunction levenshtein(a: string, b: string): number {\n const la = a.length;\n const lb = b.length;\n\n if (la === 0) return lb;\n if (lb === 0) return la;\n\n // Use single-row optimization\n let prev = new Array<number>(lb + 1);\n let curr = new Array<number>(lb + 1);\n\n for (let j = 0; j <= lb; j++) prev[j] = j;\n\n for (let i = 1; i <= la; i++) {\n curr[0] = i;\n for (let j = 1; j <= lb; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n curr[j] = Math.min(\n prev[j] + 1, // deletion\n curr[j - 1] + 1, // insertion\n prev[j - 1] + cost, // substitution\n );\n }\n [prev, curr] = [curr, prev];\n }\n\n return prev[lb];\n}\n","import type { Factory } from '../domain/types.js';\n\n/**\n * Symbol used to mark a factory as transient.\n * Transient factories create a new instance on every access.\n */\nexport const TRANSIENT_MARKER = Symbol.for('inwire:transient');\n\n/**\n * A factory wrapper that marks it as transient.\n */\nexport interface TransientFactory<T = any> {\n (container: any): T;\n [TRANSIENT_MARKER]: true;\n}\n\n/**\n * Wraps a factory function to produce a new instance on every access,\n * instead of the default singleton behavior.\n *\n * @example\n * ```typescript\n * import { createContainer, transient } from 'inwire';\n *\n * const container = createContainer({\n * logger: () => new LoggerService(), // singleton (default)\n * requestId: transient(() => crypto.randomUUID()), // new instance every access\n * });\n *\n * container.requestId; // 'abc-123'\n * container.requestId; // 'def-456' (different!)\n * ```\n */\nexport function transient<T>(factory: Factory<T>): Factory<T> {\n const wrapper = ((container: any) => factory(container)) as TransientFactory<T>;\n wrapper[TRANSIENT_MARKER] = true;\n return wrapper;\n}\n\n/** Checks if a factory is marked as transient. */\nexport function isTransient(factory: unknown): factory is TransientFactory {\n return (\n typeof factory === 'function' &&\n TRANSIENT_MARKER in factory &&\n (factory as any)[TRANSIENT_MARKER] === true\n );\n}\n","import type { DepsDefinition, Factory, IResolver } from '../domain/types.js';\nimport { hasOnInit } from '../domain/lifecycle.js';\nimport {\n CircularDependencyError,\n FactoryError,\n ProviderNotFoundError,\n ScopeMismatchWarning,\n UndefinedReturnError,\n} from '../domain/errors.js';\nimport { Validator } from '../domain/validation.js';\nimport { isTransient } from './transient.js';\n\n/**\n * Core resolver that powers the container's Proxy.\n * Handles lazy resolution, singleton caching, cycle detection,\n * dependency tracking, and scope mismatch warnings.\n */\nexport class Resolver implements IResolver {\n private readonly factories: Map<string, Factory>;\n private readonly cache: Map<string, unknown>;\n private readonly resolving = new Set<string>();\n private readonly depGraph = new Map<string, string[]>();\n private readonly warnings: ScopeMismatchWarning[] = [];\n private readonly validator = new Validator();\n\n /** Parent resolver for scoped containers */\n private readonly parent?: Resolver;\n\n /** Optional name for debugging/introspection */\n private readonly name?: string;\n\n constructor(\n factories: Map<string, Factory>,\n cache?: Map<string, unknown>,\n parent?: Resolver,\n name?: string,\n ) {\n this.factories = factories;\n this.cache = cache ?? new Map();\n this.parent = parent;\n this.name = name;\n }\n\n getName(): string | undefined {\n return this.name;\n }\n\n /**\n * Resolves a dependency by key.\n * - Returns cached singleton if available\n * - Detects circular dependencies\n * - Tracks dependencies accessed by each factory\n * - Calls `onInit()` on newly created instances\n * - Emits scope mismatch warnings\n */\n resolve(key: string, chain: string[] = []): unknown {\n // Check singleton cache (non-transient only)\n const factory = this.factories.get(key);\n\n if (factory && !isTransient(factory) && this.cache.has(key)) {\n return this.cache.get(key);\n }\n\n // Try parent if we don't have the factory\n if (!factory) {\n if (this.parent) {\n return this.parent.resolve(key, chain);\n }\n const allKeys = this.getAllRegisteredKeys();\n const suggestion = this.validator.suggestKey(key, allKeys);\n throw new ProviderNotFoundError(key, chain, allKeys, suggestion);\n }\n\n // Circular dependency detection\n if (this.resolving.has(key)) {\n throw new CircularDependencyError(key, [...chain]);\n }\n\n this.resolving.add(key);\n const currentChain = [...chain, key];\n\n try {\n // Create a tracking proxy to record which deps this factory accesses\n const deps: string[] = [];\n const trackingProxy = this.createTrackingProxy(key, deps, currentChain);\n\n const instance = factory(trackingProxy);\n\n if (instance === undefined) {\n throw new UndefinedReturnError(key, currentChain);\n }\n\n // Record the dependency graph\n this.depGraph.set(key, deps);\n\n // Check scope mismatch: singleton depending on transient\n if (!isTransient(factory)) {\n for (const dep of deps) {\n const depFactory = this.getFactory(dep);\n if (depFactory && isTransient(depFactory)) {\n this.warnings.push(new ScopeMismatchWarning(key, dep));\n }\n }\n }\n\n // Cache singleton\n if (!isTransient(factory)) {\n this.cache.set(key, instance);\n }\n\n // Call onInit if present\n if (hasOnInit(instance)) {\n const initResult = instance.onInit();\n // If onInit returns a promise, we don't await it here (sync resolution)\n // Users should use preload() for async init\n if (initResult instanceof Promise) {\n initResult.catch(() => {\n // onInit errors are swallowed during lazy resolution\n // Use preload() to catch async init errors\n });\n }\n }\n\n return instance;\n } catch (error) {\n if (\n error instanceof CircularDependencyError ||\n error instanceof ProviderNotFoundError ||\n error instanceof UndefinedReturnError ||\n error instanceof FactoryError\n ) {\n throw error;\n }\n throw new FactoryError(key, currentChain, error);\n } finally {\n this.resolving.delete(key);\n }\n }\n\n isResolved(key: string): boolean {\n return this.cache.has(key);\n }\n\n getDepGraph(): Map<string, string[]> {\n return new Map(this.depGraph);\n }\n\n getResolvedKeys(): string[] {\n return [...this.cache.keys()];\n }\n\n getFactories(): Map<string, Factory> {\n return this.factories;\n }\n\n getCache(): Map<string, unknown> {\n return this.cache;\n }\n\n getWarnings(): ScopeMismatchWarning[] {\n return [...this.warnings];\n }\n\n getAllRegisteredKeys(): string[] {\n const keys = new Set<string>(this.factories.keys());\n if (this.parent) {\n for (const key of this.parent.getAllRegisteredKeys()) {\n keys.add(key);\n }\n }\n return [...keys];\n }\n\n /**\n * Creates a Proxy that records which keys a factory accesses.\n * This builds the dependency graph automatically.\n */\n private createTrackingProxy(\n factoryKey: string,\n deps: string[],\n chain: string[],\n ): any {\n return new Proxy(\n {},\n {\n get: (_target, prop) => {\n if (typeof prop === 'symbol') return undefined;\n const depKey = prop as string;\n deps.push(depKey);\n return this.resolve(depKey, chain);\n },\n },\n );\n }\n\n /** Look up a factory in this resolver or its parent chain. */\n private getFactory(key: string): Factory | undefined {\n return this.factories.get(key) ?? this.parent?.getFactory(key);\n }\n}\n","import type {\n ContainerGraph,\n ContainerHealth,\n ContainerWarning,\n ProviderInfo,\n} from '../domain/types.js';\nimport type { Resolver } from '../infrastructure/proxy-handler.js';\nimport { isTransient } from '../infrastructure/transient.js';\n\n/**\n * Builds introspection data from a Resolver instance.\n * Provides `inspect()`, `describe()`, `health()`, and `toString()`.\n */\nexport class Introspection {\n constructor(private readonly resolver: Resolver) {}\n\n /**\n * Returns the full dependency graph as a serializable JSON object.\n */\n inspect(): ContainerGraph {\n const providers: Record<string, ProviderInfo> = {};\n for (const [key, factory] of this.resolver.getFactories()) {\n providers[key] = {\n key,\n resolved: this.resolver.isResolved(key),\n deps: this.resolver.getDepGraph().get(key) ?? [],\n scope: isTransient(factory) ? 'transient' : 'singleton',\n };\n }\n const name = this.resolver.getName();\n return name ? { name, providers } : { providers };\n }\n\n /**\n * Returns detailed information about a specific provider.\n */\n describe(key: string): ProviderInfo {\n const factory = this.resolver.getFactories().get(key);\n if (!factory) {\n return { key, resolved: false, deps: [], scope: 'singleton' };\n }\n return {\n key,\n resolved: this.resolver.isResolved(key),\n deps: this.resolver.getDepGraph().get(key) ?? [],\n scope: isTransient(factory) ? 'transient' : 'singleton',\n };\n }\n\n /**\n * Returns container health status with warnings.\n */\n health(): ContainerHealth {\n const allKeys = [...this.resolver.getFactories().keys()];\n const resolvedKeys = this.resolver.getResolvedKeys();\n const resolvedSet = new Set(resolvedKeys);\n\n const warnings: ContainerWarning[] = this.resolver\n .getWarnings()\n .map((w) => ({\n type: w.type,\n message: w.message,\n details: w.details,\n }));\n\n return {\n totalProviders: allKeys.length,\n resolved: resolvedKeys,\n unresolved: allKeys.filter((k) => !resolvedSet.has(k)),\n warnings,\n };\n }\n\n /**\n * Returns a human-readable representation of the container.\n */\n toString(): string {\n const parts: string[] = [];\n for (const [key] of this.resolver.getFactories()) {\n const resolved = this.resolver.isResolved(key);\n const deps = this.resolver.getDepGraph().get(key);\n const depsStr = deps && deps.length > 0 ? ` -> [${deps.join(', ')}]` : '';\n const status = resolved ? '(resolved)' : '(pending)';\n parts.push(`${key}${depsStr} ${status}`);\n }\n const name = this.resolver.getName();\n const label = name ? `Scope(${name})` : 'Container';\n return `${label} { ${parts.join(', ')} }`;\n }\n}\n","import type { Container, DepsDefinition, Factory, ScopeOptions } from '../domain/types.js';\nimport { Resolver } from '../infrastructure/proxy-handler.js';\nimport { buildContainerProxy } from './create-container.js';\n\n/**\n * Creates a child (scoped) container that inherits the parent's singletons\n * and can add/override dependencies. Scoped singletons are independent from the parent.\n *\n * @example\n * ```typescript\n * const request = createScope(parentResolver, {\n * requestId: () => crypto.randomUUID(),\n * currentUser: () => extractUser(req),\n * }, { name: 'request-123' });\n * ```\n */\nexport function createScope<\n TExtra extends DepsDefinition,\n>(\n parentResolver: Resolver,\n extra: TExtra,\n options?: ScopeOptions,\n): Container<any> {\n const childFactories = new Map<string, Factory>();\n for (const [key, factory] of Object.entries(extra)) {\n childFactories.set(key, factory as Factory);\n }\n\n const childResolver = new Resolver(childFactories, new Map(), parentResolver, options?.name);\n return buildContainerProxy(childResolver);\n}\n","import type { Container, DepsDefinition, Factory, ResolvedDeps, ScopeOptions } from '../domain/types.js';\nimport { hasOnDestroy } from '../domain/lifecycle.js';\nimport { Validator } from '../domain/validation.js';\nimport { Resolver } from '../infrastructure/proxy-handler.js';\nimport { Introspection } from './introspection.js';\nimport { createScope } from './scope.js';\n\nconst validator = new Validator();\n\n/**\n * Creates a dependency injection container from an object of factory functions.\n * Each factory receives the container and returns an instance.\n * Dependencies are resolved lazily and cached as singletons by default.\n *\n * @example\n * ```typescript\n * const container = createContainer({\n * logger: () => new LoggerService(),\n * db: () => new Database(process.env.DB_URL!),\n * userRepo: (c): UserRepository => new PgUserRepo(c.db),\n * userService: (c) => new UserService(c.userRepo, c.logger),\n * });\n *\n * container.userService; // type: UserService — lazy, singleton, fully resolved\n * ```\n */\nexport function createContainer<T extends DepsDefinition>(\n defs: T,\n): Container<ResolvedDeps<T>> {\n // Validate config\n validator.validateConfig(defs);\n\n // Build factories map\n const factories = new Map<string, Factory>();\n for (const [key, factory] of Object.entries(defs)) {\n factories.set(key, factory as Factory);\n }\n\n // Detect duplicate keys (warn, don't throw)\n // This is useful when spreading multiple modules\n // We check by looking at the property descriptor — if a key was overwritten\n // during spread, JS already picked the last one. We can't detect this post-spread,\n // so the user needs to use detectDuplicateKeys() explicitly or we warn at a higher level.\n\n const resolver = new Resolver(factories);\n return buildContainerProxy(resolver) as Container<ResolvedDeps<T>>;\n}\n\n/**\n * Builds the Proxy-based container from a Resolver.\n * Used by both `createContainer` and `createScope`.\n * @internal\n */\nexport function buildContainerProxy(resolver: Resolver): Container<any> {\n const introspection = new Introspection(resolver);\n const methods: Record<string, Function> = {\n scope: (extra: DepsDefinition, options?: ScopeOptions) => createScope(resolver, extra, options),\n\n extend: (extra: DepsDefinition) => {\n validator.validateConfig(extra);\n const merged = new Map(resolver.getFactories());\n for (const [key, factory] of Object.entries(extra)) {\n merged.set(key, factory as Factory);\n }\n // Share existing cache (singletons already resolved)\n const newResolver = new Resolver(merged, new Map(resolver.getCache()));\n return buildContainerProxy(newResolver);\n },\n\n preload: async (...keys: string[]) => {\n const toResolve = keys.length > 0 ? keys : [...resolver.getFactories().keys()];\n for (const key of toResolve) {\n resolver.resolve(key);\n }\n },\n\n reset: (...keys: string[]) => {\n const cache = resolver.getCache();\n for (const key of keys) {\n cache.delete(key);\n }\n },\n\n inspect: () => introspection.inspect(),\n describe: (key: string) => introspection.describe(key),\n health: () => introspection.health(),\n toString: () => introspection.toString(),\n\n dispose: async () => {\n const cache = resolver.getCache();\n // Dispose in reverse order of resolution (LIFO)\n const entries = [...cache.entries()].reverse();\n for (const [, instance] of entries) {\n if (hasOnDestroy(instance)) {\n await instance.onDestroy();\n }\n }\n cache.clear();\n },\n };\n\n const proxy = new Proxy(\n {},\n {\n get(_target, prop) {\n if (typeof prop === 'symbol') {\n if (prop === Symbol.toPrimitive || prop === Symbol.toStringTag) {\n return () => introspection.toString();\n }\n return undefined;\n }\n\n const key = prop as string;\n\n // Container methods\n if (key in methods) {\n return methods[key];\n }\n\n // Dependency resolution\n return resolver.resolve(key);\n },\n\n has(_target, prop) {\n if (typeof prop === 'symbol') return false;\n const key = prop as string;\n return (\n key in methods ||\n resolver.getFactories().has(key) ||\n resolver.getAllRegisteredKeys().includes(key)\n );\n },\n\n ownKeys() {\n return [...resolver.getAllRegisteredKeys(), ...Object.keys(methods)];\n },\n\n getOwnPropertyDescriptor(_target, prop) {\n if (typeof prop === 'symbol') return undefined;\n const key = prop as string;\n if (\n key in methods ||\n resolver.getFactories().has(key) ||\n resolver.getAllRegisteredKeys().includes(key)\n ) {\n return {\n configurable: true,\n enumerable: key in methods ? false : true,\n writable: false,\n };\n }\n return undefined;\n },\n },\n );\n\n return proxy as Container<any>;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,387 @@
1
+ /**
2
+ * A factory function that receives the container and returns an instance.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * const factory: Factory<MyService> = (c) => new MyService(c.db);
7
+ * ```
8
+ */
9
+ type Factory<T = any> = (container: any) => T;
10
+ /**
11
+ * An object of factory functions — the definition of a container.
12
+ * Each key maps to a factory that produces the dependency.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const deps: DepsDefinition = {
17
+ * logger: () => new LoggerService(),
18
+ * db: () => new Database(process.env.DB_URL!),
19
+ * userRepo: (c) => new PgUserRepo(c.db),
20
+ * };
21
+ * ```
22
+ */
23
+ type DepsDefinition = Record<string, Factory>;
24
+ /**
25
+ * Extracts the resolved types from a deps definition.
26
+ * Maps each key to the return type of its factory function.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * type Resolved = ResolvedDeps<{ logger: () => LoggerService }>;
31
+ * // { logger: LoggerService }
32
+ * ```
33
+ */
34
+ type ResolvedDeps<T extends DepsDefinition> = {
35
+ readonly [K in keyof T]: ReturnType<T[K]>;
36
+ };
37
+ /**
38
+ * Options for creating a scoped container.
39
+ */
40
+ interface ScopeOptions {
41
+ /** Optional name for the scope, useful for debugging and introspection. */
42
+ name?: string;
43
+ }
44
+ /**
45
+ * Full container type exposed to the user.
46
+ * Combines resolved dependencies with container methods.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const container: Container<{ logger: LoggerService }> = createContainer({
51
+ * logger: () => new LoggerService(),
52
+ * });
53
+ * container.logger; // LoggerService
54
+ * container.inspect(); // ContainerGraph
55
+ * ```
56
+ */
57
+ type Container<T extends Record<string, any> = Record<string, any>> = T & IContainer<T>;
58
+ /**
59
+ * Container methods interface. Defines the API available on every container.
60
+ */
61
+ interface IContainer<T extends Record<string, any> = Record<string, any>> {
62
+ /**
63
+ * Creates a child container with additional dependencies.
64
+ * Child inherits all parent singletons and can add/override deps.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const request = app.scope({
69
+ * requestId: () => crypto.randomUUID(),
70
+ * currentUser: () => extractUser(req),
71
+ * });
72
+ * request.requestId; // scoped singleton
73
+ * request.logger; // inherited from parent
74
+ * ```
75
+ */
76
+ scope<E extends DepsDefinition>(extra: E, options?: ScopeOptions): Container<T & ResolvedDeps<E>>;
77
+ /**
78
+ * Returns a new container with additional dependencies.
79
+ * Existing singletons are shared. The original container is not modified.
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const appWithAuth = app.extend(authDeps);
84
+ * ```
85
+ */
86
+ extend<E extends DepsDefinition>(extra: E): Container<T & ResolvedDeps<E>>;
87
+ /**
88
+ * Pre-resolves dependencies (warm-up).
89
+ * Call with specific keys to resolve only those, or without arguments to resolve all.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * await container.preload('db', 'cache'); // specific deps
94
+ * await container.preload(); // all deps
95
+ * ```
96
+ */
97
+ preload(...keys: (keyof T)[]): Promise<void>;
98
+ /**
99
+ * Returns the full dependency graph as a serializable JSON object.
100
+ * Useful for AI analysis of the architecture.
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * container.inspect();
105
+ * // { providers: { logger: { key: 'logger', resolved: true, deps: [], scope: 'singleton' } } }
106
+ * ```
107
+ */
108
+ inspect(): ContainerGraph;
109
+ /**
110
+ * Returns detailed information about a specific provider.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * container.describe('userService');
115
+ * // { key: 'userService', resolved: true, deps: ['userRepo', 'logger'], scope: 'singleton' }
116
+ * ```
117
+ */
118
+ describe(key: keyof T): ProviderInfo;
119
+ /**
120
+ * Returns container health status and warnings.
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * container.health();
125
+ * // { totalProviders: 12, resolved: ['db', 'logger'], unresolved: ['cache'], warnings: [] }
126
+ * ```
127
+ */
128
+ health(): ContainerHealth;
129
+ /**
130
+ * Invalidates cached singletons, forcing re-creation on next access.
131
+ * Does not affect parent scopes.
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * container.reset('db'); // reset one
136
+ * container.reset('db', 'cache'); // reset multiple
137
+ * ```
138
+ */
139
+ reset(...keys: (keyof T)[]): void;
140
+ /**
141
+ * Disposes the container. Calls `onDestroy()` on all resolved instances
142
+ * that implement it, in reverse resolution order.
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * await container.dispose();
147
+ * ```
148
+ */
149
+ dispose(): Promise<void>;
150
+ }
151
+ /**
152
+ * Full dependency graph of the container.
153
+ */
154
+ interface ContainerGraph {
155
+ name?: string;
156
+ providers: Record<string, ProviderInfo>;
157
+ }
158
+ /**
159
+ * Detailed information about a single provider/dependency.
160
+ */
161
+ interface ProviderInfo {
162
+ key: string;
163
+ resolved: boolean;
164
+ deps: string[];
165
+ scope: 'singleton' | 'transient';
166
+ }
167
+ /**
168
+ * Container health status with warnings.
169
+ */
170
+ interface ContainerHealth {
171
+ totalProviders: number;
172
+ resolved: string[];
173
+ unresolved: string[];
174
+ warnings: ContainerWarning[];
175
+ }
176
+ /**
177
+ * A warning detected by the container's runtime analysis.
178
+ */
179
+ interface ContainerWarning {
180
+ type: 'scope_mismatch' | 'duplicate_key';
181
+ message: string;
182
+ details: Record<string, unknown>;
183
+ }
184
+
185
+ /**
186
+ * Base class for all container errors.
187
+ * Every error includes a human-readable `hint` and structured `details`
188
+ * so that AI tools and developers can auto-correct issues.
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * try { container.userService; }
193
+ * catch (e) {
194
+ * if (e instanceof ContainerError) {
195
+ * console.log(e.hint); // actionable fix
196
+ * console.log(e.details); // structured context
197
+ * }
198
+ * }
199
+ * ```
200
+ */
201
+ declare abstract class ContainerError extends Error {
202
+ abstract readonly hint: string;
203
+ abstract readonly details: Record<string, unknown>;
204
+ constructor(message: string);
205
+ }
206
+ /**
207
+ * Thrown when a non-function value is passed in the deps definition.
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * createContainer({ apiKey: 'sk-123' });
212
+ * // ContainerConfigError: 'apiKey' must be a factory function, got string.
213
+ * // hint: "Wrap it: apiKey: () => 'sk-123'"
214
+ * ```
215
+ */
216
+ declare class ContainerConfigError extends ContainerError {
217
+ readonly hint: string;
218
+ readonly details: Record<string, unknown>;
219
+ constructor(key: string, actualType: string);
220
+ }
221
+ /**
222
+ * Thrown when a reserved container method name is used as a dependency key.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * createContainer({ inspect: () => 'foo' });
227
+ * // ReservedKeyError: 'inspect' is a reserved container method.
228
+ * // hint: "Rename this dependency, e.g. 'inspectService' or 'dataInspector'."
229
+ * ```
230
+ */
231
+ declare class ReservedKeyError extends ContainerError {
232
+ readonly hint: string;
233
+ readonly details: Record<string, unknown>;
234
+ constructor(key: string, reserved: readonly string[]);
235
+ }
236
+ /**
237
+ * Thrown when a dependency cannot be found during resolution.
238
+ * Includes fuzzy suggestion if a similar key exists.
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * container.userService;
243
+ * // ProviderNotFoundError: Cannot resolve 'userService': dependency 'userRepo' not found.
244
+ * // hint: "Did you mean 'userRepository'?"
245
+ * ```
246
+ */
247
+ declare class ProviderNotFoundError extends ContainerError {
248
+ readonly hint: string;
249
+ readonly details: Record<string, unknown>;
250
+ constructor(key: string, chain: string[], registered: string[], suggestion?: string);
251
+ }
252
+ /**
253
+ * Thrown when a circular dependency is detected.
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * // CircularDependencyError: Circular dependency detected while resolving 'authService'.
258
+ * // Cycle: authService -> userService -> authService
259
+ * ```
260
+ */
261
+ declare class CircularDependencyError extends ContainerError {
262
+ readonly hint: string;
263
+ readonly details: Record<string, unknown>;
264
+ constructor(key: string, chain: string[]);
265
+ }
266
+ /**
267
+ * Thrown when a factory function returns `undefined`.
268
+ *
269
+ * @example
270
+ * ```typescript
271
+ * container.db;
272
+ * // UndefinedReturnError: Factory 'db' returned undefined.
273
+ * // hint: "Did you forget a return statement?"
274
+ * ```
275
+ */
276
+ declare class UndefinedReturnError extends ContainerError {
277
+ readonly hint: string;
278
+ readonly details: Record<string, unknown>;
279
+ constructor(key: string, chain: string[]);
280
+ }
281
+ /**
282
+ * Thrown when a factory function throws an error during resolution.
283
+ * Wraps the original error with resolution context.
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * container.db;
288
+ * // FactoryError: Factory 'db' threw an error: "Connection refused"
289
+ * ```
290
+ */
291
+ declare class FactoryError extends ContainerError {
292
+ readonly hint: string;
293
+ readonly details: Record<string, unknown>;
294
+ readonly originalError: unknown;
295
+ constructor(key: string, chain: string[], originalError: unknown);
296
+ }
297
+ /**
298
+ * Warning emitted when a singleton depends on a transient dependency.
299
+ * The transient value gets frozen inside the singleton — almost always a bug.
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * // ScopeMismatchWarning: Singleton 'userService' depends on transient 'requestId'.
304
+ * ```
305
+ */
306
+ declare class ScopeMismatchWarning {
307
+ readonly type: "scope_mismatch";
308
+ readonly message: string;
309
+ readonly hint: string;
310
+ readonly details: Record<string, unknown>;
311
+ constructor(singletonKey: string, transientKey: string);
312
+ }
313
+
314
+ /**
315
+ * Creates a dependency injection container from an object of factory functions.
316
+ * Each factory receives the container and returns an instance.
317
+ * Dependencies are resolved lazily and cached as singletons by default.
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * const container = createContainer({
322
+ * logger: () => new LoggerService(),
323
+ * db: () => new Database(process.env.DB_URL!),
324
+ * userRepo: (c): UserRepository => new PgUserRepo(c.db),
325
+ * userService: (c) => new UserService(c.userRepo, c.logger),
326
+ * });
327
+ *
328
+ * container.userService; // type: UserService — lazy, singleton, fully resolved
329
+ * ```
330
+ */
331
+ declare function createContainer<T extends DepsDefinition>(defs: T): Container<ResolvedDeps<T>>;
332
+
333
+ /**
334
+ * Wraps a factory function to produce a new instance on every access,
335
+ * instead of the default singleton behavior.
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * import { createContainer, transient } from 'inwire';
340
+ *
341
+ * const container = createContainer({
342
+ * logger: () => new LoggerService(), // singleton (default)
343
+ * requestId: transient(() => crypto.randomUUID()), // new instance every access
344
+ * });
345
+ *
346
+ * container.requestId; // 'abc-123'
347
+ * container.requestId; // 'def-456' (different!)
348
+ * ```
349
+ */
350
+ declare function transient<T>(factory: Factory<T>): Factory<T>;
351
+
352
+ /**
353
+ * Implement this interface (or just add an `onInit` method) to run
354
+ * initialization logic when the dependency is first resolved.
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * class Database implements OnInit {
359
+ * async onInit() { await this.connect(); }
360
+ * }
361
+ * ```
362
+ */
363
+ interface OnInit {
364
+ onInit(): void | Promise<void>;
365
+ }
366
+ /**
367
+ * Implement this interface (or just add an `onDestroy` method) to run
368
+ * cleanup logic when `container.dispose()` is called.
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * class Database implements OnDestroy {
373
+ * async onDestroy() { await this.disconnect(); }
374
+ * }
375
+ * ```
376
+ */
377
+ interface OnDestroy {
378
+ onDestroy(): void | Promise<void>;
379
+ }
380
+
381
+ /**
382
+ * Detects duplicate keys across multiple modules (spread objects).
383
+ * Returns an array of keys that appear in more than one source.
384
+ */
385
+ declare function detectDuplicateKeys(...modules: Record<string, unknown>[]): string[];
386
+
387
+ export { CircularDependencyError, type Container, ContainerConfigError, ContainerError, type ContainerGraph, type ContainerHealth, type ContainerWarning, type DepsDefinition, type Factory, FactoryError, type IContainer, type OnDestroy, type OnInit, type ProviderInfo, ProviderNotFoundError, ReservedKeyError, type ResolvedDeps, ScopeMismatchWarning, type ScopeOptions, UndefinedReturnError, createContainer, detectDuplicateKeys, transient };