@qwickapps/server 1.7.0 → 1.7.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/CHANGELOG.md +53 -0
- package/README.md +13 -116
- package/dist/src/core/control-panel.d.ts.map +1 -1
- package/dist/src/core/control-panel.js +6 -4
- package/dist/src/core/control-panel.js.map +1 -1
- package/dist/src/core/gateway.d.ts.map +1 -1
- package/dist/src/core/gateway.js +24 -2
- package/dist/src/core/gateway.js.map +1 -1
- package/dist/src/core/plugin-registry.d.ts +15 -2
- package/dist/src/core/plugin-registry.d.ts.map +1 -1
- package/dist/src/core/plugin-registry.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugins/api-keys/stores/postgres-store.d.ts.map +1 -1
- package/dist/src/plugins/api-keys/stores/postgres-store.js +29 -0
- package/dist/src/plugins/api-keys/stores/postgres-store.js.map +1 -1
- package/dist/src/plugins/auth/auth-plugin.d.ts.map +1 -1
- package/dist/src/plugins/auth/auth-plugin.js +4 -2
- package/dist/src/plugins/auth/auth-plugin.js.map +1 -1
- package/dist/src/plugins/auth/env-config.d.ts.map +1 -1
- package/dist/src/plugins/auth/env-config.js +1 -0
- package/dist/src/plugins/auth/env-config.js.map +1 -1
- package/dist/src/plugins/bans/index.d.ts +1 -1
- package/dist/src/plugins/bans/index.d.ts.map +1 -1
- package/dist/src/plugins/bans/index.js +1 -1
- package/dist/src/plugins/bans/index.js.map +1 -1
- package/dist/src/plugins/bans/stores/in-memory-store.d.ts +34 -0
- package/dist/src/plugins/bans/stores/in-memory-store.d.ts.map +1 -0
- package/dist/src/plugins/bans/stores/in-memory-store.js +97 -0
- package/dist/src/plugins/bans/stores/in-memory-store.js.map +1 -0
- package/dist/src/plugins/bans/stores/index.d.ts +1 -0
- package/dist/src/plugins/bans/stores/index.d.ts.map +1 -1
- package/dist/src/plugins/bans/stores/index.js +1 -0
- package/dist/src/plugins/bans/stores/index.js.map +1 -1
- package/dist/src/plugins/cache-plugin.d.ts +35 -16
- package/dist/src/plugins/cache-plugin.d.ts.map +1 -1
- package/dist/src/plugins/cache-plugin.js +299 -20
- package/dist/src/plugins/cache-plugin.js.map +1 -1
- package/dist/src/plugins/cms/cms-plugin.d.ts.map +1 -1
- package/dist/src/plugins/cms/cms-plugin.js +3 -1
- package/dist/src/plugins/cms/cms-plugin.js.map +1 -1
- package/dist/src/plugins/entitlements/index.d.ts +1 -1
- package/dist/src/plugins/entitlements/index.d.ts.map +1 -1
- package/dist/src/plugins/entitlements/index.js +1 -1
- package/dist/src/plugins/entitlements/index.js.map +1 -1
- package/dist/src/plugins/entitlements/sources/in-memory-source.d.ts +9 -0
- package/dist/src/plugins/entitlements/sources/in-memory-source.d.ts.map +1 -0
- package/dist/src/plugins/entitlements/sources/in-memory-source.js +65 -0
- package/dist/src/plugins/entitlements/sources/in-memory-source.js.map +1 -0
- package/dist/src/plugins/entitlements/sources/index.d.ts +1 -0
- package/dist/src/plugins/entitlements/sources/index.d.ts.map +1 -1
- package/dist/src/plugins/entitlements/sources/index.js +1 -0
- package/dist/src/plugins/entitlements/sources/index.js.map +1 -1
- package/dist/src/plugins/health-plugin.d.ts.map +1 -1
- package/dist/src/plugins/health-plugin.js +1 -0
- package/dist/src/plugins/health-plugin.js.map +1 -1
- package/dist/src/plugins/index.d.ts +4 -4
- package/dist/src/plugins/index.d.ts.map +1 -1
- package/dist/src/plugins/index.js +4 -4
- package/dist/src/plugins/index.js.map +1 -1
- package/dist/src/plugins/logs-plugin.d.ts.map +1 -1
- package/dist/src/plugins/logs-plugin.js +49 -1
- package/dist/src/plugins/logs-plugin.js.map +1 -1
- package/dist/src/plugins/maintenance-plugin.d.ts.map +1 -1
- package/dist/src/plugins/maintenance-plugin.js +39 -0
- package/dist/src/plugins/maintenance-plugin.js.map +1 -1
- package/dist/src/plugins/notifications/notifications-plugin.d.ts.map +1 -1
- package/dist/src/plugins/notifications/notifications-plugin.js +1 -0
- package/dist/src/plugins/notifications/notifications-plugin.js.map +1 -1
- package/dist/src/plugins/postgres-plugin.d.ts +3 -1
- package/dist/src/plugins/postgres-plugin.d.ts.map +1 -1
- package/dist/src/plugins/postgres-plugin.js +18 -8
- package/dist/src/plugins/postgres-plugin.js.map +1 -1
- package/dist/src/plugins/tenants/index.d.ts +1 -1
- package/dist/src/plugins/tenants/index.d.ts.map +1 -1
- package/dist/src/plugins/tenants/index.js +1 -1
- package/dist/src/plugins/tenants/index.js.map +1 -1
- package/dist/src/plugins/tenants/stores/in-memory-store.d.ts +59 -0
- package/dist/src/plugins/tenants/stores/in-memory-store.d.ts.map +1 -0
- package/dist/src/plugins/tenants/stores/in-memory-store.js +257 -0
- package/dist/src/plugins/tenants/stores/in-memory-store.js.map +1 -0
- package/dist/src/plugins/tenants/stores/index.d.ts +8 -0
- package/dist/src/plugins/tenants/stores/index.d.ts.map +1 -0
- package/dist/src/plugins/tenants/stores/index.js +8 -0
- package/dist/src/plugins/tenants/stores/index.js.map +1 -0
- package/dist/src/plugins/tenants/tenants-plugin.js +3 -3
- package/dist/src/plugins/tenants/tenants-plugin.js.map +1 -1
- package/dist/src/plugins/users/index.d.ts +1 -1
- package/dist/src/plugins/users/index.d.ts.map +1 -1
- package/dist/src/plugins/users/index.js +1 -1
- package/dist/src/plugins/users/index.js.map +1 -1
- package/dist/src/plugins/users/stores/in-memory-store.d.ts +36 -0
- package/dist/src/plugins/users/stores/in-memory-store.d.ts.map +1 -0
- package/dist/src/plugins/users/stores/in-memory-store.js +122 -0
- package/dist/src/plugins/users/stores/in-memory-store.js.map +1 -0
- package/dist/src/plugins/users/stores/index.d.ts +1 -0
- package/dist/src/plugins/users/stores/index.d.ts.map +1 -1
- package/dist/src/plugins/users/stores/index.js +1 -0
- package/dist/src/plugins/users/stores/index.js.map +1 -1
- package/dist/ui/src/api/controlPanelApi.d.ts +10 -1
- package/dist/ui/src/api/controlPanelApi.d.ts.map +1 -1
- package/dist/ui/src/api/controlPanelApi.js.map +1 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.d.ts +3 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.d.ts.map +1 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.js +5 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.js.map +1 -1
- package/dist/ui/src/dashboard/builtInWidgets.d.ts.map +1 -1
- package/dist/ui/src/dashboard/builtInWidgets.js +13 -1
- package/dist/ui/src/dashboard/builtInWidgets.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.d.ts +11 -0
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js +77 -0
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.js +14 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.js +14 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.d.ts +11 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js +96 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js +55 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.js +14 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/index.d.ts +6 -0
- package/dist/ui/src/dashboard/widgets/index.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/index.js +6 -0
- package/dist/ui/src/dashboard/widgets/index.js.map +1 -1
- package/dist/ui/src/pages/DashboardPage.js +1 -1
- package/dist/ui/src/pages/DashboardPage.js.map +1 -1
- package/dist-ui/assets/{index-lm1yX6UD.js → index-8y0jDGcd.js} +112 -112
- package/dist-ui/assets/{index-lm1yX6UD.js.map → index-8y0jDGcd.js.map} +1 -1
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/index.js +3109 -2774
- package/dist-ui-lib/index.js.map +1 -1
- package/dist-ui-lib/src/api/controlPanelApi.d.ts +10 -1
- package/dist-ui-lib/src/dashboard/PluginWidgetRenderer.d.ts +3 -1
- package/dist-ui-lib/src/dashboard/widgets/CacheMaintenanceWidget.d.ts +10 -0
- package/dist-ui-lib/src/dashboard/widgets/DatabaseOpsWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/EnvironmentConfigWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/LogsMaintenanceWidget.d.ts +10 -0
- package/dist-ui-lib/src/dashboard/widgets/SeedManagementWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/ServiceControlWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/index.d.ts +6 -0
- package/package.json +5 -2
- package/src/core/control-panel.ts +6 -4
- package/src/core/gateway.ts +25 -2
- package/src/core/plugin-registry.ts +15 -2
- package/src/index.ts +53 -0
- package/src/plugins/api-keys/stores/postgres-store.ts +30 -0
- package/src/plugins/auth/auth-plugin.ts +4 -2
- package/src/plugins/auth/env-config.ts +1 -0
- package/src/plugins/bans/index.ts +1 -1
- package/src/plugins/bans/stores/in-memory-store.ts +106 -0
- package/src/plugins/bans/stores/index.ts +1 -0
- package/src/plugins/cache-plugin.test.ts +2 -2
- package/src/plugins/cache-plugin.ts +331 -30
- package/src/plugins/cms/cms-plugin.ts +3 -1
- package/src/plugins/entitlements/index.ts +1 -1
- package/src/plugins/entitlements/sources/in-memory-source.ts +76 -0
- package/src/plugins/entitlements/sources/index.ts +1 -0
- package/src/plugins/health-plugin.ts +1 -0
- package/src/plugins/index.ts +4 -1
- package/src/plugins/logs-plugin.ts +55 -1
- package/src/plugins/maintenance-plugin.ts +43 -0
- package/src/plugins/notifications/notifications-plugin.ts +1 -0
- package/src/plugins/postgres-plugin.test.ts +2 -2
- package/src/plugins/postgres-plugin.ts +20 -9
- package/src/plugins/tenants/index.ts +1 -1
- package/src/plugins/tenants/stores/in-memory-store.ts +335 -0
- package/src/plugins/tenants/stores/index.ts +13 -0
- package/src/plugins/tenants/tenants-plugin.ts +3 -3
- package/src/plugins/users/index.ts +1 -1
- package/src/plugins/users/stores/in-memory-store.ts +140 -0
- package/src/plugins/users/stores/index.ts +1 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/pg-mem-pool.ts +33 -0
- package/ui/src/api/controlPanelApi.ts +10 -1
- package/ui/src/dashboard/PluginWidgetRenderer.tsx +8 -0
- package/ui/src/dashboard/builtInWidgets.tsx +19 -1
- package/ui/src/dashboard/widgets/CacheMaintenanceWidget.tsx +195 -0
- package/ui/src/dashboard/widgets/DatabaseOpsWidget.tsx +29 -0
- package/ui/src/dashboard/widgets/EnvironmentConfigWidget.tsx +29 -0
- package/ui/src/dashboard/widgets/LogsMaintenanceWidget.tsx +247 -0
- package/ui/src/dashboard/widgets/SeedManagementWidget.tsx +128 -0
- package/ui/src/dashboard/widgets/ServiceControlWidget.tsx +29 -0
- package/ui/src/dashboard/widgets/index.ts +6 -0
- package/ui/src/pages/DashboardPage.tsx +2 -2
- package/ui/src/pages/MaintenancePage.tsx +1 -1
|
@@ -245,9 +245,18 @@ export interface WidgetContribution {
|
|
|
245
245
|
title: string;
|
|
246
246
|
/** Component name to render (matched by frontend widget registry) */
|
|
247
247
|
component: string;
|
|
248
|
+
/**
|
|
249
|
+
* Widget type/category - determines which page(s) can display this widget
|
|
250
|
+
* - 'status': System health, service status, monitoring metrics (Dashboard)
|
|
251
|
+
* - 'maintenance': Operational tasks like seeding, service control, config (Maintenance page)
|
|
252
|
+
* - 'analytics': Charts, graphs, usage metrics (Dashboard or Analytics page)
|
|
253
|
+
* - 'monitoring': Performance, logs, real-time data (Monitoring page)
|
|
254
|
+
* - 'custom': Custom widgets for specific use cases
|
|
255
|
+
*/
|
|
256
|
+
type: 'status' | 'maintenance' | 'analytics' | 'monitoring' | 'custom';
|
|
248
257
|
/** Priority for ordering (lower = first, default: 100) */
|
|
249
258
|
priority?: number;
|
|
250
|
-
/** Whether this widget is shown by default */
|
|
259
|
+
/** Whether this widget is shown by default on its designated page */
|
|
251
260
|
showByDefault?: boolean;
|
|
252
261
|
pluginId: string;
|
|
253
262
|
}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
8
|
*/
|
|
9
9
|
interface PluginWidgetRendererProps {
|
|
10
|
+
/** Filter widgets by type (e.g., 'status' for dashboard, 'maintenance' for maintenance page) */
|
|
11
|
+
widgetType?: 'status' | 'maintenance' | 'analytics' | 'monitoring' | 'custom';
|
|
10
12
|
/** Only show widgets marked as showByDefault (default: true) */
|
|
11
13
|
defaultOnly?: boolean;
|
|
12
14
|
/** Additional widget IDs to show (beyond showByDefault) */
|
|
@@ -15,5 +17,5 @@ interface PluginWidgetRendererProps {
|
|
|
15
17
|
/**
|
|
16
18
|
* Renders widgets from plugins that have registered them via the server API
|
|
17
19
|
*/
|
|
18
|
-
export declare function PluginWidgetRenderer({ defaultOnly, additionalWidgetIds, }: PluginWidgetRendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
20
|
+
export declare function PluginWidgetRenderer({ widgetType, defaultOnly, additionalWidgetIds, }: PluginWidgetRendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
19
21
|
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache Maintenance Widget
|
|
3
|
+
*
|
|
4
|
+
* Provides cache management operations:
|
|
5
|
+
* - View cache statistics
|
|
6
|
+
* - Clear cache (flush all keys)
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
9
|
+
*/
|
|
10
|
+
export declare function CacheMaintenanceWidget(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Operations Widget
|
|
3
|
+
*
|
|
4
|
+
* Provides database backup, restore, and maintenance operations.
|
|
5
|
+
* Part of the maintenance plugin.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
export declare function DatabaseOpsWidget(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Configuration Widget
|
|
3
|
+
*
|
|
4
|
+
* Displays and allows editing environment variables.
|
|
5
|
+
* Part of the maintenance plugin.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
export declare function EnvironmentConfigWidget(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs Maintenance Widget
|
|
3
|
+
*
|
|
4
|
+
* Provides log management operations:
|
|
5
|
+
* - View log statistics
|
|
6
|
+
* - Clear log files
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
9
|
+
*/
|
|
10
|
+
export declare function LogsMaintenanceWidget(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed Management Widget
|
|
3
|
+
*
|
|
4
|
+
* Displays available seed scripts and allows executing them.
|
|
5
|
+
* Part of the maintenance plugin.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
export declare function SeedManagementWidget(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Control Widget
|
|
3
|
+
*
|
|
4
|
+
* Provides controls for starting, stopping, and restarting services.
|
|
5
|
+
* Part of the maintenance plugin.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ServiceControlWidget(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,3 +9,9 @@ export { AuthStatusWidget } from './AuthStatusWidget';
|
|
|
9
9
|
export { NotificationsStatsWidget } from './NotificationsStatsWidget';
|
|
10
10
|
export { CMSStatusWidget } from './CMSStatusWidget';
|
|
11
11
|
export { CMSMaintenanceWidget } from './CMSMaintenanceWidget';
|
|
12
|
+
export { SeedManagementWidget } from './SeedManagementWidget';
|
|
13
|
+
export { ServiceControlWidget } from './ServiceControlWidget';
|
|
14
|
+
export { EnvironmentConfigWidget } from './EnvironmentConfigWidget';
|
|
15
|
+
export { DatabaseOpsWidget } from './DatabaseOpsWidget';
|
|
16
|
+
export { LogsMaintenanceWidget } from './LogsMaintenanceWidget';
|
|
17
|
+
export { CacheMaintenanceWidget } from './CacheMaintenanceWidget';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qwickapps/server",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "Plugin-based application server framework for building websites, APIs, admin dashboards, and full-stack products",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"test:e2e": "playwright test",
|
|
42
42
|
"test:e2e:ui": "playwright test --ui",
|
|
43
43
|
"test:e2e:headed": "playwright test --headed",
|
|
44
|
-
"demo": "
|
|
44
|
+
"demo": "npm run build:server && pnpm tsx examples/demo-server.ts",
|
|
45
|
+
"demo:gateway": "npm run build:server && pnpm tsx examples/demo-gateway.ts",
|
|
46
|
+
"demo:all": "npm run build:server && pnpm tsx examples/demo-all.ts",
|
|
45
47
|
"type-check": "tsc --noEmit",
|
|
46
48
|
"type-check:ui": "cd ui && tsc --noEmit",
|
|
47
49
|
"validate:clean-install": "./qa/clean-install/validate.sh",
|
|
@@ -81,6 +83,7 @@
|
|
|
81
83
|
"ioredis": "^5.4.0",
|
|
82
84
|
"jsdom": "^25.0.0",
|
|
83
85
|
"pg": "^8.13.0",
|
|
86
|
+
"pg-mem": "^3.0.5",
|
|
84
87
|
"react": "^18.2.0",
|
|
85
88
|
"react-dom": "^18.2.0",
|
|
86
89
|
"react-router-dom": "^6.30.1",
|
|
@@ -41,10 +41,12 @@ import { createCorePlugin } from '../plugins/core/index.js';
|
|
|
41
41
|
// Get the package root directory for serving UI assets
|
|
42
42
|
const __filename = fileURLToPath(import.meta.url);
|
|
43
43
|
const __dirname = dirname(__filename);
|
|
44
|
-
// Handle both src/core and dist/core paths - go up to find package root
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
// Handle both src/core and dist/src/core paths - go up to find package root
|
|
45
|
+
// - src/core/control-panel.ts → go up 2 levels to package root
|
|
46
|
+
// - dist/src/core/control-panel.js → go up 3 levels to package root
|
|
47
|
+
const packageRoot = __dirname.includes('/dist/src/')
|
|
48
|
+
? join(__dirname, '..', '..', '..') // dist/src/core → package root (3 levels)
|
|
49
|
+
: join(__dirname, '..', '..'); // src/core → package root (2 levels)
|
|
48
50
|
const uiDistPath = join(packageRoot, 'dist-ui');
|
|
49
51
|
|
|
50
52
|
// Read @qwickapps/server package version
|
package/src/core/gateway.ts
CHANGED
|
@@ -37,8 +37,31 @@ import { fileURLToPath } from 'url';
|
|
|
37
37
|
// Get QwickApps Server version from package.json
|
|
38
38
|
const __filename = fileURLToPath(import.meta.url);
|
|
39
39
|
const __dirname = dirname(__filename);
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
|
|
41
|
+
// Find package.json by walking up directories
|
|
42
|
+
// Recommended approach for libraries that work in both source and compiled contexts
|
|
43
|
+
function findPackageJson(): string {
|
|
44
|
+
let currentDir = __dirname;
|
|
45
|
+
// Walk up max 5 levels looking for the correct package.json
|
|
46
|
+
for (let i = 0; i < 5; i++) {
|
|
47
|
+
try {
|
|
48
|
+
const packagePath = join(currentDir, 'package.json');
|
|
49
|
+
if (existsSync(packagePath)) {
|
|
50
|
+
const pkg = JSON.parse(readFileSync(packagePath, 'utf-8'));
|
|
51
|
+
// Verify it's the right package
|
|
52
|
+
if (pkg.name === '@qwickapps/server') {
|
|
53
|
+
return pkg.version || '1.0.0';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
// Continue searching
|
|
58
|
+
}
|
|
59
|
+
currentDir = join(currentDir, '..');
|
|
60
|
+
}
|
|
61
|
+
return '1.0.0';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const QWICKAPPS_SERVER_VERSION = findPackageJson();
|
|
42
65
|
|
|
43
66
|
/**
|
|
44
67
|
* Maintenance mode configuration for a mounted app
|
|
@@ -185,7 +185,7 @@ export interface PageContribution {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
|
-
* Widget contribution for dashboards
|
|
188
|
+
* Widget contribution for dashboards and pages
|
|
189
189
|
*/
|
|
190
190
|
export interface WidgetContribution {
|
|
191
191
|
/** Unique ID for this widget */
|
|
@@ -194,9 +194,22 @@ export interface WidgetContribution {
|
|
|
194
194
|
title: string;
|
|
195
195
|
/** Component name to render (matched by frontend widget registry) */
|
|
196
196
|
component: string;
|
|
197
|
+
/**
|
|
198
|
+
* Widget type/category - determines which page(s) can display this widget
|
|
199
|
+
* - 'status': System health, service status, monitoring metrics (Dashboard)
|
|
200
|
+
* - 'maintenance': Operational tasks like seeding, service control, config (Maintenance page)
|
|
201
|
+
* - 'analytics': Charts, graphs, usage metrics (Dashboard or Analytics page)
|
|
202
|
+
* - 'monitoring': Performance, logs, real-time data (Monitoring page)
|
|
203
|
+
* - 'custom': Custom widgets for specific use cases
|
|
204
|
+
*/
|
|
205
|
+
type: 'status' | 'maintenance' | 'analytics' | 'monitoring' | 'custom';
|
|
197
206
|
/** Priority for ordering (lower = first, default: 100) */
|
|
198
207
|
priority?: number;
|
|
199
|
-
/**
|
|
208
|
+
/**
|
|
209
|
+
* Whether this widget is shown by default on its page (default: false)
|
|
210
|
+
* true = widget appears by default in the initial layout
|
|
211
|
+
* false = widget is available but admin must add it manually
|
|
212
|
+
*/
|
|
200
213
|
showByDefault?: boolean;
|
|
201
214
|
/** Default size */
|
|
202
215
|
defaultSize?: { width: number; height: number };
|
package/src/index.ts
CHANGED
|
@@ -116,6 +116,7 @@ export {
|
|
|
116
116
|
linkUserIdentifiers,
|
|
117
117
|
findOrCreateUser,
|
|
118
118
|
postgresUserStore,
|
|
119
|
+
inMemoryUserStore,
|
|
119
120
|
// Bans plugin (separate from Users, depends on Users)
|
|
120
121
|
createBansPlugin,
|
|
121
122
|
getBanStore,
|
|
@@ -126,6 +127,7 @@ export {
|
|
|
126
127
|
unbanUser,
|
|
127
128
|
listActiveBans,
|
|
128
129
|
postgresBanStore,
|
|
130
|
+
inMemoryBanStore,
|
|
129
131
|
// API Keys plugin (M2M authentication, depends on Users)
|
|
130
132
|
createApiKeysPlugin,
|
|
131
133
|
getApiKeysStore,
|
|
@@ -158,6 +160,21 @@ export {
|
|
|
158
160
|
requireAnyEntitlement,
|
|
159
161
|
requireAllEntitlements,
|
|
160
162
|
postgresEntitlementSource,
|
|
163
|
+
inMemoryEntitlementSource,
|
|
164
|
+
// Preferences plugin
|
|
165
|
+
createPreferencesPlugin,
|
|
166
|
+
getPreferencesStore,
|
|
167
|
+
getPreferences,
|
|
168
|
+
updatePreferences,
|
|
169
|
+
deletePreferences,
|
|
170
|
+
getDefaultPreferences,
|
|
171
|
+
postgresPreferencesStore,
|
|
172
|
+
deepMerge,
|
|
173
|
+
// Tenants plugin (multi-tenant data isolation, depends on Users)
|
|
174
|
+
createTenantsPlugin,
|
|
175
|
+
getTenantStore,
|
|
176
|
+
postgresTenantStore,
|
|
177
|
+
inMemoryTenantStore,
|
|
161
178
|
// Rate Limit plugin
|
|
162
179
|
createRateLimitPlugin,
|
|
163
180
|
createRateLimitPluginFromEnv,
|
|
@@ -276,6 +293,14 @@ export {
|
|
|
276
293
|
getActivityLog,
|
|
277
294
|
postgresParentalStore,
|
|
278
295
|
kidsAdapter,
|
|
296
|
+
// Notifications plugin
|
|
297
|
+
createNotificationsPlugin,
|
|
298
|
+
NotificationsManager,
|
|
299
|
+
getNotificationsManager,
|
|
300
|
+
hasNotificationsManager,
|
|
301
|
+
broadcastToDevice,
|
|
302
|
+
broadcastToUser,
|
|
303
|
+
broadcastToAll,
|
|
279
304
|
// QwickBrain plugin
|
|
280
305
|
createQwickBrainPlugin,
|
|
281
306
|
getConnectionStatus,
|
|
@@ -355,6 +380,26 @@ export type {
|
|
|
355
380
|
UserEntitlement,
|
|
356
381
|
CachedEntitlements,
|
|
357
382
|
EntitlementStats,
|
|
383
|
+
// Preferences plugin types
|
|
384
|
+
PreferencesPluginConfig,
|
|
385
|
+
PreferencesStore,
|
|
386
|
+
UserPreferences,
|
|
387
|
+
PostgresPreferencesStoreConfig,
|
|
388
|
+
PreferencesApiConfig,
|
|
389
|
+
// Tenants plugin types
|
|
390
|
+
TenantsPluginConfig,
|
|
391
|
+
TenantStore,
|
|
392
|
+
TenantType,
|
|
393
|
+
Tenant,
|
|
394
|
+
CreateTenantInput,
|
|
395
|
+
UpdateTenantInput,
|
|
396
|
+
TenantSearchParams,
|
|
397
|
+
TenantListResponse,
|
|
398
|
+
TenantMembership,
|
|
399
|
+
CreateTenantMembershipInput,
|
|
400
|
+
UpdateTenantMembershipInput,
|
|
401
|
+
TenantWithMembership,
|
|
402
|
+
PostgresTenantStoreConfig,
|
|
358
403
|
// Rate Limit plugin types
|
|
359
404
|
RateLimitPluginConfig,
|
|
360
405
|
RateLimitEnvPluginOptions,
|
|
@@ -445,6 +490,14 @@ export type {
|
|
|
445
490
|
ParentalApiConfig,
|
|
446
491
|
PostgresParentalStoreConfig,
|
|
447
492
|
KidsAdapterConfig,
|
|
493
|
+
// Notifications plugin types
|
|
494
|
+
NotificationsPluginConfig,
|
|
495
|
+
SSEClient,
|
|
496
|
+
NotifyPayload,
|
|
497
|
+
SSEEvent,
|
|
498
|
+
NotificationsStats,
|
|
499
|
+
ConnectionHealth,
|
|
500
|
+
NotificationsManagerInterface,
|
|
448
501
|
// QwickBrain plugin types
|
|
449
502
|
QwickBrainPluginConfig,
|
|
450
503
|
MCPToolDefinition,
|
|
@@ -266,6 +266,36 @@ export function postgresApiKeyStore(config: PostgresApiKeyStoreConfig): ApiKeySt
|
|
|
266
266
|
CREATE INDEX IF NOT EXISTS idx_${tableName}_key_hash ON ${tableFullName}(key_hash);
|
|
267
267
|
`);
|
|
268
268
|
|
|
269
|
+
// Migration: Add user_id column if it doesn't exist (for existing installations)
|
|
270
|
+
await pool.query(`
|
|
271
|
+
DO $$
|
|
272
|
+
DECLARE
|
|
273
|
+
row_count INTEGER;
|
|
274
|
+
BEGIN
|
|
275
|
+
IF NOT EXISTS (
|
|
276
|
+
SELECT 1 FROM information_schema.columns
|
|
277
|
+
WHERE table_schema = '${schema}'
|
|
278
|
+
AND table_name = '${tableName}'
|
|
279
|
+
AND column_name = 'user_id'
|
|
280
|
+
) THEN
|
|
281
|
+
-- Check if table has data
|
|
282
|
+
EXECUTE 'SELECT COUNT(*) FROM ${tableFullName}' INTO row_count;
|
|
283
|
+
|
|
284
|
+
IF row_count > 0 THEN
|
|
285
|
+
-- If table has data, cannot add NOT NULL column
|
|
286
|
+
-- This requires manual migration or data cleanup
|
|
287
|
+
RAISE EXCEPTION 'Cannot add user_id column: table ${tableFullName} contains % rows. Please migrate data or clear the table first.', row_count;
|
|
288
|
+
ELSE
|
|
289
|
+
-- Table is empty, safe to add NOT NULL column
|
|
290
|
+
ALTER TABLE ${tableFullName}
|
|
291
|
+
ADD COLUMN user_id UUID NOT NULL REFERENCES "public"."users"(id) ON DELETE CASCADE;
|
|
292
|
+
|
|
293
|
+
CREATE INDEX IF NOT EXISTS idx_${tableName}_user_id ON ${tableFullName}(user_id);
|
|
294
|
+
END IF;
|
|
295
|
+
END IF;
|
|
296
|
+
END $$;
|
|
297
|
+
`);
|
|
298
|
+
|
|
269
299
|
// Enable RLS if configured
|
|
270
300
|
if (enableRLS) {
|
|
271
301
|
await pool.query(`
|
|
@@ -42,6 +42,7 @@ export function createAuthPlugin(config: AuthPluginConfig): Plugin {
|
|
|
42
42
|
|
|
43
43
|
async onStart(_pluginConfig: PluginConfig, registry: PluginRegistry): Promise<void> {
|
|
44
44
|
const app = registry.getApp();
|
|
45
|
+
const router = registry.getRouter();
|
|
45
46
|
|
|
46
47
|
// Store adapters for helper access
|
|
47
48
|
currentAdapter = config.adapter;
|
|
@@ -72,8 +73,9 @@ export function createAuthPlugin(config: AuthPluginConfig): Plugin {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
// Add the auth checking middleware
|
|
76
|
-
|
|
76
|
+
// Add the auth checking middleware to router (not app)
|
|
77
|
+
// This ensures it processes requests to /api/* routes
|
|
78
|
+
router.use(createAuthMiddleware());
|
|
77
79
|
|
|
78
80
|
// Register auth status route
|
|
79
81
|
registry.addRoute({
|
|
@@ -790,6 +790,7 @@ export function registerAuthConfigRoutes(registry: PluginRegistry): void {
|
|
|
790
790
|
id: 'auth-status',
|
|
791
791
|
title: 'Authentication',
|
|
792
792
|
component: 'AuthStatusWidget',
|
|
793
|
+
type: 'status',
|
|
793
794
|
priority: 40, // Show before integrations
|
|
794
795
|
showByDefault: true,
|
|
795
796
|
pluginId: 'auth',
|
|
@@ -28,7 +28,7 @@ export type {
|
|
|
28
28
|
} from './types.js';
|
|
29
29
|
|
|
30
30
|
// Stores
|
|
31
|
-
export { postgresBanStore } from './stores/index.js';
|
|
31
|
+
export { postgresBanStore, inMemoryBanStore } from './stores/index.js';
|
|
32
32
|
|
|
33
33
|
// UI Components
|
|
34
34
|
export { BansStatusWidget } from './BansStatusWidget.js';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory Ban Store for Demo/Testing
|
|
3
|
+
*
|
|
4
|
+
* Implements the BanStore interface with in-memory storage.
|
|
5
|
+
* Supports temporary and permanent bans with expiration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export function createInMemoryBanStore() {
|
|
9
|
+
const bans = new Map<string, any>();
|
|
10
|
+
let idCounter = 1;
|
|
11
|
+
|
|
12
|
+
function isActiveBan(ban: any): boolean {
|
|
13
|
+
if (!ban.is_active) return false;
|
|
14
|
+
if (ban.expires_at && new Date(ban.expires_at) <= new Date()) return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
name: 'in-memory',
|
|
20
|
+
|
|
21
|
+
async initialize() {
|
|
22
|
+
console.log('[InMemoryBanStore] Initialized');
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
async isBanned(userId: string) {
|
|
26
|
+
for (const ban of bans.values()) {
|
|
27
|
+
if (ban.user_id === userId && isActiveBan(ban)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
async getActiveBan(userId: string) {
|
|
35
|
+
for (const ban of bans.values()) {
|
|
36
|
+
if (ban.user_id === userId && isActiveBan(ban)) {
|
|
37
|
+
return ban;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
async createBan(input: any) {
|
|
44
|
+
const id = String(idCounter++);
|
|
45
|
+
const now = new Date();
|
|
46
|
+
const ban = {
|
|
47
|
+
id,
|
|
48
|
+
user_id: input.user_id,
|
|
49
|
+
reason: input.reason,
|
|
50
|
+
banned_by: input.banned_by || 'system',
|
|
51
|
+
banned_at: now,
|
|
52
|
+
expires_at: input.duration ? new Date(now.getTime() + input.duration * 1000) : null,
|
|
53
|
+
is_active: true,
|
|
54
|
+
metadata: input.metadata || {},
|
|
55
|
+
};
|
|
56
|
+
bans.set(id, ban);
|
|
57
|
+
return ban;
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
async removeBan(input: any) {
|
|
61
|
+
for (const ban of bans.values()) {
|
|
62
|
+
if (ban.user_id === input.user_id && isActiveBan(ban)) {
|
|
63
|
+
ban.is_active = false;
|
|
64
|
+
ban.removed_at = new Date();
|
|
65
|
+
ban.removed_by = input.removed_by;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
async listBans(userId: string) {
|
|
73
|
+
const userBans: any[] = [];
|
|
74
|
+
for (const ban of bans.values()) {
|
|
75
|
+
if (ban.user_id === userId) {
|
|
76
|
+
userBans.push(ban);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return userBans;
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
async listActiveBans(options: { limit?: number; offset?: number } = {}) {
|
|
83
|
+
const activeBans = Array.from(bans.values()).filter(isActiveBan);
|
|
84
|
+
const total = activeBans.length;
|
|
85
|
+
const offset = options.offset || 0;
|
|
86
|
+
const limit = options.limit || 50;
|
|
87
|
+
const result = activeBans.slice(offset, offset + limit);
|
|
88
|
+
return { bans: result, total };
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async cleanupExpiredBans() {
|
|
92
|
+
let cleaned = 0;
|
|
93
|
+
for (const ban of bans.values()) {
|
|
94
|
+
if (ban.is_active && ban.expires_at && new Date(ban.expires_at) <= new Date()) {
|
|
95
|
+
ban.is_active = false;
|
|
96
|
+
cleaned++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return cleaned;
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
async shutdown() {
|
|
103
|
+
console.log('[InMemoryBanStore] Shutdown');
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -141,12 +141,12 @@ describe('Cache Plugin', () => {
|
|
|
141
141
|
expect(hasCache('test')).toBe(true);
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
-
it('should log
|
|
144
|
+
it('should log info message on successful connection', async () => {
|
|
145
145
|
const plugin = createCachePlugin(mockConfig, 'test');
|
|
146
146
|
await plugin.onStart({}, mockRegistry);
|
|
147
147
|
|
|
148
148
|
const logger = mockRegistry.getLogger('cache:test');
|
|
149
|
-
expect(logger.
|
|
149
|
+
expect(logger.info).toHaveBeenCalledWith(
|
|
150
150
|
expect.stringContaining('connected')
|
|
151
151
|
);
|
|
152
152
|
});
|