@qwickapps/server 1.7.0 → 1.7.2

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 (335) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +13 -116
  3. package/dist/src/core/control-panel.d.ts.map +1 -1
  4. package/dist/src/core/control-panel.js +6 -4
  5. package/dist/src/core/control-panel.js.map +1 -1
  6. package/dist/src/core/gateway.d.ts.map +1 -1
  7. package/dist/src/core/gateway.js +24 -2
  8. package/dist/src/core/gateway.js.map +1 -1
  9. package/dist/src/core/plugin-registry.d.ts +15 -2
  10. package/dist/src/core/plugin-registry.d.ts.map +1 -1
  11. package/dist/src/core/plugin-registry.js.map +1 -1
  12. package/dist/src/index.d.ts +2 -2
  13. package/dist/src/index.d.ts.map +1 -1
  14. package/dist/src/index.js +9 -3
  15. package/dist/src/index.js.map +1 -1
  16. package/dist/src/plugins/api-keys/api-keys-plugin.d.ts +5 -2
  17. package/dist/src/plugins/api-keys/api-keys-plugin.d.ts.map +1 -1
  18. package/dist/src/plugins/api-keys/api-keys-plugin.js +61 -19
  19. package/dist/src/plugins/api-keys/api-keys-plugin.js.map +1 -1
  20. package/dist/src/plugins/api-keys/index.d.ts +0 -4
  21. package/dist/src/plugins/api-keys/index.d.ts.map +1 -1
  22. package/dist/src/plugins/api-keys/index.js +2 -3
  23. package/dist/src/plugins/api-keys/index.js.map +1 -1
  24. package/dist/src/plugins/api-keys/stores/postgres-store.d.ts.map +1 -1
  25. package/dist/src/plugins/api-keys/stores/postgres-store.js +29 -0
  26. package/dist/src/plugins/api-keys/stores/postgres-store.js.map +1 -1
  27. package/dist/src/plugins/api-keys/types.d.ts +9 -3
  28. package/dist/src/plugins/api-keys/types.d.ts.map +1 -1
  29. package/dist/src/plugins/api-keys/types.js.map +1 -1
  30. package/dist/src/plugins/auth/auth-plugin.d.ts.map +1 -1
  31. package/dist/src/plugins/auth/auth-plugin.js +4 -2
  32. package/dist/src/plugins/auth/auth-plugin.js.map +1 -1
  33. package/dist/src/plugins/auth/env-config.d.ts.map +1 -1
  34. package/dist/src/plugins/auth/env-config.js +1 -0
  35. package/dist/src/plugins/auth/env-config.js.map +1 -1
  36. package/dist/src/plugins/auth/index.d.ts +0 -4
  37. package/dist/src/plugins/auth/index.d.ts.map +1 -1
  38. package/dist/src/plugins/auth/index.js +2 -3
  39. package/dist/src/plugins/auth/index.js.map +1 -1
  40. package/dist/src/plugins/bans/bans-plugin.d.ts +5 -2
  41. package/dist/src/plugins/bans/bans-plugin.d.ts.map +1 -1
  42. package/dist/src/plugins/bans/bans-plugin.js +71 -25
  43. package/dist/src/plugins/bans/bans-plugin.js.map +1 -1
  44. package/dist/src/plugins/bans/index.d.ts +1 -5
  45. package/dist/src/plugins/bans/index.d.ts.map +1 -1
  46. package/dist/src/plugins/bans/index.js +3 -4
  47. package/dist/src/plugins/bans/index.js.map +1 -1
  48. package/dist/src/plugins/bans/stores/in-memory-store.d.ts +34 -0
  49. package/dist/src/plugins/bans/stores/in-memory-store.d.ts.map +1 -0
  50. package/dist/src/plugins/bans/stores/in-memory-store.js +97 -0
  51. package/dist/src/plugins/bans/stores/in-memory-store.js.map +1 -0
  52. package/dist/src/plugins/bans/stores/index.d.ts +1 -0
  53. package/dist/src/plugins/bans/stores/index.d.ts.map +1 -1
  54. package/dist/src/plugins/bans/stores/index.js +1 -0
  55. package/dist/src/plugins/bans/stores/index.js.map +1 -1
  56. package/dist/src/plugins/bans/types.d.ts +13 -6
  57. package/dist/src/plugins/bans/types.d.ts.map +1 -1
  58. package/dist/src/plugins/cache-plugin.d.ts +35 -16
  59. package/dist/src/plugins/cache-plugin.d.ts.map +1 -1
  60. package/dist/src/plugins/cache-plugin.js +299 -20
  61. package/dist/src/plugins/cache-plugin.js.map +1 -1
  62. package/dist/src/plugins/cms/cms-plugin.d.ts.map +1 -1
  63. package/dist/src/plugins/cms/cms-plugin.js +3 -1
  64. package/dist/src/plugins/cms/cms-plugin.js.map +1 -1
  65. package/dist/src/plugins/devices/devices-plugin.d.ts +5 -2
  66. package/dist/src/plugins/devices/devices-plugin.d.ts.map +1 -1
  67. package/dist/src/plugins/devices/devices-plugin.js +62 -26
  68. package/dist/src/plugins/devices/devices-plugin.js.map +1 -1
  69. package/dist/src/plugins/devices/index.d.ts +0 -4
  70. package/dist/src/plugins/devices/index.d.ts.map +1 -1
  71. package/dist/src/plugins/devices/index.js +2 -3
  72. package/dist/src/plugins/devices/index.js.map +1 -1
  73. package/dist/src/plugins/entitlements/entitlements-plugin.d.ts +5 -2
  74. package/dist/src/plugins/entitlements/entitlements-plugin.d.ts.map +1 -1
  75. package/dist/src/plugins/entitlements/entitlements-plugin.js +78 -41
  76. package/dist/src/plugins/entitlements/entitlements-plugin.js.map +1 -1
  77. package/dist/src/plugins/entitlements/index.d.ts +1 -5
  78. package/dist/src/plugins/entitlements/index.d.ts.map +1 -1
  79. package/dist/src/plugins/entitlements/index.js +3 -4
  80. package/dist/src/plugins/entitlements/index.js.map +1 -1
  81. package/dist/src/plugins/entitlements/sources/in-memory-source.d.ts +9 -0
  82. package/dist/src/plugins/entitlements/sources/in-memory-source.d.ts.map +1 -0
  83. package/dist/src/plugins/entitlements/sources/in-memory-source.js +65 -0
  84. package/dist/src/plugins/entitlements/sources/in-memory-source.js.map +1 -0
  85. package/dist/src/plugins/entitlements/sources/index.d.ts +1 -0
  86. package/dist/src/plugins/entitlements/sources/index.d.ts.map +1 -1
  87. package/dist/src/plugins/entitlements/sources/index.js +1 -0
  88. package/dist/src/plugins/entitlements/sources/index.js.map +1 -1
  89. package/dist/src/plugins/entitlements/types.d.ts +9 -2
  90. package/dist/src/plugins/entitlements/types.d.ts.map +1 -1
  91. package/dist/src/plugins/health-plugin.d.ts.map +1 -1
  92. package/dist/src/plugins/health-plugin.js +1 -0
  93. package/dist/src/plugins/health-plugin.js.map +1 -1
  94. package/dist/src/plugins/index.d.ts +4 -4
  95. package/dist/src/plugins/index.d.ts.map +1 -1
  96. package/dist/src/plugins/index.js +4 -4
  97. package/dist/src/plugins/index.js.map +1 -1
  98. package/dist/src/plugins/logs-plugin.d.ts.map +1 -1
  99. package/dist/src/plugins/logs-plugin.js +49 -1
  100. package/dist/src/plugins/logs-plugin.js.map +1 -1
  101. package/dist/src/plugins/maintenance-plugin.d.ts.map +1 -1
  102. package/dist/src/plugins/maintenance-plugin.js +39 -0
  103. package/dist/src/plugins/maintenance-plugin.js.map +1 -1
  104. package/dist/src/plugins/notifications/index.d.ts +0 -4
  105. package/dist/src/plugins/notifications/index.d.ts.map +1 -1
  106. package/dist/src/plugins/notifications/index.js +2 -3
  107. package/dist/src/plugins/notifications/index.js.map +1 -1
  108. package/dist/src/plugins/notifications/notifications-plugin.d.ts +5 -2
  109. package/dist/src/plugins/notifications/notifications-plugin.d.ts.map +1 -1
  110. package/dist/src/plugins/notifications/notifications-plugin.js +46 -13
  111. package/dist/src/plugins/notifications/notifications-plugin.js.map +1 -1
  112. package/dist/src/plugins/parental/index.d.ts +0 -4
  113. package/dist/src/plugins/parental/index.d.ts.map +1 -1
  114. package/dist/src/plugins/parental/index.js +2 -3
  115. package/dist/src/plugins/parental/index.js.map +1 -1
  116. package/dist/src/plugins/parental/parental-plugin.d.ts +5 -2
  117. package/dist/src/plugins/parental/parental-plugin.d.ts.map +1 -1
  118. package/dist/src/plugins/parental/parental-plugin.js +60 -24
  119. package/dist/src/plugins/parental/parental-plugin.js.map +1 -1
  120. package/dist/src/plugins/postgres-plugin.d.ts +3 -1
  121. package/dist/src/plugins/postgres-plugin.d.ts.map +1 -1
  122. package/dist/src/plugins/postgres-plugin.js +18 -8
  123. package/dist/src/plugins/postgres-plugin.js.map +1 -1
  124. package/dist/src/plugins/preferences/index.d.ts +0 -4
  125. package/dist/src/plugins/preferences/index.d.ts.map +1 -1
  126. package/dist/src/plugins/preferences/index.js +2 -3
  127. package/dist/src/plugins/preferences/index.js.map +1 -1
  128. package/dist/src/plugins/preferences/preferences-plugin.d.ts +5 -2
  129. package/dist/src/plugins/preferences/preferences-plugin.d.ts.map +1 -1
  130. package/dist/src/plugins/preferences/preferences-plugin.js +63 -19
  131. package/dist/src/plugins/preferences/preferences-plugin.js.map +1 -1
  132. package/dist/src/plugins/profiles/index.d.ts +0 -4
  133. package/dist/src/plugins/profiles/index.d.ts.map +1 -1
  134. package/dist/src/plugins/profiles/index.js +2 -3
  135. package/dist/src/plugins/profiles/index.js.map +1 -1
  136. package/dist/src/plugins/profiles/profiles-plugin.d.ts +5 -2
  137. package/dist/src/plugins/profiles/profiles-plugin.d.ts.map +1 -1
  138. package/dist/src/plugins/profiles/profiles-plugin.js +60 -26
  139. package/dist/src/plugins/profiles/profiles-plugin.js.map +1 -1
  140. package/dist/src/plugins/profiles/types.d.ts +9 -2
  141. package/dist/src/plugins/profiles/types.d.ts.map +1 -1
  142. package/dist/src/plugins/qwickbrain/index.d.ts +0 -4
  143. package/dist/src/plugins/qwickbrain/index.d.ts.map +1 -1
  144. package/dist/src/plugins/qwickbrain/index.js +2 -3
  145. package/dist/src/plugins/qwickbrain/index.js.map +1 -1
  146. package/dist/src/plugins/qwickbrain/qwickbrain-plugin.d.ts.map +1 -1
  147. package/dist/src/plugins/qwickbrain/qwickbrain-plugin.js +117 -0
  148. package/dist/src/plugins/qwickbrain/qwickbrain-plugin.js.map +1 -1
  149. package/dist/src/plugins/rate-limit/index.d.ts +0 -4
  150. package/dist/src/plugins/rate-limit/index.d.ts.map +1 -1
  151. package/dist/src/plugins/rate-limit/index.js +2 -3
  152. package/dist/src/plugins/rate-limit/index.js.map +1 -1
  153. package/dist/src/plugins/subscriptions/index.d.ts +0 -4
  154. package/dist/src/plugins/subscriptions/index.d.ts.map +1 -1
  155. package/dist/src/plugins/subscriptions/index.js +2 -3
  156. package/dist/src/plugins/subscriptions/index.js.map +1 -1
  157. package/dist/src/plugins/subscriptions/subscriptions-plugin.d.ts +5 -2
  158. package/dist/src/plugins/subscriptions/subscriptions-plugin.d.ts.map +1 -1
  159. package/dist/src/plugins/subscriptions/subscriptions-plugin.js +63 -29
  160. package/dist/src/plugins/subscriptions/subscriptions-plugin.js.map +1 -1
  161. package/dist/src/plugins/subscriptions/types.d.ts +8 -2
  162. package/dist/src/plugins/subscriptions/types.d.ts.map +1 -1
  163. package/dist/src/plugins/tenants/index.d.ts +1 -1
  164. package/dist/src/plugins/tenants/index.d.ts.map +1 -1
  165. package/dist/src/plugins/tenants/index.js +1 -1
  166. package/dist/src/plugins/tenants/index.js.map +1 -1
  167. package/dist/src/plugins/tenants/stores/in-memory-store.d.ts +59 -0
  168. package/dist/src/plugins/tenants/stores/in-memory-store.d.ts.map +1 -0
  169. package/dist/src/plugins/tenants/stores/in-memory-store.js +257 -0
  170. package/dist/src/plugins/tenants/stores/in-memory-store.js.map +1 -0
  171. package/dist/src/plugins/tenants/stores/index.d.ts +8 -0
  172. package/dist/src/plugins/tenants/stores/index.d.ts.map +1 -0
  173. package/dist/src/plugins/tenants/stores/index.js +8 -0
  174. package/dist/src/plugins/tenants/stores/index.js.map +1 -0
  175. package/dist/src/plugins/tenants/tenants-plugin.d.ts +5 -2
  176. package/dist/src/plugins/tenants/tenants-plugin.d.ts.map +1 -1
  177. package/dist/src/plugins/tenants/tenants-plugin.js +93 -60
  178. package/dist/src/plugins/tenants/tenants-plugin.js.map +1 -1
  179. package/dist/src/plugins/tenants/types.d.ts +8 -2
  180. package/dist/src/plugins/tenants/types.d.ts.map +1 -1
  181. package/dist/src/plugins/usage/index.d.ts +0 -4
  182. package/dist/src/plugins/usage/index.d.ts.map +1 -1
  183. package/dist/src/plugins/usage/index.js +2 -3
  184. package/dist/src/plugins/usage/index.js.map +1 -1
  185. package/dist/src/plugins/usage/usage-plugin.d.ts +5 -2
  186. package/dist/src/plugins/usage/usage-plugin.d.ts.map +1 -1
  187. package/dist/src/plugins/usage/usage-plugin.js +57 -23
  188. package/dist/src/plugins/usage/usage-plugin.js.map +1 -1
  189. package/dist/src/plugins/users/index.d.ts +1 -1
  190. package/dist/src/plugins/users/index.d.ts.map +1 -1
  191. package/dist/src/plugins/users/index.js +1 -1
  192. package/dist/src/plugins/users/index.js.map +1 -1
  193. package/dist/src/plugins/users/stores/in-memory-store.d.ts +36 -0
  194. package/dist/src/plugins/users/stores/in-memory-store.d.ts.map +1 -0
  195. package/dist/src/plugins/users/stores/in-memory-store.js +122 -0
  196. package/dist/src/plugins/users/stores/in-memory-store.js.map +1 -0
  197. package/dist/src/plugins/users/stores/index.d.ts +1 -0
  198. package/dist/src/plugins/users/stores/index.d.ts.map +1 -1
  199. package/dist/src/plugins/users/stores/index.js +1 -0
  200. package/dist/src/plugins/users/stores/index.js.map +1 -1
  201. package/dist/src/plugins/users/types.d.ts +7 -2
  202. package/dist/src/plugins/users/types.d.ts.map +1 -1
  203. package/dist/src/plugins/users/users-plugin.d.ts +5 -2
  204. package/dist/src/plugins/users/users-plugin.d.ts.map +1 -1
  205. package/dist/src/plugins/users/users-plugin.js +56 -23
  206. package/dist/src/plugins/users/users-plugin.js.map +1 -1
  207. package/dist/ui/src/api/controlPanelApi.d.ts +10 -1
  208. package/dist/ui/src/api/controlPanelApi.d.ts.map +1 -1
  209. package/dist/ui/src/api/controlPanelApi.js.map +1 -1
  210. package/dist/ui/src/dashboard/PluginWidgetRenderer.d.ts +3 -1
  211. package/dist/ui/src/dashboard/PluginWidgetRenderer.d.ts.map +1 -1
  212. package/dist/ui/src/dashboard/PluginWidgetRenderer.js +5 -1
  213. package/dist/ui/src/dashboard/PluginWidgetRenderer.js.map +1 -1
  214. package/dist/ui/src/dashboard/builtInWidgets.d.ts.map +1 -1
  215. package/dist/ui/src/dashboard/builtInWidgets.js +13 -1
  216. package/dist/ui/src/dashboard/builtInWidgets.js.map +1 -1
  217. package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.d.ts +11 -0
  218. package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.d.ts.map +1 -0
  219. package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js +77 -0
  220. package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js.map +1 -0
  221. package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.d.ts +10 -0
  222. package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.d.ts.map +1 -0
  223. package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.js +14 -0
  224. package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.js.map +1 -0
  225. package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.d.ts +10 -0
  226. package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.d.ts.map +1 -0
  227. package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.js +14 -0
  228. package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.js.map +1 -0
  229. package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.d.ts +11 -0
  230. package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.d.ts.map +1 -0
  231. package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js +96 -0
  232. package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js.map +1 -0
  233. package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts +10 -0
  234. package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts.map +1 -0
  235. package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js +55 -0
  236. package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js.map +1 -0
  237. package/dist/ui/src/dashboard/widgets/ServiceControlWidget.d.ts +10 -0
  238. package/dist/ui/src/dashboard/widgets/ServiceControlWidget.d.ts.map +1 -0
  239. package/dist/ui/src/dashboard/widgets/ServiceControlWidget.js +14 -0
  240. package/dist/ui/src/dashboard/widgets/ServiceControlWidget.js.map +1 -0
  241. package/dist/ui/src/dashboard/widgets/index.d.ts +6 -0
  242. package/dist/ui/src/dashboard/widgets/index.d.ts.map +1 -1
  243. package/dist/ui/src/dashboard/widgets/index.js +6 -0
  244. package/dist/ui/src/dashboard/widgets/index.js.map +1 -1
  245. package/dist/ui/src/pages/DashboardPage.js +1 -1
  246. package/dist/ui/src/pages/DashboardPage.js.map +1 -1
  247. package/dist-ui/assets/index-0gzisPdy.js +528 -0
  248. package/dist-ui/assets/{index-lm1yX6UD.js.map → index-0gzisPdy.js.map} +1 -1
  249. package/dist-ui/index.html +1 -1
  250. package/dist-ui-lib/index.js +3109 -2774
  251. package/dist-ui-lib/index.js.map +1 -1
  252. package/dist-ui-lib/src/api/controlPanelApi.d.ts +10 -1
  253. package/dist-ui-lib/src/dashboard/PluginWidgetRenderer.d.ts +3 -1
  254. package/dist-ui-lib/src/dashboard/widgets/CacheMaintenanceWidget.d.ts +10 -0
  255. package/dist-ui-lib/src/dashboard/widgets/DatabaseOpsWidget.d.ts +9 -0
  256. package/dist-ui-lib/src/dashboard/widgets/EnvironmentConfigWidget.d.ts +9 -0
  257. package/dist-ui-lib/src/dashboard/widgets/LogsMaintenanceWidget.d.ts +10 -0
  258. package/dist-ui-lib/src/dashboard/widgets/SeedManagementWidget.d.ts +9 -0
  259. package/dist-ui-lib/src/dashboard/widgets/ServiceControlWidget.d.ts +9 -0
  260. package/dist-ui-lib/src/dashboard/widgets/index.d.ts +6 -0
  261. package/package.json +12 -6
  262. package/src/core/control-panel.ts +6 -4
  263. package/src/core/gateway.ts +25 -2
  264. package/src/core/plugin-registry.ts +15 -2
  265. package/src/index.ts +53 -0
  266. package/src/plugins/api-keys/api-keys-plugin.ts +64 -20
  267. package/src/plugins/api-keys/index.ts +2 -5
  268. package/src/plugins/api-keys/stores/postgres-store.ts +30 -0
  269. package/src/plugins/api-keys/types.ts +9 -3
  270. package/src/plugins/auth/auth-plugin.ts +4 -2
  271. package/src/plugins/auth/env-config.ts +1 -0
  272. package/src/plugins/auth/index.ts +3 -5
  273. package/src/plugins/bans/bans-plugin.ts +71 -26
  274. package/src/plugins/bans/index.ts +4 -6
  275. package/src/plugins/bans/stores/in-memory-store.ts +106 -0
  276. package/src/plugins/bans/stores/index.ts +1 -0
  277. package/src/plugins/bans/types.ts +13 -6
  278. package/src/plugins/cache-plugin.test.ts +2 -2
  279. package/src/plugins/cache-plugin.ts +331 -30
  280. package/src/plugins/cms/cms-plugin.ts +3 -1
  281. package/src/plugins/devices/devices-plugin.ts +62 -27
  282. package/src/plugins/devices/index.ts +3 -5
  283. package/src/plugins/entitlements/entitlements-plugin.ts +81 -43
  284. package/src/plugins/entitlements/index.ts +4 -6
  285. package/src/plugins/entitlements/sources/in-memory-source.ts +76 -0
  286. package/src/plugins/entitlements/sources/index.ts +1 -0
  287. package/src/plugins/entitlements/types.ts +9 -2
  288. package/src/plugins/health-plugin.ts +1 -0
  289. package/src/plugins/index.ts +4 -1
  290. package/src/plugins/logs-plugin.ts +55 -1
  291. package/src/plugins/maintenance-plugin.ts +43 -0
  292. package/src/plugins/notifications/index.ts +3 -5
  293. package/src/plugins/notifications/notifications-plugin.ts +49 -19
  294. package/src/plugins/parental/index.ts +3 -5
  295. package/src/plugins/parental/parental-plugin.ts +63 -25
  296. package/src/plugins/postgres-plugin.test.ts +2 -2
  297. package/src/plugins/postgres-plugin.ts +20 -9
  298. package/src/plugins/preferences/index.ts +3 -5
  299. package/src/plugins/preferences/preferences-plugin.ts +66 -20
  300. package/src/plugins/profiles/index.ts +3 -5
  301. package/src/plugins/profiles/profiles-plugin.ts +60 -27
  302. package/src/plugins/profiles/types.ts +9 -2
  303. package/src/plugins/qwickbrain/index.ts +3 -5
  304. package/src/plugins/qwickbrain/qwickbrain-plugin.ts +135 -0
  305. package/src/plugins/rate-limit/index.ts +3 -5
  306. package/src/plugins/subscriptions/index.ts +3 -5
  307. package/src/plugins/subscriptions/subscriptions-plugin.ts +63 -30
  308. package/src/plugins/subscriptions/types.ts +8 -2
  309. package/src/plugins/tenants/index.ts +1 -1
  310. package/src/plugins/tenants/stores/in-memory-store.ts +335 -0
  311. package/src/plugins/tenants/stores/index.ts +13 -0
  312. package/src/plugins/tenants/tenants-plugin.ts +97 -62
  313. package/src/plugins/tenants/types.ts +8 -2
  314. package/src/plugins/usage/index.ts +3 -5
  315. package/src/plugins/usage/usage-plugin.ts +60 -26
  316. package/src/plugins/users/index.ts +1 -1
  317. package/src/plugins/users/stores/in-memory-store.ts +140 -0
  318. package/src/plugins/users/stores/index.ts +1 -0
  319. package/src/plugins/users/types.ts +7 -2
  320. package/src/plugins/users/users-plugin.ts +56 -24
  321. package/src/testing/index.ts +1 -0
  322. package/src/testing/pg-mem-pool.ts +33 -0
  323. package/ui/src/api/controlPanelApi.ts +10 -1
  324. package/ui/src/dashboard/PluginWidgetRenderer.tsx +8 -0
  325. package/ui/src/dashboard/builtInWidgets.tsx +19 -1
  326. package/ui/src/dashboard/widgets/CacheMaintenanceWidget.tsx +195 -0
  327. package/ui/src/dashboard/widgets/DatabaseOpsWidget.tsx +29 -0
  328. package/ui/src/dashboard/widgets/EnvironmentConfigWidget.tsx +29 -0
  329. package/ui/src/dashboard/widgets/LogsMaintenanceWidget.tsx +247 -0
  330. package/ui/src/dashboard/widgets/SeedManagementWidget.tsx +128 -0
  331. package/ui/src/dashboard/widgets/ServiceControlWidget.tsx +29 -0
  332. package/ui/src/dashboard/widgets/index.ts +6 -0
  333. package/ui/src/pages/DashboardPage.tsx +2 -2
  334. package/ui/src/pages/MaintenancePage.tsx +1 -1
  335. package/dist-ui/assets/index-lm1yX6UD.js +0 -528
@@ -1,18 +1,20 @@
1
1
  /**
2
2
  * Cache Plugin
3
3
  *
4
- * Provides Redis caching capabilities with connection pooling and health checks.
5
- * Wraps the 'ioredis' library with a simple, reusable interface.
4
+ * Provides caching capabilities with Redis or in-memory storage.
5
+ * Supports Redis via 'ioredis' library or zero-dependency in-memory LRU cache.
6
6
  *
7
7
  * ## Features
8
- * - Connection management with automatic reconnection
8
+ * - Dual-mode: Redis (persistent, distributed) or Memory (fast, local)
9
+ * - Connection management with automatic reconnection (Redis)
10
+ * - LRU eviction with TTL expiration (Memory)
9
11
  * - Key prefixing for multi-tenant/multi-app scenarios
10
- * - TTL-based caching with setex/get operations
12
+ * - TTL-based caching with get/set operations
11
13
  * - Automatic health checks
12
14
  * - Multiple named instances support
13
15
  * - Graceful shutdown
14
16
  *
15
- * ## Usage
17
+ * ## Usage (Redis)
16
18
  *
17
19
  * ```typescript
18
20
  * import { createGateway, createCachePlugin, getCache } from '@qwickapps/server';
@@ -21,6 +23,7 @@
21
23
  * // ... config
22
24
  * plugins: [
23
25
  * createCachePlugin({
26
+ * type: 'redis',
24
27
  * url: process.env.REDIS_URL,
25
28
  * keyPrefix: 'myapp:',
26
29
  * }),
@@ -33,12 +36,24 @@
33
36
  * const user = await cache.get<User>('user:123');
34
37
  * ```
35
38
  *
39
+ * ## Usage (In-Memory)
40
+ *
41
+ * ```typescript
42
+ * // Zero external dependencies - perfect for demos and testing
43
+ * createCachePlugin({
44
+ * type: 'memory',
45
+ * keyPrefix: 'demo:',
46
+ * defaultTtl: 3600,
47
+ * maxMemoryEntries: 5000,
48
+ * })
49
+ * ```
50
+ *
36
51
  * ## Multiple Caches
37
52
  *
38
53
  * ```typescript
39
54
  * // Register multiple caches with different names
40
55
  * createCachePlugin({ url: primaryUrl, keyPrefix: 'session:' }, 'sessions');
41
- * createCachePlugin({ url: cacheUrl, keyPrefix: 'cache:' }, 'content');
56
+ * createCachePlugin({ type: 'memory', keyPrefix: 'cache:' }, 'content');
42
57
  *
43
58
  * // Access by name
44
59
  * const sessions = getCache('sessions');
@@ -48,6 +63,7 @@
48
63
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
49
64
  */
50
65
 
66
+ import type { Request, Response } from 'express';
51
67
  import type { Plugin, PluginConfig, PluginRegistry } from '../core/plugin-registry.js';
52
68
 
53
69
  // Dynamic import for ioredis (optional peer dependency)
@@ -58,8 +74,11 @@ type RedisOptions = import('ioredis').RedisOptions;
58
74
  * Configuration for the cache plugin
59
75
  */
60
76
  export interface CachePluginConfig {
61
- /** Redis connection URL (e.g., redis://localhost:6379) */
62
- url: string;
77
+ /** Cache type: 'redis' or 'memory' (default: 'redis' if url provided, 'memory' otherwise) */
78
+ type?: 'redis' | 'memory';
79
+
80
+ /** Redis connection URL (required for type='redis', e.g., redis://localhost:6379) */
81
+ url?: string;
63
82
 
64
83
  /** Key prefix for all cache operations (default: '') */
65
84
  keyPrefix?: string;
@@ -67,34 +86,37 @@ export interface CachePluginConfig {
67
86
  /** Default TTL in seconds for set operations (default: 3600 = 1 hour) */
68
87
  defaultTtl?: number;
69
88
 
70
- /** Maximum number of retry attempts (default: 3) */
89
+ /** Maximum number of entries for memory cache (default: 10000, only used for type='memory') */
90
+ maxMemoryEntries?: number;
91
+
92
+ /** Maximum number of retry attempts (default: 3, only used for type='redis') */
71
93
  maxRetries?: number;
72
94
 
73
- /** Retry delay in milliseconds (default: 1000) */
95
+ /** Retry delay in milliseconds (default: 1000, only used for type='redis') */
74
96
  retryDelayMs?: number;
75
97
 
76
- /** Connection timeout in milliseconds (default: 5000) */
98
+ /** Connection timeout in milliseconds (default: 5000, only used for type='redis') */
77
99
  connectTimeoutMs?: number;
78
100
 
79
- /** Command timeout in milliseconds (default: 5000) */
101
+ /** Command timeout in milliseconds (default: 5000, only used for type='redis') */
80
102
  commandTimeoutMs?: number;
81
103
 
82
104
  /** Register a health check for this cache (default: true) */
83
105
  healthCheck?: boolean;
84
106
 
85
- /** Name for the health check (default: 'redis') */
107
+ /** Name for the health check (default: 'redis' or 'memory') */
86
108
  healthCheckName?: string;
87
109
 
88
110
  /** Health check interval in milliseconds (default: 30000) */
89
111
  healthCheckInterval?: number;
90
112
 
91
- /** Called when connection is ready */
113
+ /** Called when connection is ready (only used for type='redis') */
92
114
  onConnect?: () => void;
93
115
 
94
- /** Called on connection errors */
116
+ /** Called on connection errors (only used for type='redis') */
95
117
  onError?: (error: Error) => void;
96
118
 
97
- /** Enable lazy connect - don't connect until first command (default: false) */
119
+ /** Enable lazy connect - don't connect until first command (default: false, only used for type='redis') */
98
120
  lazyConnect?: boolean;
99
121
  }
100
122
 
@@ -219,6 +241,94 @@ export interface CacheInstance {
219
241
  close(): Promise<void>;
220
242
  }
221
243
 
244
+ /**
245
+ * Simple LRU Cache implementation for in-memory fallback
246
+ */
247
+ class LRUCache<T> {
248
+ private cache = new Map<string, { value: T; expiresAt: number }>();
249
+ private maxSize: number;
250
+
251
+ constructor(maxSize: number) {
252
+ this.maxSize = maxSize;
253
+ }
254
+
255
+ get(key: string): T | null {
256
+ const entry = this.cache.get(key);
257
+ if (!entry) return null;
258
+
259
+ // Check expiration
260
+ if (entry.expiresAt <= Date.now()) {
261
+ this.cache.delete(key);
262
+ return null;
263
+ }
264
+
265
+ // Move to end (most recently used)
266
+ this.cache.delete(key);
267
+ this.cache.set(key, entry);
268
+
269
+ return entry.value;
270
+ }
271
+
272
+ set(key: string, value: T, ttlMs: number): void {
273
+ // Remove oldest entries if at capacity
274
+ while (this.cache.size >= this.maxSize) {
275
+ const firstKey = this.cache.keys().next().value;
276
+ if (firstKey) {
277
+ this.cache.delete(firstKey);
278
+ } else {
279
+ break;
280
+ }
281
+ }
282
+
283
+ this.cache.set(key, {
284
+ value,
285
+ expiresAt: Date.now() + ttlMs,
286
+ });
287
+ }
288
+
289
+ delete(key: string): boolean {
290
+ return this.cache.delete(key);
291
+ }
292
+
293
+ has(key: string): boolean {
294
+ const entry = this.cache.get(key);
295
+ if (!entry) return false;
296
+ if (entry.expiresAt <= Date.now()) {
297
+ this.cache.delete(key);
298
+ return false;
299
+ }
300
+ return true;
301
+ }
302
+
303
+ keys(pattern: string): string[] {
304
+ const regex = new RegExp(pattern.replace(/\*/g, '.*'));
305
+ const result: string[] = [];
306
+ for (const key of this.cache.keys()) {
307
+ if (regex.test(key)) {
308
+ const entry = this.cache.get(key);
309
+ if (entry && entry.expiresAt > Date.now()) {
310
+ result.push(key);
311
+ }
312
+ }
313
+ }
314
+ return result;
315
+ }
316
+
317
+ size(): number {
318
+ // Clean up expired entries
319
+ for (const [key, entry] of this.cache.entries()) {
320
+ if (entry.expiresAt <= Date.now()) {
321
+ this.cache.delete(key);
322
+ }
323
+ }
324
+ return this.cache.size;
325
+ }
326
+
327
+ clear(): void {
328
+ this.cache.clear();
329
+ }
330
+ }
331
+
222
332
  // Global registry of cache instances by name
223
333
  const instances = new Map<string, CacheInstance>();
224
334
 
@@ -274,7 +384,11 @@ export function createCachePlugin(
274
384
  config: CachePluginConfig,
275
385
  instanceName = 'default'
276
386
  ): Plugin {
387
+ // Determine cache type
388
+ const cacheType = config.type || (config.url ? 'redis' : 'memory');
389
+
277
390
  let client: Redis | null = null;
391
+ let lru: LRUCache<string> | null = null;
278
392
  const prefix = config.keyPrefix ?? '';
279
393
  const defaultTtl = config.defaultTtl ?? 3600;
280
394
  const pluginId = `cache:${instanceName}`;
@@ -283,7 +397,129 @@ export function createCachePlugin(
283
397
  const unprefixKey = (key: string): string =>
284
398
  prefix && key.startsWith(prefix) ? key.slice(prefix.length) : key;
285
399
 
286
- const createInstance = async (): Promise<CacheInstance> => {
400
+ const createMemoryInstance = (): CacheInstance => {
401
+ const maxEntries = config.maxMemoryEntries || 10000;
402
+ lru = new LRUCache<string>(maxEntries);
403
+
404
+ return {
405
+ async get<T = unknown>(key: string): Promise<T | null> {
406
+ if (!lru) throw new Error('Cache not initialized');
407
+ const value = lru.get(prefixKey(key));
408
+ if (value === null) return null;
409
+ try {
410
+ return JSON.parse(value) as T;
411
+ } catch {
412
+ return value as unknown as T;
413
+ }
414
+ },
415
+
416
+ async getRaw(key: string): Promise<string | null> {
417
+ if (!lru) throw new Error('Cache not initialized');
418
+ return lru.get(prefixKey(key));
419
+ },
420
+
421
+ async set<T = unknown>(key: string, value: T, ttlSeconds?: number): Promise<void> {
422
+ if (!lru) throw new Error('Cache not initialized');
423
+ const ttl = (ttlSeconds ?? defaultTtl) * 1000; // Convert to ms
424
+ const serialized = typeof value === 'string' ? value : JSON.stringify(value);
425
+ lru.set(prefixKey(key), serialized, ttl);
426
+ },
427
+
428
+ async setRaw(key: string, value: string, ttlSeconds?: number): Promise<void> {
429
+ if (!lru) throw new Error('Cache not initialized');
430
+ const ttl = (ttlSeconds ?? defaultTtl) * 1000;
431
+ lru.set(prefixKey(key), value, ttl);
432
+ },
433
+
434
+ async delete(key: string): Promise<boolean> {
435
+ if (!lru) throw new Error('Cache not initialized');
436
+ return lru.delete(prefixKey(key));
437
+ },
438
+
439
+ async deletePattern(pattern: string): Promise<number> {
440
+ if (!lru) throw new Error('Cache not initialized');
441
+ const keys = lru.keys(prefixKey(pattern));
442
+ keys.forEach(k => lru!.delete(k));
443
+ return keys.length;
444
+ },
445
+
446
+ async exists(key: string): Promise<boolean> {
447
+ if (!lru) throw new Error('Cache not initialized');
448
+ return lru.has(prefixKey(key));
449
+ },
450
+
451
+ async expire(key: string, ttlSeconds: number): Promise<boolean> {
452
+ if (!lru) throw new Error('Cache not initialized');
453
+ const value = lru.get(prefixKey(key));
454
+ if (value === null) return false;
455
+ lru.set(prefixKey(key), value, ttlSeconds * 1000);
456
+ return true;
457
+ },
458
+
459
+ async ttl(key: string): Promise<number> {
460
+ if (!lru) throw new Error('Cache not initialized');
461
+ // Memory cache doesn't track TTL separately
462
+ return lru.has(prefixKey(key)) ? -1 : -2;
463
+ },
464
+
465
+ async incr(key: string, delta = 1): Promise<number> {
466
+ if (!lru) throw new Error('Cache not initialized');
467
+ const current = lru.get(prefixKey(key));
468
+ const value = current ? parseInt(current, 10) + delta : delta;
469
+ lru.set(prefixKey(key), value.toString(), defaultTtl * 1000);
470
+ return value;
471
+ },
472
+
473
+ async keys(pattern: string): Promise<string[]> {
474
+ if (!lru) throw new Error('Cache not initialized');
475
+ return lru.keys(prefixKey(pattern)).map(unprefixKey);
476
+ },
477
+
478
+ async scanKeys(pattern: string): Promise<string[]> {
479
+ // Memory cache can use same implementation as keys()
480
+ return this.keys(pattern);
481
+ },
482
+
483
+ async flush(): Promise<number> {
484
+ if (!lru) throw new Error('Cache not initialized');
485
+ if (!prefix) {
486
+ throw new Error('Cannot flush without a keyPrefix configured');
487
+ }
488
+ const keys = lru.keys(`${prefix}*`);
489
+ keys.forEach(k => lru!.delete(k));
490
+ return keys.length;
491
+ },
492
+
493
+ async getStats(): Promise<{ connected: boolean; keyCount: number; usedMemory?: string }> {
494
+ if (!lru) {
495
+ return { connected: false, keyCount: 0 };
496
+ }
497
+ return {
498
+ connected: true,
499
+ keyCount: lru.size(),
500
+ usedMemory: undefined,
501
+ };
502
+ },
503
+
504
+ getClient(): Redis {
505
+ throw new Error('Memory cache does not have a Redis client');
506
+ },
507
+
508
+ async close(): Promise<void> {
509
+ if (lru) {
510
+ lru.clear();
511
+ lru = null;
512
+ }
513
+ },
514
+ };
515
+ };
516
+
517
+ const createRedisInstance = async (): Promise<CacheInstance> => {
518
+ // Validate Redis URL is provided
519
+ if (!config.url) {
520
+ throw new Error('Redis URL is required for Redis cache type');
521
+ }
522
+
287
523
  // Dynamic import of ioredis
288
524
  const { default: Redis } = await import('ioredis');
289
525
 
@@ -468,42 +704,50 @@ export function createCachePlugin(
468
704
 
469
705
  return {
470
706
  id: pluginId,
471
- name: `Redis Cache (${instanceName})`,
707
+ name: `${cacheType === 'memory' ? 'Memory' : 'Redis'} Cache (${instanceName})`,
472
708
  version: '1.0.0',
473
709
 
474
710
  async onStart(_pluginConfig: PluginConfig, registry: PluginRegistry): Promise<void> {
475
711
  const logger = registry.getLogger(pluginId);
476
712
 
477
- // Create and register the instance
478
- const instance = await createInstance();
713
+ // Create and register the instance based on type
714
+ const instance = cacheType === 'memory'
715
+ ? createMemoryInstance()
716
+ : await createRedisInstance();
479
717
  instances.set(instanceName, instance);
480
718
 
481
- // Test connection
482
- try {
483
- // Ping to verify connection
484
- await instance.getClient().ping();
485
- logger.debug(`Cache "${instanceName}" connected`);
486
- } catch (err) {
487
- logger.error(`Cache "${instanceName}" connection failed: ${err instanceof Error ? err.message : String(err)}`);
488
- throw err;
719
+ // Test connection (skip for memory, test for Redis)
720
+ if (cacheType === 'redis') {
721
+ try {
722
+ await instance.getClient().ping();
723
+ logger.debug(`Cache "${instanceName}" connected`);
724
+ } catch (err) {
725
+ logger.error(`Cache "${instanceName}" connection failed: ${err instanceof Error ? err.message : String(err)}`);
726
+ throw err;
727
+ }
728
+ } else {
729
+ logger.debug(`Cache "${instanceName}" initialized (in-memory)`);
489
730
  }
490
731
 
491
732
  // Register health check if enabled
492
733
  if (config.healthCheck !== false) {
493
734
  registry.registerHealthCheck({
494
- name: config.healthCheckName ?? 'redis',
735
+ name: config.healthCheckName ?? (cacheType === 'memory' ? 'memory-cache' : 'redis'),
495
736
  type: 'custom',
496
737
  interval: config.healthCheckInterval ?? 30000,
497
738
  timeout: 5000,
498
739
  check: async () => {
499
740
  const start = Date.now();
500
741
  try {
501
- await instance.getClient().ping();
742
+ if (cacheType === 'redis') {
743
+ await instance.getClient().ping();
744
+ }
502
745
  const stats = await instance.getStats();
503
746
  return {
504
747
  healthy: true,
505
748
  latency: Date.now() - start,
506
749
  details: {
750
+ type: cacheType,
507
751
  connected: stats.connected,
508
752
  keyCount: stats.keyCount,
509
753
  usedMemory: stats.usedMemory,
@@ -521,6 +765,63 @@ export function createCachePlugin(
521
765
  },
522
766
  });
523
767
  }
768
+
769
+ // Register maintenance routes (only for default instance to avoid conflicts)
770
+ if (instanceName === 'default') {
771
+ // GET /stats - Cache statistics
772
+ registry.addRoute({
773
+ method: 'get',
774
+ path: '/stats',
775
+ pluginId: 'cache',
776
+ handler: async (_req: Request, res: Response) => {
777
+ try {
778
+ const stats = await instance.getStats();
779
+ return res.json(stats);
780
+ } catch (error) {
781
+ logger.error('Failed to get cache stats', { error });
782
+ return res.status(500).json({
783
+ error: 'Failed to get cache stats',
784
+ message: error instanceof Error ? error.message : String(error),
785
+ });
786
+ }
787
+ },
788
+ });
789
+
790
+ // POST /flush - Clear cache
791
+ registry.addRoute({
792
+ method: 'post',
793
+ path: '/flush',
794
+ pluginId: 'cache',
795
+ handler: async (_req: Request, res: Response) => {
796
+ try {
797
+ const deletedCount = await instance.flush();
798
+ logger.info(`Flushed cache: ${deletedCount} keys deleted`);
799
+ return res.json({
800
+ success: true,
801
+ message: `Cache flushed successfully`,
802
+ deletedCount,
803
+ });
804
+ } catch (error) {
805
+ logger.error('Failed to flush cache', { error });
806
+ return res.status(500).json({
807
+ error: 'Failed to flush cache',
808
+ message: error instanceof Error ? error.message : String(error),
809
+ });
810
+ }
811
+ },
812
+ });
813
+
814
+ // Register maintenance widget
815
+ registry.addWidget({
816
+ id: 'cache-maintenance',
817
+ title: 'Cache Management',
818
+ component: 'CacheMaintenanceWidget',
819
+ type: 'maintenance',
820
+ priority: 60,
821
+ showByDefault: true,
822
+ pluginId: 'cache',
823
+ });
824
+ }
524
825
  },
525
826
 
526
827
  async onStop(): Promise<void> {
@@ -50,6 +50,7 @@ export function createCMSPlugin(config: CMSPluginConfig): Plugin {
50
50
  id: 'cms-status',
51
51
  title: 'Payload CMS',
52
52
  component: 'CMSStatusWidget',
53
+ type: 'status',
53
54
  priority: 15, // After ServiceHealthWidget (10)
54
55
  showByDefault: true,
55
56
  pluginId: 'cms',
@@ -62,8 +63,9 @@ export function createCMSPlugin(config: CMSPluginConfig): Plugin {
62
63
  id: 'cms-maintenance',
63
64
  title: 'CMS Service Control',
64
65
  component: 'CMSMaintenanceWidget',
66
+ type: 'maintenance',
65
67
  priority: 10,
66
- showByDefault: false, // Only shown on maintenance page
68
+ showByDefault: true, // Show by default on maintenance page
67
69
  pluginId: 'cms',
68
70
  });
69
71
  }
@@ -28,6 +28,9 @@ import {
28
28
  isTokenExpired,
29
29
  getTokenExpiration,
30
30
  } from './token-utils.js';
31
+ import { hasPostgres, getPostgres } from '../postgres-plugin.js';
32
+ import { postgresDeviceStore } from './stores/index.js';
33
+ import { computeDeviceAdapter } from './adapters/index.js';
31
34
 
32
35
  // Store instances for helper access
33
36
  let currentStore: DeviceStore | null = null;
@@ -35,16 +38,18 @@ let currentAdapter: DeviceAdapter | null = null;
35
38
  let currentConfig: DevicesPluginConfig | null = null;
36
39
 
37
40
  /**
38
- * Create the Devices plugin
41
+ * Create the Devices plugin with smart defaults
42
+ *
43
+ * Config is optional - plugin will use defaults and get dependencies from registry.
44
+ * Gracefully handles missing dependencies with clear log messages.
39
45
  */
40
- export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
41
- const debug = config.debug || false;
42
- const defaultTokenValidityDays = config.defaultTokenValidityDays || 90;
43
- const apiPrefix = config.api?.prefix || '/'; // Framework adds /devices prefix automatically
44
-
45
- function log(message: string, data?: Record<string, unknown>) {
46
- if (debug) {
47
- console.log(`[DevicesPlugin] ${message}`, data || '');
46
+ export function createDevicesPlugin(config: Partial<DevicesPluginConfig> = {}): Plugin {
47
+ function log(message: string, data?: Record<string, unknown>, isError = false) {
48
+ const prefix = '[DevicesPlugin]';
49
+ if (isError) {
50
+ console.error(`${prefix} ${message}`, data || '');
51
+ } else if (config.debug) {
52
+ console.log(`${prefix} ${message}`, data || '');
48
53
  }
49
54
  }
50
55
 
@@ -54,16 +59,46 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
54
59
  version: '1.0.0',
55
60
 
56
61
  async onStart(_pluginConfig: PluginConfig, registry: PluginRegistry): Promise<void> {
57
- log('Starting devices plugin', { adapter: config.adapter.name });
62
+ const logger = registry.getLogger('devices');
63
+
64
+ // Check for postgres in registry
65
+ if (!hasPostgres()) {
66
+ logger.warn('No Database! Devices plugin disabled.');
67
+ registry.registerHealthCheck({
68
+ name: 'devices-store',
69
+ type: 'custom',
70
+ check: async () => ({
71
+ healthy: false,
72
+ details: {
73
+ error: 'PostgreSQL not available',
74
+ state: 'disabled',
75
+ },
76
+ }),
77
+ });
78
+ return;
79
+ }
80
+
81
+ // Smart defaults - get dependencies from registry
82
+ const store = config.store ?? postgresDeviceStore({
83
+ pool: () => getPostgres().getPool(),
84
+ autoCreateTables: true,
85
+ });
86
+
87
+ const adapter = config.adapter ?? computeDeviceAdapter();
88
+ const debug = config.debug ?? false;
89
+ const defaultTokenValidityDays = config.defaultTokenValidityDays ?? 90;
90
+ const apiPrefix = config.api?.prefix ?? '/devices';
91
+
92
+ log('Starting devices plugin', { adapter: adapter.name });
58
93
 
59
94
  // Initialize the store (creates tables if needed)
60
- await config.store.initialize();
95
+ await store.initialize();
61
96
  log('Devices plugin migrations complete');
62
97
 
63
98
  // Store references for helper access
64
- currentStore = config.store;
65
- currentAdapter = config.adapter;
66
- currentConfig = config;
99
+ currentStore = store;
100
+ currentAdapter = adapter;
101
+ currentConfig = { ...config, store, adapter, debug, defaultTokenValidityDays };
67
102
 
68
103
  // Register health check
69
104
  registry.registerHealthCheck({
@@ -71,12 +106,12 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
71
106
  type: 'custom',
72
107
  check: async () => {
73
108
  try {
74
- await config.store.search({ limit: 1 });
109
+ await store.search({ limit: 1 });
75
110
  return {
76
111
  healthy: true,
77
112
  details: {
78
- adapter: config.adapter.name,
79
- tokenPrefix: config.adapter.tokenPrefix,
113
+ adapter: adapter.name,
114
+ tokenPrefix: adapter.tokenPrefix,
80
115
  },
81
116
  };
82
117
  } catch {
@@ -106,7 +141,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
106
141
  sortOrder: (req.query.sortOrder as DeviceSearchParams['sortOrder']) || 'desc',
107
142
  };
108
143
 
109
- const result = await config.store.search(params);
144
+ const result = await store.search(params);
110
145
  res.json(result);
111
146
  } catch (error) {
112
147
  console.error('[DevicesPlugin] Search error:', error);
@@ -122,7 +157,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
122
157
  pluginId: 'devices',
123
158
  handler: async (req: Request, res: Response) => {
124
159
  try {
125
- const device = await config.store.getById(req.params.id);
160
+ const device = await store.getById(req.params.id);
126
161
  if (!device) {
127
162
  return res.status(404).json({ error: 'Device not found' });
128
163
  }
@@ -150,7 +185,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
150
185
  };
151
186
 
152
187
  // Validate using adapter
153
- const validation = config.adapter.validateDeviceInput(input);
188
+ const validation = adapter.validateDeviceInput(input);
154
189
  if (!validation.valid) {
155
190
  return res.status(400).json({
156
191
  error: 'Validation failed',
@@ -181,7 +216,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
181
216
  metadata: req.body.metadata,
182
217
  };
183
218
 
184
- const device = await config.store.update(req.params.id, input);
219
+ const device = await store.update(req.params.id, input);
185
220
  if (!device) {
186
221
  return res.status(404).json({ error: 'Device not found' });
187
222
  }
@@ -200,19 +235,19 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
200
235
  pluginId: 'devices',
201
236
  handler: async (req: Request, res: Response) => {
202
237
  try {
203
- const device = await config.store.getById(req.params.id);
238
+ const device = await store.getById(req.params.id);
204
239
  if (!device) {
205
240
  return res.status(404).json({ error: 'Device not found' });
206
241
  }
207
242
 
208
- const deleted = await config.store.delete(req.params.id);
243
+ const deleted = await store.delete(req.params.id);
209
244
  if (!deleted) {
210
245
  return res.status(404).json({ error: 'Device not found' });
211
246
  }
212
247
 
213
248
  // Call adapter hook
214
- if (config.adapter.onDeviceDeleted) {
215
- await config.adapter.onDeviceDeleted(device);
249
+ if (adapter.onDeviceDeleted) {
250
+ await adapter.onDeviceDeleted(device);
216
251
  }
217
252
 
218
253
  res.status(204).send();
@@ -230,7 +265,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
230
265
  pluginId: 'devices',
231
266
  handler: async (req: Request, res: Response) => {
232
267
  try {
233
- const device = await config.store.getById(req.params.id);
268
+ const device = await store.getById(req.params.id);
234
269
  if (!device) {
235
270
  return res.status(404).json({ error: 'Device not found' });
236
271
  }
@@ -295,7 +330,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
295
330
 
296
331
  async onStop(): Promise<void> {
297
332
  log('Stopping devices plugin');
298
- await config.store.shutdown();
333
+ if (currentStore) { await currentStore.shutdown(); };
299
334
  currentStore = null;
300
335
  currentAdapter = null;
301
336
  currentConfig = null;