@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
package/README.md CHANGED
@@ -61,6 +61,8 @@ For production deployments, use `createGateway` to run a gateway that:
61
61
  1. Serves the control panel UI (always responsive, even if the API crashes)
62
62
  2. Proxies API requests to an internal service
63
63
  3. Handles graceful error responses when the internal service is down
64
+ 4. Supports maintenance mode with customizable status pages
65
+ 5. Shows service unavailable pages when mounted apps are unreachable
64
66
 
65
67
  ```typescript
66
68
  import { createGateway, createHealthPlugin } from '@qwickapps/server';
@@ -115,6 +117,68 @@ Internet → Gateway (3101, public) → API Service (3100, internal)
115
117
 
116
118
  The gateway is always responsive even if the internal API service crashes, allowing you to view diagnostics and error information.
117
119
 
120
+ ### Mounted Apps with Maintenance Mode
121
+
122
+ Mount frontend apps or proxy services with full maintenance and fallback support:
123
+
124
+ ```typescript
125
+ const gateway = createGateway({
126
+ // ... base config
127
+ mountedApps: [
128
+ {
129
+ path: '/app',
130
+ name: 'Main App',
131
+ type: 'proxy',
132
+ target: 'http://localhost:4000',
133
+ maintenance: {
134
+ enabled: false, // Toggle to enable maintenance mode
135
+ title: 'Scheduled Maintenance',
136
+ message: 'We are upgrading our systems.',
137
+ expectedBackAt: '2 hours', // or ISO date, or "soon"
138
+ contactUrl: 'https://status.example.com',
139
+ bypassPaths: ['/app/health', '/app/api/status'],
140
+ },
141
+ fallback: {
142
+ title: 'Service Unavailable',
143
+ message: 'The application is temporarily unavailable.',
144
+ showRetry: true,
145
+ autoRefresh: 30, // seconds
146
+ },
147
+ },
148
+ {
149
+ path: '/docs',
150
+ name: 'Documentation',
151
+ type: 'static',
152
+ staticPath: './docs-dist',
153
+ },
154
+ ],
155
+ });
156
+ ```
157
+
158
+ ### Maintenance and Fallback Configuration
159
+
160
+ **MaintenanceConfig** - Shown when maintenance mode is enabled:
161
+
162
+ | Property | Type | Description |
163
+ |----------|------|-------------|
164
+ | `enabled` | `boolean` | Enable/disable maintenance mode |
165
+ | `title` | `string` | Page title (default: "Under Maintenance") |
166
+ | `message` | `string` | Custom message to display |
167
+ | `expectedBackAt` | `string` | ETA: ISO date, relative time ("2 hours"), or "soon" |
168
+ | `contactUrl` | `string` | Link to status page or contact |
169
+ | `bypassPaths` | `string[]` | Paths that bypass maintenance (e.g., health checks) |
170
+
171
+ **FallbackConfig** - Shown when the proxied service is unreachable:
172
+
173
+ | Property | Type | Description |
174
+ |----------|------|-------------|
175
+ | `title` | `string` | Page title (default: "Service Unavailable") |
176
+ | `message` | `string` | Custom message to display |
177
+ | `showRetry` | `boolean` | Show retry button (default: true) |
178
+ | `autoRefresh` | `number` | Auto-refresh countdown in seconds (default: 30) |
179
+
180
+ Both pages feature modern, responsive designs with automatic dark mode support.
181
+
118
182
  ## Configuration
119
183
 
120
184
  ### ControlPanelConfig
@@ -377,6 +441,334 @@ await cache.flush(); // Clear all keys with prefix
377
441
  - `hasCache(name?)` - Check if an instance is registered
378
442
  - `CacheInstance` - TypeScript type for the instance
379
443
 
444
+ #### Auth Plugin
445
+
446
+ Pluggable authentication with support for multiple providers via the adapter pattern.
447
+
448
+ ##### Zero-Config Environment Setup
449
+
450
+ The simplest way to configure auth is via environment variables:
451
+
452
+ ```typescript
453
+ import { createAuthPluginFromEnv } from '@qwickapps/server';
454
+
455
+ // Auto-configures based on AUTH_ADAPTER env var
456
+ const authPlugin = createAuthPluginFromEnv();
457
+
458
+ // With overrides
459
+ const authPlugin = createAuthPluginFromEnv({
460
+ excludePaths: ['/health', '/metrics'],
461
+ authRequired: true,
462
+ });
463
+ ```
464
+
465
+ **Environment Variables:**
466
+
467
+ ```bash
468
+ # General (required to enable auth)
469
+ AUTH_ADAPTER=supertokens|auth0|supabase|basic
470
+ AUTH_REQUIRED=true # Default: true
471
+ AUTH_EXCLUDE_PATHS=/health,/metrics # Comma-separated
472
+ AUTH_DEBUG=false
473
+
474
+ # Supertokens
475
+ SUPERTOKENS_CONNECTION_URI=http://localhost:3567
476
+ SUPERTOKENS_APP_NAME=MyApp
477
+ SUPERTOKENS_API_DOMAIN=http://localhost:3000
478
+ SUPERTOKENS_WEBSITE_DOMAIN=http://localhost:3000
479
+ SUPERTOKENS_API_KEY= # Optional, for managed service
480
+ SUPERTOKENS_GOOGLE_CLIENT_ID= # Optional social providers
481
+ SUPERTOKENS_GOOGLE_CLIENT_SECRET=
482
+ SUPERTOKENS_GITHUB_CLIENT_ID=
483
+ SUPERTOKENS_GITHUB_CLIENT_SECRET=
484
+
485
+ # Auth0
486
+ AUTH0_DOMAIN=myapp.auth0.com
487
+ AUTH0_CLIENT_ID=
488
+ AUTH0_CLIENT_SECRET=
489
+ AUTH0_BASE_URL=http://localhost:3000
490
+ AUTH0_SECRET= # Session encryption secret
491
+ AUTH0_AUDIENCE= # Optional, for API access tokens
492
+ AUTH0_SCOPES=openid,profile,email # Default scopes
493
+
494
+ # Supabase
495
+ SUPABASE_URL=https://xxx.supabase.co
496
+ SUPABASE_ANON_KEY=
497
+
498
+ # Basic Auth
499
+ BASIC_AUTH_USERNAME=admin
500
+ BASIC_AUTH_PASSWORD=
501
+ BASIC_AUTH_REALM=Protected # Default: Protected
502
+ ```
503
+
504
+ **Plugin States:**
505
+
506
+ | State | Condition | Behavior |
507
+ |-------|-----------|----------|
508
+ | `disabled` | `AUTH_ADAPTER` not set | No auth middleware |
509
+ | `enabled` | Valid configuration | Auth active |
510
+ | `error` | Invalid configuration | Disabled with error details |
511
+
512
+ **Check Auth Status:**
513
+
514
+ ```typescript
515
+ import { getAuthStatus } from '@qwickapps/server';
516
+
517
+ const status = getAuthStatus();
518
+ // { state: 'enabled', adapter: 'supertokens', config: {...} }
519
+ ```
520
+
521
+ ##### Programmatic Configuration
522
+
523
+ For more control, configure adapters directly in code:
524
+
525
+ ```typescript
526
+ import { createAuthPlugin, auth0Adapter, basicAdapter } from '@qwickapps/server';
527
+
528
+ // Auth0 with RBAC and domain restrictions
529
+ createAuthPlugin({
530
+ adapter: auth0Adapter({
531
+ domain: process.env.AUTH0_DOMAIN!,
532
+ clientId: process.env.AUTH0_CLIENT_ID!,
533
+ clientSecret: process.env.AUTH0_CLIENT_SECRET!,
534
+ baseUrl: 'https://myapp.example.com',
535
+ secret: process.env.SESSION_SECRET!,
536
+ audience: process.env.AUTH0_AUDIENCE, // For API access tokens
537
+ allowedRoles: ['admin', 'support'], // RBAC filtering
538
+ allowedDomains: ['@company.com'], // Domain whitelist
539
+ exposeAccessToken: true, // For downstream API calls
540
+ }),
541
+ excludePaths: ['/health', '/api/public'],
542
+ });
543
+
544
+ // Basic auth fallback
545
+ createAuthPlugin({
546
+ adapter: basicAdapter({
547
+ username: 'admin',
548
+ password: process.env.ADMIN_PASSWORD!,
549
+ }),
550
+ });
551
+ ```
552
+
553
+ **Available Adapters:**
554
+ - `supertokensAdapter` - Supertokens email/password + social logins (requires `supertokens-node`)
555
+ - `auth0Adapter` - Auth0 OIDC (requires `express-openid-connect`)
556
+ - `supabaseAdapter` - Supabase JWT validation
557
+ - `basicAdapter` - HTTP Basic authentication
558
+
559
+ **Helper Functions:**
560
+ ```typescript
561
+ import { isAuthenticated, getAuthenticatedUser, getAccessToken } from '@qwickapps/server';
562
+
563
+ // In your route handlers
564
+ if (isAuthenticated(req)) {
565
+ const user = getAuthenticatedUser(req);
566
+ // { id, email, name, picture, emailVerified, roles }
567
+
568
+ const accessToken = getAccessToken(req);
569
+ // Use for downstream API calls
570
+ }
571
+ ```
572
+
573
+ **Middleware Helpers:**
574
+ ```typescript
575
+ import { requireAuth, requireRoles, requireAnyRole } from '@qwickapps/server';
576
+
577
+ // Require authentication
578
+ app.get('/admin', requireAuth(), (req, res) => { ... });
579
+
580
+ // Require specific roles (all required)
581
+ app.get('/admin/users', requireRoles('admin', 'user-manager'), (req, res) => { ... });
582
+
583
+ // Require any of the roles
584
+ app.get('/dashboard', requireAnyRole('admin', 'editor', 'viewer'), (req, res) => { ... });
585
+ ```
586
+
587
+ #### Users Plugin
588
+
589
+ Storage-agnostic user management with ban support.
590
+
591
+ ```typescript
592
+ import { createUsersPlugin, postgresUserStore, getPostgres } from '@qwickapps/server';
593
+ import { Pool } from 'pg';
594
+
595
+ // Create with PostgreSQL storage
596
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
597
+
598
+ createUsersPlugin({
599
+ store: postgresUserStore({
600
+ pool,
601
+ usersTable: 'users',
602
+ bansTable: 'user_bans',
603
+ autoCreateTables: true,
604
+ }),
605
+ bans: {
606
+ enabled: true,
607
+ supportTemporary: true, // Enable expiring bans
608
+ onBan: async (user, ban) => {
609
+ // Notify external systems, revoke sessions, etc.
610
+ console.log(`User ${user.email} banned: ${ban.reason}`);
611
+ },
612
+ onUnban: async (user) => {
613
+ console.log(`User ${user.email} unbanned`);
614
+ },
615
+ },
616
+ api: {
617
+ prefix: '/api/users',
618
+ crud: true, // GET/POST/PUT/DELETE /api/users
619
+ search: true, // GET /api/users?q=...
620
+ bans: true, // Ban management endpoints
621
+ },
622
+ });
623
+ ```
624
+
625
+ **REST API Endpoints:**
626
+ | Endpoint | Method | Description |
627
+ |----------|--------|-------------|
628
+ | `/api/users` | GET | List/search users |
629
+ | `/api/users` | POST | Create user |
630
+ | `/api/users/:id` | GET | Get user by ID |
631
+ | `/api/users/:id` | PUT | Update user |
632
+ | `/api/users/:id` | DELETE | Delete user |
633
+ | `/api/users/bans` | GET | List active bans |
634
+ | `/api/users/:id/ban` | GET | Get user's ban status |
635
+ | `/api/users/:id/ban` | POST | Ban user |
636
+ | `/api/users/:id/ban` | DELETE | Unban user |
637
+ | `/api/users/:id/bans` | GET | Get user's ban history |
638
+
639
+ **Helper Functions:**
640
+ ```typescript
641
+ import { getUserById, getUserByEmail, isUserBanned, findOrCreateUser } from '@qwickapps/server';
642
+
643
+ // Get user
644
+ const user = await getUserById('user-123');
645
+ const userByEmail = await getUserByEmail('test@example.com');
646
+
647
+ // Check ban status
648
+ const banned = await isUserBanned('user-123');
649
+
650
+ // Find or create from auth provider
651
+ const user = await findOrCreateUser({
652
+ email: 'user@example.com',
653
+ name: 'Test User',
654
+ external_id: 'auth0|12345',
655
+ provider: 'auth0',
656
+ });
657
+ ```
658
+
659
+ **Email Ban Support (for auth-only scenarios):**
660
+
661
+ For cases where you don't store users locally but need to ban by email:
662
+
663
+ ```typescript
664
+ import { isEmailBanned, getEmailBan, banEmail, unbanEmail } from '@qwickapps/server';
665
+
666
+ // Check if email is banned
667
+ const banned = await isEmailBanned('user@example.com');
668
+
669
+ // Get ban details
670
+ const ban = await getEmailBan('user@example.com');
671
+
672
+ // Ban an email
673
+ await banEmail({
674
+ email: 'user@example.com',
675
+ reason: 'Spam activity',
676
+ banned_by: 'admin@company.com',
677
+ duration: 86400, // 24 hours (optional, null = permanent)
678
+ });
679
+
680
+ // Unban an email
681
+ await unbanEmail({
682
+ email: 'user@example.com',
683
+ unbanned_by: 'admin@company.com',
684
+ note: 'Cleared after review',
685
+ });
686
+ ```
687
+
688
+ **Email Ban API Endpoints:**
689
+ | Endpoint | Method | Description |
690
+ |----------|--------|-------------|
691
+ | `/api/users/email-bans` | GET | List active email bans |
692
+ | `/api/users/email-bans/:email` | GET | Check email ban status |
693
+ | `/api/users/email-bans` | POST | Ban an email |
694
+ | `/api/users/email-bans/:email` | DELETE | Unban an email |
695
+
696
+ #### Preferences Plugin
697
+
698
+ Per-user preferences storage with PostgreSQL Row-Level Security (RLS) for data isolation.
699
+
700
+ ```typescript
701
+ import { createPreferencesPlugin, postgresPreferencesStore } from '@qwickapps/server';
702
+ import { Pool } from 'pg';
703
+
704
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
705
+
706
+ createPreferencesPlugin({
707
+ store: postgresPreferencesStore({
708
+ pool,
709
+ tableName: 'user_preferences',
710
+ autoCreateTables: true,
711
+ enableRLS: true, // Enable Row-Level Security
712
+ }),
713
+ defaults: {
714
+ theme: 'system',
715
+ notifications: {
716
+ email: true,
717
+ push: true,
718
+ },
719
+ },
720
+ api: {
721
+ prefix: '/preferences',
722
+ enabled: true,
723
+ },
724
+ });
725
+ ```
726
+
727
+ **Note:** The Preferences plugin requires the Users plugin to be loaded first, as it creates a foreign key reference to the users table.
728
+
729
+ **REST API Endpoints:**
730
+ | Endpoint | Method | Description |
731
+ |----------|--------|-------------|
732
+ | `/api/preferences` | GET | Get current user's preferences (merged with defaults) |
733
+ | `/api/preferences` | PUT | Update preferences (deep merge with existing) |
734
+ | `/api/preferences` | DELETE | Reset preferences to defaults |
735
+
736
+ **Helper Functions:**
737
+ ```typescript
738
+ import {
739
+ getPreferences,
740
+ updatePreferences,
741
+ deletePreferences,
742
+ getDefaultPreferences,
743
+ deepMerge,
744
+ } from '@qwickapps/server';
745
+
746
+ // Get user preferences (merged with defaults)
747
+ const prefs = await getPreferences('user-123');
748
+
749
+ // Update preferences (deep merge - preserves nested values)
750
+ const updated = await updatePreferences('user-123', {
751
+ theme: 'dark',
752
+ notifications: { email: false },
753
+ });
754
+ // Result: { theme: 'dark', notifications: { email: false, push: true } }
755
+
756
+ // Reset to defaults
757
+ await deletePreferences('user-123');
758
+
759
+ // Get configured defaults
760
+ const defaults = getDefaultPreferences();
761
+
762
+ // Deep merge utility (exported for custom use)
763
+ const merged = deepMerge(baseObject, overrides);
764
+ ```
765
+
766
+ **Security Features:**
767
+ - PostgreSQL Row-Level Security ensures users can only access their own preferences
768
+ - Transaction-safe RLS context for connection pooling compatibility
769
+ - Input validation: 100KB size limit, 10-level nesting depth
770
+ - Foreign key to users table with `ON DELETE CASCADE`
771
+
380
772
  ### Creating Custom Plugins
381
773
 
382
774
  ```typescript
@@ -6,10 +6,15 @@
6
6
  * Copyright (c) 2025 QwickApps.com. All rights reserved.
7
7
  */
8
8
  import { type LoggingConfig } from './logging.js';
9
- import type { ControlPanelConfig, ControlPanelPlugin, ControlPanelInstance, Logger } from './types.js';
9
+ import type { ControlPanelConfig, ControlPanelInstance, Logger } from './types.js';
10
+ import { type Plugin, type PluginConfig } from './plugin-registry.js';
10
11
  export interface CreateControlPanelOptions {
11
12
  config: ControlPanelConfig;
12
- plugins?: ControlPanelPlugin[];
13
+ /** Plugins to start with the control panel */
14
+ plugins?: Array<{
15
+ plugin: Plugin;
16
+ config?: PluginConfig;
17
+ }>;
13
18
  logger?: Logger;
14
19
  /** Logging configuration */
15
20
  logging?: LoggingConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"control-panel.d.ts","sourceRoot":"","sources":["../../src/core/control-panel.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,EAA4C,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5F,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EAIpB,MAAM,EACP,MAAM,YAAY,CAAC;AAWpB,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,oBAAoB,CA4Q3F"}
1
+ {"version":3,"file":"control-panel.d.ts","sourceRoot":"","sources":["../../src/core/control-panel.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,EAA4C,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5F,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EAGpB,MAAM,EACP,MAAM,YAAY,CAAC;AACpB,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,YAAY,EAElB,MAAM,sBAAsB,CAAC;AAuB9B,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC,CAAC;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,oBAAoB,CA+U3F"}