@streetjs/container 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +78 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/dist/container.d.ts +23 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +78 -0
- package/dist/container.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/package.json +89 -0
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Architecture — @streetjs/container
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`@streetjs/container` is the StreetJS inversion-of-control core: a small,
|
|
6
|
+
dependency-injection container that other framework layers (controllers,
|
|
7
|
+
services, repositories, CLI kernels) use to wire their dependency graphs. It has
|
|
8
|
+
a single runtime dependency, `reflect-metadata`, and no coupling to HTTP,
|
|
9
|
+
databases, or any other subsystem.
|
|
10
|
+
|
|
11
|
+
## Design
|
|
12
|
+
|
|
13
|
+
### A single process-wide singleton
|
|
14
|
+
|
|
15
|
+
`Container` has a private constructor and a static `instance`. Consumers reach
|
|
16
|
+
it via `Container.getInstance()` or the exported `container` binding. A single
|
|
17
|
+
registry means a resolved dependency is shared everywhere it is injected — the
|
|
18
|
+
framework's services are effectively singletons by default.
|
|
19
|
+
|
|
20
|
+
Internally the container keeps two maps/sets:
|
|
21
|
+
|
|
22
|
+
- `singletons: Map<Constructor, object>` — resolved (or pre-registered) instances.
|
|
23
|
+
- `resolving: Set<Constructor>` — the tokens currently on the resolution stack,
|
|
24
|
+
used for cycle detection.
|
|
25
|
+
|
|
26
|
+
### Resolution algorithm
|
|
27
|
+
|
|
28
|
+
`resolve(token)`:
|
|
29
|
+
|
|
30
|
+
1. Return the cached singleton if present.
|
|
31
|
+
2. If `token` is already in `resolving`, throw a **circular dependency** error
|
|
32
|
+
annotated with the full resolution chain.
|
|
33
|
+
3. Add `token` to `resolving`, then read its constructor parameter types from
|
|
34
|
+
the `design:paramtypes` metadata that `emitDecoratorMetadata` emits.
|
|
35
|
+
4. Recursively `resolve` each parameter:
|
|
36
|
+
- A missing type or `Object` (interfaces, primitives, undecorated unions
|
|
37
|
+
erase to these) is unresolvable — throw a descriptive error naming the
|
|
38
|
+
chain and pointing at `emitDecoratorMetadata`/`@Injectable`.
|
|
39
|
+
- If a nested resolution throws, wrap the message with the chain — unless it
|
|
40
|
+
is already chain-annotated, in which case it is rethrown unchanged to avoid
|
|
41
|
+
double-wrapping.
|
|
42
|
+
5. Construct the instance, cache it, and remove `token` from `resolving` in a
|
|
43
|
+
`finally` so a failed resolution never leaves stale state.
|
|
44
|
+
|
|
45
|
+
### `@Injectable()`
|
|
46
|
+
|
|
47
|
+
The decorator writes a marker symbol via `Reflect.defineMetadata`. Its more
|
|
48
|
+
important side effect is enabling TypeScript to emit `design:paramtypes` for the
|
|
49
|
+
class — the metadata the resolver depends on.
|
|
50
|
+
|
|
51
|
+
### The `Constructor` type
|
|
52
|
+
|
|
53
|
+
`Constructor<T> = new (...args: any[]) => T` is the token type used throughout.
|
|
54
|
+
It lives here and is re-exported by the `streetjs` framework's `core/types.ts`,
|
|
55
|
+
keeping a single definition (dependency inversion, matching how `IpcMessage` and
|
|
56
|
+
`TelemetrySample` are sourced from their own packages).
|
|
57
|
+
|
|
58
|
+
## Relationship to core
|
|
59
|
+
|
|
60
|
+
The framework's `src/core/container.ts` re-exports this package verbatim, and
|
|
61
|
+
`src/core/types.ts` re-exports `Constructor` from it. Core's
|
|
62
|
+
`prebuild`/`prebuild:app` hooks compile this package before core, and the
|
|
63
|
+
Dockerfile builds it and dereferences the workspace symlink into the runtime
|
|
64
|
+
image.
|
|
65
|
+
|
|
66
|
+
## Testing
|
|
67
|
+
|
|
68
|
+
The suite runs with no external services: singleton identity, constructor
|
|
69
|
+
injection with shared sub-dependencies, cycle detection (via explicit
|
|
70
|
+
`design:paramtypes` metadata to avoid forward-reference temporal-dead-zones),
|
|
71
|
+
unresolvable-interface errors, failed-construction wrapping, and `reset`
|
|
72
|
+
semantics. Branch coverage is ≥96%.
|
|
73
|
+
|
|
74
|
+
## Non-goals
|
|
75
|
+
|
|
76
|
+
- No scopes/lifetimes beyond the process singleton (no request/transient scopes).
|
|
77
|
+
- No property or method injection — constructor injection only.
|
|
78
|
+
- No async factories or conditional bindings.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@streetjs/container` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial standalone release of the StreetJS dependency injection container,
|
|
13
|
+
extracted verbatim from the `streetjs` core (`src/core/container.ts`).
|
|
14
|
+
- `Container` singleton with `resolve`, `register`, `has`, and `reset`, plus the
|
|
15
|
+
exported `container` instance and `Container.getInstance()`.
|
|
16
|
+
- Constructor-injection resolution driven by `design:paramtypes` metadata, with
|
|
17
|
+
singleton caching across the dependency graph.
|
|
18
|
+
- Circular-dependency detection reporting the full resolution chain.
|
|
19
|
+
- Descriptive errors for unresolvable (interface/primitive/undecorated)
|
|
20
|
+
dependencies, with chain-aware wrapping that avoids double annotation.
|
|
21
|
+
- `@Injectable()` class decorator.
|
|
22
|
+
- `Constructor<T>` type utility (also re-exported by the framework core).
|
|
23
|
+
- `reflect-metadata` as the sole runtime dependency; ESM.
|
|
24
|
+
- ≥96% branch coverage and a runnable integration example.
|
|
25
|
+
|
|
26
|
+
[1.0.0]: https://github.com/hassanmubiru/StreetJS/releases/tag/container-v1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 street contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# @streetjs/container
|
|
2
|
+
|
|
3
|
+
The StreetJS dependency injection container: a process-wide singleton IoC
|
|
4
|
+
registry that resolves constructor-injected dependency trees, detects circular
|
|
5
|
+
dependencies, and exposes an `@Injectable()` class decorator. ESM,
|
|
6
|
+
strict-TypeScript, backed by `reflect-metadata`.
|
|
7
|
+
|
|
8
|
+
This is the standalone home of the container that also backs the `streetjs`
|
|
9
|
+
framework. The framework re-exports this package, so there is a single source of
|
|
10
|
+
truth.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @streetjs/container reflect-metadata
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Import `reflect-metadata` **once** at your application entry point, and enable
|
|
19
|
+
decorator metadata in your `tsconfig.json`:
|
|
20
|
+
|
|
21
|
+
```jsonc
|
|
22
|
+
{
|
|
23
|
+
"compilerOptions": {
|
|
24
|
+
"experimentalDecorators": true,
|
|
25
|
+
"emitDecoratorMetadata": true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import 'reflect-metadata';
|
|
34
|
+
import { Injectable, container } from '@streetjs/container';
|
|
35
|
+
|
|
36
|
+
@Injectable()
|
|
37
|
+
class Database {
|
|
38
|
+
query(sql: string) { /* ... */ }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Injectable()
|
|
42
|
+
class UserService {
|
|
43
|
+
constructor(private readonly db: Database) {}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Database is constructed once and injected as a singleton.
|
|
47
|
+
const users = container.resolve(UserService);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### `@Injectable()`
|
|
53
|
+
|
|
54
|
+
Class decorator that marks a class as participating in DI. Applying it also
|
|
55
|
+
triggers TypeScript's `design:paramtypes` metadata emission, which the container
|
|
56
|
+
reads to discover constructor dependencies.
|
|
57
|
+
|
|
58
|
+
### `container` / `Container`
|
|
59
|
+
|
|
60
|
+
A single shared `Container` instance is exported as `container`
|
|
61
|
+
(`Container.getInstance()` returns the same singleton).
|
|
62
|
+
|
|
63
|
+
| Method | Description |
|
|
64
|
+
| ------ | ----------- |
|
|
65
|
+
| `resolve(token)` | Return the singleton for `token`, constructing it and its dependency tree on first use. |
|
|
66
|
+
| `register(token, instance)` | Register a pre-built instance so `resolve(token)` returns it. |
|
|
67
|
+
| `has(token)` | `true` if the token has been resolved or registered. |
|
|
68
|
+
| `reset()` | Clear all instances — primarily for tests. |
|
|
69
|
+
|
|
70
|
+
### Circular-dependency detection
|
|
71
|
+
|
|
72
|
+
If resolution re-enters a token already on the resolution stack, `resolve`
|
|
73
|
+
throws with the full chain (`A -> B -> A`) instead of overflowing the stack.
|
|
74
|
+
|
|
75
|
+
### Unresolvable dependencies
|
|
76
|
+
|
|
77
|
+
A constructor parameter typed as an interface, a primitive, or an
|
|
78
|
+
un-`@Injectable` value erases to `Object`/undefined in emitted metadata. The
|
|
79
|
+
container throws a clear error naming the resolution chain and suggesting you
|
|
80
|
+
enable `emitDecoratorMetadata` and decorate the dependency.
|
|
81
|
+
|
|
82
|
+
## Example
|
|
83
|
+
|
|
84
|
+
A complete runnable example lives in
|
|
85
|
+
[`src/examples/integration.ts`](./src/examples/integration.ts):
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm run example -w packages/container
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import type { Constructor } from './types.js';
|
|
3
|
+
/** Mark a class as injectable and register its dependencies */
|
|
4
|
+
export declare function Injectable(): ClassDecorator;
|
|
5
|
+
/** Container manages singleton instances and resolves dependency trees */
|
|
6
|
+
export declare class Container {
|
|
7
|
+
private static readonly instance;
|
|
8
|
+
private readonly singletons;
|
|
9
|
+
private readonly resolving;
|
|
10
|
+
private constructor();
|
|
11
|
+
static getInstance(): Container;
|
|
12
|
+
/** Register a pre-built instance */
|
|
13
|
+
register<T extends object>(token: Constructor<T>, instance: T): void;
|
|
14
|
+
/** Resolve a class, creating it if not already instantiated */
|
|
15
|
+
resolve<T extends object>(token: Constructor<T>): T;
|
|
16
|
+
/** Remove all registered instances (useful in tests) */
|
|
17
|
+
reset(): void;
|
|
18
|
+
/** Check if a token has been resolved or registered */
|
|
19
|
+
has(token: Constructor): boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Global container singleton */
|
|
22
|
+
export declare const container: Container;
|
|
23
|
+
//# sourceMappingURL=container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,+DAA+D;AAC/D,wBAAgB,UAAU,IAAI,cAAc,CAI3C;AAED,0EAA0E;AAC1E,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAEnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IAEpD,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,SAAS;IAI/B,oCAAoC;IACpC,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAIpE,+DAA+D;IAC/D,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC;IAkDnD,wDAAwD;IACxD,KAAK,IAAI,IAAI;IAKb,uDAAuD;IACvD,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO;CAGjC;AAED,iCAAiC;AACjC,eAAO,MAAM,SAAS,WAA0B,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// src/container.ts
|
|
2
|
+
// Dependency injection container with singleton registry and circular dep detection.
|
|
3
|
+
import 'reflect-metadata';
|
|
4
|
+
const INJECTABLE_META = Symbol('street:injectable');
|
|
5
|
+
/** Mark a class as injectable and register its dependencies */
|
|
6
|
+
export function Injectable() {
|
|
7
|
+
return (target) => {
|
|
8
|
+
Reflect.defineMetadata(INJECTABLE_META, true, target);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** Container manages singleton instances and resolves dependency trees */
|
|
12
|
+
export class Container {
|
|
13
|
+
static instance = new Container();
|
|
14
|
+
singletons = new Map();
|
|
15
|
+
resolving = new Set();
|
|
16
|
+
constructor() { }
|
|
17
|
+
static getInstance() {
|
|
18
|
+
return Container.instance;
|
|
19
|
+
}
|
|
20
|
+
/** Register a pre-built instance */
|
|
21
|
+
register(token, instance) {
|
|
22
|
+
this.singletons.set(token, instance);
|
|
23
|
+
}
|
|
24
|
+
/** Resolve a class, creating it if not already instantiated */
|
|
25
|
+
resolve(token) {
|
|
26
|
+
const existing = this.singletons.get(token);
|
|
27
|
+
if (existing) {
|
|
28
|
+
return existing;
|
|
29
|
+
}
|
|
30
|
+
if (this.resolving.has(token)) {
|
|
31
|
+
throw new Error(`Circular dependency detected while resolving: ${token.name}. ` +
|
|
32
|
+
`Resolution chain: ${[...this.resolving].map((c) => c.name).join(' -> ')} -> ${token.name}`);
|
|
33
|
+
}
|
|
34
|
+
this.resolving.add(token);
|
|
35
|
+
try {
|
|
36
|
+
const paramTypes = Reflect.getMetadata('design:paramtypes', token) ?? [];
|
|
37
|
+
const deps = paramTypes.map((dep) => {
|
|
38
|
+
if (!dep || dep === Object) {
|
|
39
|
+
const chain = [...this.resolving].map((c) => c.name);
|
|
40
|
+
chain.push(token.name);
|
|
41
|
+
throw new Error(`Cannot resolve ${chain.join(' → ')}: got primitive or undefined type. ` +
|
|
42
|
+
`Ensure emitDecoratorMetadata is enabled and the dependency is decorated with @Injectable.`);
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
return this.resolve(dep);
|
|
46
|
+
}
|
|
47
|
+
catch (inner) {
|
|
48
|
+
const chain = [...this.resolving].map((c) => c.name);
|
|
49
|
+
chain.push(dep.name);
|
|
50
|
+
const reason = inner instanceof Error ? inner.message : String(inner);
|
|
51
|
+
// Only wrap if the message doesn't already contain a chain annotation
|
|
52
|
+
if (reason.includes(' → ') || reason.startsWith('Cannot resolve ')) {
|
|
53
|
+
throw inner;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Cannot resolve ${chain.join(' → ')}: ${reason}`);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const instance = new token(...deps);
|
|
59
|
+
this.singletons.set(token, instance);
|
|
60
|
+
return instance;
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
this.resolving.delete(token);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Remove all registered instances (useful in tests) */
|
|
67
|
+
reset() {
|
|
68
|
+
this.singletons.clear();
|
|
69
|
+
this.resolving.clear();
|
|
70
|
+
}
|
|
71
|
+
/** Check if a token has been resolved or registered */
|
|
72
|
+
has(token) {
|
|
73
|
+
return this.singletons.has(token);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Global container singleton */
|
|
77
|
+
export const container = Container.getInstance();
|
|
78
|
+
//# sourceMappingURL=container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streetjs/container — the StreetJS dependency injection container.
|
|
3
|
+
*
|
|
4
|
+
* A process-wide singleton IoC registry that resolves constructor-injected
|
|
5
|
+
* dependency trees from `design:paramtypes` metadata, detects circular
|
|
6
|
+
* dependencies, and exposes an `@Injectable()` class decorator. Backed by
|
|
7
|
+
* `reflect-metadata`.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import 'reflect-metadata';
|
|
11
|
+
* import { Injectable, container } from '@streetjs/container';
|
|
12
|
+
*
|
|
13
|
+
* @Injectable() class Db {}
|
|
14
|
+
* @Injectable() class UserService { constructor(readonly db: Db) {} }
|
|
15
|
+
*
|
|
16
|
+
* const svc = container.resolve(UserService); // db injected as a singleton
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* > This is the standalone home of the container that also backs the `streetjs`
|
|
20
|
+
* > framework; the framework re-exports it, so there is a single implementation.
|
|
21
|
+
*/
|
|
22
|
+
export { Container, Injectable, container } from './container.js';
|
|
23
|
+
export type { Constructor } from './types.js';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streetjs/container — the StreetJS dependency injection container.
|
|
3
|
+
*
|
|
4
|
+
* A process-wide singleton IoC registry that resolves constructor-injected
|
|
5
|
+
* dependency trees from `design:paramtypes` metadata, detects circular
|
|
6
|
+
* dependencies, and exposes an `@Injectable()` class decorator. Backed by
|
|
7
|
+
* `reflect-metadata`.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import 'reflect-metadata';
|
|
11
|
+
* import { Injectable, container } from '@streetjs/container';
|
|
12
|
+
*
|
|
13
|
+
* @Injectable() class Db {}
|
|
14
|
+
* @Injectable() class UserService { constructor(readonly db: Db) {} }
|
|
15
|
+
*
|
|
16
|
+
* const svc = container.resolve(UserService); // db injected as a singleton
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* > This is the standalone home of the container that also backs the `streetjs`
|
|
20
|
+
* > framework; the framework re-exports it, so there is a single implementation.
|
|
21
|
+
*/
|
|
22
|
+
export { Container, Injectable, container } from './container.js';
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,MAAM,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,8CAA8C"}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@streetjs/container",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "StreetJS dependency injection container: a singleton IoC registry with constructor-injection resolution, circular-dependency detection, and an @Injectable decorator. Backed by reflect-metadata.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/**/*.js",
|
|
16
|
+
"dist/**/*.js.map",
|
|
17
|
+
"dist/**/*.d.ts",
|
|
18
|
+
"dist/**/*.d.ts.map",
|
|
19
|
+
"!dist/**/*.test.js",
|
|
20
|
+
"!dist/**/*.test.js.map",
|
|
21
|
+
"!dist/**/*.test.d.ts",
|
|
22
|
+
"!dist/**/*.test.d.ts.map",
|
|
23
|
+
"!dist/tests/**",
|
|
24
|
+
"!dist/examples/**",
|
|
25
|
+
"README.md",
|
|
26
|
+
"ARCHITECTURE.md",
|
|
27
|
+
"CHANGELOG.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"c8": {
|
|
31
|
+
"include": ["dist/**/*.js"],
|
|
32
|
+
"exclude": ["dist/tests/**", "dist/examples/**", "dist/types.js"],
|
|
33
|
+
"reporter": ["text", "lcov"],
|
|
34
|
+
"all": true,
|
|
35
|
+
"check-coverage": true,
|
|
36
|
+
"lines": 90,
|
|
37
|
+
"functions": 90,
|
|
38
|
+
"branches": 90,
|
|
39
|
+
"statements": 90
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"test": "node --test dist/tests/*.test.js",
|
|
44
|
+
"coverage": "c8 node --test dist/tests/*.test.js",
|
|
45
|
+
"example": "node dist/examples/integration.js",
|
|
46
|
+
"lint": "tsc --noEmit",
|
|
47
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"streetjs",
|
|
51
|
+
"street-framework",
|
|
52
|
+
"dependency-injection",
|
|
53
|
+
"di",
|
|
54
|
+
"ioc",
|
|
55
|
+
"container",
|
|
56
|
+
"inversion-of-control",
|
|
57
|
+
"injectable",
|
|
58
|
+
"reflect-metadata",
|
|
59
|
+
"typescript",
|
|
60
|
+
"esm"
|
|
61
|
+
],
|
|
62
|
+
"author": "street contributors",
|
|
63
|
+
"license": "MIT",
|
|
64
|
+
"homepage": "https://hassanmubiru.github.io/StreetJS/",
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/hassanmubiru/StreetJS.git"
|
|
68
|
+
},
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/hassanmubiru/StreetJS/issues"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"reflect-metadata": "^0.2.2"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@types/node": "^26.1.0",
|
|
77
|
+
"c8": "^11.0.0",
|
|
78
|
+
"typescript": "^6.0.3"
|
|
79
|
+
},
|
|
80
|
+
"peerDependencies": {
|
|
81
|
+
"typescript": ">=5.0.0"
|
|
82
|
+
},
|
|
83
|
+
"engines": {
|
|
84
|
+
"node": ">=22.0.0"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
}
|
|
89
|
+
}
|