inwire 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,387 @@
1
+ /**
2
+ * A factory function that receives the container and returns an instance.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * const factory: Factory<MyService> = (c) => new MyService(c.db);
7
+ * ```
8
+ */
9
+ type Factory<T = any> = (container: any) => T;
10
+ /**
11
+ * An object of factory functions — the definition of a container.
12
+ * Each key maps to a factory that produces the dependency.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const deps: DepsDefinition = {
17
+ * logger: () => new LoggerService(),
18
+ * db: () => new Database(process.env.DB_URL!),
19
+ * userRepo: (c) => new PgUserRepo(c.db),
20
+ * };
21
+ * ```
22
+ */
23
+ type DepsDefinition = Record<string, Factory>;
24
+ /**
25
+ * Extracts the resolved types from a deps definition.
26
+ * Maps each key to the return type of its factory function.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * type Resolved = ResolvedDeps<{ logger: () => LoggerService }>;
31
+ * // { logger: LoggerService }
32
+ * ```
33
+ */
34
+ type ResolvedDeps<T extends DepsDefinition> = {
35
+ readonly [K in keyof T]: ReturnType<T[K]>;
36
+ };
37
+ /**
38
+ * Options for creating a scoped container.
39
+ */
40
+ interface ScopeOptions {
41
+ /** Optional name for the scope, useful for debugging and introspection. */
42
+ name?: string;
43
+ }
44
+ /**
45
+ * Full container type exposed to the user.
46
+ * Combines resolved dependencies with container methods.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const container: Container<{ logger: LoggerService }> = createContainer({
51
+ * logger: () => new LoggerService(),
52
+ * });
53
+ * container.logger; // LoggerService
54
+ * container.inspect(); // ContainerGraph
55
+ * ```
56
+ */
57
+ type Container<T extends Record<string, any> = Record<string, any>> = T & IContainer<T>;
58
+ /**
59
+ * Container methods interface. Defines the API available on every container.
60
+ */
61
+ interface IContainer<T extends Record<string, any> = Record<string, any>> {
62
+ /**
63
+ * Creates a child container with additional dependencies.
64
+ * Child inherits all parent singletons and can add/override deps.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const request = app.scope({
69
+ * requestId: () => crypto.randomUUID(),
70
+ * currentUser: () => extractUser(req),
71
+ * });
72
+ * request.requestId; // scoped singleton
73
+ * request.logger; // inherited from parent
74
+ * ```
75
+ */
76
+ scope<E extends DepsDefinition>(extra: E, options?: ScopeOptions): Container<T & ResolvedDeps<E>>;
77
+ /**
78
+ * Returns a new container with additional dependencies.
79
+ * Existing singletons are shared. The original container is not modified.
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const appWithAuth = app.extend(authDeps);
84
+ * ```
85
+ */
86
+ extend<E extends DepsDefinition>(extra: E): Container<T & ResolvedDeps<E>>;
87
+ /**
88
+ * Pre-resolves dependencies (warm-up).
89
+ * Call with specific keys to resolve only those, or without arguments to resolve all.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * await container.preload('db', 'cache'); // specific deps
94
+ * await container.preload(); // all deps
95
+ * ```
96
+ */
97
+ preload(...keys: (keyof T)[]): Promise<void>;
98
+ /**
99
+ * Returns the full dependency graph as a serializable JSON object.
100
+ * Useful for AI analysis of the architecture.
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * container.inspect();
105
+ * // { providers: { logger: { key: 'logger', resolved: true, deps: [], scope: 'singleton' } } }
106
+ * ```
107
+ */
108
+ inspect(): ContainerGraph;
109
+ /**
110
+ * Returns detailed information about a specific provider.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * container.describe('userService');
115
+ * // { key: 'userService', resolved: true, deps: ['userRepo', 'logger'], scope: 'singleton' }
116
+ * ```
117
+ */
118
+ describe(key: keyof T): ProviderInfo;
119
+ /**
120
+ * Returns container health status and warnings.
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * container.health();
125
+ * // { totalProviders: 12, resolved: ['db', 'logger'], unresolved: ['cache'], warnings: [] }
126
+ * ```
127
+ */
128
+ health(): ContainerHealth;
129
+ /**
130
+ * Invalidates cached singletons, forcing re-creation on next access.
131
+ * Does not affect parent scopes.
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * container.reset('db'); // reset one
136
+ * container.reset('db', 'cache'); // reset multiple
137
+ * ```
138
+ */
139
+ reset(...keys: (keyof T)[]): void;
140
+ /**
141
+ * Disposes the container. Calls `onDestroy()` on all resolved instances
142
+ * that implement it, in reverse resolution order.
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * await container.dispose();
147
+ * ```
148
+ */
149
+ dispose(): Promise<void>;
150
+ }
151
+ /**
152
+ * Full dependency graph of the container.
153
+ */
154
+ interface ContainerGraph {
155
+ name?: string;
156
+ providers: Record<string, ProviderInfo>;
157
+ }
158
+ /**
159
+ * Detailed information about a single provider/dependency.
160
+ */
161
+ interface ProviderInfo {
162
+ key: string;
163
+ resolved: boolean;
164
+ deps: string[];
165
+ scope: 'singleton' | 'transient';
166
+ }
167
+ /**
168
+ * Container health status with warnings.
169
+ */
170
+ interface ContainerHealth {
171
+ totalProviders: number;
172
+ resolved: string[];
173
+ unresolved: string[];
174
+ warnings: ContainerWarning[];
175
+ }
176
+ /**
177
+ * A warning detected by the container's runtime analysis.
178
+ */
179
+ interface ContainerWarning {
180
+ type: 'scope_mismatch' | 'duplicate_key';
181
+ message: string;
182
+ details: Record<string, unknown>;
183
+ }
184
+
185
+ /**
186
+ * Base class for all container errors.
187
+ * Every error includes a human-readable `hint` and structured `details`
188
+ * so that AI tools and developers can auto-correct issues.
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * try { container.userService; }
193
+ * catch (e) {
194
+ * if (e instanceof ContainerError) {
195
+ * console.log(e.hint); // actionable fix
196
+ * console.log(e.details); // structured context
197
+ * }
198
+ * }
199
+ * ```
200
+ */
201
+ declare abstract class ContainerError extends Error {
202
+ abstract readonly hint: string;
203
+ abstract readonly details: Record<string, unknown>;
204
+ constructor(message: string);
205
+ }
206
+ /**
207
+ * Thrown when a non-function value is passed in the deps definition.
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * createContainer({ apiKey: 'sk-123' });
212
+ * // ContainerConfigError: 'apiKey' must be a factory function, got string.
213
+ * // hint: "Wrap it: apiKey: () => 'sk-123'"
214
+ * ```
215
+ */
216
+ declare class ContainerConfigError extends ContainerError {
217
+ readonly hint: string;
218
+ readonly details: Record<string, unknown>;
219
+ constructor(key: string, actualType: string);
220
+ }
221
+ /**
222
+ * Thrown when a reserved container method name is used as a dependency key.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * createContainer({ inspect: () => 'foo' });
227
+ * // ReservedKeyError: 'inspect' is a reserved container method.
228
+ * // hint: "Rename this dependency, e.g. 'inspectService' or 'dataInspector'."
229
+ * ```
230
+ */
231
+ declare class ReservedKeyError extends ContainerError {
232
+ readonly hint: string;
233
+ readonly details: Record<string, unknown>;
234
+ constructor(key: string, reserved: readonly string[]);
235
+ }
236
+ /**
237
+ * Thrown when a dependency cannot be found during resolution.
238
+ * Includes fuzzy suggestion if a similar key exists.
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * container.userService;
243
+ * // ProviderNotFoundError: Cannot resolve 'userService': dependency 'userRepo' not found.
244
+ * // hint: "Did you mean 'userRepository'?"
245
+ * ```
246
+ */
247
+ declare class ProviderNotFoundError extends ContainerError {
248
+ readonly hint: string;
249
+ readonly details: Record<string, unknown>;
250
+ constructor(key: string, chain: string[], registered: string[], suggestion?: string);
251
+ }
252
+ /**
253
+ * Thrown when a circular dependency is detected.
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * // CircularDependencyError: Circular dependency detected while resolving 'authService'.
258
+ * // Cycle: authService -> userService -> authService
259
+ * ```
260
+ */
261
+ declare class CircularDependencyError extends ContainerError {
262
+ readonly hint: string;
263
+ readonly details: Record<string, unknown>;
264
+ constructor(key: string, chain: string[]);
265
+ }
266
+ /**
267
+ * Thrown when a factory function returns `undefined`.
268
+ *
269
+ * @example
270
+ * ```typescript
271
+ * container.db;
272
+ * // UndefinedReturnError: Factory 'db' returned undefined.
273
+ * // hint: "Did you forget a return statement?"
274
+ * ```
275
+ */
276
+ declare class UndefinedReturnError extends ContainerError {
277
+ readonly hint: string;
278
+ readonly details: Record<string, unknown>;
279
+ constructor(key: string, chain: string[]);
280
+ }
281
+ /**
282
+ * Thrown when a factory function throws an error during resolution.
283
+ * Wraps the original error with resolution context.
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * container.db;
288
+ * // FactoryError: Factory 'db' threw an error: "Connection refused"
289
+ * ```
290
+ */
291
+ declare class FactoryError extends ContainerError {
292
+ readonly hint: string;
293
+ readonly details: Record<string, unknown>;
294
+ readonly originalError: unknown;
295
+ constructor(key: string, chain: string[], originalError: unknown);
296
+ }
297
+ /**
298
+ * Warning emitted when a singleton depends on a transient dependency.
299
+ * The transient value gets frozen inside the singleton — almost always a bug.
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * // ScopeMismatchWarning: Singleton 'userService' depends on transient 'requestId'.
304
+ * ```
305
+ */
306
+ declare class ScopeMismatchWarning {
307
+ readonly type: "scope_mismatch";
308
+ readonly message: string;
309
+ readonly hint: string;
310
+ readonly details: Record<string, unknown>;
311
+ constructor(singletonKey: string, transientKey: string);
312
+ }
313
+
314
+ /**
315
+ * Creates a dependency injection container from an object of factory functions.
316
+ * Each factory receives the container and returns an instance.
317
+ * Dependencies are resolved lazily and cached as singletons by default.
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * const container = createContainer({
322
+ * logger: () => new LoggerService(),
323
+ * db: () => new Database(process.env.DB_URL!),
324
+ * userRepo: (c): UserRepository => new PgUserRepo(c.db),
325
+ * userService: (c) => new UserService(c.userRepo, c.logger),
326
+ * });
327
+ *
328
+ * container.userService; // type: UserService — lazy, singleton, fully resolved
329
+ * ```
330
+ */
331
+ declare function createContainer<T extends DepsDefinition>(defs: T): Container<ResolvedDeps<T>>;
332
+
333
+ /**
334
+ * Wraps a factory function to produce a new instance on every access,
335
+ * instead of the default singleton behavior.
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * import { createContainer, transient } from 'inwire';
340
+ *
341
+ * const container = createContainer({
342
+ * logger: () => new LoggerService(), // singleton (default)
343
+ * requestId: transient(() => crypto.randomUUID()), // new instance every access
344
+ * });
345
+ *
346
+ * container.requestId; // 'abc-123'
347
+ * container.requestId; // 'def-456' (different!)
348
+ * ```
349
+ */
350
+ declare function transient<T>(factory: Factory<T>): Factory<T>;
351
+
352
+ /**
353
+ * Implement this interface (or just add an `onInit` method) to run
354
+ * initialization logic when the dependency is first resolved.
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * class Database implements OnInit {
359
+ * async onInit() { await this.connect(); }
360
+ * }
361
+ * ```
362
+ */
363
+ interface OnInit {
364
+ onInit(): void | Promise<void>;
365
+ }
366
+ /**
367
+ * Implement this interface (or just add an `onDestroy` method) to run
368
+ * cleanup logic when `container.dispose()` is called.
369
+ *
370
+ * @example
371
+ * ```typescript
372
+ * class Database implements OnDestroy {
373
+ * async onDestroy() { await this.disconnect(); }
374
+ * }
375
+ * ```
376
+ */
377
+ interface OnDestroy {
378
+ onDestroy(): void | Promise<void>;
379
+ }
380
+
381
+ /**
382
+ * Detects duplicate keys across multiple modules (spread objects).
383
+ * Returns an array of keys that appear in more than one source.
384
+ */
385
+ declare function detectDuplicateKeys(...modules: Record<string, unknown>[]): string[];
386
+
387
+ export { CircularDependencyError, type Container, ContainerConfigError, ContainerError, type ContainerGraph, type ContainerHealth, type ContainerWarning, type DepsDefinition, type Factory, FactoryError, type IContainer, type OnDestroy, type OnInit, type ProviderInfo, ProviderNotFoundError, ReservedKeyError, type ResolvedDeps, ScopeMismatchWarning, type ScopeOptions, UndefinedReturnError, createContainer, detectDuplicateKeys, transient };