@qwickapps/server 1.7.1 → 1.8.0
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 +46 -0
- package/dist/src/core/control-panel.js +5 -5
- 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 +117 -15
- package/dist/src/core/gateway.js.map +1 -1
- package/dist/src/core/plugin-registry.d.ts +70 -0
- package/dist/src/core/plugin-registry.d.ts.map +1 -1
- package/dist/src/core/plugin-registry.js +94 -0
- package/dist/src/core/plugin-registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/plugins/api-keys/api-keys-plugin.d.ts +5 -2
- package/dist/src/plugins/api-keys/api-keys-plugin.d.ts.map +1 -1
- package/dist/src/plugins/api-keys/api-keys-plugin.js +113 -19
- package/dist/src/plugins/api-keys/api-keys-plugin.js.map +1 -1
- package/dist/src/plugins/api-keys/index.d.ts +1 -5
- package/dist/src/plugins/api-keys/index.d.ts.map +1 -1
- package/dist/src/plugins/api-keys/index.js +2 -3
- package/dist/src/plugins/api-keys/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 +83 -65
- package/dist/src/plugins/api-keys/stores/postgres-store.js.map +1 -1
- package/dist/src/plugins/api-keys/types.d.ts +22 -4
- package/dist/src/plugins/api-keys/types.d.ts.map +1 -1
- package/dist/src/plugins/api-keys/types.js.map +1 -1
- package/dist/src/plugins/auth/index.d.ts +0 -4
- package/dist/src/plugins/auth/index.d.ts.map +1 -1
- package/dist/src/plugins/auth/index.js +2 -3
- package/dist/src/plugins/auth/index.js.map +1 -1
- package/dist/src/plugins/bans/bans-plugin.d.ts +5 -2
- package/dist/src/plugins/bans/bans-plugin.d.ts.map +1 -1
- package/dist/src/plugins/bans/bans-plugin.js +71 -25
- package/dist/src/plugins/bans/bans-plugin.js.map +1 -1
- package/dist/src/plugins/bans/index.d.ts +0 -4
- package/dist/src/plugins/bans/index.d.ts.map +1 -1
- package/dist/src/plugins/bans/index.js +2 -3
- package/dist/src/plugins/bans/index.js.map +1 -1
- package/dist/src/plugins/bans/types.d.ts +13 -6
- package/dist/src/plugins/bans/types.d.ts.map +1 -1
- package/dist/src/plugins/devices/devices-plugin.d.ts +5 -2
- package/dist/src/plugins/devices/devices-plugin.d.ts.map +1 -1
- package/dist/src/plugins/devices/devices-plugin.js +62 -26
- package/dist/src/plugins/devices/devices-plugin.js.map +1 -1
- package/dist/src/plugins/devices/index.d.ts +0 -4
- package/dist/src/plugins/devices/index.d.ts.map +1 -1
- package/dist/src/plugins/devices/index.js +2 -3
- package/dist/src/plugins/devices/index.js.map +1 -1
- package/dist/src/plugins/diagnostics-plugin.d.ts.map +1 -1
- package/dist/src/plugins/diagnostics-plugin.js +73 -0
- package/dist/src/plugins/diagnostics-plugin.js.map +1 -1
- package/dist/src/plugins/entitlements/entitlements-plugin.d.ts +5 -2
- package/dist/src/plugins/entitlements/entitlements-plugin.d.ts.map +1 -1
- package/dist/src/plugins/entitlements/entitlements-plugin.js +78 -41
- package/dist/src/plugins/entitlements/entitlements-plugin.js.map +1 -1
- package/dist/src/plugins/entitlements/index.d.ts +0 -4
- package/dist/src/plugins/entitlements/index.d.ts.map +1 -1
- package/dist/src/plugins/entitlements/index.js +2 -3
- package/dist/src/plugins/entitlements/index.js.map +1 -1
- package/dist/src/plugins/entitlements/types.d.ts +9 -2
- package/dist/src/plugins/entitlements/types.d.ts.map +1 -1
- package/dist/src/plugins/index.d.ts +1 -1
- package/dist/src/plugins/index.d.ts.map +1 -1
- package/dist/src/plugins/maintenance/SeedExecutor.d.ts +2 -0
- package/dist/src/plugins/maintenance/SeedExecutor.d.ts.map +1 -1
- package/dist/src/plugins/maintenance/SeedExecutor.js +6 -2
- package/dist/src/plugins/maintenance/SeedExecutor.js.map +1 -1
- package/dist/src/plugins/maintenance/SeedList.d.ts +2 -2
- package/dist/src/plugins/maintenance/SeedList.d.ts.map +1 -1
- package/dist/src/plugins/maintenance/SeedList.js +39 -14
- package/dist/src/plugins/maintenance/SeedList.js.map +1 -1
- package/dist/src/plugins/maintenance/SeedManagementPage.d.ts +1 -1
- package/dist/src/plugins/maintenance/SeedManagementPage.d.ts.map +1 -1
- package/dist/src/plugins/maintenance/SeedManagementPage.js +9 -5
- package/dist/src/plugins/maintenance/SeedManagementPage.js.map +1 -1
- package/dist/src/plugins/maintenance/seed-executor.d.ts +6 -4
- package/dist/src/plugins/maintenance/seed-executor.d.ts.map +1 -1
- package/dist/src/plugins/maintenance/seed-executor.js +53 -17
- package/dist/src/plugins/maintenance/seed-executor.js.map +1 -1
- package/dist/src/plugins/maintenance-plugin.d.ts +24 -0
- package/dist/src/plugins/maintenance-plugin.d.ts.map +1 -1
- package/dist/src/plugins/maintenance-plugin.js +222 -34
- package/dist/src/plugins/maintenance-plugin.js.map +1 -1
- package/dist/src/plugins/notifications/index.d.ts +0 -4
- package/dist/src/plugins/notifications/index.d.ts.map +1 -1
- package/dist/src/plugins/notifications/index.js +2 -3
- package/dist/src/plugins/notifications/index.js.map +1 -1
- package/dist/src/plugins/notifications/notifications-plugin.d.ts +5 -2
- package/dist/src/plugins/notifications/notifications-plugin.d.ts.map +1 -1
- package/dist/src/plugins/notifications/notifications-plugin.js +45 -13
- package/dist/src/plugins/notifications/notifications-plugin.js.map +1 -1
- package/dist/src/plugins/parental/index.d.ts +0 -4
- package/dist/src/plugins/parental/index.d.ts.map +1 -1
- package/dist/src/plugins/parental/index.js +2 -3
- package/dist/src/plugins/parental/index.js.map +1 -1
- package/dist/src/plugins/parental/parental-plugin.d.ts +5 -2
- package/dist/src/plugins/parental/parental-plugin.d.ts.map +1 -1
- package/dist/src/plugins/parental/parental-plugin.js +60 -24
- package/dist/src/plugins/parental/parental-plugin.js.map +1 -1
- package/dist/src/plugins/postgres-plugin.d.ts +12 -0
- package/dist/src/plugins/postgres-plugin.d.ts.map +1 -1
- package/dist/src/plugins/postgres-plugin.js +319 -5
- package/dist/src/plugins/postgres-plugin.js.map +1 -1
- package/dist/src/plugins/preferences/index.d.ts +0 -4
- package/dist/src/plugins/preferences/index.d.ts.map +1 -1
- package/dist/src/plugins/preferences/index.js +2 -3
- package/dist/src/plugins/preferences/index.js.map +1 -1
- package/dist/src/plugins/preferences/preferences-plugin.d.ts +5 -2
- package/dist/src/plugins/preferences/preferences-plugin.d.ts.map +1 -1
- package/dist/src/plugins/preferences/preferences-plugin.js +63 -19
- package/dist/src/plugins/preferences/preferences-plugin.js.map +1 -1
- package/dist/src/plugins/profiles/index.d.ts +0 -4
- package/dist/src/plugins/profiles/index.d.ts.map +1 -1
- package/dist/src/plugins/profiles/index.js +2 -3
- package/dist/src/plugins/profiles/index.js.map +1 -1
- package/dist/src/plugins/profiles/profiles-plugin.d.ts +5 -2
- package/dist/src/plugins/profiles/profiles-plugin.d.ts.map +1 -1
- package/dist/src/plugins/profiles/profiles-plugin.js +60 -26
- package/dist/src/plugins/profiles/profiles-plugin.js.map +1 -1
- package/dist/src/plugins/profiles/types.d.ts +9 -2
- package/dist/src/plugins/profiles/types.d.ts.map +1 -1
- package/dist/src/plugins/qwickbrain/index.d.ts +0 -4
- package/dist/src/plugins/qwickbrain/index.d.ts.map +1 -1
- package/dist/src/plugins/qwickbrain/index.js +2 -3
- package/dist/src/plugins/qwickbrain/index.js.map +1 -1
- package/dist/src/plugins/qwickbrain/qwickbrain-plugin.d.ts.map +1 -1
- package/dist/src/plugins/qwickbrain/qwickbrain-plugin.js +117 -0
- package/dist/src/plugins/qwickbrain/qwickbrain-plugin.js.map +1 -1
- package/dist/src/plugins/rate-limit/index.d.ts +0 -4
- package/dist/src/plugins/rate-limit/index.d.ts.map +1 -1
- package/dist/src/plugins/rate-limit/index.js +2 -3
- package/dist/src/plugins/rate-limit/index.js.map +1 -1
- package/dist/src/plugins/subscriptions/index.d.ts +0 -4
- package/dist/src/plugins/subscriptions/index.d.ts.map +1 -1
- package/dist/src/plugins/subscriptions/index.js +2 -3
- package/dist/src/plugins/subscriptions/index.js.map +1 -1
- package/dist/src/plugins/subscriptions/subscriptions-plugin.d.ts +5 -2
- package/dist/src/plugins/subscriptions/subscriptions-plugin.d.ts.map +1 -1
- package/dist/src/plugins/subscriptions/subscriptions-plugin.js +63 -29
- package/dist/src/plugins/subscriptions/subscriptions-plugin.js.map +1 -1
- package/dist/src/plugins/subscriptions/types.d.ts +8 -2
- package/dist/src/plugins/subscriptions/types.d.ts.map +1 -1
- package/dist/src/plugins/tenants/tenants-plugin.d.ts +5 -2
- package/dist/src/plugins/tenants/tenants-plugin.d.ts.map +1 -1
- package/dist/src/plugins/tenants/tenants-plugin.js +91 -58
- package/dist/src/plugins/tenants/tenants-plugin.js.map +1 -1
- package/dist/src/plugins/tenants/types.d.ts +8 -2
- package/dist/src/plugins/tenants/types.d.ts.map +1 -1
- package/dist/src/plugins/usage/index.d.ts +0 -4
- package/dist/src/plugins/usage/index.d.ts.map +1 -1
- package/dist/src/plugins/usage/index.js +2 -3
- package/dist/src/plugins/usage/index.js.map +1 -1
- package/dist/src/plugins/usage/usage-plugin.d.ts +5 -2
- package/dist/src/plugins/usage/usage-plugin.d.ts.map +1 -1
- package/dist/src/plugins/usage/usage-plugin.js +57 -23
- package/dist/src/plugins/usage/usage-plugin.js.map +1 -1
- package/dist/src/plugins/users/types.d.ts +7 -2
- package/dist/src/plugins/users/types.d.ts.map +1 -1
- package/dist/src/plugins/users/users-plugin.d.ts +5 -2
- package/dist/src/plugins/users/users-plugin.d.ts.map +1 -1
- package/dist/src/plugins/users/users-plugin.js +56 -23
- package/dist/src/plugins/users/users-plugin.js.map +1 -1
- package/dist/ui/src/components/ControlPanelApp.d.ts.map +1 -1
- package/dist/ui/src/components/ControlPanelApp.js +4 -3
- package/dist/ui/src/components/ControlPanelApp.js.map +1 -1
- package/dist/ui/src/dashboard/builtInWidgets.d.ts.map +1 -1
- package/dist/ui/src/dashboard/builtInWidgets.js +3 -1
- package/dist/ui/src/dashboard/builtInWidgets.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/CMSMaintenanceWidget.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/CMSMaintenanceWidget.js +17 -4
- package/dist/ui/src/dashboard/widgets/CMSMaintenanceWidget.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/CMSStatusWidget.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/CMSStatusWidget.js +5 -1
- package/dist/ui/src/dashboard/widgets/CMSStatusWidget.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js +4 -2
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/DatabaseOperationsWidget.d.ts +12 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOperationsWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOperationsWidget.js +174 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOperationsWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js +6 -3
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts +1 -1
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js +256 -16
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/index.d.ts +1 -0
- package/dist/ui/src/dashboard/widgets/index.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/index.js +1 -0
- package/dist/ui/src/dashboard/widgets/index.js.map +1 -1
- package/dist-ui/assets/index-BkGp7ZKd.js +529 -0
- package/dist-ui/assets/index-BkGp7ZKd.js.map +1 -0
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/index.js +3735 -3187
- package/dist-ui-lib/index.js.map +1 -1
- package/dist-ui-lib/src/dashboard/widgets/DatabaseOperationsWidget.d.ts +11 -0
- package/dist-ui-lib/src/dashboard/widgets/SeedManagementWidget.d.ts +1 -1
- package/dist-ui-lib/src/dashboard/widgets/index.d.ts +1 -0
- package/package.json +8 -5
- package/src/core/control-panel.ts +5 -5
- package/src/core/gateway.ts +135 -15
- package/src/core/plugin-registry.ts +171 -0
- package/src/index.ts +2 -0
- package/src/plugins/api-keys/api-keys-plugin.ts +121 -20
- package/src/plugins/api-keys/index.ts +3 -5
- package/src/plugins/api-keys/stores/postgres-store.ts +90 -67
- package/src/plugins/api-keys/types.ts +23 -4
- package/src/plugins/auth/index.ts +3 -5
- package/src/plugins/bans/bans-plugin.ts +71 -26
- package/src/plugins/bans/index.ts +3 -5
- package/src/plugins/bans/types.ts +13 -6
- package/src/plugins/devices/devices-plugin.ts +62 -27
- package/src/plugins/devices/index.ts +3 -5
- package/src/plugins/diagnostics-plugin.ts +77 -0
- package/src/plugins/entitlements/entitlements-plugin.ts +81 -43
- package/src/plugins/entitlements/index.ts +3 -5
- package/src/plugins/entitlements/types.ts +9 -2
- package/src/plugins/index.ts +1 -1
- package/src/plugins/maintenance/SeedExecutor.tsx +9 -1
- package/src/plugins/maintenance/SeedList.tsx +85 -38
- package/src/plugins/maintenance/SeedManagementPage.tsx +10 -4
- package/src/plugins/maintenance/seed-executor.ts +56 -17
- package/src/plugins/maintenance-plugin.ts +267 -36
- package/src/plugins/notifications/index.ts +3 -5
- package/src/plugins/notifications/notifications-plugin.ts +48 -19
- package/src/plugins/parental/index.ts +3 -5
- package/src/plugins/parental/parental-plugin.ts +63 -25
- package/src/plugins/postgres-plugin.ts +410 -5
- package/src/plugins/preferences/index.ts +3 -5
- package/src/plugins/preferences/preferences-plugin.ts +66 -20
- package/src/plugins/profiles/index.ts +3 -5
- package/src/plugins/profiles/profiles-plugin.ts +60 -27
- package/src/plugins/profiles/types.ts +9 -2
- package/src/plugins/qwickbrain/index.ts +3 -5
- package/src/plugins/qwickbrain/qwickbrain-plugin.ts +135 -0
- package/src/plugins/rate-limit/index.ts +3 -5
- package/src/plugins/subscriptions/index.ts +3 -5
- package/src/plugins/subscriptions/subscriptions-plugin.ts +63 -30
- package/src/plugins/subscriptions/types.ts +8 -2
- package/src/plugins/tenants/tenants-plugin.ts +95 -60
- package/src/plugins/tenants/types.ts +8 -2
- package/src/plugins/usage/index.ts +3 -5
- package/src/plugins/usage/usage-plugin.ts +60 -26
- package/src/plugins/users/types.ts +7 -2
- package/src/plugins/users/users-plugin.ts +56 -24
- package/ui/src/App.tsx +3 -3
- package/ui/src/components/ControlPanelApp.tsx +4 -3
- package/ui/src/dashboard/builtInWidgets.tsx +3 -0
- package/ui/src/dashboard/widgets/CMSMaintenanceWidget.tsx +17 -4
- package/ui/src/dashboard/widgets/CMSStatusWidget.tsx +5 -1
- package/ui/src/dashboard/widgets/CacheMaintenanceWidget.tsx +4 -2
- package/ui/src/dashboard/widgets/DatabaseOperationsWidget.tsx +410 -0
- package/ui/src/dashboard/widgets/LogsMaintenanceWidget.tsx +6 -3
- package/ui/src/dashboard/widgets/SeedManagementWidget.tsx +533 -49
- package/ui/src/dashboard/widgets/index.ts +1 -0
- package/dist-ui/assets/index-8y0jDGcd.js +0 -528
- package/dist-ui/assets/index-8y0jDGcd.js.map +0 -1
|
@@ -22,6 +22,8 @@ import type {
|
|
|
22
22
|
} from './types.js';
|
|
23
23
|
import type { AuthenticatedRequest } from '../auth/types.js';
|
|
24
24
|
import { getUserByEmail, getUserById, getUsersByIds } from '../users/users-plugin.js';
|
|
25
|
+
import { hasPostgres, getPostgres } from '../postgres-plugin.js';
|
|
26
|
+
import { postgresBanStore } from './stores/index.js';
|
|
25
27
|
|
|
26
28
|
// Store instance for helper access
|
|
27
29
|
let currentStore: BanStore | null = null;
|
|
@@ -29,17 +31,18 @@ let banCleanupInterval: NodeJS.Timeout | null = null;
|
|
|
29
31
|
let pluginConfig: BansPluginConfig | null = null;
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
|
-
* Create the Bans plugin
|
|
34
|
+
* Create the Bans plugin with smart defaults
|
|
35
|
+
*
|
|
36
|
+
* Config is optional - plugin will use defaults and get dependencies from registry.
|
|
37
|
+
* Gracefully handles missing dependencies with clear log messages.
|
|
33
38
|
*/
|
|
34
|
-
export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (debug) {
|
|
42
|
-
console.log(`[BansPlugin] ${message}`, data || '');
|
|
39
|
+
export function createBansPlugin(config: Partial<BansPluginConfig> = {}): Plugin {
|
|
40
|
+
function log(message: string, data?: Record<string, unknown>, isError = false) {
|
|
41
|
+
const prefix = '[BansPlugin]';
|
|
42
|
+
if (isError) {
|
|
43
|
+
console.error(`${prefix} ${message}`, data || '');
|
|
44
|
+
} else if (config.debug) {
|
|
45
|
+
console.log(`${prefix} ${message}`, data || '');
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -49,26 +52,68 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
49
52
|
version: '1.0.0',
|
|
50
53
|
|
|
51
54
|
async onStart(_pluginConfig: PluginConfig, registry: PluginRegistry): Promise<void> {
|
|
52
|
-
|
|
55
|
+
const logger = registry.getLogger('bans');
|
|
53
56
|
|
|
54
57
|
// Check for users plugin dependency
|
|
55
58
|
if (!registry.hasPlugin('users')) {
|
|
56
|
-
|
|
59
|
+
logger.warn('Users plugin not loaded! Bans plugin disabled.');
|
|
60
|
+
registry.registerHealthCheck({
|
|
61
|
+
name: 'bans-store',
|
|
62
|
+
type: 'custom',
|
|
63
|
+
check: async () => ({
|
|
64
|
+
healthy: false,
|
|
65
|
+
details: {
|
|
66
|
+
error: 'Users plugin not available',
|
|
67
|
+
state: 'disabled',
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check for postgres in registry
|
|
75
|
+
if (!hasPostgres()) {
|
|
76
|
+
logger.warn('No Database! Bans plugin disabled.');
|
|
77
|
+
registry.registerHealthCheck({
|
|
78
|
+
name: 'bans-store',
|
|
79
|
+
type: 'custom',
|
|
80
|
+
check: async () => ({
|
|
81
|
+
healthy: false,
|
|
82
|
+
details: {
|
|
83
|
+
error: 'PostgreSQL not available',
|
|
84
|
+
state: 'disabled',
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
57
89
|
}
|
|
58
90
|
|
|
91
|
+
// Smart defaults - get dependencies from registry
|
|
92
|
+
const store = config.store ?? postgresBanStore({
|
|
93
|
+
pool: () => getPostgres().getPool(),
|
|
94
|
+
autoCreateTables: true,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const debug = config.debug ?? false;
|
|
98
|
+
const apiPrefix = config.api?.prefix ?? '/bans';
|
|
99
|
+
const apiEnabled = config.api?.enabled ?? true;
|
|
100
|
+
const supportTemporary = config.supportTemporary ?? true;
|
|
101
|
+
|
|
102
|
+
log('Starting bans plugin');
|
|
103
|
+
|
|
59
104
|
// Initialize the store (creates tables if needed)
|
|
60
|
-
await
|
|
105
|
+
await store.initialize();
|
|
61
106
|
log('Bans plugin migrations complete');
|
|
62
107
|
|
|
63
108
|
// Store references for helper access
|
|
64
|
-
currentStore =
|
|
65
|
-
pluginConfig = config;
|
|
109
|
+
currentStore = store;
|
|
110
|
+
pluginConfig = { ...config, store, debug, supportTemporary };
|
|
66
111
|
|
|
67
112
|
// Start ban cleanup interval if temporary bans are supported
|
|
68
|
-
if (
|
|
113
|
+
if (supportTemporary) {
|
|
69
114
|
banCleanupInterval = setInterval(async () => {
|
|
70
115
|
try {
|
|
71
|
-
const cleaned = await
|
|
116
|
+
const cleaned = await store.cleanupExpiredBans();
|
|
72
117
|
if (cleaned > 0) {
|
|
73
118
|
log('Cleaned up expired bans', { count: cleaned });
|
|
74
119
|
}
|
|
@@ -85,7 +130,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
85
130
|
check: async () => {
|
|
86
131
|
try {
|
|
87
132
|
// Simple health check - list with limit 0
|
|
88
|
-
await
|
|
133
|
+
await store.listActiveBans({ limit: 0 });
|
|
89
134
|
return { healthy: true };
|
|
90
135
|
} catch {
|
|
91
136
|
return { healthy: false };
|
|
@@ -105,7 +150,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
105
150
|
const limit = Math.min(parseInt(req.query.limit as string) || 50, 100);
|
|
106
151
|
const offset = parseInt(req.query.offset as string) || 0;
|
|
107
152
|
|
|
108
|
-
const result = await
|
|
153
|
+
const result = await store.listActiveBans({ limit, offset });
|
|
109
154
|
|
|
110
155
|
// Batch fetch users for all bans (single query instead of N queries)
|
|
111
156
|
const userIds = [...new Set(result.bans.map((ban) => ban.user_id))];
|
|
@@ -133,7 +178,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
133
178
|
pluginId: 'bans',
|
|
134
179
|
handler: async (req: Request, res: Response) => {
|
|
135
180
|
try {
|
|
136
|
-
const ban = await
|
|
181
|
+
const ban = await store.getActiveBan(req.params.userId);
|
|
137
182
|
res.json({
|
|
138
183
|
isBanned: ban !== null,
|
|
139
184
|
ban,
|
|
@@ -152,7 +197,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
152
197
|
pluginId: 'bans',
|
|
153
198
|
handler: async (req: Request, res: Response) => {
|
|
154
199
|
try {
|
|
155
|
-
const bans = await
|
|
200
|
+
const bans = await store.listBans(req.params.userId);
|
|
156
201
|
res.json({ bans });
|
|
157
202
|
} catch (error) {
|
|
158
203
|
console.error('[BansPlugin] Get ban history error:', error);
|
|
@@ -185,7 +230,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
185
230
|
return res.status(404).json({ error: 'User not found' });
|
|
186
231
|
}
|
|
187
232
|
|
|
188
|
-
const ban = await
|
|
233
|
+
const ban = await store.createBan(input);
|
|
189
234
|
|
|
190
235
|
// Call onBan callback if provided
|
|
191
236
|
if (config.callbacks?.onBan) {
|
|
@@ -227,7 +272,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
227
272
|
note: req.body?.note,
|
|
228
273
|
};
|
|
229
274
|
|
|
230
|
-
const removed = await
|
|
275
|
+
const removed = await store.removeBan(input);
|
|
231
276
|
if (!removed) {
|
|
232
277
|
return res.status(404).json({ error: 'No active ban found' });
|
|
233
278
|
}
|
|
@@ -292,7 +337,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
292
337
|
metadata: req.body.metadata,
|
|
293
338
|
};
|
|
294
339
|
|
|
295
|
-
const ban = await
|
|
340
|
+
const ban = await store.createBan(input);
|
|
296
341
|
|
|
297
342
|
// Call onBan callback if provided
|
|
298
343
|
if (config.callbacks?.onBan) {
|
|
@@ -335,7 +380,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
335
380
|
note: req.body?.note,
|
|
336
381
|
};
|
|
337
382
|
|
|
338
|
-
const removed = await
|
|
383
|
+
const removed = await store.removeBan(input);
|
|
339
384
|
if (!removed) {
|
|
340
385
|
return res.status(404).json({ error: 'No active ban found' });
|
|
341
386
|
}
|
|
@@ -370,7 +415,7 @@ export function createBansPlugin(config: BansPluginConfig): Plugin {
|
|
|
370
415
|
banCleanupInterval = null;
|
|
371
416
|
}
|
|
372
417
|
|
|
373
|
-
await
|
|
418
|
+
if (currentStore) { await currentStore.shutdown(); };
|
|
374
419
|
currentStore = null;
|
|
375
420
|
pluginConfig = null;
|
|
376
421
|
|
|
@@ -30,8 +30,6 @@ export type {
|
|
|
30
30
|
// Stores
|
|
31
31
|
export { postgresBanStore, inMemoryBanStore } from './stores/index.js';
|
|
32
32
|
|
|
33
|
-
// UI Components
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
export { BansManagementPage } from './BansManagementPage.js';
|
|
37
|
-
export type { BansManagementPageProps } from './BansManagementPage.js';
|
|
33
|
+
// UI Components are exported from main package index (@qwickapps/server)
|
|
34
|
+
// Do NOT export here to avoid loading UI dependencies when importing plugins
|
|
35
|
+
|
|
@@ -107,22 +107,29 @@ export interface BanCallbacks {
|
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Bans plugin configuration
|
|
110
|
+
*
|
|
111
|
+
* All properties are optional - plugin will use smart defaults:
|
|
112
|
+
* - store: Postgres ban store using registry's postgres instance
|
|
113
|
+
* - supportTemporary: true
|
|
114
|
+
* - api.prefix: '/bans'
|
|
115
|
+
* - api.enabled: true
|
|
116
|
+
* - debug: false
|
|
110
117
|
*/
|
|
111
118
|
export interface BansPluginConfig {
|
|
112
|
-
/** Ban storage backend */
|
|
113
|
-
store
|
|
114
|
-
/** Support temporary bans (with expiration) */
|
|
119
|
+
/** Ban storage backend (default: postgres ban store from registry) */
|
|
120
|
+
store?: BanStore;
|
|
121
|
+
/** Support temporary bans (with expiration) (default: true) */
|
|
115
122
|
supportTemporary?: boolean;
|
|
116
123
|
/** Callbacks */
|
|
117
124
|
callbacks?: BanCallbacks;
|
|
118
125
|
/** API configuration */
|
|
119
126
|
api?: {
|
|
120
|
-
/** API route prefix (default: '/
|
|
127
|
+
/** API route prefix (default: '/bans') */
|
|
121
128
|
prefix?: string;
|
|
122
|
-
/** Enable API endpoints */
|
|
129
|
+
/** Enable API endpoints (default: true) */
|
|
123
130
|
enabled?: boolean;
|
|
124
131
|
};
|
|
125
|
-
/** Enable debug logging */
|
|
132
|
+
/** Enable debug logging (default: false) */
|
|
126
133
|
debug?: boolean;
|
|
127
134
|
}
|
|
128
135
|
|
|
@@ -28,6 +28,9 @@ import {
|
|
|
28
28
|
isTokenExpired,
|
|
29
29
|
getTokenExpiration,
|
|
30
30
|
} from './token-utils.js';
|
|
31
|
+
import { hasPostgres, getPostgres } from '../postgres-plugin.js';
|
|
32
|
+
import { postgresDeviceStore } from './stores/index.js';
|
|
33
|
+
import { computeDeviceAdapter } from './adapters/index.js';
|
|
31
34
|
|
|
32
35
|
// Store instances for helper access
|
|
33
36
|
let currentStore: DeviceStore | null = null;
|
|
@@ -35,16 +38,18 @@ let currentAdapter: DeviceAdapter | null = null;
|
|
|
35
38
|
let currentConfig: DevicesPluginConfig | null = null;
|
|
36
39
|
|
|
37
40
|
/**
|
|
38
|
-
* Create the Devices plugin
|
|
41
|
+
* Create the Devices plugin with smart defaults
|
|
42
|
+
*
|
|
43
|
+
* Config is optional - plugin will use defaults and get dependencies from registry.
|
|
44
|
+
* Gracefully handles missing dependencies with clear log messages.
|
|
39
45
|
*/
|
|
40
|
-
export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
console.log(`[DevicesPlugin] ${message}`, data || '');
|
|
46
|
+
export function createDevicesPlugin(config: Partial<DevicesPluginConfig> = {}): Plugin {
|
|
47
|
+
function log(message: string, data?: Record<string, unknown>, isError = false) {
|
|
48
|
+
const prefix = '[DevicesPlugin]';
|
|
49
|
+
if (isError) {
|
|
50
|
+
console.error(`${prefix} ${message}`, data || '');
|
|
51
|
+
} else if (config.debug) {
|
|
52
|
+
console.log(`${prefix} ${message}`, data || '');
|
|
48
53
|
}
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -54,16 +59,46 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
54
59
|
version: '1.0.0',
|
|
55
60
|
|
|
56
61
|
async onStart(_pluginConfig: PluginConfig, registry: PluginRegistry): Promise<void> {
|
|
57
|
-
|
|
62
|
+
const logger = registry.getLogger('devices');
|
|
63
|
+
|
|
64
|
+
// Check for postgres in registry
|
|
65
|
+
if (!hasPostgres()) {
|
|
66
|
+
logger.warn('No Database! Devices plugin disabled.');
|
|
67
|
+
registry.registerHealthCheck({
|
|
68
|
+
name: 'devices-store',
|
|
69
|
+
type: 'custom',
|
|
70
|
+
check: async () => ({
|
|
71
|
+
healthy: false,
|
|
72
|
+
details: {
|
|
73
|
+
error: 'PostgreSQL not available',
|
|
74
|
+
state: 'disabled',
|
|
75
|
+
},
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Smart defaults - get dependencies from registry
|
|
82
|
+
const store = config.store ?? postgresDeviceStore({
|
|
83
|
+
pool: () => getPostgres().getPool(),
|
|
84
|
+
autoCreateTables: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const adapter = config.adapter ?? computeDeviceAdapter();
|
|
88
|
+
const debug = config.debug ?? false;
|
|
89
|
+
const defaultTokenValidityDays = config.defaultTokenValidityDays ?? 90;
|
|
90
|
+
const apiPrefix = config.api?.prefix ?? '/devices';
|
|
91
|
+
|
|
92
|
+
log('Starting devices plugin', { adapter: adapter.name });
|
|
58
93
|
|
|
59
94
|
// Initialize the store (creates tables if needed)
|
|
60
|
-
await
|
|
95
|
+
await store.initialize();
|
|
61
96
|
log('Devices plugin migrations complete');
|
|
62
97
|
|
|
63
98
|
// Store references for helper access
|
|
64
|
-
currentStore =
|
|
65
|
-
currentAdapter =
|
|
66
|
-
currentConfig = config;
|
|
99
|
+
currentStore = store;
|
|
100
|
+
currentAdapter = adapter;
|
|
101
|
+
currentConfig = { ...config, store, adapter, debug, defaultTokenValidityDays };
|
|
67
102
|
|
|
68
103
|
// Register health check
|
|
69
104
|
registry.registerHealthCheck({
|
|
@@ -71,12 +106,12 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
71
106
|
type: 'custom',
|
|
72
107
|
check: async () => {
|
|
73
108
|
try {
|
|
74
|
-
await
|
|
109
|
+
await store.search({ limit: 1 });
|
|
75
110
|
return {
|
|
76
111
|
healthy: true,
|
|
77
112
|
details: {
|
|
78
|
-
adapter:
|
|
79
|
-
tokenPrefix:
|
|
113
|
+
adapter: adapter.name,
|
|
114
|
+
tokenPrefix: adapter.tokenPrefix,
|
|
80
115
|
},
|
|
81
116
|
};
|
|
82
117
|
} catch {
|
|
@@ -106,7 +141,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
106
141
|
sortOrder: (req.query.sortOrder as DeviceSearchParams['sortOrder']) || 'desc',
|
|
107
142
|
};
|
|
108
143
|
|
|
109
|
-
const result = await
|
|
144
|
+
const result = await store.search(params);
|
|
110
145
|
res.json(result);
|
|
111
146
|
} catch (error) {
|
|
112
147
|
console.error('[DevicesPlugin] Search error:', error);
|
|
@@ -122,7 +157,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
122
157
|
pluginId: 'devices',
|
|
123
158
|
handler: async (req: Request, res: Response) => {
|
|
124
159
|
try {
|
|
125
|
-
const device = await
|
|
160
|
+
const device = await store.getById(req.params.id);
|
|
126
161
|
if (!device) {
|
|
127
162
|
return res.status(404).json({ error: 'Device not found' });
|
|
128
163
|
}
|
|
@@ -150,7 +185,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
150
185
|
};
|
|
151
186
|
|
|
152
187
|
// Validate using adapter
|
|
153
|
-
const validation =
|
|
188
|
+
const validation = adapter.validateDeviceInput(input);
|
|
154
189
|
if (!validation.valid) {
|
|
155
190
|
return res.status(400).json({
|
|
156
191
|
error: 'Validation failed',
|
|
@@ -181,7 +216,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
181
216
|
metadata: req.body.metadata,
|
|
182
217
|
};
|
|
183
218
|
|
|
184
|
-
const device = await
|
|
219
|
+
const device = await store.update(req.params.id, input);
|
|
185
220
|
if (!device) {
|
|
186
221
|
return res.status(404).json({ error: 'Device not found' });
|
|
187
222
|
}
|
|
@@ -200,19 +235,19 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
200
235
|
pluginId: 'devices',
|
|
201
236
|
handler: async (req: Request, res: Response) => {
|
|
202
237
|
try {
|
|
203
|
-
const device = await
|
|
238
|
+
const device = await store.getById(req.params.id);
|
|
204
239
|
if (!device) {
|
|
205
240
|
return res.status(404).json({ error: 'Device not found' });
|
|
206
241
|
}
|
|
207
242
|
|
|
208
|
-
const deleted = await
|
|
243
|
+
const deleted = await store.delete(req.params.id);
|
|
209
244
|
if (!deleted) {
|
|
210
245
|
return res.status(404).json({ error: 'Device not found' });
|
|
211
246
|
}
|
|
212
247
|
|
|
213
248
|
// Call adapter hook
|
|
214
|
-
if (
|
|
215
|
-
await
|
|
249
|
+
if (adapter.onDeviceDeleted) {
|
|
250
|
+
await adapter.onDeviceDeleted(device);
|
|
216
251
|
}
|
|
217
252
|
|
|
218
253
|
res.status(204).send();
|
|
@@ -230,7 +265,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
230
265
|
pluginId: 'devices',
|
|
231
266
|
handler: async (req: Request, res: Response) => {
|
|
232
267
|
try {
|
|
233
|
-
const device = await
|
|
268
|
+
const device = await store.getById(req.params.id);
|
|
234
269
|
if (!device) {
|
|
235
270
|
return res.status(404).json({ error: 'Device not found' });
|
|
236
271
|
}
|
|
@@ -295,7 +330,7 @@ export function createDevicesPlugin(config: DevicesPluginConfig): Plugin {
|
|
|
295
330
|
|
|
296
331
|
async onStop(): Promise<void> {
|
|
297
332
|
log('Stopping devices plugin');
|
|
298
|
-
await
|
|
333
|
+
if (currentStore) { await currentStore.shutdown(); };
|
|
299
334
|
currentStore = null;
|
|
300
335
|
currentAdapter = null;
|
|
301
336
|
currentConfig = null;
|
|
@@ -68,8 +68,6 @@ export {
|
|
|
68
68
|
} from './token-utils.js';
|
|
69
69
|
export type { DeviceTokenPair } from './token-utils.js';
|
|
70
70
|
|
|
71
|
-
// UI Components
|
|
72
|
-
export
|
|
73
|
-
|
|
74
|
-
export { DevicesManagementPage } from './DevicesManagementPage.js';
|
|
75
|
-
export type { DevicesManagementPageProps } from './DevicesManagementPage.js';
|
|
71
|
+
// UI Components are exported from main package index (@qwickapps/server)
|
|
72
|
+
// Do NOT export here to avoid loading UI dependencies when importing plugins
|
|
73
|
+
|
|
@@ -148,6 +148,83 @@ export function createDiagnosticsPlugin(config: DiagnosticsPluginConfig = {}): P
|
|
|
148
148
|
},
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
// Register maintenance listing endpoint (GET /diagnostics/maintenance)
|
|
152
|
+
registry.addRoute({
|
|
153
|
+
method: 'get',
|
|
154
|
+
path: '/maintenance',
|
|
155
|
+
pluginId: 'diagnostics',
|
|
156
|
+
handler: (_req: Request, res: Response) => {
|
|
157
|
+
try {
|
|
158
|
+
const pluginsNeedingMaintenance = registry.getPluginsNeedingMaintenance();
|
|
159
|
+
|
|
160
|
+
res.json({
|
|
161
|
+
timestamp: new Date().toISOString(),
|
|
162
|
+
count: pluginsNeedingMaintenance.length,
|
|
163
|
+
plugins: pluginsNeedingMaintenance.map(info => ({
|
|
164
|
+
pluginId: info.pluginId,
|
|
165
|
+
error: info.error,
|
|
166
|
+
recommendedAction: info.recommendedAction,
|
|
167
|
+
actions: info.actions.map(action => ({
|
|
168
|
+
id: action.id,
|
|
169
|
+
name: action.name,
|
|
170
|
+
description: action.description,
|
|
171
|
+
destructive: action.destructive,
|
|
172
|
+
})),
|
|
173
|
+
})),
|
|
174
|
+
});
|
|
175
|
+
} catch (error) {
|
|
176
|
+
res.status(500).json({
|
|
177
|
+
error: 'Failed to retrieve maintenance info',
|
|
178
|
+
message: error instanceof Error ? error.message : String(error),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Register maintenance action endpoint (POST /diagnostics/maintenance/:pluginId/:actionId)
|
|
185
|
+
registry.addRoute({
|
|
186
|
+
method: 'post',
|
|
187
|
+
path: '/maintenance/:pluginId/:actionId',
|
|
188
|
+
pluginId: 'diagnostics',
|
|
189
|
+
handler: async (req: Request, res: Response) => {
|
|
190
|
+
try {
|
|
191
|
+
const { pluginId, actionId } = req.params;
|
|
192
|
+
|
|
193
|
+
if (!pluginId || !actionId) {
|
|
194
|
+
return res.status(400).json({
|
|
195
|
+
error: 'Missing required parameters',
|
|
196
|
+
message: 'Both pluginId and actionId are required',
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
logger.info(`Executing maintenance action ${actionId} for plugin ${pluginId}`);
|
|
201
|
+
|
|
202
|
+
const result = await registry.runMaintenanceAction(pluginId, actionId);
|
|
203
|
+
|
|
204
|
+
if (result.success) {
|
|
205
|
+
res.json({
|
|
206
|
+
success: true,
|
|
207
|
+
message: result.message || 'Maintenance action completed successfully',
|
|
208
|
+
pluginId,
|
|
209
|
+
actionId,
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
res.status(500).json({
|
|
213
|
+
success: false,
|
|
214
|
+
error: result.error || 'Maintenance action failed',
|
|
215
|
+
pluginId,
|
|
216
|
+
actionId,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
} catch (error) {
|
|
220
|
+
res.status(500).json({
|
|
221
|
+
error: 'Failed to execute maintenance action',
|
|
222
|
+
message: error instanceof Error ? error.message : String(error),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
151
228
|
logger.debug('Diagnostics plugin initialized');
|
|
152
229
|
},
|
|
153
230
|
|