fragment-ts 1.0.28 → 1.0.30

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.
Files changed (51) hide show
  1. package/dist/cli/commands/init.command.js +1 -1
  2. package/dist/core/container/di-container.d.ts +7 -6
  3. package/dist/core/container/di-container.d.ts.map +1 -1
  4. package/dist/core/container/di-container.js +162 -129
  5. package/dist/core/container/di-container.js.map +1 -1
  6. package/dist/core/decorators/application.decorator.d.ts.map +1 -1
  7. package/dist/core/decorators/application.decorator.js +2 -1
  8. package/dist/core/decorators/application.decorator.js.map +1 -1
  9. package/dist/core/decorators/auto-configuration.decorator.d.ts.map +1 -1
  10. package/dist/core/decorators/auto-configuration.decorator.js +4 -3
  11. package/dist/core/decorators/auto-configuration.decorator.js.map +1 -1
  12. package/dist/core/decorators/controller.decorator.d.ts.map +1 -1
  13. package/dist/core/decorators/controller.decorator.js +1 -0
  14. package/dist/core/decorators/controller.decorator.js.map +1 -1
  15. package/dist/core/decorators/http.decorators.d.ts.map +1 -1
  16. package/dist/core/decorators/http.decorators.js +9 -0
  17. package/dist/core/decorators/http.decorators.js.map +1 -1
  18. package/dist/core/decorators/injectable.decorator.d.ts.map +1 -1
  19. package/dist/core/decorators/injectable.decorator.js +1 -0
  20. package/dist/core/decorators/injectable.decorator.js.map +1 -1
  21. package/dist/core/decorators/injection.decorators.d.ts.map +1 -1
  22. package/dist/core/decorators/injection.decorators.js +49 -19
  23. package/dist/core/decorators/injection.decorators.js.map +1 -1
  24. package/dist/core/decorators/repository.decorator.d.ts.map +1 -1
  25. package/dist/core/decorators/repository.decorator.js +1 -0
  26. package/dist/core/decorators/repository.decorator.js.map +1 -1
  27. package/dist/core/decorators/service.decorator.d.ts.map +1 -1
  28. package/dist/core/decorators/service.decorator.js +1 -0
  29. package/dist/core/decorators/service.decorator.js.map +1 -1
  30. package/dist/core/metadata/metadata-storage.d.ts +11 -0
  31. package/dist/core/metadata/metadata-storage.d.ts.map +1 -1
  32. package/dist/core/metadata/metadata-storage.js +22 -0
  33. package/dist/core/metadata/metadata-storage.js.map +1 -1
  34. package/dist/web/application.d.ts +0 -6
  35. package/dist/web/application.d.ts.map +1 -1
  36. package/dist/web/application.js +75 -38
  37. package/dist/web/application.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/cli/commands/init.command.ts +1 -1
  40. package/src/core/container/di-container.ts +247 -181
  41. package/src/core/decorators/application.decorator.ts +2 -1
  42. package/src/core/decorators/auto-configuration.decorator.ts +9 -8
  43. package/src/core/decorators/controller.decorator.ts +2 -1
  44. package/src/core/decorators/http.decorators.ts +17 -0
  45. package/src/core/decorators/injectable.decorator.ts +1 -0
  46. package/src/core/decorators/injection.decorators.ts +62 -22
  47. package/src/core/decorators/repository.decorator.ts +1 -0
  48. package/src/core/decorators/service.decorator.ts +1 -0
  49. package/src/core/metadata/metadata-storage.ts +47 -0
  50. package/src/web/application.ts +107 -64
  51. package/tsconfig.json +4 -3
@@ -1,5 +1,5 @@
1
1
  import { METADATA_KEYS } from "../metadata/metadata-keys";
2
- import { Scope } from "../decorators/injectable.decorator";
2
+ import { MetadataStorage } from "../metadata/metadata-storage";
3
3
 
4
4
  export class DIContainer {
5
5
  private static instance: DIContainer;
@@ -8,6 +8,11 @@ export class DIContainer {
8
8
  private factories: Map<any, () => any> = new Map();
9
9
  private constructing: Set<any> = new Set();
10
10
  private registered: Set<any> = new Set();
11
+ private metadataStorage: MetadataStorage;
12
+
13
+ private constructor() {
14
+ this.metadataStorage = MetadataStorage.getInstance();
15
+ }
11
16
 
12
17
  static getInstance(): DIContainer {
13
18
  if (!DIContainer.instance) {
@@ -18,19 +23,23 @@ export class DIContainer {
18
23
 
19
24
  register(token: any, instance?: any, factory?: () => any): void {
20
25
  this.registered.add(token);
26
+ console.log(
27
+ ` ✓ Registered token: ${typeof token === "function" ? token.name : token}`,
28
+ );
21
29
 
22
30
  if (instance) {
23
31
  this.singletons.set(token, instance);
32
+ console.log(` ➤ Singleton instance created`);
24
33
  } else if (factory) {
25
34
  this.factories.set(token, factory);
35
+ console.log(` ➤ Factory registered`);
26
36
  }
27
37
  }
28
38
 
29
39
  resolve<T>(token: any): T {
30
40
  if (typeof token === "function" && !this.registered.has(token)) {
31
- throw new Error(
32
- `Cannot resolve ${token.name}: Not registered as injectable. ` +
33
- `Did you forget to add @Injectable(), @Service(), @Controller(), or @Repository()?`,
41
+ console.log(
42
+ ` ℹ️ Token ${token.name} not explicitly registered, attempting to create instance`,
34
43
  );
35
44
  }
36
45
 
@@ -40,24 +49,35 @@ export class DIContainer {
40
49
  );
41
50
  }
42
51
 
52
+ // Check singletons first
43
53
  if (this.singletons.has(token)) {
54
+ console.log(
55
+ ` ✓ Resolved from singleton cache: ${typeof token === "function" ? token.name : token}`,
56
+ );
44
57
  return this.singletons.get(token);
45
58
  }
46
59
 
60
+ // Check factories
47
61
  if (this.factories.has(token)) {
62
+ console.log(
63
+ ` 🏭 Creating instance from factory: ${typeof token === "function" ? token.name : token}`,
64
+ );
48
65
  const factory = this.factories.get(token)!;
49
66
  const instance = factory();
67
+
50
68
  const scope =
51
69
  Reflect.getMetadata(METADATA_KEYS.SCOPE, token) || "singleton";
52
-
53
70
  if (scope === "singleton") {
54
71
  this.singletons.set(token, instance);
72
+ console.log(` ➤ Cached as singleton`);
55
73
  }
56
74
 
57
75
  return instance;
58
76
  }
59
77
 
78
+ // Create new instance for class tokens
60
79
  if (typeof token === "function") {
80
+ console.log(` 🔨 Creating new instance: ${token.name}`);
61
81
  this.constructing.add(token);
62
82
 
63
83
  try {
@@ -67,38 +87,53 @@ export class DIContainer {
67
87
 
68
88
  if (scope === "singleton") {
69
89
  this.singletons.set(token, instance);
90
+ console.log(` ➤ Registered as singleton`);
70
91
  }
71
92
 
72
93
  this.constructing.delete(token);
73
94
  return instance;
74
95
  } catch (error) {
75
96
  this.constructing.delete(token);
97
+ console.error(
98
+ ` ❌ Failed to create instance of ${token.name}: ${error}`,
99
+ );
76
100
  throw error;
77
101
  }
78
102
  }
79
103
 
80
- throw new Error(`Cannot resolve dependency: ${token}`);
104
+ throw new Error(
105
+ `Cannot resolve dependency: ${typeof token === "function" ? token.name : token}`,
106
+ );
81
107
  }
82
108
 
83
109
  private createInstance(target: any): any {
84
- console.log(` 🔨 Creating instance of ${target.name}`);
110
+ const className = target.name;
111
+ console.log(` 🏗️ Constructing instance of ${className}`);
85
112
 
113
+ // Get constructor parameter types
86
114
  const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
115
+ console.log(
116
+ ` 📋 Constructor parameters for ${className}: ${paramTypes.length}`,
117
+ );
87
118
 
88
119
  const params = paramTypes.map((type: any, index: number) => {
89
120
  if (!type || type === Object) {
90
121
  console.warn(
91
- ` ⚠️ Constructor param ${index} of ${target.name} has no type`,
122
+ ` ⚠️ Constructor param ${index} of ${className} has no type information`,
92
123
  );
93
124
  return undefined;
94
125
  }
95
- console.log(` 📦 Resolving constructor dependency: ${type.name}`);
126
+
127
+ console.log(
128
+ ` 🔌 Resolving constructor dependency [${index}]: ${type.name || type}`,
129
+ );
96
130
  return this.resolve(type);
97
131
  });
98
132
 
133
+ console.log(` 🚀 Instantiating ${className}`);
99
134
  const instance = new target(...params);
100
135
 
101
- // CRITICAL: Inject properties
136
+ // Inject properties
102
137
  this.injectProperties(instance);
103
138
 
104
139
  // Call @PostConstruct
@@ -106,12 +141,13 @@ export class DIContainer {
106
141
  METADATA_KEYS.POST_CONSTRUCT,
107
142
  target,
108
143
  );
144
+
109
145
  if (
110
146
  postConstructMethod &&
111
147
  typeof instance[postConstructMethod] === "function"
112
148
  ) {
113
149
  console.log(
114
- ` 🎯 Calling @PostConstruct: ${target.name}.${postConstructMethod}()`,
150
+ ` 🎯 Calling @PostConstruct method: ${className}.${String(postConstructMethod)}()`,
115
151
  );
116
152
  instance[postConstructMethod]();
117
153
  }
@@ -121,220 +157,204 @@ export class DIContainer {
121
157
 
122
158
  private injectProperties(instance: any): void {
123
159
  const constructor = instance.constructor;
124
- console.log(`🔍 Checking properties for injection on ${constructor.name}`);
160
+ const className = constructor.name;
125
161
 
126
- // Get all own property keys of the instance (including inherited via getters/setters if needed)
127
- // But primarily own enumerable + non-enumerable properties
128
- let props: string[] = [];
129
- let obj = instance;
162
+ console.log(` 🔍 Scanning for property injections on ${className}`);
130
163
 
131
- // Walk up the prototype chain to include properties from parent classes
132
- while (obj && obj !== Object.prototype) {
133
- props = props.concat(Object.getOwnPropertyNames(obj));
134
- obj = Object.getPrototypeOf(obj);
135
- }
164
+ // Get all property injections from metadata storage
165
+ const propertyInjections =
166
+ this.metadataStorage.getPropertyInjections(constructor);
136
167
 
137
- // Deduplicate
138
- const uniqueProps = Array.from(new Set(props));
168
+ if (propertyInjections.length === 0) {
169
+ console.log(` ℹ️ No property injections registered for ${className}`);
170
+ return;
171
+ }
139
172
 
140
173
  console.log(
141
- `📋 Instance properties (including inherited): ${uniqueProps.filter((p) => p !== "constructor").join(", ") || "none"}`,
174
+ ` 📌 Found ${propertyInjections.length} property injection(s) for ${className}`,
142
175
  );
143
176
 
144
- for (const prop of uniqueProps) {
145
- if (prop === "constructor") continue;
177
+ for (const { propertyKey, injections } of propertyInjections) {
178
+ console.log(` ➤ Property: ${propertyKey}`);
146
179
 
147
- // Check each injection type on the instance and its prototype
148
- this.tryInjectAutowired(instance, instance, prop, constructor.name);
149
- this.tryInjectByToken(instance, instance, prop, constructor.name);
150
- this.tryInjectValue(instance, instance, prop, constructor.name);
151
- this.tryInjectRepository(instance, instance, prop, constructor.name);
152
- this.tryInjectLazy(instance, instance, prop, constructor.name);
153
- }
154
- }
180
+ for (const injection of injections) {
181
+ console.log(` • Injection type: ${injection.type}`);
155
182
 
156
- private checkForDecoratedProperties(
157
- instance: any,
158
- constructor: Function,
159
- ): void {
160
- // Check all metadata keys that might be attached to properties
161
- const propertyKeys = [
162
- ...(Reflect.getMetadataKeys(constructor.prototype) || []),
163
- ...(Reflect.getMetadataKeys(instance) || []),
164
- ];
165
-
166
- // Filter for property-related metadata
167
- for (const key of propertyKeys) {
168
- if (key.includes("fragment:")) {
169
- // This is a Fragment metadata key, need to check if it's attached to a property
170
- const metadataValue = Reflect.getMetadata(key, constructor.prototype);
171
- if (metadataValue && typeof metadataValue === "object") {
172
- // Could be a property metadata
173
- for (const prop of Object.keys(metadataValue)) {
174
- if (prop !== "constructor") {
175
- this.tryInjectAutowired(
183
+ try {
184
+ switch (injection.type) {
185
+ case "autowired":
186
+ this.injectAutowiredProperty(
176
187
  instance,
177
- constructor.prototype,
178
- prop,
179
- constructor.name,
188
+ propertyKey,
189
+ injection.metadata?.type,
190
+ className,
180
191
  );
181
- this.tryInjectByToken(
192
+ break;
193
+ case "inject":
194
+ this.injectTokenProperty(
182
195
  instance,
183
- constructor.prototype,
184
- prop,
185
- constructor.name,
196
+ propertyKey,
197
+ injection.metadata?.token,
198
+ className,
186
199
  );
187
- this.tryInjectValue(
200
+ break;
201
+ case "repository":
202
+ this.injectRepositoryProperty(
188
203
  instance,
189
- constructor.prototype,
190
- prop,
191
- constructor.name,
204
+ propertyKey,
205
+ injection.metadata?.entity,
206
+ className,
192
207
  );
193
- this.tryInjectRepository(
208
+ break;
209
+ case "value":
210
+ this.injectValueProperty(
194
211
  instance,
195
- constructor.prototype,
196
- prop,
197
- constructor.name,
212
+ propertyKey,
213
+ injection.metadata?.expression,
214
+ className,
198
215
  );
199
- }
216
+ break;
217
+ case "lazy":
218
+ this.injectLazyProperty(instance, propertyKey, className);
219
+ break;
200
220
  }
221
+ } catch (error) {
222
+ const isOptional = Reflect.getMetadata(
223
+ METADATA_KEYS.OPTIONAL,
224
+ constructor.prototype,
225
+ propertyKey,
226
+ );
227
+
228
+ if (!isOptional) {
229
+ console.error(
230
+ ` ❌ Failed to inject ${propertyKey} in ${className}: ${error}`,
231
+ );
232
+ throw error;
233
+ }
234
+
235
+ console.warn(
236
+ ` ⚠️ Optional dependency ${propertyKey} not available for ${className}`,
237
+ );
238
+ instance[propertyKey] = undefined;
201
239
  }
202
240
  }
203
241
  }
204
242
  }
205
243
 
206
- private tryInjectAutowired(
244
+ private injectAutowiredProperty(
207
245
  instance: any,
208
- proto: any,
209
- prop: string,
246
+ propertyKey: string,
247
+ type: any,
210
248
  className: string,
211
249
  ): void {
212
- const type = Reflect.getMetadata(METADATA_KEYS.AUTOWIRED, proto, prop);
213
-
214
- if (!type) return;
215
-
216
- console.log(` 💉 @Autowired found: ${className}.${prop} -> ${type.name}`);
217
-
218
- const isOptional = Reflect.getMetadata(METADATA_KEYS.OPTIONAL, proto, prop);
219
-
220
- try {
221
- instance[prop] = this.resolve(type);
222
- console.log(` ✅ Injected ${type.name} into ${className}.${prop}`);
223
- } catch (error) {
224
- if (!isOptional) {
250
+ if (!type) {
251
+ const designType = Reflect.getMetadata(
252
+ "design:type",
253
+ instance,
254
+ propertyKey,
255
+ );
256
+ if (designType && designType !== Object) {
257
+ type = designType;
258
+ console.warn(
259
+ ` ⚠️ Using design:type metadata for ${className}.${propertyKey} as fallback`,
260
+ );
261
+ } else {
225
262
  throw new Error(
226
- `Failed to autowire ${type.name} into ${className}.${prop}: ${error}`,
263
+ `Type information not available for ${className}.${propertyKey}`,
227
264
  );
228
265
  }
229
- console.warn(
230
- ` ⚠️ Optional dependency ${type.name} not available for ${className}.${prop}`,
231
- );
232
- instance[prop] = undefined;
233
266
  }
267
+
268
+ console.log(` 💉 @Autowired: ${className}.${propertyKey} -> ${type.name}`);
269
+ instance[propertyKey] = this.resolve(type);
270
+ console.log(` ✅ Injected ${type.name} into ${className}.${propertyKey}`);
234
271
  }
235
272
 
236
- private tryInjectByToken(
273
+ private injectTokenProperty(
237
274
  instance: any,
238
- proto: any,
239
- prop: string,
275
+ propertyKey: string,
276
+ token: any,
240
277
  className: string,
241
278
  ): void {
242
- const token = Reflect.getMetadata(METADATA_KEYS.INJECT, proto, prop);
243
-
244
- if (!token) return;
245
-
246
- const tokenName = typeof token === "string" ? token : token.name;
247
- console.log(` 💉 @Inject found: ${className}.${prop} -> ${tokenName}`);
248
-
249
- const isOptional = Reflect.getMetadata(METADATA_KEYS.OPTIONAL, proto, prop);
250
-
251
- try {
252
- instance[prop] = this.resolve(token);
253
- console.log(` ✅ Injected ${tokenName} into ${className}.${prop}`);
254
- } catch (error) {
255
- if (!isOptional) {
256
- throw new Error(
257
- `Failed to inject ${tokenName} into ${className}.${prop}: ${error}`,
258
- );
259
- }
260
- console.warn(
261
- ` ⚠️ Optional dependency ${tokenName} not available for ${className}.${prop}`,
279
+ if (!token) {
280
+ throw new Error(
281
+ `Token not provided for @Inject on ${className}.${propertyKey}`,
262
282
  );
263
- instance[prop] = undefined;
264
283
  }
284
+
285
+ const tokenName = typeof token === "string" ? token : token.name;
286
+ console.log(` 💉 @Inject: ${className}.${propertyKey} -> ${tokenName}`);
287
+ instance[propertyKey] = this.resolve(token);
288
+ console.log(` ✅ Injected ${tokenName} into ${className}.${propertyKey}`);
265
289
  }
266
290
 
267
- private tryInjectValue(
291
+ private injectRepositoryProperty(
268
292
  instance: any,
269
- proto: any,
270
- prop: string,
293
+ propertyKey: string,
294
+ entity: any,
271
295
  className: string,
272
296
  ): void {
273
- const expression = Reflect.getMetadata(METADATA_KEYS.VALUE, proto, prop);
274
-
275
- if (expression === undefined) return;
297
+ if (!entity) {
298
+ throw new Error(
299
+ `Entity not provided for @InjectRepository on ${className}.${propertyKey}`,
300
+ );
301
+ }
276
302
 
277
- console.log(` 🔧 @Value found: ${className}.${prop} = ${expression}`);
278
- instance[prop] = this.resolveValue(expression);
279
- console.log(` ✅ Set value for ${className}.${prop}`);
303
+ console.log(
304
+ ` 💾 @InjectRepository: ${className}.${propertyKey} -> Repository<${entity.name}>`,
305
+ );
306
+ instance[propertyKey] = this.resolveRepository(entity);
307
+ console.log(
308
+ ` ✅ Injected Repository<${entity.name}> into ${className}.${propertyKey}`,
309
+ );
280
310
  }
281
311
 
282
- private tryInjectRepository(
312
+ private injectValueProperty(
283
313
  instance: any,
284
- proto: any,
285
- prop: string,
314
+ propertyKey: string,
315
+ expression: string,
286
316
  className: string,
287
317
  ): void {
288
- const entity = Reflect.getMetadata(
289
- METADATA_KEYS.INJECT_REPOSITORY,
290
- proto,
291
- prop,
292
- );
293
-
294
- if (!entity) return;
295
-
296
- console.log(
297
- ` 💾 @InjectRepository found: ${className}.${prop} -> Repository<${entity.name}>`,
298
- );
299
-
300
- try {
301
- instance[prop] = this.resolveRepository(entity);
302
- console.log(
303
- ` ✅ Injected Repository<${entity.name}> into ${className}.${prop}`,
304
- );
305
- } catch (error) {
318
+ if (!expression) {
306
319
  throw new Error(
307
- `Failed to inject repository for ${entity.name} into ${className}.${prop}: ${error}`,
320
+ `Expression not provided for @Value on ${className}.${propertyKey}`,
308
321
  );
309
322
  }
323
+
324
+ console.log(` 🔧 @Value: ${className}.${propertyKey} = ${expression}`);
325
+ instance[propertyKey] = this.resolveValue(expression);
326
+ console.log(` ✅ Set value for ${className}.${propertyKey}`);
310
327
  }
311
328
 
312
- private tryInjectLazy(
329
+ private injectLazyProperty(
313
330
  instance: any,
314
- proto: any,
315
- prop: string,
331
+ propertyKey: string,
316
332
  className: string,
317
333
  ): void {
318
- const isLazy = Reflect.getMetadata(METADATA_KEYS.LAZY, proto, prop);
334
+ // Get the type for later resolution
335
+ const type = Reflect.getMetadata("design:type", instance, propertyKey);
336
+ if (!type) {
337
+ throw new Error(
338
+ `Type information not available for @Lazy ${className}.${propertyKey}`,
339
+ );
340
+ }
319
341
 
320
- if (!isLazy) return;
321
-
322
- const type = Reflect.getMetadata("design:type", proto, prop);
323
- console.log(
324
- ` ⏳ @Lazy found: ${className}.${prop} (${type?.name || "unknown"})`,
325
- );
342
+ console.log(` ⏳ @Lazy: ${className}.${propertyKey} (${type.name})`);
326
343
 
327
344
  let cached: any = null;
328
345
  let resolved = false;
329
346
 
330
- Object.defineProperty(instance, prop, {
347
+ Object.defineProperty(instance, propertyKey, {
331
348
  get: () => {
332
349
  if (!resolved) {
333
350
  console.log(
334
- ` 🔓 Lazy-loading ${type.name} for ${className}.${prop}`,
351
+ ` 🔓 Lazy-loading ${type.name} for ${className}.${propertyKey}`,
335
352
  );
336
353
  cached = this.resolve(type);
337
354
  resolved = true;
355
+ console.log(
356
+ ` ✅ Lazy-loaded ${type.name} for ${className}.${propertyKey}`,
357
+ );
338
358
  }
339
359
  return cached;
340
360
  },
@@ -344,45 +364,79 @@ export class DIContainer {
344
364
  }
345
365
 
346
366
  private resolveValue(expression: string): any {
347
- const match = expression.match(
348
- /\$\{([^:}]+)(?::([^}]*))?\}|\$([A-Z_][A-Z0-9_]*)/i,
349
- );
350
- if (match) {
351
- const key = match[1] || match[3];
352
- const defaultValue = match[2];
353
- const value = process.env[key];
354
-
355
- if (value === undefined) {
356
- if (defaultValue !== undefined) {
357
- return defaultValue;
367
+ // Standardize expression format (remove ${} if present)
368
+ let key = expression.replace(/\$\{|\}/g, "");
369
+ let defaultValue: any = undefined;
370
+
371
+ // Handle default values (format: KEY:default)
372
+ const defaultMatch = key.match(/^(.*?):(.*)$/);
373
+ if (defaultMatch) {
374
+ key = defaultMatch[1].trim();
375
+ defaultValue = defaultMatch[2].trim();
376
+
377
+ // Try to parse default value as JSON or number if possible
378
+ try {
379
+ defaultValue = JSON.parse(defaultValue);
380
+ } catch {
381
+ // Try number conversion
382
+ const numValue = parseFloat(defaultValue);
383
+ if (!isNaN(numValue) && defaultValue.trim() === numValue.toString()) {
384
+ defaultValue = numValue;
385
+ }
386
+ // Try boolean conversion
387
+ else if (defaultValue.toLowerCase() === "true") {
388
+ defaultValue = true;
389
+ } else if (defaultValue.toLowerCase() === "false") {
390
+ defaultValue = false;
358
391
  }
359
- console.warn(` ⚠️ Environment variable "${key}" not defined`);
360
- return "";
361
392
  }
393
+ }
394
+
395
+ console.log(
396
+ ` 🔍 Resolving config value: ${key}${defaultValue !== undefined ? ` (default: ${defaultValue})` : ""}`,
397
+ );
398
+
399
+ // Check environment variables first
400
+ const envValue = process.env[key.toUpperCase()] || process.env[key];
401
+ if (envValue !== undefined) {
402
+ console.log(` 🌍 Found in environment: ${envValue}`);
362
403
 
363
- if (value.startsWith("{") || value.startsWith("[")) {
404
+ // Try to parse as JSON if it looks like an object/array
405
+ if (envValue.startsWith("{") || envValue.startsWith("[")) {
364
406
  try {
365
- return JSON.parse(value);
407
+ return JSON.parse(envValue);
366
408
  } catch {
367
- return value;
409
+ return envValue;
368
410
  }
369
411
  }
370
412
 
371
- if (/^\d+(\.\d+)?$/.test(value)) {
372
- return parseFloat(value);
413
+ // Try to parse as number
414
+ const numValue = parseFloat(envValue);
415
+ if (!isNaN(numValue) && envValue.trim() === numValue.toString()) {
416
+ return numValue;
373
417
  }
374
418
 
375
- if (value.toLowerCase() === "true") return true;
376
- if (value.toLowerCase() === "false") return false;
419
+ // Try to parse as boolean
420
+ if (envValue.toLowerCase() === "true") return true;
421
+ if (envValue.toLowerCase() === "false") return false;
422
+
423
+ return envValue;
424
+ }
377
425
 
378
- return value;
426
+ // Return default value if available
427
+ if (defaultValue !== undefined) {
428
+ console.log(` 📦 Using default value: ${defaultValue}`);
429
+ return defaultValue;
379
430
  }
380
431
 
381
- return expression;
432
+ console.warn(` ⚠️ Config value not found: ${key}`);
433
+ return undefined;
382
434
  }
383
435
 
384
436
  private resolveRepository(entity: any): any {
385
437
  try {
438
+ console.log(` 🔍 Resolving repository for entity: ${entity.name}`);
439
+
386
440
  const { TypeORMModule } = require("../../typeorm/typeorm-module");
387
441
  const dataSource = TypeORMModule.getDataSource();
388
442
 
@@ -390,8 +444,14 @@ export class DIContainer {
390
444
  throw new Error("TypeORM DataSource not initialized");
391
445
  }
392
446
 
447
+ console.log(
448
+ ` ✅ Found DataSource, creating repository for ${entity.name}`,
449
+ );
393
450
  return dataSource.getRepository(entity);
394
451
  } catch (error) {
452
+ console.error(
453
+ ` ❌ Failed to resolve repository for ${entity.name}: ${(error as Error).message}`,
454
+ );
395
455
  throw new Error(
396
456
  `Failed to resolve repository for ${entity.name}: ${(error as Error)?.message}`,
397
457
  );
@@ -399,7 +459,11 @@ export class DIContainer {
399
459
  }
400
460
 
401
461
  has(token: any): boolean {
402
- return this.registered.has(token);
462
+ return (
463
+ this.registered.has(token) ||
464
+ this.singletons.has(token) ||
465
+ this.factories.has(token)
466
+ );
403
467
  }
404
468
 
405
469
  getAllInstances(): any[] {
@@ -407,6 +471,7 @@ export class DIContainer {
407
471
  }
408
472
 
409
473
  clear(): void {
474
+ console.log("🧹 Clearing DI Container");
410
475
  this.singletons.clear();
411
476
  this.transients.clear();
412
477
  this.factories.clear();
@@ -416,5 +481,6 @@ export class DIContainer {
416
481
 
417
482
  reset(): void {
418
483
  this.clear();
484
+ console.log("🔁 DI Container reset complete");
419
485
  }
420
486
  }
@@ -11,6 +11,7 @@ export function FragmentApplication(
11
11
  options: ApplicationOptions = {},
12
12
  ): ClassDecorator {
13
13
  return (target: any) => {
14
+ console.log(`🚀 Registering Fragment application: ${target.name}`);
14
15
  Reflect.defineMetadata(
15
16
  METADATA_KEYS.APPLICATION,
16
17
  {
@@ -18,7 +19,7 @@ export function FragmentApplication(
18
19
  port: options.port || 3000,
19
20
  host: options.host || "0.0.0.0",
20
21
  configPath: options.configPath || "fragment.json",
21
- autoScan: options.autoScan || true,
22
+ autoScan: options.autoScan !== false, // default to true
22
23
  },
23
24
  target,
24
25
  );