@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.
- package/README.md +392 -0
- package/dist/core/control-panel.d.ts +7 -2
- package/dist/core/control-panel.d.ts.map +1 -1
- package/dist/core/control-panel.js +120 -54
- package/dist/core/control-panel.js.map +1 -1
- package/dist/core/gateway.d.ts +159 -79
- package/dist/core/gateway.d.ts.map +1 -1
- package/dist/core/gateway.js +679 -319
- package/dist/core/gateway.js.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/plugin-registry.d.ts +307 -0
- package/dist/core/plugin-registry.d.ts.map +1 -0
- package/dist/core/plugin-registry.js +352 -0
- package/dist/core/plugin-registry.js.map +1 -0
- package/dist/core/types.d.ts +16 -33
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/plugins/auth/adapters/auth0-adapter.d.ts +14 -0
- package/dist/plugins/auth/adapters/auth0-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/auth0-adapter.js +179 -0
- package/dist/plugins/auth/adapters/auth0-adapter.js.map +1 -0
- package/dist/plugins/auth/adapters/basic-adapter.d.ts +13 -0
- package/dist/plugins/auth/adapters/basic-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/basic-adapter.js +51 -0
- package/dist/plugins/auth/adapters/basic-adapter.js.map +1 -0
- package/dist/plugins/auth/adapters/index.d.ts +10 -0
- package/dist/plugins/auth/adapters/index.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/index.js +10 -0
- package/dist/plugins/auth/adapters/index.js.map +1 -0
- package/dist/plugins/auth/adapters/supabase-adapter.d.ts +13 -0
- package/dist/plugins/auth/adapters/supabase-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/supabase-adapter.js +109 -0
- package/dist/plugins/auth/adapters/supabase-adapter.js.map +1 -0
- package/dist/plugins/auth/adapters/supertokens-adapter.d.ts +18 -0
- package/dist/plugins/auth/adapters/supertokens-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/supertokens-adapter.js +267 -0
- package/dist/plugins/auth/adapters/supertokens-adapter.js.map +1 -0
- package/dist/plugins/auth/auth-plugin.d.ts +40 -0
- package/dist/plugins/auth/auth-plugin.d.ts.map +1 -0
- package/dist/plugins/auth/auth-plugin.js +255 -0
- package/dist/plugins/auth/auth-plugin.js.map +1 -0
- package/dist/plugins/auth/auth-plugin.test.d.ts +9 -0
- package/dist/plugins/auth/auth-plugin.test.d.ts.map +1 -0
- package/dist/plugins/auth/auth-plugin.test.js +147 -0
- package/dist/plugins/auth/auth-plugin.test.js.map +1 -0
- package/dist/plugins/auth/env-config.d.ts +88 -0
- package/dist/plugins/auth/env-config.d.ts.map +1 -0
- package/dist/plugins/auth/env-config.js +489 -0
- package/dist/plugins/auth/env-config.js.map +1 -0
- package/dist/plugins/auth/index.d.ts +14 -0
- package/dist/plugins/auth/index.d.ts.map +1 -0
- package/dist/plugins/auth/index.js +16 -0
- package/dist/plugins/auth/index.js.map +1 -0
- package/dist/plugins/auth/supertokens-adapter.test.d.ts +10 -0
- package/dist/plugins/auth/supertokens-adapter.test.d.ts.map +1 -0
- package/dist/plugins/auth/supertokens-adapter.test.js +486 -0
- package/dist/plugins/auth/supertokens-adapter.test.js.map +1 -0
- package/dist/plugins/auth/types.d.ts +218 -0
- package/dist/plugins/auth/types.d.ts.map +1 -0
- package/dist/plugins/auth/types.js +14 -0
- package/dist/plugins/auth/types.js.map +1 -0
- package/dist/plugins/bans/bans-plugin.d.ts +59 -0
- package/dist/plugins/bans/bans-plugin.d.ts.map +1 -0
- package/dist/plugins/bans/bans-plugin.js +428 -0
- package/dist/plugins/bans/bans-plugin.js.map +1 -0
- package/dist/plugins/bans/index.d.ts +9 -0
- package/dist/plugins/bans/index.d.ts.map +1 -0
- package/dist/plugins/bans/index.js +10 -0
- package/dist/plugins/bans/index.js.map +1 -0
- package/dist/plugins/bans/stores/index.d.ts +7 -0
- package/dist/plugins/bans/stores/index.d.ts.map +1 -0
- package/dist/plugins/bans/stores/index.js +7 -0
- package/dist/plugins/bans/stores/index.js.map +1 -0
- package/dist/plugins/bans/stores/postgres-store.d.ts +29 -0
- package/dist/plugins/bans/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/bans/stores/postgres-store.js +132 -0
- package/dist/plugins/bans/stores/postgres-store.js.map +1 -0
- package/dist/plugins/bans/types.d.ts +128 -0
- package/dist/plugins/bans/types.d.ts.map +1 -0
- package/dist/plugins/bans/types.js +11 -0
- package/dist/plugins/bans/types.js.map +1 -0
- package/dist/plugins/cache-plugin.d.ts +14 -3
- package/dist/plugins/cache-plugin.d.ts.map +1 -1
- package/dist/plugins/cache-plugin.js +27 -7
- package/dist/plugins/cache-plugin.js.map +1 -1
- package/dist/plugins/cache-plugin.test.js +99 -32
- package/dist/plugins/cache-plugin.test.js.map +1 -1
- package/dist/plugins/config-plugin.d.ts +3 -2
- package/dist/plugins/config-plugin.d.ts.map +1 -1
- package/dist/plugins/config-plugin.js +17 -10
- package/dist/plugins/config-plugin.js.map +1 -1
- package/dist/plugins/diagnostics-plugin.d.ts +2 -2
- package/dist/plugins/diagnostics-plugin.d.ts.map +1 -1
- package/dist/plugins/diagnostics-plugin.js +17 -10
- package/dist/plugins/diagnostics-plugin.js.map +1 -1
- package/dist/plugins/entitlements/entitlements-plugin.d.ts +95 -0
- package/dist/plugins/entitlements/entitlements-plugin.d.ts.map +1 -0
- package/dist/plugins/entitlements/entitlements-plugin.js +707 -0
- package/dist/plugins/entitlements/entitlements-plugin.js.map +1 -0
- package/dist/plugins/entitlements/index.d.ts +12 -0
- package/dist/plugins/entitlements/index.d.ts.map +1 -0
- package/dist/plugins/entitlements/index.js +16 -0
- package/dist/plugins/entitlements/index.js.map +1 -0
- package/dist/plugins/entitlements/sources/index.d.ts +9 -0
- package/dist/plugins/entitlements/sources/index.d.ts.map +1 -0
- package/dist/plugins/entitlements/sources/index.js +9 -0
- package/dist/plugins/entitlements/sources/index.js.map +1 -0
- package/dist/plugins/entitlements/sources/postgres-source.d.ts +29 -0
- package/dist/plugins/entitlements/sources/postgres-source.d.ts.map +1 -0
- package/dist/plugins/entitlements/sources/postgres-source.js +169 -0
- package/dist/plugins/entitlements/sources/postgres-source.js.map +1 -0
- package/dist/plugins/entitlements/types.d.ts +232 -0
- package/dist/plugins/entitlements/types.d.ts.map +1 -0
- package/dist/plugins/entitlements/types.js +11 -0
- package/dist/plugins/entitlements/types.js.map +1 -0
- package/dist/plugins/frontend-app-plugin.d.ts +9 -3
- package/dist/plugins/frontend-app-plugin.d.ts.map +1 -1
- package/dist/plugins/frontend-app-plugin.js +14 -9
- package/dist/plugins/frontend-app-plugin.js.map +1 -1
- package/dist/plugins/health-plugin.d.ts +5 -2
- package/dist/plugins/health-plugin.d.ts.map +1 -1
- package/dist/plugins/health-plugin.js +20 -5
- package/dist/plugins/health-plugin.js.map +1 -1
- package/dist/plugins/index.d.ts +10 -2
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +10 -2
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/logs-plugin.d.ts +3 -2
- package/dist/plugins/logs-plugin.d.ts.map +1 -1
- package/dist/plugins/logs-plugin.js +21 -12
- package/dist/plugins/logs-plugin.js.map +1 -1
- package/dist/plugins/postgres-plugin.d.ts +3 -3
- package/dist/plugins/postgres-plugin.d.ts.map +1 -1
- package/dist/plugins/postgres-plugin.js +9 -7
- package/dist/plugins/postgres-plugin.js.map +1 -1
- package/dist/plugins/postgres-plugin.test.js +50 -29
- package/dist/plugins/postgres-plugin.test.js.map +1 -1
- package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts +7 -0
- package/dist/plugins/preferences/__tests__/deep-merge.test.d.ts.map +1 -0
- package/dist/plugins/preferences/__tests__/deep-merge.test.js +215 -0
- package/dist/plugins/preferences/__tests__/deep-merge.test.js.map +1 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts +7 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.d.ts.map +1 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.js +265 -0
- package/dist/plugins/preferences/__tests__/preferences-plugin.test.js.map +1 -0
- package/dist/plugins/preferences/index.d.ts +12 -0
- package/dist/plugins/preferences/index.d.ts.map +1 -0
- package/dist/plugins/preferences/index.js +13 -0
- package/dist/plugins/preferences/index.js.map +1 -0
- package/dist/plugins/preferences/preferences-plugin.d.ts +39 -0
- package/dist/plugins/preferences/preferences-plugin.d.ts.map +1 -0
- package/dist/plugins/preferences/preferences-plugin.js +226 -0
- package/dist/plugins/preferences/preferences-plugin.js.map +1 -0
- package/dist/plugins/preferences/stores/index.d.ts +9 -0
- package/dist/plugins/preferences/stores/index.d.ts.map +1 -0
- package/dist/plugins/preferences/stores/index.js +9 -0
- package/dist/plugins/preferences/stores/index.js.map +1 -0
- package/dist/plugins/preferences/stores/postgres-store.d.ts +41 -0
- package/dist/plugins/preferences/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/preferences/stores/postgres-store.js +181 -0
- package/dist/plugins/preferences/stores/postgres-store.js.map +1 -0
- package/dist/plugins/preferences/types.d.ts +91 -0
- package/dist/plugins/preferences/types.d.ts.map +1 -0
- package/dist/plugins/preferences/types.js +10 -0
- package/dist/plugins/preferences/types.js.map +1 -0
- package/dist/plugins/users/__tests__/users-plugin.test.d.ts +9 -0
- package/dist/plugins/users/__tests__/users-plugin.test.d.ts.map +1 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js +546 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -0
- package/dist/plugins/users/index.d.ts +12 -0
- package/dist/plugins/users/index.d.ts.map +1 -0
- package/dist/plugins/users/index.js +13 -0
- package/dist/plugins/users/index.js.map +1 -0
- package/dist/plugins/users/stores/index.d.ts +7 -0
- package/dist/plugins/users/stores/index.d.ts.map +1 -0
- package/dist/plugins/users/stores/index.js +7 -0
- package/dist/plugins/users/stores/index.js.map +1 -0
- package/dist/plugins/users/stores/postgres-store.d.ts +28 -0
- package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/users/stores/postgres-store.js +157 -0
- package/dist/plugins/users/stores/postgres-store.js.map +1 -0
- package/dist/plugins/users/types.d.ts +225 -0
- package/dist/plugins/users/types.d.ts.map +1 -0
- package/dist/plugins/users/types.js +12 -0
- package/dist/plugins/users/types.js.map +1 -0
- package/dist/plugins/users/users-plugin.d.ts +45 -0
- package/dist/plugins/users/users-plugin.d.ts.map +1 -0
- package/dist/plugins/users/users-plugin.js +359 -0
- package/dist/plugins/users/users-plugin.js.map +1 -0
- package/dist-ui/assets/index-BY8OxNgO.js +465 -0
- package/dist-ui/assets/index-BY8OxNgO.js.map +1 -0
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/api/controlPanelApi.d.ts +278 -0
- package/dist-ui-lib/components/ControlPanelApp.d.ts +61 -0
- package/dist-ui-lib/components/index.d.ts +18 -0
- package/dist-ui-lib/config/AppConfig.d.ts +7 -0
- package/dist-ui-lib/dashboard/DashboardWidgetRegistry.d.ts +62 -0
- package/dist-ui-lib/dashboard/DashboardWidgetRenderer.d.ts +8 -0
- package/dist-ui-lib/dashboard/PluginWidgetRenderer.d.ts +19 -0
- package/dist-ui-lib/dashboard/WidgetComponentRegistry.d.ts +48 -0
- package/dist-ui-lib/dashboard/builtInWidgets.d.ts +25 -0
- package/dist-ui-lib/dashboard/index.d.ts +13 -0
- package/dist-ui-lib/dashboard/widgets/ServiceHealthWidget.d.ts +12 -0
- package/dist-ui-lib/dashboard/widgets/index.d.ts +6 -0
- package/dist-ui-lib/index.js +5172 -0
- package/dist-ui-lib/index.js.map +1 -0
- package/dist-ui-lib/pages/AuthPage.d.ts +1 -0
- package/dist-ui-lib/pages/ConfigPage.d.ts +1 -0
- package/dist-ui-lib/pages/DashboardPage.d.ts +1 -0
- package/dist-ui-lib/pages/DiagnosticsPage.d.ts +1 -0
- package/dist-ui-lib/pages/EntitlementsPage.d.ts +17 -0
- package/dist-ui-lib/pages/LogsPage.d.ts +1 -0
- package/dist-ui-lib/pages/NotFoundPage.d.ts +1 -0
- package/dist-ui-lib/pages/PluginPage.d.ts +15 -0
- package/dist-ui-lib/pages/PluginsPage.d.ts +1 -0
- package/dist-ui-lib/pages/SystemPage.d.ts +1 -0
- package/dist-ui-lib/pages/UsersPage.d.ts +22 -0
- package/package.json +24 -7
- package/src/core/control-panel.ts +145 -61
- package/src/core/gateway.ts +863 -403
- package/src/core/index.ts +21 -2
- package/src/core/plugin-registry.ts +716 -0
- package/src/core/types.ts +31 -37
- package/src/index.ts +125 -19
- package/src/plugins/auth/adapters/auth0-adapter.ts +214 -0
- package/src/plugins/auth/adapters/basic-adapter.ts +61 -0
- package/src/plugins/auth/adapters/index.ts +10 -0
- package/src/plugins/auth/adapters/supabase-adapter.ts +149 -0
- package/src/plugins/auth/adapters/supertokens-adapter.ts +326 -0
- package/src/plugins/auth/auth-plugin.test.ts +176 -0
- package/src/plugins/auth/auth-plugin.ts +303 -0
- package/src/plugins/auth/env-config.ts +572 -0
- package/src/plugins/auth/index.ts +42 -0
- package/src/plugins/auth/supertokens-adapter.test.ts +621 -0
- package/src/plugins/auth/types.ts +245 -0
- package/src/plugins/bans/bans-plugin.ts +485 -0
- package/src/plugins/bans/index.ts +31 -0
- package/src/plugins/bans/stores/index.ts +7 -0
- package/src/plugins/bans/stores/postgres-store.ts +195 -0
- package/src/plugins/bans/types.ts +141 -0
- package/src/plugins/cache-plugin.test.ts +108 -32
- package/src/plugins/cache-plugin.ts +40 -9
- package/src/plugins/config-plugin.ts +23 -12
- package/src/plugins/diagnostics-plugin.ts +22 -12
- package/src/plugins/entitlements/entitlements-plugin.ts +820 -0
- package/src/plugins/entitlements/index.ts +51 -0
- package/src/plugins/entitlements/sources/index.ts +9 -0
- package/src/plugins/entitlements/sources/postgres-source.ts +253 -0
- package/src/plugins/entitlements/types.ts +256 -0
- package/src/plugins/frontend-app-plugin.ts +24 -12
- package/src/plugins/health-plugin.ts +27 -7
- package/src/plugins/index.ts +132 -4
- package/src/plugins/logs-plugin.ts +28 -14
- package/src/plugins/postgres-plugin.test.ts +52 -29
- package/src/plugins/postgres-plugin.ts +11 -9
- package/src/plugins/preferences/__tests__/deep-merge.test.ts +242 -0
- package/src/plugins/preferences/__tests__/preferences-plugin.test.ts +350 -0
- package/src/plugins/preferences/index.ts +30 -0
- package/src/plugins/preferences/preferences-plugin.ts +270 -0
- package/src/plugins/preferences/stores/index.ts +9 -0
- package/src/plugins/preferences/stores/postgres-store.ts +252 -0
- package/src/plugins/preferences/types.ts +100 -0
- package/src/plugins/users/__tests__/users-plugin.test.ts +690 -0
- package/src/plugins/users/index.ts +38 -0
- package/src/plugins/users/stores/index.ts +7 -0
- package/src/plugins/users/stores/postgres-store.ts +225 -0
- package/src/plugins/users/types.ts +247 -0
- package/src/plugins/users/users-plugin.ts +418 -0
- package/ui/src/App.tsx +188 -31
- package/ui/src/api/controlPanelApi.ts +453 -1
- package/ui/src/components/ControlPanelApp.tsx +212 -0
- package/ui/src/components/index.ts +62 -0
- package/ui/src/dashboard/DashboardWidgetRegistry.tsx +129 -0
- package/ui/src/dashboard/DashboardWidgetRenderer.tsx +34 -0
- package/ui/src/dashboard/PluginWidgetRenderer.tsx +118 -0
- package/ui/src/dashboard/WidgetComponentRegistry.tsx +120 -0
- package/ui/src/dashboard/builtInWidgets.tsx +35 -0
- package/ui/src/dashboard/index.ts +35 -0
- package/ui/src/dashboard/widgets/ServiceHealthWidget.tsx +140 -0
- package/ui/src/dashboard/widgets/index.ts +7 -0
- package/ui/src/pages/AuthPage.tsx +259 -0
- package/ui/src/pages/DashboardPage.tsx +28 -149
- package/ui/src/pages/EntitlementsPage.tsx +557 -0
- package/ui/src/pages/LogsPage.tsx +174 -8
- package/ui/src/pages/PluginPage.tsx +148 -0
- package/ui/src/pages/PluginsPage.tsx +394 -0
- package/ui/src/pages/SystemPage.tsx +445 -0
- package/ui/src/pages/UsersPage.tsx +837 -0
- package/ui/tsconfig.lib.json +11 -0
- package/ui/vite.lib.config.ts +56 -0
- package/dist-ui/assets/index-CW1BviRn.js +0 -465
- package/dist-ui/assets/index-CW1BviRn.js.map +0 -1
- 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,
|
|
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
|
-
|
|
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,
|
|
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"}
|