@hazeljs/core 0.2.0-alpha.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.
Files changed (195) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +560 -0
  3. package/dist/__tests__/container.test.d.ts +2 -0
  4. package/dist/__tests__/container.test.d.ts.map +1 -0
  5. package/dist/__tests__/container.test.js +454 -0
  6. package/dist/__tests__/decorators.test.d.ts +2 -0
  7. package/dist/__tests__/decorators.test.d.ts.map +1 -0
  8. package/dist/__tests__/decorators.test.js +1237 -0
  9. package/dist/__tests__/errors/http.error.test.d.ts +2 -0
  10. package/dist/__tests__/errors/http.error.test.d.ts.map +1 -0
  11. package/dist/__tests__/errors/http.error.test.js +117 -0
  12. package/dist/__tests__/filters/exception-filter.test.d.ts +2 -0
  13. package/dist/__tests__/filters/exception-filter.test.d.ts.map +1 -0
  14. package/dist/__tests__/filters/exception-filter.test.js +135 -0
  15. package/dist/__tests__/filters/http-exception.filter.test.d.ts +2 -0
  16. package/dist/__tests__/filters/http-exception.filter.test.d.ts.map +1 -0
  17. package/dist/__tests__/filters/http-exception.filter.test.js +119 -0
  18. package/dist/__tests__/hazel-app.test.d.ts +2 -0
  19. package/dist/__tests__/hazel-app.test.d.ts.map +1 -0
  20. package/dist/__tests__/hazel-app.test.js +810 -0
  21. package/dist/__tests__/hazel-module.test.d.ts +2 -0
  22. package/dist/__tests__/hazel-module.test.d.ts.map +1 -0
  23. package/dist/__tests__/hazel-module.test.js +408 -0
  24. package/dist/__tests__/hazel-response.test.d.ts +2 -0
  25. package/dist/__tests__/hazel-response.test.d.ts.map +1 -0
  26. package/dist/__tests__/hazel-response.test.js +138 -0
  27. package/dist/__tests__/health.test.d.ts +2 -0
  28. package/dist/__tests__/health.test.d.ts.map +1 -0
  29. package/dist/__tests__/health.test.js +147 -0
  30. package/dist/__tests__/index.test.d.ts +2 -0
  31. package/dist/__tests__/index.test.d.ts.map +1 -0
  32. package/dist/__tests__/index.test.js +239 -0
  33. package/dist/__tests__/interceptors/interceptor.test.d.ts +2 -0
  34. package/dist/__tests__/interceptors/interceptor.test.d.ts.map +1 -0
  35. package/dist/__tests__/interceptors/interceptor.test.js +166 -0
  36. package/dist/__tests__/logger.test.d.ts +2 -0
  37. package/dist/__tests__/logger.test.d.ts.map +1 -0
  38. package/dist/__tests__/logger.test.js +141 -0
  39. package/dist/__tests__/middleware/cors.test.d.ts +2 -0
  40. package/dist/__tests__/middleware/cors.test.d.ts.map +1 -0
  41. package/dist/__tests__/middleware/cors.test.js +129 -0
  42. package/dist/__tests__/middleware/csrf.test.d.ts +2 -0
  43. package/dist/__tests__/middleware/csrf.test.d.ts.map +1 -0
  44. package/dist/__tests__/middleware/csrf.test.js +247 -0
  45. package/dist/__tests__/middleware/global-middleware.test.d.ts +2 -0
  46. package/dist/__tests__/middleware/global-middleware.test.d.ts.map +1 -0
  47. package/dist/__tests__/middleware/global-middleware.test.js +259 -0
  48. package/dist/__tests__/middleware/rate-limit.test.d.ts +2 -0
  49. package/dist/__tests__/middleware/rate-limit.test.d.ts.map +1 -0
  50. package/dist/__tests__/middleware/rate-limit.test.js +264 -0
  51. package/dist/__tests__/middleware/security-headers.test.d.ts +2 -0
  52. package/dist/__tests__/middleware/security-headers.test.d.ts.map +1 -0
  53. package/dist/__tests__/middleware/security-headers.test.js +229 -0
  54. package/dist/__tests__/middleware/timeout.test.d.ts +2 -0
  55. package/dist/__tests__/middleware/timeout.test.d.ts.map +1 -0
  56. package/dist/__tests__/middleware/timeout.test.js +132 -0
  57. package/dist/__tests__/middleware.test.d.ts +2 -0
  58. package/dist/__tests__/middleware.test.d.ts.map +1 -0
  59. package/dist/__tests__/middleware.test.js +180 -0
  60. package/dist/__tests__/pipes/pipe.test.d.ts +2 -0
  61. package/dist/__tests__/pipes/pipe.test.d.ts.map +1 -0
  62. package/dist/__tests__/pipes/pipe.test.js +245 -0
  63. package/dist/__tests__/pipes/validation.pipe.test.d.ts +2 -0
  64. package/dist/__tests__/pipes/validation.pipe.test.d.ts.map +1 -0
  65. package/dist/__tests__/pipes/validation.pipe.test.js +297 -0
  66. package/dist/__tests__/request-parser.test.d.ts +2 -0
  67. package/dist/__tests__/request-parser.test.d.ts.map +1 -0
  68. package/dist/__tests__/request-parser.test.js +182 -0
  69. package/dist/__tests__/router.test.d.ts +2 -0
  70. package/dist/__tests__/router.test.d.ts.map +1 -0
  71. package/dist/__tests__/router.test.js +1183 -0
  72. package/dist/__tests__/routing/route-matcher.test.d.ts +2 -0
  73. package/dist/__tests__/routing/route-matcher.test.d.ts.map +1 -0
  74. package/dist/__tests__/routing/route-matcher.test.js +219 -0
  75. package/dist/__tests__/routing/version.decorator.test.d.ts +2 -0
  76. package/dist/__tests__/routing/version.decorator.test.d.ts.map +1 -0
  77. package/dist/__tests__/routing/version.decorator.test.js +298 -0
  78. package/dist/__tests__/service.test.d.ts +2 -0
  79. package/dist/__tests__/service.test.d.ts.map +1 -0
  80. package/dist/__tests__/service.test.js +121 -0
  81. package/dist/__tests__/shutdown.test.d.ts +2 -0
  82. package/dist/__tests__/shutdown.test.d.ts.map +1 -0
  83. package/dist/__tests__/shutdown.test.js +250 -0
  84. package/dist/__tests__/testing/testing.module.test.d.ts +2 -0
  85. package/dist/__tests__/testing/testing.module.test.d.ts.map +1 -0
  86. package/dist/__tests__/testing/testing.module.test.js +370 -0
  87. package/dist/__tests__/upload/file-upload.test.d.ts +2 -0
  88. package/dist/__tests__/upload/file-upload.test.d.ts.map +1 -0
  89. package/dist/__tests__/upload/file-upload.test.js +498 -0
  90. package/dist/__tests__/utils/sanitize.test.d.ts +2 -0
  91. package/dist/__tests__/utils/sanitize.test.d.ts.map +1 -0
  92. package/dist/__tests__/utils/sanitize.test.js +291 -0
  93. package/dist/__tests__/validator.test.d.ts +2 -0
  94. package/dist/__tests__/validator.test.d.ts.map +1 -0
  95. package/dist/__tests__/validator.test.js +300 -0
  96. package/dist/container.d.ts +80 -0
  97. package/dist/container.d.ts.map +1 -0
  98. package/dist/container.js +271 -0
  99. package/dist/decorators.d.ts +166 -0
  100. package/dist/decorators.d.ts.map +1 -0
  101. package/dist/decorators.js +538 -0
  102. package/dist/errors/http.error.d.ts +34 -0
  103. package/dist/errors/http.error.d.ts.map +1 -0
  104. package/dist/errors/http.error.js +69 -0
  105. package/dist/filters/exception-filter.d.ts +39 -0
  106. package/dist/filters/exception-filter.d.ts.map +1 -0
  107. package/dist/filters/exception-filter.js +38 -0
  108. package/dist/filters/http-exception.filter.d.ts +9 -0
  109. package/dist/filters/http-exception.filter.d.ts.map +1 -0
  110. package/dist/filters/http-exception.filter.js +42 -0
  111. package/dist/hazel-app.d.ts +94 -0
  112. package/dist/hazel-app.d.ts.map +1 -0
  113. package/dist/hazel-app.js +516 -0
  114. package/dist/hazel-module.d.ts +29 -0
  115. package/dist/hazel-module.d.ts.map +1 -0
  116. package/dist/hazel-module.js +137 -0
  117. package/dist/hazel-response.d.ts +25 -0
  118. package/dist/hazel-response.d.ts.map +1 -0
  119. package/dist/hazel-response.js +89 -0
  120. package/dist/health.d.ts +73 -0
  121. package/dist/health.d.ts.map +1 -0
  122. package/dist/health.js +174 -0
  123. package/dist/index.d.ts +41 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +159 -0
  126. package/dist/interceptors/interceptor.d.ts +30 -0
  127. package/dist/interceptors/interceptor.d.ts.map +1 -0
  128. package/dist/interceptors/interceptor.js +71 -0
  129. package/dist/logger.d.ts +8 -0
  130. package/dist/logger.d.ts.map +1 -0
  131. package/dist/logger.js +261 -0
  132. package/dist/middleware/cors.middleware.d.ts +44 -0
  133. package/dist/middleware/cors.middleware.d.ts.map +1 -0
  134. package/dist/middleware/cors.middleware.js +118 -0
  135. package/dist/middleware/csrf.middleware.d.ts +82 -0
  136. package/dist/middleware/csrf.middleware.d.ts.map +1 -0
  137. package/dist/middleware/csrf.middleware.js +183 -0
  138. package/dist/middleware/global-middleware.d.ts +111 -0
  139. package/dist/middleware/global-middleware.d.ts.map +1 -0
  140. package/dist/middleware/global-middleware.js +179 -0
  141. package/dist/middleware/rate-limit.middleware.d.ts +73 -0
  142. package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
  143. package/dist/middleware/rate-limit.middleware.js +124 -0
  144. package/dist/middleware/security-headers.middleware.d.ts +76 -0
  145. package/dist/middleware/security-headers.middleware.d.ts.map +1 -0
  146. package/dist/middleware/security-headers.middleware.js +123 -0
  147. package/dist/middleware/timeout.middleware.d.ts +25 -0
  148. package/dist/middleware/timeout.middleware.d.ts.map +1 -0
  149. package/dist/middleware/timeout.middleware.js +74 -0
  150. package/dist/middleware.d.ts +13 -0
  151. package/dist/middleware.d.ts.map +1 -0
  152. package/dist/middleware.js +47 -0
  153. package/dist/pipes/pipe.d.ts +50 -0
  154. package/dist/pipes/pipe.d.ts.map +1 -0
  155. package/dist/pipes/pipe.js +96 -0
  156. package/dist/pipes/validation.pipe.d.ts +6 -0
  157. package/dist/pipes/validation.pipe.d.ts.map +1 -0
  158. package/dist/pipes/validation.pipe.js +61 -0
  159. package/dist/request-context.d.ts +22 -0
  160. package/dist/request-context.d.ts.map +1 -0
  161. package/dist/request-context.js +2 -0
  162. package/dist/request-parser.d.ts +7 -0
  163. package/dist/request-parser.d.ts.map +1 -0
  164. package/dist/request-parser.js +60 -0
  165. package/dist/router.d.ts +33 -0
  166. package/dist/router.d.ts.map +1 -0
  167. package/dist/router.js +506 -0
  168. package/dist/routing/route-matcher.d.ts +39 -0
  169. package/dist/routing/route-matcher.d.ts.map +1 -0
  170. package/dist/routing/route-matcher.js +93 -0
  171. package/dist/routing/version.decorator.d.ts +36 -0
  172. package/dist/routing/version.decorator.d.ts.map +1 -0
  173. package/dist/routing/version.decorator.js +89 -0
  174. package/dist/service.d.ts +9 -0
  175. package/dist/service.d.ts.map +1 -0
  176. package/dist/service.js +39 -0
  177. package/dist/shutdown.d.ts +32 -0
  178. package/dist/shutdown.d.ts.map +1 -0
  179. package/dist/shutdown.js +109 -0
  180. package/dist/testing/testing.module.d.ts +83 -0
  181. package/dist/testing/testing.module.d.ts.map +1 -0
  182. package/dist/testing/testing.module.js +164 -0
  183. package/dist/types.d.ts +82 -0
  184. package/dist/types.d.ts.map +1 -0
  185. package/dist/types.js +2 -0
  186. package/dist/upload/file-upload.d.ts +75 -0
  187. package/dist/upload/file-upload.d.ts.map +1 -0
  188. package/dist/upload/file-upload.js +261 -0
  189. package/dist/utils/sanitize.d.ts +45 -0
  190. package/dist/utils/sanitize.d.ts.map +1 -0
  191. package/dist/utils/sanitize.js +165 -0
  192. package/dist/validator.d.ts +7 -0
  193. package/dist/validator.d.ts.map +1 -0
  194. package/dist/validator.js +119 -0
  195. package/package.json +67 -0
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HazelModuleInstance = exports.Module = void 0;
7
+ exports.HazelModule = HazelModule;
8
+ exports.getModuleMetadata = getModuleMetadata;
9
+ require("reflect-metadata");
10
+ const container_1 = require("./container");
11
+ const logger_1 = __importDefault(require("./logger"));
12
+ const MODULE_METADATA_KEY = 'hazel:module';
13
+ const ROUTE_METADATA_KEY = 'hazel:route';
14
+ function HazelModule(options) {
15
+ return (target) => {
16
+ Reflect.defineMetadata(MODULE_METADATA_KEY, options, target);
17
+ };
18
+ }
19
+ // Alias for backward compatibility
20
+ exports.Module = HazelModule;
21
+ function getModuleMetadata(target) {
22
+ const fromDecorator = Reflect.getMetadata(MODULE_METADATA_KEY, target);
23
+ if (fromDecorator)
24
+ return fromDecorator;
25
+ // Support dynamic modules: { module, providers?, controllers?, imports? }
26
+ if (target && typeof target === 'object' && 'module' in target) {
27
+ const dyn = target;
28
+ return {
29
+ providers: dyn.providers,
30
+ controllers: dyn.controllers,
31
+ imports: dyn.imports,
32
+ };
33
+ }
34
+ return undefined;
35
+ }
36
+ class HazelModuleInstance {
37
+ constructor(moduleType) {
38
+ this.moduleType = moduleType;
39
+ const name = moduleType?.name ?? moduleType?.module?.name ?? 'DynamicModule';
40
+ logger_1.default.debug(`Initializing HazelModule: ${name}`);
41
+ this.container = container_1.Container.getInstance();
42
+ this.initialize();
43
+ }
44
+ initialize() {
45
+ const metadata = getModuleMetadata(this.moduleType) || {};
46
+ logger_1.default.debug('Module metadata:', metadata);
47
+ // Initialize imported modules first (so their providers are available)
48
+ if (metadata.imports) {
49
+ logger_1.default.debug('Initializing imported modules:', metadata.imports.map((m) => (m && typeof m === 'object' && 'module' in m ? m.module?.name : m?.name)));
50
+ metadata.imports.forEach((moduleType) => {
51
+ new HazelModuleInstance(moduleType);
52
+ });
53
+ }
54
+ // Register providers
55
+ if (metadata.providers) {
56
+ logger_1.default.debug('Registering providers:', metadata.providers.map((p) => {
57
+ const val = p && typeof p === 'object' && 'provide' in p ? p.provide : p?.name;
58
+ return typeof val === 'symbol' ? val.toString() : val;
59
+ }));
60
+ metadata.providers.forEach((provider) => {
61
+ // Dynamic module provider: { provide, useFactory?, useClass?, useValue? } (NestJS-style)
62
+ if (provider && typeof provider === 'object' && ('provide' in provider || 'token' in provider)) {
63
+ const p = provider;
64
+ const token = p.token ?? p.provide;
65
+ logger_1.default.debug(`Registering provider config for: ${typeof token === 'symbol' ? token.toString() : token}`);
66
+ this.container.registerProvider({
67
+ token,
68
+ useFactory: p.useFactory,
69
+ useClass: p.useClass,
70
+ useValue: p.useValue,
71
+ inject: p.inject,
72
+ });
73
+ return;
74
+ }
75
+ const cls = provider;
76
+ logger_1.default.debug(`Registering provider: ${cls?.name}`);
77
+ // Check if provider is request-scoped
78
+ const scope = Reflect.getMetadata('hazel:scope', cls);
79
+ if (scope === 'request') {
80
+ // Don't eagerly resolve request-scoped providers
81
+ this.container.registerProvider({
82
+ token: cls,
83
+ useClass: cls,
84
+ scope: container_1.Scope.REQUEST,
85
+ });
86
+ }
87
+ else {
88
+ // Eagerly resolve singleton and transient providers
89
+ this.container.register(cls, this.container.resolve(cls));
90
+ }
91
+ });
92
+ }
93
+ // Register controllers
94
+ if (metadata.controllers) {
95
+ logger_1.default.debug('Registering controllers:', metadata.controllers.map((c) => c?.name));
96
+ metadata.controllers.forEach((controller) => {
97
+ logger_1.default.debug(`Registering controller: ${controller.name}`);
98
+ // Check if controller has request-scoped dependencies
99
+ const paramTypes = Reflect.getMetadata('design:paramtypes', controller) || [];
100
+ const hasRequestScopedDeps = paramTypes.some((paramType) => {
101
+ if (!paramType)
102
+ return false;
103
+ const scope = Reflect.getMetadata('hazel:scope', paramType);
104
+ return scope === 'request';
105
+ });
106
+ if (hasRequestScopedDeps) {
107
+ // Don't eagerly resolve controllers with request-scoped dependencies
108
+ logger_1.default.debug(`Skipping eager resolution for controller with request-scoped deps: ${controller.name}`);
109
+ // Register as a class provider so it gets resolved per-request
110
+ this.container.registerProvider({
111
+ token: controller,
112
+ useClass: controller,
113
+ scope: container_1.Scope.SINGLETON, // Controller itself is singleton, but deps are request-scoped
114
+ });
115
+ }
116
+ else {
117
+ // Eagerly resolve controllers without request-scoped dependencies
118
+ const instance = this.container.resolve(controller);
119
+ this.container.register(controller, instance);
120
+ }
121
+ // Register controller routes
122
+ const prototype = controller.prototype;
123
+ const methodNames = Object.getOwnPropertyNames(prototype).filter((name) => name !== 'constructor' && typeof prototype[name] === 'function');
124
+ methodNames.forEach((methodName) => {
125
+ const route = Reflect.getMetadata(ROUTE_METADATA_KEY, prototype, methodName);
126
+ if (route) {
127
+ logger_1.default.debug(`Registering route: ${route.method} ${route.path}`);
128
+ }
129
+ });
130
+ });
131
+ }
132
+ }
133
+ getContainer() {
134
+ return this.container;
135
+ }
136
+ }
137
+ exports.HazelModuleInstance = HazelModuleInstance;
@@ -0,0 +1,25 @@
1
+ import { Response } from './types';
2
+ export interface HazelResponse {
3
+ setHeader(name: string, value: string): void;
4
+ write(chunk: string): void;
5
+ end(): void;
6
+ status(code: number): HazelResponse;
7
+ json(data: unknown): void;
8
+ redirect(url: string, statusCode?: number): void;
9
+ /** Send a Buffer as binary (e.g. audio, PDF). Sets Content-Type if provided. */
10
+ sendBuffer?(buffer: Buffer, contentType?: string): void;
11
+ }
12
+ export declare class HazelExpressResponse implements HazelResponse {
13
+ private res;
14
+ private isStreaming;
15
+ private headersSent;
16
+ constructor(res: Response);
17
+ setHeader(name: string, value: string): void;
18
+ write(chunk: string): void;
19
+ end(): void;
20
+ status(code: number): HazelResponse;
21
+ redirect(url: string, statusCode?: number): void;
22
+ sendBuffer(buffer: Buffer, contentType?: string): void;
23
+ json(data: unknown): void;
24
+ }
25
+ //# sourceMappingURL=hazel-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hazel-response.d.ts","sourceRoot":"","sources":["../src/hazel-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,IAAI,IAAI,CAAC;IACZ,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,gFAAgF;IAChF,UAAU,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzD;AAED,qBAAa,oBAAqB,YAAW,aAAa;IAI5C,OAAO,CAAC,GAAG;IAHvB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,WAAW,CAAkB;gBAEjB,GAAG,EAAE,QAAQ;IAEjC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM5C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAY1B,GAAG,IAAI,IAAI;IAMX,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa;IAOnC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,GAAE,MAAY,GAAG,IAAI;IAWrD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAWtD,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;CA+B1B"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HazelExpressResponse = void 0;
4
+ class HazelExpressResponse {
5
+ constructor(res) {
6
+ this.res = res;
7
+ this.isStreaming = false;
8
+ this.headersSent = false;
9
+ }
10
+ setHeader(name, value) {
11
+ if (!this.headersSent) {
12
+ this.res.setHeader(name, value);
13
+ }
14
+ }
15
+ write(chunk) {
16
+ if (!this.isStreaming) {
17
+ this.isStreaming = true;
18
+ this.headersSent = true;
19
+ this.res.setHeader('Content-Type', 'text/plain');
20
+ this.res.setHeader('Transfer-Encoding', 'chunked');
21
+ this.res.send(chunk);
22
+ }
23
+ else {
24
+ this.res.send(chunk);
25
+ }
26
+ }
27
+ end() {
28
+ if (this.isStreaming) {
29
+ this.res.end();
30
+ }
31
+ }
32
+ status(code) {
33
+ if (!this.headersSent) {
34
+ this.res.status(code);
35
+ }
36
+ return this;
37
+ }
38
+ redirect(url, statusCode = 302) {
39
+ if (this.headersSent)
40
+ return;
41
+ if (typeof this.res.redirect === 'function') {
42
+ this.res.redirect(url, statusCode);
43
+ return;
44
+ }
45
+ this.headersSent = true;
46
+ this.res.writeHead(statusCode, { Location: url });
47
+ this.res.end();
48
+ }
49
+ sendBuffer(buffer, contentType) {
50
+ if (this.isStreaming || this.headersSent) {
51
+ return;
52
+ }
53
+ if (contentType) {
54
+ this.res.setHeader('Content-Type', contentType);
55
+ }
56
+ this.res.send(buffer);
57
+ this.headersSent = true;
58
+ }
59
+ json(data) {
60
+ if (this.isStreaming || this.headersSent) {
61
+ return; // Don't try to send JSON if we're already streaming or headers are sent
62
+ }
63
+ try {
64
+ if (data && typeof data === 'object') {
65
+ // Handle error responses specially
66
+ if ('error' in data) {
67
+ this.res.json({ error: data.error });
68
+ return;
69
+ }
70
+ // For other objects, use a safe replacer
71
+ const safeData = JSON.parse(JSON.stringify(data, (key, value) => {
72
+ if (key === 'res' || value === this.res) {
73
+ return '[Response Object]';
74
+ }
75
+ return value;
76
+ }));
77
+ this.res.json(safeData);
78
+ }
79
+ else {
80
+ this.res.json(data);
81
+ }
82
+ }
83
+ catch {
84
+ // If JSON stringify fails, send a simple error message
85
+ this.res.json({ error: 'Failed to serialize response' });
86
+ }
87
+ }
88
+ }
89
+ exports.HazelExpressResponse = HazelExpressResponse;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Health Check System
3
+ * Provides /health and /readiness endpoints for monitoring
4
+ */
5
+ export interface HealthCheck {
6
+ name: string;
7
+ check: () => Promise<HealthCheckResult>;
8
+ critical?: boolean;
9
+ timeout?: number;
10
+ }
11
+ export interface HealthCheckResult {
12
+ status: 'healthy' | 'unhealthy' | 'degraded';
13
+ message?: string;
14
+ details?: Record<string, unknown>;
15
+ responseTime?: number;
16
+ }
17
+ export interface HealthStatus {
18
+ status: 'healthy' | 'unhealthy' | 'degraded';
19
+ timestamp: string;
20
+ uptime: number;
21
+ checks: Record<string, HealthCheckResult>;
22
+ version?: string;
23
+ environment?: string;
24
+ }
25
+ export declare class HealthCheckManager {
26
+ private checks;
27
+ private startTime;
28
+ /**
29
+ * Register a health check
30
+ */
31
+ registerCheck(check: HealthCheck): void;
32
+ /**
33
+ * Run all health checks
34
+ */
35
+ runChecks(): Promise<HealthStatus>;
36
+ /**
37
+ * Get liveness status (is the service running?)
38
+ */
39
+ getLiveness(): Promise<{
40
+ status: 'alive';
41
+ timestamp: string;
42
+ }>;
43
+ /**
44
+ * Get readiness status (is the service ready to accept traffic?)
45
+ */
46
+ getReadiness(): Promise<HealthStatus>;
47
+ /**
48
+ * Get startup status (has the service completed startup?)
49
+ */
50
+ getStartup(): Promise<{
51
+ status: 'started';
52
+ uptime: number;
53
+ timestamp: string;
54
+ }>;
55
+ }
56
+ /**
57
+ * Built-in health checks
58
+ */
59
+ export declare class BuiltInHealthChecks {
60
+ /**
61
+ * Memory usage check
62
+ */
63
+ static memoryCheck(thresholdMB?: number): HealthCheck;
64
+ /**
65
+ * Event loop lag check
66
+ */
67
+ static eventLoopCheck(thresholdMs?: number): HealthCheck;
68
+ /**
69
+ * Disk space check (if applicable)
70
+ */
71
+ static diskSpaceCheck(): HealthCheck;
72
+ }
73
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,SAAS,CAAsB;IAEvC;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAKvC;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAqDxC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAOpE;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAI3C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAOtF;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,WAAW,SAAM,GAAG,WAAW;IA+BlD;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,WAAW,SAAM,GAAG,WAAW;IAyBrD;;OAEG;IACH,MAAM,CAAC,cAAc,IAAI,WAAW;CAcrC"}
package/dist/health.js ADDED
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /**
3
+ * Health Check System
4
+ * Provides /health and /readiness endpoints for monitoring
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.BuiltInHealthChecks = exports.HealthCheckManager = void 0;
11
+ const logger_1 = __importDefault(require("./logger"));
12
+ class HealthCheckManager {
13
+ constructor() {
14
+ this.checks = new Map();
15
+ this.startTime = Date.now();
16
+ }
17
+ /**
18
+ * Register a health check
19
+ */
20
+ registerCheck(check) {
21
+ this.checks.set(check.name, check);
22
+ logger_1.default.debug(`Registered health check: ${check.name}`);
23
+ }
24
+ /**
25
+ * Run all health checks
26
+ */
27
+ async runChecks() {
28
+ const results = {};
29
+ let overallStatus = 'healthy';
30
+ for (const [name, check] of this.checks) {
31
+ try {
32
+ const startTime = Date.now();
33
+ // Run check with timeout
34
+ const result = await Promise.race([
35
+ check.check(),
36
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Health check ${name} timeout`)), check.timeout || 5000)),
37
+ ]);
38
+ result.responseTime = Date.now() - startTime;
39
+ results[name] = result;
40
+ // Update overall status
41
+ if (result.status === 'unhealthy' && check.critical) {
42
+ overallStatus = 'unhealthy';
43
+ }
44
+ else if (result.status === 'degraded' && overallStatus === 'healthy') {
45
+ overallStatus = 'degraded';
46
+ }
47
+ }
48
+ catch (error) {
49
+ const errorResult = {
50
+ status: 'unhealthy',
51
+ message: error instanceof Error ? error.message : 'Unknown error',
52
+ };
53
+ results[name] = errorResult;
54
+ if (check.critical) {
55
+ overallStatus = 'unhealthy';
56
+ }
57
+ logger_1.default.error(`Health check failed: ${name}`, error);
58
+ }
59
+ }
60
+ return {
61
+ status: overallStatus,
62
+ timestamp: new Date().toISOString(),
63
+ uptime: Date.now() - this.startTime,
64
+ checks: results,
65
+ version: process.env.APP_VERSION,
66
+ environment: process.env.NODE_ENV,
67
+ };
68
+ }
69
+ /**
70
+ * Get liveness status (is the service running?)
71
+ */
72
+ async getLiveness() {
73
+ return {
74
+ status: 'alive',
75
+ timestamp: new Date().toISOString(),
76
+ };
77
+ }
78
+ /**
79
+ * Get readiness status (is the service ready to accept traffic?)
80
+ */
81
+ async getReadiness() {
82
+ return this.runChecks();
83
+ }
84
+ /**
85
+ * Get startup status (has the service completed startup?)
86
+ */
87
+ async getStartup() {
88
+ return {
89
+ status: 'started',
90
+ uptime: Date.now() - this.startTime,
91
+ timestamp: new Date().toISOString(),
92
+ };
93
+ }
94
+ }
95
+ exports.HealthCheckManager = HealthCheckManager;
96
+ /**
97
+ * Built-in health checks
98
+ */
99
+ class BuiltInHealthChecks {
100
+ /**
101
+ * Memory usage check
102
+ */
103
+ static memoryCheck(thresholdMB = 500) {
104
+ return {
105
+ name: 'memory',
106
+ check: async () => {
107
+ const memUsage = process.memoryUsage();
108
+ const heapUsedMB = memUsage.heapUsed / 1024 / 1024;
109
+ if (heapUsedMB > thresholdMB) {
110
+ return {
111
+ status: 'degraded',
112
+ message: `High memory usage: ${heapUsedMB.toFixed(2)}MB`,
113
+ details: {
114
+ heapUsed: `${heapUsedMB.toFixed(2)}MB`,
115
+ heapTotal: `${(memUsage.heapTotal / 1024 / 1024).toFixed(2)}MB`,
116
+ rss: `${(memUsage.rss / 1024 / 1024).toFixed(2)}MB`,
117
+ },
118
+ };
119
+ }
120
+ return {
121
+ status: 'healthy',
122
+ details: {
123
+ heapUsed: `${heapUsedMB.toFixed(2)}MB`,
124
+ heapTotal: `${(memUsage.heapTotal / 1024 / 1024).toFixed(2)}MB`,
125
+ },
126
+ };
127
+ },
128
+ critical: false,
129
+ };
130
+ }
131
+ /**
132
+ * Event loop lag check
133
+ */
134
+ static eventLoopCheck(thresholdMs = 100) {
135
+ return {
136
+ name: 'eventLoop',
137
+ check: async () => {
138
+ const start = Date.now();
139
+ await new Promise((resolve) => setImmediate(resolve));
140
+ const lag = Date.now() - start;
141
+ if (lag > thresholdMs) {
142
+ return {
143
+ status: 'degraded',
144
+ message: `High event loop lag: ${lag}ms`,
145
+ details: { lag: `${lag}ms` },
146
+ };
147
+ }
148
+ return {
149
+ status: 'healthy',
150
+ details: { lag: `${lag}ms` },
151
+ };
152
+ },
153
+ critical: false,
154
+ };
155
+ }
156
+ /**
157
+ * Disk space check (if applicable)
158
+ */
159
+ static diskSpaceCheck() {
160
+ return {
161
+ name: 'diskSpace',
162
+ check: async () => {
163
+ // This is a placeholder - actual implementation would check disk space
164
+ // using a library like 'check-disk-space'
165
+ return {
166
+ status: 'healthy',
167
+ message: 'Disk space check not implemented',
168
+ };
169
+ },
170
+ critical: false,
171
+ };
172
+ }
173
+ }
174
+ exports.BuiltInHealthChecks = BuiltInHealthChecks;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * HazelJS Core Framework
3
+ * A modern, modular Node.js framework with TypeScript support
4
+ */
5
+ import 'reflect-metadata';
6
+ export { HazelApp, type EarlyHttpHandler, type ProxyHandler } from './hazel-app';
7
+ export { HazelModule, Module, HazelModuleInstance, getModuleMetadata } from './hazel-module';
8
+ export type { ModuleOptions, DynamicModule } from './hazel-module';
9
+ export { ShutdownManager } from './shutdown';
10
+ export type { ShutdownHandler } from './shutdown';
11
+ export { HealthCheckManager, BuiltInHealthChecks } from './health';
12
+ export type { HealthCheck, HealthCheckResult, HealthStatus } from './health';
13
+ export { TimeoutMiddleware } from './middleware/timeout.middleware';
14
+ export type { TimeoutOptions } from './middleware/timeout.middleware';
15
+ export { Controller, Injectable, Service, Get, Post, Put, Delete, Patch, Body, Param, Query, Req, Res, Ip, Host, Headers, HttpCode, Header, Redirect, Inject, UsePipes, UseInterceptors, UseGuards, Public, SkipAuth, AITask, Timeout, Optional, Session, Retry, ApiTags, ApiOperation, SetMetadata, getMetadata, createParamDecorator, CUSTOM_METADATA_PREFIX, type ControllerMetadata, type RouteMetadata, type ControllerOptions, type RouteOptions, type ServiceOptions, type InjectableOptions, type RepositoryOptions, type OnModuleInit, type OnModuleDestroy, type ExecutionContext, type CanActivate, type RetryDecoratorOptions, type ApiOperationOptions, type ParamDecoratorContext, } from './decorators';
16
+ export { Container, Scope, type InjectionToken, type Provider } from './container';
17
+ export type { Type, Request, Response, RequestContext, ValidationSchema } from './types';
18
+ export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, InternalServerError, HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException, InternalServerErrorException, RequestTimeoutError, } from './errors/http.error';
19
+ export { PipeTransform, ValidationError, ParseIntPipe, type PipeMetadata } from './pipes/pipe';
20
+ export { ValidationPipe } from './pipes/validation.pipe';
21
+ export { Interceptor, RetryInterceptor, type InterceptorMetadata, type RetryOptions, } from './interceptors/interceptor';
22
+ export { type ExceptionFilter, type ArgumentsHost, ArgumentsHostImpl, Catch, getFilterExceptions, } from './filters/exception-filter';
23
+ export { HttpExceptionFilter } from './filters/http-exception.filter';
24
+ export { Test, TestingModule, TestingModuleBuilder, type TestingModuleMetadata, } from './testing/testing.module';
25
+ export { RouteMatcher, type RouteMatch } from './routing/route-matcher';
26
+ export { Version, VersioningType, type VersioningOptions, getVersionMetadata, matchVersion, extractVersion, } from './routing/version.decorator';
27
+ export { GlobalMiddlewareManager, CorsMiddleware, LoggerMiddleware, type MiddlewareFunction, type MiddlewareClass, type MiddlewareConsumer, type MiddlewareConfigProxy, type RouteInfo, type NextFunction, type CorsOptions, } from './middleware/global-middleware';
28
+ export { Middleware, type MiddlewareHandler } from './middleware';
29
+ export { SecurityHeadersMiddleware, type SecurityHeadersOptions, } from './middleware/security-headers.middleware';
30
+ export { RateLimitMiddleware, type RateLimitOptions, } from './middleware/rate-limit.middleware';
31
+ export { CsrfMiddleware, type CsrfOptions, } from './middleware/csrf.middleware';
32
+ export { FileUploadInterceptor, UploadedFileDecorator as UploadedFile, UploadedFilesDecorator as UploadedFiles, type UploadedFile as UploadedFileType, type FileUploadOptions, } from './upload/file-upload';
33
+ export { default as logger } from './logger';
34
+ export { default } from './logger';
35
+ export { Validator } from './validator';
36
+ export { Router } from './router';
37
+ export { RequestParser } from './request-parser';
38
+ export { RequestContext as RequestContextClass } from './request-context';
39
+ export { HazelResponse } from './hazel-response';
40
+ export { sanitizeHtml, sanitizeString, sanitizeUrl, sanitizeEmail, sanitizeSql, sanitizeObject, escapeHtml, } from './utils/sanitize';
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}