@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,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
- }