ts-ioc-container 50.0.0 → 50.1.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 CHANGED
@@ -36,7 +36,7 @@ no global container objects.
36
36
  - [Setup](#setup)
37
37
  - [Quickstart](#quickstart)
38
38
  - [Cheatsheet](#cheatsheet)
39
- - [Spec-driven workflow](#spec-driven-workflow)
39
+ - [Specs-driven workflow](#specs-driven-workflow)
40
40
  - [Product capability map](#product-capability-map)
41
41
  - [Acceptance specs](#acceptance-specs)
42
42
  - [tsyringe alternative](https://igorbabkin.github.io/ts-ioc-container/tsyringe-alternative)
@@ -144,7 +144,7 @@ container.resolve(App).start();
144
144
  > for `R.fromValue(...)` and `R.fromFn(...)` (which have no class to decorate)
145
145
  > or for third-party classes you don't own.
146
146
 
147
- ## Spec-driven workflow
147
+ ## Specs-driven workflow
148
148
 
149
149
  Public behavior is described as product capabilities before it is implemented.
150
150
  The repository keeps the same chain visible in specs, tests, docs, and this
@@ -184,49 +184,203 @@ tests stay in the feature folders under `__tests__/`.
184
184
 
185
185
  ### Express/Next handler (per-request scope)
186
186
 
187
- ```typescript
188
- const app = new Container({ tags: ['application'] }).addRegistration(R.fromClass(Logger).pipe(singleton()));
187
+ import 'reflect-metadata';
188
+ import { bindTo, Container, inject, register, Registration as R, singleton } from 'ts-ioc-container';
189
+
190
+ /**
191
+ * Web Framework Integration - Per-Request Scope
192
+ *
193
+ * In Express/Next.js applications, each HTTP request typically gets its own
194
+ * scope. This ensures request-specific state (logger context, current user,
195
+ * correlation IDs) is isolated between concurrent requests.
196
+ *
197
+ * Scope hierarchy:
198
+ * Application (singleton services — live for entire app lifetime)
199
+ * └── Request (per-request services — created and disposed per request)
200
+ */
201
+
202
+ @register(bindTo('ILogger'), singleton())
203
+ class Logger {
204
+ readonly messages: string[] = [];
189
205
 
190
- function handleRequest() {
191
- const requestScope = app.createScope({ tags: ['request'] });
192
- const logger = requestScope.resolve<Logger>('Logger');
193
- logger.log('req started');
206
+ log(message: string) {
207
+ this.messages.push(message);
208
+ }
194
209
  }
195
- ```
210
+
211
+ describe('Express/Next per-request scope', () => {
212
+ it('should give each request its own Logger instance', () => {
213
+ const app = new Container({ tags: ['application'] }).addRegistration(R.fromClass(Logger));
214
+
215
+ // Simulate two concurrent HTTP requests
216
+ const request1Scope = app.createScope({ tags: ['request'] });
217
+ const request2Scope = app.createScope({ tags: ['request'] });
218
+
219
+ const logger1 = request1Scope.resolve<Logger>('ILogger');
220
+ const logger2 = request2Scope.resolve<Logger>('ILogger');
221
+
222
+ logger1.log('req 1 started');
223
+ logger2.log('req 2 started');
224
+
225
+ // Each request has its own Logger — logs don't leak between requests
226
+ expect(logger1.messages).toEqual(['req 1 started']);
227
+ expect(logger2.messages).toEqual(['req 2 started']);
228
+ expect(logger1).not.toBe(logger2);
229
+ });
230
+
231
+ it('should resolve the same Logger within a single request', () => {
232
+ const app = new Container({ tags: ['application'] }).addRegistration(R.fromClass(Logger));
233
+
234
+ const requestScope = app.createScope({ tags: ['request'] });
235
+
236
+ const logger1 = requestScope.resolve<Logger>('ILogger');
237
+ const logger2 = requestScope.resolve<Logger>('ILogger');
238
+
239
+ // Within one request, singleton is maintained
240
+ expect(logger1).toBe(logger2);
241
+ });
242
+ });
243
+
196
244
 
197
245
  ### Background worker (singleton client, transient jobs)
198
246
 
199
- ```typescript
247
+ import 'reflect-metadata';
248
+ import { Container, inject, register, Registration as R, singleton } from 'ts-ioc-container';
249
+
250
+ /**
251
+ * Background Worker - Singleton Client, Transient Jobs
252
+ *
253
+ * A queue worker typically needs:
254
+ * - A single shared QueueClient (expensive to create, holds connections)
255
+ * - A new JobHandler per job (stateful — holds job-specific data)
256
+ *
257
+ * singleton() on QueueClient ensures one shared connection pool.
258
+ * No singleton on JobHandler gives a fresh instance per resolve.
259
+ */
260
+
200
261
  @register(singleton())
201
- class QueueClient {}
262
+ class QueueClient {
263
+ readonly connected = true;
264
+
265
+ dequeue(): string {
266
+ return 'job-payload';
267
+ }
268
+ }
202
269
 
203
270
  class JobHandler {
204
- constructor(@inject('QueueClient') private queue: QueueClient) {}
271
+ readonly result: string;
272
+
273
+ constructor(@inject('QueueClient') private queue: QueueClient) {
274
+ this.result = this.queue.dequeue();
275
+ }
205
276
  }
206
277
 
207
- const worker = new Container({ tags: ['worker'] })
208
- .addRegistration(R.fromClass(QueueClient))
209
- .addRegistration(R.fromClass(JobHandler));
210
- ```
278
+ describe('Background worker', () => {
279
+ function createWorker() {
280
+ return new Container({ tags: ['worker'] })
281
+ .addRegistration(R.fromClass(QueueClient))
282
+ .addRegistration(R.fromClass(JobHandler));
283
+ }
284
+
285
+ it('should share a single QueueClient across all job handlers', () => {
286
+ const worker = createWorker();
287
+
288
+ const handler1 = worker.resolve(JobHandler);
289
+ const handler2 = worker.resolve(JobHandler);
290
+
291
+ const client1 = worker.resolve<QueueClient>('QueueClient');
292
+ const client2 = worker.resolve<QueueClient>('QueueClient');
293
+
294
+ // QueueClient is a singleton — same connection shared everywhere
295
+ expect(client1).toBe(client2);
296
+ expect(client1.connected).toBe(true);
297
+
298
+ // JobHandler is transient — fresh instance per job
299
+ expect(handler1).not.toBe(handler2);
300
+ });
301
+
302
+ it('should inject the shared QueueClient into each JobHandler', () => {
303
+ const worker = createWorker();
304
+
305
+ const handler = worker.resolve(JobHandler);
306
+
307
+ expect(handler.result).toBe('job-payload');
308
+ });
309
+ });
310
+
211
311
 
212
312
  ### Frontend widget/page scope with lazy dependency
213
313
 
214
- ```typescript
314
+ import 'reflect-metadata';
315
+ import { bindTo, Container, inject, register, Registration as R, select, singleton } from 'ts-ioc-container';
316
+
317
+ /**
318
+ * Frontend Widget - Page Scope with Lazy Dependency
319
+ *
320
+ * In frontend applications, feature flags are fetched once per page load
321
+ * (singleton per page scope) but a widget may not need them on every render.
322
+ * Lazy injection defers instantiation until the widget actually reads the flags,
323
+ * avoiding unnecessary work for widgets that never display flag-gated content.
324
+ *
325
+ * Scope hierarchy:
326
+ * Application
327
+ * └── Page (singleton flags fetched once)
328
+ * └── Widget (lazy flag access)
329
+ */
330
+
215
331
  @register(bindTo('FeatureFlags'), singleton())
216
332
  class FeatureFlags {
217
- load() {
218
- /* fetch flags */
333
+ load(): Record<string, boolean> {
334
+ return { newDashboard: true };
219
335
  }
220
336
  }
221
337
 
222
338
  class Widget {
223
- constructor(@inject(select.token('FeatureFlags').lazy()) private flags: FeatureFlags) {}
339
+ constructor(@inject(select.token('FeatureFlags').lazy()) public flags: FeatureFlags) {}
224
340
  }
225
341
 
226
- const page = new Container({ tags: ['page'] })
227
- .addRegistration(R.fromClass(FeatureFlags))
228
- .addRegistration(R.fromClass(Widget));
229
- ```
342
+ describe('Frontend widget/page scope with lazy dependency', () => {
343
+ function createPage() {
344
+ return new Container({ tags: ['page'] })
345
+ .addRegistration(R.fromClass(FeatureFlags))
346
+ .addRegistration(R.fromClass(Widget));
347
+ }
348
+
349
+ it('should not instantiate FeatureFlags until the widget actually accesses it', () => {
350
+ const page = createPage();
351
+
352
+ const widget = page.resolve(Widget);
353
+
354
+ // Widget is resolved, but FeatureFlags has not been instantiated yet
355
+ let instances = Array.from(page.getInstances()).filter((x) => x instanceof FeatureFlags);
356
+ expect(instances).toHaveLength(0);
357
+
358
+ // Accessing any property on the lazy proxy triggers instantiation
359
+ const _load = widget.flags.load;
360
+ expect(_load).toBeDefined();
361
+
362
+ instances = Array.from(page.getInstances()).filter((x) => x instanceof FeatureFlags);
363
+ expect(instances).toHaveLength(1);
364
+ });
365
+
366
+ it('should share the same FeatureFlags singleton across widgets on the same page', () => {
367
+ const page = createPage();
368
+
369
+ const widget1 = page.resolve(Widget);
370
+ const widget2 = page.resolve(Widget);
371
+
372
+ // Trigger instantiation through both widgets
373
+ const _load1 = widget1.flags.load;
374
+ const _load2 = widget2.flags.load;
375
+ expect(_load1).toBeDefined();
376
+ expect(_load2).toBeDefined();
377
+
378
+ // Only one FeatureFlags instance was created across the whole page scope
379
+ const instances = Array.from(page.getInstances()).filter((x) => x instanceof FeatureFlags);
380
+ expect(instances).toHaveLength(1);
381
+ });
382
+ });
383
+
230
384
 
231
385
  ## Container
232
386
 
@@ -1826,7 +1980,7 @@ describe('Singleton', function () {
1826
1980
 
1827
1981
  ### Arguments
1828
1982
 
1829
- Sometimes you want to bind some arguments to provider. This is what `ArgsProvider` is for.
1983
+ Sometimes you want to bind some arguments to provider.
1830
1984
 
1831
1985
  - `provider(setArgs('someArgument'))`
1832
1986
  - `provider(setArgsFn((container) => [container.resolve(Logger), 'someValue']))`
@@ -1862,6 +2016,8 @@ const userToken = ApiToken.args('https://users.api.com', 1000);
1862
2016
 
1863
2017
  ```typescript
1864
2018
  import {
2019
+ addArgs,
2020
+ addArgsFn,
1865
2021
  args,
1866
2022
  bindTo,
1867
2023
  Container,
@@ -1884,7 +2040,7 @@ import {
1884
2040
  * - Generic classes (like Repositories) that need to know what they are managing
1885
2041
  */
1886
2042
 
1887
- describe('ArgsProvider', function () {
2043
+ describe('IProvider', function () {
1888
2044
  function createContainer() {
1889
2045
  return new Container();
1890
2046
  }
@@ -1941,6 +2097,49 @@ describe('ArgsProvider', function () {
1941
2097
  });
1942
2098
  });
1943
2099
 
2100
+ describe('Appending Arguments', () => {
2101
+ it('can append static arguments after existing resolve arguments', function () {
2102
+ @register(addArgs('configured'))
2103
+ class Service {
2104
+ constructor(
2105
+ @inject(args(0)) public runtime: string,
2106
+ @inject(args(1)) public configured: string,
2107
+ ) {}
2108
+ }
2109
+
2110
+ const root = createContainer().addRegistration(R.fromClass(Service));
2111
+
2112
+ const service = root.resolve<Service>('Service', { args: ['runtime'] });
2113
+ expect(service.runtime).toBe('runtime');
2114
+ expect(service.configured).toBe('configured');
2115
+ });
2116
+
2117
+ it('can append dynamic arguments after an existing argsFn', function () {
2118
+ class Config {
2119
+ tenant = 'tenant-a';
2120
+ }
2121
+
2122
+ @register(
2123
+ setArgs('fixed'),
2124
+ addArgsFn((scope, { args = [] } = {}) => [scope.resolve<Config>('Config').tenant, ...args]),
2125
+ )
2126
+ class Service {
2127
+ constructor(
2128
+ @inject(args(0)) public fixed: string,
2129
+ @inject(args(1)) public tenant: string,
2130
+ @inject(args(2)) public runtime: string,
2131
+ ) {}
2132
+ }
2133
+
2134
+ const root = createContainer().addRegistration(R.fromClass(Config)).addRegistration(R.fromClass(Service));
2135
+
2136
+ const service = root.resolve<Service>('Service', { args: ['runtime'] });
2137
+ expect(service.fixed).toBe('fixed');
2138
+ expect(service.tenant).toBe('tenant-a');
2139
+ expect(service.runtime).toBe('runtime');
2140
+ });
2141
+ });
2142
+
1944
2143
  describe('Generic Repositories (Advanced Pattern)', () => {
1945
2144
  // This example demonstrates how to implement the Generic Repository pattern
1946
2145
  // where a generic EntityManager needs to know WHICH repository to use.
package/cjm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SingleToken = exports.ClassToken = exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.InjectionToken = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onDispose = exports.onDisposeHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.hasHooks = exports.hook = exports.getHooks = exports.UnexpectedHookResultError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.DependencyNotFoundError = exports.Registration = exports.bindTo = exports.register = exports.scope = exports.decorate = exports.SingletonProvider = exports.singleton = exports.Provider = exports.ProviderDecorator = exports.setArgs = exports.setArgsFn = exports.lazy = exports.scopeAccess = exports.ProxyInjector = exports.SimpleInjector = exports.MetadataInjector = exports.Injector = exports.argsFn = exports.args = exports.resolveArgs = exports.inject = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
4
- exports.resolveConstructor = exports.Is = exports.pipe = exports.select = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.methodTag = exports.getMethodLabels = exports.methodLabel = exports.getMethodMeta = exports.methodMeta = exports.getParamTags = exports.paramTag = exports.getParamLabels = exports.paramLabel = exports.getParamMeta = exports.paramMeta = exports.getClassTags = exports.classTag = exports.getClassLabels = exports.classLabel = exports.getClassMeta = exports.classMeta = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = void 0;
3
+ exports.toSingleAlias = exports.SingleAliasToken = exports.toGroupAlias = exports.GroupAliasToken = exports.InjectionToken = exports.HooksRunner = exports.AddOnDisposeHookModule = exports.onDispose = exports.onDisposeHooksRunner = exports.AddOnConstructHookModule = exports.onConstruct = exports.onConstructHooksRunner = exports.injectProp = exports.createHookContext = exports.createHookContextFactory = exports.HookContext = exports.hasHooks = exports.hook = exports.getHooks = exports.UnexpectedHookResultError = exports.ContainerDisposedError = exports.MethodNotImplementedError = exports.DependencyMissingKeyError = exports.DependencyNotFoundError = exports.Registration = exports.bindTo = exports.register = exports.scope = exports.decorate = exports.SingletonProvider = exports.singleton = exports.Provider = exports.ProviderDecorator = exports.setArgs = exports.setArgsFn = exports.addArgsFn = exports.addArgs = exports.lazy = exports.scopeAccess = exports.ProxyInjector = exports.SimpleInjector = exports.MetadataInjector = exports.Injector = exports.argsFn = exports.args = exports.resolveArgs = exports.inject = exports.EmptyContainer = exports.Container = exports.isDependencyKey = void 0;
4
+ exports.resolveConstructor = exports.Is = exports.pipe = exports.select = exports.once = exports.shallowCache = exports.debounce = exports.throttle = exports.handleAsyncError = exports.handleError = exports.getMethodTags = exports.methodTag = exports.getMethodLabels = exports.methodLabel = exports.getMethodMeta = exports.methodMeta = exports.getParamTags = exports.paramTag = exports.getParamLabels = exports.paramLabel = exports.getParamMeta = exports.paramMeta = exports.getClassTags = exports.classTag = exports.getClassLabels = exports.classLabel = exports.getClassMeta = exports.classMeta = exports.GroupInstanceToken = exports.ConstantToken = exports.FunctionToken = exports.SingleToken = exports.ClassToken = void 0;
5
5
  // Containers
6
6
  var IContainer_1 = require("./container/IContainer");
7
7
  Object.defineProperty(exports, "isDependencyKey", { enumerable: true, get: function () { return IContainer_1.isDependencyKey; } });
@@ -27,6 +27,8 @@ Object.defineProperty(exports, "ProxyInjector", { enumerable: true, get: functio
27
27
  var IProvider_1 = require("./provider/IProvider");
28
28
  Object.defineProperty(exports, "scopeAccess", { enumerable: true, get: function () { return IProvider_1.scopeAccess; } });
29
29
  Object.defineProperty(exports, "lazy", { enumerable: true, get: function () { return IProvider_1.lazy; } });
30
+ Object.defineProperty(exports, "addArgs", { enumerable: true, get: function () { return IProvider_1.addArgs; } });
31
+ Object.defineProperty(exports, "addArgsFn", { enumerable: true, get: function () { return IProvider_1.addArgsFn; } });
30
32
  Object.defineProperty(exports, "setArgsFn", { enumerable: true, get: function () { return IProvider_1.setArgsFn; } });
31
33
  Object.defineProperty(exports, "setArgs", { enumerable: true, get: function () { return IProvider_1.setArgs; } });
32
34
  Object.defineProperty(exports, "ProviderDecorator", { enumerable: true, get: function () { return IProvider_1.ProviderDecorator; } });
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProviderDecorator = exports.lazy = exports.scopeAccess = exports.setArgsFn = exports.setArgs = void 0;
3
+ exports.ProviderDecorator = exports.lazy = exports.scopeAccess = exports.addArgsFn = exports.addArgs = exports.setArgsFn = exports.setArgs = void 0;
4
4
  const ProviderPipe_1 = require("./ProviderPipe");
5
5
  const setArgs = (...extraArgs) => (0, ProviderPipe_1.registerPipe)((p) => p.setArgs(() => extraArgs));
6
6
  exports.setArgs = setArgs;
7
7
  const setArgsFn = (fn) => (0, ProviderPipe_1.registerPipe)((p) => p.setArgs(fn));
8
8
  exports.setArgsFn = setArgsFn;
9
+ const addArgs = (...extraArgs) => (0, ProviderPipe_1.registerPipe)((p) => p.addArgs(...extraArgs));
10
+ exports.addArgs = addArgs;
11
+ const addArgsFn = (fn) => (0, ProviderPipe_1.registerPipe)((p) => p.addArgsFn(fn));
12
+ exports.addArgsFn = addArgsFn;
9
13
  const scopeAccess = (rule) => (0, ProviderPipe_1.registerPipe)((p) => p.setAccessRule(rule));
10
14
  exports.scopeAccess = scopeAccess;
11
15
  const lazy = () => (0, ProviderPipe_1.registerPipe)((p) => p.lazy());
@@ -39,6 +43,14 @@ class ProviderDecorator {
39
43
  this.decorated.setArgs(argsFn);
40
44
  return this;
41
45
  }
46
+ addArgs(...extraArgs) {
47
+ this.decorated.addArgs(...extraArgs);
48
+ return this;
49
+ }
50
+ addArgsFn(argsFn) {
51
+ this.decorated.addArgsFn(argsFn);
52
+ return this;
53
+ }
42
54
  lazy() {
43
55
  this.decorated.lazy();
44
56
  return this;
@@ -42,6 +42,16 @@ class Provider {
42
42
  this.argsFn = argsFn;
43
43
  return this;
44
44
  }
45
+ addArgs(...extraArgs) {
46
+ const parentFn = this.argsFn;
47
+ this.argsFn = (container, options) => [...parentFn(container, options), ...extraArgs];
48
+ return this;
49
+ }
50
+ addArgsFn(argsFn) {
51
+ const parentFn = this.argsFn;
52
+ this.argsFn = (container, options) => [...parentFn(container, options), ...argsFn(container, options)];
53
+ return this;
54
+ }
45
55
  hasAccess(options) {
46
56
  return this.checkAccess(options);
47
57
  }
package/esm/index.js CHANGED
@@ -9,7 +9,7 @@ export { MetadataInjector } from './injector/MetadataInjector';
9
9
  export { SimpleInjector } from './injector/SimpleInjector';
10
10
  export { ProxyInjector } from './injector/ProxyInjector';
11
11
  // Providers
12
- export { scopeAccess, lazy, setArgsFn, setArgs, ProviderDecorator, } from './provider/IProvider';
12
+ export { scopeAccess, lazy, addArgs, addArgsFn, setArgsFn, setArgs, ProviderDecorator, } from './provider/IProvider';
13
13
  export { Provider } from './provider/Provider';
14
14
  export { singleton, SingletonProvider } from './provider/SingletonProvider';
15
15
  export { decorate } from './provider/DecoratorProvider';
@@ -1,6 +1,8 @@
1
1
  import { isProviderPipe, registerPipe } from './ProviderPipe';
2
2
  export const setArgs = (...extraArgs) => registerPipe((p) => p.setArgs(() => extraArgs));
3
3
  export const setArgsFn = (fn) => registerPipe((p) => p.setArgs(fn));
4
+ export const addArgs = (...extraArgs) => registerPipe((p) => p.addArgs(...extraArgs));
5
+ export const addArgsFn = (fn) => registerPipe((p) => p.addArgsFn(fn));
4
6
  export const scopeAccess = (rule) => registerPipe((p) => p.setAccessRule(rule));
5
7
  export const lazy = () => registerPipe((p) => p.lazy());
6
8
  export class ProviderDecorator {
@@ -32,6 +34,14 @@ export class ProviderDecorator {
32
34
  this.decorated.setArgs(argsFn);
33
35
  return this;
34
36
  }
37
+ addArgs(...extraArgs) {
38
+ this.decorated.addArgs(...extraArgs);
39
+ return this;
40
+ }
41
+ addArgsFn(argsFn) {
42
+ this.decorated.addArgsFn(argsFn);
43
+ return this;
44
+ }
35
45
  lazy() {
36
46
  this.decorated.lazy();
37
47
  return this;
@@ -39,6 +39,16 @@ export class Provider {
39
39
  this.argsFn = argsFn;
40
40
  return this;
41
41
  }
42
+ addArgs(...extraArgs) {
43
+ const parentFn = this.argsFn;
44
+ this.argsFn = (container, options) => [...parentFn(container, options), ...extraArgs];
45
+ return this;
46
+ }
47
+ addArgsFn(argsFn) {
48
+ const parentFn = this.argsFn;
49
+ this.argsFn = (container, options) => [...parentFn(container, options), ...argsFn(container, options)];
50
+ return this;
51
+ }
42
52
  hasAccess(options) {
43
53
  return this.checkAccess(options);
44
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-ioc-container",
3
- "version": "50.0.0",
3
+ "version": "50.1.0",
4
4
  "description": "Fast, lightweight TypeScript dependency injection container with a clean API, scoped lifecycles, decorators, tokens, hooks, lazy injection, customizable providers, and no global container objects.",
5
5
  "workspaces": [
6
6
  "docs"
@@ -90,11 +90,11 @@
90
90
  "@swc/core": "^1.15.24",
91
91
  "@types/node": "^25.5.2",
92
92
  "@typescript-eslint/eslint-plugin": "8.32.1",
93
- "@typescript-eslint/parser": "8.29.1",
93
+ "@typescript-eslint/parser": "8.58.2",
94
94
  "@vitest/coverage-v8": "^4.1.2",
95
95
  "cz-conventional-changelog": "^3.3.0",
96
96
  "eslint": "9.24.0",
97
- "eslint-config-prettier": "10.1.1",
97
+ "eslint-config-prettier": "10.1.8",
98
98
  "eslint-plugin-prettier": "5.2.6",
99
99
  "handlebars": "^4.7.8",
100
100
  "husky": "^9.1.7",
@@ -6,7 +6,7 @@ export { type IInjector, type InjectOptions, type IInjectFnResolver, Injector }
6
6
  export { MetadataInjector } from './injector/MetadataInjector';
7
7
  export { SimpleInjector } from './injector/SimpleInjector';
8
8
  export { ProxyInjector } from './injector/ProxyInjector';
9
- export { type ResolveDependency, type IProvider, scopeAccess, lazy, setArgsFn, setArgs, type ArgsFn, ProviderDecorator, type IMapper, type ProviderOptions, } from './provider/IProvider';
9
+ export { type ResolveDependency, type IProvider, scopeAccess, lazy, addArgs, addArgsFn, setArgsFn, setArgs, type ArgsFn, ProviderDecorator, type IMapper, type ProviderOptions, } from './provider/IProvider';
10
10
  export { Provider } from './provider/Provider';
11
11
  export { singleton, SingletonProvider } from './provider/SingletonProvider';
12
12
  export { decorate, type DecorateFn } from './provider/DecoratorProvider';
@@ -22,10 +22,14 @@ export interface IProvider<T = any> {
22
22
  pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
23
23
  setAccessRule(hasAccessWhen: ScopeAccessRule): this;
24
24
  setArgs(argsFn: ArgsFn): this;
25
+ addArgs(...extraArgs: unknown[]): this;
26
+ addArgsFn(argsFn: ArgsFn): this;
25
27
  lazy(): this;
26
28
  }
27
29
  export declare const setArgs: <T>(...extraArgs: unknown[]) => ProviderPipe<T>;
28
30
  export declare const setArgsFn: <T>(fn: ArgsFn) => ProviderPipe<T>;
31
+ export declare const addArgs: <T>(...extraArgs: unknown[]) => ProviderPipe<T>;
32
+ export declare const addArgsFn: <T>(fn: ArgsFn) => ProviderPipe<T>;
29
33
  export declare const scopeAccess: <T>(rule: ScopeAccessRule) => ProviderPipe<T>;
30
34
  export declare const lazy: <T>() => ProviderPipe<T>;
31
35
  export declare abstract class ProviderDecorator<T> implements IProvider<T> {
@@ -36,5 +40,7 @@ export declare abstract class ProviderDecorator<T> implements IProvider<T> {
36
40
  resolve(container: IContainer, options: ProviderOptions): T;
37
41
  pipe(...mappers: (MapFn<IProvider<T>> | ProviderPipe<T>)[]): IProvider<T>;
38
42
  setArgs(argsFn: ArgsFn): this;
43
+ addArgs(...extraArgs: unknown[]): this;
44
+ addArgsFn(argsFn: ArgsFn): this;
39
45
  lazy(): this;
40
46
  }
@@ -17,5 +17,7 @@ export declare class Provider<T = any> implements IProvider<T> {
17
17
  setAccessRule(predicate: ScopeAccessRule): this;
18
18
  lazy(): this;
19
19
  setArgs(argsFn: ArgsFn): this;
20
+ addArgs(...extraArgs: unknown[]): this;
21
+ addArgsFn(argsFn: ArgsFn): this;
20
22
  hasAccess(options: ScopeAccessOptions): boolean;
21
23
  }