@engjts/nexus 0.1.8 → 0.1.10

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 (221) hide show
  1. package/dist/advanced/playground/playground.js.map +1 -1
  2. package/dist/advanced/static/generateDirectoryListing.d.ts +1 -1
  3. package/dist/advanced/static/generateDirectoryListing.d.ts.map +1 -1
  4. package/dist/advanced/static/generateDirectoryListing.js +12 -6
  5. package/dist/advanced/static/generateDirectoryListing.js.map +1 -1
  6. package/dist/advanced/static/index.d.ts +2 -0
  7. package/dist/advanced/static/index.d.ts.map +1 -1
  8. package/dist/advanced/static/index.js +4 -1
  9. package/dist/advanced/static/index.js.map +1 -1
  10. package/dist/advanced/static/serveStatic.d.ts.map +1 -1
  11. package/dist/advanced/static/serveStatic.js +7 -1
  12. package/dist/advanced/static/serveStatic.js.map +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +3 -1
  16. package/dist/index.js.map +1 -1
  17. package/package.json +1 -1
  18. package/BENCHMARK_REPORT.md +0 -343
  19. package/documentation/01-getting-started.md +0 -240
  20. package/documentation/02-context.md +0 -335
  21. package/documentation/03-routing.md +0 -397
  22. package/documentation/04-middleware.md +0 -483
  23. package/documentation/05-validation.md +0 -514
  24. package/documentation/06-error-handling.md +0 -465
  25. package/documentation/07-performance.md +0 -364
  26. package/documentation/08-adapters.md +0 -470
  27. package/documentation/09-api-reference.md +0 -548
  28. package/documentation/10-examples.md +0 -582
  29. package/documentation/11-deployment.md +0 -477
  30. package/documentation/12-sentry.md +0 -620
  31. package/documentation/13-sentry-data-storage.md +0 -996
  32. package/documentation/14-sentry-data-reference.md +0 -457
  33. package/documentation/15-sentry-summary.md +0 -409
  34. package/documentation/16-alerts-system.md +0 -745
  35. package/documentation/17-alert-adapters.md +0 -696
  36. package/documentation/18-alerts-implementation-summary.md +0 -385
  37. package/documentation/19-class-based-routing.md +0 -840
  38. package/documentation/20-websocket-realtime.md +0 -813
  39. package/documentation/21-cache-system.md +0 -510
  40. package/documentation/22-job-queue.md +0 -772
  41. package/documentation/23-sentry-plugin.md +0 -551
  42. package/documentation/24-testing-utilities.md +0 -1287
  43. package/documentation/25-api-versioning.md +0 -533
  44. package/documentation/26-context-store.md +0 -607
  45. package/documentation/27-dependency-injection.md +0 -329
  46. package/documentation/28-lifecycle-hooks.md +0 -521
  47. package/documentation/29-package-structure.md +0 -196
  48. package/documentation/30-plugin-system.md +0 -414
  49. package/documentation/31-jwt-authentication.md +0 -597
  50. package/documentation/32-cli.md +0 -268
  51. package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
  52. package/documentation/ALERTS-INDEX.md +0 -330
  53. package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
  54. package/documentation/README.md +0 -178
  55. package/documentation/index.html +0 -34
  56. package/modern_framework_paper.md +0 -1870
  57. package/public/css/style.css +0 -87
  58. package/public/index.html +0 -34
  59. package/public/js/app.js +0 -27
  60. package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
  61. package/src/advanced/cache/MultiTierCache.ts +0 -194
  62. package/src/advanced/cache/RedisCacheStore.ts +0 -341
  63. package/src/advanced/cache/index.ts +0 -5
  64. package/src/advanced/cache/types.ts +0 -40
  65. package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
  66. package/src/advanced/graphql/index.ts +0 -22
  67. package/src/advanced/graphql/server.ts +0 -252
  68. package/src/advanced/graphql/types.ts +0 -42
  69. package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
  70. package/src/advanced/jobs/JobQueue.ts +0 -556
  71. package/src/advanced/jobs/RedisQueueStore.ts +0 -367
  72. package/src/advanced/jobs/index.ts +0 -5
  73. package/src/advanced/jobs/types.ts +0 -70
  74. package/src/advanced/observability/APMManager.ts +0 -163
  75. package/src/advanced/observability/AlertManager.ts +0 -109
  76. package/src/advanced/observability/MetricRegistry.ts +0 -151
  77. package/src/advanced/observability/ObservabilityCenter.ts +0 -304
  78. package/src/advanced/observability/StructuredLogger.ts +0 -154
  79. package/src/advanced/observability/TracingManager.ts +0 -117
  80. package/src/advanced/observability/adapters.ts +0 -304
  81. package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
  82. package/src/advanced/observability/index.ts +0 -11
  83. package/src/advanced/observability/types.ts +0 -174
  84. package/src/advanced/playground/extractPathParams.ts +0 -6
  85. package/src/advanced/playground/generateFieldExample.ts +0 -31
  86. package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1956
  87. package/src/advanced/playground/generateSummary.ts +0 -19
  88. package/src/advanced/playground/getTagFromPath.ts +0 -9
  89. package/src/advanced/playground/index.ts +0 -8
  90. package/src/advanced/playground/playground.ts +0 -250
  91. package/src/advanced/playground/types.ts +0 -49
  92. package/src/advanced/playground/zodToExample.ts +0 -16
  93. package/src/advanced/playground/zodToParams.ts +0 -15
  94. package/src/advanced/postman/buildAuth.ts +0 -31
  95. package/src/advanced/postman/buildBody.ts +0 -15
  96. package/src/advanced/postman/buildQueryParams.ts +0 -27
  97. package/src/advanced/postman/buildRequestItem.ts +0 -36
  98. package/src/advanced/postman/buildResponses.ts +0 -11
  99. package/src/advanced/postman/buildUrl.ts +0 -33
  100. package/src/advanced/postman/capitalize.ts +0 -4
  101. package/src/advanced/postman/generateCollection.ts +0 -59
  102. package/src/advanced/postman/generateEnvironment.ts +0 -34
  103. package/src/advanced/postman/generateExampleFromZod.ts +0 -21
  104. package/src/advanced/postman/generateFieldExample.ts +0 -45
  105. package/src/advanced/postman/generateName.ts +0 -20
  106. package/src/advanced/postman/generateUUID.ts +0 -11
  107. package/src/advanced/postman/getTagFromPath.ts +0 -10
  108. package/src/advanced/postman/index.ts +0 -28
  109. package/src/advanced/postman/postman.ts +0 -156
  110. package/src/advanced/postman/slugify.ts +0 -7
  111. package/src/advanced/postman/types.ts +0 -140
  112. package/src/advanced/realtime/index.ts +0 -18
  113. package/src/advanced/realtime/websocket.ts +0 -231
  114. package/src/advanced/sentry/index.ts +0 -1236
  115. package/src/advanced/sentry/types.ts +0 -355
  116. package/src/advanced/static/generateDirectoryListing.ts +0 -47
  117. package/src/advanced/static/generateETag.ts +0 -7
  118. package/src/advanced/static/getMimeType.ts +0 -9
  119. package/src/advanced/static/index.ts +0 -32
  120. package/src/advanced/static/isSafePath.ts +0 -13
  121. package/src/advanced/static/publicDir.ts +0 -21
  122. package/src/advanced/static/serveStatic.ts +0 -225
  123. package/src/advanced/static/spa.ts +0 -24
  124. package/src/advanced/static/types.ts +0 -159
  125. package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
  126. package/src/advanced/swagger/buildOperation.ts +0 -61
  127. package/src/advanced/swagger/buildParameters.ts +0 -61
  128. package/src/advanced/swagger/buildRequestBody.ts +0 -21
  129. package/src/advanced/swagger/buildResponses.ts +0 -54
  130. package/src/advanced/swagger/capitalize.ts +0 -5
  131. package/src/advanced/swagger/convertPath.ts +0 -9
  132. package/src/advanced/swagger/createSwagger.ts +0 -12
  133. package/src/advanced/swagger/generateOperationId.ts +0 -21
  134. package/src/advanced/swagger/generateSpec.ts +0 -105
  135. package/src/advanced/swagger/generateSummary.ts +0 -24
  136. package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
  137. package/src/advanced/swagger/generateThemeCss.ts +0 -53
  138. package/src/advanced/swagger/index.ts +0 -25
  139. package/src/advanced/swagger/swagger.ts +0 -237
  140. package/src/advanced/swagger/types.ts +0 -206
  141. package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
  142. package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
  143. package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
  144. package/src/advanced/testing/factory.ts +0 -509
  145. package/src/advanced/testing/harness.ts +0 -612
  146. package/src/advanced/testing/index.ts +0 -430
  147. package/src/advanced/testing/load-test.ts +0 -618
  148. package/src/advanced/testing/mock-server.ts +0 -498
  149. package/src/advanced/testing/mock.ts +0 -670
  150. package/src/cli/bin.ts +0 -9
  151. package/src/cli/cli.ts +0 -158
  152. package/src/cli/commands/add.ts +0 -178
  153. package/src/cli/commands/build.ts +0 -73
  154. package/src/cli/commands/create.ts +0 -166
  155. package/src/cli/commands/dev.ts +0 -85
  156. package/src/cli/commands/generate.ts +0 -99
  157. package/src/cli/commands/help.ts +0 -95
  158. package/src/cli/commands/init.ts +0 -91
  159. package/src/cli/commands/version.ts +0 -38
  160. package/src/cli/index.ts +0 -6
  161. package/src/cli/templates/generators.ts +0 -359
  162. package/src/cli/templates/index.ts +0 -680
  163. package/src/cli/utils/exec.ts +0 -52
  164. package/src/cli/utils/file-system.ts +0 -78
  165. package/src/cli/utils/logger.ts +0 -111
  166. package/src/core/adapter.ts +0 -88
  167. package/src/core/application.ts +0 -1453
  168. package/src/core/context-pool.ts +0 -79
  169. package/src/core/context.ts +0 -856
  170. package/src/core/index.ts +0 -94
  171. package/src/core/middleware.ts +0 -272
  172. package/src/core/performance/buffer-pool.ts +0 -108
  173. package/src/core/performance/middleware-optimizer.ts +0 -162
  174. package/src/core/plugin/PluginManager.ts +0 -435
  175. package/src/core/plugin/builder.ts +0 -358
  176. package/src/core/plugin/index.ts +0 -50
  177. package/src/core/plugin/types.ts +0 -214
  178. package/src/core/router/file-router.ts +0 -623
  179. package/src/core/router/index.ts +0 -260
  180. package/src/core/router/radix-tree.ts +0 -242
  181. package/src/core/serializer.ts +0 -397
  182. package/src/core/store/index.ts +0 -30
  183. package/src/core/store/registry.ts +0 -178
  184. package/src/core/store/request-store.ts +0 -240
  185. package/src/core/store/types.ts +0 -233
  186. package/src/core/types.ts +0 -616
  187. package/src/database/adapter.ts +0 -35
  188. package/src/database/adapters/index.ts +0 -1
  189. package/src/database/adapters/mysql.ts +0 -669
  190. package/src/database/database.ts +0 -70
  191. package/src/database/dialect.ts +0 -388
  192. package/src/database/index.ts +0 -12
  193. package/src/database/migrations.ts +0 -86
  194. package/src/database/optimizer.ts +0 -125
  195. package/src/database/query-builder.ts +0 -404
  196. package/src/database/realtime.ts +0 -53
  197. package/src/database/schema.ts +0 -71
  198. package/src/database/transactions.ts +0 -56
  199. package/src/database/types.ts +0 -87
  200. package/src/deployment/cluster.ts +0 -471
  201. package/src/deployment/config.ts +0 -454
  202. package/src/deployment/docker.ts +0 -599
  203. package/src/deployment/graceful-shutdown.ts +0 -373
  204. package/src/deployment/index.ts +0 -56
  205. package/src/index.ts +0 -281
  206. package/src/security/adapter.ts +0 -318
  207. package/src/security/auth/JWTPlugin.ts +0 -234
  208. package/src/security/auth/JWTProvider.ts +0 -316
  209. package/src/security/auth/adapter.ts +0 -12
  210. package/src/security/auth/jwt.ts +0 -234
  211. package/src/security/auth/middleware.ts +0 -188
  212. package/src/security/csrf.ts +0 -220
  213. package/src/security/headers.ts +0 -108
  214. package/src/security/index.ts +0 -60
  215. package/src/security/rate-limit/adapter.ts +0 -7
  216. package/src/security/rate-limit/memory.ts +0 -108
  217. package/src/security/rate-limit/middleware.ts +0 -181
  218. package/src/security/sanitization.ts +0 -75
  219. package/src/security/types.ts +0 -240
  220. package/src/security/utils.ts +0 -52
  221. package/tsconfig.json +0 -39
@@ -1,856 +0,0 @@
1
- /**
2
- * Context implementation
3
- * Provides a unified request/response context with immutable properties
4
- */
5
-
6
- import { IncomingMessage, ServerResponse } from 'http';
7
- import { parse as fastQueryParse } from 'fast-querystring';
8
- import {
9
- Context,
10
- Headers,
11
- Cookies,
12
- CookieOptions,
13
- ResponseBuilder,
14
- Response,
15
- HTTPMethod
16
- } from './types';
17
- import { ContextStore, StoreConstructor, StoreRegistry, RequestStore, RequestStoreConstructor, RequestStoreRegistry } from './store';
18
- import { SerializerFunction } from './serializer';
19
-
20
- /**
21
- * Cookie manager implementation
22
- */
23
- class CookieManager implements Cookies {
24
- private cookies: Map<string, string>;
25
- private setCookies: Array<{ name: string; value: string; options?: CookieOptions }> = [];
26
-
27
- constructor(cookieHeader?: string) {
28
- this.cookies = new Map();
29
- if (cookieHeader) {
30
- const pairs = cookieHeader.split(';');
31
- for (const pair of pairs) {
32
- const [name, value] = pair.trim().split('=');
33
- if (name && value) {
34
- this.cookies.set(name, decodeURIComponent(value));
35
- }
36
- }
37
- }
38
- }
39
-
40
- get(name: string): string | undefined {
41
- return this.cookies.get(name);
42
- }
43
-
44
- set(name: string, value: string, options?: CookieOptions): void {
45
- this.cookies.set(name, value);
46
- this.setCookies.push({ name, value, options });
47
- }
48
-
49
- delete(name: string): void {
50
- this.cookies.delete(name);
51
- this.setCookies.push({
52
- name,
53
- value: '',
54
- options: { expires: new Date(0) }
55
- });
56
- }
57
-
58
- getSetCookieHeaders(): string[] {
59
- return this.setCookies.map(({ name, value, options }) => {
60
- let cookie = `${name}=${encodeURIComponent(value)}`;
61
-
62
- if (options) {
63
- if (options.maxAge) cookie += `; Max-Age=${options.maxAge}`;
64
- if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
65
- if (options.path) cookie += `; Path=${options.path}`;
66
- if (options.domain) cookie += `; Domain=${options.domain}`;
67
- if (options.secure) cookie += '; Secure';
68
- if (options.httpOnly) cookie += '; HttpOnly';
69
- if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;
70
- }
71
-
72
- return cookie;
73
- });
74
- }
75
- }
76
-
77
- /**
78
- * Pre-cached headers for common content types
79
- * This avoids object creation on every response
80
- */
81
- const CACHED_HEADERS = {
82
- JSON: { 'Content-Type': 'application/json' } as Headers,
83
- HTML: { 'Content-Type': 'text/html; charset=utf-8' } as Headers,
84
- TEXT: { 'Content-Type': 'text/plain; charset=utf-8' } as Headers,
85
- };
86
-
87
- /**
88
- * Response builder implementation
89
- * Supports fast-json-stringify for optimized JSON serialization
90
- */
91
- class ResponseBuilderImpl implements ResponseBuilder {
92
- private _status: number = 200;
93
- private _headers: Headers = {};
94
- private _hasCustomHeaders: boolean = false;
95
- private _serializers: Map<number | string, SerializerFunction> | null = null;
96
-
97
- status(code: number): ResponseBuilder {
98
- this._status = code;
99
- return this;
100
- }
101
-
102
- header(name: string, value: string): ResponseBuilder {
103
- this._headers[name] = value;
104
- this._hasCustomHeaders = true;
105
- return this;
106
- }
107
-
108
- /**
109
- * Set serializers for this response builder (called by router)
110
- * @internal
111
- */
112
- setSerializers(serializers: Map<number | string, SerializerFunction>): void {
113
- this._serializers = serializers;
114
- }
115
-
116
- /**
117
- * Get the appropriate serializer for current status code
118
- */
119
- private getSerializer(): SerializerFunction | null {
120
- if (!this._serializers) return null;
121
-
122
- // Try exact match first
123
- const exactMatch = this._serializers.get(this._status);
124
- if (exactMatch) return exactMatch;
125
-
126
- // Try status code ranges (2xx, 4xx, 5xx)
127
- const range = `${Math.floor(this._status / 100)}xx`;
128
- const rangeMatch = this._serializers.get(range);
129
- if (rangeMatch) return rangeMatch;
130
-
131
- // Try default
132
- return this._serializers.get('default') || null;
133
- }
134
-
135
- json<T>(data: T): Response {
136
- // Try to use fast serializer first
137
- const serializer = this.getSerializer();
138
- const body = serializer ? serializer(data) : JSON.stringify(data);
139
-
140
- return {
141
- statusCode: this._status,
142
- headers: this._hasCustomHeaders
143
- ? { ...this._headers, 'Content-Type': 'application/json' }
144
- : CACHED_HEADERS.JSON,
145
- body
146
- };
147
- }
148
-
149
- html(content: string): Response {
150
- return {
151
- statusCode: this._status,
152
- headers: this._hasCustomHeaders
153
- ? { ...this._headers, 'Content-Type': 'text/html; charset=utf-8' }
154
- : CACHED_HEADERS.HTML,
155
- body: content
156
- };
157
- }
158
-
159
- text(content: string): Response {
160
- return {
161
- statusCode: this._status,
162
- headers: this._hasCustomHeaders
163
- ? { ...this._headers, 'Content-Type': 'text/plain; charset=utf-8' }
164
- : CACHED_HEADERS.TEXT,
165
- body: content
166
- };
167
- }
168
-
169
- redirect(url: string, status: number = 302): Response {
170
- return {
171
- statusCode: status,
172
- headers: this._hasCustomHeaders
173
- ? { ...this._headers, 'Location': url }
174
- : { 'Location': url },
175
- body: ''
176
- };
177
- }
178
-
179
- stream(readable: NodeJS.ReadableStream): Response {
180
- return {
181
- statusCode: this._status,
182
- headers: this._headers,
183
- body: null,
184
- stream: readable
185
- };
186
- }
187
-
188
- /**
189
- * Reset for reuse (object pooling)
190
- */
191
- reset(): void {
192
- this._status = 200;
193
- this._headers = {};
194
- this._hasCustomHeaders = false;
195
- this._serializers = null;
196
- }
197
- }
198
-
199
- /**
200
- * Reusable response builder pool
201
- */
202
- const responseBuilderPool: ResponseBuilderImpl[] = [];
203
- const RESPONSE_BUILDER_POOL_SIZE = 100;
204
-
205
- function acquireResponseBuilder(): ResponseBuilderImpl {
206
- if (responseBuilderPool.length > 0) {
207
- const builder = responseBuilderPool.pop()!;
208
- builder.reset();
209
- return builder;
210
- }
211
- return new ResponseBuilderImpl();
212
- }
213
-
214
- function releaseResponseBuilder(builder: ResponseBuilderImpl): void {
215
- if (responseBuilderPool.length < RESPONSE_BUILDER_POOL_SIZE) {
216
- responseBuilderPool.push(builder);
217
- }
218
- }
219
-
220
- /**
221
- * Context implementation
222
- */
223
- export class ContextImpl implements Context {
224
- method: HTTPMethod;
225
- path: string;
226
- private _url: URL | null = null; // Lazy URL creation
227
- private _host: string = 'localhost';
228
- params: Record<string, string> = {};
229
- private _query: Record<string, any> | null = null; // Lazy query parsing
230
- private _queryString: string = ''; // Raw query string for lazy parsing
231
- headers: Headers;
232
- private _cookieHeader: string | undefined;
233
- private _cookies: CookieManager | null = null; // Lazy cookie parsing
234
- raw: { req: IncomingMessage; res: ServerResponse };
235
- response: ResponseBuilder;
236
-
237
- // Lazy body parsing - key optimization!
238
- private _parsedBody: any = undefined;
239
- private _bodyPromise: Promise<any> | null = null;
240
- private _bodyParsed: boolean = false;
241
-
242
- // Store registry reference (set by Application)
243
- private _storeRegistry?: StoreRegistry;
244
-
245
- // Request-scoped store registry - now lazy!
246
- private _requestStoreRegistry: RequestStoreRegistry | null = null;
247
-
248
- // Request-scoped simple key-value storage - now lazy!
249
- private _data: Map<string, any> | null = null;
250
-
251
- // Debug mode
252
- private _debug: boolean = false;
253
-
254
- constructor(req: IncomingMessage, res: ServerResponse) {
255
- this.raw = { req, res };
256
-
257
- // Parse method - use direct access, avoid optional chaining overhead
258
- this.method = (req.method ? req.method.toUpperCase() : 'GET') as HTTPMethod;
259
-
260
- // Fast URL parsing - just extract path, delay query parsing
261
- const url = req.url || '/';
262
- const queryIndex = url.indexOf('?');
263
-
264
- if (queryIndex === -1) {
265
- this.path = url;
266
- this._queryString = '';
267
- this._query = null; // Will be {} when accessed
268
- } else {
269
- this.path = url.substring(0, queryIndex);
270
- // Store query string for lazy parsing
271
- this._queryString = url.substring(queryIndex + 1);
272
- this._query = null; // Parse lazily
273
- }
274
-
275
- // Store host for lazy URL creation
276
- this._host = (req.headers.host as string) || 'localhost';
277
-
278
- // URL is now lazy - don't create here!
279
- this._url = null;
280
-
281
- // Parse headers (direct reference, no copy)
282
- this.headers = req.headers as Headers;
283
-
284
- // Store cookie header for lazy parsing
285
- this._cookieHeader = req.headers.cookie;
286
- this._cookies = null;
287
-
288
- // Get response builder from pool
289
- this.response = acquireResponseBuilder();
290
- }
291
-
292
- /**
293
- * Lazy URL getter - only create URL object when accessed
294
- * Most handlers don't need the full URL object
295
- */
296
- get url(): URL {
297
- if (!this._url) {
298
- this._url = new URL(this.path, `http://${this._host}`);
299
- }
300
- return this._url;
301
- }
302
-
303
- set url(value: URL) {
304
- this._url = value;
305
- }
306
-
307
- /**
308
- * Lazy query getter - only parse query string when accessed
309
- * Most simple endpoints like /json don't need query parsing
310
- * Inline fast-querystring for minimal overhead
311
- */
312
- get query(): Record<string, any> {
313
- if (this._query === null) {
314
- // Inline fast-querystring call directly - no method call overhead
315
- this._query = this._queryString
316
- ? fastQueryParse(this._queryString) as Record<string, any>
317
- : {};
318
- }
319
- return this._query;
320
- }
321
-
322
- set query(value: Record<string, any>) {
323
- this._query = value;
324
- }
325
-
326
- /**
327
- * Lazy cookies getter - only parse cookies when accessed
328
- */
329
- get cookies(): Cookies {
330
- if (!this._cookies) {
331
- this._cookies = new CookieManager(this._cookieHeader);
332
- }
333
- return this._cookies;
334
- }
335
-
336
- set cookies(value: Cookies) {
337
- this._cookies = value as CookieManager;
338
- }
339
-
340
- /**
341
- * Reinitialize context for pooling (avoids new object creation)
342
- */
343
- reinitialize(req: IncomingMessage, res: ServerResponse): void {
344
- this.raw = { req, res };
345
- this.method = (req.method ? req.method.toUpperCase() : 'GET') as HTTPMethod;
346
-
347
- // Fast URL parsing - delay query parsing
348
- const url = req.url || '/';
349
- const queryIndex = url.indexOf('?');
350
-
351
- if (queryIndex === -1) {
352
- this.path = url;
353
- this._queryString = '';
354
- this._query = null;
355
- } else {
356
- this.path = url.substring(0, queryIndex);
357
- this._queryString = url.substring(queryIndex + 1);
358
- this._query = null; // Parse lazily
359
- }
360
-
361
- // Lazy URL - don't create here
362
- this._host = (req.headers.host as string) || 'localhost';
363
- this._url = null;
364
-
365
- this.headers = req.headers as Headers;
366
-
367
- // Lazy cookies
368
- this._cookieHeader = req.headers.cookie;
369
- this._cookies = null;
370
-
371
- // Reuse or get new response builder from pool
372
- if (this.response && typeof (this.response as ResponseBuilderImpl).reset === 'function') {
373
- (this.response as ResponseBuilderImpl).reset();
374
- } else {
375
- this.response = acquireResponseBuilder();
376
- }
377
-
378
- // Reset body state
379
- this._parsedBody = undefined;
380
- this._bodyPromise = null;
381
- this._bodyParsed = false;
382
-
383
- // Reset params
384
- this.params = {};
385
-
386
- // Lazy data and store - just null them, create on access
387
- if (this._data) {
388
- this._data.clear();
389
- }
390
- this._requestStoreRegistry = null;
391
- }
392
-
393
- /**
394
- * Lazy body getter - parses body on first access
395
- * This is the KEY optimization that fixes POST performance!
396
- */
397
- get body(): any {
398
- // If already parsed synchronously, return it
399
- if (this._bodyParsed) {
400
- return this._parsedBody;
401
- }
402
-
403
- // Return undefined if not parsed yet
404
- // Use getBody() for async access
405
- return this._parsedBody;
406
- }
407
-
408
- /**
409
- * Set body directly (for backwards compatibility)
410
- */
411
- set body(value: any) {
412
- this._parsedBody = value;
413
- this._bodyParsed = true;
414
- }
415
-
416
- /**
417
- * Check if body is ready for sync access (no await needed)
418
- */
419
- get isBodyReady(): boolean {
420
- return this._bodyParsed;
421
- }
422
-
423
- /**
424
- * Wait for body to be parsed
425
- * Use this if you need to ensure body is available for sync access
426
- * @example
427
- * ```typescript
428
- * app.post('/data', async (ctx) => {
429
- * await ctx.waitForBody();
430
- * console.log(ctx.body); // Now safe to access synchronously
431
- * });
432
- * ```
433
- */
434
- async waitForBody(): Promise<any> {
435
- return this.getBody();
436
- }
437
-
438
- /**
439
- * Async body getter - use this in handlers for POST/PUT/PATCH
440
- * @example
441
- * ```typescript
442
- * app.post('/data', async (ctx) => {
443
- * const body = await ctx.getBody();
444
- * return { received: body };
445
- * });
446
- * ```
447
- */
448
- async getBody<T = any>(): Promise<T> {
449
- // Already parsed
450
- if (this._bodyParsed) {
451
- return this._parsedBody as T;
452
- }
453
-
454
- // Already parsing (dedup concurrent calls)
455
- if (this._bodyPromise) {
456
- return this._bodyPromise as Promise<T>;
457
- }
458
-
459
- // Start parsing with optimized parser
460
- this._bodyPromise = this.parseBodyOptimized();
461
- this._parsedBody = await this._bodyPromise;
462
- this._bodyParsed = true;
463
- this._bodyPromise = null;
464
-
465
- return this._parsedBody as T;
466
- }
467
-
468
- /**
469
- * Ultra-optimized body parser inspired by Fastify's approach
470
- * Key optimizations:
471
- * 1. Pre-check content-type before reading data
472
- * 2. Use direct string concatenation with setEncoding
473
- * 3. Minimal closure allocation
474
- * 4. Fast-path for JSON (most common case)
475
- */
476
- private parseBodyOptimized(): Promise<any> {
477
- const req = this.raw.req;
478
- const contentType = req.headers['content-type'];
479
-
480
- // Fast path: determine parser type once, before data collection
481
- const isJSON = contentType ? contentType.charCodeAt(0) === 97 && contentType.startsWith('application/json') : false;
482
- const isForm = !isJSON && contentType ? contentType.includes('x-www-form-urlencoded') : false;
483
-
484
- return new Promise((resolve, reject) => {
485
- // Set encoding for string mode - avoids Buffer.toString() overhead
486
- req.setEncoding('utf8');
487
-
488
- let body = '';
489
-
490
- const onData = (chunk: string) => {
491
- body += chunk;
492
- };
493
-
494
- const onEnd = () => {
495
- // Cleanup listeners immediately
496
- req.removeListener('data', onData);
497
- req.removeListener('end', onEnd);
498
- req.removeListener('error', onError);
499
-
500
- if (!body) {
501
- resolve({});
502
- return;
503
- }
504
-
505
- try {
506
- if (isJSON) {
507
- resolve(JSON.parse(body));
508
- } else if (isForm) {
509
- resolve(fastQueryParse(body));
510
- } else {
511
- resolve(body);
512
- }
513
- } catch (e) {
514
- reject(e);
515
- }
516
- };
517
-
518
- const onError = (err: Error) => {
519
- req.removeListener('data', onData);
520
- req.removeListener('end', onEnd);
521
- req.removeListener('error', onError);
522
- reject(err);
523
- };
524
-
525
- req.on('data', onData);
526
- req.on('end', onEnd);
527
- req.on('error', onError);
528
- });
529
- }
530
-
531
- /**
532
- * Internal body parser - optimized for performance
533
- * Uses string accumulation instead of Buffer.concat for better perf
534
- * @deprecated Use parseBodyOptimized instead
535
- */
536
- private parseBodyInternal(): Promise<any> {
537
- return new Promise((resolve, reject) => {
538
- const req = this.raw.req;
539
- const contentType = req.headers['content-type'] || '';
540
-
541
- // Use setEncoding to get strings directly - faster than Buffer.toString()
542
- req.setEncoding('utf8');
543
-
544
- let body = '';
545
-
546
- req.on('data', (chunk: string) => {
547
- body += chunk;
548
- });
549
-
550
- req.on('end', () => {
551
- if (!body) {
552
- resolve({});
553
- return;
554
- }
555
-
556
- try {
557
- // Inline content type check for hot path (JSON)
558
- if (contentType.includes('application/json')) {
559
- resolve(JSON.parse(body));
560
- } else if (contentType.includes('application/x-www-form-urlencoded')) {
561
- resolve(fastQueryParse(body));
562
- } else {
563
- resolve(body);
564
- }
565
- } catch (error) {
566
- reject(error);
567
- }
568
- });
569
-
570
- req.on('error', reject);
571
- });
572
- }
573
-
574
- /**
575
- * Parse body based on content type
576
- */
577
- private parseContentType(body: string, contentType: string): any {
578
- if (contentType.includes('application/json')) {
579
- return body ? JSON.parse(body) : {};
580
- } else if (contentType.includes('application/x-www-form-urlencoded')) {
581
- return fastQueryParse(body);
582
- } else if (contentType.includes('text/')) {
583
- return body;
584
- }
585
- return body;
586
- }
587
-
588
- /**
589
- * Clear body state (for pooling)
590
- */
591
- clearBody(): void {
592
- this._parsedBody = undefined;
593
- this._bodyPromise = null;
594
- this._bodyParsed = false;
595
- }
596
-
597
- // Convenience methods
598
- json<T>(data: T, status?: number): Response {
599
- if (status !== undefined) {
600
- return this.response.status(status).json(data);
601
- }
602
- return this.response.json(data);
603
- }
604
-
605
- html(content: string, status?: number): Response {
606
- if (status !== undefined) {
607
- return this.response.status(status).html(content);
608
- }
609
- return this.response.html(content);
610
- }
611
-
612
- text(content: string, status?: number): Response {
613
- if (status !== undefined) {
614
- return this.response.status(status).text(content);
615
- }
616
- return this.response.text(content);
617
- }
618
-
619
- redirect(url: string, status?: number): Response {
620
- return this.response.redirect(url, status);
621
- }
622
-
623
- stream(readable: NodeJS.ReadableStream): Response {
624
- return this.response.stream(readable);
625
- }
626
-
627
- /**
628
- * Access a registered global store by its class
629
- * Store persist across all requests (singleton)
630
- *
631
- * @param StoreClass - Store constructor class
632
- * @returns Store instance
633
- *
634
- * @example
635
- * ```typescript
636
- * app.get('/users', async (ctx) => {
637
- * const userStore = ctx.store(UserStore);
638
- * return { users: userStore.state.users };
639
- * });
640
- * ```
641
- */
642
- store<T extends ContextStore<any>>(StoreClass: StoreConstructor<T>): T {
643
- if (!this._storeRegistry) {
644
- throw new Error(
645
- '[Context] Store registry not initialized. ' +
646
- 'Make sure to call app.stores([...]) before accessing stores.'
647
- );
648
- }
649
- return this._storeRegistry.get(StoreClass);
650
- }
651
-
652
- /**
653
- * Lazy getter for request store registry
654
- */
655
- private getOrCreateRequestStoreRegistry(): RequestStoreRegistry {
656
- if (!this._requestStoreRegistry) {
657
- this._requestStoreRegistry = new RequestStoreRegistry(this._debug);
658
- }
659
- return this._requestStoreRegistry;
660
- }
661
-
662
- /**
663
- * Lazy getter for request data map
664
- */
665
- private getOrCreateData(): Map<string, any> {
666
- if (!this._data) {
667
- this._data = new Map();
668
- }
669
- return this._data;
670
- }
671
-
672
- /**
673
- * Access a request-scoped store by its class
674
- * Store only exists for this request, disposed after response
675
- *
676
- * @param StoreClass - RequestStore constructor class
677
- * @returns Store instance (created on first access)
678
- *
679
- * @example
680
- * ```typescript
681
- * class CheckoutStore extends RequestStore<CheckoutState> {
682
- * protected initial() { return { items: [], total: 0 }; }
683
- *
684
- * addItem(item: Item) {
685
- * this.update({
686
- * items: [...this.state.items, item],
687
- * total: this.state.total + item.price
688
- * });
689
- * }
690
- * }
691
- *
692
- * app.post('/checkout', async (ctx) => {
693
- * const checkout = ctx.requestStore(CheckoutStore);
694
- * checkout.addItem(ctx.body.item);
695
- * return { total: checkout.state.total };
696
- * });
697
- * // checkout store is automatically disposed after response
698
- * ```
699
- */
700
- requestStore<T extends RequestStore<any>>(StoreClass: RequestStoreConstructor<T>): T {
701
- return this.getOrCreateRequestStoreRegistry().get(StoreClass);
702
- }
703
-
704
- /**
705
- * Set a value in request-scoped storage
706
- * Data is automatically cleared after the request completes
707
- *
708
- * @param key - Storage key
709
- * @param value - Value to store
710
- *
711
- * @example
712
- * ```typescript
713
- * // In middleware or onBefore
714
- * ctx.set('user', { id: '123', name: 'John' });
715
- * ctx.set('startTime', Date.now());
716
- *
717
- * // In handler
718
- * const user = ctx.get('user');
719
- * ```
720
- */
721
- set<T = any>(key: string, value: T): void {
722
- this.getOrCreateData().set(key, value);
723
- }
724
-
725
- /**
726
- * Get a value from request-scoped storage
727
- *
728
- * @param key - Storage key
729
- * @returns The stored value or undefined
730
- *
731
- * @example
732
- * ```typescript
733
- * const user = ctx.get<User>('user');
734
- * const startTime = ctx.get<number>('startTime');
735
- * ```
736
- */
737
- get<T = any>(key: string): T | undefined {
738
- return this._data?.get(key) as T | undefined;
739
- }
740
-
741
- /**
742
- * Set store registry (called by Application)
743
- * @internal
744
- */
745
- setStoreRegistry(registry: StoreRegistry): void {
746
- this._storeRegistry = registry;
747
- }
748
-
749
- /**
750
- * Set debug mode (called by Application)
751
- * @internal
752
- */
753
- setDebugMode(debug: boolean): void {
754
- this._debug = debug;
755
- // Reset request store registry - will be created lazily with new debug mode
756
- this._requestStoreRegistry = null;
757
- }
758
-
759
- /**
760
- * Dispose request-scoped stores and data (called after response)
761
- * @internal
762
- */
763
- disposeRequestStores(): void {
764
- if (this._requestStoreRegistry) {
765
- this._requestStoreRegistry.dispose();
766
- this._requestStoreRegistry = null;
767
- }
768
- if (this._data) {
769
- this._data.clear();
770
- }
771
- // Release response builder back to pool
772
- if (this.response && typeof (this.response as ResponseBuilderImpl).reset === 'function') {
773
- releaseResponseBuilder(this.response as ResponseBuilderImpl);
774
- }
775
- }
776
-
777
- /**
778
- * Get request store registry for advanced usage
779
- * @internal
780
- */
781
- getRequestStoreRegistry(): RequestStoreRegistry {
782
- return this.getOrCreateRequestStoreRegistry();
783
- }
784
-
785
- /**
786
- * Set route parameters (called by router)
787
- */
788
- setParams(params: Record<string, string>): void {
789
- this.params = params;
790
- }
791
-
792
- /**
793
- * Set response serializers for fast JSON serialization
794
- * Called by router when route has response schema
795
- * @internal
796
- */
797
- setSerializers(serializers: Map<number | string, SerializerFunction>): void {
798
- if (this.response && typeof (this.response as ResponseBuilderImpl).setSerializers === 'function') {
799
- (this.response as ResponseBuilderImpl).setSerializers(serializers);
800
- }
801
- }
802
-
803
- /**
804
- * Set request body (called after parsing or by middleware)
805
- * @deprecated Use ctx.getBody() for async body access
806
- */
807
- setBody(body: any): void {
808
- this._parsedBody = body;
809
- this._bodyParsed = true;
810
- }
811
-
812
- /**
813
- * Get all Set-Cookie headers
814
- */
815
- getSetCookieHeaders(): string[] {
816
- // Use _cookies directly to avoid creating CookieManager if not needed
817
- if (!this._cookies) {
818
- return [];
819
- }
820
- return this._cookies.getSetCookieHeaders();
821
- }
822
- }
823
-
824
- /**
825
- * Parse request body based on Content-Type
826
- * @deprecated Use ctx.getBody() instead for lazy parsing
827
- */
828
- export async function parseBody(req: IncomingMessage): Promise<any> {
829
- return new Promise((resolve, reject) => {
830
- const contentType = req.headers['content-type'] || '';
831
- const chunks: Buffer[] = [];
832
-
833
- req.on('data', (chunk: Buffer) => chunks.push(chunk));
834
-
835
- req.on('end', () => {
836
- try {
837
- const buffer = Buffer.concat(chunks);
838
- const body = buffer.toString('utf-8');
839
-
840
- if (contentType.includes('application/json')) {
841
- resolve(body ? JSON.parse(body) : {});
842
- } else if (contentType.includes('application/x-www-form-urlencoded')) {
843
- resolve(fastQueryParse(body));
844
- } else if (contentType.includes('text/')) {
845
- resolve(body);
846
- } else {
847
- resolve(buffer);
848
- }
849
- } catch (error) {
850
- reject(error);
851
- }
852
- });
853
-
854
- req.on('error', reject);
855
- });
856
- }