@engjts/nexus 0.1.8 → 0.1.9

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 (205) hide show
  1. package/package.json +1 -1
  2. package/BENCHMARK_REPORT.md +0 -343
  3. package/documentation/01-getting-started.md +0 -240
  4. package/documentation/02-context.md +0 -335
  5. package/documentation/03-routing.md +0 -397
  6. package/documentation/04-middleware.md +0 -483
  7. package/documentation/05-validation.md +0 -514
  8. package/documentation/06-error-handling.md +0 -465
  9. package/documentation/07-performance.md +0 -364
  10. package/documentation/08-adapters.md +0 -470
  11. package/documentation/09-api-reference.md +0 -548
  12. package/documentation/10-examples.md +0 -582
  13. package/documentation/11-deployment.md +0 -477
  14. package/documentation/12-sentry.md +0 -620
  15. package/documentation/13-sentry-data-storage.md +0 -996
  16. package/documentation/14-sentry-data-reference.md +0 -457
  17. package/documentation/15-sentry-summary.md +0 -409
  18. package/documentation/16-alerts-system.md +0 -745
  19. package/documentation/17-alert-adapters.md +0 -696
  20. package/documentation/18-alerts-implementation-summary.md +0 -385
  21. package/documentation/19-class-based-routing.md +0 -840
  22. package/documentation/20-websocket-realtime.md +0 -813
  23. package/documentation/21-cache-system.md +0 -510
  24. package/documentation/22-job-queue.md +0 -772
  25. package/documentation/23-sentry-plugin.md +0 -551
  26. package/documentation/24-testing-utilities.md +0 -1287
  27. package/documentation/25-api-versioning.md +0 -533
  28. package/documentation/26-context-store.md +0 -607
  29. package/documentation/27-dependency-injection.md +0 -329
  30. package/documentation/28-lifecycle-hooks.md +0 -521
  31. package/documentation/29-package-structure.md +0 -196
  32. package/documentation/30-plugin-system.md +0 -414
  33. package/documentation/31-jwt-authentication.md +0 -597
  34. package/documentation/32-cli.md +0 -268
  35. package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
  36. package/documentation/ALERTS-INDEX.md +0 -330
  37. package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
  38. package/documentation/README.md +0 -178
  39. package/documentation/index.html +0 -34
  40. package/modern_framework_paper.md +0 -1870
  41. package/public/css/style.css +0 -87
  42. package/public/index.html +0 -34
  43. package/public/js/app.js +0 -27
  44. package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
  45. package/src/advanced/cache/MultiTierCache.ts +0 -194
  46. package/src/advanced/cache/RedisCacheStore.ts +0 -341
  47. package/src/advanced/cache/index.ts +0 -5
  48. package/src/advanced/cache/types.ts +0 -40
  49. package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
  50. package/src/advanced/graphql/index.ts +0 -22
  51. package/src/advanced/graphql/server.ts +0 -252
  52. package/src/advanced/graphql/types.ts +0 -42
  53. package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
  54. package/src/advanced/jobs/JobQueue.ts +0 -556
  55. package/src/advanced/jobs/RedisQueueStore.ts +0 -367
  56. package/src/advanced/jobs/index.ts +0 -5
  57. package/src/advanced/jobs/types.ts +0 -70
  58. package/src/advanced/observability/APMManager.ts +0 -163
  59. package/src/advanced/observability/AlertManager.ts +0 -109
  60. package/src/advanced/observability/MetricRegistry.ts +0 -151
  61. package/src/advanced/observability/ObservabilityCenter.ts +0 -304
  62. package/src/advanced/observability/StructuredLogger.ts +0 -154
  63. package/src/advanced/observability/TracingManager.ts +0 -117
  64. package/src/advanced/observability/adapters.ts +0 -304
  65. package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
  66. package/src/advanced/observability/index.ts +0 -11
  67. package/src/advanced/observability/types.ts +0 -174
  68. package/src/advanced/playground/extractPathParams.ts +0 -6
  69. package/src/advanced/playground/generateFieldExample.ts +0 -31
  70. package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1956
  71. package/src/advanced/playground/generateSummary.ts +0 -19
  72. package/src/advanced/playground/getTagFromPath.ts +0 -9
  73. package/src/advanced/playground/index.ts +0 -8
  74. package/src/advanced/playground/playground.ts +0 -250
  75. package/src/advanced/playground/types.ts +0 -49
  76. package/src/advanced/playground/zodToExample.ts +0 -16
  77. package/src/advanced/playground/zodToParams.ts +0 -15
  78. package/src/advanced/postman/buildAuth.ts +0 -31
  79. package/src/advanced/postman/buildBody.ts +0 -15
  80. package/src/advanced/postman/buildQueryParams.ts +0 -27
  81. package/src/advanced/postman/buildRequestItem.ts +0 -36
  82. package/src/advanced/postman/buildResponses.ts +0 -11
  83. package/src/advanced/postman/buildUrl.ts +0 -33
  84. package/src/advanced/postman/capitalize.ts +0 -4
  85. package/src/advanced/postman/generateCollection.ts +0 -59
  86. package/src/advanced/postman/generateEnvironment.ts +0 -34
  87. package/src/advanced/postman/generateExampleFromZod.ts +0 -21
  88. package/src/advanced/postman/generateFieldExample.ts +0 -45
  89. package/src/advanced/postman/generateName.ts +0 -20
  90. package/src/advanced/postman/generateUUID.ts +0 -11
  91. package/src/advanced/postman/getTagFromPath.ts +0 -10
  92. package/src/advanced/postman/index.ts +0 -28
  93. package/src/advanced/postman/postman.ts +0 -156
  94. package/src/advanced/postman/slugify.ts +0 -7
  95. package/src/advanced/postman/types.ts +0 -140
  96. package/src/advanced/realtime/index.ts +0 -18
  97. package/src/advanced/realtime/websocket.ts +0 -231
  98. package/src/advanced/sentry/index.ts +0 -1236
  99. package/src/advanced/sentry/types.ts +0 -355
  100. package/src/advanced/static/generateDirectoryListing.ts +0 -47
  101. package/src/advanced/static/generateETag.ts +0 -7
  102. package/src/advanced/static/getMimeType.ts +0 -9
  103. package/src/advanced/static/index.ts +0 -32
  104. package/src/advanced/static/isSafePath.ts +0 -13
  105. package/src/advanced/static/publicDir.ts +0 -21
  106. package/src/advanced/static/serveStatic.ts +0 -225
  107. package/src/advanced/static/spa.ts +0 -24
  108. package/src/advanced/static/types.ts +0 -159
  109. package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
  110. package/src/advanced/swagger/buildOperation.ts +0 -61
  111. package/src/advanced/swagger/buildParameters.ts +0 -61
  112. package/src/advanced/swagger/buildRequestBody.ts +0 -21
  113. package/src/advanced/swagger/buildResponses.ts +0 -54
  114. package/src/advanced/swagger/capitalize.ts +0 -5
  115. package/src/advanced/swagger/convertPath.ts +0 -9
  116. package/src/advanced/swagger/createSwagger.ts +0 -12
  117. package/src/advanced/swagger/generateOperationId.ts +0 -21
  118. package/src/advanced/swagger/generateSpec.ts +0 -105
  119. package/src/advanced/swagger/generateSummary.ts +0 -24
  120. package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
  121. package/src/advanced/swagger/generateThemeCss.ts +0 -53
  122. package/src/advanced/swagger/index.ts +0 -25
  123. package/src/advanced/swagger/swagger.ts +0 -237
  124. package/src/advanced/swagger/types.ts +0 -206
  125. package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
  126. package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
  127. package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
  128. package/src/advanced/testing/factory.ts +0 -509
  129. package/src/advanced/testing/harness.ts +0 -612
  130. package/src/advanced/testing/index.ts +0 -430
  131. package/src/advanced/testing/load-test.ts +0 -618
  132. package/src/advanced/testing/mock-server.ts +0 -498
  133. package/src/advanced/testing/mock.ts +0 -670
  134. package/src/cli/bin.ts +0 -9
  135. package/src/cli/cli.ts +0 -158
  136. package/src/cli/commands/add.ts +0 -178
  137. package/src/cli/commands/build.ts +0 -73
  138. package/src/cli/commands/create.ts +0 -166
  139. package/src/cli/commands/dev.ts +0 -85
  140. package/src/cli/commands/generate.ts +0 -99
  141. package/src/cli/commands/help.ts +0 -95
  142. package/src/cli/commands/init.ts +0 -91
  143. package/src/cli/commands/version.ts +0 -38
  144. package/src/cli/index.ts +0 -6
  145. package/src/cli/templates/generators.ts +0 -359
  146. package/src/cli/templates/index.ts +0 -680
  147. package/src/cli/utils/exec.ts +0 -52
  148. package/src/cli/utils/file-system.ts +0 -78
  149. package/src/cli/utils/logger.ts +0 -111
  150. package/src/core/adapter.ts +0 -88
  151. package/src/core/application.ts +0 -1453
  152. package/src/core/context-pool.ts +0 -79
  153. package/src/core/context.ts +0 -856
  154. package/src/core/index.ts +0 -94
  155. package/src/core/middleware.ts +0 -272
  156. package/src/core/performance/buffer-pool.ts +0 -108
  157. package/src/core/performance/middleware-optimizer.ts +0 -162
  158. package/src/core/plugin/PluginManager.ts +0 -435
  159. package/src/core/plugin/builder.ts +0 -358
  160. package/src/core/plugin/index.ts +0 -50
  161. package/src/core/plugin/types.ts +0 -214
  162. package/src/core/router/file-router.ts +0 -623
  163. package/src/core/router/index.ts +0 -260
  164. package/src/core/router/radix-tree.ts +0 -242
  165. package/src/core/serializer.ts +0 -397
  166. package/src/core/store/index.ts +0 -30
  167. package/src/core/store/registry.ts +0 -178
  168. package/src/core/store/request-store.ts +0 -240
  169. package/src/core/store/types.ts +0 -233
  170. package/src/core/types.ts +0 -616
  171. package/src/database/adapter.ts +0 -35
  172. package/src/database/adapters/index.ts +0 -1
  173. package/src/database/adapters/mysql.ts +0 -669
  174. package/src/database/database.ts +0 -70
  175. package/src/database/dialect.ts +0 -388
  176. package/src/database/index.ts +0 -12
  177. package/src/database/migrations.ts +0 -86
  178. package/src/database/optimizer.ts +0 -125
  179. package/src/database/query-builder.ts +0 -404
  180. package/src/database/realtime.ts +0 -53
  181. package/src/database/schema.ts +0 -71
  182. package/src/database/transactions.ts +0 -56
  183. package/src/database/types.ts +0 -87
  184. package/src/deployment/cluster.ts +0 -471
  185. package/src/deployment/config.ts +0 -454
  186. package/src/deployment/docker.ts +0 -599
  187. package/src/deployment/graceful-shutdown.ts +0 -373
  188. package/src/deployment/index.ts +0 -56
  189. package/src/index.ts +0 -281
  190. package/src/security/adapter.ts +0 -318
  191. package/src/security/auth/JWTPlugin.ts +0 -234
  192. package/src/security/auth/JWTProvider.ts +0 -316
  193. package/src/security/auth/adapter.ts +0 -12
  194. package/src/security/auth/jwt.ts +0 -234
  195. package/src/security/auth/middleware.ts +0 -188
  196. package/src/security/csrf.ts +0 -220
  197. package/src/security/headers.ts +0 -108
  198. package/src/security/index.ts +0 -60
  199. package/src/security/rate-limit/adapter.ts +0 -7
  200. package/src/security/rate-limit/memory.ts +0 -108
  201. package/src/security/rate-limit/middleware.ts +0 -181
  202. package/src/security/sanitization.ts +0 -75
  203. package/src/security/types.ts +0 -240
  204. package/src/security/utils.ts +0 -52
  205. package/tsconfig.json +0 -39
@@ -1,188 +0,0 @@
1
- /**
2
- * Authentication Middleware
3
- *
4
- * Provides authentication and authorization middleware
5
- */
6
-
7
- import type { Context, Next, Middleware } from '../../core/types';
8
- import type { User, AuthContext, AuthStrategies } from '../types';
9
- import type { AuthAdapter, PermissionAdapter } from '../adapter';
10
- import { DefaultPermissionAdapter } from '../adapter';
11
- import { JWTAuthAdapter } from './jwt';
12
-
13
- /**
14
- * Authentication middleware factory
15
- *
16
- * @example
17
- * ```ts
18
- * // JWT authentication
19
- * app.use(authenticate({
20
- * jwt: {
21
- * secret: process.env.JWT_SECRET,
22
- * expiresIn: '15m'
23
- * }
24
- * }));
25
- *
26
- * // Optional authentication
27
- * app.use(authenticate({ jwt: config }, { required: false }));
28
- * ```
29
- */
30
- export function authenticate(
31
- strategies: AuthStrategies,
32
- options: {
33
- required?: boolean;
34
- strategies?: ('jwt' | 'oauth' | 'session')[];
35
- } = {}
36
- ): Middleware<Context, AuthContext> {
37
- const adapters = new Map<string, AuthAdapter>();
38
- const required = options.required !== false;
39
- const strategyOrder = options.strategies || ['jwt', 'oauth', 'session'];
40
-
41
- // Initialize adapters
42
- if (strategies.jwt) {
43
- adapters.set('jwt', new JWTAuthAdapter());
44
- }
45
- // OAuth and Session will be added in future
46
- // if (strategies.oauth) adapters.set('oauth', new OAuthAdapter());
47
- // if (strategies.session) adapters.set('session', new SessionAdapter());
48
-
49
- return (async (ctx: Context, next: Next, _deps: any) => {
50
- let user: User | null = null;
51
-
52
- // Try each strategy in order
53
- for (const strategyName of strategyOrder) {
54
- const adapter = adapters.get(strategyName);
55
- const config = (strategies as any)[strategyName];
56
-
57
- if (adapter && config) {
58
- try {
59
- user = await adapter.verify(ctx, config);
60
- if (user) {
61
- break;
62
- }
63
- } catch (error) {
64
- // Try next strategy
65
- continue;
66
- }
67
- }
68
- }
69
-
70
- // If no user found and auth is required
71
- if (!user && required) {
72
- return {
73
- statusCode: 401,
74
- headers: { 'Content-Type': 'application/json' },
75
- body: JSON.stringify({ error: 'Unauthorized' })
76
- };
77
- }
78
-
79
- // Attach user to context
80
- (ctx as unknown as AuthContext).user = user!;
81
-
82
- return next(ctx as unknown as AuthContext);
83
- }) as Middleware<Context, AuthContext>;
84
- }
85
-
86
- /**
87
- * Optional authentication - doesn't throw if no auth provided
88
- */
89
- export function optionalAuth(strategies: AuthStrategies): Middleware<Context, Partial<AuthContext>> {
90
- return authenticate(strategies, { required: false }) as any;
91
- }
92
-
93
- /**
94
- * Require authentication - throws 401 if not authenticated
95
- */
96
- export function requireAuth(strategies: AuthStrategies): Middleware<Context, AuthContext> {
97
- return authenticate(strategies, { required: true });
98
- }
99
-
100
- /**
101
- * Permission-based authorization middleware
102
- *
103
- * @example
104
- * ```ts
105
- * app.post('/admin/users',
106
- * authenticate({ jwt: config }),
107
- * requirePermissions(['admin', 'write:users']),
108
- * handler
109
- * );
110
- * ```
111
- */
112
- export function requirePermissions(
113
- permissions: string[],
114
- adapter?: PermissionAdapter
115
- ): Middleware<AuthContext, AuthContext> {
116
- const permissionChecker = adapter || new DefaultPermissionAdapter();
117
-
118
- return (async (ctx: AuthContext, next: Next, _deps: any) => {
119
- if (!ctx.user) {
120
- return {
121
- statusCode: 401,
122
- headers: { 'Content-Type': 'application/json' },
123
- body: JSON.stringify({ error: 'Unauthorized' })
124
- };
125
- }
126
-
127
- const result = permissionChecker.checkPermissions(ctx.user, permissions);
128
-
129
- if (!result.allowed) {
130
- return {
131
- statusCode: 403,
132
- headers: { 'Content-Type': 'application/json' },
133
- body: JSON.stringify({
134
- error: 'Forbidden',
135
- message: 'Insufficient permissions',
136
- missing: result.missing
137
- })
138
- };
139
- }
140
-
141
- return next(ctx);
142
- }) as Middleware<AuthContext, AuthContext>;
143
- }
144
-
145
- /**
146
- * Role-based authorization middleware
147
- *
148
- * @example
149
- * ```ts
150
- * app.get('/admin/*',
151
- * authenticate({ jwt: config }),
152
- * requireRoles(['admin']),
153
- * handler
154
- * );
155
- * ```
156
- */
157
- export function requireRoles(
158
- roles: string[],
159
- adapter?: PermissionAdapter
160
- ): Middleware<AuthContext, AuthContext> {
161
- const permissionChecker = adapter || new DefaultPermissionAdapter();
162
-
163
- return (async (ctx: AuthContext, next: Next, _deps: any) => {
164
- if (!ctx.user) {
165
- return {
166
- statusCode: 401,
167
- headers: { 'Content-Type': 'application/json' },
168
- body: JSON.stringify({ error: 'Unauthorized' })
169
- };
170
- }
171
-
172
- const hasRole = permissionChecker.checkRoles(ctx.user, roles);
173
-
174
- if (!hasRole) {
175
- return {
176
- statusCode: 403,
177
- headers: { 'Content-Type': 'application/json' },
178
- body: JSON.stringify({
179
- error: 'Forbidden',
180
- message: 'Insufficient roles',
181
- required: roles
182
- })
183
- };
184
- }
185
-
186
- return next(ctx);
187
- }) as Middleware<AuthContext, AuthContext>;
188
- }
@@ -1,220 +0,0 @@
1
- /**
2
- * CSRF Protection Middleware
3
- *
4
- * Implements Cross-Site Request Forgery protection
5
- */
6
-
7
- import type { Context, Next, Middleware } from '../core/types';
8
- import type { CSRFConfig } from './types';
9
- import type { CSRFAdapter } from './adapter';
10
-
11
- /**
12
- * Default CSRF token adapter
13
- * Uses double-submit cookie pattern
14
- */
15
- class DefaultCSRFAdapter implements CSRFAdapter {
16
- private readonly tokenLength: number;
17
-
18
- constructor(tokenLength: number = 32) {
19
- this.tokenLength = tokenLength;
20
- }
21
-
22
- generateToken(_ctx: Context): string {
23
- // Generate random token
24
- const bytes = crypto.getRandomValues(new Uint8Array(this.tokenLength));
25
- return Array.from(bytes)
26
- .map(b => b.toString(16).padStart(2, '0'))
27
- .join('');
28
- }
29
-
30
- validateToken(ctx: Context, token: string): boolean {
31
- // In double-submit cookie pattern, token in cookie should match token in header/body
32
- const cookieToken = this.extractTokenFromCookie(ctx);
33
-
34
- if (!cookieToken) {
35
- return false;
36
- }
37
-
38
- // Constant-time comparison to prevent timing attacks
39
- return this.constantTimeCompare(token, cookieToken);
40
- }
41
-
42
- extractToken(ctx: Context): string | null {
43
- // Try header first
44
- const csrfHeader = ctx.headers['x-csrf-token'] || ctx.headers['X-CSRF-Token'];
45
- if (csrfHeader) {
46
- return Array.isArray(csrfHeader) ? csrfHeader[0] : csrfHeader;
47
- }
48
-
49
- const csrfTokenHeader = ctx.headers['csrf-token'] || ctx.headers['CSRF-Token'];
50
- if (csrfTokenHeader) {
51
- return Array.isArray(csrfTokenHeader) ? csrfTokenHeader[0] : csrfTokenHeader;
52
- }
53
-
54
- // Try body
55
- if (ctx.body && typeof ctx.body === 'object') {
56
- return (ctx.body as any)._csrf || (ctx.body as any).csrf_token || null;
57
- }
58
-
59
- return null;
60
- }
61
-
62
- private extractTokenFromCookie(ctx: Context): string | null {
63
- const cookieHeaderRaw = ctx.headers['cookie'] || ctx.headers['Cookie'];
64
- if (!cookieHeaderRaw) {
65
- return null;
66
- }
67
-
68
- const cookieHeader = Array.isArray(cookieHeaderRaw) ? cookieHeaderRaw[0] : cookieHeaderRaw;
69
-
70
- const match = cookieHeader.match(/_csrf=([^;]+)/);
71
- return match ? match[1] : null;
72
- }
73
-
74
- private constantTimeCompare(a: string, b: string): boolean {
75
- if (a.length !== b.length) {
76
- return false;
77
- }
78
-
79
- let result = 0;
80
- for (let i = 0; i < a.length; i++) {
81
- result |= a.charCodeAt(i) ^ b.charCodeAt(i);
82
- }
83
-
84
- return result === 0;
85
- }
86
- }
87
-
88
- /**
89
- * CSRF protection middleware
90
- *
91
- * @example
92
- * ```ts
93
- * app.use(csrf({
94
- * cookie: { sameSite: 'strict' },
95
- * excludeRoutes: ['/api/webhook/*']
96
- * }));
97
- * ```
98
- */
99
- export function csrf(
100
- config: CSRFConfig = {},
101
- adapter?: CSRFAdapter
102
- ): Middleware {
103
- const csrfAdapter = adapter || new DefaultCSRFAdapter(config.tokenLength);
104
- const auto = config.auto !== false;
105
- const excludeMethods = config.excludeMethods || ['GET', 'HEAD', 'OPTIONS'];
106
- const excludeRoutes = config.excludeRoutes || [];
107
-
108
- return async (ctx: Context, next: Next, _deps: any) => {
109
- // Skip safe methods
110
- if (excludeMethods.includes(ctx.method)) {
111
- return next(ctx);
112
- }
113
-
114
- // Skip excluded routes
115
- for (const pattern of excludeRoutes) {
116
- const regex = new RegExp('^' + pattern.replace('*', '.*') + '$');
117
- if (regex.test(ctx.path)) {
118
- return next(ctx);
119
- }
120
- }
121
-
122
- // Validate CSRF token
123
- if (auto) {
124
- const token = csrfAdapter.extractToken(ctx);
125
-
126
- if (!token) {
127
- return {
128
- statusCode: 403,
129
- headers: { 'Content-Type': 'application/json' },
130
- body: JSON.stringify({
131
- error: 'CSRF token missing'
132
- })
133
- };
134
- }
135
-
136
- const valid = csrfAdapter.validateToken(ctx, token);
137
-
138
- if (!valid) {
139
- return {
140
- statusCode: 403,
141
- headers: { 'Content-Type': 'application/json' },
142
- body: JSON.stringify({
143
- error: 'CSRF token invalid'
144
- })
145
- };
146
- }
147
- }
148
-
149
- return next(ctx);
150
- };
151
- }
152
-
153
- /**
154
- * Generate CSRF token middleware
155
- * Attaches token to context and sets cookie
156
- *
157
- * @example
158
- * ```ts
159
- * app.use(generateCSRFToken());
160
- *
161
- * // In handler
162
- * app.get('/form', async (ctx) => {
163
- * const token = ctx.csrfToken;
164
- * return ctx.html(`<input type="hidden" name="_csrf" value="${token}">`);
165
- * });
166
- * ```
167
- */
168
- export function generateCSRFToken(
169
- config: CSRFConfig = {},
170
- adapter?: CSRFAdapter
171
- ): Middleware {
172
- const csrfAdapter = adapter || new DefaultCSRFAdapter(config.tokenLength);
173
- const cookieName = config.cookie?.name || '_csrf';
174
- const cookieOptions = {
175
- sameSite: config.cookie?.sameSite || 'strict',
176
- secure: config.cookie?.secure !== false,
177
- httpOnly: config.cookie?.httpOnly !== false
178
- };
179
-
180
- return async (ctx: Context, next: Next, _deps: any) => {
181
- // Generate token
182
- const token = csrfAdapter.generateToken(ctx);
183
-
184
- // Attach to context
185
- (ctx as any).csrfToken = token;
186
-
187
- // Execute handler
188
- const response = await next(ctx);
189
-
190
- // Set cookie
191
- const cookieValue = `${cookieName}=${token}; SameSite=${cookieOptions.sameSite}${cookieOptions.secure ? '; Secure' : ''}${cookieOptions.httpOnly ? '; HttpOnly' : ''}; Path=/`;
192
-
193
- // Append cookie to response headers
194
- if (!response.headers['Set-Cookie']) {
195
- response.headers['Set-Cookie'] = cookieValue;
196
- } else if (Array.isArray(response.headers['Set-Cookie'])) {
197
- response.headers['Set-Cookie'].push(cookieValue);
198
- } else {
199
- response.headers['Set-Cookie'] = [response.headers['Set-Cookie'], cookieValue];
200
- }
201
-
202
- return response;
203
- };
204
- }
205
-
206
- /**
207
- * Combined CSRF middleware - generates and validates tokens
208
- */
209
- export function csrfProtection(config: CSRFConfig = {}): Middleware {
210
- const generateMiddleware = generateCSRFToken(config);
211
- const validateMiddleware = csrf(config);
212
-
213
- return async (ctx: Context, next: Next, deps: any) => {
214
- // First generate token
215
- return generateMiddleware(ctx, async (ctxWithToken: Context) => {
216
- // Then validate on unsafe methods
217
- return validateMiddleware(ctxWithToken, next, deps);
218
- }, deps);
219
- };
220
- }
@@ -1,108 +0,0 @@
1
- /**
2
- * Security Headers Middleware
3
- *
4
- * Automatically applies security headers to responses
5
- */
6
-
7
- import type { Context, Next, Middleware } from '../core/types';
8
- import type { SecurityHeadersConfig } from './types';
9
- import type { SecurityHeadersAdapter } from './adapter';
10
- import { DefaultSecurityHeadersAdapter } from './adapter';
11
-
12
- /**
13
- * Create security headers middleware
14
- *
15
- * @example
16
- * ```ts
17
- * app.use(securityHeaders({
18
- * mode: 'strict',
19
- * csp: {
20
- * directives: {
21
- * 'default-src': ["'self'"],
22
- * 'script-src': ["'self'", "'nonce'"]
23
- * }
24
- * }
25
- * }));
26
- * ```
27
- */
28
- export function securityHeaders(
29
- config: SecurityHeadersConfig = {},
30
- adapter?: SecurityHeadersAdapter
31
- ): Middleware {
32
- const adapterInstance = adapter || new DefaultSecurityHeadersAdapter();
33
- const nonces = new WeakMap<Context, string>();
34
-
35
- return async (ctx: Context, next: Next, _deps: any) => {
36
- // Generate nonce if CSP uses it
37
- if (config.autoNonce && config.csp) {
38
- const nonce = adapterInstance.generateNonce?.() || crypto.randomUUID();
39
- nonces.set(ctx, nonce);
40
-
41
- // Replace 'nonce' placeholder in CSP directives
42
- if (config.csp.directives) {
43
- for (const [key, values] of Object.entries(config.csp.directives)) {
44
- config.csp.directives[key] = values.map(v =>
45
- v === "'nonce'" ? `'nonce-${nonce}'` : v
46
- );
47
- }
48
- }
49
-
50
- // Attach nonce to context for use in templates
51
- (ctx as any).nonce = nonce;
52
- }
53
-
54
- // Generate headers
55
- const headers = adapterInstance.generateHeaders(ctx, config);
56
-
57
- // Execute handler
58
- const response = await next(ctx);
59
-
60
- // Apply headers to response
61
- for (const [name, value] of Object.entries(headers)) {
62
- response.headers[name] = value;
63
- }
64
-
65
- return response;
66
- };
67
- }
68
-
69
- /**
70
- * Strict security headers preset
71
- */
72
- export function strictSecurityHeaders(customConfig: Partial<SecurityHeadersConfig> = {}): Middleware {
73
- return securityHeaders({
74
- mode: 'strict',
75
- csp: {
76
- directives: {
77
- 'default-src': ["'self'"],
78
- 'script-src': ["'self'"],
79
- 'style-src': ["'self'"],
80
- 'img-src': ["'self'", 'data:', 'https:'],
81
- 'font-src': ["'self'"],
82
- 'connect-src': ["'self'"],
83
- 'frame-ancestors': ["'none'"],
84
- 'base-uri': ["'self'"],
85
- 'form-action': ["'self'"]
86
- }
87
- },
88
- ...customConfig
89
- });
90
- }
91
-
92
- /**
93
- * Moderate security headers preset
94
- */
95
- export function moderateSecurityHeaders(customConfig: Partial<SecurityHeadersConfig> = {}): Middleware {
96
- return securityHeaders({
97
- mode: 'moderate',
98
- csp: {
99
- directives: {
100
- 'default-src': ["'self'"],
101
- 'script-src': ["'self'", "'unsafe-inline'"],
102
- 'style-src': ["'self'", "'unsafe-inline'"],
103
- 'img-src': ["'self'", 'data:', 'https:']
104
- }
105
- },
106
- ...customConfig
107
- });
108
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * Security Module Entry Point
3
- *
4
- * Exports all security features
5
- */
6
-
7
- // Types
8
- export * from './types';
9
-
10
- // Adapters
11
- export * from './adapter';
12
-
13
- // Security Headers
14
- export {
15
- securityHeaders,
16
- strictSecurityHeaders,
17
- moderateSecurityHeaders
18
- } from './headers';
19
-
20
- // Input Sanitization
21
- export {
22
- sanitizeInput,
23
- strictSanitization,
24
- lenientSanitization
25
- } from './sanitization';
26
-
27
- // Authentication
28
- export {
29
- authenticate,
30
- optionalAuth,
31
- requireAuth,
32
- requirePermissions,
33
- requireRoles
34
- } from './auth/middleware';
35
-
36
- export { JWTAuthAdapter } from './auth/jwt';
37
-
38
- // JWT Provider (for DI)
39
- export { JWTProvider, createJWTProvider } from './auth/JWTProvider';
40
- export type { JWTProviderConfig, TokenPayload, VerifyResult } from './auth/JWTProvider';
41
-
42
- // JWT Plugin
43
- export { jwtPlugin } from './auth/JWTPlugin';
44
- export type { JWTPluginConfig, JWTPluginExports } from './auth/JWTPlugin';
45
-
46
- // Rate Limiting
47
- export {
48
- rateLimit,
49
- strictRateLimit,
50
- lenientRateLimit
51
- } from './rate-limit/middleware';
52
-
53
- export { MemoryRateLimiter } from './rate-limit/memory';
54
-
55
- // CSRF Protection
56
- export {
57
- csrf,
58
- generateCSRFToken,
59
- csrfProtection
60
- } from './csrf';
@@ -1,7 +0,0 @@
1
- /**
2
- * Rate Limit Adapter Interface
3
- *
4
- * Extensible rate limiting storage backends
5
- */
6
-
7
- export type { RateLimitAdapter } from '../adapter';
@@ -1,108 +0,0 @@
1
- /**
2
- * In-Memory Rate Limiter
3
- *
4
- * Simple in-memory rate limiting implementation
5
- */
6
-
7
- import type { RateLimitAdapter } from '../adapter';
8
- import type { RateLimitInfo } from '../types';
9
-
10
- interface RateLimitEntry {
11
- count: number;
12
- resetTime: number;
13
- firstRequest: number;
14
- }
15
-
16
- /**
17
- * In-memory rate limit storage
18
- * Uses sliding window algorithm
19
- */
20
- export class MemoryRateLimiter implements RateLimitAdapter {
21
- private store = new Map<string, RateLimitEntry>();
22
- private cleanupInterval: NodeJS.Timeout | null = null;
23
-
24
- constructor(cleanupIntervalMs: number = 60000) {
25
- // Periodic cleanup of expired entries
26
- this.cleanupInterval = setInterval(() => {
27
- this.cleanup();
28
- }, cleanupIntervalMs);
29
- }
30
-
31
- async increment(key: string, windowMs: number): Promise<{
32
- count: number;
33
- resetTime: number;
34
- }> {
35
- const now = Date.now();
36
- const entry = this.store.get(key);
37
-
38
- // No existing entry or expired
39
- if (!entry || now >= entry.resetTime) {
40
- const newEntry: RateLimitEntry = {
41
- count: 1,
42
- resetTime: now + windowMs,
43
- firstRequest: now
44
- };
45
- this.store.set(key, newEntry);
46
-
47
- return {
48
- count: 1,
49
- resetTime: newEntry.resetTime
50
- };
51
- }
52
-
53
- // Increment existing entry
54
- entry.count++;
55
-
56
- return {
57
- count: entry.count,
58
- resetTime: entry.resetTime
59
- };
60
- }
61
-
62
- async get(key: string): Promise<RateLimitInfo | null> {
63
- const entry = this.store.get(key);
64
-
65
- if (!entry) {
66
- return null;
67
- }
68
-
69
- const now = Date.now();
70
-
71
- // Expired
72
- if (now >= entry.resetTime) {
73
- this.store.delete(key);
74
- return null;
75
- }
76
-
77
- return {
78
- limit: -1, // Will be set by middleware
79
- remaining: -1, // Will be calculated by middleware
80
- reset: Math.floor(entry.resetTime / 1000),
81
- retryAfter: Math.ceil((entry.resetTime - now) / 1000)
82
- };
83
- }
84
-
85
- async reset(key: string): Promise<void> {
86
- this.store.delete(key);
87
- }
88
-
89
- async cleanup(): Promise<void> {
90
- const now = Date.now();
91
-
92
- for (const [key, entry] of this.store.entries()) {
93
- if (now >= entry.resetTime) {
94
- this.store.delete(key);
95
- }
96
- }
97
- }
98
-
99
- /**
100
- * Stop cleanup interval
101
- */
102
- destroy(): void {
103
- if (this.cleanupInterval) {
104
- clearInterval(this.cleanupInterval);
105
- this.cleanupInterval = null;
106
- }
107
- }
108
- }