opinionated-machine 6.9.0 → 6.10.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/README.md +265 -2
- package/dist/index.d.ts +1 -1
- package/dist/lib/AbstractModule.d.ts +27 -9
- package/dist/lib/AbstractModule.js.map +1 -1
- package/dist/lib/resolverFunctions.d.ts +34 -18
- package/dist/lib/resolverFunctions.js +2 -1
- package/dist/lib/resolverFunctions.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Very opinionated DI framework for fastify, built on top of awilix
|
|
|
4
4
|
## Table of Contents
|
|
5
5
|
|
|
6
6
|
- [Basic usage](#basic-usage)
|
|
7
|
+
- [Managing global public dependencies across modules](#managing-global-public-dependencies-across-modules)
|
|
8
|
+
- [Avoiding circular dependencies in typed cradle parameters](#avoiding-circular-dependencies-in-typed-cradle-parameters)
|
|
7
9
|
- [Defining controllers](#defining-controllers)
|
|
8
10
|
- [Putting it all together](#putting-it-all-together)
|
|
9
11
|
- [Resolver Functions](#resolver-functions)
|
|
@@ -124,13 +126,274 @@ export type ModuleDependencies = InferModuleDependencies<MyModule>
|
|
|
124
126
|
|
|
125
127
|
The `InferModuleDependencies` utility type extracts the dependency types from the resolvers returned by `resolveDependencies()`, so you don't need to maintain a separate type manually.
|
|
126
128
|
|
|
127
|
-
When a module is used as a secondary module, only resolvers marked as **public** (`asServiceClass`, `asUseCaseClass`, `asJobQueueClass`, `asEnqueuedJobQueueManagerFunction`) are exposed. Use `InferPublicModuleDependencies` to infer only the public dependencies:
|
|
129
|
+
When a module is used as a secondary module, only resolvers marked as **public** (`asServiceClass`, `asUseCaseClass`, `asJobQueueClass`, `asEnqueuedJobQueueManagerFunction`) are exposed. Use `InferPublicModuleDependencies` to infer only the public dependencies (private ones are omitted entirely):
|
|
128
130
|
|
|
129
131
|
```ts
|
|
130
|
-
// Inferred as { service: Service } —
|
|
132
|
+
// Inferred as { service: Service } — private resolvers are omitted
|
|
131
133
|
export type MyModulePublicDependencies = InferPublicModuleDependencies<MyModule>
|
|
132
134
|
```
|
|
133
135
|
|
|
136
|
+
### Managing global public dependencies across modules
|
|
137
|
+
|
|
138
|
+
When your application has multiple secondary modules, you need a single type that combines all their public dependencies. The library exports an empty `PublicDependencies` interface that each module can augment via TypeScript's [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation). Each module file adds its own public deps to this shared interface using `declare module`. The augmentations are **project-wide** — they apply everywhere as long as the augmenting file is part of your TypeScript compilation (included in `tsconfig.json`), with no explicit import chain required.
|
|
139
|
+
|
|
140
|
+
Start with a `CommonModule` that provides shared infrastructure dependencies (logger, config, etc.), then add domain modules that each augment the same interface independently.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
// CommonModule.ts — shared infrastructure
|
|
144
|
+
import { AbstractModule, type InferPublicModuleDependencies } from 'opinionated-machine'
|
|
145
|
+
|
|
146
|
+
export class CommonModule extends AbstractModule {
|
|
147
|
+
resolveDependencies(diOptions: DependencyInjectionOptions) {
|
|
148
|
+
return {
|
|
149
|
+
config: asSingletonFunction(() => loadConfig()), // private — omitted
|
|
150
|
+
logger: asServiceClass(Logger), // public
|
|
151
|
+
eventEmitter: asServiceClass(AppEventEmitter), // public
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
declare module 'opinionated-machine' {
|
|
157
|
+
interface PublicDependencies extends InferPublicModuleDependencies<CommonModule> {}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
// UsersModule.ts — no need to import CommonModule's type
|
|
163
|
+
import { AbstractModule, type InferPublicModuleDependencies } from 'opinionated-machine'
|
|
164
|
+
|
|
165
|
+
export class UsersModule extends AbstractModule {
|
|
166
|
+
resolveDependencies(diOptions: DependencyInjectionOptions) {
|
|
167
|
+
return {
|
|
168
|
+
userService: asServiceClass(UserService), // public
|
|
169
|
+
userRepository: asRepositoryClass(UserRepository), // private — omitted
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
declare module 'opinionated-machine' {
|
|
175
|
+
interface PublicDependencies extends InferPublicModuleDependencies<UsersModule> {}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
// BillingModule.ts — independent, no chain
|
|
181
|
+
import { AbstractModule, type InferPublicModuleDependencies } from 'opinionated-machine'
|
|
182
|
+
|
|
183
|
+
export class BillingModule extends AbstractModule {
|
|
184
|
+
resolveDependencies(diOptions: DependencyInjectionOptions) {
|
|
185
|
+
return {
|
|
186
|
+
billingService: asServiceClass(BillingService), // public
|
|
187
|
+
paymentGateway: asRepositoryClass(PaymentGateway), // private — omitted
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
declare module 'opinionated-machine' {
|
|
193
|
+
interface PublicDependencies extends InferPublicModuleDependencies<BillingModule> {}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Importing `PublicDependencies` from anywhere gives you the full accumulated type: `{ logger: Logger; eventEmitter: AppEventEmitter; userService: UserService; billingService: BillingService }`. Private dependencies (`config`, `userRepository`, `paymentGateway`) are omitted automatically. No explicit import chain between modules is needed — each module augments the interface independently.
|
|
198
|
+
|
|
199
|
+
#### Typing constructor dependencies within a module
|
|
200
|
+
|
|
201
|
+
Classes within a module can access both the module's own dependencies (including private ones like repositories) and all public dependencies from other modules. Combine `InferModuleDependencies` with `PublicDependencies` to get the full cradle type available at runtime:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
// UsersModule.ts
|
|
205
|
+
import {
|
|
206
|
+
AbstractModule,
|
|
207
|
+
type InferModuleDependencies,
|
|
208
|
+
type InferPublicModuleDependencies,
|
|
209
|
+
type PublicDependencies,
|
|
210
|
+
} from 'opinionated-machine'
|
|
211
|
+
|
|
212
|
+
// Module's own deps (public + private) merged with all public deps from other modules
|
|
213
|
+
type UsersModuleInjectables = InferModuleDependencies<UsersModule> & PublicDependencies
|
|
214
|
+
|
|
215
|
+
export class UserService {
|
|
216
|
+
private readonly repository: UserRepository
|
|
217
|
+
private readonly logger: Logger // from CommonModule's public deps
|
|
218
|
+
|
|
219
|
+
constructor(dependencies: UsersModuleInjectables) {
|
|
220
|
+
this.repository = dependencies.userRepository // own private dep — accessible
|
|
221
|
+
this.logger = dependencies.logger // public dep from another module — accessible
|
|
222
|
+
// dependencies.billingRepository // private dep from another module — type error
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
class UserRepository {}
|
|
227
|
+
|
|
228
|
+
export class UsersModule extends AbstractModule {
|
|
229
|
+
resolveDependencies(diOptions: DependencyInjectionOptions) {
|
|
230
|
+
return {
|
|
231
|
+
userService: asServiceClass(UserService),
|
|
232
|
+
userRepository: asRepositoryClass(UserRepository),
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
declare module 'opinionated-machine' {
|
|
238
|
+
interface PublicDependencies extends InferPublicModuleDependencies<UsersModule> {}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
This gives each class access to exactly what the DI container provides at runtime: the module's own registered dependencies plus all public dependencies from secondary modules. Private dependencies from other modules are excluded at the type level, matching the runtime behavior.
|
|
243
|
+
|
|
244
|
+
#### Constructing the combined dependency type for `DIContext`
|
|
245
|
+
|
|
246
|
+
Use `PublicDependencies` when building the full dependency type:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
import type { PublicDependencies } from 'opinionated-machine'
|
|
250
|
+
|
|
251
|
+
type Dependencies = InferModuleDependencies<PrimaryModule> & PublicDependencies
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Avoiding circular dependencies in typed cradle parameters
|
|
255
|
+
|
|
256
|
+
Because `InferModuleDependencies` is inferred from the module's own `resolveDependencies()` return type, classes and functions that reference it inside the same module could create a circular type dependency. The library handles this automatically for class-based resolvers. For function-based resolvers, use the indexed access pattern described below.
|
|
257
|
+
|
|
258
|
+
#### Class-based resolvers (recommended — works automatically)
|
|
259
|
+
|
|
260
|
+
All class-based resolver functions (`asSingletonClass`, `asServiceClass`, `asRepositoryClass`, etc.) use a `ClassValue<T>` type internally, which infers the instance type from the class's `prototype` property rather than its constructor signature. This means classes can freely reference `InferModuleDependencies` in their constructors without causing circular type dependencies:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
import { AbstractModule, type InferModuleDependencies, asServiceClass, asSingletonClass } from 'opinionated-machine'
|
|
264
|
+
|
|
265
|
+
export class MyService {
|
|
266
|
+
// Constructor references ModuleDependencies — no circular dependency!
|
|
267
|
+
constructor({ myHelper }: ModuleDependencies) {
|
|
268
|
+
// myHelper is fully typed as MyHelper
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export class MyHelper {
|
|
273
|
+
process() {}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export class MyModule extends AbstractModule {
|
|
277
|
+
resolveDependencies(diOptions: DependencyInjectionOptions) {
|
|
278
|
+
return {
|
|
279
|
+
myService: asServiceClass(MyService), // ClassValue<T> breaks the cycle
|
|
280
|
+
myHelper: asSingletonClass(MyHelper),
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export type ModuleDependencies = InferModuleDependencies<MyModule>
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Prefer class-based resolvers wherever possible** — they provide full type safety with no `any` fallback and no extra annotations needed.
|
|
289
|
+
|
|
290
|
+
#### Function-based resolvers (`asSingletonFunction`)
|
|
291
|
+
|
|
292
|
+
Function-based resolvers (`asSingletonFunction`) cannot use the `ClassValue<T>` trick because functions don't have a `prototype` property that separates return type from parameter types. Use **indexed access** on `InferModuleDependencies` to type individual dependencies without triggering a circular reference:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
// Inside resolveDependencies():
|
|
296
|
+
myHelper: asSingletonClass(MyHelper),
|
|
297
|
+
myService: asServiceClass(MyService),
|
|
298
|
+
|
|
299
|
+
myFactory: asSingletonFunction(
|
|
300
|
+
({ myHelper, myService }: {
|
|
301
|
+
myHelper: ModuleDependencies['myHelper']
|
|
302
|
+
myService: ModuleDependencies['myService']
|
|
303
|
+
}) => {
|
|
304
|
+
return () => myHelper.process()
|
|
305
|
+
},
|
|
306
|
+
),
|
|
307
|
+
|
|
308
|
+
// ...
|
|
309
|
+
|
|
310
|
+
// At the bottom of the file:
|
|
311
|
+
export type ModuleDependencies = InferModuleDependencies<MyModule>
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
This works because TypeScript resolves indexed access types (`ModuleDependencies['myHelper']`) **lazily** — it looks up individual properties without computing the entire `ModuleDependencies` type, avoiding the cycle. Each dependency is fully typed and stays in sync with the module's resolvers automatically. No explicit return type annotation is needed.
|
|
315
|
+
|
|
316
|
+
For cross-module dependencies, use `InferPublicModuleDependencies`:
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
type OtherDeps = InferPublicModuleDependencies<OtherModule>
|
|
320
|
+
|
|
321
|
+
myFactory: asSingletonFunction(
|
|
322
|
+
({ externalService }: { externalService: OtherDeps['externalService'] }) => {
|
|
323
|
+
return new MyFactory(externalService)
|
|
324
|
+
},
|
|
325
|
+
),
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Note:** `Pick<ModuleDependencies, 'a' | 'b'>` does **not** work — `Pick` requires `keyof ModuleDependencies`, which forces TypeScript to resolve the entire type and triggers the circular reference. Each property must be accessed individually via indexed access.
|
|
329
|
+
|
|
330
|
+
**Alternative: class wrapper**
|
|
331
|
+
|
|
332
|
+
When adapting a third-party class with an incompatible constructor, `asSingletonFunction` is typically used to bridge the gap between the DI cradle and the library's API. If the adapter needs many dependencies, the indexed access syntax can become verbose. In that case, wrap the adaptation logic in a class and use `asSingletonClass` instead — the constructor can reference `ModuleDependencies` directly since `ClassValue<T>` breaks the cycle automatically:
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
// Third-party library — constructor is incompatible with DI cradle
|
|
336
|
+
import { S3Client } from '@aws-sdk/client-s3'
|
|
337
|
+
|
|
338
|
+
// With asSingletonFunction, each dep needs indexed access:
|
|
339
|
+
s3Client: asSingletonFunction(
|
|
340
|
+
({ config, logger }: {
|
|
341
|
+
config: ModuleDependencies['config']
|
|
342
|
+
logger: ModuleDependencies['logger']
|
|
343
|
+
}) => {
|
|
344
|
+
return new S3Client({
|
|
345
|
+
region: config.awsRegion,
|
|
346
|
+
credentials: { accessKeyId: config.awsAccessKey, secretAccessKey: config.awsSecretKey },
|
|
347
|
+
logger,
|
|
348
|
+
})
|
|
349
|
+
},
|
|
350
|
+
),
|
|
351
|
+
|
|
352
|
+
// With a class wrapper, reference ModuleDependencies directly.
|
|
353
|
+
// If you need to add domain-specific methods, the wrapper becomes a full adapter:
|
|
354
|
+
class S3StorageAdapter {
|
|
355
|
+
private readonly client: S3Client
|
|
356
|
+
|
|
357
|
+
constructor({ config, logger }: ModuleDependencies) {
|
|
358
|
+
this.client = new S3Client({
|
|
359
|
+
region: config.awsRegion,
|
|
360
|
+
credentials: { accessKeyId: config.awsAccessKey, secretAccessKey: config.awsSecretKey },
|
|
361
|
+
logger,
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async upload(bucket: string, key: string, body: Buffer): Promise<string> {
|
|
366
|
+
await this.client.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: body }))
|
|
367
|
+
return `https://${bucket}.s3.amazonaws.com/${key}`
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// In resolveDependencies():
|
|
372
|
+
s3StorageAdapter: asSingletonClass(S3StorageAdapter),
|
|
373
|
+
|
|
374
|
+
// If you just need the third-party instance as-is without adding any logic,
|
|
375
|
+
// use a simple container to avoid re-wrapping every method:
|
|
376
|
+
class S3ClientProvider {
|
|
377
|
+
readonly client: S3Client
|
|
378
|
+
|
|
379
|
+
constructor({ config, logger }: ModuleDependencies) {
|
|
380
|
+
this.client = new S3Client({
|
|
381
|
+
region: config.awsRegion,
|
|
382
|
+
credentials: { accessKeyId: config.awsAccessKey, secretAccessKey: config.awsSecretKey },
|
|
383
|
+
logger,
|
|
384
|
+
})
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// In resolveDependencies():
|
|
389
|
+
s3ClientProvider: asSingletonClass(S3ClientProvider),
|
|
390
|
+
|
|
391
|
+
// Consumers access the original instance directly:
|
|
392
|
+
// this.s3ClientProvider.client.send(new PutObjectCommand({ ... }))
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
This is more heavyweight than a function resolver but provides full type safety with no indexed access needed, and scales cleanly to any number of dependencies.
|
|
396
|
+
|
|
134
397
|
You can also use the explicit generic pattern if you prefer (e.g. for `isolatedDeclarations` mode):
|
|
135
398
|
|
|
136
399
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { AbstractController, type BuildRoutesReturnType } from './lib/AbstractController.js';
|
|
2
|
-
export { AbstractModule, type InferModuleDependencies, type InferPublicModuleDependencies, type MandatoryNameAndRegistrationPair, type
|
|
2
|
+
export { AbstractModule, type InferModuleDependencies, type InferPublicModuleDependencies, type MandatoryNameAndRegistrationPair, type PublicDependencies, } from './lib/AbstractModule.js';
|
|
3
3
|
export { AbstractTestContextFactory, type CreateTestContextParams, } from './lib/AbstractTestContextFactory.js';
|
|
4
4
|
export type { NestedPartial } from './lib/configUtils.js';
|
|
5
5
|
export { type DependencyInjectionOptions, DIContext, type RegisterDependenciesParams, } from './lib/DIContext.js';
|
|
@@ -3,10 +3,6 @@ import type { DependencyInjectionOptions } from './DIContext.js';
|
|
|
3
3
|
export type MandatoryNameAndRegistrationPair<T> = {
|
|
4
4
|
[U in keyof T]: Resolver<T[U]>;
|
|
5
5
|
};
|
|
6
|
-
/**
|
|
7
|
-
* Use this utility type to combine dependencies from multiple modules into full context list of dependencies
|
|
8
|
-
*/
|
|
9
|
-
export type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
10
6
|
/**
|
|
11
7
|
* Infers the module's dependency types from the return type of `resolveDependencies()`.
|
|
12
8
|
*
|
|
@@ -32,20 +28,20 @@ export type InferModuleDependencies<M extends AbstractModule> = ReturnType<M['re
|
|
|
32
28
|
[K in keyof R]: R[K] extends Resolver<infer T> ? T : never;
|
|
33
29
|
} : never;
|
|
34
30
|
/**
|
|
35
|
-
* Infers only the **public** dependency types from the return type of `resolveDependencies()
|
|
31
|
+
* Infers only the **public** dependency types from the return type of `resolveDependencies()`,
|
|
32
|
+
* omitting non-public dependencies entirely.
|
|
36
33
|
*
|
|
37
34
|
* When a module is used as a secondary module, only resolvers marked with `public: true`
|
|
38
35
|
* (i.e. those created via `asServiceClass`, `asUseCaseClass`, `asJobQueueClass`, or
|
|
39
|
-
* `asEnqueuedJobQueueManagerFunction`) are exposed.
|
|
40
|
-
* to just those public dependencies.
|
|
36
|
+
* `asEnqueuedJobQueueManagerFunction`) are exposed. Non-public resolvers are filtered out.
|
|
41
37
|
*
|
|
42
38
|
* @example
|
|
43
39
|
* ```typescript
|
|
44
40
|
* export class MyModule extends AbstractModule {
|
|
45
41
|
* resolveDependencies(diOptions: DependencyInjectionOptions) {
|
|
46
42
|
* return {
|
|
47
|
-
* myService: asServiceClass(MyService), // public
|
|
48
|
-
* myRepo: asRepositoryClass(MyRepository), // private
|
|
43
|
+
* myService: asServiceClass(MyService), // public → MyService
|
|
44
|
+
* myRepo: asRepositoryClass(MyRepository), // private → omitted
|
|
49
45
|
* }
|
|
50
46
|
* }
|
|
51
47
|
* }
|
|
@@ -59,6 +55,28 @@ export type InferPublicModuleDependencies<M extends AbstractModule> = ReturnType
|
|
|
59
55
|
readonly __publicResolver: true;
|
|
60
56
|
} ? K : never]: R[K] extends Resolver<infer T> ? T : never;
|
|
61
57
|
} : never;
|
|
58
|
+
/**
|
|
59
|
+
* Augmentation target for accumulating public dependencies across modules.
|
|
60
|
+
*
|
|
61
|
+
* Each module augments this interface via `declare module` to register its
|
|
62
|
+
* public dependencies. The augmentations are project-wide — they apply
|
|
63
|
+
* everywhere as long as the augmenting file is part of the TypeScript
|
|
64
|
+
* compilation, with no explicit import chain required.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* // In your module file:
|
|
69
|
+
* declare module 'opinionated-machine' {
|
|
70
|
+
* interface PublicDependencies extends InferPublicModuleDependencies<MyModule> {}
|
|
71
|
+
* }
|
|
72
|
+
*
|
|
73
|
+
* // In any consumer file:
|
|
74
|
+
* import type { PublicDependencies } from 'opinionated-machine'
|
|
75
|
+
* // PublicDependencies contains all augmented public deps
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export interface PublicDependencies {
|
|
79
|
+
}
|
|
62
80
|
export declare abstract class AbstractModule<ModuleDependencies = unknown, ExternalDependencies = never> {
|
|
63
81
|
abstract resolveDependencies(diOptions: DependencyInjectionOptions, externalDependencies: ExternalDependencies): MandatoryNameAndRegistrationPair<ModuleDependencies>;
|
|
64
82
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractModule.js","sourceRoot":"","sources":["../../lib/AbstractModule.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AbstractModule.js","sourceRoot":"","sources":["../../lib/AbstractModule.ts"],"names":[],"mappings":"AAwFA,MAAM,OAAgB,cAAc;IAMlC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACI,kBAAkB,CACvB,UAAsC;QAEtC,OAAO,EAAE,CAAA;IACX,CAAC;CACF"}
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import type { BuildResolver, BuildResolverOptions,
|
|
1
|
+
import type { BuildResolver, BuildResolverOptions, DisposableResolver } from 'awilix';
|
|
2
2
|
import type { FunctionReturning } from 'awilix/lib/container';
|
|
3
3
|
import type { DependencyInjectionOptions } from './DIContext.js';
|
|
4
|
+
/**
|
|
5
|
+
* Type-level representation of a class value that infers the instance type
|
|
6
|
+
* from the `prototype` property rather than from the constructor signature.
|
|
7
|
+
*
|
|
8
|
+
* This breaks circular type dependencies that occur when a class constructor
|
|
9
|
+
* references a type derived from the module's own resolver return type
|
|
10
|
+
* (e.g. `InferModuleDependencies`), because TypeScript can resolve the
|
|
11
|
+
* instance type (prototype) without evaluating constructor parameter types.
|
|
12
|
+
*
|
|
13
|
+
* Constructor parameter types are still fully checked — the cycle is only
|
|
14
|
+
* broken at the resolver inference level.
|
|
15
|
+
*/
|
|
16
|
+
type ClassValue<T> = {
|
|
17
|
+
prototype: T;
|
|
18
|
+
};
|
|
4
19
|
declare module 'awilix' {
|
|
5
20
|
interface ResolverOptions<T> {
|
|
6
21
|
public?: boolean;
|
|
@@ -14,10 +29,10 @@ export type PublicResolver<T> = BuildResolver<T> & DisposableResolver<T> & {
|
|
|
14
29
|
export interface EnqueuedJobQueueManager {
|
|
15
30
|
start(enabled?: string[] | boolean): Promise<void>;
|
|
16
31
|
}
|
|
17
|
-
export declare function asSingletonClass<T = object>(Type:
|
|
32
|
+
export declare function asSingletonClass<T = object>(Type: ClassValue<T>, opts: BuildResolverOptions<T> & {
|
|
18
33
|
public: true;
|
|
19
34
|
}): PublicResolver<T>;
|
|
20
|
-
export declare function asSingletonClass<T = object>(Type:
|
|
35
|
+
export declare function asSingletonClass<T = object>(Type: ClassValue<T>, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
21
36
|
/**
|
|
22
37
|
* Register a class with an additional config parameter passed to the constructor.
|
|
23
38
|
* Uses asFunction wrapper internally to pass the config as a second parameter.
|
|
@@ -28,21 +43,21 @@ export declare function asSingletonClass<T = object>(Type: Constructor<T>, opts?
|
|
|
28
43
|
* myService: asClassWithConfig(MyService, { enableFeature: true }),
|
|
29
44
|
* ```
|
|
30
45
|
*/
|
|
31
|
-
export declare function asClassWithConfig<T = object, Config = unknown>(Type:
|
|
46
|
+
export declare function asClassWithConfig<T = object, Config = unknown>(Type: ClassValue<T>, config: Config, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
32
47
|
export declare function asSingletonFunction<T>(fn: FunctionReturning<T>, opts: BuildResolverOptions<T> & {
|
|
33
48
|
public: true;
|
|
34
49
|
}): PublicResolver<T>;
|
|
35
50
|
export declare function asSingletonFunction<T>(fn: FunctionReturning<T>, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
36
|
-
export declare function asServiceClass<T = object>(Type:
|
|
51
|
+
export declare function asServiceClass<T = object>(Type: ClassValue<T>, opts: BuildResolverOptions<T> & {
|
|
37
52
|
public: false;
|
|
38
53
|
}): BuildResolver<T> & DisposableResolver<T>;
|
|
39
|
-
export declare function asServiceClass<T = object>(Type:
|
|
40
|
-
export declare function asUseCaseClass<T = object>(Type:
|
|
54
|
+
export declare function asServiceClass<T = object>(Type: ClassValue<T>, opts?: BuildResolverOptions<T>): PublicResolver<T>;
|
|
55
|
+
export declare function asUseCaseClass<T = object>(Type: ClassValue<T>, opts: BuildResolverOptions<T> & {
|
|
41
56
|
public: false;
|
|
42
57
|
}): BuildResolver<T> & DisposableResolver<T>;
|
|
43
|
-
export declare function asUseCaseClass<T = object>(Type:
|
|
44
|
-
export declare function asRepositoryClass<T = object>(Type:
|
|
45
|
-
export declare function asControllerClass<T = object>(Type:
|
|
58
|
+
export declare function asUseCaseClass<T = object>(Type: ClassValue<T>, opts?: BuildResolverOptions<T>): PublicResolver<T>;
|
|
59
|
+
export declare function asRepositoryClass<T = object>(Type: ClassValue<T>, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
60
|
+
export declare function asControllerClass<T = object>(Type: ClassValue<T>, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
46
61
|
export type SSEControllerModuleOptions = {
|
|
47
62
|
diOptions: DependencyInjectionOptions;
|
|
48
63
|
};
|
|
@@ -64,7 +79,7 @@ export type SSEControllerModuleOptions = {
|
|
|
64
79
|
* notificationsSSEController: asSSEControllerClass(NotificationsSSEController, { diOptions }),
|
|
65
80
|
* ```
|
|
66
81
|
*/
|
|
67
|
-
export declare function asSSEControllerClass<T = object>(Type:
|
|
82
|
+
export declare function asSSEControllerClass<T = object>(Type: ClassValue<T>, sseOptions?: SSEControllerModuleOptions, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
68
83
|
export type DualModeControllerModuleOptions = {
|
|
69
84
|
diOptions: DependencyInjectionOptions;
|
|
70
85
|
};
|
|
@@ -87,17 +102,17 @@ export type DualModeControllerModuleOptions = {
|
|
|
87
102
|
* chatController: asDualModeControllerClass(ChatController, { diOptions }),
|
|
88
103
|
* ```
|
|
89
104
|
*/
|
|
90
|
-
export declare function asDualModeControllerClass<T = object>(Type:
|
|
105
|
+
export declare function asDualModeControllerClass<T = object>(Type: ClassValue<T>, dualModeOptions?: DualModeControllerModuleOptions, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
91
106
|
export type MessageQueueConsumerModuleOptions = {
|
|
92
107
|
queueName: string;
|
|
93
108
|
diOptions: DependencyInjectionOptions;
|
|
94
109
|
};
|
|
95
|
-
export declare function asMessageQueueHandlerClass<T = object>(Type:
|
|
110
|
+
export declare function asMessageQueueHandlerClass<T = object>(Type: ClassValue<T>, mqOptions: MessageQueueConsumerModuleOptions, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
96
111
|
export type EnqueuedJobWorkerModuleOptions = {
|
|
97
112
|
queueName: string;
|
|
98
113
|
diOptions: DependencyInjectionOptions;
|
|
99
114
|
};
|
|
100
|
-
export declare function asEnqueuedJobWorkerClass<T = object>(Type:
|
|
115
|
+
export declare function asEnqueuedJobWorkerClass<T = object>(Type: ClassValue<T>, workerOptions: EnqueuedJobWorkerModuleOptions, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
101
116
|
/**
|
|
102
117
|
* Helper function to register a pg-boss job processor class with the DI container.
|
|
103
118
|
* Handles asyncInit/asyncDispose lifecycle and enabled check based on diOptions.
|
|
@@ -113,21 +128,22 @@ export declare function asEnqueuedJobWorkerClass<T = object>(Type: Constructor<T
|
|
|
113
128
|
export declare function asPgBossProcessorClass<T extends {
|
|
114
129
|
start(): Promise<void>;
|
|
115
130
|
stop(): Promise<void>;
|
|
116
|
-
}>(Type:
|
|
131
|
+
}>(Type: ClassValue<T>, processorOptions: EnqueuedJobWorkerModuleOptions, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
117
132
|
export type PeriodicJobOptions = {
|
|
118
133
|
jobName: string;
|
|
119
134
|
diOptions: DependencyInjectionOptions;
|
|
120
135
|
};
|
|
121
|
-
export declare function asPeriodicJobClass<T = object>(Type:
|
|
136
|
+
export declare function asPeriodicJobClass<T = object>(Type: ClassValue<T>, workerOptions: PeriodicJobOptions, opts?: BuildResolverOptions<T>): BuildResolver<T> & DisposableResolver<T>;
|
|
122
137
|
export type JobQueueModuleOptions = {
|
|
123
138
|
queueName?: string;
|
|
124
139
|
diOptions: DependencyInjectionOptions;
|
|
125
140
|
};
|
|
126
|
-
export declare function asJobQueueClass<T = object>(Type:
|
|
141
|
+
export declare function asJobQueueClass<T = object>(Type: ClassValue<T>, queueOptions: JobQueueModuleOptions, opts: BuildResolverOptions<T> & {
|
|
127
142
|
public: false;
|
|
128
143
|
}): BuildResolver<T> & DisposableResolver<T>;
|
|
129
|
-
export declare function asJobQueueClass<T = object>(Type:
|
|
144
|
+
export declare function asJobQueueClass<T = object>(Type: ClassValue<T>, queueOptions: JobQueueModuleOptions, opts?: BuildResolverOptions<T>): PublicResolver<T>;
|
|
130
145
|
export declare function asEnqueuedJobQueueManagerFunction<T extends EnqueuedJobQueueManager>(fn: FunctionReturning<T>, diOptions: DependencyInjectionOptions, opts: BuildResolverOptions<T> & {
|
|
131
146
|
public: false;
|
|
132
147
|
}): BuildResolver<T> & DisposableResolver<T>;
|
|
133
148
|
export declare function asEnqueuedJobQueueManagerFunction<T extends EnqueuedJobQueueManager>(fn: FunctionReturning<T>, diOptions: DependencyInjectionOptions, opts?: BuildResolverOptions<T>): PublicResolver<T>;
|
|
149
|
+
export {};
|
|
@@ -17,8 +17,9 @@ export function asSingletonClass(Type, opts) {
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
export function asClassWithConfig(Type, config, opts) {
|
|
20
|
+
const Ctor = Type;
|
|
20
21
|
// biome-ignore lint/suspicious/noExplicitAny: Dynamic constructor invocation with cradle proxy
|
|
21
|
-
return asFunction((cradle) => new
|
|
22
|
+
return asFunction((cradle) => new Ctor(cradle, config), {
|
|
22
23
|
...opts,
|
|
23
24
|
lifetime: opts?.lifetime ?? 'SINGLETON',
|
|
24
25
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolverFunctions.js","sourceRoot":"","sources":["../../lib/resolverFunctions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAG5C,OAAO,EACL,2BAA2B,EAC3B,iBAAiB,EACjB,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"resolverFunctions.js","sourceRoot":"","sources":["../../lib/resolverFunctions.ts"],"names":[],"mappings":"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"}
|