@qwickapps/server 1.3.1 → 1.5.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 (395) 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 +15 -3
  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/bans/bans-plugin.d.ts.map +1 -1
  38. package/dist/plugins/bans/bans-plugin.js +12 -3
  39. package/dist/plugins/bans/bans-plugin.js.map +1 -1
  40. package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts +11 -0
  41. package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts.map +1 -0
  42. package/dist/plugins/devices/__tests__/devices-plugin.test.js +410 -0
  43. package/dist/plugins/devices/__tests__/devices-plugin.test.js.map +1 -0
  44. package/dist/plugins/devices/__tests__/token-utils.test.d.ts +7 -0
  45. package/dist/plugins/devices/__tests__/token-utils.test.d.ts.map +1 -0
  46. package/dist/plugins/devices/__tests__/token-utils.test.js +197 -0
  47. package/dist/plugins/devices/__tests__/token-utils.test.js.map +1 -0
  48. package/dist/plugins/devices/adapters/compute-adapter.d.ts +36 -0
  49. package/dist/plugins/devices/adapters/compute-adapter.d.ts.map +1 -0
  50. package/dist/plugins/devices/adapters/compute-adapter.js +100 -0
  51. package/dist/plugins/devices/adapters/compute-adapter.js.map +1 -0
  52. package/dist/plugins/devices/adapters/index.d.ts +12 -0
  53. package/dist/plugins/devices/adapters/index.d.ts.map +1 -0
  54. package/dist/plugins/devices/adapters/index.js +10 -0
  55. package/dist/plugins/devices/adapters/index.js.map +1 -0
  56. package/dist/plugins/devices/adapters/mobile-adapter.d.ts +41 -0
  57. package/dist/plugins/devices/adapters/mobile-adapter.d.ts.map +1 -0
  58. package/dist/plugins/devices/adapters/mobile-adapter.js +131 -0
  59. package/dist/plugins/devices/adapters/mobile-adapter.js.map +1 -0
  60. package/dist/plugins/devices/devices-plugin.d.ts +70 -0
  61. package/dist/plugins/devices/devices-plugin.d.ts.map +1 -0
  62. package/dist/plugins/devices/devices-plugin.js +453 -0
  63. package/dist/plugins/devices/devices-plugin.js.map +1 -0
  64. package/dist/plugins/devices/index.d.ts +18 -0
  65. package/dist/plugins/devices/index.d.ts.map +1 -0
  66. package/dist/plugins/devices/index.js +18 -0
  67. package/dist/plugins/devices/index.js.map +1 -0
  68. package/dist/plugins/devices/stores/index.d.ts +9 -0
  69. package/dist/plugins/devices/stores/index.d.ts.map +1 -0
  70. package/dist/plugins/devices/stores/index.js +9 -0
  71. package/dist/plugins/devices/stores/index.js.map +1 -0
  72. package/dist/plugins/devices/stores/postgres-store.d.ts +26 -0
  73. package/dist/plugins/devices/stores/postgres-store.d.ts.map +1 -0
  74. package/dist/plugins/devices/stores/postgres-store.js +199 -0
  75. package/dist/plugins/devices/stores/postgres-store.js.map +1 -0
  76. package/dist/plugins/devices/token-utils.d.ts +100 -0
  77. package/dist/plugins/devices/token-utils.d.ts.map +1 -0
  78. package/dist/plugins/devices/token-utils.js +162 -0
  79. package/dist/plugins/devices/token-utils.js.map +1 -0
  80. package/dist/plugins/devices/types.d.ts +307 -0
  81. package/dist/plugins/devices/types.d.ts.map +1 -0
  82. package/dist/plugins/devices/types.js +10 -0
  83. package/dist/plugins/devices/types.js.map +1 -0
  84. package/dist/plugins/index.d.ts +18 -4
  85. package/dist/plugins/index.d.ts.map +1 -1
  86. package/dist/plugins/index.js +16 -2
  87. package/dist/plugins/index.js.map +1 -1
  88. package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts +5 -0
  89. package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts.map +1 -0
  90. package/dist/plugins/notifications/__tests__/notifications-manager.test.js +470 -0
  91. package/dist/plugins/notifications/__tests__/notifications-manager.test.js.map +1 -0
  92. package/dist/plugins/notifications/index.d.ts +71 -0
  93. package/dist/plugins/notifications/index.d.ts.map +1 -0
  94. package/dist/plugins/notifications/index.js +72 -0
  95. package/dist/plugins/notifications/index.js.map +1 -0
  96. package/dist/plugins/notifications/notifications-manager.d.ts +182 -0
  97. package/dist/plugins/notifications/notifications-manager.d.ts.map +1 -0
  98. package/dist/plugins/notifications/notifications-manager.js +610 -0
  99. package/dist/plugins/notifications/notifications-manager.js.map +1 -0
  100. package/dist/plugins/notifications/notifications-plugin.d.ts +83 -0
  101. package/dist/plugins/notifications/notifications-plugin.d.ts.map +1 -0
  102. package/dist/plugins/notifications/notifications-plugin.js +337 -0
  103. package/dist/plugins/notifications/notifications-plugin.js.map +1 -0
  104. package/dist/plugins/notifications/types.d.ts +164 -0
  105. package/dist/plugins/notifications/types.d.ts.map +1 -0
  106. package/dist/plugins/notifications/types.js +9 -0
  107. package/dist/plugins/notifications/types.js.map +1 -0
  108. package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts +12 -0
  109. package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts.map +1 -0
  110. package/dist/plugins/parental/__tests__/parental-plugin.test.js +349 -0
  111. package/dist/plugins/parental/__tests__/parental-plugin.test.js.map +1 -0
  112. package/dist/plugins/parental/adapters/index.d.ts +8 -0
  113. package/dist/plugins/parental/adapters/index.d.ts.map +1 -0
  114. package/dist/plugins/parental/adapters/index.js +7 -0
  115. package/dist/plugins/parental/adapters/index.js.map +1 -0
  116. package/dist/plugins/parental/adapters/kids-adapter.d.ts +24 -0
  117. package/dist/plugins/parental/adapters/kids-adapter.d.ts.map +1 -0
  118. package/dist/plugins/parental/adapters/kids-adapter.js +174 -0
  119. package/dist/plugins/parental/adapters/kids-adapter.js.map +1 -0
  120. package/dist/plugins/parental/index.d.ts +14 -0
  121. package/dist/plugins/parental/index.d.ts.map +1 -0
  122. package/dist/plugins/parental/index.js +15 -0
  123. package/dist/plugins/parental/index.js.map +1 -0
  124. package/dist/plugins/parental/parental-plugin.d.ts +88 -0
  125. package/dist/plugins/parental/parental-plugin.d.ts.map +1 -0
  126. package/dist/plugins/parental/parental-plugin.js +666 -0
  127. package/dist/plugins/parental/parental-plugin.js.map +1 -0
  128. package/dist/plugins/parental/stores/index.d.ts +7 -0
  129. package/dist/plugins/parental/stores/index.d.ts.map +1 -0
  130. package/dist/plugins/parental/stores/index.js +7 -0
  131. package/dist/plugins/parental/stores/index.js.map +1 -0
  132. package/dist/plugins/parental/stores/postgres-store.d.ts +10 -0
  133. package/dist/plugins/parental/stores/postgres-store.d.ts.map +1 -0
  134. package/dist/plugins/parental/stores/postgres-store.js +209 -0
  135. package/dist/plugins/parental/stores/postgres-store.js.map +1 -0
  136. package/dist/plugins/parental/types.d.ts +154 -0
  137. package/dist/plugins/parental/types.d.ts.map +1 -0
  138. package/dist/plugins/parental/types.js +10 -0
  139. package/dist/plugins/parental/types.js.map +1 -0
  140. package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts +11 -0
  141. package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts.map +1 -0
  142. package/dist/plugins/profiles/__tests__/profiles-plugin.test.js +243 -0
  143. package/dist/plugins/profiles/__tests__/profiles-plugin.test.js.map +1 -0
  144. package/dist/plugins/profiles/index.d.ts +12 -0
  145. package/dist/plugins/profiles/index.d.ts.map +1 -0
  146. package/dist/plugins/profiles/index.js +13 -0
  147. package/dist/plugins/profiles/index.js.map +1 -0
  148. package/dist/plugins/profiles/profiles-plugin.d.ts +71 -0
  149. package/dist/plugins/profiles/profiles-plugin.d.ts.map +1 -0
  150. package/dist/plugins/profiles/profiles-plugin.js +481 -0
  151. package/dist/plugins/profiles/profiles-plugin.js.map +1 -0
  152. package/dist/plugins/profiles/stores/index.d.ts +9 -0
  153. package/dist/plugins/profiles/stores/index.d.ts.map +1 -0
  154. package/dist/plugins/profiles/stores/index.js +9 -0
  155. package/dist/plugins/profiles/stores/index.js.map +1 -0
  156. package/dist/plugins/profiles/stores/postgres-store.d.ts +18 -0
  157. package/dist/plugins/profiles/stores/postgres-store.d.ts.map +1 -0
  158. package/dist/plugins/profiles/stores/postgres-store.js +310 -0
  159. package/dist/plugins/profiles/stores/postgres-store.js.map +1 -0
  160. package/dist/plugins/profiles/types.d.ts +289 -0
  161. package/dist/plugins/profiles/types.d.ts.map +1 -0
  162. package/dist/plugins/profiles/types.js +10 -0
  163. package/dist/plugins/profiles/types.js.map +1 -0
  164. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts +7 -0
  165. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.d.ts.map +1 -0
  166. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js +220 -0
  167. package/dist/plugins/rate-limit/__tests__/rate-limit-plugin.test.js.map +1 -0
  168. package/dist/plugins/rate-limit/cleanup.d.ts +40 -0
  169. package/dist/plugins/rate-limit/cleanup.d.ts.map +1 -0
  170. package/dist/plugins/rate-limit/cleanup.js +72 -0
  171. package/dist/plugins/rate-limit/cleanup.js.map +1 -0
  172. package/dist/plugins/rate-limit/env-config.d.ts +91 -0
  173. package/dist/plugins/rate-limit/env-config.d.ts.map +1 -0
  174. package/dist/plugins/rate-limit/env-config.js +318 -0
  175. package/dist/plugins/rate-limit/env-config.js.map +1 -0
  176. package/dist/plugins/rate-limit/index.d.ts +76 -0
  177. package/dist/plugins/rate-limit/index.d.ts.map +1 -0
  178. package/dist/plugins/rate-limit/index.js +79 -0
  179. package/dist/plugins/rate-limit/index.js.map +1 -0
  180. package/dist/plugins/rate-limit/middleware.d.ts +40 -0
  181. package/dist/plugins/rate-limit/middleware.d.ts.map +1 -0
  182. package/dist/plugins/rate-limit/middleware.js +169 -0
  183. package/dist/plugins/rate-limit/middleware.js.map +1 -0
  184. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts +44 -0
  185. package/dist/plugins/rate-limit/rate-limit-plugin.d.ts.map +1 -0
  186. package/dist/plugins/rate-limit/rate-limit-plugin.js +354 -0
  187. package/dist/plugins/rate-limit/rate-limit-plugin.js.map +1 -0
  188. package/dist/plugins/rate-limit/rate-limit-service.d.ts +110 -0
  189. package/dist/plugins/rate-limit/rate-limit-service.d.ts.map +1 -0
  190. package/dist/plugins/rate-limit/rate-limit-service.js +172 -0
  191. package/dist/plugins/rate-limit/rate-limit-service.js.map +1 -0
  192. package/dist/plugins/rate-limit/stores/cache-store.d.ts +33 -0
  193. package/dist/plugins/rate-limit/stores/cache-store.d.ts.map +1 -0
  194. package/dist/plugins/rate-limit/stores/cache-store.js +225 -0
  195. package/dist/plugins/rate-limit/stores/cache-store.js.map +1 -0
  196. package/dist/plugins/rate-limit/stores/index.d.ts +8 -0
  197. package/dist/plugins/rate-limit/stores/index.d.ts.map +1 -0
  198. package/dist/plugins/rate-limit/stores/index.js +8 -0
  199. package/dist/plugins/rate-limit/stores/index.js.map +1 -0
  200. package/dist/plugins/rate-limit/stores/postgres-store.d.ts +34 -0
  201. package/dist/plugins/rate-limit/stores/postgres-store.d.ts.map +1 -0
  202. package/dist/plugins/rate-limit/stores/postgres-store.js +320 -0
  203. package/dist/plugins/rate-limit/stores/postgres-store.js.map +1 -0
  204. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts +21 -0
  205. package/dist/plugins/rate-limit/strategies/fixed-window.d.ts.map +1 -0
  206. package/dist/plugins/rate-limit/strategies/fixed-window.js +97 -0
  207. package/dist/plugins/rate-limit/strategies/fixed-window.js.map +1 -0
  208. package/dist/plugins/rate-limit/strategies/index.d.ts +14 -0
  209. package/dist/plugins/rate-limit/strategies/index.d.ts.map +1 -0
  210. package/dist/plugins/rate-limit/strategies/index.js +27 -0
  211. package/dist/plugins/rate-limit/strategies/index.js.map +1 -0
  212. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts +22 -0
  213. package/dist/plugins/rate-limit/strategies/sliding-window.d.ts.map +1 -0
  214. package/dist/plugins/rate-limit/strategies/sliding-window.js +122 -0
  215. package/dist/plugins/rate-limit/strategies/sliding-window.js.map +1 -0
  216. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts +28 -0
  217. package/dist/plugins/rate-limit/strategies/token-bucket.d.ts.map +1 -0
  218. package/dist/plugins/rate-limit/strategies/token-bucket.js +121 -0
  219. package/dist/plugins/rate-limit/strategies/token-bucket.js.map +1 -0
  220. package/dist/plugins/rate-limit/types.d.ts +265 -0
  221. package/dist/plugins/rate-limit/types.d.ts.map +1 -0
  222. package/dist/plugins/rate-limit/types.js +9 -0
  223. package/dist/plugins/rate-limit/types.js.map +1 -0
  224. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts +11 -0
  225. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts.map +1 -0
  226. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js +305 -0
  227. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js.map +1 -0
  228. package/dist/plugins/subscriptions/index.d.ts +12 -0
  229. package/dist/plugins/subscriptions/index.d.ts.map +1 -0
  230. package/dist/plugins/subscriptions/index.js +13 -0
  231. package/dist/plugins/subscriptions/index.js.map +1 -0
  232. package/dist/plugins/subscriptions/stores/index.d.ts +9 -0
  233. package/dist/plugins/subscriptions/stores/index.d.ts.map +1 -0
  234. package/dist/plugins/subscriptions/stores/index.js +9 -0
  235. package/dist/plugins/subscriptions/stores/index.js.map +1 -0
  236. package/dist/plugins/subscriptions/stores/postgres-store.d.ts +14 -0
  237. package/dist/plugins/subscriptions/stores/postgres-store.d.ts.map +1 -0
  238. package/dist/plugins/subscriptions/stores/postgres-store.js +359 -0
  239. package/dist/plugins/subscriptions/stores/postgres-store.js.map +1 -0
  240. package/dist/plugins/subscriptions/subscriptions-plugin.d.ts +82 -0
  241. package/dist/plugins/subscriptions/subscriptions-plugin.d.ts.map +1 -0
  242. package/dist/plugins/subscriptions/subscriptions-plugin.js +449 -0
  243. package/dist/plugins/subscriptions/subscriptions-plugin.js.map +1 -0
  244. package/dist/plugins/subscriptions/types.d.ts +308 -0
  245. package/dist/plugins/subscriptions/types.d.ts.map +1 -0
  246. package/dist/plugins/subscriptions/types.js +10 -0
  247. package/dist/plugins/subscriptions/types.js.map +1 -0
  248. package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts +11 -0
  249. package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts.map +1 -0
  250. package/dist/plugins/usage/__tests__/usage-plugin.test.js +218 -0
  251. package/dist/plugins/usage/__tests__/usage-plugin.test.js.map +1 -0
  252. package/dist/plugins/usage/index.d.ts +12 -0
  253. package/dist/plugins/usage/index.d.ts.map +1 -0
  254. package/dist/plugins/usage/index.js +13 -0
  255. package/dist/plugins/usage/index.js.map +1 -0
  256. package/dist/plugins/usage/stores/index.d.ts +9 -0
  257. package/dist/plugins/usage/stores/index.d.ts.map +1 -0
  258. package/dist/plugins/usage/stores/index.js +9 -0
  259. package/dist/plugins/usage/stores/index.js.map +1 -0
  260. package/dist/plugins/usage/stores/postgres-store.d.ts +14 -0
  261. package/dist/plugins/usage/stores/postgres-store.d.ts.map +1 -0
  262. package/dist/plugins/usage/stores/postgres-store.js +146 -0
  263. package/dist/plugins/usage/stores/postgres-store.js.map +1 -0
  264. package/dist/plugins/usage/types.d.ts +195 -0
  265. package/dist/plugins/usage/types.d.ts.map +1 -0
  266. package/dist/plugins/usage/types.js +10 -0
  267. package/dist/plugins/usage/types.js.map +1 -0
  268. package/dist/plugins/usage/usage-plugin.d.ts +51 -0
  269. package/dist/plugins/usage/usage-plugin.d.ts.map +1 -0
  270. package/dist/plugins/usage/usage-plugin.js +412 -0
  271. package/dist/plugins/usage/usage-plugin.js.map +1 -0
  272. package/dist/plugins/users/__tests__/postgres-store.test.d.ts +10 -0
  273. package/dist/plugins/users/__tests__/postgres-store.test.d.ts.map +1 -0
  274. package/dist/plugins/users/__tests__/postgres-store.test.js +229 -0
  275. package/dist/plugins/users/__tests__/postgres-store.test.js.map +1 -0
  276. package/dist/plugins/users/__tests__/users-plugin.test.js +3 -0
  277. package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -1
  278. package/dist/plugins/users/index.d.ts +2 -2
  279. package/dist/plugins/users/index.d.ts.map +1 -1
  280. package/dist/plugins/users/index.js +1 -1
  281. package/dist/plugins/users/index.js.map +1 -1
  282. package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -1
  283. package/dist/plugins/users/stores/postgres-store.js +76 -0
  284. package/dist/plugins/users/stores/postgres-store.js.map +1 -1
  285. package/dist/plugins/users/types.d.ts +74 -6
  286. package/dist/plugins/users/types.d.ts.map +1 -1
  287. package/dist/plugins/users/users-plugin.d.ts +15 -1
  288. package/dist/plugins/users/users-plugin.d.ts.map +1 -1
  289. package/dist/plugins/users/users-plugin.js +29 -0
  290. package/dist/plugins/users/users-plugin.js.map +1 -1
  291. package/dist-ui/assets/index-CynOqPkb.js +469 -0
  292. package/dist-ui/assets/{index-BY8OxNgO.js.map → index-CynOqPkb.js.map} +1 -1
  293. package/dist-ui/index.html +1 -1
  294. package/dist-ui-lib/api/controlPanelApi.d.ts +187 -0
  295. package/dist-ui-lib/components/StatCard.d.ts +16 -0
  296. package/dist-ui-lib/dashboard/widgets/AuthStatusWidget.d.ts +9 -0
  297. package/dist-ui-lib/dashboard/widgets/IntegrationStatusWidget.d.ts +9 -0
  298. package/dist-ui-lib/dashboard/widgets/NotificationsStatsWidget.d.ts +12 -0
  299. package/dist-ui-lib/dashboard/widgets/index.d.ts +3 -0
  300. package/dist-ui-lib/index.js +3579 -2379
  301. package/dist-ui-lib/index.js.map +1 -1
  302. package/dist-ui-lib/pages/IntegrationsPage.d.ts +1 -0
  303. package/dist-ui-lib/pages/NotificationsPage.d.ts +9 -0
  304. package/dist-ui-lib/pages/RateLimitPage.d.ts +1 -0
  305. package/dist-ui-lib/utils/formatters.d.ts +19 -0
  306. package/package.json +1 -1
  307. package/src/core/control-panel.ts +128 -0
  308. package/src/core/types.ts +17 -0
  309. package/src/index.ts +216 -0
  310. package/src/plugins/auth/adapter-wrapper.test.ts +395 -0
  311. package/src/plugins/auth/adapter-wrapper.ts +205 -0
  312. package/src/plugins/auth/config-store.test.ts +417 -0
  313. package/src/plugins/auth/config-store.ts +305 -0
  314. package/src/plugins/auth/env-config.ts +714 -7
  315. package/src/plugins/auth/index.ts +22 -1
  316. package/src/plugins/auth/types.ts +138 -0
  317. package/src/plugins/bans/bans-plugin.ts +15 -3
  318. package/src/plugins/devices/__tests__/devices-plugin.test.ts +551 -0
  319. package/src/plugins/devices/__tests__/token-utils.test.ts +264 -0
  320. package/src/plugins/devices/adapters/compute-adapter.ts +139 -0
  321. package/src/plugins/devices/adapters/index.ts +13 -0
  322. package/src/plugins/devices/adapters/mobile-adapter.ts +179 -0
  323. package/src/plugins/devices/devices-plugin.ts +538 -0
  324. package/src/plugins/devices/index.ts +69 -0
  325. package/src/plugins/devices/stores/index.ts +9 -0
  326. package/src/plugins/devices/stores/postgres-store.ts +304 -0
  327. package/src/plugins/devices/token-utils.ts +213 -0
  328. package/src/plugins/devices/types.ts +351 -0
  329. package/src/plugins/index.ts +267 -0
  330. package/src/plugins/notifications/__tests__/notifications-manager.test.ts +637 -0
  331. package/src/plugins/notifications/index.ts +91 -0
  332. package/src/plugins/notifications/notifications-manager.ts +773 -0
  333. package/src/plugins/notifications/notifications-plugin.ts +398 -0
  334. package/src/plugins/notifications/types.ts +207 -0
  335. package/src/plugins/parental/__tests__/parental-plugin.test.ts +465 -0
  336. package/src/plugins/parental/adapters/index.ts +8 -0
  337. package/src/plugins/parental/adapters/kids-adapter.ts +206 -0
  338. package/src/plugins/parental/index.ts +55 -0
  339. package/src/plugins/parental/parental-plugin.ts +759 -0
  340. package/src/plugins/parental/stores/index.ts +7 -0
  341. package/src/plugins/parental/stores/postgres-store.ts +304 -0
  342. package/src/plugins/parental/types.ts +180 -0
  343. package/src/plugins/profiles/__tests__/profiles-plugin.test.ts +321 -0
  344. package/src/plugins/profiles/index.ts +49 -0
  345. package/src/plugins/profiles/profiles-plugin.ts +546 -0
  346. package/src/plugins/profiles/stores/index.ts +9 -0
  347. package/src/plugins/profiles/stores/postgres-store.ts +439 -0
  348. package/src/plugins/profiles/types.ts +338 -0
  349. package/src/plugins/rate-limit/__tests__/rate-limit-plugin.test.ts +259 -0
  350. package/src/plugins/rate-limit/cleanup.ts +117 -0
  351. package/src/plugins/rate-limit/env-config.ts +400 -0
  352. package/src/plugins/rate-limit/index.ts +128 -0
  353. package/src/plugins/rate-limit/middleware.ts +212 -0
  354. package/src/plugins/rate-limit/rate-limit-plugin.ts +400 -0
  355. package/src/plugins/rate-limit/rate-limit-service.ts +228 -0
  356. package/src/plugins/rate-limit/stores/cache-store.ts +261 -0
  357. package/src/plugins/rate-limit/stores/index.ts +8 -0
  358. package/src/plugins/rate-limit/stores/postgres-store.ts +402 -0
  359. package/src/plugins/rate-limit/strategies/fixed-window.ts +116 -0
  360. package/src/plugins/rate-limit/strategies/index.ts +30 -0
  361. package/src/plugins/rate-limit/strategies/sliding-window.ts +157 -0
  362. package/src/plugins/rate-limit/strategies/token-bucket.ts +154 -0
  363. package/src/plugins/rate-limit/types.ts +338 -0
  364. package/src/plugins/subscriptions/__tests__/subscriptions-plugin.test.ts +404 -0
  365. package/src/plugins/subscriptions/index.ts +51 -0
  366. package/src/plugins/subscriptions/stores/index.ts +9 -0
  367. package/src/plugins/subscriptions/stores/postgres-store.ts +482 -0
  368. package/src/plugins/subscriptions/subscriptions-plugin.ts +530 -0
  369. package/src/plugins/subscriptions/types.ts +355 -0
  370. package/src/plugins/usage/__tests__/usage-plugin.test.ts +288 -0
  371. package/src/plugins/usage/index.ts +39 -0
  372. package/src/plugins/usage/stores/index.ts +9 -0
  373. package/src/plugins/usage/stores/postgres-store.ts +213 -0
  374. package/src/plugins/usage/types.ts +222 -0
  375. package/src/plugins/usage/usage-plugin.ts +484 -0
  376. package/src/plugins/users/__tests__/postgres-store.test.ts +326 -0
  377. package/src/plugins/users/__tests__/users-plugin.test.ts +3 -0
  378. package/src/plugins/users/index.ts +6 -0
  379. package/src/plugins/users/stores/postgres-store.ts +104 -0
  380. package/src/plugins/users/types.ts +82 -6
  381. package/src/plugins/users/users-plugin.ts +37 -0
  382. package/ui/src/App.tsx +36 -14
  383. package/ui/src/api/controlPanelApi.ts +329 -6
  384. package/ui/src/components/StatCard.tsx +58 -0
  385. package/ui/src/dashboard/builtInWidgets.tsx +7 -1
  386. package/ui/src/dashboard/widgets/AuthStatusWidget.tsx +143 -0
  387. package/ui/src/dashboard/widgets/IntegrationStatusWidget.tsx +135 -0
  388. package/ui/src/dashboard/widgets/NotificationsStatsWidget.tsx +167 -0
  389. package/ui/src/dashboard/widgets/index.ts +3 -0
  390. package/ui/src/pages/AuthPage.tsx +986 -142
  391. package/ui/src/pages/IntegrationsPage.tsx +288 -0
  392. package/ui/src/pages/NotificationsPage.tsx +417 -0
  393. package/ui/src/pages/RateLimitPage.tsx +292 -0
  394. package/ui/src/utils/formatters.ts +33 -0
  395. package/dist-ui/assets/index-BY8OxNgO.js +0 -465
@@ -0,0 +1,212 @@
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
+
9
+ import type { Request, Response, NextFunction, RequestHandler } from 'express';
10
+ import type { RateLimitMiddlewareOptions, LimitStatus } from './types.js';
11
+ import type { AuthenticatedRequest } from '../auth/types.js';
12
+ import { getRateLimitService } from './rate-limit-service.js';
13
+
14
+ /**
15
+ * Default key generator
16
+ * Uses user ID if authenticated, otherwise IP address
17
+ */
18
+ function defaultKeyGenerator(req: Request): string {
19
+ const authReq = req as AuthenticatedRequest;
20
+ const userId = authReq.auth?.user?.id;
21
+
22
+ if (userId) {
23
+ return `user:${userId}`;
24
+ }
25
+
26
+ // Fall back to IP address
27
+ const ip = req.ip ||
28
+ req.headers['x-forwarded-for']?.toString().split(',')[0].trim() ||
29
+ req.socket.remoteAddress ||
30
+ 'unknown';
31
+
32
+ return `ip:${ip}`;
33
+ }
34
+
35
+ /**
36
+ * Default handler when rate limit is exceeded
37
+ */
38
+ function defaultHandler(
39
+ _req: Request,
40
+ res: Response,
41
+ _next: NextFunction,
42
+ status: LimitStatus
43
+ ): void {
44
+ res.status(429).json({
45
+ error: 'Too Many Requests',
46
+ message: `Rate limit exceeded. Try again in ${status.retryAfter} seconds.`,
47
+ retryAfter: status.retryAfter,
48
+ });
49
+ }
50
+
51
+ /**
52
+ * Set standard rate limit headers on response
53
+ */
54
+ function setRateLimitHeaders(res: Response, status: LimitStatus): void {
55
+ // Standard rate limit headers (IETF draft)
56
+ res.setHeader('RateLimit-Limit', status.limit.toString());
57
+ res.setHeader('RateLimit-Remaining', status.remaining.toString());
58
+ res.setHeader('RateLimit-Reset', status.resetAt.toString());
59
+
60
+ // Retry-After header (RFC 7231)
61
+ if (status.limited) {
62
+ res.setHeader('Retry-After', status.retryAfter.toString());
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Create rate limit middleware
68
+ *
69
+ * @param options Middleware configuration
70
+ * @returns Express middleware function
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * // Basic usage
75
+ * app.use('/api', rateLimitMiddleware());
76
+ *
77
+ * // Custom configuration
78
+ * app.post('/api/chat', rateLimitMiddleware({
79
+ * windowMs: 60000,
80
+ * max: 50,
81
+ * keyGenerator: (req) => `chat:${req.user.id}`,
82
+ * }));
83
+ *
84
+ * // Tiered limits
85
+ * app.use(rateLimitMiddleware({
86
+ * max: (req) => req.user?.tier === 'premium' ? 1000 : 50,
87
+ * }));
88
+ * ```
89
+ */
90
+ export function rateLimitMiddleware(options: RateLimitMiddlewareOptions = {}): RequestHandler {
91
+ const {
92
+ windowMs,
93
+ max,
94
+ keyGenerator = defaultKeyGenerator,
95
+ skip,
96
+ handler = defaultHandler,
97
+ strategy,
98
+ headers = true,
99
+ keyPrefix = '',
100
+ } = options;
101
+
102
+ return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
103
+ try {
104
+ // Check if should skip
105
+ if (skip) {
106
+ const shouldSkip = await skip(req);
107
+ if (shouldSkip) {
108
+ next();
109
+ return;
110
+ }
111
+ }
112
+
113
+ // Generate the rate limit key
114
+ let key = await keyGenerator(req);
115
+ if (keyPrefix) {
116
+ key = `${keyPrefix}:${key}`;
117
+ }
118
+
119
+ // Resolve max requests (can be dynamic)
120
+ let maxRequests: number | undefined;
121
+ if (typeof max === 'function') {
122
+ maxRequests = await max(req);
123
+ } else {
124
+ maxRequests = max;
125
+ }
126
+
127
+ // Get the rate limit service
128
+ const service = getRateLimitService();
129
+
130
+ // Check and increment the rate limit
131
+ const status = await service.incrementLimit(key, {
132
+ windowMs,
133
+ maxRequests,
134
+ strategy,
135
+ });
136
+
137
+ // Set headers if enabled
138
+ if (headers) {
139
+ setRateLimitHeaders(res, status);
140
+ }
141
+
142
+ // If rate limited, call handler
143
+ if (status.limited) {
144
+ handler(req, res, next, status);
145
+ return;
146
+ }
147
+
148
+ // Continue to next middleware
149
+ next();
150
+ } catch (error) {
151
+ // On error, log and allow request (fail open)
152
+ console.error('[RateLimitMiddleware] Error:', error);
153
+ next();
154
+ }
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Create a rate limit middleware that only checks without incrementing
160
+ * Useful for displaying rate limit status without counting the request
161
+ */
162
+ export function rateLimitStatusMiddleware(options: RateLimitMiddlewareOptions = {}): RequestHandler {
163
+ const {
164
+ windowMs,
165
+ max,
166
+ keyGenerator = defaultKeyGenerator,
167
+ strategy,
168
+ headers = true,
169
+ keyPrefix = '',
170
+ } = options;
171
+
172
+ return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
173
+ try {
174
+ // Generate the rate limit key
175
+ let key = await keyGenerator(req);
176
+ if (keyPrefix) {
177
+ key = `${keyPrefix}:${key}`;
178
+ }
179
+
180
+ // Resolve max requests (can be dynamic)
181
+ let maxRequests: number | undefined;
182
+ if (typeof max === 'function') {
183
+ maxRequests = await max(req);
184
+ } else {
185
+ maxRequests = max;
186
+ }
187
+
188
+ // Get the rate limit service
189
+ const service = getRateLimitService();
190
+
191
+ // Check without incrementing
192
+ const status = await service.checkLimit(key, {
193
+ windowMs,
194
+ maxRequests,
195
+ strategy,
196
+ increment: false,
197
+ });
198
+
199
+ // Set headers if enabled
200
+ if (headers) {
201
+ setRateLimitHeaders(res, status);
202
+ }
203
+
204
+ // Always continue (this middleware doesn't block)
205
+ next();
206
+ } catch (error) {
207
+ // On error, log and continue
208
+ console.error('[RateLimitStatusMiddleware] Error:', error);
209
+ next();
210
+ }
211
+ };
212
+ }
@@ -0,0 +1,400 @@
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
+
11
+ import type { Request, Response } from 'express';
12
+ import type { Plugin, PluginConfig, PluginRegistry } from '../../core/plugin-registry.js';
13
+ import type { RateLimitPluginConfig, RateLimitStrategy } from './types.js';
14
+ import type { AuthenticatedRequest } from '../auth/types.js';
15
+ import { RateLimitService, setRateLimitService } from './rate-limit-service.js';
16
+ import { createRateLimitCache } from './stores/cache-store.js';
17
+ import { createCleanupJob, type CleanupJob } from './cleanup.js';
18
+
19
+ /**
20
+ * Runtime configuration state
21
+ */
22
+ interface RuntimeConfig {
23
+ windowMs: number;
24
+ maxRequests: number;
25
+ strategy: RateLimitStrategy;
26
+ cleanupEnabled: boolean;
27
+ cleanupIntervalMs: number;
28
+ }
29
+
30
+ /**
31
+ * Create the Rate Limit plugin
32
+ *
33
+ * @param config Plugin configuration
34
+ * @returns Plugin instance
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import {
39
+ * createGateway,
40
+ * createRateLimitPlugin,
41
+ * postgresRateLimitStore,
42
+ * getPostgres,
43
+ * } from '@qwickapps/server';
44
+ *
45
+ * const gateway = createGateway({
46
+ * plugins: [
47
+ * createRateLimitPlugin({
48
+ * store: postgresRateLimitStore({
49
+ * pool: () => getPostgres().getPool(),
50
+ * }),
51
+ * defaults: {
52
+ * windowMs: 60000,
53
+ * maxRequests: 100,
54
+ * strategy: 'sliding-window',
55
+ * },
56
+ * }),
57
+ * ],
58
+ * });
59
+ * ```
60
+ */
61
+ export function createRateLimitPlugin(config: RateLimitPluginConfig): Plugin {
62
+ const debug = config.debug || false;
63
+ const apiPrefix = config.api?.prefix || '/rate-limit';
64
+ const apiEnabled = config.api?.enabled !== false;
65
+ const uiEnabled = config.ui?.enabled !== false;
66
+ const initialCleanupEnabled = config.cleanup?.enabled !== false;
67
+ const initialCleanupIntervalMs = config.cleanup?.intervalMs || 300000;
68
+
69
+ let service: RateLimitService | null = null;
70
+ let cleanupJob: CleanupJob | null = null;
71
+ let cache: ReturnType<typeof createRateLimitCache>;
72
+
73
+ // Runtime config state (can be modified via API)
74
+ const runtimeConfig: RuntimeConfig = {
75
+ windowMs: config.defaults?.windowMs || 60000,
76
+ maxRequests: config.defaults?.maxRequests || 100,
77
+ strategy: config.defaults?.strategy || 'sliding-window',
78
+ cleanupEnabled: initialCleanupEnabled,
79
+ cleanupIntervalMs: initialCleanupIntervalMs,
80
+ };
81
+
82
+ function log(message: string, data?: Record<string, unknown>) {
83
+ if (debug) {
84
+ console.log(`[RateLimitPlugin] ${message}`, data || '');
85
+ }
86
+ }
87
+
88
+ return {
89
+ id: 'rate-limit',
90
+ name: 'Rate Limit',
91
+ version: '1.0.0',
92
+
93
+ async onStart(_pluginConfig: PluginConfig, registry: PluginRegistry): Promise<void> {
94
+ log('Starting rate limit plugin');
95
+
96
+ // Initialize the store
97
+ await config.store.initialize();
98
+ log('Store initialized');
99
+
100
+ // Create cache
101
+ cache = createRateLimitCache(config.cache);
102
+ log('Cache created', { type: cache.name });
103
+
104
+ // Create service
105
+ service = new RateLimitService({
106
+ store: config.store,
107
+ cache,
108
+ defaults: config.defaults,
109
+ });
110
+ setRateLimitService(service);
111
+ log('Service created');
112
+
113
+ // Start cleanup job if enabled
114
+ if (runtimeConfig.cleanupEnabled) {
115
+ cleanupJob = createCleanupJob({
116
+ store: config.store,
117
+ intervalMs: runtimeConfig.cleanupIntervalMs,
118
+ debug,
119
+ });
120
+ cleanupJob.start();
121
+ log('Cleanup job started', { intervalMs: runtimeConfig.cleanupIntervalMs });
122
+ }
123
+
124
+ // Register health check
125
+ registry.registerHealthCheck({
126
+ name: 'rate-limit',
127
+ type: 'custom',
128
+ check: async () => {
129
+ try {
130
+ const defaults = service?.getDefaults();
131
+ return {
132
+ healthy: service !== null,
133
+ details: {
134
+ store: config.store.name,
135
+ cache: cache.name,
136
+ cacheAvailable: cache.isAvailable(),
137
+ defaults,
138
+ cleanupEnabled: runtimeConfig.cleanupEnabled,
139
+ },
140
+ };
141
+ } catch {
142
+ return { healthy: false };
143
+ }
144
+ },
145
+ });
146
+
147
+ // Register UI menu item if enabled
148
+ if (uiEnabled) {
149
+ registry.addMenuItem({
150
+ pluginId: 'rate-limit',
151
+ id: 'rate-limit:sidebar',
152
+ label: 'Rate Limits',
153
+ icon: 'speed',
154
+ route: '/rate-limits',
155
+ order: 40, // After Entitlements (35)
156
+ });
157
+ }
158
+
159
+ // Add API routes if enabled
160
+ if (apiEnabled) {
161
+ // GET /rate-limit/config - Get current config
162
+ registry.addRoute({
163
+ method: 'get',
164
+ path: '/rate-limit/config',
165
+ pluginId: 'rate-limit',
166
+ handler: async (_req: Request, res: Response) => {
167
+ try {
168
+ const defaults = service?.getDefaults();
169
+ res.json({
170
+ ...runtimeConfig,
171
+ ...defaults,
172
+ store: config.store.name,
173
+ cache: cache.name,
174
+ cacheAvailable: cache.isAvailable(),
175
+ });
176
+ } catch (error) {
177
+ console.error('[RateLimitPlugin] Config error:', error);
178
+ res.status(500).json({ error: 'Failed to get config' });
179
+ }
180
+ },
181
+ });
182
+
183
+ // PUT /rate-limit/config - Update config at runtime
184
+ registry.addRoute({
185
+ method: 'put',
186
+ path: '/rate-limit/config',
187
+ pluginId: 'rate-limit',
188
+ handler: async (req: Request, res: Response) => {
189
+ try {
190
+ const updates = req.body as Partial<RuntimeConfig>;
191
+ const validStrategies: RateLimitStrategy[] = ['sliding-window', 'fixed-window', 'token-bucket'];
192
+
193
+ // Validate and apply updates
194
+ if (updates.windowMs !== undefined) {
195
+ if (typeof updates.windowMs !== 'number' || updates.windowMs <= 0) {
196
+ return res.status(400).json({ error: 'windowMs must be a positive number' });
197
+ }
198
+ runtimeConfig.windowMs = updates.windowMs;
199
+ }
200
+
201
+ if (updates.maxRequests !== undefined) {
202
+ if (typeof updates.maxRequests !== 'number' || updates.maxRequests <= 0) {
203
+ return res.status(400).json({ error: 'maxRequests must be a positive number' });
204
+ }
205
+ runtimeConfig.maxRequests = updates.maxRequests;
206
+ }
207
+
208
+ if (updates.strategy !== undefined) {
209
+ if (!validStrategies.includes(updates.strategy)) {
210
+ return res.status(400).json({
211
+ error: `Invalid strategy. Must be one of: ${validStrategies.join(', ')}`,
212
+ });
213
+ }
214
+ runtimeConfig.strategy = updates.strategy;
215
+ }
216
+
217
+ // Update service defaults
218
+ if (service) {
219
+ service.setDefaults({
220
+ windowMs: runtimeConfig.windowMs,
221
+ maxRequests: runtimeConfig.maxRequests,
222
+ strategy: runtimeConfig.strategy,
223
+ });
224
+ }
225
+
226
+ // Handle cleanup config changes
227
+ if (updates.cleanupEnabled !== undefined) {
228
+ runtimeConfig.cleanupEnabled = updates.cleanupEnabled;
229
+ if (updates.cleanupEnabled && !cleanupJob) {
230
+ // Start cleanup job
231
+ cleanupJob = createCleanupJob({
232
+ store: config.store,
233
+ intervalMs: runtimeConfig.cleanupIntervalMs,
234
+ debug,
235
+ });
236
+ cleanupJob.start();
237
+ } else if (!updates.cleanupEnabled && cleanupJob) {
238
+ // Stop cleanup job
239
+ cleanupJob.stop();
240
+ cleanupJob = null;
241
+ }
242
+ }
243
+
244
+ if (updates.cleanupIntervalMs !== undefined) {
245
+ if (typeof updates.cleanupIntervalMs !== 'number' || updates.cleanupIntervalMs <= 0) {
246
+ return res.status(400).json({ error: 'cleanupIntervalMs must be a positive number' });
247
+ }
248
+ runtimeConfig.cleanupIntervalMs = updates.cleanupIntervalMs;
249
+ // Restart cleanup job with new interval if running
250
+ if (cleanupJob && runtimeConfig.cleanupEnabled) {
251
+ cleanupJob.stop();
252
+ cleanupJob = createCleanupJob({
253
+ store: config.store,
254
+ intervalMs: runtimeConfig.cleanupIntervalMs,
255
+ debug,
256
+ });
257
+ cleanupJob.start();
258
+ }
259
+ }
260
+
261
+ log('Config updated', { ...runtimeConfig });
262
+
263
+ res.json({
264
+ success: true,
265
+ config: {
266
+ ...runtimeConfig,
267
+ store: config.store.name,
268
+ cache: cache.name,
269
+ cacheAvailable: cache.isAvailable(),
270
+ },
271
+ });
272
+ } catch (error) {
273
+ console.error('[RateLimitPlugin] Config update error:', error);
274
+ res.status(500).json({ error: 'Failed to update config' });
275
+ }
276
+ },
277
+ });
278
+ // GET /rate-limit/status - Get rate limit status for current user
279
+ registry.addRoute({
280
+ method: 'get',
281
+ path: `${apiPrefix}/status`,
282
+ pluginId: 'rate-limit',
283
+ handler: async (req: Request, res: Response) => {
284
+ try {
285
+ const authReq = req as AuthenticatedRequest;
286
+ const userId = authReq.auth?.user?.id;
287
+
288
+ // Generate key (same logic as middleware)
289
+ let key: string;
290
+ if (userId) {
291
+ key = `user:${userId}`;
292
+ } else {
293
+ const ip = req.ip ||
294
+ req.headers['x-forwarded-for']?.toString().split(',')[0].trim() ||
295
+ req.socket.remoteAddress ||
296
+ 'unknown';
297
+ key = `ip:${ip}`;
298
+ }
299
+
300
+ // Get status without incrementing
301
+ const status = await service!.checkLimit(key, {
302
+ userId,
303
+ increment: false,
304
+ });
305
+
306
+ res.json({
307
+ key,
308
+ ...status,
309
+ });
310
+ } catch (error) {
311
+ console.error('[RateLimitPlugin] Status error:', error);
312
+ res.status(500).json({ error: 'Failed to get rate limit status' });
313
+ }
314
+ },
315
+ });
316
+
317
+ // GET /rate-limit/status/:key - Get rate limit status for a specific key
318
+ registry.addRoute({
319
+ method: 'get',
320
+ path: `${apiPrefix}/status/:key`,
321
+ pluginId: 'rate-limit',
322
+ handler: async (req: Request, res: Response) => {
323
+ try {
324
+ const authReq = req as AuthenticatedRequest;
325
+ const userId = authReq.auth?.user?.id;
326
+ const key = req.params.key;
327
+
328
+ if (!key) {
329
+ return res.status(400).json({ error: 'Key is required' });
330
+ }
331
+
332
+ // Get status without incrementing
333
+ const status = await service!.checkLimit(key, {
334
+ userId,
335
+ increment: false,
336
+ });
337
+
338
+ res.json({
339
+ key,
340
+ ...status,
341
+ });
342
+ } catch (error) {
343
+ console.error('[RateLimitPlugin] Status error:', error);
344
+ res.status(500).json({ error: 'Failed to get rate limit status' });
345
+ }
346
+ },
347
+ });
348
+
349
+ // DELETE /rate-limit/clear/:key - Clear a rate limit (requires auth)
350
+ registry.addRoute({
351
+ method: 'delete',
352
+ path: `${apiPrefix}/clear/:key`,
353
+ pluginId: 'rate-limit',
354
+ handler: async (req: Request, res: Response) => {
355
+ try {
356
+ const authReq = req as AuthenticatedRequest;
357
+ const userId = authReq.auth?.user?.id;
358
+
359
+ if (!userId) {
360
+ return res.status(401).json({ error: 'Authentication required' });
361
+ }
362
+
363
+ const key = req.params.key;
364
+ if (!key) {
365
+ return res.status(400).json({ error: 'Key is required' });
366
+ }
367
+
368
+ await service!.clearLimit(key, userId);
369
+ res.status(204).send();
370
+ } catch (error) {
371
+ console.error('[RateLimitPlugin] Clear error:', error);
372
+ res.status(500).json({ error: 'Failed to clear rate limit' });
373
+ }
374
+ },
375
+ });
376
+ }
377
+
378
+ log('Rate limit plugin started');
379
+ },
380
+
381
+ async onStop(): Promise<void> {
382
+ log('Stopping rate limit plugin');
383
+
384
+ // Stop cleanup job
385
+ if (cleanupJob) {
386
+ cleanupJob.stop();
387
+ cleanupJob = null;
388
+ }
389
+
390
+ // Clear service reference
391
+ setRateLimitService(null);
392
+ service = null;
393
+
394
+ // Shutdown store
395
+ await config.store.shutdown();
396
+
397
+ log('Rate limit plugin stopped');
398
+ },
399
+ };
400
+ }