@shinigoji/levain-core 1.0.0-rc.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Levain contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # @shinigoji/levain-core
2
+
3
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Strict-blue?logo=typescript)](https://www.typescriptlang.org/)
4
+ [![Status](https://img.shields.io/badge/Status-V1%20RC%20Freeze-blue)](#stability)
5
+ [![Runtime](https://img.shields.io/badge/Runtime-Node%20%7C%20Bun-111?logo=javascript)](#runtime-compatibility)
6
+
7
+ Type-safe dependency injection for TypeScript.
8
+
9
+ `@shinigoji/levain-core` is built for explicit composition, predictable lifetimes, and safe sync/async resolution without
10
+ decorators or runtime magic.
11
+
12
+ ## Stability
13
+
14
+ `@shinigoji/levain-core` is in **V1 RC freeze** mode: the public API contract is now treated
15
+ as stable for release-candidate validation before `1.0.0`.
16
+
17
+ ## Install
18
+
19
+ When published:
20
+
21
+ ```bash
22
+ npm install @shinigoji/levain-core
23
+ ```
24
+
25
+ Inside this monorepo, use the workspace package directly.
26
+
27
+ ## Runtime Compatibility
28
+
29
+ | Runtime | Status |
30
+ |---------|-----------|
31
+ | Node.js | Supported |
32
+ | Bun | Supported |
33
+
34
+ ## 60-Second Quick Start
35
+
36
+ ```ts
37
+ import {createContainer, createDSL} from "@shinigoji/levain-core";
38
+
39
+ const {token, singleton} = createDSL();
40
+
41
+ class Logger {
42
+ info(message: string) {
43
+ console.log(message);
44
+ }
45
+ }
46
+
47
+ class UserService {
48
+ constructor(private readonly logger: Logger) {}
49
+ }
50
+
51
+ const LOGGER = token<Logger>("LOGGER");
52
+ const USER_SERVICE = token<UserService>("USER_SERVICE");
53
+
54
+ const container = createContainer()
55
+ .register(...singleton(LOGGER, () => new Logger()))
56
+ .register(...singleton.withDeps(USER_SERVICE, [LOGGER], (logger) => new UserService(logger)));
57
+
58
+ const service = container.resolve(USER_SERVICE);
59
+ ```
60
+
61
+ ## Features
62
+
63
+ - Hierarchical containers with per-request scopes
64
+ - `singleton`, `scoped`, `transient` lifetimes
65
+ - Async factories with `resolveAsync()`
66
+ - Runtime safety errors with useful metadata
67
+ - Optional static graph validation with `container.validate()`
68
+
69
+ ## API Overview
70
+
71
+ ```ts
72
+ import {
73
+ createContainer,
74
+ createDSL,
75
+ AsyncFactoryInSyncResolveError,
76
+ CircularDependencyError,
77
+ DependencyNotFoundError,
78
+ InvalidLifetimeDependencyError,
79
+ } from "@shinigoji/levain-core";
80
+ ```
81
+
82
+ `createDSL()` returns:
83
+
84
+ - `token<T>(description)`
85
+ - `singleton`, `scoped`, `transient`
86
+ - `*.withDeps(token, deps, factory)`
87
+ - `*.async(token, asyncFactory)`
88
+ - `*.async.withDeps(token, deps, asyncFactory)`
89
+
90
+ `createContainer()` returns:
91
+
92
+ - `register(token, registration)`
93
+ - `registerMany(...entries)`
94
+ - `resolve(token)` / `tryResolve(token)`
95
+ - `resolveAsync(token)` / `tryResolveAsync(token)`
96
+ - `createScope()`
97
+ - `inspect(options?)`
98
+ - `dispose(options?)`
99
+ - `validate()`
100
+
101
+ ## Public API Contract (V1 Hardening)
102
+
103
+ The public entrypoint is intentionally constrained to `@shinigoji/levain-core` root exports.
104
+ Internal modules (`src/token`, `src/registration`, etc.) are not part of the
105
+ compatibility contract and may change without semver guarantees.
106
+
107
+ ### V1 Stable Contract
108
+
109
+ The following API surface is intended to be semver-stable for V1:
110
+
111
+ - `createContainer`, `createDSL`
112
+ - `Container` methods:
113
+ - `register`
114
+ - `registerMany`
115
+ - `resolve` / `tryResolve`
116
+ - `resolveAsync` / `tryResolveAsync`
117
+ - `createScope`
118
+ - `inspect`
119
+ - `dispose`
120
+ - `validate`
121
+ - Error classes and metadata:
122
+ - `DependencyNotFoundError` (`code`, `tokenDescription`, `resolutionPath`)
123
+ - `CircularDependencyError` (`code`, `resolutionPath`)
124
+ - `InvalidLifetimeDependencyError` (`code`, `consumer`, `consumerLifetime`, `dependency`, `dependencyLifetime`, `resolutionPath`)
125
+ - `AsyncFactoryInSyncResolveError` (`code`, `tokenDescription`)
126
+ - `MissingDependencyMetadataError` (`tokenDescription`)
127
+ - Public type exports from package root:
128
+ - `Token`
129
+ - `Lifetime`
130
+ - `Resolver`, `AsyncResolver`
131
+ - `Registration`, `AsyncRegistration`
132
+ - `LevainDSL`, `DSLBuilder`, `AsyncDSLBuilder`
133
+ - `RegistrationEntry`, `AsyncRegistrationEntry`
134
+ - `ResolveDeps`, `TokenType`
135
+ - `ErrorCode`
136
+ - `InspectOptions`, `DisposeOptions`
137
+ - `ContainerRegistrationInfo`, `ContainerInspection`
138
+ - `ValidateOptions`
139
+
140
+ ### Non-Contractual Surface (May Change)
141
+
142
+ The following are intentionally out of contract before/for V1:
143
+
144
+ - Deep imports (anything under `@shinigoji/levain-core/src/*`)
145
+ - Internal helper names, file layout, and implementation details
146
+ - Exact error message strings (error classes + metadata are the stable interface)
147
+ - Documentation HTML structure under `docs/api`
148
+
149
+ ### RC Freeze Policy
150
+
151
+ During `1.0.0-rc`:
152
+
153
+ - avoid adding new public API surface unless critical
154
+ - accept bug fixes, docs clarifications, and compatibility hardening
155
+ - require explicit migration notes for any behavioral change
156
+
157
+ Contract checks in this package:
158
+
159
+ - Runtime export-surface contract: `test/public-api.test.ts`
160
+ - Type-level contract assertions: `test/public-api.contract.ts` (validated by `bun run typecheck`)
161
+ - Packaged tarball smoke checks (runtime + types): `scripts/release-check.sh`
162
+
163
+ Generated API reference:
164
+
165
+ - `bun run docs:api` (outputs HTML docs into `docs/api`)
166
+
167
+ Production guides:
168
+
169
+ - HTTP request scope: [`docs/guides/http-request-scope.md`](./docs/guides/http-request-scope.md)
170
+ - Worker job scope: [`docs/guides/worker-job-scope.md`](./docs/guides/worker-job-scope.md)
171
+ - CLI command scope: [`docs/guides/cli-command-scope.md`](./docs/guides/cli-command-scope.md)
172
+
173
+ ## Lifetimes
174
+
175
+ | Lifetime | Behavior |
176
+ |-------------|------------------------------------------|
177
+ | `singleton` | One instance shared by root + all scopes |
178
+ | `scoped` | One instance per scope |
179
+ | `transient` | New instance on each resolve |
180
+
181
+ ## Async Rules
182
+
183
+ - `resolve()` throws if target registration is async
184
+ - `resolveAsync()` works for sync and async registrations
185
+ - Async singleton/scoped cache in-flight promises (prevents double init)
186
+
187
+ ## Validation
188
+
189
+ ```ts
190
+ container.validate();
191
+ container.validate({ requireDepsMetadata: true });
192
+ ```
193
+
194
+ Checks registrations defined with `withDeps` for:
195
+
196
+ - missing dependencies
197
+ - circular dependencies
198
+ - lifetime violations (`singleton -> scoped`)
199
+ - sync registration depending on async registration
200
+
201
+ With `requireDepsMetadata: true`, validation also requires every registration
202
+ to be declared with `withDeps(...)` (including zero-dependency factories via
203
+ `withDeps([] as const, ...)`) so the whole graph can be statically verified.
204
+
205
+ ## Introspection
206
+
207
+ ```ts
208
+ const snapshot = container.inspect();
209
+ ```
210
+
211
+ `inspect()` returns a read-only snapshot of visible registrations (including
212
+ inherited ones by default), registration lifetimes, declared deps metadata, and
213
+ cache sizes.
214
+
215
+ ## Disposal
216
+
217
+ ```ts
218
+ await container.dispose();
219
+ ```
220
+
221
+ `dispose()` clears scoped/singleton caches and attempts to call one of:
222
+
223
+ - `Symbol.asyncDispose`
224
+ - `Symbol.dispose`
225
+ - `dispose()`
226
+ - `close()`
227
+
228
+ By default it disposes child scopes too. Use:
229
+
230
+ ```ts
231
+ await container.dispose({ includeChildren: false });
232
+ ```
233
+
234
+ ## Error Types
235
+
236
+ - `DependencyNotFoundError`
237
+ - `CircularDependencyError`
238
+ - `InvalidLifetimeDependencyError`
239
+ - `AsyncFactoryInSyncResolveError`
240
+ - `MissingDependencyMetadataError`
241
+
242
+ ## Migration (from manual wiring)
243
+
244
+ 1. Start by introducing typed tokens for existing services.
245
+ 2. Register existing factories with `singleton/scoped/transient`.
246
+ 3. Replace constructor wiring progressively with `withDeps(...)`.
247
+ 4. Add `container.validate()` at startup.
248
+ 5. Move async initializers to `*.async` and use `resolveAsync()` in async flows.
249
+
250
+ ## Release Readiness
251
+
252
+ Run the pre-publish check suite from this package:
253
+
254
+ ```bash
255
+ bun run release:check
256
+ ```
257
+
258
+ Generate API docs from declarations:
259
+
260
+ ```bash
261
+ bun run docs:api
262
+ ```
263
+
264
+ ## V1 RC Release Flow
265
+
266
+ Enable prerelease mode with Changesets:
267
+
268
+ ```bash
269
+ bunx @changesets/cli pre enter rc
270
+ ```
271
+
272
+ Then merge changesets as usual. Release automation will publish RC versions
273
+ (`1.0.0-rc.x`) while prerelease mode is active.
274
+
275
+ To leave prerelease mode and publish final `1.0.0`:
276
+
277
+ ```bash
278
+ bunx @changesets/cli pre exit
279
+ ```
280
+
281
+ ## Design Principles
282
+
283
+ - Explicit over implicit
284
+ - Type-first API
285
+ - Deterministic runtime behavior
286
+ - Fail fast with actionable errors
287
+
288
+ ## Non-Goals (v1)
289
+
290
+ - Decorator/reflection-based DI
291
+ - Auto-registration and classpath scanning
292
+ - Framework-specific bindings
@@ -0,0 +1,227 @@
1
+ /**
2
+ * A typed token used to register and resolve services in a container.
3
+ * Each token is unique thanks to its `Symbol` key — two tokens with the
4
+ * same description are distinct.
5
+ */
6
+ interface Token<T> {
7
+ readonly key: symbol;
8
+ readonly description: string;
9
+ }
10
+ /** Creates a new unique {@link Token} with the given description. */
11
+ declare function createToken<T>(description: string): Token<T>;
12
+
13
+ /** The lifetime strategy for a registration. */
14
+ type Lifetime = "singleton" | "scoped" | "transient";
15
+ /** Synchronous dependency resolver. Passed to sync factory functions. */
16
+ interface Resolver {
17
+ resolve<T>(token: Token<T>): T;
18
+ tryResolve<T>(token: Token<T>): T | undefined;
19
+ }
20
+ /** Asynchronous dependency resolver. Passed to async factory functions. */
21
+ interface AsyncResolver {
22
+ resolveAsync<T>(token: Token<T>): Promise<T>;
23
+ tryResolveAsync<T>(token: Token<T>): Promise<T | undefined>;
24
+ }
25
+ /** A synchronous service registration with a lifetime and factory. */
26
+ interface Registration<T> {
27
+ lifetime: Lifetime;
28
+ factory: (resolver: Resolver) => T;
29
+ /** Dependency tokens declared via `withDeps`. Used by {@link Container.validate}. */
30
+ deps?: readonly Token<unknown>[];
31
+ }
32
+ /** An asynchronous service registration with a lifetime and async factory. */
33
+ interface AsyncRegistration<T> {
34
+ lifetime: Lifetime;
35
+ factory: (resolver: AsyncResolver) => Promise<T>;
36
+ async: true;
37
+ /** Dependency tokens declared via `withDeps`. Used by {@link Container.validate}. */
38
+ deps?: readonly Token<unknown>[];
39
+ }
40
+
41
+ type TokenType<TToken> = TToken extends Token<infer T> ? T : never;
42
+ type ResolveDeps<TDeps extends readonly Token<unknown>[]> = {
43
+ [K in keyof TDeps]: TokenType<TDeps[K]>;
44
+ };
45
+ type RegistrationEntry<T> = readonly [Token<T>, Registration<T>];
46
+ type AsyncRegistrationEntry<T> = readonly [Token<T>, AsyncRegistration<T>];
47
+ interface AsyncDSLBuilder {
48
+ <T>(token: Token<T>, factory: (resolver: AsyncResolver) => Promise<T>): AsyncRegistrationEntry<T>;
49
+ withDeps<const TDeps extends readonly Token<unknown>[], T>(token: Token<T>, deps: TDeps, factory: (...deps: ResolveDeps<TDeps>) => Promise<T>): AsyncRegistrationEntry<T>;
50
+ }
51
+ interface DSLBuilder {
52
+ <T>(token: Token<T>, factory: (resolver: Resolver) => T): RegistrationEntry<T>;
53
+ withDeps<const TDeps extends readonly Token<unknown>[], T>(token: Token<T>, deps: TDeps, factory: (...deps: ResolveDeps<TDeps>) => T): RegistrationEntry<T>;
54
+ async: AsyncDSLBuilder;
55
+ }
56
+ interface LevainDSL {
57
+ token: typeof createToken;
58
+ singleton: DSLBuilder;
59
+ scoped: DSLBuilder;
60
+ transient: DSLBuilder;
61
+ }
62
+ /**
63
+ * Creates the Levain DSL — the main entry point for defining services.
64
+ *
65
+ * Returns builders that produce `[token, registration]` tuples ready
66
+ * to pass to {@link Container.register}.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const { token, singleton, transient } = createDSL();
71
+ *
72
+ * const LOGGER = token<Logger>("LOGGER");
73
+ * const [logTok, logReg] = singleton(LOGGER, () => new Logger());
74
+ *
75
+ * const container = createContainer().register(logTok, logReg);
76
+ * ```
77
+ */
78
+ declare function createDSL(): LevainDSL;
79
+
80
+ interface ValidateOptions {
81
+ requireDepsMetadata?: boolean;
82
+ }
83
+ interface InspectOptions {
84
+ includeInherited?: boolean;
85
+ }
86
+ interface DisposeOptions {
87
+ includeChildren?: boolean;
88
+ }
89
+ interface ContainerRegistrationInfo {
90
+ tokenDescription: string;
91
+ lifetime: Lifetime;
92
+ async: boolean;
93
+ deps: string[];
94
+ source: "self" | "inherited";
95
+ }
96
+ interface ContainerInspection {
97
+ hasParent: boolean;
98
+ childScopeCount: number;
99
+ cache: {
100
+ singleton: number;
101
+ scoped: number;
102
+ };
103
+ registrations: ContainerRegistrationInfo[];
104
+ }
105
+ /**
106
+ * Dependency injection container with support for hierarchical scoping,
107
+ * lifetime management, and both sync and async resolution.
108
+ */
109
+ declare class Container implements Resolver, AsyncResolver {
110
+ private readonly parent?;
111
+ private readonly registry;
112
+ private readonly singletonCache;
113
+ private readonly scopedCache;
114
+ private readonly children;
115
+ private constructor();
116
+ static createRoot(): Container;
117
+ /** Registers a service factory for the given token. */
118
+ register<T>(token: Token<T>, registration: Registration<T> | AsyncRegistration<T>): this;
119
+ /** Registers multiple [token, registration] entries at once. */
120
+ registerMany(...entries: ReadonlyArray<readonly [
121
+ Token<unknown>,
122
+ Registration<unknown> | AsyncRegistration<unknown>
123
+ ]>): this;
124
+ /** Creates a child scope that inherits registrations from this container. */
125
+ createScope(): Container;
126
+ /** Returns a read-only snapshot of visible registrations and cache stats. */
127
+ inspect(options?: InspectOptions): ContainerInspection;
128
+ /**
129
+ * Disposes resolved scoped/singleton instances by calling one of:
130
+ * `Symbol.asyncDispose`, `Symbol.dispose`, `dispose()`, or `close()`.
131
+ */
132
+ dispose(options?: DisposeOptions): Promise<void>;
133
+ /**
134
+ * Synchronously resolves a service by its token.
135
+ * @throws {DependencyNotFoundError} If the token is not registered.
136
+ * @throws {CircularDependencyError} If a circular dependency is detected.
137
+ * @throws {InvalidLifetimeDependencyError} If lifetime rules are violated.
138
+ * @throws {AsyncFactoryInSyncResolveError} If the registration is async.
139
+ */
140
+ resolve: <T>(token: Token<T>) => T;
141
+ private resolveWithStack;
142
+ /** Like {@link resolve}, but returns `undefined` instead of throwing {@link DependencyNotFoundError}. */
143
+ tryResolve: <T>(token: Token<T>) => T | undefined;
144
+ /**
145
+ * Asynchronously resolves a service by its token. Works with both sync
146
+ * and async registrations. Async singletons and scoped services cache
147
+ * the `Promise` to prevent double initialization on concurrent calls.
148
+ */
149
+ resolveAsync: <T>(token: Token<T>) => Promise<T>;
150
+ private resolveAsyncWithStack;
151
+ /** Like {@link resolveAsync}, but returns `undefined` instead of throwing {@link DependencyNotFoundError}. */
152
+ tryResolveAsync: <T>(token: Token<T>) => Promise<T | undefined>;
153
+ /**
154
+ * Statically validates the dependency graph without resolving anything.
155
+ * Checks registrations that declare dependencies via `withDeps` for:
156
+ * missing dependencies, circular dependencies, lifetime violations,
157
+ * and sync-depends-on-async errors. Validates child scopes recursively.
158
+ */
159
+ validate(options?: ValidateOptions): void;
160
+ private validateContainer;
161
+ private checkCycle;
162
+ private checkLifetime;
163
+ private detectStaticCycles;
164
+ private checkStaticLifetimeRules;
165
+ private describeKey;
166
+ private collectRegistrationsForInspection;
167
+ private disposeCacheValues;
168
+ private callDisposer;
169
+ private findRegistration;
170
+ private createResolverContext;
171
+ }
172
+ /** Creates a new root {@link Container}. */
173
+ declare function createContainer(): Container;
174
+
175
+ /** Stable machine-readable error code for public DI errors. */
176
+ type ErrorCode = "E_DEP_NOT_FOUND" | "E_CIRCULAR_DEP" | "E_ASYNC_IN_SYNC_RESOLVE" | "E_INVALID_LIFETIME_DEP";
177
+ /** Thrown when resolving a token that has no registration in the container or its parents. */
178
+ declare class DependencyNotFoundError extends Error {
179
+ readonly code: ErrorCode;
180
+ readonly tokenDescription: string;
181
+ readonly resolutionPath: string[];
182
+ constructor(tokenDescription: string, resolutionPath?: string[]);
183
+ }
184
+ /** Thrown when a circular dependency is detected during resolution. */
185
+ declare class CircularDependencyError extends Error {
186
+ readonly code: ErrorCode;
187
+ readonly resolutionPath: string[];
188
+ constructor(resolutionPath: string[]);
189
+ }
190
+ /**
191
+ * Thrown when {@link Container.resolve} encounters an async registration.
192
+ * Use {@link Container.resolveAsync} instead.
193
+ */
194
+ declare class AsyncFactoryInSyncResolveError extends Error {
195
+ readonly code: ErrorCode;
196
+ readonly tokenDescription: string;
197
+ constructor(tokenDescription: string);
198
+ }
199
+ /**
200
+ * Thrown when a registration violates lifetime rules.
201
+ * For example, a singleton depending on a scoped service.
202
+ */
203
+ declare class InvalidLifetimeDependencyError extends Error {
204
+ readonly code: ErrorCode;
205
+ readonly consumer: string;
206
+ readonly consumerLifetime: string;
207
+ readonly dependency: string;
208
+ readonly dependencyLifetime: string;
209
+ readonly resolutionPath: string[];
210
+ constructor(args: {
211
+ consumer: string;
212
+ consumerLifetime: string;
213
+ dependency: string;
214
+ dependencyLifetime: string;
215
+ resolutionPath: string[];
216
+ });
217
+ }
218
+ /**
219
+ * Thrown when strict validation requires dependency metadata but a
220
+ * registration was not declared via `withDeps`.
221
+ */
222
+ declare class MissingDependencyMetadataError extends Error {
223
+ readonly tokenDescription: string;
224
+ constructor(tokenDescription: string);
225
+ }
226
+
227
+ export { type AsyncDSLBuilder, AsyncFactoryInSyncResolveError, type AsyncRegistration, type AsyncRegistrationEntry, type AsyncResolver, CircularDependencyError, Container, type ContainerInspection, type ContainerRegistrationInfo, type DSLBuilder, DependencyNotFoundError, type DisposeOptions, type ErrorCode, type InspectOptions, InvalidLifetimeDependencyError, type LevainDSL, type Lifetime, MissingDependencyMetadataError, type Registration, type RegistrationEntry, type ResolveDeps, type Resolver, type Token, type TokenType, type ValidateOptions, createContainer, createDSL };
package/dist/index.js ADDED
@@ -0,0 +1,601 @@
1
+ // src/registration.ts
2
+ function isAsyncRegistration(reg) {
3
+ return "async" in reg && reg.async === true;
4
+ }
5
+ function createAsyncRegistrationBuilder(lifetime) {
6
+ const builder = ((factory) => {
7
+ return { lifetime, factory, async: true };
8
+ });
9
+ builder.withDeps = (deps, factory) => {
10
+ return {
11
+ lifetime,
12
+ async: true,
13
+ deps,
14
+ factory: async (resolver) => {
15
+ const resolvedDeps = await Promise.all(
16
+ deps.map((dep) => resolver.resolveAsync(dep))
17
+ );
18
+ return factory(...resolvedDeps);
19
+ }
20
+ };
21
+ };
22
+ return builder;
23
+ }
24
+ function createRegistrationBuilder(lifetime) {
25
+ const builder = ((factory) => {
26
+ return { lifetime, factory };
27
+ });
28
+ builder.withDeps = (deps, factory) => {
29
+ return {
30
+ lifetime,
31
+ deps,
32
+ factory: (resolver) => {
33
+ const resolvedDeps = deps.map((dep) => resolver.resolve(dep));
34
+ return factory(...resolvedDeps);
35
+ }
36
+ };
37
+ };
38
+ builder.async = createAsyncRegistrationBuilder(lifetime);
39
+ return builder;
40
+ }
41
+ var singleton = createRegistrationBuilder("singleton");
42
+ var scoped = createRegistrationBuilder("scoped");
43
+ var transient = createRegistrationBuilder("transient");
44
+
45
+ // src/token.ts
46
+ function createToken(description) {
47
+ return { key: Symbol(description), description };
48
+ }
49
+
50
+ // src/dsl.ts
51
+ function createAsyncDSLBuilder(registrationBuilder) {
52
+ const builder = ((token, factory) => {
53
+ return [token, registrationBuilder(factory)];
54
+ });
55
+ builder.withDeps = (token, deps, factory) => {
56
+ return [token, registrationBuilder.withDeps(deps, factory)];
57
+ };
58
+ return builder;
59
+ }
60
+ function createDSLBuilder(registrationBuilder) {
61
+ const builder = ((token, factory) => {
62
+ return [token, registrationBuilder(factory)];
63
+ });
64
+ builder.withDeps = (token, deps, factory) => {
65
+ return [token, registrationBuilder.withDeps(deps, factory)];
66
+ };
67
+ builder.async = createAsyncDSLBuilder(registrationBuilder.async);
68
+ return builder;
69
+ }
70
+ function createDSL() {
71
+ return {
72
+ /** Creates a new unique typed token. */
73
+ token: createToken,
74
+ /** Registers a service as a singleton (one instance for the container's lifetime). */
75
+ singleton: createDSLBuilder(singleton),
76
+ /** Registers a service as scoped (one instance per scope). */
77
+ scoped: createDSLBuilder(scoped),
78
+ /** Registers a service as transient (new instance on every resolution). */
79
+ transient: createDSLBuilder(transient)
80
+ };
81
+ }
82
+
83
+ // src/errors.ts
84
+ var DependencyNotFoundError = class extends Error {
85
+ code = "E_DEP_NOT_FOUND";
86
+ tokenDescription;
87
+ resolutionPath;
88
+ constructor(tokenDescription, resolutionPath = []) {
89
+ const pathText = resolutionPath.length > 0 ? `
90
+ Resolution path: ${resolutionPath.join(" -> ")}` : "";
91
+ super(`No registration found for token: ${tokenDescription}${pathText}`);
92
+ this.name = "DependencyNotFoundError";
93
+ this.tokenDescription = tokenDescription;
94
+ this.resolutionPath = resolutionPath;
95
+ }
96
+ };
97
+ var CircularDependencyError = class extends Error {
98
+ code = "E_CIRCULAR_DEP";
99
+ resolutionPath;
100
+ constructor(resolutionPath) {
101
+ super(`Circular dependency detected: ${resolutionPath.join(" -> ")}`);
102
+ this.name = "CircularDependencyError";
103
+ this.resolutionPath = resolutionPath;
104
+ }
105
+ };
106
+ var AsyncFactoryInSyncResolveError = class extends Error {
107
+ code = "E_ASYNC_IN_SYNC_RESOLVE";
108
+ tokenDescription;
109
+ constructor(tokenDescription) {
110
+ super(
111
+ `Cannot synchronously resolve async registration: ${tokenDescription}. Use resolveAsync() instead.`
112
+ );
113
+ this.name = "AsyncFactoryInSyncResolveError";
114
+ this.tokenDescription = tokenDescription;
115
+ }
116
+ };
117
+ var InvalidLifetimeDependencyError = class extends Error {
118
+ code = "E_INVALID_LIFETIME_DEP";
119
+ consumer;
120
+ consumerLifetime;
121
+ dependency;
122
+ dependencyLifetime;
123
+ resolutionPath;
124
+ constructor(args) {
125
+ const {
126
+ consumer,
127
+ consumerLifetime,
128
+ dependency,
129
+ dependencyLifetime,
130
+ resolutionPath
131
+ } = args;
132
+ const pathText = resolutionPath.length > 0 ? `
133
+ Resolution path: ${resolutionPath.join(" -> ")}` : "";
134
+ super(
135
+ `Invalid lifetime dependency: ${consumerLifetime} "${consumer}" cannot depend on ${dependencyLifetime} "${dependency}"${pathText}`
136
+ );
137
+ this.name = "InvalidLifetimeDependencyError";
138
+ this.consumer = consumer;
139
+ this.consumerLifetime = consumerLifetime;
140
+ this.dependency = dependency;
141
+ this.dependencyLifetime = dependencyLifetime;
142
+ this.resolutionPath = resolutionPath;
143
+ }
144
+ };
145
+ var MissingDependencyMetadataError = class extends Error {
146
+ tokenDescription;
147
+ constructor(tokenDescription) {
148
+ super(
149
+ `Missing dependency metadata for token: ${tokenDescription}. Use withDeps(...) so validate({ requireDepsMetadata: true }) can statically verify it.`
150
+ );
151
+ this.name = "MissingDependencyMetadataError";
152
+ this.tokenDescription = tokenDescription;
153
+ }
154
+ };
155
+
156
+ // src/container.ts
157
+ function describeToken(token) {
158
+ return token.description ?? token.key.toString();
159
+ }
160
+ function findInvalidLifetimeConsumer(stack, dependencyLifetime) {
161
+ if (dependencyLifetime === "scoped") {
162
+ return stack.find((frame) => frame.lifetime === "singleton");
163
+ }
164
+ return void 0;
165
+ }
166
+ var Container = class _Container {
167
+ constructor(parent) {
168
+ this.parent = parent;
169
+ }
170
+ parent;
171
+ registry = /* @__PURE__ */ new Map();
172
+ singletonCache = /* @__PURE__ */ new Map();
173
+ scopedCache = /* @__PURE__ */ new Map();
174
+ children = /* @__PURE__ */ new Set();
175
+ static createRoot() {
176
+ return new _Container();
177
+ }
178
+ /** Registers a service factory for the given token. */
179
+ register(token, registration) {
180
+ this.registry.set(token.key, registration);
181
+ return this;
182
+ }
183
+ /** Registers multiple [token, registration] entries at once. */
184
+ registerMany(...entries) {
185
+ for (const [token, registration] of entries) {
186
+ this.registry.set(token.key, registration);
187
+ }
188
+ return this;
189
+ }
190
+ /** Creates a child scope that inherits registrations from this container. */
191
+ createScope() {
192
+ const child = new _Container(this);
193
+ this.children.add(child);
194
+ return child;
195
+ }
196
+ /** Returns a read-only snapshot of visible registrations and cache stats. */
197
+ inspect(options = {}) {
198
+ const includeInherited = options.includeInherited ?? true;
199
+ const registrations = this.collectRegistrationsForInspection(includeInherited).map(({ key, registration, source }) => ({
200
+ tokenDescription: this.describeKey(key),
201
+ lifetime: registration.lifetime,
202
+ async: isAsyncRegistration(registration),
203
+ deps: registration.deps?.map((dep) => describeToken(dep)) ?? [],
204
+ source
205
+ })).sort((a, b) => a.tokenDescription.localeCompare(b.tokenDescription));
206
+ return {
207
+ hasParent: this.parent !== void 0,
208
+ childScopeCount: this.children.size,
209
+ cache: {
210
+ singleton: this.singletonCache.size,
211
+ scoped: this.scopedCache.size
212
+ },
213
+ registrations
214
+ };
215
+ }
216
+ /**
217
+ * Disposes resolved scoped/singleton instances by calling one of:
218
+ * `Symbol.asyncDispose`, `Symbol.dispose`, `dispose()`, or `close()`.
219
+ */
220
+ async dispose(options = {}) {
221
+ const includeChildren = options.includeChildren ?? true;
222
+ const disposedValues = /* @__PURE__ */ new Set();
223
+ const errors = [];
224
+ if (includeChildren) {
225
+ for (const child of this.children) {
226
+ await child.dispose(options).catch((error) => {
227
+ errors.push(error);
228
+ });
229
+ }
230
+ }
231
+ await this.disposeCacheValues(this.scopedCache, disposedValues, errors);
232
+ await this.disposeCacheValues(this.singletonCache, disposedValues, errors);
233
+ this.scopedCache.clear();
234
+ this.singletonCache.clear();
235
+ this.children.clear();
236
+ if (errors.length > 0) {
237
+ throw new AggregateError(errors, "Container dispose failed");
238
+ }
239
+ }
240
+ /**
241
+ * Synchronously resolves a service by its token.
242
+ * @throws {DependencyNotFoundError} If the token is not registered.
243
+ * @throws {CircularDependencyError} If a circular dependency is detected.
244
+ * @throws {InvalidLifetimeDependencyError} If lifetime rules are violated.
245
+ * @throws {AsyncFactoryInSyncResolveError} If the registration is async.
246
+ */
247
+ resolve = (token) => {
248
+ return this.resolveWithStack(token, []);
249
+ };
250
+ resolveWithStack(token, stack) {
251
+ const found = this.findRegistration(token.key);
252
+ if (!found) {
253
+ throw new DependencyNotFoundError(
254
+ describeToken(token),
255
+ stack.map((frame) => describeToken(frame.token))
256
+ );
257
+ }
258
+ const { registration, owner } = found;
259
+ if (isAsyncRegistration(registration)) {
260
+ throw new AsyncFactoryInSyncResolveError(describeToken(token));
261
+ }
262
+ this.checkCycle(token, stack);
263
+ this.checkLifetime(token, registration, stack);
264
+ const nextStack = [...stack, {
265
+ token,
266
+ lifetime: registration.lifetime
267
+ }];
268
+ const resolver = this.createResolverContext(nextStack);
269
+ if (registration.lifetime === "singleton") {
270
+ if (owner.singletonCache.has(token.key)) {
271
+ return owner.singletonCache.get(token.key);
272
+ }
273
+ const instance = registration.factory(resolver);
274
+ owner.singletonCache.set(token.key, instance);
275
+ return instance;
276
+ }
277
+ if (registration.lifetime === "scoped") {
278
+ if (this.scopedCache.has(token.key)) {
279
+ return this.scopedCache.get(token.key);
280
+ }
281
+ const instance = registration.factory(resolver);
282
+ this.scopedCache.set(token.key, instance);
283
+ return instance;
284
+ }
285
+ return registration.factory(resolver);
286
+ }
287
+ /** Like {@link resolve}, but returns `undefined` instead of throwing {@link DependencyNotFoundError}. */
288
+ tryResolve = (token) => {
289
+ try {
290
+ return this.resolve(token);
291
+ } catch (error) {
292
+ if (error instanceof DependencyNotFoundError) {
293
+ return void 0;
294
+ }
295
+ throw error;
296
+ }
297
+ };
298
+ /**
299
+ * Asynchronously resolves a service by its token. Works with both sync
300
+ * and async registrations. Async singletons and scoped services cache
301
+ * the `Promise` to prevent double initialization on concurrent calls.
302
+ */
303
+ resolveAsync = async (token) => {
304
+ return await this.resolveAsyncWithStack(token, []);
305
+ };
306
+ async resolveAsyncWithStack(token, stack) {
307
+ const found = this.findRegistration(token.key);
308
+ if (!found) {
309
+ throw new DependencyNotFoundError(
310
+ describeToken(token),
311
+ stack.map((frame) => describeToken(frame.token))
312
+ );
313
+ }
314
+ const { registration, owner } = found;
315
+ this.checkCycle(token, stack);
316
+ this.checkLifetime(token, registration, stack);
317
+ const nextStack = [...stack, {
318
+ token,
319
+ lifetime: registration.lifetime
320
+ }];
321
+ const resolver = this.createResolverContext(nextStack);
322
+ if (registration.lifetime === "singleton") {
323
+ if (owner.singletonCache.has(token.key)) {
324
+ return await owner.singletonCache.get(token.key);
325
+ }
326
+ if (isAsyncRegistration(registration)) {
327
+ const promise = registration.factory(resolver).catch((err) => {
328
+ owner.singletonCache.delete(token.key);
329
+ throw err;
330
+ });
331
+ owner.singletonCache.set(token.key, promise);
332
+ return await promise;
333
+ }
334
+ const instance = registration.factory(resolver);
335
+ owner.singletonCache.set(token.key, instance);
336
+ return instance;
337
+ }
338
+ if (registration.lifetime === "scoped") {
339
+ if (this.scopedCache.has(token.key)) {
340
+ return await this.scopedCache.get(token.key);
341
+ }
342
+ if (isAsyncRegistration(registration)) {
343
+ const promise = registration.factory(resolver).catch((err) => {
344
+ this.scopedCache.delete(token.key);
345
+ throw err;
346
+ });
347
+ this.scopedCache.set(token.key, promise);
348
+ return await promise;
349
+ }
350
+ const instance = registration.factory(resolver);
351
+ this.scopedCache.set(token.key, instance);
352
+ return instance;
353
+ }
354
+ if (isAsyncRegistration(registration)) {
355
+ return await registration.factory(resolver);
356
+ }
357
+ return registration.factory(resolver);
358
+ }
359
+ /** Like {@link resolveAsync}, but returns `undefined` instead of throwing {@link DependencyNotFoundError}. */
360
+ tryResolveAsync = async (token) => {
361
+ try {
362
+ return await this.resolveAsync(token);
363
+ } catch (error) {
364
+ if (error instanceof DependencyNotFoundError) {
365
+ return void 0;
366
+ }
367
+ throw error;
368
+ }
369
+ };
370
+ /**
371
+ * Statically validates the dependency graph without resolving anything.
372
+ * Checks registrations that declare dependencies via `withDeps` for:
373
+ * missing dependencies, circular dependencies, lifetime violations,
374
+ * and sync-depends-on-async errors. Validates child scopes recursively.
375
+ */
376
+ validate(options = {}) {
377
+ this.validateContainer(options);
378
+ for (const child of this.children) {
379
+ child.validate(options);
380
+ }
381
+ }
382
+ validateContainer(options) {
383
+ if (options.requireDepsMetadata) {
384
+ for (const [key, registration] of this.registry) {
385
+ if (!registration.deps) {
386
+ throw new MissingDependencyMetadataError(this.describeKey(key));
387
+ }
388
+ }
389
+ }
390
+ for (const [key, registration] of this.registry) {
391
+ if (!registration.deps) continue;
392
+ const token = this.describeKey(key);
393
+ for (const dep of registration.deps) {
394
+ const found = this.findRegistration(dep.key);
395
+ if (!found) {
396
+ throw new DependencyNotFoundError(
397
+ describeToken(dep),
398
+ [token]
399
+ );
400
+ }
401
+ if (!isAsyncRegistration(registration) && isAsyncRegistration(found.registration)) {
402
+ throw new AsyncFactoryInSyncResolveError(describeToken(dep));
403
+ }
404
+ }
405
+ }
406
+ this.detectStaticCycles();
407
+ this.checkStaticLifetimeRules();
408
+ }
409
+ checkCycle(token, stack) {
410
+ const cycleStartIndex = stack.findIndex(
411
+ (frame) => frame.token.key === token.key
412
+ );
413
+ if (cycleStartIndex >= 0) {
414
+ const cyclePath = [
415
+ ...stack.slice(cycleStartIndex).map((frame) => describeToken(frame.token)),
416
+ describeToken(token)
417
+ ];
418
+ throw new CircularDependencyError(cyclePath);
419
+ }
420
+ }
421
+ checkLifetime(token, registration, stack) {
422
+ const invalidConsumer = findInvalidLifetimeConsumer(
423
+ stack,
424
+ registration.lifetime
425
+ );
426
+ if (invalidConsumer) {
427
+ throw new InvalidLifetimeDependencyError({
428
+ consumer: describeToken(invalidConsumer.token),
429
+ consumerLifetime: invalidConsumer.lifetime,
430
+ dependency: describeToken(token),
431
+ dependencyLifetime: registration.lifetime,
432
+ resolutionPath: [
433
+ ...stack.map((frame) => describeToken(frame.token)),
434
+ describeToken(token)
435
+ ]
436
+ });
437
+ }
438
+ }
439
+ detectStaticCycles() {
440
+ const visited = /* @__PURE__ */ new Set();
441
+ const inStack = /* @__PURE__ */ new Set();
442
+ const path = [];
443
+ const visit = (key) => {
444
+ if (inStack.has(key)) {
445
+ const description = this.describeKey(key);
446
+ const cycleStart = path.indexOf(description);
447
+ const cyclePath = [...path.slice(cycleStart), description];
448
+ throw new CircularDependencyError(cyclePath);
449
+ }
450
+ if (visited.has(key)) return;
451
+ const registration = this.findRegistration(key)?.registration;
452
+ if (!registration?.deps) return;
453
+ visited.add(key);
454
+ inStack.add(key);
455
+ path.push(this.describeKey(key));
456
+ for (const dep of registration.deps) {
457
+ visit(dep.key);
458
+ }
459
+ path.pop();
460
+ inStack.delete(key);
461
+ };
462
+ for (const [key] of this.registry) {
463
+ visit(key);
464
+ }
465
+ }
466
+ checkStaticLifetimeRules() {
467
+ const visit = (key, ancestors) => {
468
+ const found = this.findRegistration(key);
469
+ if (!found) return;
470
+ const { registration } = found;
471
+ const invalidConsumer = findInvalidLifetimeConsumer(ancestors, registration.lifetime);
472
+ if (invalidConsumer) {
473
+ throw new InvalidLifetimeDependencyError({
474
+ consumer: describeToken(invalidConsumer.token),
475
+ consumerLifetime: invalidConsumer.lifetime,
476
+ dependency: this.describeKey(key),
477
+ dependencyLifetime: registration.lifetime,
478
+ resolutionPath: [
479
+ ...ancestors.map((f) => describeToken(f.token)),
480
+ this.describeKey(key)
481
+ ]
482
+ });
483
+ }
484
+ if (!registration.deps) return;
485
+ const token = { key, description: this.describeKey(key) };
486
+ const frame = { token, lifetime: registration.lifetime };
487
+ for (const dep of registration.deps) {
488
+ visit(dep.key, [...ancestors, frame]);
489
+ }
490
+ };
491
+ for (const [key, registration] of this.registry) {
492
+ if (!registration.deps) continue;
493
+ const token = { key, description: this.describeKey(key) };
494
+ const frame = { token, lifetime: registration.lifetime };
495
+ for (const dep of registration.deps) {
496
+ visit(dep.key, [frame]);
497
+ }
498
+ }
499
+ }
500
+ describeKey(key) {
501
+ return key.description ?? key.toString();
502
+ }
503
+ collectRegistrationsForInspection(includeInherited) {
504
+ const visible = /* @__PURE__ */ new Map();
505
+ for (const [key, registration] of this.registry) {
506
+ visible.set(key, { registration, source: "self" });
507
+ }
508
+ if (includeInherited) {
509
+ let cursor = this.parent;
510
+ while (cursor) {
511
+ for (const [key, registration] of cursor.registry) {
512
+ if (!visible.has(key)) {
513
+ visible.set(key, { registration, source: "inherited" });
514
+ }
515
+ }
516
+ cursor = cursor.parent;
517
+ }
518
+ }
519
+ return [...visible.entries()].map(([key, value]) => ({
520
+ key,
521
+ registration: value.registration,
522
+ source: value.source
523
+ }));
524
+ }
525
+ async disposeCacheValues(cache, disposedValues, errors) {
526
+ for (const value of cache.values()) {
527
+ try {
528
+ const resolved = await value;
529
+ await this.callDisposer(resolved, disposedValues);
530
+ } catch (error) {
531
+ errors.push(error);
532
+ }
533
+ }
534
+ }
535
+ async callDisposer(value, disposedValues) {
536
+ if (value === null || value === void 0) return;
537
+ if (typeof value !== "object" && typeof value !== "function") return;
538
+ if (disposedValues.has(value)) return;
539
+ disposedValues.add(value);
540
+ const asyncDisposeSymbol = Symbol.asyncDispose;
541
+ const syncDisposeSymbol = Symbol.dispose;
542
+ const candidate = value;
543
+ if (asyncDisposeSymbol && typeof candidate[asyncDisposeSymbol] === "function") {
544
+ await candidate[asyncDisposeSymbol]?.();
545
+ return;
546
+ }
547
+ if (syncDisposeSymbol && typeof candidate[syncDisposeSymbol] === "function") {
548
+ candidate[syncDisposeSymbol]?.();
549
+ return;
550
+ }
551
+ if (typeof candidate.dispose === "function") {
552
+ await candidate.dispose();
553
+ return;
554
+ }
555
+ if (typeof candidate.close === "function") {
556
+ await candidate.close();
557
+ }
558
+ }
559
+ findRegistration(key) {
560
+ const registration = this.registry.get(key);
561
+ if (registration) {
562
+ return { registration, owner: this };
563
+ }
564
+ return this.parent?.findRegistration(key);
565
+ }
566
+ createResolverContext(stack) {
567
+ return {
568
+ resolve: (token) => this.resolveWithStack(token, stack),
569
+ tryResolve: (token) => {
570
+ try {
571
+ return this.resolveWithStack(token, stack);
572
+ } catch (error) {
573
+ if (error instanceof DependencyNotFoundError) {
574
+ return void 0;
575
+ }
576
+ throw error;
577
+ }
578
+ },
579
+ resolveAsync: async (token) => {
580
+ return await this.resolveAsyncWithStack(token, stack);
581
+ },
582
+ tryResolveAsync: async (token) => {
583
+ try {
584
+ return await this.resolveAsyncWithStack(token, stack);
585
+ } catch (error) {
586
+ if (error instanceof DependencyNotFoundError) {
587
+ return void 0;
588
+ }
589
+ throw error;
590
+ }
591
+ }
592
+ };
593
+ }
594
+ };
595
+ function createContainer() {
596
+ return Container.createRoot();
597
+ }
598
+
599
+ export { AsyncFactoryInSyncResolveError, CircularDependencyError, Container, DependencyNotFoundError, InvalidLifetimeDependencyError, MissingDependencyMetadataError, createContainer, createDSL };
600
+ //# sourceMappingURL=index.js.map
601
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/registration.ts","../src/token.ts","../src/dsl.ts","../src/errors.ts","../src/container.ts"],"names":[],"mappings":";AAoCO,SAAS,oBACZ,GAAA,EAC2B;AAC7B,EAAA,OAAO,OAAA,IAAW,GAAA,IAAO,GAAA,CAAI,KAAA,KAAU,IAAA;AACzC;AAyBA,SAAS,+BAA+B,QAAA,EAA8C;AACpF,EAAA,MAAM,OAAA,IAAW,CACb,OAAA,KACuB;AACzB,IAAA,OAAO,EAAE,QAAA,EAAU,OAAA,EAAS,KAAA,EAAO,IAAA,EAAK;AAAA,EAC1C,CAAA,CAAA;AAEA,EAAA,OAAA,CAAQ,QAAA,GAAW,CACf,IAAA,EACA,OAAA,KACuB;AACzB,IAAA,OAAO;AAAA,MACL,QAAA;AAAA,MACA,KAAA,EAAO,IAAA;AAAA,MACP,IAAA;AAAA,MACA,OAAA,EAAS,OAAO,QAAA,KAAa;AAC3B,QAAA,MAAM,YAAA,GAAe,MAAM,OAAA,CAAQ,GAAA;AAAA,UAC/B,KAAK,GAAA,CAAI,CAAC,QAAQ,QAAA,CAAS,YAAA,CAAa,GAAG,CAAC;AAAA,SAChD;AACA,QAAA,OAAO,OAAA,CAAQ,GAAG,YAAY,CAAA;AAAA,MAChC;AAAA,KACF;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,0BAA0B,QAAA,EAAyC;AAC1E,EAAA,MAAM,OAAA,IAAW,CAAI,OAAA,KAAwD;AAC3E,IAAA,OAAO,EAAE,UAAU,OAAA,EAAQ;AAAA,EAC7B,CAAA,CAAA;AAEA,EAAA,OAAA,CAAQ,QAAA,GAAW,CACf,IAAA,EACA,OAAA,KACkB;AACpB,IAAA,OAAO;AAAA,MACL,QAAA;AAAA,MACA,IAAA;AAAA,MACA,OAAA,EAAS,CAAC,QAAA,KAAa;AACrB,QAAA,MAAM,YAAA,GAAe,KAAK,GAAA,CAAI,CAAC,QAAQ,QAAA,CAAS,OAAA,CAAQ,GAAG,CAAC,CAAA;AAC5D,QAAA,OAAO,OAAA,CAAQ,GAAG,YAAY,CAAA;AAAA,MAChC;AAAA,KACF;AAAA,EACF,CAAA;AAEA,EAAA,OAAA,CAAQ,KAAA,GAAQ,+BAA+B,QAAQ,CAAA;AAEvD,EAAA,OAAO,OAAA;AACT;AAEO,IAAM,SAAA,GAAY,0BAA0B,WAAW,CAAA;AACvD,IAAM,MAAA,GAAS,0BAA0B,QAAQ,CAAA;AACjD,IAAM,SAAA,GAAY,0BAA0B,WAAW,CAAA;;;AC3GvD,SAAS,YAAe,WAAA,EAA+B;AAC5D,EAAA,OAAO,EAAE,GAAA,EAAK,MAAA,CAAO,WAAW,GAAG,WAAA,EAAY;AACjD;;;ACiCA,SAAS,sBACL,mBAAA,EAOe;AACf,EAAA,MAAM,OAAA,IAAW,CACb,KAAA,EACA,OAAA,KAC4B;AAC5B,IAAA,OAAO,CAAC,KAAA,EAAO,mBAAA,CAAoB,OAAO,CAAC,CAAA;AAAA,EAC/C,CAAA,CAAA;AAEA,EAAA,OAAA,CAAQ,QAAA,GAAW,CACf,KAAA,EACA,IAAA,EACA,OAAA,KAC4B;AAC5B,IAAA,OAAO,CAAC,KAAA,EAAO,mBAAA,CAAoB,QAAA,CAAS,IAAA,EAAM,OAAO,CAAC,CAAA;AAAA,EAC9D,CAAA;AAEA,EAAA,OAAO,OAAA;AACX;AAEA,SAAS,iBACL,mBAAA,EAcU;AACV,EAAA,MAAM,OAAA,IAAW,CACb,KAAA,EACA,OAAA,KACuB;AACvB,IAAA,OAAO,CAAC,KAAA,EAAO,mBAAA,CAAoB,OAAO,CAAC,CAAA;AAAA,EAC/C,CAAA,CAAA;AAEA,EAAA,OAAA,CAAQ,QAAA,GAAW,CACf,KAAA,EACA,IAAA,EACA,OAAA,KACuB;AACvB,IAAA,OAAO,CAAC,KAAA,EAAO,mBAAA,CAAoB,QAAA,CAAS,IAAA,EAAM,OAAO,CAAC,CAAA;AAAA,EAC9D,CAAA;AAEA,EAAA,OAAA,CAAQ,KAAA,GAAQ,qBAAA,CAAsB,mBAAA,CAAoB,KAAK,CAAA;AAE/D,EAAA,OAAO,OAAA;AACX;AAkBO,SAAS,SAAA,GAAuB;AACnC,EAAA,OAAO;AAAA;AAAA,IAEH,KAAA,EAAO,WAAA;AAAA;AAAA,IAEP,SAAA,EAAW,iBAAiB,SAAS,CAAA;AAAA;AAAA,IAErC,MAAA,EAAQ,iBAAiB,MAAM,CAAA;AAAA;AAAA,IAE/B,SAAA,EAAW,iBAAiB,SAAS;AAAA,GACzC;AACJ;;;AChIO,IAAM,uBAAA,GAAN,cAAsC,KAAA,CAAM;AAAA,EACtC,IAAA,GAAkB,iBAAA;AAAA,EAClB,gBAAA;AAAA,EACA,cAAA;AAAA,EAET,WAAA,CAAY,gBAAA,EAA0B,cAAA,GAA2B,EAAC,EAAG;AACjE,IAAA,MAAM,QAAA,GACF,cAAA,CAAe,MAAA,GAAS,CAAA,GAClB;AAAA,iBAAA,EAAsB,cAAA,CAAe,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA,GACjD,EAAA;AAEV,IAAA,KAAA,CAAM,CAAA,iCAAA,EAAoC,gBAAgB,CAAA,EAAG,QAAQ,CAAA,CAAE,CAAA;AACvE,IAAA,IAAA,CAAK,IAAA,GAAO,yBAAA;AACZ,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AACxB,IAAA,IAAA,CAAK,cAAA,GAAiB,cAAA;AAAA,EAC1B;AACJ;AAGO,IAAM,uBAAA,GAAN,cAAsC,KAAA,CAAM;AAAA,EACtC,IAAA,GAAkB,gBAAA;AAAA,EAClB,cAAA;AAAA,EAET,YAAY,cAAA,EAA0B;AAClC,IAAA,KAAA,CAAM,CAAA,8BAAA,EAAiC,cAAA,CAAe,IAAA,CAAK,MAAM,CAAC,CAAA,CAAE,CAAA;AACpE,IAAA,IAAA,CAAK,IAAA,GAAO,yBAAA;AACZ,IAAA,IAAA,CAAK,cAAA,GAAiB,cAAA;AAAA,EAC1B;AACJ;AAMO,IAAM,8BAAA,GAAN,cAA6C,KAAA,CAAM;AAAA,EAC7C,IAAA,GAAkB,yBAAA;AAAA,EAClB,gBAAA;AAAA,EAET,YAAY,gBAAA,EAA0B;AAClC,IAAA,KAAA;AAAA,MACI,oDAAoD,gBAAgB,CAAA,6BAAA;AAAA,KACxE;AACA,IAAA,IAAA,CAAK,IAAA,GAAO,gCAAA;AACZ,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AAAA,EAC5B;AACJ;AAMO,IAAM,8BAAA,GAAN,cAA6C,KAAA,CAAM;AAAA,EAC7C,IAAA,GAAkB,wBAAA;AAAA,EAClB,QAAA;AAAA,EACA,gBAAA;AAAA,EACA,UAAA;AAAA,EACA,kBAAA;AAAA,EACA,cAAA;AAAA,EAET,YAAY,IAAA,EAMT;AACC,IAAA,MAAM;AAAA,MACF,QAAA;AAAA,MACA,gBAAA;AAAA,MACA,UAAA;AAAA,MACA,kBAAA;AAAA,MACA;AAAA,KACJ,GAAI,IAAA;AAEJ,IAAA,MAAM,QAAA,GACF,cAAA,CAAe,MAAA,GAAS,CAAA,GAClB;AAAA,iBAAA,EAAsB,cAAA,CAAe,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA,GACjD,EAAA;AAEV,IAAA,KAAA;AAAA,MACI,CAAA,6BAAA,EAAgC,gBAAgB,CAAA,EAAA,EAAK,QAAQ,sBAAsB,kBAAkB,CAAA,EAAA,EAAK,UAAU,CAAA,CAAA,EAAI,QAAQ,CAAA;AAAA,KACpI;AAEA,IAAA,IAAA,CAAK,IAAA,GAAO,gCAAA;AACZ,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AACxB,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAA,CAAK,kBAAA,GAAqB,kBAAA;AAC1B,IAAA,IAAA,CAAK,cAAA,GAAiB,cAAA;AAAA,EAC1B;AACJ;AAMO,IAAM,8BAAA,GAAN,cAA6C,KAAA,CAAM;AAAA,EAC7C,gBAAA;AAAA,EAET,YAAY,gBAAA,EAA0B;AAClC,IAAA,KAAA;AAAA,MACI,0CAA0C,gBAAgB,CAAA,wFAAA;AAAA,KAE9D;AACA,IAAA,IAAA,CAAK,IAAA,GAAO,gCAAA;AACZ,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AAAA,EAC5B;AACJ;;;AC5DA,SAAS,cAAiB,KAAA,EAAyB;AACjD,EAAA,OAAO,KAAA,CAAM,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,QAAA,EAAS;AACjD;AAEA,SAAS,2BAAA,CACL,OACA,kBAAA,EAC2B;AAC7B,EAAA,IAAI,uBAAuB,QAAA,EAAU;AACnC,IAAA,OAAO,MAAM,IAAA,CAAK,CAAC,KAAA,KAAU,KAAA,CAAM,aAAa,WAAW,CAAA;AAAA,EAC7D;AAEA,EAAA,OAAO,MAAA;AACT;AAMO,IAAM,SAAA,GAAN,MAAM,UAAA,CAA6C;AAAA,EAM9C,YAA6B,MAAA,EAAoB;AAApB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EACrC;AAAA,EADqC,MAAA;AAAA,EALtB,QAAA,uBAAe,GAAA,EAAmC;AAAA,EAClD,cAAA,uBAAqB,GAAA,EAAkB;AAAA,EACvC,WAAA,uBAAkB,GAAA,EAAkB;AAAA,EACpC,QAAA,uBAAe,GAAA,EAAe;AAAA,EAK7C,OAAO,UAAA,GAAwB;AAC3B,IAAA,OAAO,IAAI,UAAA,EAAU;AAAA,EAC3B;AAAA;AAAA,EAGA,QAAA,CAAY,OAAiB,YAAA,EAA4D;AACvF,IAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,YAAwC,CAAA;AACrE,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA,EAGA,gBACO,OAAA,EAIC;AACN,IAAA,KAAA,MAAW,CAAC,KAAA,EAAO,YAAY,CAAA,IAAK,OAAA,EAAS;AAC3C,MAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,YAAwC,CAAA;AAAA,IACvE;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA,EAGA,WAAA,GAAyB;AACrB,IAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAU,IAAI,CAAA;AAClC,IAAA,IAAA,CAAK,QAAA,CAAS,IAAI,KAAK,CAAA;AACvB,IAAA,OAAO,KAAA;AAAA,EACT;AAAA;AAAA,EAGA,OAAA,CAAQ,OAAA,GAA0B,EAAC,EAAwB;AACzD,IAAA,MAAM,gBAAA,GAAmB,QAAQ,gBAAA,IAAoB,IAAA;AACrD,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,iCAAA,CAAkC,gBAAgB,CAAA,CACxE,GAAA,CAAI,CAAC,EAAC,GAAA,EAAK,YAAA,EAAc,MAAA,EAAM,MAAO;AAAA,MACrC,gBAAA,EAAkB,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AAAA,MACtC,UAAU,YAAA,CAAa,QAAA;AAAA,MACvB,KAAA,EAAO,oBAAoB,YAAY,CAAA;AAAA,MACvC,IAAA,EAAM,YAAA,CAAa,IAAA,EAAM,GAAA,CAAI,CAAC,QAAQ,aAAA,CAAc,GAAG,CAAC,CAAA,IAAK,EAAC;AAAA,MAC9D;AAAA,KACF,CAAE,CAAA,CACD,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,gBAAA,CAAiB,aAAA,CAAc,CAAA,CAAE,gBAAgB,CAAC,CAAA;AAExE,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,KAAK,MAAA,KAAW,MAAA;AAAA,MAC3B,eAAA,EAAiB,KAAK,QAAA,CAAS,IAAA;AAAA,MAC/B,KAAA,EAAO;AAAA,QACL,SAAA,EAAW,KAAK,cAAA,CAAe,IAAA;AAAA,QAC/B,MAAA,EAAQ,KAAK,WAAA,CAAY;AAAA,OAC3B;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAA,CAAQ,OAAA,GAA0B,EAAC,EAAkB;AACzD,IAAA,MAAM,eAAA,GAAkB,QAAQ,eAAA,IAAmB,IAAA;AACnD,IAAA,MAAM,cAAA,uBAAqB,GAAA,EAAa;AACxC,IAAA,MAAM,SAAoB,EAAC;AAE3B,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,KAAA,MAAW,KAAA,IAAS,KAAK,QAAA,EAAU;AACjC,QAAA,MAAM,MAAM,OAAA,CAAQ,OAAO,CAAA,CAAE,KAAA,CAAM,CAAC,KAAA,KAAmB;AACrD,UAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,QACnB,CAAC,CAAA;AAAA,MACH;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,CAAK,kBAAA,CAAmB,IAAA,CAAK,WAAA,EAAa,gBAAgB,MAAM,CAAA;AACtE,IAAA,MAAM,IAAA,CAAK,kBAAA,CAAmB,IAAA,CAAK,cAAA,EAAgB,gBAAgB,MAAM,CAAA;AAEzE,IAAA,IAAA,CAAK,YAAY,KAAA,EAAM;AACvB,IAAA,IAAA,CAAK,eAAe,KAAA,EAAM;AAC1B,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AAEpB,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,MAAM,IAAI,cAAA,CAAe,MAAA,EAAQ,0BAA0B,CAAA;AAAA,IAC7D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAA,GAAU,CAAI,KAAA,KAAuB;AACjC,IAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,KAAA,EAAO,EAAE,CAAA;AAAA,EAC1C,CAAA;AAAA,EAEU,gBAAA,CAAoB,OAAiB,KAAA,EAA6B;AAC1E,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,KAAA,CAAM,GAAG,CAAA;AAE7C,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAM,IAAI,uBAAA;AAAA,QACN,cAAc,KAAK,CAAA;AAAA,QACnB,MAAM,GAAA,CAAI,CAAC,UAAU,aAAA,CAAc,KAAA,CAAM,KAAK,CAAC;AAAA,OACnD;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,YAAA,EAAc,KAAA,EAAM,GAAI,KAAA;AAEhC,IAAA,IAAI,mBAAA,CAAoB,YAAY,CAAA,EAAG;AACrC,MAAA,MAAM,IAAI,8BAAA,CAA+B,aAAA,CAAc,KAAK,CAAC,CAAA;AAAA,IAC/D;AAEI,IAAA,IAAA,CAAK,UAAA,CAAW,OAAO,KAAK,CAAA;AAC5B,IAAA,IAAA,CAAK,aAAA,CAAc,KAAA,EAAO,YAAA,EAAc,KAAK,CAAA;AAE7C,IAAA,MAAM,SAAA,GAAY,CAAC,GAAG,KAAA,EAAO;AAAA,MAC/B,KAAA;AAAA,MACA,UAAU,YAAA,CAAa;AAAA,KACpB,CAAA;AAED,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,qBAAA,CAAsB,SAAS,CAAA;AAErD,IAAA,IAAI,YAAA,CAAa,aAAa,WAAA,EAAa;AACvC,MAAA,IAAI,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACrC,QAAA,OAAO,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAAA,MAC7C;AAEA,MAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAC9C,MAAA,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,QAAQ,CAAA;AAC5C,MAAA,OAAO,QAAA;AAAA,IACX;AAEA,IAAA,IAAI,YAAA,CAAa,aAAa,QAAA,EAAU;AACpC,MAAA,IAAI,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACjC,QAAA,OAAO,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAAA,MACzC;AAEA,MAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAC9C,MAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,QAAQ,CAAA;AACxC,MAAA,OAAO,QAAA;AAAA,IACX;AAEA,IAAA,OAAO,YAAA,CAAa,QAAQ,QAAQ,CAAA;AAAA,EACxC;AAAA;AAAA,EAGF,UAAA,GAAa,CAAI,KAAA,KAAmC;AAClD,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,QAAQ,KAAK,CAAA;AAAA,IAC3B,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,iBAAiB,uBAAA,EAAyB;AAC5C,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAA,GAAe,OAAU,KAAA,KAAgC;AACrD,IAAA,OAAO,MAAM,IAAA,CAAK,qBAAA,CAAsB,KAAA,EAAO,EAAE,CAAA;AAAA,EACrD,CAAA;AAAA,EAEE,MAAc,qBAAA,CACV,KAAA,EACA,KAAA,EACU;AACd,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,KAAA,CAAM,GAAG,CAAA;AAE7C,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAM,IAAI,uBAAA;AAAA,QACN,cAAc,KAAK,CAAA;AAAA,QACnB,MAAM,GAAA,CAAI,CAAC,UAAU,aAAA,CAAc,KAAA,CAAM,KAAK,CAAC;AAAA,OACnD;AAAA,IACF;AAEA,IAAA,MAAM,EAAE,YAAA,EAAc,KAAA,EAAM,GAAI,KAAA;AAE5B,IAAA,IAAA,CAAK,UAAA,CAAW,OAAO,KAAK,CAAA;AAC5B,IAAA,IAAA,CAAK,aAAA,CAAc,KAAA,EAAO,YAAA,EAAc,KAAK,CAAA;AAE7C,IAAA,MAAM,SAAA,GAAY,CAAC,GAAG,KAAA,EAAO;AAAA,MAC/B,KAAA;AAAA,MACA,UAAU,YAAA,CAAa;AAAA,KACpB,CAAA;AAED,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,qBAAA,CAAsB,SAAS,CAAA;AAErD,IAAA,IAAI,YAAA,CAAa,aAAa,WAAA,EAAa;AACvC,MAAA,IAAI,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACrC,QAAA,OAAO,MAAM,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,MAAM,GAAG,CAAA;AAAA,MACnD;AAEA,MAAA,IAAI,mBAAA,CAAoB,YAAY,CAAA,EAAG;AACnC,QAAA,MAAM,UAAU,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAiB;AACnE,UAAA,KAAA,CAAM,cAAA,CAAe,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AACrC,UAAA,MAAM,GAAA;AAAA,QACV,CAAC,CAAA;AACD,QAAA,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,OAAO,CAAA;AAC3C,QAAA,OAAO,MAAM,OAAA;AAAA,MACjB;AAEA,MAAA,MAAM,QAAA,GAAY,YAAA,CAAuC,OAAA,CAAQ,QAAQ,CAAA;AACzE,MAAA,KAAA,CAAM,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,QAAQ,CAAA;AAC5C,MAAA,OAAO,QAAA;AAAA,IACX;AAEA,IAAA,IAAI,YAAA,CAAa,aAAa,QAAA,EAAU;AACpC,MAAA,IAAI,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACjC,QAAA,OAAO,MAAM,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,MAAM,GAAG,CAAA;AAAA,MAC/C;AAEA,MAAA,IAAI,mBAAA,CAAoB,YAAY,CAAA,EAAG;AACnC,QAAA,MAAM,UAAU,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAiB;AACnE,UAAA,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AACjC,UAAA,MAAM,GAAA;AAAA,QACV,CAAC,CAAA;AACD,QAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,OAAO,CAAA;AACvC,QAAA,OAAO,MAAM,OAAA;AAAA,MACjB;AAEA,MAAA,MAAM,QAAA,GAAY,YAAA,CAAuC,OAAA,CAAQ,QAAQ,CAAA;AACzE,MAAA,IAAA,CAAK,WAAA,CAAY,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,QAAQ,CAAA;AACxC,MAAA,OAAO,QAAA;AAAA,IACX;AAEA,IAAA,IAAI,mBAAA,CAAoB,YAAY,CAAA,EAAG;AACnC,MAAA,OAAO,MAAM,YAAA,CAAa,OAAA,CAAQ,QAAQ,CAAA;AAAA,IAC9C;AAEA,IAAA,OAAQ,YAAA,CAAuC,QAAQ,QAAQ,CAAA;AAAA,EACnE;AAAA;AAAA,EAGF,eAAA,GAAkB,OAAU,KAAA,KAA4C;AACtE,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,CAAK,YAAA,CAAa,KAAK,CAAA;AAAA,IACtC,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,iBAAiB,uBAAA,EAAyB;AAC5C,QAAA,OAAO,MAAA;AAAA,MACT;AAEA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAA,CAAS,OAAA,GAA2B,EAAC,EAAS;AAC5C,IAAA,IAAA,CAAK,kBAAkB,OAAO,CAAA;AAE9B,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,QAAA,EAAU;AACjC,MAAA,KAAA,CAAM,SAAS,OAAO,CAAA;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,kBAAkB,OAAA,EAAgC;AACxD,IAAA,IAAI,QAAQ,mBAAA,EAAqB;AAC/B,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,YAAY,CAAA,IAAK,KAAK,QAAA,EAAU;AAC/C,QAAA,IAAI,CAAC,aAAa,IAAA,EAAM;AACtB,UAAA,MAAM,IAAI,8BAAA,CAA+B,IAAA,CAAK,WAAA,CAAY,GAAG,CAAC,CAAA;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,YAAY,CAAA,IAAK,KAAK,QAAA,EAAU;AAC/C,MAAA,IAAI,CAAC,aAAa,IAAA,EAAM;AAExB,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AAElC,MAAA,KAAA,MAAW,GAAA,IAAO,aAAa,IAAA,EAAM;AACnC,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,GAAG,CAAA;AAE3C,QAAA,IAAI,CAAC,KAAA,EAAO;AACV,UAAA,MAAM,IAAI,uBAAA;AAAA,YACN,cAAc,GAAG,CAAA;AAAA,YACjB,CAAC,KAAK;AAAA,WACV;AAAA,QACF;AAEA,QAAA,IAAI,CAAC,mBAAA,CAAoB,YAAY,KAAK,mBAAA,CAAoB,KAAA,CAAM,YAAY,CAAA,EAAG;AACjF,UAAA,MAAM,IAAI,8BAAA,CAA+B,aAAA,CAAc,GAAG,CAAC,CAAA;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,kBAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,wBAAA,EAAyB;AAAA,EAChC;AAAA,EAEU,UAAA,CAAc,OAAiB,KAAA,EAAgC;AACnE,IAAA,MAAM,kBAAkB,KAAA,CAAM,SAAA;AAAA,MAC9B,CAAC,KAAA,KAAU,KAAA,CAAM,KAAA,CAAM,QAAQ,KAAA,CAAM;AAAA,KACzC;AAEA,IAAA,IAAI,mBAAmB,CAAA,EAAG;AACxB,MAAA,MAAM,SAAA,GAAY;AAAA,QACd,GAAG,KAAA,CACA,KAAA,CAAM,eAAe,CAAA,CACrB,GAAA,CAAI,CAAC,KAAA,KAAU,aAAA,CAAc,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,QAC9C,cAAc,KAAK;AAAA,OACrB;AAEA,MAAA,MAAM,IAAI,wBAAwB,SAAS,CAAA;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,aAAA,CACJ,KAAA,EACA,YAAA,EACA,KAAA,EACI;AACN,IAAA,MAAM,eAAA,GAAkB,2BAAA;AAAA,MACpB,KAAA;AAAA,MACA,YAAA,CAAa;AAAA,KACjB;AAEA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,MAAM,IAAI,8BAAA,CAA+B;AAAA,QACvC,QAAA,EAAU,aAAA,CAAc,eAAA,CAAgB,KAAK,CAAA;AAAA,QAC7C,kBAAkB,eAAA,CAAgB,QAAA;AAAA,QAClC,UAAA,EAAY,cAAc,KAAK,CAAA;AAAA,QAC/B,oBAAoB,YAAA,CAAa,QAAA;AAAA,QACjC,cAAA,EAAgB;AAAA,UACZ,GAAG,MAAM,GAAA,CAAI,CAAC,UAAU,aAAA,CAAc,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,UACpD,cAAc,KAAK;AAAA;AACrB,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,kBAAA,GAA2B;AACjC,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAS;AAC7B,IAAA,MAAM,OAAA,uBAAc,GAAA,EAAS;AAC7B,IAAA,MAAM,OAAiB,EAAC;AAExB,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAA,KAAmB;AAChC,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG;AACpB,QAAA,MAAM,WAAA,GAAc,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AACxC,QAAA,MAAM,UAAA,GAAa,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA;AAC3C,QAAA,MAAM,YAAY,CAAC,GAAG,KAAK,KAAA,CAAM,UAAU,GAAG,WAAW,CAAA;AACzD,QAAA,MAAM,IAAI,wBAAwB,SAAS,CAAA;AAAA,MAC7C;AAEA,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG;AAEtB,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA,EAAG,YAAA;AACjD,MAAA,IAAI,CAAC,cAAc,IAAA,EAAM;AAEzB,MAAA,OAAA,CAAQ,IAAI,GAAG,CAAA;AACf,MAAA,OAAA,CAAQ,IAAI,GAAG,CAAA;AACf,MAAA,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,WAAA,CAAY,GAAG,CAAC,CAAA;AAE/B,MAAA,KAAA,MAAW,GAAA,IAAO,aAAa,IAAA,EAAM;AACnC,QAAA,KAAA,CAAM,IAAI,GAAG,CAAA;AAAA,MACf;AAEA,MAAA,IAAA,CAAK,GAAA,EAAI;AACT,MAAA,OAAA,CAAQ,OAAO,GAAG,CAAA;AAAA,IACpB,CAAA;AAEA,IAAA,KAAA,MAAW,CAAC,GAAG,CAAA,IAAK,IAAA,CAAK,QAAA,EAAU;AACjC,MAAA,KAAA,CAAM,GAAG,CAAA;AAAA,IACX;AAAA,EACF;AAAA,EAEQ,wBAAA,GAAiC;AACvC,IAAA,MAAM,KAAA,GAAQ,CACV,GAAA,EACA,SAAA,KACO;AACT,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,GAAG,CAAA;AACvC,MAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,MAAA,MAAM,EAAE,cAAa,GAAI,KAAA;AAEzB,MAAA,MAAM,eAAA,GAAkB,2BAAA,CAA4B,SAAA,EAAW,YAAA,CAAa,QAAQ,CAAA;AAEpF,MAAA,IAAI,eAAA,EAAiB;AACnB,QAAA,MAAM,IAAI,8BAAA,CAA+B;AAAA,UACvC,QAAA,EAAU,aAAA,CAAc,eAAA,CAAgB,KAAK,CAAA;AAAA,UAC7C,kBAAkB,eAAA,CAAgB,QAAA;AAAA,UAClC,UAAA,EAAY,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AAAA,UAChC,oBAAoB,YAAA,CAAa,QAAA;AAAA,UACjC,cAAA,EAAgB;AAAA,YACd,GAAG,UAAU,GAAA,CAAI,CAAC,MAAM,aAAA,CAAc,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,YAC9C,IAAA,CAAK,YAAY,GAAG;AAAA;AACtB,SACD,CAAA;AAAA,MACH;AAEA,MAAA,IAAI,CAAC,aAAa,IAAA,EAAM;AAExB,MAAA,MAAM,QAAwB,EAAE,GAAA,EAAK,aAAa,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,EAAE;AACxE,MAAA,MAAM,KAAA,GAAyB,EAAE,KAAA,EAAO,QAAA,EAAU,aAAa,QAAA,EAAS;AAExE,MAAA,KAAA,MAAW,GAAA,IAAO,aAAa,IAAA,EAAM;AACnC,QAAA,KAAA,CAAM,IAAI,GAAA,EAAK,CAAC,GAAG,SAAA,EAAW,KAAK,CAAC,CAAA;AAAA,MACtC;AAAA,IACF,CAAA;AAEA,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,YAAY,CAAA,IAAK,KAAK,QAAA,EAAU;AAC/C,MAAA,IAAI,CAAC,aAAa,IAAA,EAAM;AAExB,MAAA,MAAM,QAAwB,EAAE,GAAA,EAAK,aAAa,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA,EAAE;AACxE,MAAA,MAAM,KAAA,GAAyB,EAAE,KAAA,EAAO,QAAA,EAAU,aAAa,QAAA,EAAS;AAExE,MAAA,KAAA,MAAW,GAAA,IAAO,aAAa,IAAA,EAAM;AACnC,QAAA,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK,CAAC,KAAK,CAAC,CAAA;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,YAAY,GAAA,EAAkB;AACpC,IAAA,OAAO,GAAA,CAAI,WAAA,IAAe,GAAA,CAAI,QAAA,EAAS;AAAA,EACzC;AAAA,EAEQ,kCACJ,gBAAA,EAKD;AACD,IAAA,MAAM,OAAA,uBAAc,GAAA,EAGjB;AAEH,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,YAAY,CAAA,IAAK,KAAK,QAAA,EAAU;AAC/C,MAAA,OAAA,CAAQ,IAAI,GAAA,EAAK,EAAC,YAAA,EAAc,MAAA,EAAQ,QAAO,CAAA;AAAA,IACjD;AAEA,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,IAAI,SAAS,IAAA,CAAK,MAAA;AAClB,MAAA,OAAO,MAAA,EAAQ;AACb,QAAA,KAAA,MAAW,CAAC,GAAA,EAAK,YAAY,CAAA,IAAK,OAAO,QAAA,EAAU;AACjD,UAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG;AACrB,YAAA,OAAA,CAAQ,IAAI,GAAA,EAAK,EAAC,YAAA,EAAc,MAAA,EAAQ,aAAY,CAAA;AAAA,UACtD;AAAA,QACF;AACA,QAAA,MAAA,GAAS,MAAA,CAAO,MAAA;AAAA,MAClB;AAAA,IACF;AAEA,IAAA,OAAO,CAAC,GAAG,OAAA,CAAQ,OAAA,EAAS,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,MAAO;AAAA,MACnD,GAAA;AAAA,MACA,cAAc,KAAA,CAAM,YAAA;AAAA,MACpB,QAAQ,KAAA,CAAM;AAAA,KAChB,CAAE,CAAA;AAAA,EACJ;AAAA,EAEA,MAAc,kBAAA,CACV,KAAA,EACA,cAAA,EACA,MAAA,EACa;AACf,IAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,EAAO,EAAG;AAClC,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAM,KAAA;AACvB,QAAA,MAAM,IAAA,CAAK,YAAA,CAAa,QAAA,EAAU,cAAc,CAAA;AAAA,MAClD,SAAS,KAAA,EAAO;AACd,QAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,YAAA,CACV,KAAA,EACA,cAAA,EACa;AACf,IAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW;AAC3C,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,UAAU,UAAA,EAAY;AAC9D,IAAA,IAAI,cAAA,CAAe,GAAA,CAAI,KAAK,CAAA,EAAG;AAE/B,IAAA,cAAA,CAAe,IAAI,KAAK,CAAA;AAExB,IAAA,MAAM,qBAAqB,MAAA,CAAO,YAAA;AAClC,IAAA,MAAM,oBAAoB,MAAA,CAAO,OAAA;AACjC,IAAA,MAAM,SAAA,GAAY,KAAA;AAMlB,IAAA,IAAI,kBAAA,IAAsB,OAAO,SAAA,CAAU,kBAAkB,MAAM,UAAA,EAAY;AAC7E,MAAA,MAAM,SAAA,CAAU,kBAAkB,CAAA,IAAI;AACtC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,iBAAA,IAAqB,OAAO,SAAA,CAAU,iBAAiB,MAAM,UAAA,EAAY;AAC3E,MAAA,SAAA,CAAU,iBAAiB,CAAA,IAAI;AAC/B,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,SAAA,CAAU,OAAA,KAAY,UAAA,EAAY;AAC3C,MAAA,MAAM,UAAU,OAAA,EAAQ;AACxB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,SAAA,CAAU,KAAA,KAAU,UAAA,EAAY;AACzC,MAAA,MAAM,UAAU,KAAA,EAAM;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,iBACJ,GAAA,EACwE;AAC1E,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AAE1C,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,OAAO,EAAE,YAAA,EAAc,KAAA,EAAO,IAAA,EAAK;AAAA,IACrC;AAEA,IAAA,OAAO,IAAA,CAAK,MAAA,EAAQ,gBAAA,CAAiB,GAAG,CAAA;AAAA,EAC1C;AAAA,EAEU,sBACJ,KAAA,EACwB;AACxB,IAAA,OAAO;AAAA,MACH,SAAS,CAAI,KAAA,KAAuB,IAAA,CAAK,gBAAA,CAAiB,OAAO,KAAK,CAAA;AAAA,MACtE,UAAA,EAAY,CAAI,KAAA,KAAmC;AAC/C,QAAA,IAAI;AACA,UAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,KAAA,EAAO,KAAK,CAAA;AAAA,QAC7C,SAAS,KAAA,EAAO;AACZ,UAAA,IAAI,iBAAiB,uBAAA,EAAyB;AAC1C,YAAA,OAAO,MAAA;AAAA,UACX;AAEA,UAAA,MAAM,KAAA;AAAA,QACV;AAAA,MACJ,CAAA;AAAA,MACA,YAAA,EAAc,OAAU,KAAA,KAAgC;AACpD,QAAA,OAAO,MAAM,IAAA,CAAK,qBAAA,CAAsB,KAAA,EAAO,KAAK,CAAA;AAAA,MACxD,CAAA;AAAA,MACA,eAAA,EAAiB,OAAU,KAAA,KAA4C;AACnE,QAAA,IAAI;AACA,UAAA,OAAO,MAAM,IAAA,CAAK,qBAAA,CAAsB,KAAA,EAAO,KAAK,CAAA;AAAA,QACxD,SAAS,KAAA,EAAO;AACZ,UAAA,IAAI,iBAAiB,uBAAA,EAAyB;AAC1C,YAAA,OAAO,MAAA;AAAA,UACX;AAEA,UAAA,MAAM,KAAA;AAAA,QACV;AAAA,MACJ;AAAA,KACJ;AAAA,EACJ;AACJ;AAGO,SAAS,eAAA,GAA6B;AACzC,EAAA,OAAO,UAAU,UAAA,EAAW;AAChC","file":"index.js","sourcesContent":["import type {Token} from \"./token\";\n\n/** The lifetime strategy for a registration. */\nexport type Lifetime = \"singleton\" | \"scoped\" | \"transient\";\n\n/** Synchronous dependency resolver. Passed to sync factory functions. */\nexport interface Resolver {\n resolve<T>(token: Token<T>): T;\n tryResolve<T>(token: Token<T>): T | undefined;\n}\n\n/** Asynchronous dependency resolver. Passed to async factory functions. */\nexport interface AsyncResolver {\n resolveAsync<T>(token: Token<T>): Promise<T>;\n tryResolveAsync<T>(token: Token<T>): Promise<T | undefined>;\n}\n\n/** A synchronous service registration with a lifetime and factory. */\nexport interface Registration<T> {\n lifetime: Lifetime;\n factory: (resolver: Resolver) => T;\n /** Dependency tokens declared via `withDeps`. Used by {@link Container.validate}. */\n deps?: readonly Token<unknown>[];\n}\n\n/** An asynchronous service registration with a lifetime and async factory. */\nexport interface AsyncRegistration<T> {\n lifetime: Lifetime;\n factory: (resolver: AsyncResolver) => Promise<T>;\n async: true;\n /** Dependency tokens declared via `withDeps`. Used by {@link Container.validate}. */\n deps?: readonly Token<unknown>[];\n}\n\nexport type AnyRegistration<T> = Registration<T> | AsyncRegistration<T>;\n\nexport function isAsyncRegistration<T>(\n reg: AnyRegistration<T>,\n): reg is AsyncRegistration<T> {\n return \"async\" in reg && reg.async === true;\n}\n\ntype TokenType<TToken> = TToken extends Token<infer T> ? T : never;\n\ntype ResolveDeps<TDeps extends readonly Token<unknown>[]> = {\n [K in keyof TDeps]: TokenType<TDeps[K]>;\n};\n\ninterface AsyncRegistrationBuilder {\n <T>(factory: (resolver: AsyncResolver) => Promise<T>): AsyncRegistration<T>;\n withDeps<const TDeps extends readonly Token<unknown>[], T>(\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => Promise<T>,\n ): AsyncRegistration<T>;\n}\n\nexport interface RegistrationBuilder {\n <T>(factory: (resolver: Resolver) => T): Registration<T>;\n withDeps<const TDeps extends readonly Token<unknown>[], T>(\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => T,\n ): Registration<T>;\n async: AsyncRegistrationBuilder;\n}\n\nfunction createAsyncRegistrationBuilder(lifetime: Lifetime): AsyncRegistrationBuilder {\n const builder = (<T>(\n factory: (resolver: AsyncResolver) => Promise<T>,\n ): AsyncRegistration<T> => {\n return { lifetime, factory, async: true };\n }) as AsyncRegistrationBuilder;\n\n builder.withDeps = <const TDeps extends readonly Token<unknown>[], T>(\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => Promise<T>,\n ): AsyncRegistration<T> => {\n return {\n lifetime,\n async: true,\n deps,\n factory: async (resolver) => {\n const resolvedDeps = await Promise.all(\n deps.map((dep) => resolver.resolveAsync(dep)),\n ) as ResolveDeps<TDeps>;\n return factory(...resolvedDeps);\n },\n };\n };\n\n return builder;\n}\n\nfunction createRegistrationBuilder(lifetime: Lifetime): RegistrationBuilder {\n const builder = (<T>(factory: (resolver: Resolver) => T): Registration<T> => {\n return { lifetime, factory };\n }) as RegistrationBuilder;\n\n builder.withDeps = <const TDeps extends readonly Token<unknown>[], T>(\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => T,\n ): Registration<T> => {\n return {\n lifetime,\n deps,\n factory: (resolver) => {\n const resolvedDeps = deps.map((dep) => resolver.resolve(dep)) as ResolveDeps<TDeps>;\n return factory(...resolvedDeps);\n },\n };\n };\n\n builder.async = createAsyncRegistrationBuilder(lifetime);\n\n return builder;\n}\n\nexport const singleton = createRegistrationBuilder(\"singleton\");\nexport const scoped = createRegistrationBuilder(\"scoped\");\nexport const transient = createRegistrationBuilder(\"transient\");\n","/**\n * A typed token used to register and resolve services in a container.\n * Each token is unique thanks to its `Symbol` key — two tokens with the\n * same description are distinct.\n */\nexport interface Token<T> {\n readonly key: symbol;\n readonly description: string;\n}\n\n/** Creates a new unique {@link Token} with the given description. */\nexport function createToken<T>(description: string): Token<T> {\n return { key: Symbol(description), description };\n}\n","import {\n type AsyncRegistration,\n type AsyncResolver,\n type Registration,\n type Resolver,\n scoped,\n singleton,\n transient,\n} from \"./registration\";\nimport {createToken, type Token} from \"./token\";\n\nexport type TokenType<TToken> = TToken extends Token<infer T> ? T : never;\n\nexport type ResolveDeps<TDeps extends readonly Token<unknown>[]> = {\n [K in keyof TDeps]: TokenType<TDeps[K]>;\n};\n\nexport type RegistrationEntry<T> = readonly [Token<T>, Registration<T>];\nexport type AsyncRegistrationEntry<T> = readonly [Token<T>, AsyncRegistration<T>];\n\nexport interface AsyncDSLBuilder {\n <T>(token: Token<T>, factory: (resolver: AsyncResolver) => Promise<T>): AsyncRegistrationEntry<T>;\n withDeps<const TDeps extends readonly Token<unknown>[], T>(\n token: Token<T>,\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => Promise<T>,\n ): AsyncRegistrationEntry<T>;\n}\n\nexport interface DSLBuilder {\n <T>(token: Token<T>, factory: (resolver: Resolver) => T): RegistrationEntry<T>;\n withDeps<const TDeps extends readonly Token<unknown>[], T>(\n token: Token<T>,\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => T,\n ): RegistrationEntry<T>;\n async: AsyncDSLBuilder;\n}\n\nexport interface LevainDSL {\n token: typeof createToken;\n singleton: DSLBuilder;\n scoped: DSLBuilder;\n transient: DSLBuilder;\n}\n\nfunction createAsyncDSLBuilder(\n registrationBuilder: {\n <T>(factory: (resolver: AsyncResolver) => Promise<T>): AsyncRegistration<T>;\n withDeps<const TDeps extends readonly Token<unknown>[], T>(\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => Promise<T>,\n ): AsyncRegistration<T>;\n },\n): AsyncDSLBuilder {\n const builder = (<T>(\n token: Token<T>,\n factory: (resolver: AsyncResolver) => Promise<T>,\n ): AsyncRegistrationEntry<T> => {\n return [token, registrationBuilder(factory)] as const;\n }) as AsyncDSLBuilder;\n\n builder.withDeps = <const TDeps extends readonly Token<unknown>[], T>(\n token: Token<T>,\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => Promise<T>,\n ): AsyncRegistrationEntry<T> => {\n return [token, registrationBuilder.withDeps(deps, factory)] as const;\n };\n\n return builder;\n}\n\nfunction createDSLBuilder(\n registrationBuilder: {\n <T>(factory: (resolver: Resolver) => T): Registration<T>;\n withDeps<const TDeps extends readonly Token<unknown>[], T>(\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => T,\n ): Registration<T>;\n async: {\n <T>(factory: (resolver: AsyncResolver) => Promise<T>): AsyncRegistration<T>;\n withDeps<const TDeps extends readonly Token<unknown>[], T>(\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => Promise<T>,\n ): AsyncRegistration<T>;\n };\n },\n): DSLBuilder {\n const builder = (<T>(\n token: Token<T>,\n factory: (resolver: Resolver) => T,\n ): RegistrationEntry<T> => {\n return [token, registrationBuilder(factory)] as const;\n }) as DSLBuilder;\n\n builder.withDeps = <const TDeps extends readonly Token<unknown>[], T>(\n token: Token<T>,\n deps: TDeps,\n factory: (...deps: ResolveDeps<TDeps>) => T,\n ): RegistrationEntry<T> => {\n return [token, registrationBuilder.withDeps(deps, factory)] as const;\n };\n\n builder.async = createAsyncDSLBuilder(registrationBuilder.async);\n\n return builder;\n}\n\n/**\n * Creates the Levain DSL — the main entry point for defining services.\n *\n * Returns builders that produce `[token, registration]` tuples ready\n * to pass to {@link Container.register}.\n *\n * @example\n * ```ts\n * const { token, singleton, transient } = createDSL();\n *\n * const LOGGER = token<Logger>(\"LOGGER\");\n * const [logTok, logReg] = singleton(LOGGER, () => new Logger());\n *\n * const container = createContainer().register(logTok, logReg);\n * ```\n */\nexport function createDSL(): LevainDSL {\n return {\n /** Creates a new unique typed token. */\n token: createToken,\n /** Registers a service as a singleton (one instance for the container's lifetime). */\n singleton: createDSLBuilder(singleton),\n /** Registers a service as scoped (one instance per scope). */\n scoped: createDSLBuilder(scoped),\n /** Registers a service as transient (new instance on every resolution). */\n transient: createDSLBuilder(transient),\n };\n}\n","/** Stable machine-readable error code for public DI errors. */\nexport type ErrorCode =\n | \"E_DEP_NOT_FOUND\"\n | \"E_CIRCULAR_DEP\"\n | \"E_ASYNC_IN_SYNC_RESOLVE\"\n | \"E_INVALID_LIFETIME_DEP\";\n\n/** Thrown when resolving a token that has no registration in the container or its parents. */\nexport class DependencyNotFoundError extends Error {\n readonly code: ErrorCode = \"E_DEP_NOT_FOUND\";\n readonly tokenDescription: string;\n readonly resolutionPath: string[];\n\n constructor(tokenDescription: string, resolutionPath: string[] = []) {\n const pathText =\n resolutionPath.length > 0\n ? `\\nResolution path: ${resolutionPath.join(\" -> \")}`\n : \"\";\n\n super(`No registration found for token: ${tokenDescription}${pathText}`);\n this.name = \"DependencyNotFoundError\";\n this.tokenDescription = tokenDescription;\n this.resolutionPath = resolutionPath;\n }\n}\n\n/** Thrown when a circular dependency is detected during resolution. */\nexport class CircularDependencyError extends Error {\n readonly code: ErrorCode = \"E_CIRCULAR_DEP\";\n readonly resolutionPath: string[];\n\n constructor(resolutionPath: string[]) {\n super(`Circular dependency detected: ${resolutionPath.join(\" -> \")}`);\n this.name = \"CircularDependencyError\";\n this.resolutionPath = resolutionPath;\n }\n}\n\n/**\n * Thrown when {@link Container.resolve} encounters an async registration.\n * Use {@link Container.resolveAsync} instead.\n */\nexport class AsyncFactoryInSyncResolveError extends Error {\n readonly code: ErrorCode = \"E_ASYNC_IN_SYNC_RESOLVE\";\n readonly tokenDescription: string;\n\n constructor(tokenDescription: string) {\n super(\n `Cannot synchronously resolve async registration: ${tokenDescription}. Use resolveAsync() instead.`,\n );\n this.name = \"AsyncFactoryInSyncResolveError\";\n this.tokenDescription = tokenDescription;\n }\n}\n\n/**\n * Thrown when a registration violates lifetime rules.\n * For example, a singleton depending on a scoped service.\n */\nexport class InvalidLifetimeDependencyError extends Error {\n readonly code: ErrorCode = \"E_INVALID_LIFETIME_DEP\";\n readonly consumer: string;\n readonly consumerLifetime: string;\n readonly dependency: string;\n readonly dependencyLifetime: string;\n readonly resolutionPath: string[];\n\n constructor(args: {\n consumer: string;\n consumerLifetime: string;\n dependency: string;\n dependencyLifetime: string;\n resolutionPath: string[];\n }) {\n const {\n consumer,\n consumerLifetime,\n dependency,\n dependencyLifetime,\n resolutionPath,\n } = args;\n\n const pathText =\n resolutionPath.length > 0\n ? `\\nResolution path: ${resolutionPath.join(\" -> \")}`\n : \"\";\n\n super(\n `Invalid lifetime dependency: ${consumerLifetime} \"${consumer}\" cannot depend on ${dependencyLifetime} \"${dependency}\"${pathText}`,\n );\n\n this.name = \"InvalidLifetimeDependencyError\";\n this.consumer = consumer;\n this.consumerLifetime = consumerLifetime;\n this.dependency = dependency;\n this.dependencyLifetime = dependencyLifetime;\n this.resolutionPath = resolutionPath;\n }\n}\n\n/**\n * Thrown when strict validation requires dependency metadata but a\n * registration was not declared via `withDeps`.\n */\nexport class MissingDependencyMetadataError extends Error {\n readonly tokenDescription: string;\n\n constructor(tokenDescription: string) {\n super(\n `Missing dependency metadata for token: ${tokenDescription}. ` +\n \"Use withDeps(...) so validate({ requireDepsMetadata: true }) can statically verify it.\",\n );\n this.name = \"MissingDependencyMetadataError\";\n this.tokenDescription = tokenDescription;\n }\n}\n","import {\n AsyncFactoryInSyncResolveError,\n CircularDependencyError,\n DependencyNotFoundError,\n InvalidLifetimeDependencyError,\n MissingDependencyMetadataError,\n} from \"./errors\";\nimport {\n type AsyncRegistration,\n type AnyRegistration,\n type AsyncResolver,\n isAsyncRegistration,\n type Lifetime,\n type Registration,\n type Resolver,\n} from \"./registration\";\nimport type {Token} from \"./token\";\n\ntype Key = symbol;\n\ninterface ResolutionFrame {\n token: Token<unknown>;\n lifetime: Lifetime;\n}\n\nexport interface ValidateOptions {\n requireDepsMetadata?: boolean;\n}\n\nexport interface InspectOptions {\n includeInherited?: boolean;\n}\n\nexport interface DisposeOptions {\n includeChildren?: boolean;\n}\n\nexport interface ContainerRegistrationInfo {\n tokenDescription: string;\n lifetime: Lifetime;\n async: boolean;\n deps: string[];\n source: \"self\" | \"inherited\";\n}\n\nexport interface ContainerInspection {\n hasParent: boolean;\n childScopeCount: number;\n cache: {\n singleton: number;\n scoped: number;\n };\n registrations: ContainerRegistrationInfo[];\n}\n\nfunction describeToken<T>(token: Token<T>): string {\n return token.description ?? token.key.toString();\n}\n\nfunction findInvalidLifetimeConsumer(\n stack: ResolutionFrame[],\n dependencyLifetime: Lifetime,\n): ResolutionFrame | undefined {\n if (dependencyLifetime === \"scoped\") {\n return stack.find((frame) => frame.lifetime === \"singleton\");\n }\n\n return undefined;\n}\n\n/**\n * Dependency injection container with support for hierarchical scoping,\n * lifetime management, and both sync and async resolution.\n */\nexport class Container implements Resolver, AsyncResolver {\n private readonly registry = new Map<Key, AnyRegistration<unknown>>();\n private readonly singletonCache = new Map<Key, unknown>();\n private readonly scopedCache = new Map<Key, unknown>();\n private readonly children = new Set<Container>();\n\n private constructor(private readonly parent?: Container) {\n }\n\n static createRoot(): Container {\n return new Container();\n }\n\n /** Registers a service factory for the given token. */\n register<T>(token: Token<T>, registration: Registration<T> | AsyncRegistration<T>): this {\n this.registry.set(token.key, registration as AnyRegistration<unknown>);\n return this;\n }\n\n /** Registers multiple [token, registration] entries at once. */\n registerMany(\n ...entries: ReadonlyArray<readonly [\n Token<unknown>,\n Registration<unknown> | AsyncRegistration<unknown>,\n ]>\n ): this {\n for (const [token, registration] of entries) {\n this.registry.set(token.key, registration as AnyRegistration<unknown>);\n }\n\n return this;\n }\n\n /** Creates a child scope that inherits registrations from this container. */\n createScope(): Container {\n const child = new Container(this);\n this.children.add(child);\n return child;\n }\n\n /** Returns a read-only snapshot of visible registrations and cache stats. */\n inspect(options: InspectOptions = {}): ContainerInspection {\n const includeInherited = options.includeInherited ?? true;\n const registrations = this.collectRegistrationsForInspection(includeInherited)\n .map(({key, registration, source}) => ({\n tokenDescription: this.describeKey(key),\n lifetime: registration.lifetime,\n async: isAsyncRegistration(registration),\n deps: registration.deps?.map((dep) => describeToken(dep)) ?? [],\n source,\n }))\n .sort((a, b) => a.tokenDescription.localeCompare(b.tokenDescription));\n\n return {\n hasParent: this.parent !== undefined,\n childScopeCount: this.children.size,\n cache: {\n singleton: this.singletonCache.size,\n scoped: this.scopedCache.size,\n },\n registrations,\n };\n }\n\n /**\n * Disposes resolved scoped/singleton instances by calling one of:\n * `Symbol.asyncDispose`, `Symbol.dispose`, `dispose()`, or `close()`.\n */\n async dispose(options: DisposeOptions = {}): Promise<void> {\n const includeChildren = options.includeChildren ?? true;\n const disposedValues = new Set<unknown>();\n const errors: unknown[] = [];\n\n if (includeChildren) {\n for (const child of this.children) {\n await child.dispose(options).catch((error: unknown) => {\n errors.push(error);\n });\n }\n }\n\n await this.disposeCacheValues(this.scopedCache, disposedValues, errors);\n await this.disposeCacheValues(this.singletonCache, disposedValues, errors);\n\n this.scopedCache.clear();\n this.singletonCache.clear();\n this.children.clear();\n\n if (errors.length > 0) {\n throw new AggregateError(errors, \"Container dispose failed\");\n }\n }\n\n /**\n * Synchronously resolves a service by its token.\n * @throws {DependencyNotFoundError} If the token is not registered.\n * @throws {CircularDependencyError} If a circular dependency is detected.\n * @throws {InvalidLifetimeDependencyError} If lifetime rules are violated.\n * @throws {AsyncFactoryInSyncResolveError} If the registration is async.\n */\n resolve = <T>(token: Token<T>): T => {\n return this.resolveWithStack(token, []);\n };\n\n private resolveWithStack<T>(token: Token<T>, stack: ResolutionFrame[]): T {\n const found = this.findRegistration(token.key);\n\n if (!found) {\n throw new DependencyNotFoundError(\n describeToken(token),\n stack.map((frame) => describeToken(frame.token)),\n );\n }\n\n const { registration, owner } = found;\n\n if (isAsyncRegistration(registration)) {\n throw new AsyncFactoryInSyncResolveError(describeToken(token));\n }\n\n this.checkCycle(token, stack);\n this.checkLifetime(token, registration, stack);\n\n const nextStack = [...stack, {\n token,\n lifetime: registration.lifetime,\n }];\n\n const resolver = this.createResolverContext(nextStack);\n\n if (registration.lifetime === \"singleton\") {\n if (owner.singletonCache.has(token.key)) {\n return owner.singletonCache.get(token.key) as T;\n }\n\n const instance = registration.factory(resolver);\n owner.singletonCache.set(token.key, instance);\n return instance as T;\n }\n\n if (registration.lifetime === \"scoped\") {\n if (this.scopedCache.has(token.key)) {\n return this.scopedCache.get(token.key) as T;\n }\n\n const instance = registration.factory(resolver);\n this.scopedCache.set(token.key, instance);\n return instance as T;\n }\n\n return registration.factory(resolver) as T;\n }\n\n /** Like {@link resolve}, but returns `undefined` instead of throwing {@link DependencyNotFoundError}. */\n tryResolve = <T>(token: Token<T>): T | undefined => {\n try {\n return this.resolve(token);\n } catch (error) {\n if (error instanceof DependencyNotFoundError) {\n return undefined;\n }\n\n throw error;\n }\n };\n\n /**\n * Asynchronously resolves a service by its token. Works with both sync\n * and async registrations. Async singletons and scoped services cache\n * the `Promise` to prevent double initialization on concurrent calls.\n */\n resolveAsync = async <T>(token: Token<T>): Promise<T> => {\n return await this.resolveAsyncWithStack(token, []);\n };\n\n private async resolveAsyncWithStack<T>(\n token: Token<T>,\n stack: ResolutionFrame[],\n ): Promise<T> {\n const found = this.findRegistration(token.key);\n\n if (!found) {\n throw new DependencyNotFoundError(\n describeToken(token),\n stack.map((frame) => describeToken(frame.token)),\n );\n }\n\n const { registration, owner } = found;\n\n this.checkCycle(token, stack);\n this.checkLifetime(token, registration, stack);\n\n const nextStack = [...stack, {\n token,\n lifetime: registration.lifetime,\n }];\n\n const resolver = this.createResolverContext(nextStack);\n\n if (registration.lifetime === \"singleton\") {\n if (owner.singletonCache.has(token.key)) {\n return await owner.singletonCache.get(token.key) as T;\n }\n\n if (isAsyncRegistration(registration)) {\n const promise = registration.factory(resolver).catch((err: unknown) => {\n owner.singletonCache.delete(token.key);\n throw err;\n });\n owner.singletonCache.set(token.key, promise);\n return await promise as T;\n }\n\n const instance = (registration as Registration<unknown>).factory(resolver);\n owner.singletonCache.set(token.key, instance);\n return instance as T;\n }\n\n if (registration.lifetime === \"scoped\") {\n if (this.scopedCache.has(token.key)) {\n return await this.scopedCache.get(token.key) as T;\n }\n\n if (isAsyncRegistration(registration)) {\n const promise = registration.factory(resolver).catch((err: unknown) => {\n this.scopedCache.delete(token.key);\n throw err;\n });\n this.scopedCache.set(token.key, promise);\n return await promise as T;\n }\n\n const instance = (registration as Registration<unknown>).factory(resolver);\n this.scopedCache.set(token.key, instance);\n return instance as T;\n }\n\n if (isAsyncRegistration(registration)) {\n return await registration.factory(resolver) as T;\n }\n\n return (registration as Registration<unknown>).factory(resolver) as T;\n }\n\n /** Like {@link resolveAsync}, but returns `undefined` instead of throwing {@link DependencyNotFoundError}. */\n tryResolveAsync = async <T>(token: Token<T>): Promise<T | undefined> => {\n try {\n return await this.resolveAsync(token);\n } catch (error) {\n if (error instanceof DependencyNotFoundError) {\n return undefined;\n }\n\n throw error;\n }\n };\n\n /**\n * Statically validates the dependency graph without resolving anything.\n * Checks registrations that declare dependencies via `withDeps` for:\n * missing dependencies, circular dependencies, lifetime violations,\n * and sync-depends-on-async errors. Validates child scopes recursively.\n */\n validate(options: ValidateOptions = {}): void {\n this.validateContainer(options);\n\n for (const child of this.children) {\n child.validate(options);\n }\n }\n\n private validateContainer(options: ValidateOptions): void {\n if (options.requireDepsMetadata) {\n for (const [key, registration] of this.registry) {\n if (!registration.deps) {\n throw new MissingDependencyMetadataError(this.describeKey(key));\n }\n }\n }\n\n for (const [key, registration] of this.registry) {\n if (!registration.deps) continue;\n\n const token = this.describeKey(key);\n\n for (const dep of registration.deps) {\n const found = this.findRegistration(dep.key);\n\n if (!found) {\n throw new DependencyNotFoundError(\n describeToken(dep),\n [token],\n );\n }\n\n if (!isAsyncRegistration(registration) && isAsyncRegistration(found.registration)) {\n throw new AsyncFactoryInSyncResolveError(describeToken(dep));\n }\n }\n }\n\n this.detectStaticCycles();\n this.checkStaticLifetimeRules();\n }\n\n private checkCycle<T>(token: Token<T>, stack: ResolutionFrame[]): void {\n const cycleStartIndex = stack.findIndex(\n (frame) => frame.token.key === token.key,\n );\n\n if (cycleStartIndex >= 0) {\n const cyclePath = [\n ...stack\n .slice(cycleStartIndex)\n .map((frame) => describeToken(frame.token)),\n describeToken(token),\n ];\n\n throw new CircularDependencyError(cyclePath);\n }\n }\n\n private checkLifetime<T>(\n token: Token<T>,\n registration: AnyRegistration<unknown>,\n stack: ResolutionFrame[],\n ): void {\n const invalidConsumer = findInvalidLifetimeConsumer(\n stack,\n registration.lifetime,\n );\n\n if (invalidConsumer) {\n throw new InvalidLifetimeDependencyError({\n consumer: describeToken(invalidConsumer.token),\n consumerLifetime: invalidConsumer.lifetime,\n dependency: describeToken(token),\n dependencyLifetime: registration.lifetime,\n resolutionPath: [\n ...stack.map((frame) => describeToken(frame.token)),\n describeToken(token),\n ],\n });\n }\n }\n\n private detectStaticCycles(): void {\n const visited = new Set<Key>();\n const inStack = new Set<Key>();\n const path: string[] = [];\n\n const visit = (key: Key): void => {\n if (inStack.has(key)) {\n const description = this.describeKey(key);\n const cycleStart = path.indexOf(description);\n const cyclePath = [...path.slice(cycleStart), description];\n throw new CircularDependencyError(cyclePath);\n }\n\n if (visited.has(key)) return;\n\n const registration = this.findRegistration(key)?.registration;\n if (!registration?.deps) return;\n\n visited.add(key);\n inStack.add(key);\n path.push(this.describeKey(key));\n\n for (const dep of registration.deps) {\n visit(dep.key);\n }\n\n path.pop();\n inStack.delete(key);\n };\n\n for (const [key] of this.registry) {\n visit(key);\n }\n }\n\n private checkStaticLifetimeRules(): void {\n const visit = (\n key: Key,\n ancestors: ResolutionFrame[],\n ): void => {\n const found = this.findRegistration(key);\n if (!found) return;\n\n const { registration } = found;\n\n const invalidConsumer = findInvalidLifetimeConsumer(ancestors, registration.lifetime);\n\n if (invalidConsumer) {\n throw new InvalidLifetimeDependencyError({\n consumer: describeToken(invalidConsumer.token),\n consumerLifetime: invalidConsumer.lifetime,\n dependency: this.describeKey(key),\n dependencyLifetime: registration.lifetime,\n resolutionPath: [\n ...ancestors.map((f) => describeToken(f.token)),\n this.describeKey(key),\n ],\n });\n }\n\n if (!registration.deps) return;\n\n const token: Token<unknown> = { key, description: this.describeKey(key) };\n const frame: ResolutionFrame = { token, lifetime: registration.lifetime };\n\n for (const dep of registration.deps) {\n visit(dep.key, [...ancestors, frame]);\n }\n };\n\n for (const [key, registration] of this.registry) {\n if (!registration.deps) continue;\n\n const token: Token<unknown> = { key, description: this.describeKey(key) };\n const frame: ResolutionFrame = { token, lifetime: registration.lifetime };\n\n for (const dep of registration.deps) {\n visit(dep.key, [frame]);\n }\n }\n }\n\n private describeKey(key: Key): string {\n return key.description ?? key.toString();\n }\n\n private collectRegistrationsForInspection(\n includeInherited: boolean,\n ): Array<{\n key: Key;\n registration: AnyRegistration<unknown>;\n source: \"self\" | \"inherited\";\n }> {\n const visible = new Map<Key, {\n registration: AnyRegistration<unknown>;\n source: \"self\" | \"inherited\";\n }>();\n\n for (const [key, registration] of this.registry) {\n visible.set(key, {registration, source: \"self\"});\n }\n\n if (includeInherited) {\n let cursor = this.parent;\n while (cursor) {\n for (const [key, registration] of cursor.registry) {\n if (!visible.has(key)) {\n visible.set(key, {registration, source: \"inherited\"});\n }\n }\n cursor = cursor.parent;\n }\n }\n\n return [...visible.entries()].map(([key, value]) => ({\n key,\n registration: value.registration,\n source: value.source,\n }));\n }\n\n private async disposeCacheValues(\n cache: Map<Key, unknown>,\n disposedValues: Set<unknown>,\n errors: unknown[],\n ): Promise<void> {\n for (const value of cache.values()) {\n try {\n const resolved = await value;\n await this.callDisposer(resolved, disposedValues);\n } catch (error) {\n errors.push(error);\n }\n }\n }\n\n private async callDisposer(\n value: unknown,\n disposedValues: Set<unknown>,\n ): Promise<void> {\n if (value === null || value === undefined) return;\n if (typeof value !== \"object\" && typeof value !== \"function\") return;\n if (disposedValues.has(value)) return;\n\n disposedValues.add(value);\n\n const asyncDisposeSymbol = Symbol.asyncDispose as symbol | undefined;\n const syncDisposeSymbol = Symbol.dispose as symbol | undefined;\n const candidate = value as {\n [k: symbol]: (() => Promise<void> | void) | undefined;\n dispose?: () => Promise<void> | void;\n close?: () => Promise<void> | void;\n };\n\n if (asyncDisposeSymbol && typeof candidate[asyncDisposeSymbol] === \"function\") {\n await candidate[asyncDisposeSymbol]?.();\n return;\n }\n\n if (syncDisposeSymbol && typeof candidate[syncDisposeSymbol] === \"function\") {\n candidate[syncDisposeSymbol]?.();\n return;\n }\n\n if (typeof candidate.dispose === \"function\") {\n await candidate.dispose();\n return;\n }\n\n if (typeof candidate.close === \"function\") {\n await candidate.close();\n }\n }\n\n private findRegistration(\n key: Key,\n ): { registration: AnyRegistration<unknown>; owner: Container } | undefined {\n const registration = this.registry.get(key);\n\n if (registration) {\n return { registration, owner: this };\n }\n\n return this.parent?.findRegistration(key);\n }\n\n private createResolverContext(\n stack: ResolutionFrame[],\n ): Resolver & AsyncResolver {\n return {\n resolve: <T>(token: Token<T>): T => this.resolveWithStack(token, stack),\n tryResolve: <T>(token: Token<T>): T | undefined => {\n try {\n return this.resolveWithStack(token, stack);\n } catch (error) {\n if (error instanceof DependencyNotFoundError) {\n return undefined;\n }\n\n throw error;\n }\n },\n resolveAsync: async <T>(token: Token<T>): Promise<T> => {\n return await this.resolveAsyncWithStack(token, stack);\n },\n tryResolveAsync: async <T>(token: Token<T>): Promise<T | undefined> => {\n try {\n return await this.resolveAsyncWithStack(token, stack);\n } catch (error) {\n if (error instanceof DependencyNotFoundError) {\n return undefined;\n }\n\n throw error;\n }\n },\n };\n }\n}\n\n/** Creates a new root {@link Container}. */\nexport function createContainer(): Container {\n return Container.createRoot();\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@shinigoji/levain-core",
3
+ "version": "1.0.0-rc.0",
4
+ "description": "Type-safe dependency injection for TypeScript with explicit lifetimes, scopes, and async resolution.",
5
+ "license": "MIT",
6
+ "private": false,
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "module": "./dist/index.js",
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "keywords": [
23
+ "dependency-injection",
24
+ "di",
25
+ "typescript",
26
+ "ioc",
27
+ "container"
28
+ ],
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "scripts": {
33
+ "build": "tsup",
34
+ "docs:api": "bun run build && typedoc --options typedoc.json",
35
+ "prepack": "bun run build",
36
+ "dev": "tsup --watch",
37
+ "test": "bun test",
38
+ "typecheck": "tsc -p tsconfig.json --noEmit",
39
+ "release:check": "./scripts/release-check.sh",
40
+ "clean": "rm -rf dist"
41
+ },
42
+ "devDependencies": {
43
+ "@types/bun": "^1.3.11",
44
+ "tsup": "^8.5.1",
45
+ "typedoc": "^0.28.18",
46
+ "typescript": "^6.0.2"
47
+ }
48
+ }