getbox 1.0.0 → 1.2.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/CONTEXT.md ADDED
@@ -0,0 +1,123 @@
1
+ # getbox/context
2
+
3
+ `getbox/context` provides an alternative pattern where the box is available implicitly via `AsyncLocalStorage`. Classes can resolve dependencies directly in their constructors without needing `static init` methods or passing the box around.
4
+
5
+ ## Setup
6
+
7
+ Wrap your application entry point with `withBox` to create a scoped box.
8
+
9
+ ```ts
10
+ import { withBox } from "getbox/context";
11
+
12
+ withBox(() => {
13
+ // All code in this scope can resolve dependencies
14
+ const app = resolve(App);
15
+ app.start();
16
+ });
17
+ ```
18
+
19
+ You can also pass an existing box to the scope.
20
+
21
+ ```ts
22
+ import { Box } from "getbox";
23
+ import { withBox } from "getbox/context";
24
+
25
+ const box = new Box();
26
+ Box.mock(box, LoggerFactory, new TestLogger());
27
+
28
+ withBox(box, () => {
29
+ const app = resolve(App);
30
+ app.start();
31
+ });
32
+ ```
33
+
34
+ ## Resolving dependencies
35
+
36
+ With the context pattern, classes can use `resolve` directly as field initializers. No `static init` method is needed.
37
+
38
+ ```ts
39
+ import { resolve } from "getbox/context";
40
+
41
+ class UserService {
42
+ public db = resolve(Database);
43
+ public logger = resolve(LoggerFactory);
44
+
45
+ createUser(name: string) {
46
+ this.logger.log(`Creating user: ${name}`);
47
+ return this.db.query("INSERT INTO users ...");
48
+ }
49
+ }
50
+ ```
51
+
52
+ Compare this with the base pattern which requires `static init`:
53
+
54
+ ```ts
55
+ import { Box } from "getbox";
56
+
57
+ class UserService {
58
+ constructor(private db: Database, private logger: Logger) {}
59
+
60
+ static init(box: Box) {
61
+ return box.for(UserService).get(Database, LoggerFactory);
62
+ }
63
+ }
64
+ ```
65
+
66
+ ## Resolving multiple dependencies
67
+
68
+ Use `resolveAll` to resolve multiple constructors at once. Accepts an object or array of constructors.
69
+
70
+ ```ts
71
+ withBox(() => {
72
+ // Object form
73
+ const { db, logger } = resolveAll({ db: Database, logger: LoggerFactory });
74
+
75
+ // Array form
76
+ const [db2, logger2] = resolveAll([Database, LoggerFactory]);
77
+
78
+ console.log(db === db2); // true (cached)
79
+ console.log(logger === logger2); // true (cached)
80
+ });
81
+ ```
82
+
83
+ ## Resolving constructor parameters
84
+
85
+ Use `construct` to create a class instance with resolved constructor parameters.
86
+
87
+ ```ts
88
+ class UserService {
89
+ constructor(private db: Database, private logger: Logger) {}
90
+ }
91
+
92
+ withBox(() => {
93
+ const service = construct(UserService).get(Database, LoggerFactory);
94
+ service.createUser("Alice");
95
+ });
96
+ ```
97
+
98
+ ## Accessing the box
99
+
100
+ Use `useBox()` to get the current box from the scope. This is useful when you need full access to the box API.
101
+
102
+ ```ts
103
+ withBox(() => {
104
+ const box = useBox();
105
+ const db = box.new(Database);
106
+ });
107
+ ```
108
+
109
+ ## Nested and concurrent scopes
110
+
111
+ Each `withBox` call creates an independent scope. Nested scopes do not share the parent box, and concurrent async scopes are isolated from each other.
112
+
113
+ ```ts
114
+ withBox(() => {
115
+ const db = resolve(Database);
116
+
117
+ // Inner scope gets a fresh box
118
+ withBox(() => {
119
+ const db2 = resolve(Database);
120
+ console.log(db === db2); // false (different scope)
121
+ });
122
+ });
123
+ ```
package/README.md CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  ### Lightweight dependency injection for TypeScript.
4
4
 
5
- `getbox` provides a simple way of managing dependencies in TypeScript applications. It uses classes and factory functions to define dependencies and automatically handles instance caching.
5
+ `getbox` provides a simple way of managing dependencies in TypeScript applications. Dependencies are defined as constructors that act as interfaces for the values they resolve.
6
6
 
7
- The main advantage of `getbox` is removing the need to manually pass references around when instantiating classes that depend on one another.
7
+ Callers know the type of the value they need, but not how it will be derived. The box resolves constructors lazily and caches instances automatically.
8
+
9
+ For an alternative pattern using AsyncLocalStorage where classes can resolve dependencies directly in their constructors, see [getbox/context](./CONTEXT.md).
8
10
 
9
11
  ## Installation
10
12
 
@@ -22,8 +24,6 @@ Classes are instantiated once and cached. Subsequent calls return the cached ins
22
24
 
23
25
  ```ts
24
26
  // printer.ts
25
- import { Box } from "getbox";
26
-
27
27
  export class Printer {
28
28
  print(text: string): string {
29
29
  return text.toUpperCase();
@@ -77,29 +77,21 @@ console.log(office.printer === printer); // true
77
77
  Use `box.new()` to create a new instance each time without caching. This is useful for instances that should not be shared.
78
78
 
79
79
  ```ts
80
- // printer.ts
80
+ // main.ts
81
81
  import { Box } from "getbox";
82
82
 
83
- export class Printer {
84
- id = Math.random();
85
-
86
- print(text: string): string {
87
- return text.toUpperCase();
83
+ class Database {
84
+ connect() {
85
+ /* ... */
88
86
  }
89
87
  }
90
- ```
91
-
92
- ```ts
93
- // main.ts
94
- import { Box } from "getbox";
95
- import { Printer } from "./printer";
96
88
 
97
89
  const box = new Box();
98
90
 
99
- const printer1 = box.new(Printer);
100
- const printer2 = box.new(Printer);
91
+ const db1 = box.new(Database);
92
+ const db2 = box.new(Database);
101
93
 
102
- console.log(printer1 === printer2); // false
94
+ console.log(db1 === db2); // false
103
95
  ```
104
96
 
105
97
  ## Factory functions
@@ -146,7 +138,7 @@ export class UserService {
146
138
 
147
139
  ## Constants
148
140
 
149
- Use the `constant` helper to register constant values without needing a factory or class.
141
+ Use the `constant` helper to register constant values without needing a factory or class. Constant values are never cached since they are already fixed.
150
142
 
151
143
  ```ts
152
144
  import { Box, constant } from "getbox";
@@ -154,7 +146,7 @@ import { Box, constant } from "getbox";
154
146
  const ApiUrl = constant("https://api.example.com");
155
147
  const Port = constant(3000);
156
148
  const Config = constant({
157
- apiUrl: "https://api.example.com",
149
+ baseUrl: "https://example.com",
158
150
  timeout: 5000,
159
151
  });
160
152
 
@@ -169,39 +161,71 @@ console.log(port); // 3000
169
161
  console.log(config.timeout); // 5000
170
162
  ```
171
163
 
172
- ## Constructing classes with dependencies
164
+ Since constructors act as interfaces, a `constant` can later be replaced with a `factory` without changing any callers.
165
+
166
+ ```ts
167
+ const ApiUrl = factory((box: Box) => {
168
+ const config = box.get(Config);
169
+ return `${config.baseUrl}/api`;
170
+ });
171
+
172
+ const apiUrl = box.get(ApiUrl); // "https://example.com/api"
173
+ ```
174
+
175
+ ## Transient factories
173
176
 
174
- Use `box.for()` for a convenient way to create instances of classes that take other constructors as dependencies. The instance created with `box.for()` is not cached, but dependencies resolved with `.get()` are cached.
177
+ Use the `transient` helper to create a factory whose result is never cached. The factory is called on every resolution, even when retrieved via `box.get()`.
175
178
 
176
179
  ```ts
177
- // database.ts
178
- export class Database {
179
- connect() { /* ... */ }
180
- }
180
+ import { Box, transient } from "getbox";
181
181
 
182
- // logger.ts
183
- import { Box, factory } from "getbox";
182
+ const RequestId = transient(() => crypto.randomUUID());
184
183
 
185
- export interface Logger {
186
- log(message: string): void;
187
- }
184
+ const box = new Box();
188
185
 
189
- export const LoggerFactory = factory((box: Box): Logger => {
190
- return console;
191
- });
186
+ const id1 = box.get(RequestId);
187
+ const id2 = box.get(RequestId);
188
+
189
+ console.log(id1 === id2); // false
192
190
  ```
193
191
 
192
+ ## Resolving multiple constructors
193
+
194
+ Use `box.all.get()` to resolve multiple constructors at once. Pass an object to get an object of instances, or an array to get an array of instances.
195
+
194
196
  ```ts
195
- // service.ts
196
197
  import { Box } from "getbox";
197
- import { Database } from "./database";
198
- import { Logger, LoggerFactory } from "./logger";
199
198
 
200
- export class UserService {
201
- constructor(
202
- private db: Database,
203
- private logger: Logger
204
- ) {}
199
+ const box = new Box();
200
+
201
+ // Object form
202
+ const { db, logger } = box.all.get({ db: Database, logger: LoggerFactory });
203
+
204
+ // Array form
205
+ const [db2, logger2] = box.all.get([Database, LoggerFactory]);
206
+
207
+ console.log(db === db2); // true (cached)
208
+ console.log(logger === logger2); // true (cached)
209
+ ```
210
+
211
+ Use `box.all.new()` to resolve multiple constructors as transient instances.
212
+
213
+ ```ts
214
+ const { db } = box.all.new({ db: Database });
215
+ const [db2] = box.all.new([Database]);
216
+
217
+ console.log(db === db2); // false (transient)
218
+ ```
219
+
220
+ ## Class constructors
221
+
222
+ Use `box.for()` inside a class's `static init` method to resolve constructor dependencies automatically. The instance returned by the builder is cached or transient depending on whether the class is retrieved via `box.get()` or `box.new()`.
223
+
224
+ ```ts
225
+ import { Box, factory } from "getbox";
226
+
227
+ class UserService {
228
+ constructor(private db: Database, private logger: Logger) {}
205
229
 
206
230
  static init(box: Box) {
207
231
  // Create new instance with cached dependencies
@@ -210,18 +234,10 @@ export class UserService {
210
234
 
211
235
  createUser(name: string) {
212
236
  this.logger.log(`Creating user: ${name}`);
213
- // Use db to save user
214
237
  }
215
238
  }
216
- ```
217
-
218
- ```ts
219
- // main.ts
220
- import { Box } from "getbox";
221
- import { UserService } from "./service";
222
239
 
223
240
  const box = new Box();
224
-
225
241
  const service = box.get(UserService);
226
242
  service.createUser("Alice");
227
243
  ```
@@ -245,7 +261,8 @@ class MockLogger implements Logger {
245
261
  }
246
262
 
247
263
  const box = new Box();
248
- Box.mock(box, LoggerFactory, new MockLogger());
264
+ const mockLogger = new MockLogger();
265
+ Box.mock(box, LoggerFactory, mockLogger);
249
266
 
250
267
  const service = box.get(UserService);
251
268
  service.createUser("Alice");
@@ -253,6 +270,23 @@ service.createUser("Alice");
253
270
  console.log(mockLogger.messages); // ["Creating user: Alice"]
254
271
  ```
255
272
 
273
+ ## Clearing the cache
274
+
275
+ Use `Box.clear` to remove cached instances. Pass a specific constructor to clear a single entry, or omit it to clear all cached instances.
276
+
277
+ ```ts
278
+ const box = new Box();
279
+
280
+ const db = box.get(Database);
281
+
282
+ // Clear a specific constructor
283
+ Box.clear(box, Database);
284
+ console.log(box.get(Database) === db); // false (new instance)
285
+
286
+ // Clear all cached instances
287
+ Box.clear(box);
288
+ ```
289
+
256
290
  ## Circular dependencies
257
291
 
258
292
  `getbox` does not prevent circular dependencies. You should structure your code to avoid circular imports between modules.
@@ -0,0 +1,42 @@
1
+ const require_index = require('./index.cjs');
2
+ let node_async_hooks = require("node:async_hooks");
3
+
4
+ //#region src/context.ts
5
+ const storage = new node_async_hooks.AsyncLocalStorage();
6
+ function withBox(boxOrFn, fn) {
7
+ if (typeof boxOrFn === "function") return storage.run(new require_index.Box(), boxOrFn);
8
+ return storage.run(boxOrFn, fn);
9
+ }
10
+ /**
11
+ * Returns the current {@link Box} from the active {@link withBox} scope.
12
+ * Throws if called outside a scope.
13
+ */
14
+ function useBox() {
15
+ const box = storage.getStore();
16
+ if (!box) throw new Error("useBox() must be called within a withBox() scope");
17
+ return box;
18
+ }
19
+ /**
20
+ * Resolves a cached instance from the current {@link withBox} scope.
21
+ * Shorthand for `useBox().get(constructor)`.
22
+ */
23
+ function resolve(constructor) {
24
+ return useBox().get(constructor);
25
+ }
26
+ function resolveAll(constructors) {
27
+ return useBox().all.get(constructors);
28
+ }
29
+ /**
30
+ * Returns a builder for creating a class instance with resolved constructor
31
+ * parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
32
+ */
33
+ function construct(constructor) {
34
+ return useBox().for(constructor);
35
+ }
36
+
37
+ //#endregion
38
+ exports.construct = construct;
39
+ exports.resolve = resolve;
40
+ exports.resolveAll = resolveAll;
41
+ exports.useBox = useBox;
42
+ exports.withBox = withBox;
@@ -0,0 +1,33 @@
1
+ import { Box, Construct, Constructor, ConstructorInstanceType } from "./index.cjs";
2
+
3
+ //#region src/context.d.ts
4
+
5
+ /**
6
+ * Runs a function within a scoped {@link Box} context using AsyncLocalStorage.
7
+ * Creates a fresh Box if none is provided.
8
+ */
9
+ declare function withBox<T>(fn: () => T): T;
10
+ declare function withBox<T>(box: Box, fn: () => T): T;
11
+ /**
12
+ * Returns the current {@link Box} from the active {@link withBox} scope.
13
+ * Throws if called outside a scope.
14
+ */
15
+ declare function useBox(): Box;
16
+ /**
17
+ * Resolves a cached instance from the current {@link withBox} scope.
18
+ * Shorthand for `useBox().get(constructor)`.
19
+ */
20
+ declare function resolve<T>(constructor: Constructor<T>): T;
21
+ /**
22
+ * Resolves multiple cached instances from the current {@link withBox} scope.
23
+ * Shorthand for `useBox().all.get(constructors)`.
24
+ */
25
+ declare function resolveAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
26
+ declare function resolveAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
27
+ /**
28
+ * Returns a builder for creating a class instance with resolved constructor
29
+ * parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
30
+ */
31
+ declare function construct<T extends new (...args: any) => any>(constructor: T): Construct<T>;
32
+ //#endregion
33
+ export { construct, resolve, resolveAll, useBox, withBox };
@@ -0,0 +1,33 @@
1
+ import { Box, Construct, Constructor, ConstructorInstanceType } from "./index.mjs";
2
+
3
+ //#region src/context.d.ts
4
+
5
+ /**
6
+ * Runs a function within a scoped {@link Box} context using AsyncLocalStorage.
7
+ * Creates a fresh Box if none is provided.
8
+ */
9
+ declare function withBox<T>(fn: () => T): T;
10
+ declare function withBox<T>(box: Box, fn: () => T): T;
11
+ /**
12
+ * Returns the current {@link Box} from the active {@link withBox} scope.
13
+ * Throws if called outside a scope.
14
+ */
15
+ declare function useBox(): Box;
16
+ /**
17
+ * Resolves a cached instance from the current {@link withBox} scope.
18
+ * Shorthand for `useBox().get(constructor)`.
19
+ */
20
+ declare function resolve<T>(constructor: Constructor<T>): T;
21
+ /**
22
+ * Resolves multiple cached instances from the current {@link withBox} scope.
23
+ * Shorthand for `useBox().all.get(constructors)`.
24
+ */
25
+ declare function resolveAll<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
26
+ declare function resolveAll<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
27
+ /**
28
+ * Returns a builder for creating a class instance with resolved constructor
29
+ * parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
30
+ */
31
+ declare function construct<T extends new (...args: any) => any>(constructor: T): Construct<T>;
32
+ //#endregion
33
+ export { construct, resolve, resolveAll, useBox, withBox };
@@ -0,0 +1,38 @@
1
+ import { Box } from "./index.mjs";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+
4
+ //#region src/context.ts
5
+ const storage = new AsyncLocalStorage();
6
+ function withBox(boxOrFn, fn) {
7
+ if (typeof boxOrFn === "function") return storage.run(new Box(), boxOrFn);
8
+ return storage.run(boxOrFn, fn);
9
+ }
10
+ /**
11
+ * Returns the current {@link Box} from the active {@link withBox} scope.
12
+ * Throws if called outside a scope.
13
+ */
14
+ function useBox() {
15
+ const box = storage.getStore();
16
+ if (!box) throw new Error("useBox() must be called within a withBox() scope");
17
+ return box;
18
+ }
19
+ /**
20
+ * Resolves a cached instance from the current {@link withBox} scope.
21
+ * Shorthand for `useBox().get(constructor)`.
22
+ */
23
+ function resolve(constructor) {
24
+ return useBox().get(constructor);
25
+ }
26
+ function resolveAll(constructors) {
27
+ return useBox().all.get(constructors);
28
+ }
29
+ /**
30
+ * Returns a builder for creating a class instance with resolved constructor
31
+ * parameters from the current {@link withBox} scope. Shorthand for `useBox().for(constructor)`.
32
+ */
33
+ function construct(constructor) {
34
+ return useBox().for(constructor);
35
+ }
36
+
37
+ //#endregion
38
+ export { construct, resolve, resolveAll, useBox, withBox };
package/dist/index.cjs CHANGED
@@ -1,38 +1,197 @@
1
1
 
2
2
  //#region src/index.ts
3
+ /**
4
+ * Creates a {@link Constructor} from a factory function.
5
+ * The factory receives the box as an argument, allowing it to resolve other dependencies.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const LoggerFactory = factory((box: Box): Logger => {
10
+ * return new ConsoleLogger();
11
+ * });
12
+ *
13
+ * const logger = box.get(LoggerFactory);
14
+ * ```
15
+ */
3
16
  function factory(init) {
4
17
  return { init };
5
18
  }
19
+ const noCacheSymbol = Symbol("Box constant");
20
+ /**
21
+ * Creates a {@link Constructor} from a factory function whose result is never cached.
22
+ * The factory is called on every resolution, always returning a fresh value
23
+ * even when retrieved via {@link Box.get}.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const RequestId = transient(() => crypto.randomUUID());
28
+ * const id1 = box.get(RequestId);
29
+ * const id2 = box.get(RequestId);
30
+ * console.log(id1 === id2); // false
31
+ * ```
32
+ */
33
+ function transient(init) {
34
+ return {
35
+ init,
36
+ [noCacheSymbol]: true
37
+ };
38
+ }
39
+ /**
40
+ * Creates a {@link Constructor} that always resolves to the given constant value.
41
+ * Constant values are never cached since they are already fixed.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * const ApiUrl = constant("https://api.example.com");
46
+ * const port = box.get(ApiUrl); // "https://api.example.com"
47
+ * ```
48
+ */
6
49
  function constant(value) {
7
- return { init: () => value };
50
+ return {
51
+ init: () => value,
52
+ [noCacheSymbol]: true
53
+ };
8
54
  }
55
+ /**
56
+ * Dependency injection container that resolves and caches instances from
57
+ * a {@link Constructor}.
58
+ *
59
+ * A constructor is an object with an `init(box: Box)` method,
60
+ * a class with a `static init(box: Box)` method, or a class with a
61
+ * no-argument constructor. The {@link factory} and {@link constant} helpers
62
+ * create constructors from functions and values respectively.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * class Database {
67
+ * connect() {}
68
+ * }
69
+ *
70
+ * class UserService {
71
+ * constructor(private db: Database) {}
72
+ * static init(box: Box) {
73
+ * return new UserService(box.get(Database));
74
+ * }
75
+ * }
76
+ *
77
+ * const box = new Box();
78
+ * const service = box.get(UserService);
79
+ * const db = box.get(Database);
80
+ *
81
+ * console.log(service.db === db); // true (cached)
82
+ * console.log(box.new(Database) === db); // false (transient)
83
+ * ```
84
+ */
9
85
  var Box = class {
10
86
  cache = /* @__PURE__ */ new Map();
87
+ /**
88
+ * Creates a new (transient) instance without caching. Useful for instances
89
+ * that should not be shared.
90
+ */
11
91
  new(constructor) {
12
92
  return "init" in constructor ? constructor.init(this) : new constructor();
13
93
  }
94
+ /**
95
+ * Resolves an instance from the cache, or creates and caches a new one.
96
+ * Subsequent calls with the same constructor return the cached instance.
97
+ */
14
98
  get(constructor) {
15
99
  if (this.cache.has(constructor)) return this.cache.get(constructor);
16
100
  const value = this.new(constructor);
17
- this.cache.set(constructor, value);
101
+ if (!(noCacheSymbol in constructor && constructor[noCacheSymbol])) this.cache.set(constructor, value);
18
102
  return value;
19
103
  }
104
+ /** Resolves multiple constructors at once. */
105
+ all = new BoxAll(this);
106
+ /**
107
+ * Returns a {@link Construct} builder for creating class instances by
108
+ * resolving constructors for each constructor parameter.
109
+ *
110
+ * Intended to be used inside a class's `static init` method. The instance
111
+ * returned by the builder is never cached itself, but can be cached when
112
+ * the class is retrieved via {@link Box.get} or kept transient via {@link Box.new}.
113
+ */
20
114
  for(constructor) {
21
115
  return new Construct(this, constructor);
22
116
  }
117
+ /**
118
+ * Registers a mock value in the box's cache for a given constructor.
119
+ * Useful for replacing dependencies in tests.
120
+ */
23
121
  static mock(box, constructor, value) {
24
122
  box.cache.set(constructor, value);
25
123
  }
124
+ /**
125
+ * Removes the instance from the box's cache for a given constructor.
126
+ * Removes all instances if no constructor is provided.
127
+ */
128
+ static clear(box, constructor) {
129
+ if (!constructor) return box.cache.clear();
130
+ box.cache.delete(constructor);
131
+ }
132
+ };
133
+ /** Resolves multiple constructors at once from a {@link Box}. */
134
+ var BoxAll = class {
135
+ constructor(box) {
136
+ this.box = box;
137
+ }
138
+ get(constructors) {
139
+ if (Array.isArray(constructors)) return constructors.map((c) => this.box.get(c));
140
+ const result = {};
141
+ for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.get(constructor);
142
+ return result;
143
+ }
144
+ new(constructors) {
145
+ if (Array.isArray(constructors)) return constructors.map((c) => this.box.new(c));
146
+ const result = {};
147
+ for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.new(constructor);
148
+ return result;
149
+ }
26
150
  };
151
+ /** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
27
152
  var Construct = class {
28
153
  constructor(box, construct) {
29
154
  this.box = box;
30
155
  this.construct = construct;
31
156
  }
157
+ /**
158
+ * Resolves each dependency as a new transient instance via {@link Box.new},
159
+ * meaning dependencies are not cached or shared.
160
+ *
161
+ * The returned instance is cached or transient depending on whether the
162
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * class UserService {
167
+ * constructor(private db: Database, private logger: Logger) {}
168
+ * static init(box: Box) {
169
+ * return box.for(UserService).new(Database, LoggerFactory);
170
+ * }
171
+ * }
172
+ * ```
173
+ */
32
174
  new(...args) {
33
175
  const instances = args.map((arg) => this.box.new(arg));
34
176
  return new this.construct(...instances);
35
177
  }
178
+ /**
179
+ * Resolves each dependency as a cached instance via {@link Box.get},
180
+ * meaning dependencies are shared across the box.
181
+ *
182
+ * The returned instance is cached or transient depending on whether the
183
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * class UserService {
188
+ * constructor(private db: Database, private logger: Logger) {}
189
+ * static init(box: Box) {
190
+ * return box.for(UserService).get(Database, LoggerFactory);
191
+ * }
192
+ * }
193
+ * ```
194
+ */
36
195
  get(...args) {
37
196
  const instances = args.map((arg) => this.box.get(arg));
38
197
  return new this.construct(...instances);
@@ -41,5 +200,7 @@ var Construct = class {
41
200
 
42
201
  //#endregion
43
202
  exports.Box = Box;
203
+ exports.Construct = Construct;
44
204
  exports.constant = constant;
45
- exports.factory = factory;
205
+ exports.factory = factory;
206
+ exports.transient = transient;
package/dist/index.d.cts CHANGED
@@ -1,29 +1,183 @@
1
1
  //#region src/index.d.ts
2
+ /**
3
+ * A type that can be resolved by a {@link Box}. Either an object with an
4
+ * `init(box: Box)` method, a class with a `static init(box: Box)` method
5
+ * that returns an instance, or a class with a no-argument constructor.
6
+ */
2
7
  type Constructor<T> = {
3
8
  init(box: Box): T;
4
9
  } | {
5
10
  new (): T;
6
11
  };
12
+ /** Extracts the instance type from a {@link Constructor}. */
7
13
  type ConstructorInstanceType<T> = T extends Constructor<infer U> ? U : never;
14
+ /**
15
+ * Creates a {@link Constructor} from a factory function.
16
+ * The factory receives the box as an argument, allowing it to resolve other dependencies.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const LoggerFactory = factory((box: Box): Logger => {
21
+ * return new ConsoleLogger();
22
+ * });
23
+ *
24
+ * const logger = box.get(LoggerFactory);
25
+ * ```
26
+ */
8
27
  declare function factory<T>(init: (box: Box) => T): Constructor<T>;
28
+ /**
29
+ * Creates a {@link Constructor} from a factory function whose result is never cached.
30
+ * The factory is called on every resolution, always returning a fresh value
31
+ * even when retrieved via {@link Box.get}.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const RequestId = transient(() => crypto.randomUUID());
36
+ * const id1 = box.get(RequestId);
37
+ * const id2 = box.get(RequestId);
38
+ * console.log(id1 === id2); // false
39
+ * ```
40
+ */
41
+ declare function transient<T>(init: (box: Box) => T): Constructor<T>;
42
+ /**
43
+ * Creates a {@link Constructor} that always resolves to the given constant value.
44
+ * Constant values are never cached since they are already fixed.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const ApiUrl = constant("https://api.example.com");
49
+ * const port = box.get(ApiUrl); // "https://api.example.com"
50
+ * ```
51
+ */
9
52
  declare function constant<const T>(value: T): Constructor<T>;
53
+ /**
54
+ * Dependency injection container that resolves and caches instances from
55
+ * a {@link Constructor}.
56
+ *
57
+ * A constructor is an object with an `init(box: Box)` method,
58
+ * a class with a `static init(box: Box)` method, or a class with a
59
+ * no-argument constructor. The {@link factory} and {@link constant} helpers
60
+ * create constructors from functions and values respectively.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * class Database {
65
+ * connect() {}
66
+ * }
67
+ *
68
+ * class UserService {
69
+ * constructor(private db: Database) {}
70
+ * static init(box: Box) {
71
+ * return new UserService(box.get(Database));
72
+ * }
73
+ * }
74
+ *
75
+ * const box = new Box();
76
+ * const service = box.get(UserService);
77
+ * const db = box.get(Database);
78
+ *
79
+ * console.log(service.db === db); // true (cached)
80
+ * console.log(box.new(Database) === db); // false (transient)
81
+ * ```
82
+ */
10
83
  declare class Box {
11
84
  private cache;
85
+ /**
86
+ * Creates a new (transient) instance without caching. Useful for instances
87
+ * that should not be shared.
88
+ */
12
89
  new<T>(constructor: Constructor<T>): T;
90
+ /**
91
+ * Resolves an instance from the cache, or creates and caches a new one.
92
+ * Subsequent calls with the same constructor return the cached instance.
93
+ */
13
94
  get<T>(constructor: Constructor<T>): T;
95
+ /** Resolves multiple constructors at once. */
96
+ readonly all: BoxAll;
97
+ /**
98
+ * Returns a {@link Construct} builder for creating class instances by
99
+ * resolving constructors for each constructor parameter.
100
+ *
101
+ * Intended to be used inside a class's `static init` method. The instance
102
+ * returned by the builder is never cached itself, but can be cached when
103
+ * the class is retrieved via {@link Box.get} or kept transient via {@link Box.new}.
104
+ */
14
105
  for<T extends ClassConstructor<any>>(constructor: T): Construct<T>;
106
+ /**
107
+ * Registers a mock value in the box's cache for a given constructor.
108
+ * Useful for replacing dependencies in tests.
109
+ */
15
110
  static mock<T, V extends T = T>(box: Box, constructor: Constructor<T>, value: V): void;
111
+ /**
112
+ * Removes the instance from the box's cache for a given constructor.
113
+ * Removes all instances if no constructor is provided.
114
+ */
115
+ static clear<T>(box: Box, constructor?: Constructor<T>): void;
16
116
  }
117
+ /** Resolves multiple constructors at once from a {@link Box}. */
118
+ declare class BoxAll {
119
+ private box;
120
+ constructor(box: Box);
121
+ /**
122
+ * Resolves each constructor as a cached instance via {@link Box.get}.
123
+ * Accepts an array or object of constructors and returns instances in the same shape.
124
+ */
125
+ get<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
126
+ get<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
127
+ /**
128
+ * Resolves each constructor as a new transient instance via {@link Box.new}.
129
+ * Accepts an array or object of constructors and returns instances in the same shape.
130
+ */
131
+ new<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
132
+ new<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
133
+ }
134
+ /** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
17
135
  declare class Construct<T extends ClassConstructor<any>> {
18
136
  private box;
19
137
  private construct;
20
138
  constructor(box: Box, construct: T);
139
+ /**
140
+ * Resolves each dependency as a new transient instance via {@link Box.new},
141
+ * meaning dependencies are not cached or shared.
142
+ *
143
+ * The returned instance is cached or transient depending on whether the
144
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * class UserService {
149
+ * constructor(private db: Database, private logger: Logger) {}
150
+ * static init(box: Box) {
151
+ * return box.for(UserService).new(Database, LoggerFactory);
152
+ * }
153
+ * }
154
+ * ```
155
+ */
21
156
  new(...args: ClassConstructorArgs<T>): InstanceType<T>;
157
+ /**
158
+ * Resolves each dependency as a cached instance via {@link Box.get},
159
+ * meaning dependencies are shared across the box.
160
+ *
161
+ * The returned instance is cached or transient depending on whether the
162
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * class UserService {
167
+ * constructor(private db: Database, private logger: Logger) {}
168
+ * static init(box: Box) {
169
+ * return box.for(UserService).get(Database, LoggerFactory);
170
+ * }
171
+ * }
172
+ * ```
173
+ */
22
174
  get(...args: ClassConstructorArgs<T>): InstanceType<T>;
23
175
  }
176
+ /** A class with any constructor signature. */
24
177
  type ClassConstructor<T> = {
25
178
  new (...args: any): T;
26
179
  };
180
+ /** Maps each constructor parameter to its corresponding {@link Constructor} type. */
27
181
  type ClassConstructorArgs<T extends ClassConstructor<any>, Args = ConstructorParameters<T>> = { [K in keyof Args]: Constructor<Args[K]> };
28
182
  //#endregion
29
- export { Box, Constructor, ConstructorInstanceType, constant, factory };
183
+ export { Box, Construct, Constructor, ConstructorInstanceType, constant, factory, transient };
package/dist/index.d.mts CHANGED
@@ -1,29 +1,183 @@
1
1
  //#region src/index.d.ts
2
+ /**
3
+ * A type that can be resolved by a {@link Box}. Either an object with an
4
+ * `init(box: Box)` method, a class with a `static init(box: Box)` method
5
+ * that returns an instance, or a class with a no-argument constructor.
6
+ */
2
7
  type Constructor<T> = {
3
8
  init(box: Box): T;
4
9
  } | {
5
10
  new (): T;
6
11
  };
12
+ /** Extracts the instance type from a {@link Constructor}. */
7
13
  type ConstructorInstanceType<T> = T extends Constructor<infer U> ? U : never;
14
+ /**
15
+ * Creates a {@link Constructor} from a factory function.
16
+ * The factory receives the box as an argument, allowing it to resolve other dependencies.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const LoggerFactory = factory((box: Box): Logger => {
21
+ * return new ConsoleLogger();
22
+ * });
23
+ *
24
+ * const logger = box.get(LoggerFactory);
25
+ * ```
26
+ */
8
27
  declare function factory<T>(init: (box: Box) => T): Constructor<T>;
28
+ /**
29
+ * Creates a {@link Constructor} from a factory function whose result is never cached.
30
+ * The factory is called on every resolution, always returning a fresh value
31
+ * even when retrieved via {@link Box.get}.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const RequestId = transient(() => crypto.randomUUID());
36
+ * const id1 = box.get(RequestId);
37
+ * const id2 = box.get(RequestId);
38
+ * console.log(id1 === id2); // false
39
+ * ```
40
+ */
41
+ declare function transient<T>(init: (box: Box) => T): Constructor<T>;
42
+ /**
43
+ * Creates a {@link Constructor} that always resolves to the given constant value.
44
+ * Constant values are never cached since they are already fixed.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const ApiUrl = constant("https://api.example.com");
49
+ * const port = box.get(ApiUrl); // "https://api.example.com"
50
+ * ```
51
+ */
9
52
  declare function constant<const T>(value: T): Constructor<T>;
53
+ /**
54
+ * Dependency injection container that resolves and caches instances from
55
+ * a {@link Constructor}.
56
+ *
57
+ * A constructor is an object with an `init(box: Box)` method,
58
+ * a class with a `static init(box: Box)` method, or a class with a
59
+ * no-argument constructor. The {@link factory} and {@link constant} helpers
60
+ * create constructors from functions and values respectively.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * class Database {
65
+ * connect() {}
66
+ * }
67
+ *
68
+ * class UserService {
69
+ * constructor(private db: Database) {}
70
+ * static init(box: Box) {
71
+ * return new UserService(box.get(Database));
72
+ * }
73
+ * }
74
+ *
75
+ * const box = new Box();
76
+ * const service = box.get(UserService);
77
+ * const db = box.get(Database);
78
+ *
79
+ * console.log(service.db === db); // true (cached)
80
+ * console.log(box.new(Database) === db); // false (transient)
81
+ * ```
82
+ */
10
83
  declare class Box {
11
84
  private cache;
85
+ /**
86
+ * Creates a new (transient) instance without caching. Useful for instances
87
+ * that should not be shared.
88
+ */
12
89
  new<T>(constructor: Constructor<T>): T;
90
+ /**
91
+ * Resolves an instance from the cache, or creates and caches a new one.
92
+ * Subsequent calls with the same constructor return the cached instance.
93
+ */
13
94
  get<T>(constructor: Constructor<T>): T;
95
+ /** Resolves multiple constructors at once. */
96
+ readonly all: BoxAll;
97
+ /**
98
+ * Returns a {@link Construct} builder for creating class instances by
99
+ * resolving constructors for each constructor parameter.
100
+ *
101
+ * Intended to be used inside a class's `static init` method. The instance
102
+ * returned by the builder is never cached itself, but can be cached when
103
+ * the class is retrieved via {@link Box.get} or kept transient via {@link Box.new}.
104
+ */
14
105
  for<T extends ClassConstructor<any>>(constructor: T): Construct<T>;
106
+ /**
107
+ * Registers a mock value in the box's cache for a given constructor.
108
+ * Useful for replacing dependencies in tests.
109
+ */
15
110
  static mock<T, V extends T = T>(box: Box, constructor: Constructor<T>, value: V): void;
111
+ /**
112
+ * Removes the instance from the box's cache for a given constructor.
113
+ * Removes all instances if no constructor is provided.
114
+ */
115
+ static clear<T>(box: Box, constructor?: Constructor<T>): void;
16
116
  }
117
+ /** Resolves multiple constructors at once from a {@link Box}. */
118
+ declare class BoxAll {
119
+ private box;
120
+ constructor(box: Box);
121
+ /**
122
+ * Resolves each constructor as a cached instance via {@link Box.get}.
123
+ * Accepts an array or object of constructors and returns instances in the same shape.
124
+ */
125
+ get<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
126
+ get<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
127
+ /**
128
+ * Resolves each constructor as a new transient instance via {@link Box.new}.
129
+ * Accepts an array or object of constructors and returns instances in the same shape.
130
+ */
131
+ new<const T extends Constructor<any>[]>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
132
+ new<T extends Record<string, Constructor<any>>>(constructors: T): { [K in keyof T]: ConstructorInstanceType<T[K]> };
133
+ }
134
+ /** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
17
135
  declare class Construct<T extends ClassConstructor<any>> {
18
136
  private box;
19
137
  private construct;
20
138
  constructor(box: Box, construct: T);
139
+ /**
140
+ * Resolves each dependency as a new transient instance via {@link Box.new},
141
+ * meaning dependencies are not cached or shared.
142
+ *
143
+ * The returned instance is cached or transient depending on whether the
144
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * class UserService {
149
+ * constructor(private db: Database, private logger: Logger) {}
150
+ * static init(box: Box) {
151
+ * return box.for(UserService).new(Database, LoggerFactory);
152
+ * }
153
+ * }
154
+ * ```
155
+ */
21
156
  new(...args: ClassConstructorArgs<T>): InstanceType<T>;
157
+ /**
158
+ * Resolves each dependency as a cached instance via {@link Box.get},
159
+ * meaning dependencies are shared across the box.
160
+ *
161
+ * The returned instance is cached or transient depending on whether the
162
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * class UserService {
167
+ * constructor(private db: Database, private logger: Logger) {}
168
+ * static init(box: Box) {
169
+ * return box.for(UserService).get(Database, LoggerFactory);
170
+ * }
171
+ * }
172
+ * ```
173
+ */
22
174
  get(...args: ClassConstructorArgs<T>): InstanceType<T>;
23
175
  }
176
+ /** A class with any constructor signature. */
24
177
  type ClassConstructor<T> = {
25
178
  new (...args: any): T;
26
179
  };
180
+ /** Maps each constructor parameter to its corresponding {@link Constructor} type. */
27
181
  type ClassConstructorArgs<T extends ClassConstructor<any>, Args = ConstructorParameters<T>> = { [K in keyof Args]: Constructor<Args[K]> };
28
182
  //#endregion
29
- export { Box, Constructor, ConstructorInstanceType, constant, factory };
183
+ export { Box, Construct, Constructor, ConstructorInstanceType, constant, factory, transient };
package/dist/index.mjs CHANGED
@@ -1,37 +1,196 @@
1
1
  //#region src/index.ts
2
+ /**
3
+ * Creates a {@link Constructor} from a factory function.
4
+ * The factory receives the box as an argument, allowing it to resolve other dependencies.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const LoggerFactory = factory((box: Box): Logger => {
9
+ * return new ConsoleLogger();
10
+ * });
11
+ *
12
+ * const logger = box.get(LoggerFactory);
13
+ * ```
14
+ */
2
15
  function factory(init) {
3
16
  return { init };
4
17
  }
18
+ const noCacheSymbol = Symbol("Box constant");
19
+ /**
20
+ * Creates a {@link Constructor} from a factory function whose result is never cached.
21
+ * The factory is called on every resolution, always returning a fresh value
22
+ * even when retrieved via {@link Box.get}.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const RequestId = transient(() => crypto.randomUUID());
27
+ * const id1 = box.get(RequestId);
28
+ * const id2 = box.get(RequestId);
29
+ * console.log(id1 === id2); // false
30
+ * ```
31
+ */
32
+ function transient(init) {
33
+ return {
34
+ init,
35
+ [noCacheSymbol]: true
36
+ };
37
+ }
38
+ /**
39
+ * Creates a {@link Constructor} that always resolves to the given constant value.
40
+ * Constant values are never cached since they are already fixed.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const ApiUrl = constant("https://api.example.com");
45
+ * const port = box.get(ApiUrl); // "https://api.example.com"
46
+ * ```
47
+ */
5
48
  function constant(value) {
6
- return { init: () => value };
49
+ return {
50
+ init: () => value,
51
+ [noCacheSymbol]: true
52
+ };
7
53
  }
54
+ /**
55
+ * Dependency injection container that resolves and caches instances from
56
+ * a {@link Constructor}.
57
+ *
58
+ * A constructor is an object with an `init(box: Box)` method,
59
+ * a class with a `static init(box: Box)` method, or a class with a
60
+ * no-argument constructor. The {@link factory} and {@link constant} helpers
61
+ * create constructors from functions and values respectively.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * class Database {
66
+ * connect() {}
67
+ * }
68
+ *
69
+ * class UserService {
70
+ * constructor(private db: Database) {}
71
+ * static init(box: Box) {
72
+ * return new UserService(box.get(Database));
73
+ * }
74
+ * }
75
+ *
76
+ * const box = new Box();
77
+ * const service = box.get(UserService);
78
+ * const db = box.get(Database);
79
+ *
80
+ * console.log(service.db === db); // true (cached)
81
+ * console.log(box.new(Database) === db); // false (transient)
82
+ * ```
83
+ */
8
84
  var Box = class {
9
85
  cache = /* @__PURE__ */ new Map();
86
+ /**
87
+ * Creates a new (transient) instance without caching. Useful for instances
88
+ * that should not be shared.
89
+ */
10
90
  new(constructor) {
11
91
  return "init" in constructor ? constructor.init(this) : new constructor();
12
92
  }
93
+ /**
94
+ * Resolves an instance from the cache, or creates and caches a new one.
95
+ * Subsequent calls with the same constructor return the cached instance.
96
+ */
13
97
  get(constructor) {
14
98
  if (this.cache.has(constructor)) return this.cache.get(constructor);
15
99
  const value = this.new(constructor);
16
- this.cache.set(constructor, value);
100
+ if (!(noCacheSymbol in constructor && constructor[noCacheSymbol])) this.cache.set(constructor, value);
17
101
  return value;
18
102
  }
103
+ /** Resolves multiple constructors at once. */
104
+ all = new BoxAll(this);
105
+ /**
106
+ * Returns a {@link Construct} builder for creating class instances by
107
+ * resolving constructors for each constructor parameter.
108
+ *
109
+ * Intended to be used inside a class's `static init` method. The instance
110
+ * returned by the builder is never cached itself, but can be cached when
111
+ * the class is retrieved via {@link Box.get} or kept transient via {@link Box.new}.
112
+ */
19
113
  for(constructor) {
20
114
  return new Construct(this, constructor);
21
115
  }
116
+ /**
117
+ * Registers a mock value in the box's cache for a given constructor.
118
+ * Useful for replacing dependencies in tests.
119
+ */
22
120
  static mock(box, constructor, value) {
23
121
  box.cache.set(constructor, value);
24
122
  }
123
+ /**
124
+ * Removes the instance from the box's cache for a given constructor.
125
+ * Removes all instances if no constructor is provided.
126
+ */
127
+ static clear(box, constructor) {
128
+ if (!constructor) return box.cache.clear();
129
+ box.cache.delete(constructor);
130
+ }
131
+ };
132
+ /** Resolves multiple constructors at once from a {@link Box}. */
133
+ var BoxAll = class {
134
+ constructor(box) {
135
+ this.box = box;
136
+ }
137
+ get(constructors) {
138
+ if (Array.isArray(constructors)) return constructors.map((c) => this.box.get(c));
139
+ const result = {};
140
+ for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.get(constructor);
141
+ return result;
142
+ }
143
+ new(constructors) {
144
+ if (Array.isArray(constructors)) return constructors.map((c) => this.box.new(c));
145
+ const result = {};
146
+ for (const [key, constructor] of Object.entries(constructors)) result[key] = this.box.new(constructor);
147
+ return result;
148
+ }
25
149
  };
150
+ /** Builder for creating class instances with constructor dependencies resolved from a {@link Box}. */
26
151
  var Construct = class {
27
152
  constructor(box, construct) {
28
153
  this.box = box;
29
154
  this.construct = construct;
30
155
  }
156
+ /**
157
+ * Resolves each dependency as a new transient instance via {@link Box.new},
158
+ * meaning dependencies are not cached or shared.
159
+ *
160
+ * The returned instance is cached or transient depending on whether the
161
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * class UserService {
166
+ * constructor(private db: Database, private logger: Logger) {}
167
+ * static init(box: Box) {
168
+ * return box.for(UserService).new(Database, LoggerFactory);
169
+ * }
170
+ * }
171
+ * ```
172
+ */
31
173
  new(...args) {
32
174
  const instances = args.map((arg) => this.box.new(arg));
33
175
  return new this.construct(...instances);
34
176
  }
177
+ /**
178
+ * Resolves each dependency as a cached instance via {@link Box.get},
179
+ * meaning dependencies are shared across the box.
180
+ *
181
+ * The returned instance is cached or transient depending on whether the
182
+ * class is retrieved via {@link Box.get} or {@link Box.new}.
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * class UserService {
187
+ * constructor(private db: Database, private logger: Logger) {}
188
+ * static init(box: Box) {
189
+ * return box.for(UserService).get(Database, LoggerFactory);
190
+ * }
191
+ * }
192
+ * ```
193
+ */
35
194
  get(...args) {
36
195
  const instances = args.map((arg) => this.box.get(arg));
37
196
  return new this.construct(...instances);
@@ -39,4 +198,4 @@ var Construct = class {
39
198
  };
40
199
 
41
200
  //#endregion
42
- export { Box, constant, factory };
201
+ export { Box, Construct, constant, factory, transient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getbox",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Lightweight dependency injection for TypeScript",
5
5
  "private": false,
6
6
  "main": "./dist/index.cjs",
@@ -16,15 +16,18 @@
16
16
  "types": "./dist/index.d.cts",
17
17
  "default": "./dist/index.cjs"
18
18
  }
19
+ },
20
+ "./context": {
21
+ "import": {
22
+ "types": "./dist/context.d.mts",
23
+ "default": "./dist/context.mjs"
24
+ },
25
+ "require": {
26
+ "types": "./dist/context.d.cts",
27
+ "default": "./dist/context.cjs"
28
+ }
19
29
  }
20
30
  },
21
- "scripts": {
22
- "build": "tsc && tsdown src/index.ts --format esm,cjs",
23
- "release": "pnpm run build && changeset publish",
24
- "watch": "vitest",
25
- "test": "vitest run",
26
- "test:coverage": "vitest run --coverage"
27
- },
28
31
  "keywords": [
29
32
  "DI",
30
33
  "dependency injection",
@@ -44,9 +47,17 @@
44
47
  "homepage": "https://github.com/eriicafes/getbox#readme",
45
48
  "devDependencies": {
46
49
  "@changesets/cli": "^2.29.8",
50
+ "@types/node": "^25.2.3",
47
51
  "@vitest/coverage-v8": "^4.0.16",
48
52
  "tsdown": "^0.18.3",
49
53
  "typescript": "^5.9.3",
50
54
  "vitest": "^4.0.16"
55
+ },
56
+ "scripts": {
57
+ "build": "tsc && tsdown src/index.ts src/context.ts --format esm,cjs",
58
+ "release": "pnpm run build && changeset publish",
59
+ "watch": "vitest",
60
+ "test": "vitest run",
61
+ "test:coverage": "vitest run --coverage"
51
62
  }
52
- }
63
+ }