@veloxts/core 0.3.3 → 0.3.4

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,262 @@
1
+ /**
2
+ * Lifecycle scope management for dependency injection
3
+ *
4
+ * Defines how service instances are created and shared:
5
+ * - Singleton: One instance for the entire application
6
+ * - Transient: New instance on every resolution
7
+ * - Request: One instance per HTTP request
8
+ *
9
+ * @module di/scope
10
+ */
11
+ import { VeloxError } from '../errors.js';
12
+ // ============================================================================
13
+ // Scope Enum
14
+ // ============================================================================
15
+ /**
16
+ * Service lifecycle scope
17
+ *
18
+ * Determines how instances are created and shared across the application.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Singleton - shared across all requests
23
+ * container.register({
24
+ * provide: ConfigService,
25
+ * useClass: ConfigService,
26
+ * scope: Scope.SINGLETON
27
+ * });
28
+ *
29
+ * // Transient - new instance every time
30
+ * container.register({
31
+ * provide: RequestIdGenerator,
32
+ * useClass: RequestIdGenerator,
33
+ * scope: Scope.TRANSIENT
34
+ * });
35
+ *
36
+ * // Request - shared within a single HTTP request
37
+ * container.register({
38
+ * provide: UserContext,
39
+ * useClass: UserContext,
40
+ * scope: Scope.REQUEST
41
+ * });
42
+ * ```
43
+ */
44
+ export var Scope;
45
+ (function (Scope) {
46
+ /**
47
+ * Singleton scope
48
+ *
49
+ * A single instance is created and shared across the entire application.
50
+ * The instance is created on first resolution and reused for all subsequent
51
+ * resolutions.
52
+ *
53
+ * Best for:
54
+ * - Configuration services
55
+ * - Database connection pools
56
+ * - Cache clients
57
+ * - Stateless utility services
58
+ */
59
+ Scope["SINGLETON"] = "singleton";
60
+ /**
61
+ * Transient scope
62
+ *
63
+ * A new instance is created every time the service is resolved.
64
+ * No caching or sharing occurs.
65
+ *
66
+ * Best for:
67
+ * - Services that maintain mutable state
68
+ * - Factories that produce unique objects
69
+ * - Services where isolation is critical
70
+ */
71
+ Scope["TRANSIENT"] = "transient";
72
+ /**
73
+ * Request scope
74
+ *
75
+ * A single instance is created and shared within the lifetime of an HTTP request.
76
+ * Different requests get different instances.
77
+ *
78
+ * Best for:
79
+ * - User context/session data
80
+ * - Request-specific caching
81
+ * - Transaction management
82
+ * - Audit logging with request context
83
+ *
84
+ * Note: Resolving request-scoped services outside of a request context
85
+ * will throw an error.
86
+ */
87
+ Scope["REQUEST"] = "request";
88
+ })(Scope || (Scope = {}));
89
+ // ============================================================================
90
+ // Scope Manager
91
+ // ============================================================================
92
+ /**
93
+ * Request-scoped instance store key
94
+ * Using a symbol prevents collision with user-defined properties
95
+ */
96
+ const REQUEST_SCOPE_KEY = Symbol('velox:di:request-scope');
97
+ /**
98
+ * Manages service instance lifecycles
99
+ *
100
+ * Handles creation, caching, and cleanup of service instances
101
+ * based on their configured scope.
102
+ *
103
+ * @internal
104
+ */
105
+ export class ScopeManager {
106
+ /**
107
+ * Singleton instance cache
108
+ * Maps tokens to their singleton instances
109
+ */
110
+ singletonCache = new Map();
111
+ /**
112
+ * Whether request scope hooks have been set up
113
+ */
114
+ requestScopeInitialized = false;
115
+ /**
116
+ * Attaches the scope manager to a Fastify server
117
+ *
118
+ * This sets up the request lifecycle hooks needed for request-scoped services.
119
+ * Must be called before resolving request-scoped services.
120
+ *
121
+ * @param server - Fastify server instance
122
+ */
123
+ attachToFastify(server) {
124
+ if (this.requestScopeInitialized) {
125
+ return;
126
+ }
127
+ // Initialize request scope cache on each request
128
+ server.addHook('onRequest', async (request) => {
129
+ request[REQUEST_SCOPE_KEY] = new Map();
130
+ });
131
+ // Clean up request scope cache after response
132
+ server.addHook('onResponse', async (request) => {
133
+ const cache = request[REQUEST_SCOPE_KEY];
134
+ if (cache) {
135
+ cache.clear();
136
+ delete request[REQUEST_SCOPE_KEY];
137
+ }
138
+ });
139
+ this.requestScopeInitialized = true;
140
+ }
141
+ /**
142
+ * Gets a singleton instance from cache
143
+ *
144
+ * @param token - The service token
145
+ * @returns The cached instance or undefined
146
+ */
147
+ getSingleton(token) {
148
+ return this.singletonCache.get(token);
149
+ }
150
+ /**
151
+ * Stores a singleton instance in cache
152
+ *
153
+ * @param token - The service token
154
+ * @param instance - The instance to cache
155
+ */
156
+ setSingleton(token, instance) {
157
+ this.singletonCache.set(token, instance);
158
+ }
159
+ /**
160
+ * Checks if a singleton instance exists
161
+ *
162
+ * @param token - The service token
163
+ * @returns true if a singleton instance is cached
164
+ */
165
+ hasSingleton(token) {
166
+ return this.singletonCache.has(token);
167
+ }
168
+ /**
169
+ * Gets a request-scoped instance from the current request's cache
170
+ *
171
+ * @param token - The service token
172
+ * @param request - The current Fastify request
173
+ * @returns The cached instance or undefined
174
+ */
175
+ getRequestScoped(token, request) {
176
+ const cache = request[REQUEST_SCOPE_KEY];
177
+ if (!cache) {
178
+ return undefined;
179
+ }
180
+ return cache.get(token);
181
+ }
182
+ /**
183
+ * Stores a request-scoped instance in the current request's cache
184
+ *
185
+ * @param token - The service token
186
+ * @param instance - The instance to cache
187
+ * @param request - The current Fastify request
188
+ */
189
+ setRequestScoped(token, instance, request) {
190
+ const cache = request[REQUEST_SCOPE_KEY];
191
+ if (!cache) {
192
+ throw new VeloxError('Request scope cache not initialized. Ensure ScopeManager is attached to Fastify.', 500, 'REQUEST_SCOPE_UNAVAILABLE');
193
+ }
194
+ cache.set(token, instance);
195
+ }
196
+ /**
197
+ * Checks if a request-scoped instance exists
198
+ *
199
+ * @param token - The service token
200
+ * @param request - The current Fastify request
201
+ * @returns true if a request-scoped instance is cached
202
+ */
203
+ hasRequestScoped(token, request) {
204
+ const cache = request[REQUEST_SCOPE_KEY];
205
+ return cache?.has(token) ?? false;
206
+ }
207
+ /**
208
+ * Validates that request scope is available and returns the request
209
+ *
210
+ * @param request - The current request (may be undefined outside request context)
211
+ * @returns The validated FastifyRequest
212
+ * @throws {VeloxError} If request scope is not available
213
+ */
214
+ ensureRequestScope(request) {
215
+ if (!request) {
216
+ throw new VeloxError('Cannot resolve request-scoped service outside of request context. ' +
217
+ 'Ensure you are resolving within a request handler or middleware.', 500, 'REQUEST_SCOPE_UNAVAILABLE');
218
+ }
219
+ if (!request[REQUEST_SCOPE_KEY]) {
220
+ throw new VeloxError('Request scope cache not initialized. Ensure ScopeManager is attached to Fastify.', 500, 'REQUEST_SCOPE_UNAVAILABLE');
221
+ }
222
+ return request;
223
+ }
224
+ /**
225
+ * Clears all singleton instances
226
+ *
227
+ * Useful for testing or application shutdown.
228
+ */
229
+ clearSingletons() {
230
+ this.singletonCache.clear();
231
+ }
232
+ /**
233
+ * Clears all cached instances and resets state
234
+ *
235
+ * @internal
236
+ */
237
+ reset() {
238
+ this.singletonCache.clear();
239
+ this.requestScopeInitialized = false;
240
+ }
241
+ }
242
+ // ============================================================================
243
+ // Scope Utilities
244
+ // ============================================================================
245
+ /**
246
+ * Validates a scope value
247
+ *
248
+ * @param scope - The scope to validate
249
+ * @returns true if the scope is valid
250
+ */
251
+ export function isValidScope(scope) {
252
+ return scope === Scope.SINGLETON || scope === Scope.TRANSIENT || scope === Scope.REQUEST;
253
+ }
254
+ /**
255
+ * Gets the default scope for a provider
256
+ *
257
+ * @returns The default scope (SINGLETON)
258
+ */
259
+ export function getDefaultScope() {
260
+ return Scope.SINGLETON;
261
+ }
262
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/di/scope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Service tokens for dependency injection
3
+ *
4
+ * Tokens are unique identifiers used to register and resolve services.
5
+ * VeloxTS supports three token types:
6
+ * - Class tokens: The class constructor itself
7
+ * - String tokens: String literals for named services
8
+ * - Symbol tokens: Unique symbols for collision-free tokens
9
+ *
10
+ * @module di/tokens
11
+ */
12
+ /**
13
+ * Abstract class token type
14
+ *
15
+ * Represents a class constructor that can be used as a service token.
16
+ * Supports both concrete classes and abstract classes.
17
+ *
18
+ * @template T - The type that the class constructs
19
+ */
20
+ export interface AbstractClass<T = unknown> {
21
+ prototype: T;
22
+ }
23
+ /**
24
+ * Concrete class constructor type
25
+ *
26
+ * Represents a class that can be instantiated with `new`.
27
+ * The constructor accepts any arguments and returns an instance of T.
28
+ *
29
+ * @template T - The type that the class constructs
30
+ */
31
+ export interface ClassConstructor<T = unknown> extends AbstractClass<T> {
32
+ new (...args: never[]): T;
33
+ }
34
+ /**
35
+ * Unique brand symbol for string tokens (compile-time only)
36
+ * @internal
37
+ */
38
+ declare const StringTokenBrand: unique symbol;
39
+ /**
40
+ * Unique brand symbol for symbol tokens (compile-time only)
41
+ * @internal
42
+ */
43
+ declare const SymbolTokenBrand: unique symbol;
44
+ /**
45
+ * String token type for named services
46
+ *
47
+ * Branded type to distinguish service tokens from regular strings at compile time.
48
+ * The brand is purely a compile-time construct for type safety.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const DATABASE = createStringToken<DatabaseClient>('DATABASE');
53
+ * container.register({ provide: DATABASE, useFactory: () => createDb() });
54
+ * ```
55
+ */
56
+ export type StringToken<T = unknown> = string & {
57
+ readonly [StringTokenBrand]: T;
58
+ };
59
+ /**
60
+ * Symbol token type for unique service identifiers
61
+ *
62
+ * Branded type that carries the service type information.
63
+ * The brand is purely a compile-time construct for type safety.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const LOGGER = createSymbolToken<Logger>('LOGGER');
68
+ * container.register({ provide: LOGGER, useClass: ConsoleLogger });
69
+ * ```
70
+ */
71
+ export type SymbolToken<T = unknown> = symbol & {
72
+ readonly [SymbolTokenBrand]: T;
73
+ };
74
+ /**
75
+ * Union of all valid injection token types
76
+ *
77
+ * A token can be:
78
+ * - A class constructor (for automatic injection)
79
+ * - A string token (for named services)
80
+ * - A symbol token (for unique identifiers)
81
+ *
82
+ * @template T - The type of service the token represents
83
+ */
84
+ export type InjectionToken<T = unknown> = ClassConstructor<T> | AbstractClass<T> | StringToken<T> | SymbolToken<T>;
85
+ /**
86
+ * Extract the type from an injection token
87
+ *
88
+ * @template T - The injection token type
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * type UserServiceType = TokenType<typeof UserService>; // UserService
93
+ * type DbType = TokenType<typeof DATABASE>; // DatabaseClient
94
+ * ```
95
+ */
96
+ export type TokenType<T> = T extends InjectionToken<infer U> ? U : never;
97
+ /**
98
+ * Creates a typed string token for service registration
99
+ *
100
+ * String tokens are useful when you want human-readable identifiers.
101
+ * The type parameter ensures type safety when resolving the service.
102
+ *
103
+ * @template T - The type of service this token represents
104
+ * @param name - The string identifier for this token
105
+ * @returns A typed string token
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * interface DatabaseClient {
110
+ * query(sql: string): Promise<unknown>;
111
+ * }
112
+ *
113
+ * const DATABASE = createStringToken<DatabaseClient>('DATABASE');
114
+ *
115
+ * // Registration
116
+ * container.register({
117
+ * provide: DATABASE,
118
+ * useFactory: () => createDatabaseClient()
119
+ * });
120
+ *
121
+ * // Resolution - type is inferred as DatabaseClient
122
+ * const db = container.resolve(DATABASE);
123
+ * await db.query('SELECT * FROM users');
124
+ * ```
125
+ */
126
+ export declare function createStringToken<T>(name: string): StringToken<T>;
127
+ /**
128
+ * Creates a typed symbol token for service registration
129
+ *
130
+ * Symbol tokens guarantee uniqueness across the application,
131
+ * preventing name collisions between different modules.
132
+ *
133
+ * @template T - The type of service this token represents
134
+ * @param description - Optional description for debugging
135
+ * @returns A typed symbol token
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * interface Logger {
140
+ * log(message: string): void;
141
+ * }
142
+ *
143
+ * const LOGGER = createSymbolToken<Logger>('Logger');
144
+ *
145
+ * // Registration
146
+ * container.register({
147
+ * provide: LOGGER,
148
+ * useClass: ConsoleLogger
149
+ * });
150
+ *
151
+ * // Resolution - type is inferred as Logger
152
+ * const logger = container.resolve(LOGGER);
153
+ * logger.log('Hello, world!');
154
+ * ```
155
+ */
156
+ export declare function createSymbolToken<T>(description?: string): SymbolToken<T>;
157
+ /**
158
+ * Creates a typed string token for service registration
159
+ *
160
+ * This is the preferred API for creating tokens. String tokens are
161
+ * useful when you want human-readable identifiers.
162
+ *
163
+ * @template T - The type of service this token represents
164
+ * @param name - The string identifier for this token
165
+ * @returns A typed string token
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const DATABASE = token<DatabaseClient>('DATABASE');
170
+ * const CONFIG = token<AppConfig>('CONFIG');
171
+ *
172
+ * container.register({ provide: DATABASE, useFactory: createDb });
173
+ * ```
174
+ */
175
+ export declare function token<T>(name: string): StringToken<T>;
176
+ export declare namespace token {
177
+ var symbol: <T>(description?: string) => SymbolToken<T>;
178
+ }
179
+ /**
180
+ * Gets a human-readable name for a token
181
+ *
182
+ * @param token - The token to get the name for
183
+ * @returns A string representation of the token
184
+ *
185
+ * @internal
186
+ */
187
+ export declare function getTokenName(token: InjectionToken): string;
188
+ /**
189
+ * Type guard for class constructor tokens
190
+ *
191
+ * @param token - The token to check
192
+ * @returns true if the token is a class constructor
193
+ */
194
+ export declare function isClassToken(token: InjectionToken): token is ClassConstructor;
195
+ /**
196
+ * Type guard for string tokens
197
+ *
198
+ * @param token - The token to check
199
+ * @returns true if the token is a string token
200
+ */
201
+ export declare function isStringToken(token: InjectionToken): token is StringToken;
202
+ /**
203
+ * Type guard for symbol tokens
204
+ *
205
+ * @param token - The token to check
206
+ * @returns true if the token is a symbol token
207
+ */
208
+ export declare function isSymbolToken(token: InjectionToken): token is SymbolToken;
209
+ /**
210
+ * Validates that a token is a valid injection token
211
+ *
212
+ * @param token - The value to validate
213
+ * @throws {VeloxError} If the token is not valid
214
+ *
215
+ * @internal
216
+ */
217
+ export declare function validateToken(token: unknown): asserts token is InjectionToken;
218
+ /**
219
+ * Extend the error code registry for DI-related errors
220
+ */
221
+ declare module '../errors.js' {
222
+ interface VeloxErrorCodeRegistry {
223
+ di: 'INVALID_INJECTION_TOKEN' | 'SERVICE_NOT_FOUND' | 'CIRCULAR_DEPENDENCY' | 'MISSING_INJECTABLE_DECORATOR' | 'INVALID_PROVIDER' | 'SCOPE_MISMATCH' | 'REQUEST_SCOPE_UNAVAILABLE';
224
+ }
225
+ }
226
+ export {};
227
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/di/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,SAAS,EAAE,CAAC,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC;IACrE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;CAC3B;AAED;;;GAGG;AACH,OAAO,CAAC,MAAM,gBAAgB,EAAE,OAAO,MAAM,CAAC;AAE9C;;;GAGG;AACH,OAAO,CAAC,MAAM,gBAAgB,EAAE,OAAO,MAAM,CAAC;AAE9C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,OAAO,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAEnF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,OAAO,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAEnF;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,IAClC,gBAAgB,CAAC,CAAC,CAAC,GACnB,aAAa,CAAC,CAAC,CAAC,GAChB,WAAW,CAAC,CAAC,CAAC,GACd,WAAW,CAAC,CAAC,CAAC,CAAC;AAEnB;;;;;;;;;;GAUG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAMzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAEjE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAEzE;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAErD;yBAFe,KAAK;iBAkBe,CAAC,gBAAgB,MAAM,KAAG,WAAW,CAAC,CAAC,CAAC;;AAQ5E;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAkB1D;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAE7E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,WAAW,CAEzE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,WAAW,CAGzE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,cAAc,CAkB7E;AAMD;;GAEG;AACH,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,sBAAsB;QAC9B,EAAE,EACE,yBAAyB,GACzB,mBAAmB,GACnB,qBAAqB,GACrB,8BAA8B,GAC9B,kBAAkB,GAClB,gBAAgB,GAChB,2BAA2B,CAAC;KACjC;CACF"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Service tokens for dependency injection
3
+ *
4
+ * Tokens are unique identifiers used to register and resolve services.
5
+ * VeloxTS supports three token types:
6
+ * - Class tokens: The class constructor itself
7
+ * - String tokens: String literals for named services
8
+ * - Symbol tokens: Unique symbols for collision-free tokens
9
+ *
10
+ * @module di/tokens
11
+ */
12
+ import { VeloxError } from '../errors.js';
13
+ // ============================================================================
14
+ // Token Creation Functions
15
+ // ============================================================================
16
+ /**
17
+ * Creates a typed string token for service registration
18
+ *
19
+ * String tokens are useful when you want human-readable identifiers.
20
+ * The type parameter ensures type safety when resolving the service.
21
+ *
22
+ * @template T - The type of service this token represents
23
+ * @param name - The string identifier for this token
24
+ * @returns A typed string token
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * interface DatabaseClient {
29
+ * query(sql: string): Promise<unknown>;
30
+ * }
31
+ *
32
+ * const DATABASE = createStringToken<DatabaseClient>('DATABASE');
33
+ *
34
+ * // Registration
35
+ * container.register({
36
+ * provide: DATABASE,
37
+ * useFactory: () => createDatabaseClient()
38
+ * });
39
+ *
40
+ * // Resolution - type is inferred as DatabaseClient
41
+ * const db = container.resolve(DATABASE);
42
+ * await db.query('SELECT * FROM users');
43
+ * ```
44
+ */
45
+ export function createStringToken(name) {
46
+ return name;
47
+ }
48
+ /**
49
+ * Creates a typed symbol token for service registration
50
+ *
51
+ * Symbol tokens guarantee uniqueness across the application,
52
+ * preventing name collisions between different modules.
53
+ *
54
+ * @template T - The type of service this token represents
55
+ * @param description - Optional description for debugging
56
+ * @returns A typed symbol token
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * interface Logger {
61
+ * log(message: string): void;
62
+ * }
63
+ *
64
+ * const LOGGER = createSymbolToken<Logger>('Logger');
65
+ *
66
+ * // Registration
67
+ * container.register({
68
+ * provide: LOGGER,
69
+ * useClass: ConsoleLogger
70
+ * });
71
+ *
72
+ * // Resolution - type is inferred as Logger
73
+ * const logger = container.resolve(LOGGER);
74
+ * logger.log('Hello, world!');
75
+ * ```
76
+ */
77
+ export function createSymbolToken(description) {
78
+ return Symbol(description);
79
+ }
80
+ // ============================================================================
81
+ // Succinct Token API
82
+ // ============================================================================
83
+ /**
84
+ * Creates a typed string token for service registration
85
+ *
86
+ * This is the preferred API for creating tokens. String tokens are
87
+ * useful when you want human-readable identifiers.
88
+ *
89
+ * @template T - The type of service this token represents
90
+ * @param name - The string identifier for this token
91
+ * @returns A typed string token
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const DATABASE = token<DatabaseClient>('DATABASE');
96
+ * const CONFIG = token<AppConfig>('CONFIG');
97
+ *
98
+ * container.register({ provide: DATABASE, useFactory: createDb });
99
+ * ```
100
+ */
101
+ export function token(name) {
102
+ return name;
103
+ }
104
+ /**
105
+ * Token creation namespace with factory methods
106
+ *
107
+ * Provides a succinct, grouped API for creating different token types.
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * // String token (most common)
112
+ * const DATABASE = token<DatabaseClient>('DATABASE');
113
+ *
114
+ * // Symbol token (guaranteed unique)
115
+ * const LOGGER = token.symbol<Logger>('LOGGER');
116
+ * ```
117
+ */
118
+ token.symbol = function symbolToken(description) {
119
+ return Symbol(description);
120
+ };
121
+ // ============================================================================
122
+ // Token Utilities
123
+ // ============================================================================
124
+ /**
125
+ * Gets a human-readable name for a token
126
+ *
127
+ * @param token - The token to get the name for
128
+ * @returns A string representation of the token
129
+ *
130
+ * @internal
131
+ */
132
+ export function getTokenName(token) {
133
+ // Cast to unknown for proper typeof narrowing without IDE warnings
134
+ // This is safe because InjectionToken runtime values are always string | symbol | function
135
+ const rawToken = token;
136
+ if (typeof rawToken === 'string') {
137
+ return rawToken;
138
+ }
139
+ if (typeof rawToken === 'symbol') {
140
+ return rawToken.description ?? 'Symbol()';
141
+ }
142
+ if (typeof rawToken === 'function') {
143
+ return rawToken.name || 'AnonymousClass';
144
+ }
145
+ return 'Unknown';
146
+ }
147
+ /**
148
+ * Type guard for class constructor tokens
149
+ *
150
+ * @param token - The token to check
151
+ * @returns true if the token is a class constructor
152
+ */
153
+ export function isClassToken(token) {
154
+ return typeof token === 'function';
155
+ }
156
+ /**
157
+ * Type guard for string tokens
158
+ *
159
+ * @param token - The token to check
160
+ * @returns true if the token is a string token
161
+ */
162
+ export function isStringToken(token) {
163
+ return typeof token === 'string';
164
+ }
165
+ /**
166
+ * Type guard for symbol tokens
167
+ *
168
+ * @param token - The token to check
169
+ * @returns true if the token is a symbol token
170
+ */
171
+ export function isSymbolToken(token) {
172
+ // Cast to unknown for proper typeof narrowing without IDE warnings
173
+ return typeof token === 'symbol';
174
+ }
175
+ /**
176
+ * Validates that a token is a valid injection token
177
+ *
178
+ * @param token - The value to validate
179
+ * @throws {VeloxError} If the token is not valid
180
+ *
181
+ * @internal
182
+ */
183
+ export function validateToken(token) {
184
+ if (token === null || token === undefined) {
185
+ throw new VeloxError('Injection token cannot be null or undefined', 500, 'INVALID_INJECTION_TOKEN');
186
+ }
187
+ const tokenType = typeof token;
188
+ if (tokenType !== 'string' && tokenType !== 'symbol' && tokenType !== 'function') {
189
+ throw new VeloxError(`Invalid injection token type: ${tokenType}. Expected string, symbol, or class constructor.`, 500, 'INVALID_INJECTION_TOKEN');
190
+ }
191
+ }
192
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/di/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAmG1C,+EAA+E;AAC/E,2BAA2B;AAC3B,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,iBAAiB,CAAI,IAAY;IAC/C,OAAO,IAAsB,CAAC;AAChC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,iBAAiB,CAAI,WAAoB;IACvD,OAAO,MAAM,CAAC,WAAW,CAAmB,CAAC;AAC/C,CAAC;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,KAAK,CAAI,IAAY;IACnC,OAAO,IAAsB,CAAC;AAChC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,KAAK,CAAC,MAAM,GAAG,SAAS,WAAW,CAAI,WAAoB;IACzD,OAAO,MAAM,CAAC,WAAW,CAAmB,CAAC;AAC/C,CAAC,CAAC;AAEF,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAqB;IAChD,mEAAmE;IACnE,2FAA2F;IAC3F,MAAM,QAAQ,GAAY,KAAK,CAAC;IAEhC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,WAAW,IAAI,UAAU,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,OAAO,QAAQ,CAAC,IAAI,IAAI,gBAAgB,CAAC;IAC3C,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAqB;IAChD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAqB;IACjD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAqB;IACjD,mEAAmE;IACnE,OAAO,OAAQ,KAAiB,KAAK,QAAQ,CAAC;AAChD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,MAAM,IAAI,UAAU,CAClB,6CAA6C,EAC7C,GAAG,EACH,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC;IAE/B,IAAI,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;QACjF,MAAM,IAAI,UAAU,CAClB,iCAAiC,SAAS,kDAAkD,EAC5F,GAAG,EACH,yBAAyB,CAC1B,CAAC;IACJ,CAAC;AACH,CAAC"}