@forinda/kickjs-core 0.3.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/LICENSE +21 -0
- package/dist/adapter.d.ts +63 -0
- package/dist/adapter.js +1 -0
- package/dist/adapter.js.map +1 -0
- package/dist/app-module.d.ts +31 -0
- package/dist/app-module.js +1 -0
- package/dist/app-module.js.map +1 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/chunk-AZH3H6VS.js +171 -0
- package/dist/chunk-AZH3H6VS.js.map +1 -0
- package/dist/chunk-GAO2TPCH.js +230 -0
- package/dist/chunk-GAO2TPCH.js.map +1 -0
- package/dist/chunk-IHZOCBCK.js +75 -0
- package/dist/chunk-IHZOCBCK.js.map +1 -0
- package/dist/chunk-PKJSIVAI.js +56 -0
- package/dist/chunk-PKJSIVAI.js.map +1 -0
- package/dist/chunk-RYMYKGZK.js +37 -0
- package/dist/chunk-RYMYKGZK.js.map +1 -0
- package/dist/container.d.ts +40 -0
- package/dist/container.js +9 -0
- package/dist/container.js.map +1 -0
- package/dist/decorators.d.ts +65 -0
- package/dist/decorators.js +48 -0
- package/dist/decorators.js.map +1 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.js +8 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +57 -0
- package/dist/interfaces.js +12 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/logger.d.ts +45 -0
- package/dist/logger.js +14 -0
- package/dist/logger.js.map +1 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Felix Orinda
|
|
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.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Container } from './container.js';
|
|
2
|
+
import './interfaces.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Where in the middleware pipeline an adapter's middleware should be inserted.
|
|
6
|
+
*
|
|
7
|
+
* beforeGlobal → runs before any user-defined global middleware
|
|
8
|
+
* afterGlobal → runs after global middleware, before module routes
|
|
9
|
+
* beforeRoutes → just before module routes are mounted
|
|
10
|
+
* afterRoutes → after module routes but before error handlers
|
|
11
|
+
*/
|
|
12
|
+
type MiddlewarePhase = 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes';
|
|
13
|
+
/** A middleware entry contributed by an adapter */
|
|
14
|
+
interface AdapterMiddleware {
|
|
15
|
+
/** Express-compatible handler: (req, res, next) => void */
|
|
16
|
+
handler: any;
|
|
17
|
+
/** Which phase to insert into (default: 'afterGlobal') */
|
|
18
|
+
phase?: MiddlewarePhase;
|
|
19
|
+
/** Optional path to scope the middleware to (e.g. '/api/v1/auth') */
|
|
20
|
+
path?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Adapters plug into the Application lifecycle.
|
|
24
|
+
* Implement this to add WebSocket, database, rate limiting, docs, etc.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* class RateLimitAdapter implements AppAdapter {
|
|
29
|
+
* middleware() {
|
|
30
|
+
* return [
|
|
31
|
+
* { path: '/api/v1/auth', handler: rateLimit({ max: 10 }), phase: 'beforeRoutes' },
|
|
32
|
+
* { handler: rateLimit({ max: 200 }), phase: 'beforeRoutes' },
|
|
33
|
+
* ]
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
interface AppAdapter {
|
|
39
|
+
/** Human-readable name for logging */
|
|
40
|
+
name?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Return middleware entries to be inserted into the pipeline.
|
|
43
|
+
* The `phase` controls ordering relative to global middleware and routes.
|
|
44
|
+
*/
|
|
45
|
+
middleware?(): AdapterMiddleware[];
|
|
46
|
+
/** Called before global middleware — register early routes (docs UI, health) */
|
|
47
|
+
beforeMount?(app: any, container: Container): void;
|
|
48
|
+
/**
|
|
49
|
+
* Called for each module route that gets mounted.
|
|
50
|
+
* Use this to collect route metadata (e.g. for OpenAPI spec generation).
|
|
51
|
+
*/
|
|
52
|
+
onRouteMount?(controllerClass: any, mountPath: string): void;
|
|
53
|
+
/** Called after modules registered, before HTTP server starts */
|
|
54
|
+
beforeStart?(app: any, container: Container): void;
|
|
55
|
+
/** Called after the HTTP server is listening — attach to the raw http.Server */
|
|
56
|
+
afterStart?(server: any, container: Container): void;
|
|
57
|
+
/** Called on shutdown — clean up connections */
|
|
58
|
+
shutdown?(): void | Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/** Constructor type for AppAdapter classes */
|
|
61
|
+
type AppAdapterClass = new () => AppAdapter;
|
|
62
|
+
|
|
63
|
+
export type { AdapterMiddleware, AppAdapter, AppAdapterClass, MiddlewarePhase };
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Container } from './container.js';
|
|
2
|
+
import './interfaces.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Route set returned by a module's routes() method.
|
|
6
|
+
* Combined with versioning: /{apiPrefix}/v{version}{path}
|
|
7
|
+
*/
|
|
8
|
+
interface ModuleRoutes {
|
|
9
|
+
/** URL prefix (e.g. '/users') */
|
|
10
|
+
path: string;
|
|
11
|
+
/** Express Router instance (from buildRoutes) */
|
|
12
|
+
router: any;
|
|
13
|
+
/** Optional API version override (defaults to Application.defaultVersion) */
|
|
14
|
+
version?: number;
|
|
15
|
+
/** Controller class for OpenAPI introspection */
|
|
16
|
+
controller?: any;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Interface that every feature module must implement.
|
|
20
|
+
* Modules register their DI bindings and declare their routes.
|
|
21
|
+
*/
|
|
22
|
+
interface AppModule {
|
|
23
|
+
/** Bind interfaces to implementations in the container */
|
|
24
|
+
register(container: Container): void;
|
|
25
|
+
/** Return route definitions for this module */
|
|
26
|
+
routes(): ModuleRoutes | ModuleRoutes[];
|
|
27
|
+
}
|
|
28
|
+
/** Constructor type for AppModule classes */
|
|
29
|
+
type AppModuleClass = new () => AppModule;
|
|
30
|
+
|
|
31
|
+
export type { AppModule, AppModuleClass, ModuleRoutes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=app-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
METADATA,
|
|
3
|
+
Scope
|
|
4
|
+
} from "./chunk-RYMYKGZK.js";
|
|
5
|
+
import {
|
|
6
|
+
__name
|
|
7
|
+
} from "./chunk-7QVYU63E.js";
|
|
8
|
+
|
|
9
|
+
// src/container.ts
|
|
10
|
+
import "reflect-metadata";
|
|
11
|
+
function tokenName(token) {
|
|
12
|
+
if (typeof token === "symbol") return token.toString();
|
|
13
|
+
return token?.name || String(token);
|
|
14
|
+
}
|
|
15
|
+
__name(tokenName, "tokenName");
|
|
16
|
+
var Container = class _Container {
|
|
17
|
+
static {
|
|
18
|
+
__name(this, "Container");
|
|
19
|
+
}
|
|
20
|
+
static instance;
|
|
21
|
+
registrations = /* @__PURE__ */ new Map();
|
|
22
|
+
resolving = /* @__PURE__ */ new Set();
|
|
23
|
+
/** Callback set by the decorators module to flush pending registrations */
|
|
24
|
+
static _onReady = null;
|
|
25
|
+
static getInstance() {
|
|
26
|
+
if (!_Container.instance) {
|
|
27
|
+
_Container.instance = new _Container();
|
|
28
|
+
}
|
|
29
|
+
if (_Container._onReady) {
|
|
30
|
+
_Container._onReady(_Container.instance);
|
|
31
|
+
_Container._onReady = null;
|
|
32
|
+
}
|
|
33
|
+
return _Container.instance;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resets the container by replacing the singleton with a fresh instance.
|
|
37
|
+
* Useful for testing to ensure a clean slate between test runs.
|
|
38
|
+
*/
|
|
39
|
+
static reset() {
|
|
40
|
+
_Container.instance = new _Container();
|
|
41
|
+
}
|
|
42
|
+
/** Register a class constructor under the given token */
|
|
43
|
+
register(token, target, scope = Scope.SINGLETON) {
|
|
44
|
+
this.registrations.set(token, {
|
|
45
|
+
target,
|
|
46
|
+
scope
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** Register a factory function under the given token */
|
|
50
|
+
registerFactory(token, factory, scope = Scope.SINGLETON) {
|
|
51
|
+
this.registrations.set(token, {
|
|
52
|
+
target: Object,
|
|
53
|
+
scope,
|
|
54
|
+
factory
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Register a pre-constructed singleton instance */
|
|
58
|
+
registerInstance(token, instance) {
|
|
59
|
+
this.registrations.set(token, {
|
|
60
|
+
target: instance.constructor,
|
|
61
|
+
scope: Scope.SINGLETON,
|
|
62
|
+
instance
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** Check if a binding exists for the given token */
|
|
66
|
+
has(token) {
|
|
67
|
+
return this.registrations.has(token);
|
|
68
|
+
}
|
|
69
|
+
/** Resolve a dependency by its token */
|
|
70
|
+
resolve(token) {
|
|
71
|
+
const reg = this.registrations.get(token);
|
|
72
|
+
if (!reg) {
|
|
73
|
+
throw new Error(`No binding found for: ${tokenName(token)}`);
|
|
74
|
+
}
|
|
75
|
+
if (reg.scope === Scope.SINGLETON && reg.instance !== void 0) {
|
|
76
|
+
return reg.instance;
|
|
77
|
+
}
|
|
78
|
+
if (reg.factory) {
|
|
79
|
+
const instance = reg.factory();
|
|
80
|
+
if (reg.scope === Scope.SINGLETON) {
|
|
81
|
+
reg.instance = instance;
|
|
82
|
+
}
|
|
83
|
+
return instance;
|
|
84
|
+
}
|
|
85
|
+
if (this.resolving.has(token)) {
|
|
86
|
+
const chain = [
|
|
87
|
+
...this.resolving
|
|
88
|
+
].map(tokenName);
|
|
89
|
+
chain.push(tokenName(token));
|
|
90
|
+
throw new Error(`Circular dependency detected: ${chain.join(" -> ")}`);
|
|
91
|
+
}
|
|
92
|
+
this.resolving.add(token);
|
|
93
|
+
try {
|
|
94
|
+
const instance = this.createInstance(reg);
|
|
95
|
+
if (reg.scope === Scope.SINGLETON) {
|
|
96
|
+
reg.instance = instance;
|
|
97
|
+
}
|
|
98
|
+
return instance;
|
|
99
|
+
} finally {
|
|
100
|
+
this.resolving.delete(token);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Process all @Configuration classes and invoke their @Bean methods */
|
|
104
|
+
bootstrap() {
|
|
105
|
+
for (const [, reg] of this.registrations) {
|
|
106
|
+
const isConfig = Reflect.getMetadata(METADATA.CONFIGURATION, reg.target);
|
|
107
|
+
if (isConfig) {
|
|
108
|
+
this.processConfiguration(reg.target);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
createInstance(reg) {
|
|
113
|
+
const paramTypes = Reflect.getMetadata(METADATA.PARAM_TYPES, reg.target) || [];
|
|
114
|
+
const args = paramTypes.map((paramType, index) => {
|
|
115
|
+
const injectTokens = Reflect.getMetadata(METADATA.INJECT, reg.target) || {};
|
|
116
|
+
const token = injectTokens[index] || paramType;
|
|
117
|
+
return this.resolve(token);
|
|
118
|
+
});
|
|
119
|
+
const instance = new reg.target(...args);
|
|
120
|
+
this.injectProperties(instance, reg.target);
|
|
121
|
+
const postConstruct = Reflect.getMetadata(METADATA.POST_CONSTRUCT, reg.target.prototype);
|
|
122
|
+
if (postConstruct && typeof instance[postConstruct] === "function") {
|
|
123
|
+
instance[postConstruct]();
|
|
124
|
+
}
|
|
125
|
+
return instance;
|
|
126
|
+
}
|
|
127
|
+
injectProperties(instance, target) {
|
|
128
|
+
const autowiredProps = Reflect.getMetadata(METADATA.AUTOWIRED, target.prototype) || /* @__PURE__ */ new Map();
|
|
129
|
+
for (const [prop, token] of autowiredProps) {
|
|
130
|
+
const resolvedToken = token || Reflect.getMetadata(METADATA.PROPERTY_TYPE, target.prototype, prop);
|
|
131
|
+
if (resolvedToken) {
|
|
132
|
+
Object.defineProperty(instance, prop, {
|
|
133
|
+
get: /* @__PURE__ */ __name(() => this.resolve(resolvedToken), "get"),
|
|
134
|
+
enumerable: true,
|
|
135
|
+
configurable: true
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const valueProps = Reflect.getMetadata(METADATA.VALUE, target.prototype) || /* @__PURE__ */ new Map();
|
|
140
|
+
for (const [prop, config] of valueProps) {
|
|
141
|
+
Object.defineProperty(instance, prop, {
|
|
142
|
+
get() {
|
|
143
|
+
const val = process.env[config.envKey];
|
|
144
|
+
if (val !== void 0) return val;
|
|
145
|
+
if (config.defaultValue !== void 0) return config.defaultValue;
|
|
146
|
+
throw new Error(`@Value('${config.envKey}'): Environment variable "${config.envKey}" is not set and no default was provided.`);
|
|
147
|
+
},
|
|
148
|
+
enumerable: true,
|
|
149
|
+
configurable: true
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
processConfiguration(target) {
|
|
154
|
+
const instance = this.resolve(target);
|
|
155
|
+
const prototype = target.prototype;
|
|
156
|
+
for (const key of Object.getOwnPropertyNames(prototype)) {
|
|
157
|
+
if (key === "constructor") continue;
|
|
158
|
+
const beanMeta = Reflect.getMetadata(METADATA.BEAN, prototype, key);
|
|
159
|
+
if (!beanMeta) continue;
|
|
160
|
+
const options = Reflect.getMetadata(METADATA.BEAN_OPTIONS, prototype, key) || {};
|
|
161
|
+
const returnType = Reflect.getMetadata(METADATA.RETURN_TYPE, prototype, key);
|
|
162
|
+
const token = returnType || key;
|
|
163
|
+
this.registerFactory(token, () => instance[key](), options.scope || Scope.SINGLETON);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export {
|
|
169
|
+
Container
|
|
170
|
+
};
|
|
171
|
+
//# sourceMappingURL=chunk-AZH3H6VS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/container.ts"],"sourcesContent":["import 'reflect-metadata'\nimport { Constructor, Scope, METADATA } from './interfaces'\n\n/** Internal registration entry that tracks how a dependency should be resolved */\ninterface Registration {\n target: Constructor\n scope: Scope\n instance?: any\n factory?: () => any\n}\n\n/** Format a token for display in error messages */\nfunction tokenName(token: any): string {\n if (typeof token === 'symbol') return token.toString()\n return token?.name || String(token)\n}\n\n/**\n * Inversion-of-Control (IoC) container that manages dependency registration,\n * resolution, and lifecycle. Implements the Singleton pattern so all parts of\n * the application share a single container instance.\n *\n * Supports constructor injection, property injection (@Autowired),\n * factory-based beans (@Bean), and lifecycle hooks (@PostConstruct).\n */\nexport class Container {\n private static instance: Container\n private registrations = new Map<any, Registration>()\n private resolving = new Set<any>()\n\n /** Callback set by the decorators module to flush pending registrations */\n static _onReady: ((container: Container) => void) | null = null\n\n static getInstance(): Container {\n if (!Container.instance) {\n Container.instance = new Container()\n }\n // Flush any decorator registrations that queued before the container existed\n if (Container._onReady) {\n Container._onReady(Container.instance)\n Container._onReady = null\n }\n return Container.instance\n }\n\n /**\n * Resets the container by replacing the singleton with a fresh instance.\n * Useful for testing to ensure a clean slate between test runs.\n */\n static reset(): void {\n Container.instance = new Container()\n }\n\n /** Register a class constructor under the given token */\n register(token: any, target: Constructor, scope: Scope = Scope.SINGLETON): void {\n this.registrations.set(token, { target, scope })\n }\n\n /** Register a factory function under the given token */\n registerFactory(token: any, factory: () => any, scope: Scope = Scope.SINGLETON): void {\n this.registrations.set(token, { target: Object as any, scope, factory })\n }\n\n /** Register a pre-constructed singleton instance */\n registerInstance(token: any, instance: any): void {\n this.registrations.set(token, {\n target: instance.constructor,\n scope: Scope.SINGLETON,\n instance,\n })\n }\n\n /** Check if a binding exists for the given token */\n has(token: any): boolean {\n return this.registrations.has(token)\n }\n\n /** Resolve a dependency by its token */\n resolve<T = any>(token: any): T {\n const reg = this.registrations.get(token)\n if (!reg) {\n throw new Error(`No binding found for: ${tokenName(token)}`)\n }\n\n if (reg.scope === Scope.SINGLETON && reg.instance !== undefined) {\n return reg.instance\n }\n\n if (reg.factory) {\n const instance = reg.factory()\n if (reg.scope === Scope.SINGLETON) {\n reg.instance = instance\n }\n return instance\n }\n\n if (this.resolving.has(token)) {\n const chain = [...this.resolving].map(tokenName)\n chain.push(tokenName(token))\n throw new Error(`Circular dependency detected: ${chain.join(' -> ')}`)\n }\n this.resolving.add(token)\n\n try {\n const instance = this.createInstance(reg)\n if (reg.scope === Scope.SINGLETON) {\n reg.instance = instance\n }\n return instance\n } finally {\n this.resolving.delete(token)\n }\n }\n\n /** Process all @Configuration classes and invoke their @Bean methods */\n bootstrap(): void {\n for (const [, reg] of this.registrations) {\n const isConfig = Reflect.getMetadata(METADATA.CONFIGURATION, reg.target)\n if (isConfig) {\n this.processConfiguration(reg.target)\n }\n }\n }\n\n private createInstance(reg: Registration): any {\n const paramTypes: Constructor[] = Reflect.getMetadata(METADATA.PARAM_TYPES, reg.target) || []\n\n const args = paramTypes.map((paramType, index) => {\n // Check for @Inject token override on constructor parameter\n const injectTokens: Record<number, any> =\n Reflect.getMetadata(METADATA.INJECT, reg.target) || {}\n const token = injectTokens[index] || paramType\n return this.resolve(token)\n })\n\n const instance = new reg.target(...args)\n\n // Property injection via @Autowired\n this.injectProperties(instance, reg.target)\n\n // @PostConstruct lifecycle hook\n const postConstruct = Reflect.getMetadata(METADATA.POST_CONSTRUCT, reg.target.prototype)\n if (postConstruct && typeof instance[postConstruct] === 'function') {\n instance[postConstruct]()\n }\n\n return instance\n }\n\n private injectProperties(instance: any, target: Constructor): void {\n // @Autowired — lazy DI property injection\n const autowiredProps: Map<string, any> =\n Reflect.getMetadata(METADATA.AUTOWIRED, target.prototype) || new Map()\n\n for (const [prop, token] of autowiredProps) {\n const resolvedToken =\n token || Reflect.getMetadata(METADATA.PROPERTY_TYPE, target.prototype, prop)\n if (resolvedToken) {\n Object.defineProperty(instance, prop, {\n get: () => this.resolve(resolvedToken),\n enumerable: true,\n configurable: true,\n })\n }\n }\n\n // @Value — lazy environment variable injection\n const valueProps: Map<string, { envKey: string; defaultValue?: any }> =\n Reflect.getMetadata(METADATA.VALUE, target.prototype) || new Map()\n\n for (const [prop, config] of valueProps) {\n Object.defineProperty(instance, prop, {\n get() {\n const val = process.env[config.envKey]\n if (val !== undefined) return val\n if (config.defaultValue !== undefined) return config.defaultValue\n throw new Error(\n `@Value('${config.envKey}'): Environment variable \"${config.envKey}\" is not set and no default was provided.`,\n )\n },\n enumerable: true,\n configurable: true,\n })\n }\n }\n\n private processConfiguration(target: Constructor): void {\n const instance = this.resolve(target)\n const prototype = target.prototype\n\n for (const key of Object.getOwnPropertyNames(prototype)) {\n if (key === 'constructor') continue\n const beanMeta = Reflect.getMetadata(METADATA.BEAN, prototype, key)\n if (!beanMeta) continue\n\n const options = Reflect.getMetadata(METADATA.BEAN_OPTIONS, prototype, key) || {}\n const returnType = Reflect.getMetadata(METADATA.RETURN_TYPE, prototype, key)\n const token = returnType || key\n\n this.registerFactory(token, () => instance[key](), options.scope || Scope.SINGLETON)\n }\n }\n}\n"],"mappings":";;;;;;;;;AAAA,OAAO;AAYP,SAASA,UAAUC,OAAU;AAC3B,MAAI,OAAOA,UAAU,SAAU,QAAOA,MAAMC,SAAQ;AACpD,SAAOD,OAAOE,QAAQC,OAAOH,KAAAA;AAC/B;AAHSD;AAaF,IAAMK,YAAN,MAAMA,WAAAA;EAzBb,OAyBaA;;;EACX,OAAeC;EACPC,gBAAgB,oBAAIC,IAAAA;EACpBC,YAAY,oBAAIC,IAAAA;;EAGxB,OAAOC,WAAoD;EAE3D,OAAOC,cAAyB;AAC9B,QAAI,CAACP,WAAUC,UAAU;AACvBD,iBAAUC,WAAW,IAAID,WAAAA;IAC3B;AAEA,QAAIA,WAAUM,UAAU;AACtBN,iBAAUM,SAASN,WAAUC,QAAQ;AACrCD,iBAAUM,WAAW;IACvB;AACA,WAAON,WAAUC;EACnB;;;;;EAMA,OAAOO,QAAc;AACnBR,eAAUC,WAAW,IAAID,WAAAA;EAC3B;;EAGAS,SAASb,OAAYc,QAAqBC,QAAeC,MAAMC,WAAiB;AAC9E,SAAKX,cAAcY,IAAIlB,OAAO;MAAEc;MAAQC;IAAM,CAAA;EAChD;;EAGAI,gBAAgBnB,OAAYoB,SAAoBL,QAAeC,MAAMC,WAAiB;AACpF,SAAKX,cAAcY,IAAIlB,OAAO;MAAEc,QAAQO;MAAeN;MAAOK;IAAQ,CAAA;EACxE;;EAGAE,iBAAiBtB,OAAYK,UAAqB;AAChD,SAAKC,cAAcY,IAAIlB,OAAO;MAC5Bc,QAAQT,SAAS;MACjBU,OAAOC,MAAMC;MACbZ;IACF,CAAA;EACF;;EAGAkB,IAAIvB,OAAqB;AACvB,WAAO,KAAKM,cAAciB,IAAIvB,KAAAA;EAChC;;EAGAwB,QAAiBxB,OAAe;AAC9B,UAAMyB,MAAM,KAAKnB,cAAcoB,IAAI1B,KAAAA;AACnC,QAAI,CAACyB,KAAK;AACR,YAAM,IAAIE,MAAM,yBAAyB5B,UAAUC,KAAAA,CAAAA,EAAQ;IAC7D;AAEA,QAAIyB,IAAIV,UAAUC,MAAMC,aAAaQ,IAAIpB,aAAauB,QAAW;AAC/D,aAAOH,IAAIpB;IACb;AAEA,QAAIoB,IAAIL,SAAS;AACf,YAAMf,WAAWoB,IAAIL,QAAO;AAC5B,UAAIK,IAAIV,UAAUC,MAAMC,WAAW;AACjCQ,YAAIpB,WAAWA;MACjB;AACA,aAAOA;IACT;AAEA,QAAI,KAAKG,UAAUe,IAAIvB,KAAAA,GAAQ;AAC7B,YAAM6B,QAAQ;WAAI,KAAKrB;QAAWsB,IAAI/B,SAAAA;AACtC8B,YAAME,KAAKhC,UAAUC,KAAAA,CAAAA;AACrB,YAAM,IAAI2B,MAAM,iCAAiCE,MAAMG,KAAK,MAAA,CAAA,EAAS;IACvE;AACA,SAAKxB,UAAUyB,IAAIjC,KAAAA;AAEnB,QAAI;AACF,YAAMK,WAAW,KAAK6B,eAAeT,GAAAA;AACrC,UAAIA,IAAIV,UAAUC,MAAMC,WAAW;AACjCQ,YAAIpB,WAAWA;MACjB;AACA,aAAOA;IACT,UAAA;AACE,WAAKG,UAAU2B,OAAOnC,KAAAA;IACxB;EACF;;EAGAoC,YAAkB;AAChB,eAAW,CAAA,EAAGX,GAAAA,KAAQ,KAAKnB,eAAe;AACxC,YAAM+B,WAAWC,QAAQC,YAAYC,SAASC,eAAehB,IAAIX,MAAM;AACvE,UAAIuB,UAAU;AACZ,aAAKK,qBAAqBjB,IAAIX,MAAM;MACtC;IACF;EACF;EAEQoB,eAAeT,KAAwB;AAC7C,UAAMkB,aAA4BL,QAAQC,YAAYC,SAASI,aAAanB,IAAIX,MAAM,KAAK,CAAA;AAE3F,UAAM+B,OAAOF,WAAWb,IAAI,CAACgB,WAAWC,UAAAA;AAEtC,YAAMC,eACJV,QAAQC,YAAYC,SAASS,QAAQxB,IAAIX,MAAM,KAAK,CAAC;AACvD,YAAMd,QAAQgD,aAAaD,KAAAA,KAAUD;AACrC,aAAO,KAAKtB,QAAQxB,KAAAA;IACtB,CAAA;AAEA,UAAMK,WAAW,IAAIoB,IAAIX,OAAM,GAAI+B,IAAAA;AAGnC,SAAKK,iBAAiB7C,UAAUoB,IAAIX,MAAM;AAG1C,UAAMqC,gBAAgBb,QAAQC,YAAYC,SAASY,gBAAgB3B,IAAIX,OAAOuC,SAAS;AACvF,QAAIF,iBAAiB,OAAO9C,SAAS8C,aAAAA,MAAmB,YAAY;AAClE9C,eAAS8C,aAAAA,EAAc;IACzB;AAEA,WAAO9C;EACT;EAEQ6C,iBAAiB7C,UAAeS,QAA2B;AAEjE,UAAMwC,iBACJhB,QAAQC,YAAYC,SAASe,WAAWzC,OAAOuC,SAAS,KAAK,oBAAI9C,IAAAA;AAEnE,eAAW,CAACiD,MAAMxD,KAAAA,KAAUsD,gBAAgB;AAC1C,YAAMG,gBACJzD,SAASsC,QAAQC,YAAYC,SAASkB,eAAe5C,OAAOuC,WAAWG,IAAAA;AACzE,UAAIC,eAAe;AACjBpC,eAAOsC,eAAetD,UAAUmD,MAAM;UACpC9B,KAAK,6BAAM,KAAKF,QAAQiC,aAAAA,GAAnB;UACLG,YAAY;UACZC,cAAc;QAChB,CAAA;MACF;IACF;AAGA,UAAMC,aACJxB,QAAQC,YAAYC,SAASuB,OAAOjD,OAAOuC,SAAS,KAAK,oBAAI9C,IAAAA;AAE/D,eAAW,CAACiD,MAAMQ,MAAAA,KAAWF,YAAY;AACvCzC,aAAOsC,eAAetD,UAAUmD,MAAM;QACpC9B,MAAAA;AACE,gBAAMuC,MAAMC,QAAQC,IAAIH,OAAOI,MAAM;AACrC,cAAIH,QAAQrC,OAAW,QAAOqC;AAC9B,cAAID,OAAOK,iBAAiBzC,OAAW,QAAOoC,OAAOK;AACrD,gBAAM,IAAI1C,MACR,WAAWqC,OAAOI,MAAM,6BAA6BJ,OAAOI,MAAM,2CAA2C;QAEjH;QACAR,YAAY;QACZC,cAAc;MAChB,CAAA;IACF;EACF;EAEQnB,qBAAqB5B,QAA2B;AACtD,UAAMT,WAAW,KAAKmB,QAAQV,MAAAA;AAC9B,UAAMuC,YAAYvC,OAAOuC;AAEzB,eAAWiB,OAAOjD,OAAOkD,oBAAoBlB,SAAAA,GAAY;AACvD,UAAIiB,QAAQ,cAAe;AAC3B,YAAME,WAAWlC,QAAQC,YAAYC,SAASiC,MAAMpB,WAAWiB,GAAAA;AAC/D,UAAI,CAACE,SAAU;AAEf,YAAME,UAAUpC,QAAQC,YAAYC,SAASmC,cAActB,WAAWiB,GAAAA,KAAQ,CAAC;AAC/E,YAAMM,aAAatC,QAAQC,YAAYC,SAASqC,aAAaxB,WAAWiB,GAAAA;AACxE,YAAMtE,QAAQ4E,cAAcN;AAE5B,WAAKnD,gBAAgBnB,OAAO,MAAMK,SAASiE,GAAAA,EAAI,GAAII,QAAQ3D,SAASC,MAAMC,SAAS;IACrF;EACF;AACF;","names":["tokenName","token","toString","name","String","Container","instance","registrations","Map","resolving","Set","_onReady","getInstance","reset","register","target","scope","Scope","SINGLETON","set","registerFactory","factory","Object","registerInstance","has","resolve","reg","get","Error","undefined","chain","map","push","join","add","createInstance","delete","bootstrap","isConfig","Reflect","getMetadata","METADATA","CONFIGURATION","processConfiguration","paramTypes","PARAM_TYPES","args","paramType","index","injectTokens","INJECT","injectProperties","postConstruct","POST_CONSTRUCT","prototype","autowiredProps","AUTOWIRED","prop","resolvedToken","PROPERTY_TYPE","defineProperty","enumerable","configurable","valueProps","VALUE","config","val","process","env","envKey","defaultValue","key","getOwnPropertyNames","beanMeta","BEAN","options","BEAN_OPTIONS","returnType","RETURN_TYPE"]}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Container
|
|
3
|
+
} from "./chunk-AZH3H6VS.js";
|
|
4
|
+
import {
|
|
5
|
+
METADATA,
|
|
6
|
+
Scope
|
|
7
|
+
} from "./chunk-RYMYKGZK.js";
|
|
8
|
+
import {
|
|
9
|
+
__name
|
|
10
|
+
} from "./chunk-7QVYU63E.js";
|
|
11
|
+
|
|
12
|
+
// src/decorators.ts
|
|
13
|
+
import "reflect-metadata";
|
|
14
|
+
var pendingRegistrations = [];
|
|
15
|
+
var containerRef = null;
|
|
16
|
+
function flushPending(container) {
|
|
17
|
+
containerRef = container;
|
|
18
|
+
for (const { target, scope } of pendingRegistrations) {
|
|
19
|
+
if (!container.has(target)) {
|
|
20
|
+
container.register(target, target, scope);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
pendingRegistrations.length = 0;
|
|
24
|
+
}
|
|
25
|
+
__name(flushPending, "flushPending");
|
|
26
|
+
Container._onReady = flushPending;
|
|
27
|
+
function registerInContainer(target, scope) {
|
|
28
|
+
Reflect.defineMetadata(METADATA.INJECTABLE, true, target);
|
|
29
|
+
Reflect.defineMetadata(METADATA.SCOPE, scope, target);
|
|
30
|
+
if (containerRef) {
|
|
31
|
+
if (!containerRef.has(target)) {
|
|
32
|
+
containerRef.register(target, target, scope);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
pendingRegistrations.push({
|
|
36
|
+
target,
|
|
37
|
+
scope
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
__name(registerInContainer, "registerInContainer");
|
|
42
|
+
function Injectable(options) {
|
|
43
|
+
return (target) => {
|
|
44
|
+
registerInContainer(target, options?.scope ?? Scope.SINGLETON);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
__name(Injectable, "Injectable");
|
|
48
|
+
function Service(options) {
|
|
49
|
+
return (target) => {
|
|
50
|
+
registerInContainer(target, options?.scope ?? Scope.SINGLETON);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
__name(Service, "Service");
|
|
54
|
+
function Component(options) {
|
|
55
|
+
return (target) => {
|
|
56
|
+
registerInContainer(target, options?.scope ?? Scope.SINGLETON);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
__name(Component, "Component");
|
|
60
|
+
function Repository(options) {
|
|
61
|
+
return (target) => {
|
|
62
|
+
registerInContainer(target, options?.scope ?? Scope.SINGLETON);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
__name(Repository, "Repository");
|
|
66
|
+
function Configuration() {
|
|
67
|
+
return (target) => {
|
|
68
|
+
registerInContainer(target, Scope.SINGLETON);
|
|
69
|
+
Reflect.defineMetadata(METADATA.CONFIGURATION, true, target);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
__name(Configuration, "Configuration");
|
|
73
|
+
function Controller(path) {
|
|
74
|
+
return (target) => {
|
|
75
|
+
registerInContainer(target, Scope.SINGLETON);
|
|
76
|
+
Reflect.defineMetadata(METADATA.CONTROLLER_PATH, path || "/", target);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
__name(Controller, "Controller");
|
|
80
|
+
function Bean(options) {
|
|
81
|
+
return (target, propertyKey) => {
|
|
82
|
+
Reflect.defineMetadata(METADATA.BEAN, true, target, propertyKey);
|
|
83
|
+
if (options) {
|
|
84
|
+
Reflect.defineMetadata(METADATA.BEAN_OPTIONS, options, target, propertyKey);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
__name(Bean, "Bean");
|
|
89
|
+
function PostConstruct() {
|
|
90
|
+
return (target, propertyKey) => {
|
|
91
|
+
Reflect.defineMetadata(METADATA.POST_CONSTRUCT, propertyKey, target);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
__name(PostConstruct, "PostConstruct");
|
|
95
|
+
function Transactional() {
|
|
96
|
+
return (_target, _propertyKey, descriptor) => {
|
|
97
|
+
const original = descriptor.value;
|
|
98
|
+
descriptor.value = async function(...args) {
|
|
99
|
+
if (!containerRef) {
|
|
100
|
+
throw new Error("@Transactional: Container not initialized. Call bootstrap() first.");
|
|
101
|
+
}
|
|
102
|
+
const txManager = containerRef.resolve(/* @__PURE__ */ Symbol.for("TransactionManager"));
|
|
103
|
+
const tx = await txManager.begin();
|
|
104
|
+
try {
|
|
105
|
+
const result = await original.apply(this, args);
|
|
106
|
+
await txManager.commit(tx);
|
|
107
|
+
return result;
|
|
108
|
+
} catch (err) {
|
|
109
|
+
await txManager.rollback(tx);
|
|
110
|
+
throw err;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
return descriptor;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
__name(Transactional, "Transactional");
|
|
117
|
+
function Autowired(token) {
|
|
118
|
+
return (target, propertyKey) => {
|
|
119
|
+
const existing = Reflect.getMetadata(METADATA.AUTOWIRED, target) || /* @__PURE__ */ new Map();
|
|
120
|
+
existing.set(propertyKey, token);
|
|
121
|
+
Reflect.defineMetadata(METADATA.AUTOWIRED, existing, target);
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
__name(Autowired, "Autowired");
|
|
125
|
+
function Inject(token) {
|
|
126
|
+
return (target, _propertyKey, parameterIndex) => {
|
|
127
|
+
const existing = Reflect.getMetadata(METADATA.INJECT, target) || {};
|
|
128
|
+
existing[parameterIndex] = token;
|
|
129
|
+
Reflect.defineMetadata(METADATA.INJECT, existing, target);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
__name(Inject, "Inject");
|
|
133
|
+
function Value(envKey, defaultValue) {
|
|
134
|
+
return (target, propertyKey) => {
|
|
135
|
+
const existing = Reflect.getMetadata(METADATA.VALUE, target) || /* @__PURE__ */ new Map();
|
|
136
|
+
existing.set(propertyKey, {
|
|
137
|
+
envKey,
|
|
138
|
+
defaultValue
|
|
139
|
+
});
|
|
140
|
+
Reflect.defineMetadata(METADATA.VALUE, existing, target);
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
__name(Value, "Value");
|
|
144
|
+
function createRouteDecorator(method) {
|
|
145
|
+
return (path, validation) => {
|
|
146
|
+
return (target, propertyKey) => {
|
|
147
|
+
const routes = Reflect.getMetadata(METADATA.ROUTES, target.constructor) || [];
|
|
148
|
+
routes.push({
|
|
149
|
+
method,
|
|
150
|
+
path: path || "/",
|
|
151
|
+
handlerName: propertyKey,
|
|
152
|
+
validation
|
|
153
|
+
});
|
|
154
|
+
Reflect.defineMetadata(METADATA.ROUTES, routes, target.constructor);
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
__name(createRouteDecorator, "createRouteDecorator");
|
|
159
|
+
var Get = createRouteDecorator("GET");
|
|
160
|
+
var Post = createRouteDecorator("POST");
|
|
161
|
+
var Put = createRouteDecorator("PUT");
|
|
162
|
+
var Delete = createRouteDecorator("DELETE");
|
|
163
|
+
var Patch = createRouteDecorator("PATCH");
|
|
164
|
+
function Middleware(...handlers) {
|
|
165
|
+
return (target, propertyKey) => {
|
|
166
|
+
if (propertyKey) {
|
|
167
|
+
const existing = Reflect.getMetadata(METADATA.METHOD_MIDDLEWARES, target.constructor, propertyKey) || [];
|
|
168
|
+
Reflect.defineMetadata(METADATA.METHOD_MIDDLEWARES, [
|
|
169
|
+
...existing,
|
|
170
|
+
...handlers
|
|
171
|
+
], target.constructor, propertyKey);
|
|
172
|
+
} else {
|
|
173
|
+
const existing = Reflect.getMetadata(METADATA.CLASS_MIDDLEWARES, target) || [];
|
|
174
|
+
Reflect.defineMetadata(METADATA.CLASS_MIDDLEWARES, [
|
|
175
|
+
...existing,
|
|
176
|
+
...handlers
|
|
177
|
+
], target);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
__name(Middleware, "Middleware");
|
|
182
|
+
function FileUpload(config) {
|
|
183
|
+
return (target, propertyKey) => {
|
|
184
|
+
Reflect.defineMetadata(METADATA.FILE_UPLOAD, config, target.constructor, propertyKey);
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
__name(FileUpload, "FileUpload");
|
|
188
|
+
function Builder(target) {
|
|
189
|
+
Reflect.defineMetadata(METADATA.BUILDER, true, target);
|
|
190
|
+
target.builder = function() {
|
|
191
|
+
const props = {};
|
|
192
|
+
const proxy = new Proxy({}, {
|
|
193
|
+
get(_, key) {
|
|
194
|
+
if (key === "build") {
|
|
195
|
+
return () => Object.assign(new target(), props);
|
|
196
|
+
}
|
|
197
|
+
return (value) => {
|
|
198
|
+
props[key] = value;
|
|
199
|
+
return proxy;
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
return proxy;
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
__name(Builder, "Builder");
|
|
207
|
+
|
|
208
|
+
export {
|
|
209
|
+
Injectable,
|
|
210
|
+
Service,
|
|
211
|
+
Component,
|
|
212
|
+
Repository,
|
|
213
|
+
Configuration,
|
|
214
|
+
Controller,
|
|
215
|
+
Bean,
|
|
216
|
+
PostConstruct,
|
|
217
|
+
Transactional,
|
|
218
|
+
Autowired,
|
|
219
|
+
Inject,
|
|
220
|
+
Value,
|
|
221
|
+
Get,
|
|
222
|
+
Post,
|
|
223
|
+
Put,
|
|
224
|
+
Delete,
|
|
225
|
+
Patch,
|
|
226
|
+
Middleware,
|
|
227
|
+
FileUpload,
|
|
228
|
+
Builder
|
|
229
|
+
};
|
|
230
|
+
//# sourceMappingURL=chunk-GAO2TPCH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/decorators.ts"],"sourcesContent":["import 'reflect-metadata'\nimport { METADATA, Scope, type BeanOptions, type ServiceOptions } from './interfaces'\nimport { Container } from './container'\n\n// ── Deferred Registration Queue ─────────────────────────────────────────\n// Decorators execute at class-definition time (module load). The Container\n// may not exist yet when the first decorator fires. We queue registrations\n// and flush them on first Container.getInstance() call.\n\ntype PendingRegistration = { target: any; scope: Scope }\nconst pendingRegistrations: PendingRegistration[] = []\nlet containerRef: any = null\n\nfunction flushPending(container: any): void {\n containerRef = container\n for (const { target, scope } of pendingRegistrations) {\n if (!container.has(target)) {\n container.register(target, target, scope)\n }\n }\n pendingRegistrations.length = 0\n}\n\n// Wire up synchronously — Container._onReady is called on first getInstance()\nContainer._onReady = flushPending\n\n// ── Class Decorators ────────────────────────────────────────────────────\n\nfunction registerInContainer(target: any, scope: Scope): void {\n Reflect.defineMetadata(METADATA.INJECTABLE, true, target)\n Reflect.defineMetadata(METADATA.SCOPE, scope, target)\n\n if (containerRef) {\n // Container already initialized — register immediately\n if (!containerRef.has(target)) {\n containerRef.register(target, target, scope)\n }\n } else {\n // Container not ready yet — queue for later\n pendingRegistrations.push({ target, scope })\n }\n}\n\n/** Mark a class as injectable with lifecycle scope */\nexport function Injectable(options?: ServiceOptions): ClassDecorator {\n return (target: any) => {\n registerInContainer(target, options?.scope ?? Scope.SINGLETON)\n }\n}\n\n/** Mark a class as a service (semantic alias for Injectable) */\nexport function Service(options?: ServiceOptions): ClassDecorator {\n return (target: any) => {\n registerInContainer(target, options?.scope ?? Scope.SINGLETON)\n }\n}\n\n/** Mark a class as a generic managed component */\nexport function Component(options?: ServiceOptions): ClassDecorator {\n return (target: any) => {\n registerInContainer(target, options?.scope ?? Scope.SINGLETON)\n }\n}\n\n/** Mark a class as a repository */\nexport function Repository(options?: ServiceOptions): ClassDecorator {\n return (target: any) => {\n registerInContainer(target, options?.scope ?? Scope.SINGLETON)\n }\n}\n\n/** Mark a class as a configuration provider for @Bean methods */\nexport function Configuration(): ClassDecorator {\n return (target: any) => {\n registerInContainer(target, Scope.SINGLETON)\n Reflect.defineMetadata(METADATA.CONFIGURATION, true, target)\n }\n}\n\n/** Mark a class as an HTTP controller with an optional route prefix */\nexport function Controller(path?: string): ClassDecorator {\n return (target: any) => {\n registerInContainer(target, Scope.SINGLETON)\n Reflect.defineMetadata(METADATA.CONTROLLER_PATH, path || '/', target)\n }\n}\n\n// ── Method Decorators ───────────────────────────────────────────────────\n\n/** Mark a method inside @Configuration as a bean factory */\nexport function Bean(options?: BeanOptions): MethodDecorator {\n return (target, propertyKey) => {\n Reflect.defineMetadata(METADATA.BEAN, true, target, propertyKey)\n if (options) {\n Reflect.defineMetadata(METADATA.BEAN_OPTIONS, options, target, propertyKey)\n }\n }\n}\n\n/** Mark a method as a lifecycle hook called after instantiation */\nexport function PostConstruct(): MethodDecorator {\n return (target, propertyKey) => {\n Reflect.defineMetadata(METADATA.POST_CONSTRUCT, propertyKey, target)\n }\n}\n\n/** Wrap a method in a database transaction with auto commit/rollback */\nexport function Transactional(): MethodDecorator {\n return (_target, _propertyKey, descriptor: PropertyDescriptor) => {\n const original = descriptor.value\n descriptor.value = async function (this: any, ...args: any[]) {\n if (!containerRef) {\n throw new Error('@Transactional: Container not initialized. Call bootstrap() first.')\n }\n const txManager = containerRef.resolve(Symbol.for('TransactionManager'))\n const tx = await txManager.begin()\n try {\n const result = await original.apply(this, args)\n await txManager.commit(tx)\n return result\n } catch (err) {\n await txManager.rollback(tx)\n throw err\n }\n }\n return descriptor\n }\n}\n\n// ── Property Decorators ─────────────────────────────────────────────────\n\n/** Property injection — resolved lazily from the container */\nexport function Autowired(token?: any): PropertyDecorator {\n return (target, propertyKey) => {\n const existing: Map<string, any> = Reflect.getMetadata(METADATA.AUTOWIRED, target) || new Map()\n existing.set(propertyKey as string, token)\n Reflect.defineMetadata(METADATA.AUTOWIRED, existing, target)\n }\n}\n\n/** Constructor parameter injection with explicit token */\nexport function Inject(token: any): ParameterDecorator {\n return (target, _propertyKey, parameterIndex) => {\n const existing: Record<number, any> = Reflect.getMetadata(METADATA.INJECT, target) || {}\n existing[parameterIndex] = token\n Reflect.defineMetadata(METADATA.INJECT, existing, target)\n }\n}\n\n/**\n * Inject an environment variable value. Evaluated lazily so the env\n * is available at access time, not at decoration time.\n *\n * If no default is provided and the env var is missing, throws at access time\n * to catch misconfiguration early instead of returning undefined.\n *\n * Uses metadata + instance getter to work correctly with `useDefineForClassFields`.\n */\nexport function Value(envKey: string, defaultValue?: any): PropertyDecorator {\n return (target, propertyKey) => {\n const existing: Map<string, { envKey: string; defaultValue?: any }> =\n Reflect.getMetadata(METADATA.VALUE, target) || new Map()\n existing.set(propertyKey as string, { envKey, defaultValue })\n Reflect.defineMetadata(METADATA.VALUE, existing, target)\n }\n}\n\n// ── HTTP Route Decorators ───────────────────────────────────────────────\n\nexport interface RouteDefinition {\n method: string\n path: string\n handlerName: string\n validation?: {\n body?: any\n query?: any\n params?: any\n }\n}\n\nfunction createRouteDecorator(method: string) {\n return (path?: string, validation?: RouteDefinition['validation']): MethodDecorator => {\n return (target, propertyKey) => {\n const routes: RouteDefinition[] =\n Reflect.getMetadata(METADATA.ROUTES, target.constructor) || []\n routes.push({\n method,\n path: path || '/',\n handlerName: propertyKey as string,\n validation,\n })\n Reflect.defineMetadata(METADATA.ROUTES, routes, target.constructor)\n }\n }\n}\n\nexport const Get = createRouteDecorator('GET')\nexport const Post = createRouteDecorator('POST')\nexport const Put = createRouteDecorator('PUT')\nexport const Delete = createRouteDecorator('DELETE')\nexport const Patch = createRouteDecorator('PATCH')\n\n// ── Middleware Decorators ───────────────────────────────────────────────\n\nexport type MiddlewareHandler = (ctx: any, next: () => void) => void | Promise<void>\n\n/** Attach middleware handlers to a class or method */\nexport function Middleware(...handlers: MiddlewareHandler[]): ClassDecorator & MethodDecorator {\n return (target: any, propertyKey?: string | symbol) => {\n if (propertyKey) {\n // Method-level middleware\n const existing: MiddlewareHandler[] =\n Reflect.getMetadata(METADATA.METHOD_MIDDLEWARES, target.constructor, propertyKey) || []\n Reflect.defineMetadata(\n METADATA.METHOD_MIDDLEWARES,\n [...existing, ...handlers],\n target.constructor,\n propertyKey,\n )\n } else {\n // Class-level middleware\n const existing: MiddlewareHandler[] =\n Reflect.getMetadata(METADATA.CLASS_MIDDLEWARES, target) || []\n Reflect.defineMetadata(METADATA.CLASS_MIDDLEWARES, [...existing, ...handlers], target)\n }\n }\n}\n\n// ── File Upload Decorator ───────────────────────────────────────────────\n\nexport interface FileUploadConfig {\n mode: 'single' | 'array' | 'none'\n fieldName?: string\n maxCount?: number\n maxSize?: number\n allowedMimeTypes?: string[]\n}\n\n/** Configure file upload handling for a controller method */\nexport function FileUpload(config: FileUploadConfig): MethodDecorator {\n return (target, propertyKey) => {\n Reflect.defineMetadata(METADATA.FILE_UPLOAD, config, target.constructor, propertyKey)\n }\n}\n\n// ── Builder Decorator ───────────────────────────────────────────────────\n\n/** Add a static builder() method for fluent construction */\nexport function Builder(target: any): void {\n Reflect.defineMetadata(METADATA.BUILDER, true, target)\n\n target.builder = function () {\n const props: Record<string, any> = {}\n const proxy: any = new Proxy(\n {},\n {\n get(_, key) {\n if (key === 'build') {\n return () => Object.assign(new target(), props)\n }\n return (value: any) => {\n props[key as string] = value\n return proxy\n }\n },\n },\n )\n return proxy\n }\n}\n"],"mappings":"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","names":["pendingRegistrations","containerRef","flushPending","container","target","scope","has","register","length","Container","_onReady","registerInContainer","Reflect","defineMetadata","METADATA","INJECTABLE","SCOPE","push","Injectable","options","Scope","SINGLETON","Service","Component","Repository","Configuration","CONFIGURATION","Controller","path","CONTROLLER_PATH","Bean","propertyKey","BEAN","BEAN_OPTIONS","PostConstruct","POST_CONSTRUCT","Transactional","_target","_propertyKey","descriptor","original","value","args","Error","txManager","resolve","Symbol","for","tx","begin","result","apply","commit","err","rollback","Autowired","token","existing","getMetadata","AUTOWIRED","Map","set","Inject","parameterIndex","INJECT","Value","envKey","defaultValue","VALUE","createRouteDecorator","method","validation","routes","ROUTES","handlerName","Get","Post","Put","Delete","Patch","Middleware","handlers","METHOD_MIDDLEWARES","CLASS_MIDDLEWARES","FileUpload","config","FILE_UPLOAD","Builder","BUILDER","builder","props","proxy","Proxy","get","_","key","Object","assign"]}
|