@qwickapps/server 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/README.md +157 -0
  2. package/dist/core/control-panel.d.ts.map +1 -1
  3. package/dist/core/control-panel.js +114 -0
  4. package/dist/core/control-panel.js.map +1 -1
  5. package/dist/core/types.d.ts +19 -0
  6. package/dist/core/types.d.ts.map +1 -1
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +4 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/plugins/auth/adapter-wrapper.d.ts +47 -0
  12. package/dist/plugins/auth/adapter-wrapper.d.ts.map +1 -0
  13. package/dist/plugins/auth/adapter-wrapper.js +166 -0
  14. package/dist/plugins/auth/adapter-wrapper.js.map +1 -0
  15. package/dist/plugins/auth/adapter-wrapper.test.d.ts +7 -0
  16. package/dist/plugins/auth/adapter-wrapper.test.d.ts.map +1 -0
  17. package/dist/plugins/auth/adapter-wrapper.test.js +303 -0
  18. package/dist/plugins/auth/adapter-wrapper.test.js.map +1 -0
  19. package/dist/plugins/auth/config-store.d.ts +11 -0
  20. package/dist/plugins/auth/config-store.d.ts.map +1 -0
  21. package/dist/plugins/auth/config-store.js +232 -0
  22. package/dist/plugins/auth/config-store.js.map +1 -0
  23. package/dist/plugins/auth/config-store.test.d.ts +7 -0
  24. package/dist/plugins/auth/config-store.test.d.ts.map +1 -0
  25. package/dist/plugins/auth/config-store.test.js +299 -0
  26. package/dist/plugins/auth/config-store.test.js.map +1 -0
  27. package/dist/plugins/auth/env-config.d.ts +51 -1
  28. package/dist/plugins/auth/env-config.d.ts.map +1 -1
  29. package/dist/plugins/auth/env-config.js +640 -7
  30. package/dist/plugins/auth/env-config.js.map +1 -1
  31. package/dist/plugins/auth/index.d.ts +6 -2
  32. package/dist/plugins/auth/index.d.ts.map +1 -1
  33. package/dist/plugins/auth/index.js +5 -1
  34. package/dist/plugins/auth/index.js.map +1 -1
  35. package/dist/plugins/auth/types.d.ts +106 -0
  36. package/dist/plugins/auth/types.d.ts.map +1 -1
  37. package/dist/plugins/index.d.ts +4 -2
  38. package/dist/plugins/index.d.ts.map +1 -1
  39. package/dist/plugins/index.js +3 -1
  40. package/dist/plugins/index.js.map +1 -1
  41. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts +7 -0
  42. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts.map +1 -0
  43. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js +220 -0
  44. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js.map +1 -0
  45. package/dist/plugins/rate-limit/cleanup.d.ts +40 -0
  46. package/dist/plugins/rate-limit/cleanup.d.ts.map +1 -0
  47. package/dist/plugins/rate-limit/cleanup.js +72 -0
  48. package/dist/plugins/rate-limit/cleanup.js.map +1 -0
  49. package/dist/plugins/rate-limit/env-config.d.ts +91 -0
  50. package/dist/plugins/rate-limit/env-config.d.ts.map +1 -0
  51. package/dist/plugins/rate-limit/env-config.js +318 -0
  52. package/dist/plugins/rate-limit/env-config.js.map +1 -0
  53. package/dist/plugins/rate-limit/index.d.ts +76 -0
  54. package/dist/plugins/rate-limit/index.d.ts.map +1 -0
  55. package/dist/plugins/rate-limit/index.js +79 -0
  56. package/dist/plugins/rate-limit/index.js.map +1 -0
  57. package/dist/plugins/rate-limit/middleware.d.ts +40 -0
  58. package/dist/plugins/rate-limit/middleware.d.ts.map +1 -0
  59. package/dist/plugins/rate-limit/middleware.js +169 -0
  60. package/dist/plugins/rate-limit/middleware.js.map +1 -0
  61. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts +44 -0
  62. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts.map +1 -0
  63. package/dist/plugins/rate-limit/rate-limit-plugin.js +354 -0
  64. package/dist/plugins/rate-limit/rate-limit-plugin.js.map +1 -0
  65. package/dist/plugins/rate-limit/rate-limit-service.d.ts +110 -0
  66. package/dist/plugins/rate-limit/rate-limit-service.d.ts.map +1 -0
  67. package/dist/plugins/rate-limit/rate-limit-service.js +172 -0
  68. package/dist/plugins/rate-limit/rate-limit-service.js.map +1 -0
  69. package/dist/plugins/rate-limit/stores/cache-store.d.ts +33 -0
  70. package/dist/plugins/rate-limit/stores/cache-store.d.ts.map +1 -0
  71. package/dist/plugins/rate-limit/stores/cache-store.js +225 -0
  72. package/dist/plugins/rate-limit/stores/cache-store.js.map +1 -0
  73. package/dist/plugins/rate-limit/stores/index.d.ts +8 -0
  74. package/dist/plugins/rate-limit/stores/index.d.ts.map +1 -0
  75. package/dist/plugins/rate-limit/stores/index.js +8 -0
  76. package/dist/plugins/rate-limit/stores/index.js.map +1 -0
  77. package/dist/plugins/rate-limit/stores/postgres-store.d.ts +34 -0
  78. package/dist/plugins/rate-limit/stores/postgres-store.d.ts.map +1 -0
  79. package/dist/plugins/rate-limit/stores/postgres-store.js +320 -0
  80. package/dist/plugins/rate-limit/stores/postgres-store.js.map +1 -0
  81. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts +21 -0
  82. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts.map +1 -0
  83. package/dist/plugins/rate-limit/strategies/fixed-window.js +97 -0
  84. package/dist/plugins/rate-limit/strategies/fixed-window.js.map +1 -0
  85. package/dist/plugins/rate-limit/strategies/index.d.ts +14 -0
  86. package/dist/plugins/rate-limit/strategies/index.d.ts.map +1 -0
  87. package/dist/plugins/rate-limit/strategies/index.js +27 -0
  88. package/dist/plugins/rate-limit/strategies/index.js.map +1 -0
  89. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts +22 -0
  90. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts.map +1 -0
  91. package/dist/plugins/rate-limit/strategies/sliding-window.js +122 -0
  92. package/dist/plugins/rate-limit/strategies/sliding-window.js.map +1 -0
  93. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts +28 -0
  94. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts.map +1 -0
  95. package/dist/plugins/rate-limit/strategies/token-bucket.js +121 -0
  96. package/dist/plugins/rate-limit/strategies/token-bucket.js.map +1 -0
  97. package/dist/plugins/rate-limit/types.d.ts +265 -0
  98. package/dist/plugins/rate-limit/types.d.ts.map +1 -0
  99. package/dist/plugins/rate-limit/types.js +9 -0
  100. package/dist/plugins/rate-limit/types.js.map +1 -0
  101. package/dist-ui/assets/index-D7DoZ9rL.js +478 -0
  102. package/dist-ui/assets/index-D7DoZ9rL.js.map +1 -0
  103. package/dist-ui/index.html +1 -1
  104. package/dist-ui-lib/api/controlPanelApi.d.ts +141 -0
  105. package/dist-ui-lib/dashboard/widgets/AuthStatusWidget.d.ts +9 -0
  106. package/dist-ui-lib/dashboard/widgets/IntegrationStatusWidget.d.ts +9 -0
  107. package/dist-ui-lib/dashboard/widgets/index.d.ts +2 -0
  108. package/dist-ui-lib/index.js +3332 -2343
  109. package/dist-ui-lib/index.js.map +1 -1
  110. package/dist-ui-lib/pages/IntegrationsPage.d.ts +1 -0
  111. package/dist-ui-lib/pages/RateLimitPage.d.ts +1 -0
  112. package/package.json +1 -1
  113. package/src/core/control-panel.ts +128 -0
  114. package/src/core/types.ts +17 -0
  115. package/src/index.ts +38 -0
  116. package/src/plugins/auth/adapter-wrapper.test.ts +395 -0
  117. package/src/plugins/auth/adapter-wrapper.ts +205 -0
  118. package/src/plugins/auth/config-store.test.ts +417 -0
  119. package/src/plugins/auth/config-store.ts +305 -0
  120. package/src/plugins/auth/env-config.ts +714 -7
  121. package/src/plugins/auth/index.ts +22 -1
  122. package/src/plugins/auth/types.ts +138 -0
  123. package/src/plugins/index.ts +49 -0
  124. package/src/plugins/rate-limit/__tests__/rate-limit-plugin.test.ts +259 -0
  125. package/src/plugins/rate-limit/cleanup.ts +117 -0
  126. package/src/plugins/rate-limit/env-config.ts +400 -0
  127. package/src/plugins/rate-limit/index.ts +128 -0
  128. package/src/plugins/rate-limit/middleware.ts +212 -0
  129. package/src/plugins/rate-limit/rate-limit-plugin.ts +400 -0
  130. package/src/plugins/rate-limit/rate-limit-service.ts +228 -0
  131. package/src/plugins/rate-limit/stores/cache-store.ts +261 -0
  132. package/src/plugins/rate-limit/stores/index.ts +8 -0
  133. package/src/plugins/rate-limit/stores/postgres-store.ts +402 -0
  134. package/src/plugins/rate-limit/strategies/fixed-window.ts +116 -0
  135. package/src/plugins/rate-limit/strategies/index.ts +30 -0
  136. package/src/plugins/rate-limit/strategies/sliding-window.ts +157 -0
  137. package/src/plugins/rate-limit/strategies/token-bucket.ts +154 -0
  138. package/src/plugins/rate-limit/types.ts +338 -0
  139. package/ui/src/App.tsx +32 -14
  140. package/ui/src/api/controlPanelApi.ts +226 -0
  141. package/ui/src/dashboard/builtInWidgets.tsx +5 -1
  142. package/ui/src/dashboard/widgets/AuthStatusWidget.tsx +143 -0
  143. package/ui/src/dashboard/widgets/IntegrationStatusWidget.tsx +135 -0
  144. package/ui/src/dashboard/widgets/index.ts +2 -0
  145. package/ui/src/pages/AuthPage.tsx +986 -142
  146. package/ui/src/pages/IntegrationsPage.tsx +288 -0
  147. package/ui/src/pages/RateLimitPage.tsx +292 -0
  148. package/dist-ui/assets/index-BY8OxNgO.js +0 -465
  149. package/dist-ui/assets/index-BY8OxNgO.js.map +0 -1
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Rate Limit Middleware
3
+ *
4
+ * Express middleware for automatic rate limiting.
5
+ *
6
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
7
+ */
8
+ import type { RequestHandler } from 'express';
9
+ import type { RateLimitMiddlewareOptions } from './types.js';
10
+ /**
11
+ * Create rate limit middleware
12
+ *
13
+ * @param options Middleware configuration
14
+ * @returns Express middleware function
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * // Basic usage
19
+ * app.use('/api', rateLimitMiddleware());
20
+ *
21
+ * // Custom configuration
22
+ * app.post('/api/chat', rateLimitMiddleware({
23
+ * windowMs: 60000,
24
+ * max: 50,
25
+ * keyGenerator: (req) => `chat:${req.user.id}`,
26
+ * }));
27
+ *
28
+ * // Tiered limits
29
+ * app.use(rateLimitMiddleware({
30
+ * max: (req) => req.user?.tier === 'premium' ? 1000 : 50,
31
+ * }));
32
+ * ```
33
+ */
34
+ export declare function rateLimitMiddleware(options?: RateLimitMiddlewareOptions): RequestHandler;
35
+ /**
36
+ * Create a rate limit middleware that only checks without incrementing
37
+ * Useful for displaying rate limit status without counting the request
38
+ */
39
+ export declare function rateLimitStatusMiddleware(options?: RateLimitMiddlewareOptions): RequestHandler;
40
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/plugins/rate-limit/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAO,KAAK,EAAE,0BAA0B,EAAe,MAAM,YAAY,CAAC;AAwD1E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,cAAc,CAkE5F;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,0BAA+B,GAAG,cAAc,CAkDlG"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Rate Limit Middleware
3
+ *
4
+ * Express middleware for automatic rate limiting.
5
+ *
6
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
7
+ */
8
+ import { getRateLimitService } from './rate-limit-service.js';
9
+ /**
10
+ * Default key generator
11
+ * Uses user ID if authenticated, otherwise IP address
12
+ */
13
+ function defaultKeyGenerator(req) {
14
+ const authReq = req;
15
+ const userId = authReq.auth?.user?.id;
16
+ if (userId) {
17
+ return `user:${userId}`;
18
+ }
19
+ // Fall back to IP address
20
+ const ip = req.ip ||
21
+ req.headers['x-forwarded-for']?.toString().split(',')[0].trim() ||
22
+ req.socket.remoteAddress ||
23
+ 'unknown';
24
+ return `ip:${ip}`;
25
+ }
26
+ /**
27
+ * Default handler when rate limit is exceeded
28
+ */
29
+ function defaultHandler(_req, res, _next, status) {
30
+ res.status(429).json({
31
+ error: 'Too Many Requests',
32
+ message: `Rate limit exceeded. Try again in ${status.retryAfter} seconds.`,
33
+ retryAfter: status.retryAfter,
34
+ });
35
+ }
36
+ /**
37
+ * Set standard rate limit headers on response
38
+ */
39
+ function setRateLimitHeaders(res, status) {
40
+ // Standard rate limit headers (IETF draft)
41
+ res.setHeader('RateLimit-Limit', status.limit.toString());
42
+ res.setHeader('RateLimit-Remaining', status.remaining.toString());
43
+ res.setHeader('RateLimit-Reset', status.resetAt.toString());
44
+ // Retry-After header (RFC 7231)
45
+ if (status.limited) {
46
+ res.setHeader('Retry-After', status.retryAfter.toString());
47
+ }
48
+ }
49
+ /**
50
+ * Create rate limit middleware
51
+ *
52
+ * @param options Middleware configuration
53
+ * @returns Express middleware function
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * // Basic usage
58
+ * app.use('/api', rateLimitMiddleware());
59
+ *
60
+ * // Custom configuration
61
+ * app.post('/api/chat', rateLimitMiddleware({
62
+ * windowMs: 60000,
63
+ * max: 50,
64
+ * keyGenerator: (req) => `chat:${req.user.id}`,
65
+ * }));
66
+ *
67
+ * // Tiered limits
68
+ * app.use(rateLimitMiddleware({
69
+ * max: (req) => req.user?.tier === 'premium' ? 1000 : 50,
70
+ * }));
71
+ * ```
72
+ */
73
+ export function rateLimitMiddleware(options = {}) {
74
+ const { windowMs, max, keyGenerator = defaultKeyGenerator, skip, handler = defaultHandler, strategy, headers = true, keyPrefix = '', } = options;
75
+ return async (req, res, next) => {
76
+ try {
77
+ // Check if should skip
78
+ if (skip) {
79
+ const shouldSkip = await skip(req);
80
+ if (shouldSkip) {
81
+ next();
82
+ return;
83
+ }
84
+ }
85
+ // Generate the rate limit key
86
+ let key = await keyGenerator(req);
87
+ if (keyPrefix) {
88
+ key = `${keyPrefix}:${key}`;
89
+ }
90
+ // Resolve max requests (can be dynamic)
91
+ let maxRequests;
92
+ if (typeof max === 'function') {
93
+ maxRequests = await max(req);
94
+ }
95
+ else {
96
+ maxRequests = max;
97
+ }
98
+ // Get the rate limit service
99
+ const service = getRateLimitService();
100
+ // Check and increment the rate limit
101
+ const status = await service.incrementLimit(key, {
102
+ windowMs,
103
+ maxRequests,
104
+ strategy,
105
+ });
106
+ // Set headers if enabled
107
+ if (headers) {
108
+ setRateLimitHeaders(res, status);
109
+ }
110
+ // If rate limited, call handler
111
+ if (status.limited) {
112
+ handler(req, res, next, status);
113
+ return;
114
+ }
115
+ // Continue to next middleware
116
+ next();
117
+ }
118
+ catch (error) {
119
+ // On error, log and allow request (fail open)
120
+ console.error('[RateLimitMiddleware] Error:', error);
121
+ next();
122
+ }
123
+ };
124
+ }
125
+ /**
126
+ * Create a rate limit middleware that only checks without incrementing
127
+ * Useful for displaying rate limit status without counting the request
128
+ */
129
+ export function rateLimitStatusMiddleware(options = {}) {
130
+ const { windowMs, max, keyGenerator = defaultKeyGenerator, strategy, headers = true, keyPrefix = '', } = options;
131
+ return async (req, res, next) => {
132
+ try {
133
+ // Generate the rate limit key
134
+ let key = await keyGenerator(req);
135
+ if (keyPrefix) {
136
+ key = `${keyPrefix}:${key}`;
137
+ }
138
+ // Resolve max requests (can be dynamic)
139
+ let maxRequests;
140
+ if (typeof max === 'function') {
141
+ maxRequests = await max(req);
142
+ }
143
+ else {
144
+ maxRequests = max;
145
+ }
146
+ // Get the rate limit service
147
+ const service = getRateLimitService();
148
+ // Check without incrementing
149
+ const status = await service.checkLimit(key, {
150
+ windowMs,
151
+ maxRequests,
152
+ strategy,
153
+ increment: false,
154
+ });
155
+ // Set headers if enabled
156
+ if (headers) {
157
+ setRateLimitHeaders(res, status);
158
+ }
159
+ // Always continue (this middleware doesn't block)
160
+ next();
161
+ }
162
+ catch (error) {
163
+ // On error, log and continue
164
+ console.error('[RateLimitStatusMiddleware] Error:', error);
165
+ next();
166
+ }
167
+ };
168
+ }
169
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/plugins/rate-limit/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Rate Limit Plugin
3
+ *
4
+ * Provides rate limiting capabilities for @qwickapps/server.
5
+ * Includes PostgreSQL persistence with RLS, caching, multiple strategies,
6
+ * and Express middleware.
7
+ *
8
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
9
+ */
10
+ import type { Plugin } from '../../core/plugin-registry.js';
11
+ import type { RateLimitPluginConfig } from './types.js';
12
+ /**
13
+ * Create the Rate Limit plugin
14
+ *
15
+ * @param config Plugin configuration
16
+ * @returns Plugin instance
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import {
21
+ * createGateway,
22
+ * createRateLimitPlugin,
23
+ * postgresRateLimitStore,
24
+ * getPostgres,
25
+ * } from '@qwickapps/server';
26
+ *
27
+ * const gateway = createGateway({
28
+ * plugins: [
29
+ * createRateLimitPlugin({
30
+ * store: postgresRateLimitStore({
31
+ * pool: () => getPostgres().getPool(),
32
+ * }),
33
+ * defaults: {
34
+ * windowMs: 60000,
35
+ * maxRequests: 100,
36
+ * strategy: 'sliding-window',
37
+ * },
38
+ * }),
39
+ * ],
40
+ * });
41
+ * ```
42
+ */
43
+ export declare function createRateLimitPlugin(config: RateLimitPluginConfig): Plugin;
44
+ //# sourceMappingURL=rate-limit-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/rate-limit/rate-limit-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAgC,MAAM,+BAA+B,CAAC;AAC1F,OAAO,KAAK,EAAE,qBAAqB,EAAqB,MAAM,YAAY,CAAC;AAiB3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAmV3E"}
@@ -0,0 +1,354 @@
1
+ /**
2
+ * Rate Limit Plugin
3
+ *
4
+ * Provides rate limiting capabilities for @qwickapps/server.
5
+ * Includes PostgreSQL persistence with RLS, caching, multiple strategies,
6
+ * and Express middleware.
7
+ *
8
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
9
+ */
10
+ import { RateLimitService, setRateLimitService } from './rate-limit-service.js';
11
+ import { createRateLimitCache } from './stores/cache-store.js';
12
+ import { createCleanupJob } from './cleanup.js';
13
+ /**
14
+ * Create the Rate Limit plugin
15
+ *
16
+ * @param config Plugin configuration
17
+ * @returns Plugin instance
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import {
22
+ * createGateway,
23
+ * createRateLimitPlugin,
24
+ * postgresRateLimitStore,
25
+ * getPostgres,
26
+ * } from '@qwickapps/server';
27
+ *
28
+ * const gateway = createGateway({
29
+ * plugins: [
30
+ * createRateLimitPlugin({
31
+ * store: postgresRateLimitStore({
32
+ * pool: () => getPostgres().getPool(),
33
+ * }),
34
+ * defaults: {
35
+ * windowMs: 60000,
36
+ * maxRequests: 100,
37
+ * strategy: 'sliding-window',
38
+ * },
39
+ * }),
40
+ * ],
41
+ * });
42
+ * ```
43
+ */
44
+ export function createRateLimitPlugin(config) {
45
+ const debug = config.debug || false;
46
+ const apiPrefix = config.api?.prefix || '/rate-limit';
47
+ const apiEnabled = config.api?.enabled !== false;
48
+ const uiEnabled = config.ui?.enabled !== false;
49
+ const initialCleanupEnabled = config.cleanup?.enabled !== false;
50
+ const initialCleanupIntervalMs = config.cleanup?.intervalMs || 300000;
51
+ let service = null;
52
+ let cleanupJob = null;
53
+ let cache;
54
+ // Runtime config state (can be modified via API)
55
+ const runtimeConfig = {
56
+ windowMs: config.defaults?.windowMs || 60000,
57
+ maxRequests: config.defaults?.maxRequests || 100,
58
+ strategy: config.defaults?.strategy || 'sliding-window',
59
+ cleanupEnabled: initialCleanupEnabled,
60
+ cleanupIntervalMs: initialCleanupIntervalMs,
61
+ };
62
+ function log(message, data) {
63
+ if (debug) {
64
+ console.log(`[RateLimitPlugin] ${message}`, data || '');
65
+ }
66
+ }
67
+ return {
68
+ id: 'rate-limit',
69
+ name: 'Rate Limit',
70
+ version: '1.0.0',
71
+ async onStart(_pluginConfig, registry) {
72
+ log('Starting rate limit plugin');
73
+ // Initialize the store
74
+ await config.store.initialize();
75
+ log('Store initialized');
76
+ // Create cache
77
+ cache = createRateLimitCache(config.cache);
78
+ log('Cache created', { type: cache.name });
79
+ // Create service
80
+ service = new RateLimitService({
81
+ store: config.store,
82
+ cache,
83
+ defaults: config.defaults,
84
+ });
85
+ setRateLimitService(service);
86
+ log('Service created');
87
+ // Start cleanup job if enabled
88
+ if (runtimeConfig.cleanupEnabled) {
89
+ cleanupJob = createCleanupJob({
90
+ store: config.store,
91
+ intervalMs: runtimeConfig.cleanupIntervalMs,
92
+ debug,
93
+ });
94
+ cleanupJob.start();
95
+ log('Cleanup job started', { intervalMs: runtimeConfig.cleanupIntervalMs });
96
+ }
97
+ // Register health check
98
+ registry.registerHealthCheck({
99
+ name: 'rate-limit',
100
+ type: 'custom',
101
+ check: async () => {
102
+ try {
103
+ const defaults = service?.getDefaults();
104
+ return {
105
+ healthy: service !== null,
106
+ details: {
107
+ store: config.store.name,
108
+ cache: cache.name,
109
+ cacheAvailable: cache.isAvailable(),
110
+ defaults,
111
+ cleanupEnabled: runtimeConfig.cleanupEnabled,
112
+ },
113
+ };
114
+ }
115
+ catch {
116
+ return { healthy: false };
117
+ }
118
+ },
119
+ });
120
+ // Register UI menu item if enabled
121
+ if (uiEnabled) {
122
+ registry.addMenuItem({
123
+ pluginId: 'rate-limit',
124
+ id: 'rate-limit:sidebar',
125
+ label: 'Rate Limits',
126
+ icon: 'speed',
127
+ route: '/rate-limits',
128
+ order: 40, // After Entitlements (35)
129
+ });
130
+ }
131
+ // Add API routes if enabled
132
+ if (apiEnabled) {
133
+ // GET /rate-limit/config - Get current config
134
+ registry.addRoute({
135
+ method: 'get',
136
+ path: '/rate-limit/config',
137
+ pluginId: 'rate-limit',
138
+ handler: async (_req, res) => {
139
+ try {
140
+ const defaults = service?.getDefaults();
141
+ res.json({
142
+ ...runtimeConfig,
143
+ ...defaults,
144
+ store: config.store.name,
145
+ cache: cache.name,
146
+ cacheAvailable: cache.isAvailable(),
147
+ });
148
+ }
149
+ catch (error) {
150
+ console.error('[RateLimitPlugin] Config error:', error);
151
+ res.status(500).json({ error: 'Failed to get config' });
152
+ }
153
+ },
154
+ });
155
+ // PUT /rate-limit/config - Update config at runtime
156
+ registry.addRoute({
157
+ method: 'put',
158
+ path: '/rate-limit/config',
159
+ pluginId: 'rate-limit',
160
+ handler: async (req, res) => {
161
+ try {
162
+ const updates = req.body;
163
+ const validStrategies = ['sliding-window', 'fixed-window', 'token-bucket'];
164
+ // Validate and apply updates
165
+ if (updates.windowMs !== undefined) {
166
+ if (typeof updates.windowMs !== 'number' || updates.windowMs <= 0) {
167
+ return res.status(400).json({ error: 'windowMs must be a positive number' });
168
+ }
169
+ runtimeConfig.windowMs = updates.windowMs;
170
+ }
171
+ if (updates.maxRequests !== undefined) {
172
+ if (typeof updates.maxRequests !== 'number' || updates.maxRequests <= 0) {
173
+ return res.status(400).json({ error: 'maxRequests must be a positive number' });
174
+ }
175
+ runtimeConfig.maxRequests = updates.maxRequests;
176
+ }
177
+ if (updates.strategy !== undefined) {
178
+ if (!validStrategies.includes(updates.strategy)) {
179
+ return res.status(400).json({
180
+ error: `Invalid strategy. Must be one of: ${validStrategies.join(', ')}`,
181
+ });
182
+ }
183
+ runtimeConfig.strategy = updates.strategy;
184
+ }
185
+ // Update service defaults
186
+ if (service) {
187
+ service.setDefaults({
188
+ windowMs: runtimeConfig.windowMs,
189
+ maxRequests: runtimeConfig.maxRequests,
190
+ strategy: runtimeConfig.strategy,
191
+ });
192
+ }
193
+ // Handle cleanup config changes
194
+ if (updates.cleanupEnabled !== undefined) {
195
+ runtimeConfig.cleanupEnabled = updates.cleanupEnabled;
196
+ if (updates.cleanupEnabled && !cleanupJob) {
197
+ // Start cleanup job
198
+ cleanupJob = createCleanupJob({
199
+ store: config.store,
200
+ intervalMs: runtimeConfig.cleanupIntervalMs,
201
+ debug,
202
+ });
203
+ cleanupJob.start();
204
+ }
205
+ else if (!updates.cleanupEnabled && cleanupJob) {
206
+ // Stop cleanup job
207
+ cleanupJob.stop();
208
+ cleanupJob = null;
209
+ }
210
+ }
211
+ if (updates.cleanupIntervalMs !== undefined) {
212
+ if (typeof updates.cleanupIntervalMs !== 'number' || updates.cleanupIntervalMs <= 0) {
213
+ return res.status(400).json({ error: 'cleanupIntervalMs must be a positive number' });
214
+ }
215
+ runtimeConfig.cleanupIntervalMs = updates.cleanupIntervalMs;
216
+ // Restart cleanup job with new interval if running
217
+ if (cleanupJob && runtimeConfig.cleanupEnabled) {
218
+ cleanupJob.stop();
219
+ cleanupJob = createCleanupJob({
220
+ store: config.store,
221
+ intervalMs: runtimeConfig.cleanupIntervalMs,
222
+ debug,
223
+ });
224
+ cleanupJob.start();
225
+ }
226
+ }
227
+ log('Config updated', { ...runtimeConfig });
228
+ res.json({
229
+ success: true,
230
+ config: {
231
+ ...runtimeConfig,
232
+ store: config.store.name,
233
+ cache: cache.name,
234
+ cacheAvailable: cache.isAvailable(),
235
+ },
236
+ });
237
+ }
238
+ catch (error) {
239
+ console.error('[RateLimitPlugin] Config update error:', error);
240
+ res.status(500).json({ error: 'Failed to update config' });
241
+ }
242
+ },
243
+ });
244
+ // GET /rate-limit/status - Get rate limit status for current user
245
+ registry.addRoute({
246
+ method: 'get',
247
+ path: `${apiPrefix}/status`,
248
+ pluginId: 'rate-limit',
249
+ handler: async (req, res) => {
250
+ try {
251
+ const authReq = req;
252
+ const userId = authReq.auth?.user?.id;
253
+ // Generate key (same logic as middleware)
254
+ let key;
255
+ if (userId) {
256
+ key = `user:${userId}`;
257
+ }
258
+ else {
259
+ const ip = req.ip ||
260
+ req.headers['x-forwarded-for']?.toString().split(',')[0].trim() ||
261
+ req.socket.remoteAddress ||
262
+ 'unknown';
263
+ key = `ip:${ip}`;
264
+ }
265
+ // Get status without incrementing
266
+ const status = await service.checkLimit(key, {
267
+ userId,
268
+ increment: false,
269
+ });
270
+ res.json({
271
+ key,
272
+ ...status,
273
+ });
274
+ }
275
+ catch (error) {
276
+ console.error('[RateLimitPlugin] Status error:', error);
277
+ res.status(500).json({ error: 'Failed to get rate limit status' });
278
+ }
279
+ },
280
+ });
281
+ // GET /rate-limit/status/:key - Get rate limit status for a specific key
282
+ registry.addRoute({
283
+ method: 'get',
284
+ path: `${apiPrefix}/status/:key`,
285
+ pluginId: 'rate-limit',
286
+ handler: async (req, res) => {
287
+ try {
288
+ const authReq = req;
289
+ const userId = authReq.auth?.user?.id;
290
+ const key = req.params.key;
291
+ if (!key) {
292
+ return res.status(400).json({ error: 'Key is required' });
293
+ }
294
+ // Get status without incrementing
295
+ const status = await service.checkLimit(key, {
296
+ userId,
297
+ increment: false,
298
+ });
299
+ res.json({
300
+ key,
301
+ ...status,
302
+ });
303
+ }
304
+ catch (error) {
305
+ console.error('[RateLimitPlugin] Status error:', error);
306
+ res.status(500).json({ error: 'Failed to get rate limit status' });
307
+ }
308
+ },
309
+ });
310
+ // DELETE /rate-limit/clear/:key - Clear a rate limit (requires auth)
311
+ registry.addRoute({
312
+ method: 'delete',
313
+ path: `${apiPrefix}/clear/:key`,
314
+ pluginId: 'rate-limit',
315
+ handler: async (req, res) => {
316
+ try {
317
+ const authReq = req;
318
+ const userId = authReq.auth?.user?.id;
319
+ if (!userId) {
320
+ return res.status(401).json({ error: 'Authentication required' });
321
+ }
322
+ const key = req.params.key;
323
+ if (!key) {
324
+ return res.status(400).json({ error: 'Key is required' });
325
+ }
326
+ await service.clearLimit(key, userId);
327
+ res.status(204).send();
328
+ }
329
+ catch (error) {
330
+ console.error('[RateLimitPlugin] Clear error:', error);
331
+ res.status(500).json({ error: 'Failed to clear rate limit' });
332
+ }
333
+ },
334
+ });
335
+ }
336
+ log('Rate limit plugin started');
337
+ },
338
+ async onStop() {
339
+ log('Stopping rate limit plugin');
340
+ // Stop cleanup job
341
+ if (cleanupJob) {
342
+ cleanupJob.stop();
343
+ cleanupJob = null;
344
+ }
345
+ // Clear service reference
346
+ setRateLimitService(null);
347
+ service = null;
348
+ // Shutdown store
349
+ await config.store.shutdown();
350
+ log('Rate limit plugin stopped');
351
+ },
352
+ };
353
+ }
354
+ //# sourceMappingURL=rate-limit-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-plugin.js","sourceRoot":"","sources":["../../../src/plugins/rate-limit/rate-limit-plugin.ts"],"names":[],"mappings":"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"}