exisjs 0.7.0 → 0.7.1
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 +9 -3
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +4 -3
- package/dist/config/config.js.map +1 -1
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +3 -2
- package/dist/config/env.js.map +1 -1
- package/dist/decorators/constants.d.ts +7 -0
- package/dist/decorators/constants.d.ts.map +1 -1
- package/dist/decorators/constants.js +2 -1
- package/dist/decorators/constants.js.map +1 -1
- package/dist/decorators/core/metadata.d.ts +31 -0
- package/dist/decorators/core/metadata.d.ts.map +1 -1
- package/dist/decorators/core/metadata.js +110 -1
- package/dist/decorators/core/metadata.js.map +1 -1
- package/dist/decorators/core.d.ts +16 -2
- package/dist/decorators/core.d.ts.map +1 -1
- package/dist/decorators/core.js +22 -0
- package/dist/decorators/core.js.map +1 -1
- package/dist/decorators/middleware.d.ts +17 -7
- package/dist/decorators/middleware.d.ts.map +1 -1
- package/dist/decorators/middleware.js +111 -183
- package/dist/decorators/middleware.js.map +1 -1
- package/dist/decorators/params.d.ts +54 -12
- package/dist/decorators/params.d.ts.map +1 -1
- package/dist/decorators/params.js +40 -20
- package/dist/decorators/params.js.map +1 -1
- package/dist/decorators/routing.d.ts.map +1 -1
- package/dist/decorators/routing.js +2 -1
- package/dist/decorators/routing.js.map +1 -1
- package/dist/di/container.d.ts +5 -1
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/container.js +56 -8
- package/dist/di/container.js.map +1 -1
- package/dist/di/decorators.d.ts +30 -0
- package/dist/di/decorators.d.ts.map +1 -0
- package/dist/di/decorators.js +59 -0
- package/dist/di/decorators.js.map +1 -0
- package/dist/di/index.d.ts +1 -0
- package/dist/di/index.d.ts.map +1 -1
- package/dist/di/index.js +4 -1
- package/dist/di/index.js.map +1 -1
- package/dist/di/inject.d.ts +2 -1
- package/dist/di/inject.d.ts.map +1 -1
- package/dist/di/inject.js.map +1 -1
- package/dist/docs/content/decorators.mdx +44 -10
- package/dist/docs/content/modules.mdx +22 -1
- package/dist/docs/content/providers.mdx +33 -1
- package/dist/docs/reference/decorators.mdx +14 -3
- package/dist/docs/reference/di.mdx +35 -11
- package/dist/docs/reference/logger.mdx +100 -0
- package/dist/docs/reference/router.mdx +9 -9
- package/dist/error/errors.d.ts.map +1 -1
- package/dist/error/errors.js +3 -5
- package/dist/error/errors.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/index.js.map +1 -1
- package/dist/middleware/rate-limit.d.ts +0 -2
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +2 -14
- package/dist/middleware/rate-limit.js.map +1 -1
- package/dist/module/index.d.ts +2 -0
- package/dist/module/index.d.ts.map +1 -1
- package/dist/module/index.js +3 -1
- package/dist/module/index.js.map +1 -1
- package/dist/plugin/manager.d.ts +1 -1
- package/dist/plugin/manager.d.ts.map +1 -1
- package/dist/plugin/manager.js +47 -0
- package/dist/plugin/manager.js.map +1 -1
- package/dist/router/controller-registrar.d.ts.map +1 -1
- package/dist/router/controller-registrar.js +33 -6
- package/dist/router/controller-registrar.js.map +1 -1
- package/dist/router/route-builder.d.ts.map +1 -1
- package/dist/router/route-builder.js +2 -1
- package/dist/router/route-builder.js.map +1 -1
- package/dist/router/route-scanner.d.ts.map +1 -1
- package/dist/router/route-scanner.js +10 -11
- package/dist/router/route-scanner.js.map +1 -1
- package/dist/server/app.d.ts +1 -1
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +1 -1
- package/dist/server/app.js.map +1 -1
- package/dist/server/response.d.ts.map +1 -1
- package/dist/server/response.js +2 -1
- package/dist/server/response.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +0 -1
- package/dist/utils/logger.js.map +1 -1
- package/package.json +1 -1
package/dist/di/container.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type ProviderToken<T = any> = string | symbol | (new (...args: any[]) => T);
|
|
2
2
|
export interface BaseProvider {
|
|
3
|
-
scope?: 'singleton' | 'request';
|
|
3
|
+
scope?: 'singleton' | 'request' | 'transient';
|
|
4
4
|
}
|
|
5
5
|
export interface ValueProvider<T> extends BaseProvider {
|
|
6
6
|
useValue: T;
|
|
@@ -12,11 +12,15 @@ export interface ClassProvider<T> extends BaseProvider {
|
|
|
12
12
|
useClass: new (...args: any[]) => T;
|
|
13
13
|
}
|
|
14
14
|
export type ProviderDefinition<T> = ValueProvider<T> | FactoryProvider<T> | ClassProvider<T> | T;
|
|
15
|
+
export declare const INJECT_METADATA: unique symbol;
|
|
16
|
+
export declare const OPTIONAL_METADATA: unique symbol;
|
|
17
|
+
export declare const SCOPE_METADATA: unique symbol;
|
|
15
18
|
export declare class Container {
|
|
16
19
|
private providers;
|
|
17
20
|
private singletonCache;
|
|
18
21
|
provide<T>(token: ProviderToken<T>, provider: ProviderDefinition<T>): void;
|
|
19
22
|
clearCache(): void;
|
|
23
|
+
instantiateClass<T>(TargetClass: new (...args: any[]) => T, requestCache?: Map<ProviderToken, any>): T;
|
|
20
24
|
resolve<T>(token: ProviderToken<T>, requestCache?: Map<ProviderToken, any>): T;
|
|
21
25
|
}
|
|
22
26
|
//# sourceMappingURL=container.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/di/container.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,GAAG,IAC/B,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;AAE/C,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/di/container.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,GAAG,IAC/B,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;AAE/C,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,CAAA;CAC9C;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,CAAE,SAAQ,YAAY;IACpD,QAAQ,EAAE,CAAC,CAAA;CACZ;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,CAAE,SAAQ,YAAY;IACtD,UAAU,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CACjC;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,CAAE,SAAQ,YAAY;IACpD,QAAQ,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;CACpC;AAED,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAC9B,aAAa,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAE9D,eAAO,MAAM,eAAe,eAAqC,CAAA;AACjE,eAAO,MAAM,iBAAiB,eAAuC,CAAA;AACrE,eAAO,MAAM,cAAc,eAA6B,CAAA;AAExD,qBAAa,SAAS;IACpB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,cAAc,CAAgC;IAEtD,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,IAAI;IAK1E,UAAU,IAAI,IAAI;IAIlB,gBAAgB,CAAC,CAAC,EAChB,WAAW,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EACtC,YAAY,CAAC,EAAE,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,GACrC,CAAC;IAmDJ,OAAO,CAAC,CAAC,EACP,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,YAAY,CAAC,EAAE,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,GACrC,CAAC;CA6FL"}
|
package/dist/di/container.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Container = void 0;
|
|
3
|
+
exports.Container = exports.SCOPE_METADATA = exports.OPTIONAL_METADATA = exports.INJECT_METADATA = void 0;
|
|
4
|
+
exports.INJECT_METADATA = Symbol.for('exisjs:inject_tokens');
|
|
5
|
+
exports.OPTIONAL_METADATA = Symbol.for('exisjs:optional_tokens');
|
|
6
|
+
exports.SCOPE_METADATA = Symbol.for('exisjs:scope');
|
|
4
7
|
class Container {
|
|
5
8
|
constructor() {
|
|
6
9
|
this.providers = new Map();
|
|
@@ -13,6 +16,46 @@ class Container {
|
|
|
13
16
|
clearCache() {
|
|
14
17
|
this.singletonCache.clear();
|
|
15
18
|
}
|
|
19
|
+
instantiateClass(TargetClass, requestCache) {
|
|
20
|
+
const injectTokens = TargetClass[exports.INJECT_METADATA] ||
|
|
21
|
+
(TargetClass.prototype &&
|
|
22
|
+
TargetClass.prototype[exports.INJECT_METADATA]) ||
|
|
23
|
+
{};
|
|
24
|
+
const optionalParams = TargetClass[exports.OPTIONAL_METADATA] ||
|
|
25
|
+
(TargetClass.prototype &&
|
|
26
|
+
TargetClass.prototype[exports.OPTIONAL_METADATA]) ||
|
|
27
|
+
new Set();
|
|
28
|
+
const maxIndex = Object.keys(injectTokens).reduce((max, curr) => Math.max(max, Number(curr)), -1);
|
|
29
|
+
if (maxIndex === -1 && optionalParams.size === 0) {
|
|
30
|
+
return new TargetClass();
|
|
31
|
+
}
|
|
32
|
+
const args = [];
|
|
33
|
+
const totalParams = Math.max(maxIndex + 1, ...Array.from(optionalParams).map((idx) => idx + 1));
|
|
34
|
+
for (let i = 0; i < totalParams; i++) {
|
|
35
|
+
const token = injectTokens[i];
|
|
36
|
+
const isOptional = optionalParams.has(i);
|
|
37
|
+
if (token !== undefined) {
|
|
38
|
+
try {
|
|
39
|
+
args.push(this.resolve(token, requestCache));
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (isOptional) {
|
|
43
|
+
args.push(undefined);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (isOptional) {
|
|
51
|
+
args.push(undefined);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
args.push(undefined);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return new TargetClass(...args);
|
|
58
|
+
}
|
|
16
59
|
resolve(token, requestCache) {
|
|
17
60
|
// 1. Check singleton cache
|
|
18
61
|
if (this.singletonCache.has(token)) {
|
|
@@ -26,9 +69,11 @@ class Container {
|
|
|
26
69
|
if (provider === undefined) {
|
|
27
70
|
if (typeof token === 'function') {
|
|
28
71
|
try {
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
72
|
+
const scope = token.prototype?.[exports.SCOPE_METADATA] || 'singleton';
|
|
73
|
+
const instance = this.instantiateClass(token, requestCache);
|
|
74
|
+
if (scope === 'transient') {
|
|
75
|
+
return instance;
|
|
76
|
+
}
|
|
32
77
|
if (scope === 'request') {
|
|
33
78
|
if (!requestCache) {
|
|
34
79
|
throw new Error(`Cannot resolve request-scoped provider '${String(token)}' outside of a request context. This usually happens if you try to resolve a request-scoped dependency during app startup, inside a background job, or without passing the request context cache.`);
|
|
@@ -52,8 +97,8 @@ class Container {
|
|
|
52
97
|
let resolvedValue;
|
|
53
98
|
let scope = 'singleton';
|
|
54
99
|
if (provider && typeof provider === 'object') {
|
|
55
|
-
if ('scope' in provider && provider.scope
|
|
56
|
-
scope =
|
|
100
|
+
if ('scope' in provider && provider.scope) {
|
|
101
|
+
scope = provider.scope;
|
|
57
102
|
}
|
|
58
103
|
if ('useValue' in provider) {
|
|
59
104
|
resolvedValue = provider.useValue;
|
|
@@ -62,15 +107,18 @@ class Container {
|
|
|
62
107
|
resolvedValue = provider.useFactory();
|
|
63
108
|
}
|
|
64
109
|
else if ('useClass' in provider) {
|
|
65
|
-
resolvedValue =
|
|
110
|
+
resolvedValue = this.instantiateClass(provider.useClass, requestCache);
|
|
66
111
|
}
|
|
67
112
|
else {
|
|
68
|
-
resolvedValue = provider;
|
|
113
|
+
resolvedValue = provider;
|
|
69
114
|
}
|
|
70
115
|
}
|
|
71
116
|
else {
|
|
72
117
|
resolvedValue = provider;
|
|
73
118
|
}
|
|
119
|
+
if (scope === 'transient') {
|
|
120
|
+
return resolvedValue;
|
|
121
|
+
}
|
|
74
122
|
if (scope === 'request') {
|
|
75
123
|
if (!requestCache) {
|
|
76
124
|
throw new Error(`Cannot resolve request-scoped provider '${String(token)}' outside of a request context. This usually happens if you try to resolve a request-scoped dependency during app startup, inside a background job, or without passing the request context cache.`);
|
package/dist/di/container.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/di/container.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/di/container.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ProviderToken } from './container';
|
|
2
|
+
/**
|
|
3
|
+
* Parameter decorator that specifies a dependency token to inject into a class constructor.
|
|
4
|
+
*
|
|
5
|
+
* Example:
|
|
6
|
+
* ```ts
|
|
7
|
+
* class UserService {
|
|
8
|
+
* constructor(
|
|
9
|
+
* @Inject('DATABASE_URL') private dbUrl: string,
|
|
10
|
+
* @Inject(LoggerService) private logger: LoggerService
|
|
11
|
+
* ) {}
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function Inject(token: ProviderToken): ParameterDecorator;
|
|
16
|
+
/**
|
|
17
|
+
* Parameter decorator that marks a dependency as optional.
|
|
18
|
+
* If the dependency cannot be resolved, `undefined` is injected instead of throwing an error.
|
|
19
|
+
*
|
|
20
|
+
* Example:
|
|
21
|
+
* ```ts
|
|
22
|
+
* class NotificationService {
|
|
23
|
+
* constructor(
|
|
24
|
+
* @Inject('SLACK_WEBHOOK') @Optional() private webhook?: string
|
|
25
|
+
* ) {}
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function Optional(): ParameterDecorator;
|
|
30
|
+
//# sourceMappingURL=decorators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/di/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,aAAa,EAAE,MAAM,aAAa,CAAA;AAE/E;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,kBAAkB,CAmB/D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,IAAI,kBAAkB,CAkB7C"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Inject = Inject;
|
|
4
|
+
exports.Optional = Optional;
|
|
5
|
+
const container_1 = require("./container");
|
|
6
|
+
/**
|
|
7
|
+
* Parameter decorator that specifies a dependency token to inject into a class constructor.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* ```ts
|
|
11
|
+
* class UserService {
|
|
12
|
+
* constructor(
|
|
13
|
+
* @Inject('DATABASE_URL') private dbUrl: string,
|
|
14
|
+
* @Inject(LoggerService) private logger: LoggerService
|
|
15
|
+
* ) {}
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
function Inject(token) {
|
|
20
|
+
return function (target, propertyKey, parameterIndex) {
|
|
21
|
+
// For constructor parameters, propertyKey is undefined and target is the constructor function
|
|
22
|
+
const targetObj = propertyKey !== undefined ? target : target;
|
|
23
|
+
const currentTokens = (targetObj[container_1.INJECT_METADATA] =
|
|
24
|
+
targetObj[container_1.INJECT_METADATA] || {});
|
|
25
|
+
currentTokens[parameterIndex] = token;
|
|
26
|
+
// Also attach to prototype just in case target varies across transpiler settings
|
|
27
|
+
if (targetObj.prototype) {
|
|
28
|
+
const protoTokens = (targetObj.prototype[container_1.INJECT_METADATA] =
|
|
29
|
+
targetObj.prototype[container_1.INJECT_METADATA] || {});
|
|
30
|
+
protoTokens[parameterIndex] = token;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parameter decorator that marks a dependency as optional.
|
|
36
|
+
* If the dependency cannot be resolved, `undefined` is injected instead of throwing an error.
|
|
37
|
+
*
|
|
38
|
+
* Example:
|
|
39
|
+
* ```ts
|
|
40
|
+
* class NotificationService {
|
|
41
|
+
* constructor(
|
|
42
|
+
* @Inject('SLACK_WEBHOOK') @Optional() private webhook?: string
|
|
43
|
+
* ) {}
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function Optional() {
|
|
48
|
+
return function (target, propertyKey, parameterIndex) {
|
|
49
|
+
const targetObj = propertyKey !== undefined ? target : target;
|
|
50
|
+
const currentOptional = (targetObj[container_1.OPTIONAL_METADATA] =
|
|
51
|
+
targetObj[container_1.OPTIONAL_METADATA] || new Set());
|
|
52
|
+
currentOptional.add(parameterIndex);
|
|
53
|
+
if (targetObj.prototype) {
|
|
54
|
+
const protoOptional = (targetObj.prototype[container_1.OPTIONAL_METADATA] = targetObj.prototype[container_1.OPTIONAL_METADATA] || new Set());
|
|
55
|
+
protoOptional.add(parameterIndex);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=decorators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/di/decorators.ts"],"names":[],"mappings":";;AAeA,wBAmBC;AAeD,4BAkBC;AAnED,2CAA+E;AAE/E;;;;;;;;;;;;GAYG;AACH,SAAgB,MAAM,CAAC,KAAoB;IACzC,OAAO,UACL,MAAW,EACX,WAAwC,EACxC,cAAsB;QAEtB,8FAA8F;QAC9F,MAAM,SAAS,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;QAC7D,MAAM,aAAa,GAAG,CAAC,SAAS,CAAC,2BAAe,CAAC;YAC/C,SAAS,CAAC,2BAAe,CAAC,IAAI,EAAE,CAAC,CAAA;QACnC,aAAa,CAAC,cAAc,CAAC,GAAG,KAAK,CAAA;QAErC,iFAAiF;QACjF,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;YACxB,MAAM,WAAW,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,2BAAe,CAAC;gBACvD,SAAS,CAAC,SAAS,CAAC,2BAAe,CAAC,IAAI,EAAE,CAAC,CAAA;YAC7C,WAAW,CAAC,cAAc,CAAC,GAAG,KAAK,CAAA;QACrC,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,QAAQ;IACtB,OAAO,UACL,MAAW,EACX,WAAwC,EACxC,cAAsB;QAEtB,MAAM,SAAS,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;QAC7D,MAAM,eAAe,GAAgB,CAAC,SAAS,CAAC,6BAAiB,CAAC;YAChE,SAAS,CAAC,6BAAiB,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC,CAAA;QACpD,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QAEnC,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;YACxB,MAAM,aAAa,GAAgB,CAAC,SAAS,CAAC,SAAS,CACrD,6BAAiB,CAClB,GAAG,SAAS,CAAC,SAAS,CAAC,6BAAiB,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC,CAAA;YAChE,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
|
package/dist/di/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { inject } from './inject';
|
|
2
2
|
export { Container } from './container';
|
|
3
|
+
export { Inject, Optional } from './decorators';
|
|
3
4
|
export type { ProviderToken, ProviderDefinition, ValueProvider, FactoryProvider, ClassProvider, } from './container';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/di/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/di/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/di/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC/C,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,aAAa,GACd,MAAM,aAAa,CAAA"}
|
package/dist/di/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Container = exports.inject = void 0;
|
|
3
|
+
exports.Optional = exports.Inject = exports.Container = exports.inject = void 0;
|
|
4
4
|
var inject_1 = require("./inject");
|
|
5
5
|
Object.defineProperty(exports, "inject", { enumerable: true, get: function () { return inject_1.inject; } });
|
|
6
6
|
var container_1 = require("./container");
|
|
7
7
|
Object.defineProperty(exports, "Container", { enumerable: true, get: function () { return container_1.Container; } });
|
|
8
|
+
var decorators_1 = require("./decorators");
|
|
9
|
+
Object.defineProperty(exports, "Inject", { enumerable: true, get: function () { return decorators_1.Inject; } });
|
|
10
|
+
Object.defineProperty(exports, "Optional", { enumerable: true, get: function () { return decorators_1.Optional; } });
|
|
8
11
|
//# sourceMappingURL=index.js.map
|
package/dist/di/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/di/index.ts"],"names":[],"mappings":";;;AAAA,mCAAiC;AAAxB,gGAAA,MAAM,OAAA;AACf,yCAAuC;AAA9B,sGAAA,SAAS,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/di/index.ts"],"names":[],"mappings":";;;AAAA,mCAAiC;AAAxB,gGAAA,MAAM,OAAA;AACf,yCAAuC;AAA9B,sGAAA,SAAS,OAAA;AAClB,2CAA+C;AAAtC,oGAAA,MAAM,OAAA;AAAE,sGAAA,QAAQ,OAAA"}
|
package/dist/di/inject.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderToken } from './container';
|
|
1
2
|
/**
|
|
2
3
|
* Injects a dependency from the Exis Application container.
|
|
3
4
|
* Must be called inside an active route or middleware context.
|
|
@@ -15,5 +16,5 @@
|
|
|
15
16
|
* @return {T} The resolved dependency
|
|
16
17
|
* @public
|
|
17
18
|
*/
|
|
18
|
-
export declare function inject<T>(token:
|
|
19
|
+
export declare function inject<T>(token: ProviderToken<T>): T;
|
|
19
20
|
//# sourceMappingURL=inject.d.ts.map
|
package/dist/di/inject.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inject.d.ts","sourceRoot":"","sources":["../../src/di/inject.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"inject.d.ts","sourceRoot":"","sources":["../../src/di/inject.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAQpD"}
|
package/dist/di/inject.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/di/inject.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/di/inject.ts"],"names":[],"mappings":";;AAoBA,wBAQC;AA5BD,+CAAoD;AAGpD;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,MAAM,CAAI,KAAuB;IAC/C,MAAM,KAAK,GAAG,0BAAgB,CAAC,QAAQ,EAAE,CAAA;IACzC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;AAChD,CAAC"}
|
|
@@ -132,18 +132,25 @@ export default class UsersController {
|
|
|
132
132
|
### Available Parameter Decorators
|
|
133
133
|
- `@Body(nameOrPipe?)` — Extracts `req.body` or runs through a validation schema/pipe.
|
|
134
134
|
- `@Param(nameOrPipe?)` — Extracts a route path param (e.g. `:id`).
|
|
135
|
+
- `@QueryParam(nameOrPipe?)` / `@Query(nameOrPipe?)` — Extracts a query parameter from the URL query string.
|
|
135
136
|
- `@Headers(nameOrPipe?)` — Extracts a request header by name.
|
|
136
137
|
- `@HostParam(nameOrPipe?)` — Extracts a host subdomain parameter.
|
|
137
138
|
- `@Req()` — Injects the raw request object.
|
|
138
139
|
- `@Res(options?)` — Injects the response object (e.g. `{ passthrough: true }`).
|
|
139
140
|
- `@Ip()` — Injects the client IP address.
|
|
140
141
|
- `@Next()` — Injects the `next` function.
|
|
142
|
+
- `createParamDecorator(factory)` — Creates custom reusable route parameter decorators:
|
|
143
|
+
```typescript
|
|
144
|
+
export const CurrentUser = createParamDecorator((data: string | undefined, ctx) => {
|
|
145
|
+
return data ? ctx.req.user?.[data] : ctx.req.user
|
|
146
|
+
})
|
|
147
|
+
```
|
|
141
148
|
|
|
142
149
|
---
|
|
143
150
|
|
|
144
151
|
## 4. Middleware & Pipeline Decorators
|
|
145
152
|
|
|
146
|
-
You can bind
|
|
153
|
+
You can bind middlewares, guards, interceptors, and exception filters to controllers or route methods using the unified `@Use()` decorator:
|
|
147
154
|
|
|
148
155
|
```typescript filename="src/http/checkout/route.ts"
|
|
149
156
|
import { Controller, Post, Use, Idempotent } from 'exisjs/decorators'
|
|
@@ -161,23 +168,25 @@ export default class CheckoutController {
|
|
|
161
168
|
```
|
|
162
169
|
|
|
163
170
|
### Available Lifecycle & Middleware Decorators
|
|
164
|
-
- `@Use(...
|
|
171
|
+
- `@Use(...items)` — Unified decorator that attaches middlewares, guards (`canActivate`), interceptors (`intercept`), or exception filters (`catch`) to a class or method.
|
|
165
172
|
- `@Idempotent(options?)` — Caches responses based on the `Idempotency-Key` header using off-heap native memory.
|
|
166
173
|
|
|
167
174
|
---
|
|
168
175
|
|
|
169
|
-
## 5. Response Modifiers
|
|
176
|
+
## 5. Response & Metadata Modifiers
|
|
170
177
|
|
|
171
178
|
Modify HTTP response status codes, redirect clients, or set headers declaratively:
|
|
172
179
|
|
|
173
180
|
```typescript filename="src/http/api/route.ts"
|
|
174
|
-
import { Controller, Post, Get, HttpCode, Header, Redirect } from 'exisjs/decorators'
|
|
181
|
+
import { Controller, Post, Get, HttpCode, Header, Redirect, SetMetadata, Reflector } from 'exisjs/decorators'
|
|
175
182
|
|
|
176
183
|
@Controller('/api')
|
|
184
|
+
@SetMetadata('roles', ['admin'])
|
|
177
185
|
export default class ApiController {
|
|
178
186
|
@Post('/create')
|
|
179
187
|
@HttpCode(201) // Forces 201 Created
|
|
180
188
|
@Header('X-Custom-Version', '2.0')
|
|
189
|
+
@SetMetadata('permissions', ['write:api'])
|
|
181
190
|
async create() {
|
|
182
191
|
return { success: true }
|
|
183
192
|
}
|
|
@@ -195,17 +204,19 @@ export default class ApiController {
|
|
|
195
204
|
- `@Redirect(url: string, statusCode?: number)` — Redirects the client.
|
|
196
205
|
- `@Permissions(...permissions: string[])` — Attaches route permissions metadata.
|
|
197
206
|
- `@Hosts(...hosts: string[])` — Restricts route/controller to specific Host headers.
|
|
207
|
+
- `@SetMetadata(key, value)` — Attaches custom metadata to a class or method.
|
|
208
|
+
- `Reflector` — Static utility to inspect metadata attached via `@SetMetadata` across classes and methods (`Reflector.get`, `Reflector.getAllAndOverride`, `Reflector.getAllAndMerge`).
|
|
198
209
|
|
|
199
210
|
---
|
|
200
211
|
|
|
201
|
-
## 6. Dependency Injection
|
|
212
|
+
## 6. Dependency Injection & Modules
|
|
202
213
|
|
|
203
|
-
To mark a service class as an injectable provider for the IoC container, use the `@Injectable()` decorator:
|
|
214
|
+
To mark a service class as an injectable provider for the IoC container, use the `@Injectable()` decorator. ExisJS supports `singleton` (default), `request`, and `transient` scopes:
|
|
204
215
|
|
|
205
216
|
```typescript filename="src/http/users/service.ts"
|
|
206
217
|
import { Injectable } from 'exisjs/decorators'
|
|
207
218
|
|
|
208
|
-
@Injectable({ scope: '
|
|
219
|
+
@Injectable({ scope: 'transient' })
|
|
209
220
|
export class UserService {
|
|
210
221
|
async fetchUser(id: string) {
|
|
211
222
|
return { id, name: 'Alice' }
|
|
@@ -213,15 +224,21 @@ export class UserService {
|
|
|
213
224
|
}
|
|
214
225
|
```
|
|
215
226
|
|
|
216
|
-
|
|
227
|
+
### Constructor Parameter Injection (`@Inject` & `@Optional`)
|
|
228
|
+
|
|
229
|
+
You can inject dependencies using tokens or classes, and mark optional dependencies with `@Optional()`:
|
|
217
230
|
|
|
218
231
|
```typescript filename="src/http/users/route.ts"
|
|
219
|
-
import { Controller, Get, Param } from 'exisjs/decorators'
|
|
232
|
+
import { Controller, Get, Param, Inject, Optional } from 'exisjs/decorators'
|
|
220
233
|
import { UserService } from './service'
|
|
221
234
|
|
|
222
235
|
@Controller('/users')
|
|
223
236
|
export default class UsersController {
|
|
224
|
-
constructor(
|
|
237
|
+
constructor(
|
|
238
|
+
private userService: UserService,
|
|
239
|
+
@Inject('DATABASE_URL') private dbUrl: string,
|
|
240
|
+
@Optional() @Inject('ANALYTICS_SERVICE') private analytics?: any
|
|
241
|
+
) {}
|
|
225
242
|
|
|
226
243
|
@Get('/:id')
|
|
227
244
|
async getUser(@Param('id') id: string) {
|
|
@@ -229,3 +246,20 @@ export default class UsersController {
|
|
|
229
246
|
}
|
|
230
247
|
}
|
|
231
248
|
```
|
|
249
|
+
|
|
250
|
+
### Application Modules (`@Module`)
|
|
251
|
+
|
|
252
|
+
You can group controllers, providers, and imports into high-level OOP modules using `@Module`:
|
|
253
|
+
|
|
254
|
+
```typescript filename="src/http/users/users.module.ts"
|
|
255
|
+
import { Module } from 'exisjs/module' // or 'exisjs/decorators'
|
|
256
|
+
import UsersController from './route'
|
|
257
|
+
import { UserService } from './service'
|
|
258
|
+
|
|
259
|
+
@Module({
|
|
260
|
+
controllers: [UsersController],
|
|
261
|
+
providers: [UserService],
|
|
262
|
+
exports: [UserService]
|
|
263
|
+
})
|
|
264
|
+
export class UsersModule {}
|
|
265
|
+
```
|
|
@@ -74,7 +74,28 @@ export default exis({
|
|
|
74
74
|
})
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### Class-Based (OOP) Paradigm (`@Module`)
|
|
80
|
+
|
|
81
|
+
For applications following the OOP paradigm, you can define modules using the `@Module` class decorator:
|
|
82
|
+
|
|
83
|
+
```typescript filename="src/modules/auth.module.ts"
|
|
84
|
+
import { Module } from 'exisjs/module'
|
|
85
|
+
import { AuthService } from './auth.service'
|
|
86
|
+
import { AuthController } from './auth.controller'
|
|
87
|
+
import { DatabaseModule } from './database.module'
|
|
88
|
+
|
|
89
|
+
@Module({
|
|
90
|
+
imports: [DatabaseModule],
|
|
91
|
+
controllers: [AuthController],
|
|
92
|
+
providers: [AuthService],
|
|
93
|
+
exports: [AuthService]
|
|
94
|
+
})
|
|
95
|
+
export class AuthModule {}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
You can then register it into your server:
|
|
78
99
|
|
|
79
100
|
```typescript filename="src/http/server.ts"
|
|
80
101
|
import { Server } from 'exisjs/decorators'
|
|
@@ -134,14 +134,46 @@ import { UsersService } from './users/service'
|
|
|
134
134
|
export default class RootServer {}
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
### Constructor Injection (`@Inject` and `@Optional`)
|
|
138
|
+
|
|
139
|
+
In addition to property-level `inject()`, ExisJS provides full OOP constructor parameter injection with `@Inject(token)` and `@Optional()`:
|
|
140
|
+
|
|
141
|
+
```typescript filename="src/http/users/route.ts"
|
|
142
|
+
import { Controller, Get, Param, Inject, Optional } from 'exisjs/decorators'
|
|
143
|
+
import { UsersService } from './service'
|
|
144
|
+
|
|
145
|
+
@Controller('/users')
|
|
146
|
+
export default class UsersController {
|
|
147
|
+
constructor(
|
|
148
|
+
private usersService: UsersService,
|
|
149
|
+
@Inject('DATABASE_URL') private dbUrl: string,
|
|
150
|
+
@Optional() @Inject('METRICS') private metrics?: any
|
|
151
|
+
) {}
|
|
152
|
+
|
|
153
|
+
@Get('/:id')
|
|
154
|
+
async getUser(@Param('id') id: string) {
|
|
155
|
+
return this.usersService.findAll()
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
137
160
|
## Injection Scopes
|
|
138
161
|
|
|
139
162
|
For people coming from different programming language backgrounds, it might be unexpected to learn that in ExisJS, almost everything is shared across incoming requests. We have a connection pool to the database, singleton services with global state, etc. This is because Node.js doesn't follow the request/response Multi-Threaded Stateless Model.
|
|
140
163
|
|
|
141
|
-
However, there are
|
|
164
|
+
However, there are use-cases when request-based or transient lifetime is desired. ExisJS supports three provider scopes in the `@Injectable()` decorator and `app.provide()`:
|
|
142
165
|
|
|
143
166
|
- **Singleton (Default)**: A single instance of the provider is shared across the entire application.
|
|
144
167
|
- **Request**: A new instance of the provider is created exclusively for each incoming request, and garbage collected afterward.
|
|
168
|
+
- **Transient**: A brand-new instance is created every single time the dependency is requested/injected.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
@Injectable({ scope: 'transient' })
|
|
172
|
+
export class OperationContext {
|
|
173
|
+
public readonly id = crypto.randomUUID()
|
|
174
|
+
}
|
|
175
|
+
```
|
|
145
176
|
|
|
146
177
|
> [!WARNING]
|
|
147
178
|
> **Request Scope Constraints**: A provider marked as `scope: 'request'` **must** be resolved within the lifecycle of an active HTTP request. If you try to `inject()` or resolve a request-scoped provider during application startup, inside a background queue worker, or from a cron job, the container will throw a runtime error.
|
|
179
|
+
|
|
@@ -67,17 +67,19 @@ Parameter decorators automatically extract data from the incoming request and in
|
|
|
67
67
|
- `@Body(nameOrPipe?)`: Parses and injects the JSON request body (or passes it through a validator/pipe).
|
|
68
68
|
- `@Param(nameOrPipe?)`: Injects a URL path parameter (e.g., `id` from `/:id`).
|
|
69
69
|
- `@Headers(nameOrPipe?)`: Injects an HTTP header by name.
|
|
70
|
+
- `@QueryParam(nameOrPipe?)` / `@Query(nameOrPipe?)`: Injects a URL query parameter (e.g., `?search=term`).
|
|
70
71
|
- `@HostParam(nameOrPipe?)`: Injects a subdomain parameter.
|
|
71
72
|
- `@Req()`: Injects the raw ExisJS Request object.
|
|
72
73
|
- `@Res(options?)`: Injects the raw ExisJS Response object (`{ passthrough: true }`).
|
|
73
74
|
- `@Ip()`: Injects the client's IP address.
|
|
74
75
|
- `@Next()`: Injects the Next function.
|
|
76
|
+
- `createParamDecorator(factory)`: Exports a factory to create custom parameter decorators (e.g. `@CurrentUser()`).
|
|
75
77
|
|
|
76
78
|
---
|
|
77
79
|
|
|
78
80
|
## 3. Middleware & Pipeline Decorators
|
|
79
81
|
|
|
80
|
-
- `@Use(...
|
|
82
|
+
- `@Use(...middlewaresOrGuardsOrInterceptorsOrFilters)`: Unified decorator that binds middlewares, guards (`canActivate`), interceptors (`intercept`), or exception filters (`catch`) to a controller class or method.
|
|
81
83
|
- `@Idempotent(options?)`: Caches responses based on the `Idempotency-Key` header using native in-memory off-heap storage.
|
|
82
84
|
|
|
83
85
|
---
|
|
@@ -90,11 +92,20 @@ Parameter decorators automatically extract data from the incoming request and in
|
|
|
90
92
|
- `@Redirect(url: string, statusCode?: number)`: Redirects request to target URL.
|
|
91
93
|
- `@Permissions(...permissions: string[])`: Sets required permissions on the route.
|
|
92
94
|
- `@Hosts(...hosts: string[])`: Restricts routes to specific Host headers.
|
|
95
|
+
- `@SetMetadata(key, value)`: Attaches arbitrary custom metadata to a class or handler method, retrievable via `Reflector`.
|
|
96
|
+
- `Reflector`: Utility class to inspect metadata attached by `@SetMetadata`:
|
|
97
|
+
- `Reflector.get(key, target)`: Retrieves metadata for a specific target.
|
|
98
|
+
- `Reflector.getAllAndOverride(key, targets)`: Retrieves metadata, overriding higher-level targets with lower-level targets.
|
|
99
|
+
- `Reflector.getAllAndMerge(key, targets)`: Merges array/object metadata across multiple targets.
|
|
93
100
|
|
|
94
101
|
---
|
|
95
102
|
|
|
96
|
-
## 5. Dependency Injection
|
|
103
|
+
## 5. Dependency Injection & Modules
|
|
97
104
|
|
|
98
|
-
- `@
|
|
105
|
+
- `@Module({ imports?, controllers?, providers?, exports? })`: OOP class decorator equivalent to `defineModule()` for structuring application modules.
|
|
106
|
+
- `@Injectable(options?)`: Marks a service class as an IoC provider managed by the container. Supports `{ scope: 'singleton' | 'request' | 'transient' }`.
|
|
107
|
+
- `@Inject(token)`: Constructor parameter decorator for injecting dependencies by class, string, or symbol token.
|
|
108
|
+
- `@Optional()`: Constructor parameter decorator resolving missing dependencies to `undefined` without throwing.
|
|
99
109
|
- `@Boundary(config)`: Marks a class as a folder-scoped Boundary configuring CORS, headers, exclusions, and pipeline steps.
|
|
100
110
|
- `@Server(config)`: Marks a class as a root server definition.
|
|
111
|
+
|