@martel/calyx 1.11.0 → 1.13.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +1 -1
  3. package/src/cache/cache.interceptor.ts +4 -2
  4. package/src/cache/decorators.ts +4 -0
  5. package/src/cache/index.ts +1 -0
  6. package/src/cli/index.ts +7 -1
  7. package/src/config/config.module.ts +16 -2
  8. package/src/config/config.service.ts +20 -6
  9. package/src/core/container.ts +559 -140
  10. package/src/core/index.ts +2 -0
  11. package/src/core/lazy-module-loader.ts +29 -0
  12. package/src/core/metadata.ts +6 -1
  13. package/src/core/testing-module.ts +123 -0
  14. package/src/cqrs/cqrs.ts +264 -0
  15. package/src/database/sequelize.module.ts +239 -0
  16. package/src/event-emitter/decorators.ts +2 -2
  17. package/src/event-emitter/event-emitter.ts +3 -0
  18. package/src/graphql/decorators.ts +16 -0
  19. package/src/graphql/graphql.module.ts +16 -0
  20. package/src/http/application.ts +261 -21
  21. package/src/http/decorators.ts +25 -1
  22. package/src/http/exceptions.ts +97 -0
  23. package/src/http/factory.ts +3 -0
  24. package/src/http/router.ts +27 -4
  25. package/src/index.ts +3 -0
  26. package/src/microservices/clients.module.ts +47 -0
  27. package/src/microservices/exceptions.ts +10 -0
  28. package/src/microservices/index.ts +2 -0
  29. package/src/microservices/microservice.ts +1 -1
  30. package/src/queue/queue.module.ts +73 -5
  31. package/src/schedule/decorators.ts +10 -6
  32. package/src/schedule/index.ts +1 -0
  33. package/src/schedule/schedule.module.ts +3 -2
  34. package/src/schedule/scheduler-registry.ts +50 -0
  35. package/src/security/index.ts +1 -0
  36. package/src/security/throttler.module.ts +108 -0
  37. package/src/terminus/terminus.ts +134 -0
  38. package/src/validation/compiler.ts +133 -10
  39. package/src/validation/decorators.ts +164 -2
  40. package/src/validation/http-pipes.ts +128 -0
  41. package/src/validation/index.ts +1 -0
  42. package/src/websockets/decorators.ts +12 -2
  43. package/src/websockets/exceptions.ts +10 -0
  44. package/src/websockets/index.ts +1 -0
  45. package/tests/circular-di.test.ts +151 -0
  46. package/tests/di.test.ts +10 -2
  47. package/tests/nestjs-parity.test.ts +527 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # [1.13.0](https://github.com/bmartel/calyx/compare/v1.12.0...v1.13.0) (2026-07-01)
2
+
3
+
4
+ ### Features
5
+
6
+ * **core:** implement circular dependency proxy resolution and recursive dynamic modules ([82b7c8d](https://github.com/bmartel/calyx/commit/82b7c8df2973a67f68b12a33f1200b956595f6bc))
7
+ * **nestjs-parity:** implement global prefixing, dynamic host routing, advanced validation, config namespaces, queues, cqrs, and health indicators ([c418b9b](https://github.com/bmartel/calyx/commit/c418b9b3ca32b9a93b3dc14e2aa10aa3ae0c75d9))
8
+
9
+ # [1.12.0](https://github.com/bmartel/calyx/compare/v1.11.0...v1.12.0) (2026-07-01)
10
+
11
+
12
+ ### Features
13
+
14
+ * **core:** implement core NestJS feature parity extensions ([ba69f26](https://github.com/bmartel/calyx/commit/ba69f266d1b6ead3ab2ce4f6c5b112258131ed75))
15
+
1
16
  # [1.11.0](https://github.com/bmartel/calyx/compare/v1.10.1...v1.11.0) (2026-07-01)
2
17
 
3
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@martel/calyx",
3
- "version": "1.11.0",
3
+ "version": "1.13.0",
4
4
  "description": "High-performance Bun-native NestJS-compatible framework",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -18,7 +18,9 @@ export class CacheInterceptor implements NestInterceptor {
18
18
  }
19
19
 
20
20
  const url = new URL(req.url);
21
- const key = `http_cache::${url.pathname}${url.search}`;
21
+ const handler = context.getHandler();
22
+ const key = Reflect.getMetadata('cache_metadata_key', handler) ?? `http_cache::${url.pathname}${url.search}`;
23
+ const ttl = Reflect.getMetadata('cache_metadata_ttl', handler);
22
24
 
23
25
  const cached = await this.cacheService.get(key);
24
26
  if (cached !== undefined) {
@@ -26,7 +28,7 @@ export class CacheInterceptor implements NestInterceptor {
26
28
  }
27
29
 
28
30
  const result = await next.handle();
29
- await this.cacheService.set(key, result);
31
+ await this.cacheService.set(key, result, ttl);
30
32
  return result;
31
33
  }
32
34
  }
@@ -0,0 +1,4 @@
1
+ import { SetMetadata } from '../core/decorators.ts';
2
+
3
+ export const CacheKey = (key: string) => SetMetadata('cache_metadata_key', key);
4
+ export const CacheTTL = (ttl: number) => SetMetadata('cache_metadata_ttl', ttl);
@@ -1,3 +1,4 @@
1
1
  export * from './cache.service.ts';
2
2
  export * from './cache.interceptor.ts';
3
3
  export * from './cache.module.ts';
4
+ export * from './decorators.ts';
package/src/cli/index.ts CHANGED
@@ -97,7 +97,13 @@ function runBuild(cmdArgs: string[]) {
97
97
  '--external',
98
98
  'typeorm',
99
99
  '--external',
100
- 'graphql'
100
+ 'sequelize',
101
+ '--external',
102
+ 'graphql',
103
+ '--external',
104
+ 'class-validator',
105
+ '--external',
106
+ 'class-transformer'
101
107
  ], { stdio: 'inherit' });
102
108
  if (proc.status === 0) {
103
109
  console.log('Build completed successfully. Output at ./dist/main.js');
@@ -40,8 +40,13 @@ export class ConfigModule {
40
40
  if (options.load) {
41
41
  for (const factory of options.load) {
42
42
  const data = factory();
43
- for (const [key, val] of Object.entries(data)) {
44
- configData[key] = String(val);
43
+ const key = (factory as any).KEY;
44
+ if (key) {
45
+ (configData as any)[key] = data;
46
+ } else {
47
+ for (const [k, val] of Object.entries(data)) {
48
+ configData[k] = String(val);
49
+ }
45
50
  }
46
51
  }
47
52
  }
@@ -59,3 +64,12 @@ export class ConfigModule {
59
64
  };
60
65
  }
61
66
  }
67
+
68
+ export function registerAs<T extends Record<string, any> = Record<string, any>>(
69
+ token: string,
70
+ configFactory: () => T,
71
+ ) {
72
+ const factory = () => configFactory();
73
+ Object.defineProperty(factory, 'KEY', { value: token, writable: false });
74
+ return factory;
75
+ }
@@ -2,23 +2,37 @@ import { Injectable } from '../core/decorators.ts';
2
2
 
3
3
  @Injectable()
4
4
  export class ConfigService {
5
- private readonly env: Record<string, string> = {};
5
+ private readonly env: Record<string, any> = {};
6
6
 
7
- constructor(internalConfig?: Record<string, string>) {
7
+ constructor(internalConfig?: Record<string, any>) {
8
8
  this.env = internalConfig ?? (process.env as Record<string, string>);
9
9
  }
10
10
 
11
- get<T = string>(path: string, defaultValue?: T): T {
12
- const val = this.env[path];
11
+ get<T = any>(path: string, defaultValue?: T): T {
12
+ let val = this.env[path];
13
+ if (val === undefined && path.includes('.')) {
14
+ const segments = path.split('.');
15
+ let current: any = this.env;
16
+ for (const segment of segments) {
17
+ if (current && typeof current === 'object' && segment in current) {
18
+ current = current[segment];
19
+ } else {
20
+ current = undefined;
21
+ break;
22
+ }
23
+ }
24
+ val = current;
25
+ }
26
+
13
27
  if (val === undefined) {
14
28
  return defaultValue as T;
15
29
  }
16
30
  if (val === 'true') return true as unknown as T;
17
31
  if (val === 'false') return false as unknown as T;
18
32
  const num = Number(val);
19
- if (!isNaN(num) && val.trim() !== '') {
33
+ if (typeof val === 'string' && !isNaN(num) && val.trim() !== '') {
20
34
  return num as unknown as T;
21
35
  }
22
- return val as unknown as T;
36
+ return val as T;
23
37
  }
24
38
  }