@qwickapps/server 1.2.0 → 1.3.1

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 (299) hide show
  1. package/README.md +392 -0
  2. package/dist/core/control-panel.d.ts +7 -2
  3. package/dist/core/control-panel.d.ts.map +1 -1
  4. package/dist/core/control-panel.js +120 -54
  5. package/dist/core/control-panel.js.map +1 -1
  6. package/dist/core/gateway.d.ts +159 -79
  7. package/dist/core/gateway.d.ts.map +1 -1
  8. package/dist/core/gateway.js +679 -319
  9. package/dist/core/gateway.js.map +1 -1
  10. package/dist/core/index.d.ts +3 -1
  11. package/dist/core/index.d.ts.map +1 -1
  12. package/dist/core/index.js +2 -0
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/core/plugin-registry.d.ts +307 -0
  15. package/dist/core/plugin-registry.d.ts.map +1 -0
  16. package/dist/core/plugin-registry.js +352 -0
  17. package/dist/core/plugin-registry.js.map +1 -0
  18. package/dist/core/types.d.ts +16 -33
  19. package/dist/core/types.d.ts.map +1 -1
  20. package/dist/index.d.ts +8 -5
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +15 -7
  23. package/dist/index.js.map +1 -1
  24. package/dist/plugins/auth/adapters/auth0-adapter.d.ts +14 -0
  25. package/dist/plugins/auth/adapters/auth0-adapter.d.ts.map +1 -0
  26. package/dist/plugins/auth/adapters/auth0-adapter.js +179 -0
  27. package/dist/plugins/auth/adapters/auth0-adapter.js.map +1 -0
  28. package/dist/plugins/auth/adapters/basic-adapter.d.ts +13 -0
  29. package/dist/plugins/auth/adapters/basic-adapter.d.ts.map +1 -0
  30. package/dist/plugins/auth/adapters/basic-adapter.js +51 -0
  31. package/dist/plugins/auth/adapters/basic-adapter.js.map +1 -0
  32. package/dist/plugins/auth/adapters/index.d.ts +10 -0
  33. package/dist/plugins/auth/adapters/index.d.ts.map +1 -0
  34. package/dist/plugins/auth/adapters/index.js +10 -0
  35. package/dist/plugins/auth/adapters/index.js.map +1 -0
  36. package/dist/plugins/auth/adapters/supabase-adapter.d.ts +13 -0
  37. package/dist/plugins/auth/adapters/supabase-adapter.d.ts.map +1 -0
  38. package/dist/plugins/auth/adapters/supabase-adapter.js +109 -0
  39. package/dist/plugins/auth/adapters/supabase-adapter.js.map +1 -0
  40. package/dist/plugins/auth/adapters/supertokens-adapter.d.ts +18 -0
  41. package/dist/plugins/auth/adapters/supertokens-adapter.d.ts.map +1 -0
  42. package/dist/plugins/auth/adapters/supertokens-adapter.js +267 -0
  43. package/dist/plugins/auth/adapters/supertokens-adapter.js.map +1 -0
  44. package/dist/plugins/auth/auth-plugin.d.ts +40 -0
  45. package/dist/plugins/auth/auth-plugin.d.ts.map +1 -0
  46. package/dist/plugins/auth/auth-plugin.js +255 -0
  47. package/dist/plugins/auth/auth-plugin.js.map +1 -0
  48. package/dist/plugins/auth/auth-plugin.test.d.ts +9 -0
  49. package/dist/plugins/auth/auth-plugin.test.d.ts.map +1 -0
  50. package/dist/plugins/auth/auth-plugin.test.js +147 -0
  51. package/dist/plugins/auth/auth-plugin.test.js.map +1 -0
  52. package/dist/plugins/auth/env-config.d.ts +88 -0
  53. package/dist/plugins/auth/env-config.d.ts.map +1 -0
  54. package/dist/plugins/auth/env-config.js +489 -0
  55. package/dist/plugins/auth/env-config.js.map +1 -0
  56. package/dist/plugins/auth/index.d.ts +14 -0
  57. package/dist/plugins/auth/index.d.ts.map +1 -0
  58. package/dist/plugins/auth/index.js +16 -0
  59. package/dist/plugins/auth/index.js.map +1 -0
  60. package/dist/plugins/auth/supertokens-adapter.test.d.ts +10 -0
  61. package/dist/plugins/auth/supertokens-adapter.test.d.ts.map +1 -0
  62. package/dist/plugins/auth/supertokens-adapter.test.js +486 -0
  63. package/dist/plugins/auth/supertokens-adapter.test.js.map +1 -0
  64. package/dist/plugins/auth/types.d.ts +218 -0
  65. package/dist/plugins/auth/types.d.ts.map +1 -0
  66. package/dist/plugins/auth/types.js +14 -0
  67. package/dist/plugins/auth/types.js.map +1 -0
  68. package/dist/plugins/bans/bans-plugin.d.ts +59 -0
  69. package/dist/plugins/bans/bans-plugin.d.ts.map +1 -0
  70. package/dist/plugins/bans/bans-plugin.js +428 -0
  71. package/dist/plugins/bans/bans-plugin.js.map +1 -0
  72. package/dist/plugins/bans/index.d.ts +9 -0
  73. package/dist/plugins/bans/index.d.ts.map +1 -0
  74. package/dist/plugins/bans/index.js +10 -0
  75. package/dist/plugins/bans/index.js.map +1 -0
  76. package/dist/plugins/bans/stores/index.d.ts +7 -0
  77. package/dist/plugins/bans/stores/index.d.ts.map +1 -0
  78. package/dist/plugins/bans/stores/index.js +7 -0
  79. package/dist/plugins/bans/stores/index.js.map +1 -0
  80. package/dist/plugins/bans/stores/postgres-store.d.ts +29 -0
  81. package/dist/plugins/bans/stores/postgres-store.d.ts.map +1 -0
  82. package/dist/plugins/bans/stores/postgres-store.js +132 -0
  83. package/dist/plugins/bans/stores/postgres-store.js.map +1 -0
  84. package/dist/plugins/bans/types.d.ts +128 -0
  85. package/dist/plugins/bans/types.d.ts.map +1 -0
  86. package/dist/plugins/bans/types.js +11 -0
  87. package/dist/plugins/bans/types.js.map +1 -0
  88. package/dist/plugins/cache-plugin.d.ts +14 -3
  89. package/dist/plugins/cache-plugin.d.ts.map +1 -1
  90. package/dist/plugins/cache-plugin.js +27 -7
  91. package/dist/plugins/cache-plugin.js.map +1 -1
  92. package/dist/plugins/cache-plugin.test.js +99 -32
  93. package/dist/plugins/cache-plugin.test.js.map +1 -1
  94. package/dist/plugins/config-plugin.d.ts +3 -2
  95. package/dist/plugins/config-plugin.d.ts.map +1 -1
  96. package/dist/plugins/config-plugin.js +17 -10
  97. package/dist/plugins/config-plugin.js.map +1 -1
  98. package/dist/plugins/diagnostics-plugin.d.ts +2 -2
  99. package/dist/plugins/diagnostics-plugin.d.ts.map +1 -1
  100. package/dist/plugins/diagnostics-plugin.js +17 -10
  101. package/dist/plugins/diagnostics-plugin.js.map +1 -1
  102. package/dist/plugins/entitlements/entitlements-plugin.d.ts +95 -0
  103. package/dist/plugins/entitlements/entitlements-plugin.d.ts.map +1 -0
  104. package/dist/plugins/entitlements/entitlements-plugin.js +707 -0
  105. package/dist/plugins/entitlements/entitlements-plugin.js.map +1 -0
  106. package/dist/plugins/entitlements/index.d.ts +12 -0
  107. package/dist/plugins/entitlements/index.d.ts.map +1 -0
  108. package/dist/plugins/entitlements/index.js +16 -0
  109. package/dist/plugins/entitlements/index.js.map +1 -0
  110. package/dist/plugins/entitlements/sources/index.d.ts +9 -0
  111. package/dist/plugins/entitlements/sources/index.d.ts.map +1 -0
  112. package/dist/plugins/entitlements/sources/index.js +9 -0
  113. package/dist/plugins/entitlements/sources/index.js.map +1 -0
  114. package/dist/plugins/entitlements/sources/postgres-source.d.ts +29 -0
  115. package/dist/plugins/entitlements/sources/postgres-source.d.ts.map +1 -0
  116. package/dist/plugins/entitlements/sources/postgres-source.js +169 -0
  117. package/dist/plugins/entitlements/sources/postgres-source.js.map +1 -0
  118. package/dist/plugins/entitlements/types.d.ts +232 -0
  119. package/dist/plugins/entitlements/types.d.ts.map +1 -0
  120. package/dist/plugins/entitlements/types.js +11 -0
  121. package/dist/plugins/entitlements/types.js.map +1 -0
  122. package/dist/plugins/frontend-app-plugin.d.ts +9 -3
  123. package/dist/plugins/frontend-app-plugin.d.ts.map +1 -1
  124. package/dist/plugins/frontend-app-plugin.js +14 -9
  125. package/dist/plugins/frontend-app-plugin.js.map +1 -1
  126. package/dist/plugins/health-plugin.d.ts +5 -2
  127. package/dist/plugins/health-plugin.d.ts.map +1 -1
  128. package/dist/plugins/health-plugin.js +20 -5
  129. package/dist/plugins/health-plugin.js.map +1 -1
  130. package/dist/plugins/index.d.ts +10 -2
  131. package/dist/plugins/index.d.ts.map +1 -1
  132. package/dist/plugins/index.js +10 -2
  133. package/dist/plugins/index.js.map +1 -1
  134. package/dist/plugins/logs-plugin.d.ts +3 -2
  135. package/dist/plugins/logs-plugin.d.ts.map +1 -1
  136. package/dist/plugins/logs-plugin.js +21 -12
  137. package/dist/plugins/logs-plugin.js.map +1 -1
  138. package/dist/plugins/postgres-plugin.d.ts +3 -3
  139. package/dist/plugins/postgres-plugin.d.ts.map +1 -1
  140. package/dist/plugins/postgres-plugin.js +9 -7
  141. package/dist/plugins/postgres-plugin.js.map +1 -1
  142. package/dist/plugins/postgres-plugin.test.js +50 -29
  143. package/dist/plugins/postgres-plugin.test.js.map +1 -1
  144. package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts +7 -0
  145. package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts.map +1 -0
  146. package/dist/plugins/preferences/__tests__/deep-merge.test.js +215 -0
  147. package/dist/plugins/preferences/__tests__/deep-merge.test.js.map +1 -0
  148. package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts +7 -0
  149. package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts.map +1 -0
  150. package/dist/plugins/preferences/__tests__/preferences-plugin.test.js +265 -0
  151. package/dist/plugins/preferences/__tests__/preferences-plugin.test.js.map +1 -0
  152. package/dist/plugins/preferences/index.d.ts +12 -0
  153. package/dist/plugins/preferences/index.d.ts.map +1 -0
  154. package/dist/plugins/preferences/index.js +13 -0
  155. package/dist/plugins/preferences/index.js.map +1 -0
  156. package/dist/plugins/preferences/preferences-plugin.d.ts +39 -0
  157. package/dist/plugins/preferences/preferences-plugin.d.ts.map +1 -0
  158. package/dist/plugins/preferences/preferences-plugin.js +226 -0
  159. package/dist/plugins/preferences/preferences-plugin.js.map +1 -0
  160. package/dist/plugins/preferences/stores/index.d.ts +9 -0
  161. package/dist/plugins/preferences/stores/index.d.ts.map +1 -0
  162. package/dist/plugins/preferences/stores/index.js +9 -0
  163. package/dist/plugins/preferences/stores/index.js.map +1 -0
  164. package/dist/plugins/preferences/stores/postgres-store.d.ts +41 -0
  165. package/dist/plugins/preferences/stores/postgres-store.d.ts.map +1 -0
  166. package/dist/plugins/preferences/stores/postgres-store.js +181 -0
  167. package/dist/plugins/preferences/stores/postgres-store.js.map +1 -0
  168. package/dist/plugins/preferences/types.d.ts +91 -0
  169. package/dist/plugins/preferences/types.d.ts.map +1 -0
  170. package/dist/plugins/preferences/types.js +10 -0
  171. package/dist/plugins/preferences/types.js.map +1 -0
  172. package/dist/plugins/users/__tests__/users-plugin.test.d.ts +9 -0
  173. package/dist/plugins/users/__tests__/users-plugin.test.d.ts.map +1 -0
  174. package/dist/plugins/users/__tests__/users-plugin.test.js +546 -0
  175. package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -0
  176. package/dist/plugins/users/index.d.ts +12 -0
  177. package/dist/plugins/users/index.d.ts.map +1 -0
  178. package/dist/plugins/users/index.js +13 -0
  179. package/dist/plugins/users/index.js.map +1 -0
  180. package/dist/plugins/users/stores/index.d.ts +7 -0
  181. package/dist/plugins/users/stores/index.d.ts.map +1 -0
  182. package/dist/plugins/users/stores/index.js +7 -0
  183. package/dist/plugins/users/stores/index.js.map +1 -0
  184. package/dist/plugins/users/stores/postgres-store.d.ts +28 -0
  185. package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -0
  186. package/dist/plugins/users/stores/postgres-store.js +157 -0
  187. package/dist/plugins/users/stores/postgres-store.js.map +1 -0
  188. package/dist/plugins/users/types.d.ts +225 -0
  189. package/dist/plugins/users/types.d.ts.map +1 -0
  190. package/dist/plugins/users/types.js +12 -0
  191. package/dist/plugins/users/types.js.map +1 -0
  192. package/dist/plugins/users/users-plugin.d.ts +45 -0
  193. package/dist/plugins/users/users-plugin.d.ts.map +1 -0
  194. package/dist/plugins/users/users-plugin.js +359 -0
  195. package/dist/plugins/users/users-plugin.js.map +1 -0
  196. package/dist-ui/assets/index-BY8OxNgO.js +465 -0
  197. package/dist-ui/assets/index-BY8OxNgO.js.map +1 -0
  198. package/dist-ui/index.html +1 -1
  199. package/dist-ui-lib/api/controlPanelApi.d.ts +278 -0
  200. package/dist-ui-lib/components/ControlPanelApp.d.ts +61 -0
  201. package/dist-ui-lib/components/index.d.ts +18 -0
  202. package/dist-ui-lib/config/AppConfig.d.ts +7 -0
  203. package/dist-ui-lib/dashboard/DashboardWidgetRegistry.d.ts +62 -0
  204. package/dist-ui-lib/dashboard/DashboardWidgetRenderer.d.ts +8 -0
  205. package/dist-ui-lib/dashboard/PluginWidgetRenderer.d.ts +19 -0
  206. package/dist-ui-lib/dashboard/WidgetComponentRegistry.d.ts +48 -0
  207. package/dist-ui-lib/dashboard/builtInWidgets.d.ts +25 -0
  208. package/dist-ui-lib/dashboard/index.d.ts +13 -0
  209. package/dist-ui-lib/dashboard/widgets/ServiceHealthWidget.d.ts +12 -0
  210. package/dist-ui-lib/dashboard/widgets/index.d.ts +6 -0
  211. package/dist-ui-lib/index.js +5172 -0
  212. package/dist-ui-lib/index.js.map +1 -0
  213. package/dist-ui-lib/pages/AuthPage.d.ts +1 -0
  214. package/dist-ui-lib/pages/ConfigPage.d.ts +1 -0
  215. package/dist-ui-lib/pages/DashboardPage.d.ts +1 -0
  216. package/dist-ui-lib/pages/DiagnosticsPage.d.ts +1 -0
  217. package/dist-ui-lib/pages/EntitlementsPage.d.ts +17 -0
  218. package/dist-ui-lib/pages/LogsPage.d.ts +1 -0
  219. package/dist-ui-lib/pages/NotFoundPage.d.ts +1 -0
  220. package/dist-ui-lib/pages/PluginPage.d.ts +15 -0
  221. package/dist-ui-lib/pages/PluginsPage.d.ts +1 -0
  222. package/dist-ui-lib/pages/SystemPage.d.ts +1 -0
  223. package/dist-ui-lib/pages/UsersPage.d.ts +22 -0
  224. package/package.json +24 -7
  225. package/src/core/control-panel.ts +145 -61
  226. package/src/core/gateway.ts +863 -403
  227. package/src/core/index.ts +21 -2
  228. package/src/core/plugin-registry.ts +716 -0
  229. package/src/core/types.ts +31 -37
  230. package/src/index.ts +125 -19
  231. package/src/plugins/auth/adapters/auth0-adapter.ts +214 -0
  232. package/src/plugins/auth/adapters/basic-adapter.ts +61 -0
  233. package/src/plugins/auth/adapters/index.ts +10 -0
  234. package/src/plugins/auth/adapters/supabase-adapter.ts +149 -0
  235. package/src/plugins/auth/adapters/supertokens-adapter.ts +326 -0
  236. package/src/plugins/auth/auth-plugin.test.ts +176 -0
  237. package/src/plugins/auth/auth-plugin.ts +303 -0
  238. package/src/plugins/auth/env-config.ts +572 -0
  239. package/src/plugins/auth/index.ts +42 -0
  240. package/src/plugins/auth/supertokens-adapter.test.ts +621 -0
  241. package/src/plugins/auth/types.ts +245 -0
  242. package/src/plugins/bans/bans-plugin.ts +485 -0
  243. package/src/plugins/bans/index.ts +31 -0
  244. package/src/plugins/bans/stores/index.ts +7 -0
  245. package/src/plugins/bans/stores/postgres-store.ts +195 -0
  246. package/src/plugins/bans/types.ts +141 -0
  247. package/src/plugins/cache-plugin.test.ts +108 -32
  248. package/src/plugins/cache-plugin.ts +40 -9
  249. package/src/plugins/config-plugin.ts +23 -12
  250. package/src/plugins/diagnostics-plugin.ts +22 -12
  251. package/src/plugins/entitlements/entitlements-plugin.ts +820 -0
  252. package/src/plugins/entitlements/index.ts +51 -0
  253. package/src/plugins/entitlements/sources/index.ts +9 -0
  254. package/src/plugins/entitlements/sources/postgres-source.ts +253 -0
  255. package/src/plugins/entitlements/types.ts +256 -0
  256. package/src/plugins/frontend-app-plugin.ts +24 -12
  257. package/src/plugins/health-plugin.ts +27 -7
  258. package/src/plugins/index.ts +132 -4
  259. package/src/plugins/logs-plugin.ts +28 -14
  260. package/src/plugins/postgres-plugin.test.ts +52 -29
  261. package/src/plugins/postgres-plugin.ts +11 -9
  262. package/src/plugins/preferences/__tests__/deep-merge.test.ts +242 -0
  263. package/src/plugins/preferences/__tests__/preferences-plugin.test.ts +350 -0
  264. package/src/plugins/preferences/index.ts +30 -0
  265. package/src/plugins/preferences/preferences-plugin.ts +270 -0
  266. package/src/plugins/preferences/stores/index.ts +9 -0
  267. package/src/plugins/preferences/stores/postgres-store.ts +252 -0
  268. package/src/plugins/preferences/types.ts +100 -0
  269. package/src/plugins/users/__tests__/users-plugin.test.ts +690 -0
  270. package/src/plugins/users/index.ts +38 -0
  271. package/src/plugins/users/stores/index.ts +7 -0
  272. package/src/plugins/users/stores/postgres-store.ts +225 -0
  273. package/src/plugins/users/types.ts +247 -0
  274. package/src/plugins/users/users-plugin.ts +418 -0
  275. package/ui/src/App.tsx +188 -31
  276. package/ui/src/api/controlPanelApi.ts +453 -1
  277. package/ui/src/components/ControlPanelApp.tsx +212 -0
  278. package/ui/src/components/index.ts +62 -0
  279. package/ui/src/dashboard/DashboardWidgetRegistry.tsx +129 -0
  280. package/ui/src/dashboard/DashboardWidgetRenderer.tsx +34 -0
  281. package/ui/src/dashboard/PluginWidgetRenderer.tsx +118 -0
  282. package/ui/src/dashboard/WidgetComponentRegistry.tsx +120 -0
  283. package/ui/src/dashboard/builtInWidgets.tsx +35 -0
  284. package/ui/src/dashboard/index.ts +35 -0
  285. package/ui/src/dashboard/widgets/ServiceHealthWidget.tsx +140 -0
  286. package/ui/src/dashboard/widgets/index.ts +7 -0
  287. package/ui/src/pages/AuthPage.tsx +259 -0
  288. package/ui/src/pages/DashboardPage.tsx +28 -149
  289. package/ui/src/pages/EntitlementsPage.tsx +557 -0
  290. package/ui/src/pages/LogsPage.tsx +174 -8
  291. package/ui/src/pages/PluginPage.tsx +148 -0
  292. package/ui/src/pages/PluginsPage.tsx +394 -0
  293. package/ui/src/pages/SystemPage.tsx +445 -0
  294. package/ui/src/pages/UsersPage.tsx +837 -0
  295. package/ui/tsconfig.lib.json +11 -0
  296. package/ui/vite.lib.config.ts +56 -0
  297. package/dist-ui/assets/index-CW1BviRn.js +0 -465
  298. package/dist-ui/assets/index-CW1BviRn.js.map +0 -1
  299. package/ui/src/pages/HealthPage.tsx +0 -204
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Users Plugin Index
3
+ *
4
+ * User identity management plugin.
5
+ * For ban management, use the separate Bans Plugin which depends on this plugin.
6
+ *
7
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
8
+ */
9
+
10
+ // Main plugin
11
+ export {
12
+ createUsersPlugin,
13
+ getUserStore,
14
+ getUserById,
15
+ getUserByEmail,
16
+ findOrCreateUser,
17
+ buildUserInfo,
18
+ } from './users-plugin.js';
19
+
20
+ // Types
21
+ export type {
22
+ UsersPluginConfig,
23
+ UserStore,
24
+ User,
25
+ CreateUserInput,
26
+ UpdateUserInput,
27
+ UserSearchParams,
28
+ UserListResponse,
29
+ PostgresUserStoreConfig,
30
+ UserSyncConfig,
31
+ UsersApiConfig,
32
+ UsersUiConfig,
33
+ UserInfo,
34
+ UserSyncInput,
35
+ } from './types.js';
36
+
37
+ // Stores
38
+ export { postgresUserStore } from './stores/index.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * User Stores Index
3
+ *
4
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
5
+ */
6
+
7
+ export { postgresUserStore } from './postgres-store.js';
@@ -0,0 +1,225 @@
1
+ /**
2
+ * PostgreSQL User Store
3
+ *
4
+ * User storage implementation using PostgreSQL.
5
+ * Requires the 'pg' package to be installed.
6
+ *
7
+ * Note: Ban management is handled by the separate Bans Plugin.
8
+ *
9
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
10
+ */
11
+
12
+ import type {
13
+ UserStore,
14
+ User,
15
+ CreateUserInput,
16
+ UpdateUserInput,
17
+ UserSearchParams,
18
+ UserListResponse,
19
+ PostgresUserStoreConfig,
20
+ } from '../types.js';
21
+
22
+ // Pool interface (from pg package)
23
+ interface PgPool {
24
+ query(text: string, values?: unknown[]): Promise<{ rows: unknown[]; rowCount: number | null }>;
25
+ }
26
+
27
+ /**
28
+ * Create a PostgreSQL user store
29
+ *
30
+ * @param config Configuration including a pg Pool instance
31
+ * @returns UserStore implementation
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { Pool } from 'pg';
36
+ * import { postgresUserStore } from '@qwickapps/server';
37
+ *
38
+ * const pool = new Pool({ connectionString: process.env.DATABASE_URL });
39
+ * const store = postgresUserStore({ pool });
40
+ * ```
41
+ */
42
+ export function postgresUserStore(config: PostgresUserStoreConfig): UserStore {
43
+ const {
44
+ pool: poolOrFn,
45
+ usersTable = 'users',
46
+ schema = 'public',
47
+ autoCreateTables = true,
48
+ } = config;
49
+
50
+ // Helper to get pool (supports lazy initialization via function)
51
+ const getPool = (): PgPool => {
52
+ const pool = typeof poolOrFn === 'function' ? poolOrFn() : poolOrFn;
53
+ return pool as PgPool;
54
+ };
55
+
56
+ const usersTableFull = `"${schema}"."${usersTable}"`;
57
+
58
+ return {
59
+ name: 'postgres',
60
+
61
+ async initialize(): Promise<void> {
62
+ if (!autoCreateTables) return;
63
+
64
+ // Create users table
65
+ await getPool().query(`
66
+ CREATE TABLE IF NOT EXISTS ${usersTableFull} (
67
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
68
+ email VARCHAR(255) NOT NULL UNIQUE,
69
+ name VARCHAR(255),
70
+ external_id VARCHAR(255),
71
+ provider VARCHAR(50),
72
+ picture TEXT,
73
+ metadata JSONB DEFAULT '{}',
74
+ created_at TIMESTAMPTZ DEFAULT NOW(),
75
+ updated_at TIMESTAMPTZ DEFAULT NOW(),
76
+ last_login_at TIMESTAMPTZ
77
+ );
78
+
79
+ CREATE INDEX IF NOT EXISTS idx_${usersTable}_email ON ${usersTableFull}(email);
80
+ CREATE INDEX IF NOT EXISTS idx_${usersTable}_external_id ON ${usersTableFull}(external_id, provider);
81
+ `);
82
+ },
83
+
84
+ async getById(id: string): Promise<User | null> {
85
+ const result = await getPool().query(`SELECT * FROM ${usersTableFull} WHERE id = $1`, [id]);
86
+ return (result.rows[0] as User) || null;
87
+ },
88
+
89
+ async getByEmail(email: string): Promise<User | null> {
90
+ const result = await getPool().query(`SELECT * FROM ${usersTableFull} WHERE LOWER(email) = LOWER($1)`, [
91
+ email,
92
+ ]);
93
+ return (result.rows[0] as User) || null;
94
+ },
95
+
96
+ async getByExternalId(externalId: string, provider: string): Promise<User | null> {
97
+ const result = await getPool().query(
98
+ `SELECT * FROM ${usersTableFull} WHERE external_id = $1 AND provider = $2`,
99
+ [externalId, provider]
100
+ );
101
+ return (result.rows[0] as User) || null;
102
+ },
103
+
104
+ async create(input: CreateUserInput): Promise<User> {
105
+ const result = await getPool().query(
106
+ `INSERT INTO ${usersTableFull} (email, name, external_id, provider, picture, metadata)
107
+ VALUES ($1, $2, $3, $4, $5, $6)
108
+ RETURNING *`,
109
+ [
110
+ input.email.toLowerCase(),
111
+ input.name,
112
+ input.external_id,
113
+ input.provider,
114
+ input.picture,
115
+ JSON.stringify(input.metadata || {}),
116
+ ]
117
+ );
118
+ return result.rows[0] as User;
119
+ },
120
+
121
+ async update(id: string, input: UpdateUserInput): Promise<User | null> {
122
+ const updates: string[] = [];
123
+ const values: unknown[] = [];
124
+ let paramIndex = 1;
125
+
126
+ if (input.name !== undefined) {
127
+ updates.push(`name = $${paramIndex++}`);
128
+ values.push(input.name);
129
+ }
130
+ if (input.picture !== undefined) {
131
+ updates.push(`picture = $${paramIndex++}`);
132
+ values.push(input.picture);
133
+ }
134
+ if (input.metadata !== undefined) {
135
+ updates.push(`metadata = $${paramIndex++}`);
136
+ values.push(JSON.stringify(input.metadata));
137
+ }
138
+
139
+ if (updates.length === 0) {
140
+ return this.getById(id);
141
+ }
142
+
143
+ updates.push(`updated_at = NOW()`);
144
+ values.push(id);
145
+
146
+ const result = await getPool().query(
147
+ `UPDATE ${usersTableFull} SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
148
+ values
149
+ );
150
+ return (result.rows[0] as User) || null;
151
+ },
152
+
153
+ async delete(id: string): Promise<boolean> {
154
+ const result = await getPool().query(`DELETE FROM ${usersTableFull} WHERE id = $1`, [id]);
155
+ return (result.rowCount ?? 0) > 0;
156
+ },
157
+
158
+ async search(params: UserSearchParams): Promise<UserListResponse> {
159
+ const {
160
+ query,
161
+ provider,
162
+ page = 1,
163
+ limit = 20,
164
+ sortBy = 'created_at',
165
+ sortOrder = 'desc',
166
+ } = params;
167
+
168
+ const conditions: string[] = [];
169
+ const values: unknown[] = [];
170
+ let paramIndex = 1;
171
+
172
+ if (query) {
173
+ conditions.push(`(LOWER(email) LIKE $${paramIndex} OR LOWER(name) LIKE $${paramIndex})`);
174
+ values.push(`%${query.toLowerCase()}%`);
175
+ paramIndex++;
176
+ }
177
+
178
+ if (provider) {
179
+ conditions.push(`provider = $${paramIndex}`);
180
+ values.push(provider);
181
+ paramIndex++;
182
+ }
183
+
184
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
185
+
186
+ // Validate sort column to prevent SQL injection
187
+ const validSortColumns = ['email', 'name', 'created_at', 'last_login_at'];
188
+ const sortColumn = validSortColumns.includes(sortBy) ? sortBy : 'created_at';
189
+ const sortDir = sortOrder === 'asc' ? 'ASC' : 'DESC';
190
+
191
+ const offset = (page - 1) * limit;
192
+
193
+ // Get total count
194
+ const countResult = await getPool().query(
195
+ `SELECT COUNT(*) FROM ${usersTableFull} ${whereClause}`,
196
+ values
197
+ );
198
+ const total = parseInt((countResult.rows[0] as { count: string }).count, 10);
199
+
200
+ // Get users
201
+ const result = await getPool().query(
202
+ `SELECT * FROM ${usersTableFull} ${whereClause}
203
+ ORDER BY ${sortColumn} ${sortDir}
204
+ LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
205
+ [...values, limit, offset]
206
+ );
207
+
208
+ return {
209
+ users: result.rows as User[],
210
+ total,
211
+ page,
212
+ limit,
213
+ totalPages: Math.ceil(total / limit),
214
+ };
215
+ },
216
+
217
+ async updateLastLogin(id: string): Promise<void> {
218
+ await getPool().query(`UPDATE ${usersTableFull} SET last_login_at = NOW() WHERE id = $1`, [id]);
219
+ },
220
+
221
+ async shutdown(): Promise<void> {
222
+ // Pool is managed externally, nothing to do here
223
+ },
224
+ };
225
+ }
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Users Plugin Types
3
+ *
4
+ * Type definitions for user identity management.
5
+ * Storage-agnostic - supports any database through the UserStore interface.
6
+ *
7
+ * Note: Ban management is handled by the separate Bans Plugin.
8
+ *
9
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
10
+ */
11
+
12
+ /**
13
+ * User record in the database
14
+ */
15
+ export interface User {
16
+ /** Primary key - UUID */
17
+ id: string;
18
+ /** User's email address (unique) */
19
+ email: string;
20
+ /** User's display name */
21
+ name?: string;
22
+ /** External provider ID (e.g., Auth0 sub) */
23
+ external_id?: string;
24
+ /** Provider name (e.g., 'auth0', 'supabase') */
25
+ provider?: string;
26
+ /** Profile picture URL */
27
+ picture?: string;
28
+ /** Additional metadata (JSON) */
29
+ metadata?: Record<string, unknown>;
30
+ /** When the user was created */
31
+ created_at: Date;
32
+ /** When the user was last updated */
33
+ updated_at: Date;
34
+ /** When the user last logged in */
35
+ last_login_at?: Date;
36
+ }
37
+
38
+ /**
39
+ * User creation payload
40
+ */
41
+ export interface CreateUserInput {
42
+ email: string;
43
+ name?: string;
44
+ external_id?: string;
45
+ provider?: string;
46
+ picture?: string;
47
+ metadata?: Record<string, unknown>;
48
+ }
49
+
50
+ /**
51
+ * User update payload
52
+ */
53
+ export interface UpdateUserInput {
54
+ name?: string;
55
+ picture?: string;
56
+ metadata?: Record<string, unknown>;
57
+ }
58
+
59
+ /**
60
+ * User search parameters
61
+ */
62
+ export interface UserSearchParams {
63
+ /** Search query (searches email and name) */
64
+ query?: string;
65
+ /** Filter by provider */
66
+ provider?: string;
67
+ /** Page number (1-indexed) */
68
+ page?: number;
69
+ /** Items per page */
70
+ limit?: number;
71
+ /** Sort field */
72
+ sortBy?: 'email' | 'name' | 'created_at' | 'last_login_at';
73
+ /** Sort direction */
74
+ sortOrder?: 'asc' | 'desc';
75
+ }
76
+
77
+ /**
78
+ * Paginated user list response
79
+ */
80
+ export interface UserListResponse {
81
+ users: User[];
82
+ total: number;
83
+ page: number;
84
+ limit: number;
85
+ totalPages: number;
86
+ }
87
+
88
+ /**
89
+ * User store interface - all storage backends must implement this
90
+ */
91
+ export interface UserStore {
92
+ /** Store name (e.g., 'postgres', 'memory') */
93
+ name: string;
94
+
95
+ /**
96
+ * Initialize the store (create tables, etc.)
97
+ */
98
+ initialize(): Promise<void>;
99
+
100
+ /**
101
+ * Get a user by ID
102
+ */
103
+ getById(id: string): Promise<User | null>;
104
+
105
+ /**
106
+ * Get a user by email
107
+ */
108
+ getByEmail(email: string): Promise<User | null>;
109
+
110
+ /**
111
+ * Get a user by external ID
112
+ */
113
+ getByExternalId(externalId: string, provider: string): Promise<User | null>;
114
+
115
+ /**
116
+ * Create a new user
117
+ */
118
+ create(input: CreateUserInput): Promise<User>;
119
+
120
+ /**
121
+ * Update an existing user
122
+ */
123
+ update(id: string, input: UpdateUserInput): Promise<User | null>;
124
+
125
+ /**
126
+ * Delete a user
127
+ */
128
+ delete(id: string): Promise<boolean>;
129
+
130
+ /**
131
+ * Search/list users
132
+ */
133
+ search(params: UserSearchParams): Promise<UserListResponse>;
134
+
135
+ /**
136
+ * Update last login timestamp
137
+ */
138
+ updateLastLogin(id: string): Promise<void>;
139
+
140
+ /**
141
+ * Shutdown the store
142
+ */
143
+ shutdown(): Promise<void>;
144
+ }
145
+
146
+ /**
147
+ * PostgreSQL user store configuration
148
+ * Note: Import Pool type from 'pg' when using this store
149
+ */
150
+ export interface PostgresUserStoreConfig {
151
+ /** PostgreSQL pool instance or a function that returns one (for lazy initialization) */
152
+ pool: unknown | (() => unknown);
153
+ /** Users table name (default: 'users') */
154
+ usersTable?: string;
155
+ /** Schema name (default: 'public') */
156
+ schema?: string;
157
+ /** Auto-create tables on init (default: true) */
158
+ autoCreateTables?: boolean;
159
+ }
160
+
161
+ /**
162
+ * User sync configuration
163
+ */
164
+ export interface UserSyncConfig {
165
+ /** Enable sync */
166
+ enabled: boolean;
167
+ /** Create local user on first login */
168
+ onFirstLogin?: boolean;
169
+ /** Fields to sync from external provider */
170
+ syncFields?: Array<'email' | 'name' | 'picture'>;
171
+ }
172
+
173
+ /**
174
+ * API configuration
175
+ */
176
+ export interface UsersApiConfig {
177
+ /** API route prefix (default: '/api/users') */
178
+ prefix?: string;
179
+ /** Enable CRUD endpoints */
180
+ crud?: boolean;
181
+ /** Enable search endpoint */
182
+ search?: boolean;
183
+ }
184
+
185
+ /**
186
+ * UI configuration
187
+ */
188
+ export interface UsersUiConfig {
189
+ /** Enable UI pages */
190
+ enabled: boolean;
191
+ /** UI page path (default: '/users') */
192
+ page?: string;
193
+ }
194
+
195
+ /**
196
+ * Users plugin configuration
197
+ */
198
+ export interface UsersPluginConfig {
199
+ /** User storage backend */
200
+ store: UserStore;
201
+ /** Sync configuration (optional) */
202
+ sync?: UserSyncConfig;
203
+ /** API configuration */
204
+ api?: UsersApiConfig;
205
+ /** UI configuration */
206
+ ui?: UsersUiConfig;
207
+ /** Enable debug logging */
208
+ debug?: boolean;
209
+ }
210
+
211
+ /**
212
+ * Comprehensive user information aggregated from multiple plugins.
213
+ * Used by /users/:id/info and /users/sync endpoints.
214
+ */
215
+ export interface UserInfo {
216
+ /** Core user data from users plugin */
217
+ user: User;
218
+ /** User's entitlements (if entitlements plugin loaded) */
219
+ entitlements?: string[];
220
+ /** User's preferences (if preferences plugin loaded) */
221
+ preferences?: Record<string, unknown>;
222
+ /** Active ban info (if bans plugin loaded, null if not banned) */
223
+ ban?: {
224
+ id: string;
225
+ reason: string;
226
+ banned_at: Date;
227
+ expires_at?: Date;
228
+ } | null;
229
+ /** User's roles (if roles plugin loaded - future) */
230
+ roles?: string[];
231
+ }
232
+
233
+ /**
234
+ * Input for POST /users/sync endpoint
235
+ */
236
+ export interface UserSyncInput {
237
+ /** User's email address */
238
+ email: string;
239
+ /** External provider ID (e.g., Auth0 user_id) */
240
+ external_id: string;
241
+ /** Provider name (e.g., 'auth0', 'google') */
242
+ provider: string;
243
+ /** User's display name (optional) */
244
+ name?: string;
245
+ /** Profile picture URL (optional) */
246
+ picture?: string;
247
+ }