@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,320 @@
1
+ /**
2
+ * PostgreSQL Rate Limit Store
3
+ *
4
+ * Rate limit storage implementation using PostgreSQL with Row-Level Security (RLS).
5
+ * Follows the same pattern as the preferences plugin's postgres-store.
6
+ *
7
+ * RLS Context Pattern:
8
+ * Each operation uses an explicit transaction and sets `app.current_user_id`
9
+ * as a transaction-local configuration variable. The RLS policy checks this
10
+ * variable to enforce that users can only access their own rate limits.
11
+ *
12
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
13
+ */
14
+ /**
15
+ * Execute a function within an RLS-protected transaction
16
+ *
17
+ * This helper ensures that:
18
+ * 1. All queries run within the same transaction
19
+ * 2. The RLS context is set before any data access
20
+ * 3. The transaction is properly committed or rolled back
21
+ *
22
+ * @param pool PostgreSQL pool
23
+ * @param userId User ID to set as the RLS context (optional for IP-only limits)
24
+ * @param callback Function to execute within the transaction
25
+ */
26
+ async function withRLSContext(pool, userId, callback) {
27
+ const client = await pool.connect();
28
+ try {
29
+ await client.query('BEGIN');
30
+ // Set transaction-local user context for RLS
31
+ // If no userId, set to empty string (allows IP-only limits via RLS policy)
32
+ await client.query("SELECT set_config('app.current_user_id', $1, true)", [userId || '']);
33
+ const result = await callback(client);
34
+ await client.query('COMMIT');
35
+ return result;
36
+ }
37
+ catch (error) {
38
+ await client.query('ROLLBACK');
39
+ throw error;
40
+ }
41
+ finally {
42
+ client.release();
43
+ }
44
+ }
45
+ /**
46
+ * Create a PostgreSQL rate limit store with RLS
47
+ *
48
+ * @param config Configuration including a pg Pool instance
49
+ * @returns RateLimitStore implementation
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * import { Pool } from 'pg';
54
+ * import { postgresRateLimitStore } from '@qwickapps/server';
55
+ *
56
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
57
+ * const store = postgresRateLimitStore({ pool });
58
+ *
59
+ * // Or with lazy initialization:
60
+ * const store = postgresRateLimitStore({ pool: () => getPostgres().getPool() });
61
+ * ```
62
+ */
63
+ export function postgresRateLimitStore(config) {
64
+ const { pool: poolOrFn, tableName = 'rate_limits', schema = 'public', autoCreateTables = true, enableRLS = true, } = config;
65
+ // Helper to get pool (supports lazy initialization via function)
66
+ const getPool = () => {
67
+ const pool = typeof poolOrFn === 'function' ? poolOrFn() : poolOrFn;
68
+ if (!pool || typeof pool.query !== 'function') {
69
+ throw new Error('Invalid pool: must have query method');
70
+ }
71
+ return pool;
72
+ };
73
+ const tableFullName = `"${schema}"."${tableName}"`;
74
+ return {
75
+ name: 'postgres',
76
+ async initialize() {
77
+ if (!autoCreateTables)
78
+ return;
79
+ const pool = getPool();
80
+ // Create table
81
+ await pool.query(`
82
+ CREATE TABLE IF NOT EXISTS ${tableFullName} (
83
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
84
+
85
+ -- Scope identifiers (nullable, use what applies)
86
+ user_id UUID,
87
+ tenant_id UUID,
88
+ ip_address INET,
89
+
90
+ -- Limit key (composite identifier)
91
+ limit_key VARCHAR(500) NOT NULL,
92
+
93
+ -- Strategy and configuration
94
+ strategy VARCHAR(50) NOT NULL DEFAULT 'sliding-window',
95
+ max_requests INTEGER NOT NULL,
96
+ window_ms INTEGER NOT NULL,
97
+
98
+ -- Current state
99
+ current_count INTEGER DEFAULT 0,
100
+ window_start TIMESTAMPTZ NOT NULL,
101
+ window_end TIMESTAMPTZ NOT NULL,
102
+
103
+ -- Token bucket specific (nullable)
104
+ tokens_remaining NUMERIC,
105
+ last_refill TIMESTAMPTZ,
106
+
107
+ -- Metadata
108
+ metadata JSONB,
109
+ created_at TIMESTAMPTZ DEFAULT NOW(),
110
+ updated_at TIMESTAMPTZ DEFAULT NOW()
111
+ );
112
+ `);
113
+ // Create indexes
114
+ await pool.query(`
115
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_key ON ${tableFullName}(limit_key);
116
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_key_window ON ${tableFullName}(limit_key, window_start);
117
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_user ON ${tableFullName}(user_id) WHERE user_id IS NOT NULL;
118
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_tenant ON ${tableFullName}(tenant_id) WHERE tenant_id IS NOT NULL;
119
+ CREATE INDEX IF NOT EXISTS idx_${tableName}_cleanup ON ${tableFullName}(window_end);
120
+ `);
121
+ // Enable RLS if configured
122
+ if (enableRLS) {
123
+ await pool.query(`
124
+ ALTER TABLE ${tableFullName} ENABLE ROW LEVEL SECURITY;
125
+ ALTER TABLE ${tableFullName} FORCE ROW LEVEL SECURITY;
126
+ `);
127
+ // Create or replace the RLS policy
128
+ // Drop existing policy first to avoid errors on re-initialization
129
+ await pool.query(`
130
+ DROP POLICY IF EXISTS "${tableName}_access" ON ${tableFullName};
131
+ `);
132
+ // RLS policy: Users can access their own limits OR IP-only limits (no user)
133
+ await pool.query(`
134
+ CREATE POLICY "${tableName}_access" ON ${tableFullName}
135
+ FOR ALL
136
+ USING (
137
+ user_id::text = current_setting('app.current_user_id', true)
138
+ OR (user_id IS NULL AND current_setting('app.current_user_id', true) = '')
139
+ )
140
+ WITH CHECK (
141
+ user_id::text = current_setting('app.current_user_id', true)
142
+ OR (user_id IS NULL AND current_setting('app.current_user_id', true) = '')
143
+ );
144
+ `);
145
+ }
146
+ },
147
+ async get(key, userId) {
148
+ return withRLSContext(getPool(), userId, async (client) => {
149
+ const result = await client.query(`SELECT * FROM ${tableFullName}
150
+ WHERE limit_key = $1
151
+ AND window_end > NOW()
152
+ ORDER BY window_start DESC
153
+ LIMIT 1`, [key]);
154
+ if (result.rows.length === 0) {
155
+ return null;
156
+ }
157
+ const row = result.rows[0];
158
+ return {
159
+ id: row.id,
160
+ key: row.limit_key,
161
+ count: row.current_count,
162
+ maxRequests: row.max_requests,
163
+ windowMs: row.window_ms,
164
+ windowStart: new Date(row.window_start),
165
+ windowEnd: new Date(row.window_end),
166
+ strategy: row.strategy,
167
+ userId: row.user_id,
168
+ tenantId: row.tenant_id,
169
+ ipAddress: row.ip_address,
170
+ tokensRemaining: row.tokens_remaining,
171
+ lastRefill: row.last_refill ? new Date(row.last_refill) : undefined,
172
+ createdAt: new Date(row.created_at),
173
+ updatedAt: new Date(row.updated_at),
174
+ };
175
+ });
176
+ },
177
+ async increment(key, options) {
178
+ const { maxRequests, windowMs, strategy, userId, tenantId, ipAddress, amount = 1 } = options;
179
+ return withRLSContext(getPool(), userId, async (client) => {
180
+ const now = new Date();
181
+ const windowStart = new Date(now.getTime() - (now.getTime() % windowMs));
182
+ const windowEnd = new Date(windowStart.getTime() + windowMs);
183
+ // For token bucket, handle differently
184
+ if (strategy === 'token-bucket') {
185
+ // Get existing record or create new one
186
+ const existing = await client.query(`SELECT * FROM ${tableFullName}
187
+ WHERE limit_key = $1
188
+ ORDER BY created_at DESC
189
+ LIMIT 1`, [key]);
190
+ if (existing.rows.length > 0) {
191
+ const row = existing.rows[0];
192
+ const lastRefill = row.last_refill ? new Date(row.last_refill).getTime() : now.getTime();
193
+ const tokensRemaining = row.tokens_remaining ?? maxRequests;
194
+ // Calculate refill
195
+ const elapsed = now.getTime() - lastRefill;
196
+ const refillRate = maxRequests / windowMs;
197
+ const newTokens = Math.min(maxRequests, tokensRemaining + elapsed * refillRate - 1);
198
+ await client.query(`UPDATE ${tableFullName}
199
+ SET tokens_remaining = $1,
200
+ last_refill = $2,
201
+ current_count = $3,
202
+ updated_at = NOW()
203
+ WHERE id = $4`, [newTokens, now, Math.floor(maxRequests - newTokens), row.id]);
204
+ return {
205
+ id: row.id,
206
+ key,
207
+ count: Math.floor(maxRequests - newTokens),
208
+ maxRequests,
209
+ windowMs,
210
+ windowStart: new Date(row.window_start),
211
+ windowEnd: new Date(row.window_end),
212
+ strategy,
213
+ userId,
214
+ tenantId,
215
+ ipAddress,
216
+ tokensRemaining: newTokens,
217
+ lastRefill: now,
218
+ createdAt: new Date(row.created_at),
219
+ updatedAt: now,
220
+ };
221
+ }
222
+ // Create new record with full bucket minus 1
223
+ const newTokens = maxRequests - 1;
224
+ const insertResult = await client.query(`INSERT INTO ${tableFullName}
225
+ (limit_key, strategy, max_requests, window_ms, current_count,
226
+ window_start, window_end, user_id, tenant_id, ip_address,
227
+ tokens_remaining, last_refill)
228
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
229
+ RETURNING *`, [key, strategy, maxRequests, windowMs, 1, windowStart, windowEnd,
230
+ userId || null, tenantId || null, ipAddress || null, newTokens, now]);
231
+ const row = insertResult.rows[0];
232
+ return {
233
+ id: row.id,
234
+ key,
235
+ count: 1,
236
+ maxRequests,
237
+ windowMs,
238
+ windowStart,
239
+ windowEnd,
240
+ strategy,
241
+ userId,
242
+ tenantId,
243
+ ipAddress,
244
+ tokensRemaining: newTokens,
245
+ lastRefill: now,
246
+ createdAt: now,
247
+ updatedAt: now,
248
+ };
249
+ }
250
+ // For sliding-window and fixed-window, use UPDATE-then-INSERT pattern
251
+ // This avoids needing a unique constraint on (limit_key, window_start)
252
+ // First try to update existing record in current window
253
+ const updateResult = await client.query(`UPDATE ${tableFullName}
254
+ SET current_count = current_count + $1,
255
+ updated_at = NOW()
256
+ WHERE limit_key = $2
257
+ AND window_start = $3
258
+ RETURNING *`, [amount, key, windowStart]);
259
+ if (updateResult.rows.length > 0) {
260
+ const row = updateResult.rows[0];
261
+ return {
262
+ id: row.id,
263
+ key,
264
+ count: row.current_count,
265
+ maxRequests,
266
+ windowMs,
267
+ windowStart,
268
+ windowEnd,
269
+ strategy,
270
+ userId,
271
+ tenantId,
272
+ ipAddress,
273
+ createdAt: new Date(row.created_at),
274
+ updatedAt: now,
275
+ };
276
+ }
277
+ // No existing record - insert new
278
+ const insertResult = await client.query(`INSERT INTO ${tableFullName}
279
+ (limit_key, strategy, max_requests, window_ms, current_count,
280
+ window_start, window_end, user_id, tenant_id, ip_address)
281
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
282
+ RETURNING *`, [key, strategy, maxRequests, windowMs, amount, windowStart, windowEnd,
283
+ userId || null, tenantId || null, ipAddress || null]);
284
+ const row = insertResult.rows[0];
285
+ return {
286
+ id: row.id,
287
+ key,
288
+ count: amount,
289
+ maxRequests,
290
+ windowMs,
291
+ windowStart,
292
+ windowEnd,
293
+ strategy,
294
+ userId,
295
+ tenantId,
296
+ ipAddress,
297
+ createdAt: now,
298
+ updatedAt: now,
299
+ };
300
+ });
301
+ },
302
+ async clear(key, userId) {
303
+ return withRLSContext(getPool(), userId, async (client) => {
304
+ const result = await client.query(`DELETE FROM ${tableFullName} WHERE limit_key = $1`, [key]);
305
+ return (result.rowCount ?? 0) > 0;
306
+ });
307
+ },
308
+ async cleanup() {
309
+ const pool = getPool();
310
+ // Cleanup runs without RLS context as it's a system operation
311
+ // We use a direct query without user context
312
+ const result = await pool.query(`DELETE FROM ${tableFullName} WHERE window_end < NOW()`);
313
+ return result.rowCount ?? 0;
314
+ },
315
+ async shutdown() {
316
+ // Pool is managed externally, nothing to do here
317
+ },
318
+ };
319
+ }
320
+ //# sourceMappingURL=postgres-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-store.js","sourceRoot":"","sources":["../../../../src/plugins/rate-limit/stores/postgres-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Fixed Window Rate Limit Strategy
3
+ *
4
+ * Implements a simple fixed window algorithm where requests are counted
5
+ * within discrete time windows. When a new window starts, the count resets.
6
+ *
7
+ * Pros:
8
+ * - Simple to implement and understand
9
+ * - Low memory overhead
10
+ *
11
+ * Cons:
12
+ * - Burst at boundary: allows 2x requests if timed at window edge
13
+ *
14
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
15
+ */
16
+ import type { Strategy } from '../types.js';
17
+ /**
18
+ * Create the fixed window strategy
19
+ */
20
+ export declare function createFixedWindowStrategy(): Strategy;
21
+ //# sourceMappingURL=fixed-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixed-window.d.ts","sourceRoot":"","sources":["../../../../src/plugins/rate-limit/strategies/fixed-window.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,QAAQ,CAwFpD"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Fixed Window Rate Limit Strategy
3
+ *
4
+ * Implements a simple fixed window algorithm where requests are counted
5
+ * within discrete time windows. When a new window starts, the count resets.
6
+ *
7
+ * Pros:
8
+ * - Simple to implement and understand
9
+ * - Low memory overhead
10
+ *
11
+ * Cons:
12
+ * - Burst at boundary: allows 2x requests if timed at window edge
13
+ *
14
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
15
+ */
16
+ /**
17
+ * Create the fixed window strategy
18
+ */
19
+ export function createFixedWindowStrategy() {
20
+ return {
21
+ name: 'fixed-window',
22
+ async check(key, options, context) {
23
+ const { maxRequests, windowMs, increment = true } = options;
24
+ const { store, cache, userId, tenantId, ipAddress } = context;
25
+ const now = Date.now();
26
+ const windowStart = now - (now % windowMs); // Align to window boundary
27
+ const windowEnd = windowStart + windowMs;
28
+ // Try cache first
29
+ let cached = await cache.get(key);
30
+ let currentCount = 0;
31
+ if (cached && cached.windowStart === windowStart) {
32
+ // Cache hit and same window
33
+ currentCount = cached.count;
34
+ }
35
+ else if (cached && cached.windowEnd <= now) {
36
+ // Window expired - reset count
37
+ currentCount = 0;
38
+ }
39
+ else {
40
+ // Cache miss - check store
41
+ const stored = await store.get(key, userId);
42
+ if (stored) {
43
+ const storedWindowStart = stored.windowStart.getTime();
44
+ if (storedWindowStart === windowStart) {
45
+ currentCount = stored.count;
46
+ }
47
+ // If different window, count is 0 (new window)
48
+ }
49
+ }
50
+ // Check if limited
51
+ const limited = currentCount >= maxRequests;
52
+ const remaining = Math.max(0, maxRequests - currentCount - (increment && !limited ? 1 : 0));
53
+ const resetAt = Math.ceil(windowEnd / 1000);
54
+ const retryAfter = Math.max(0, Math.ceil((windowEnd - now) / 1000));
55
+ // Increment if requested and not limited
56
+ if (increment && !limited) {
57
+ // Increment in store
58
+ const updated = await store.increment(key, {
59
+ maxRequests,
60
+ windowMs,
61
+ strategy: 'fixed-window',
62
+ userId,
63
+ tenantId,
64
+ ipAddress,
65
+ amount: 1,
66
+ });
67
+ // Update cache
68
+ const newCached = {
69
+ count: updated.count,
70
+ maxRequests,
71
+ windowStart,
72
+ windowEnd,
73
+ strategy: 'fixed-window',
74
+ };
75
+ await cache.set(key, newCached, windowMs);
76
+ return {
77
+ limited: false,
78
+ current: updated.count,
79
+ limit: maxRequests,
80
+ remaining: Math.max(0, maxRequests - updated.count),
81
+ resetAt,
82
+ retryAfter,
83
+ };
84
+ }
85
+ // Return status without incrementing
86
+ return {
87
+ limited,
88
+ current: currentCount,
89
+ limit: maxRequests,
90
+ remaining,
91
+ resetAt,
92
+ retryAfter,
93
+ };
94
+ },
95
+ };
96
+ }
97
+ //# sourceMappingURL=fixed-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixed-window.js","sourceRoot":"","sources":["../../../../src/plugins/rate-limit/strategies/fixed-window.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAUH;;GAEG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO;QACL,IAAI,EAAE,cAAc;QAEpB,KAAK,CAAC,KAAK,CACT,GAAW,EACX,OAAwB,EACxB,OAAwB;YAExB,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;YAC5D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;YAE9D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,WAAW,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,2BAA2B;YACvE,MAAM,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;YAEzC,kBAAkB;YAClB,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,YAAY,GAAG,CAAC,CAAC;YAErB,IAAI,MAAM,IAAI,MAAM,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;gBACjD,4BAA4B;gBAC5B,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC;YAC9B,CAAC;iBAAM,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC;gBAC7C,+BAA+B;gBAC/B,YAAY,GAAG,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,2BAA2B;gBAC3B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC5C,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;oBACvD,IAAI,iBAAiB,KAAK,WAAW,EAAE,CAAC;wBACtC,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC;oBAC9B,CAAC;oBACD,+CAA+C;gBACjD,CAAC;YACH,CAAC;YAED,mBAAmB;YACnB,MAAM,OAAO,GAAG,YAAY,IAAI,WAAW,CAAC;YAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5F,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;YAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YAEpE,yCAAyC;YACzC,IAAI,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC1B,qBAAqB;gBACrB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;oBACzC,WAAW;oBACX,QAAQ;oBACR,QAAQ,EAAE,cAAc;oBACxB,MAAM;oBACN,QAAQ;oBACR,SAAS;oBACT,MAAM,EAAE,CAAC;iBACV,CAAC,CAAC;gBAEH,eAAe;gBACf,MAAM,SAAS,GAAgB;oBAC7B,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,WAAW;oBACX,WAAW;oBACX,SAAS;oBACT,QAAQ,EAAE,cAAc;iBACzB,CAAC;gBACF,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;gBAE1C,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,OAAO,CAAC,KAAK;oBACtB,KAAK,EAAE,WAAW;oBAClB,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;oBACnD,OAAO;oBACP,UAAU;iBACX,CAAC;YACJ,CAAC;YAED,qCAAqC;YACrC,OAAO;gBACL,OAAO;gBACP,OAAO,EAAE,YAAY;gBACrB,KAAK,EAAE,WAAW;gBAClB,SAAS;gBACT,OAAO;gBACP,UAAU;aACX,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Rate Limit Strategies
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+ export { createSlidingWindowStrategy } from './sliding-window.js';
7
+ export { createFixedWindowStrategy } from './fixed-window.js';
8
+ export { createTokenBucketStrategy } from './token-bucket.js';
9
+ import type { Strategy, RateLimitStrategy } from '../types.js';
10
+ /**
11
+ * Get a strategy by name
12
+ */
13
+ export declare function getStrategy(name: RateLimitStrategy): Strategy;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/rate-limit/strategies/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAK/D;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,QAAQ,CAW7D"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Rate Limit Strategies
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+ export { createSlidingWindowStrategy } from './sliding-window.js';
7
+ export { createFixedWindowStrategy } from './fixed-window.js';
8
+ export { createTokenBucketStrategy } from './token-bucket.js';
9
+ import { createSlidingWindowStrategy } from './sliding-window.js';
10
+ import { createFixedWindowStrategy } from './fixed-window.js';
11
+ import { createTokenBucketStrategy } from './token-bucket.js';
12
+ /**
13
+ * Get a strategy by name
14
+ */
15
+ export function getStrategy(name) {
16
+ switch (name) {
17
+ case 'sliding-window':
18
+ return createSlidingWindowStrategy();
19
+ case 'fixed-window':
20
+ return createFixedWindowStrategy();
21
+ case 'token-bucket':
22
+ return createTokenBucketStrategy();
23
+ default:
24
+ throw new Error(`Unknown rate limit strategy: ${name}`);
25
+ }
26
+ }
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugins/rate-limit/strategies/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAuB;IACjD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,gBAAgB;YACnB,OAAO,2BAA2B,EAAE,CAAC;QACvC,KAAK,cAAc;YACjB,OAAO,yBAAyB,EAAE,CAAC;QACrC,KAAK,cAAc;YACjB,OAAO,yBAAyB,EAAE,CAAC;QACrC;YACE,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Sliding Window Rate Limit Strategy
3
+ *
4
+ * Implements a sliding window algorithm that provides smooth rate limiting
5
+ * without the "burst at boundary" problem of fixed windows.
6
+ *
7
+ * The algorithm works by:
8
+ * 1. Tracking request timestamps within a sliding window
9
+ * 2. On each request, counting requests in the current window
10
+ * 3. Old requests "slide out" as time passes
11
+ *
12
+ * For performance, we approximate using weighted window counting:
13
+ * - current_window_count + (previous_window_count * overlap_percentage)
14
+ *
15
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
16
+ */
17
+ import type { Strategy } from '../types.js';
18
+ /**
19
+ * Create the sliding window strategy
20
+ */
21
+ export declare function createSlidingWindowStrategy(): Strategy;
22
+ //# sourceMappingURL=sliding-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliding-window.d.ts","sourceRoot":"","sources":["../../../../src/plugins/rate-limit/strategies/sliding-window.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,aAAa,CAAC;AAmBrB;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,QAAQ,CA+GtD"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Sliding Window Rate Limit Strategy
3
+ *
4
+ * Implements a sliding window algorithm that provides smooth rate limiting
5
+ * without the "burst at boundary" problem of fixed windows.
6
+ *
7
+ * The algorithm works by:
8
+ * 1. Tracking request timestamps within a sliding window
9
+ * 2. On each request, counting requests in the current window
10
+ * 3. Old requests "slide out" as time passes
11
+ *
12
+ * For performance, we approximate using weighted window counting:
13
+ * - current_window_count + (previous_window_count * overlap_percentage)
14
+ *
15
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
16
+ */
17
+ /**
18
+ * Calculate the sliding window count using weighted approximation
19
+ */
20
+ function calculateSlidingCount(currentCount, previousCount, windowMs, windowStart) {
21
+ const now = Date.now();
22
+ const elapsed = now - windowStart;
23
+ const overlap = Math.max(0, windowMs - elapsed) / windowMs;
24
+ // Weighted count: all of current window + portion of previous that overlaps
25
+ return Math.floor(currentCount + previousCount * overlap);
26
+ }
27
+ /**
28
+ * Create the sliding window strategy
29
+ */
30
+ export function createSlidingWindowStrategy() {
31
+ return {
32
+ name: 'sliding-window',
33
+ async check(key, options, context) {
34
+ const { maxRequests, windowMs, increment = true } = options;
35
+ const { store, cache, userId, tenantId, ipAddress } = context;
36
+ const now = Date.now();
37
+ const windowStart = now - (now % windowMs); // Align to window boundary
38
+ const windowEnd = windowStart + windowMs;
39
+ // Try cache first
40
+ let cached = await cache.get(key);
41
+ let currentCount = 0;
42
+ let previousCount = 0;
43
+ if (cached && cached.windowEnd > now) {
44
+ // Cache hit and window is still valid
45
+ currentCount = cached.count;
46
+ // For sliding window, we also need previous window's count
47
+ // This is stored in the cache with a special key
48
+ const prevCached = await cache.get(`${key}:prev`);
49
+ if (prevCached) {
50
+ previousCount = prevCached.count;
51
+ }
52
+ }
53
+ else {
54
+ // Cache miss or expired - check store
55
+ const stored = await store.get(key, userId);
56
+ if (stored && stored.windowEnd.getTime() > now) {
57
+ currentCount = stored.count;
58
+ }
59
+ }
60
+ // Calculate sliding window count
61
+ const slidingCount = calculateSlidingCount(currentCount, previousCount, windowMs, windowStart);
62
+ // Check if limited
63
+ const limited = slidingCount >= maxRequests;
64
+ const remaining = Math.max(0, maxRequests - slidingCount - (increment && !limited ? 1 : 0));
65
+ const resetAt = Math.ceil(windowEnd / 1000);
66
+ const retryAfter = Math.max(0, Math.ceil((windowEnd - now) / 1000));
67
+ // Increment if requested and not limited
68
+ if (increment && !limited) {
69
+ // Check if we're in a new window - if so, save old count as previous
70
+ if (cached && cached.windowStart !== windowStart && cached.windowStart > 0) {
71
+ // Window rolled over - save old window's data as previous
72
+ const prevCached = {
73
+ count: cached.count,
74
+ maxRequests,
75
+ windowStart: cached.windowStart,
76
+ windowEnd: cached.windowEnd,
77
+ strategy: 'sliding-window',
78
+ };
79
+ // Save previous window for overlap calculation (keep for 2x window duration)
80
+ await cache.set(`${key}:prev`, prevCached, windowMs * 2);
81
+ }
82
+ // Increment in store
83
+ const updated = await store.increment(key, {
84
+ maxRequests,
85
+ windowMs,
86
+ strategy: 'sliding-window',
87
+ userId,
88
+ tenantId,
89
+ ipAddress,
90
+ amount: 1,
91
+ });
92
+ // Update cache with current window
93
+ const newCached = {
94
+ count: updated.count,
95
+ maxRequests,
96
+ windowStart,
97
+ windowEnd,
98
+ strategy: 'sliding-window',
99
+ };
100
+ await cache.set(key, newCached, windowMs);
101
+ return {
102
+ limited: false,
103
+ current: updated.count,
104
+ limit: maxRequests,
105
+ remaining: Math.max(0, maxRequests - updated.count),
106
+ resetAt,
107
+ retryAfter,
108
+ };
109
+ }
110
+ // Return status without incrementing
111
+ return {
112
+ limited,
113
+ current: slidingCount,
114
+ limit: maxRequests,
115
+ remaining,
116
+ resetAt,
117
+ retryAfter,
118
+ };
119
+ },
120
+ };
121
+ }
122
+ //# sourceMappingURL=sliding-window.js.map