create-fluxstack 1.8.1 → 1.8.3
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/.env.example +19 -0
- package/README.md +6 -3
- package/app/client/SIMPLIFICATION.md +140 -0
- package/app/client/frontend-only.ts +1 -1
- package/app/client/src/App.tsx +148 -283
- package/app/client/src/index.css +5 -20
- package/app/client/src/lib/eden-api.ts +53 -220
- package/app/client/src/main.tsx +2 -3
- package/app/server/controllers/users.controller.ts +57 -31
- package/app/server/index.ts +5 -2
- package/app/server/live/register-components.ts +18 -7
- package/app/server/routes/env-test.ts +53 -2
- package/app/server/routes/index.ts +1 -8
- package/app/server/routes/users.routes.ts +192 -91
- package/config/fluxstack.config.ts +2 -2
- package/config/plugins.config.ts +22 -1
- package/core/build/flux-plugins-generator.ts +5 -5
- package/core/build/live-components-generator.ts +15 -12
- package/core/cli/command-registry.ts +4 -14
- package/core/cli/commands/plugin-deps.ts +8 -8
- package/core/cli/generators/component.ts +3 -3
- package/core/cli/generators/controller.ts +4 -4
- package/core/cli/generators/index.ts +8 -8
- package/core/cli/generators/interactive.ts +4 -4
- package/core/cli/generators/plugin.ts +3 -3
- package/core/cli/generators/prompts.ts +1 -1
- package/core/cli/generators/route.ts +27 -11
- package/core/cli/generators/service.ts +5 -5
- package/core/cli/generators/template-engine.ts +1 -1
- package/core/cli/generators/types.ts +1 -1
- package/core/cli/index.ts +158 -193
- package/core/cli/plugin-discovery.ts +3 -3
- package/core/client/hooks/index.ts +2 -2
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +1 -1
- package/core/client/hooks/useChunkedUpload.ts +1 -1
- package/core/client/hooks/useHybridLiveComponent.ts +1 -1
- package/core/client/hooks/useWebSocket.ts +1 -1
- package/core/config/env.ts +1 -1
- package/core/config/runtime-config.ts +5 -5
- package/core/config/schema.ts +9 -0
- package/core/framework/server.ts +30 -15
- package/core/framework/types.ts +2 -2
- package/core/live/ComponentRegistry.ts +1 -1
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +65 -161
- package/core/plugins/built-in/static/index.ts +18 -47
- package/core/plugins/built-in/swagger/index.ts +301 -231
- package/core/plugins/built-in/vite/index.ts +74 -109
- package/core/plugins/config.ts +2 -2
- package/core/plugins/dependency-manager.ts +2 -2
- package/core/plugins/discovery.ts +1 -1
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/manager.ts +19 -4
- package/core/plugins/module-resolver.ts +1 -1
- package/core/plugins/registry.ts +3 -3
- package/core/plugins/types.ts +147 -5
- package/core/server/framework.ts +2 -2
- package/core/server/live/ComponentRegistry.ts +9 -26
- package/core/server/live/FileUploadManager.ts +1 -1
- package/core/server/live/auto-generated-components.ts +26 -0
- package/core/server/live/websocket-plugin.ts +211 -19
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +4 -4
- package/core/server/plugins/database.ts +1 -2
- package/core/server/plugins/static-files-plugin.ts +259 -231
- package/core/server/plugins/swagger.ts +1 -1
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +4 -4
- package/core/server/standalone.ts +16 -1
- package/core/testing/index.ts +1 -1
- package/core/testing/setup.ts +1 -1
- package/core/utils/logger/startup-banner.ts +7 -33
- package/core/utils/version.ts +6 -6
- package/create-fluxstack.ts +68 -25
- package/package.json +2 -2
- package/plugins/crypto-auth/index.ts +52 -47
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
- package/vitest.config.ts +11 -2
- package/app/client/src/App.css +0 -883
- package/app/client/src/components/ErrorBoundary.tsx +0 -107
- package/app/client/src/components/ErrorDisplay.css +0 -365
- package/app/client/src/components/ErrorDisplay.tsx +0 -258
- package/app/client/src/components/FluxStackConfig.tsx +0 -1321
- package/app/client/src/components/HybridLiveCounter.tsx +0 -140
- package/app/client/src/components/LiveClock.tsx +0 -286
- package/app/client/src/components/MainLayout.tsx +0 -388
- package/app/client/src/components/SidebarNavigation.tsx +0 -391
- package/app/client/src/components/StateDemo.tsx +0 -178
- package/app/client/src/components/SystemMonitor.tsx +0 -1044
- package/app/client/src/components/UserProfile.tsx +0 -809
- package/app/client/src/hooks/useAuth.ts +0 -39
- package/app/client/src/hooks/useNotifications.ts +0 -56
- package/app/client/src/lib/errors.ts +0 -340
- package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
- package/app/client/src/lib/index.ts +0 -45
- package/app/client/src/pages/ApiDocs.tsx +0 -182
- package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
- package/app/client/src/pages/Demo.tsx +0 -174
- package/app/client/src/pages/HybridLive.tsx +0 -263
- package/app/client/src/pages/Overview.tsx +0 -155
- package/app/client/src/store/README.md +0 -43
- package/app/client/src/store/index.ts +0 -16
- package/app/client/src/store/slices/uiSlice.ts +0 -151
- package/app/client/src/store/slices/userSlice.ts +0 -161
- package/app/client/src/test/README.md +0 -257
- package/app/client/src/test/setup.ts +0 -70
- package/app/client/src/test/types.ts +0 -12
- package/app/server/live/CounterComponent.ts +0 -191
- package/app/server/live/FluxStackConfig.ts +0 -534
- package/app/server/live/SidebarNavigation.ts +0 -157
- package/app/server/live/SystemMonitor.ts +0 -595
- package/app/server/live/SystemMonitorIntegration.ts +0 -151
- package/app/server/live/UserProfileComponent.ts +0 -141
- package/app/server/middleware/auth.ts +0 -136
- package/app/server/middleware/errorHandling.ts +0 -252
- package/app/server/middleware/index.ts +0 -10
- package/app/server/middleware/rateLimit.ts +0 -193
- package/app/server/middleware/requestLogging.ts +0 -215
- package/app/server/middleware/validation.ts +0 -270
- package/app/server/routes/config.ts +0 -145
- package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
- package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
- package/app/server/routes/exemplo-posts.routes.ts +0 -161
- package/app/server/routes/upload.ts +0 -92
- package/app/server/services/NotificationService.ts +0 -302
- package/app/server/services/UserService.ts +0 -222
- package/app/server/services/index.ts +0 -46
- package/app/server/types/index.ts +0 -1
package/core/framework/server.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Elysia } from "elysia"
|
|
2
|
-
import type { FluxStackConfig, FluxStackContext } from "
|
|
3
|
-
import type { FluxStack, PluginContext, PluginUtils } from "
|
|
4
|
-
import { PluginRegistry } from "
|
|
5
|
-
import { PluginManager } from "
|
|
6
|
-
import { getConfigSync, getEnvironmentInfo } from "
|
|
7
|
-
import { logger } from "
|
|
8
|
-
import { displayStartupBanner, type StartupInfo } from "
|
|
9
|
-
import { createErrorHandler } from "
|
|
10
|
-
import { createTimer, formatBytes, isProduction, isDevelopment } from "
|
|
11
|
-
import type { Plugin } from "
|
|
2
|
+
import type { FluxStackConfig, FluxStackContext } from "@/core/types"
|
|
3
|
+
import type { FluxStack, PluginContext, PluginUtils } from "@/core/plugins/types"
|
|
4
|
+
import { PluginRegistry } from "@/core/plugins/registry"
|
|
5
|
+
import { PluginManager } from "@/core/plugins/manager"
|
|
6
|
+
import { getConfigSync, getEnvironmentInfo } from "@/core/config"
|
|
7
|
+
import { logger } from "@/core/utils/logger"
|
|
8
|
+
import { displayStartupBanner, type StartupInfo } from "@/core/utils/logger/startup-banner"
|
|
9
|
+
import { createErrorHandler } from "@/core/utils/errors/handlers"
|
|
10
|
+
import { createTimer, formatBytes, isProduction, isDevelopment } from "@/core/utils/helpers"
|
|
11
|
+
import type { Plugin } from "@/core/plugins"
|
|
12
12
|
|
|
13
13
|
export class FluxStackFramework {
|
|
14
14
|
private app: Elysia
|
|
@@ -19,6 +19,21 @@ export class FluxStackFramework {
|
|
|
19
19
|
private isStarted: boolean = false
|
|
20
20
|
private requestTimings: Map<string, number> = new Map()
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Helper to safely parse request.url which might be relative or absolute
|
|
24
|
+
*/
|
|
25
|
+
private parseRequestURL(request: Request): URL {
|
|
26
|
+
try {
|
|
27
|
+
// Try parsing as absolute URL first
|
|
28
|
+
return new URL(request.url)
|
|
29
|
+
} catch {
|
|
30
|
+
// If relative, use host from headers or default to localhost
|
|
31
|
+
const host = request.headers.get('host') || 'localhost'
|
|
32
|
+
const protocol = request.headers.get('x-forwarded-proto') || 'http'
|
|
33
|
+
return new URL(request.url, `${protocol}://${host}`)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
22
37
|
constructor(config?: Partial<FluxStackConfig>) {
|
|
23
38
|
// Load the full configuration
|
|
24
39
|
const fullConfig = config ? { ...getConfigSync(), ...config } : getConfigSync()
|
|
@@ -160,7 +175,7 @@ export class FluxStackFramework {
|
|
|
160
175
|
private setupHeadHandler() {
|
|
161
176
|
// Global HEAD handler to prevent Elysia's automatic HEAD conversion bug
|
|
162
177
|
this.app.head("*", ({ request, set }) => {
|
|
163
|
-
const url =
|
|
178
|
+
const url = this.parseRequestURL(request)
|
|
164
179
|
|
|
165
180
|
// Handle API routes
|
|
166
181
|
if (url.pathname.startsWith(this.context.config.server.apiPrefix)) {
|
|
@@ -234,7 +249,7 @@ export class FluxStackFramework {
|
|
|
234
249
|
// Setup onRequest hook and onBeforeRoute hook
|
|
235
250
|
this.app.onRequest(async ({ request, set }) => {
|
|
236
251
|
const startTime = Date.now()
|
|
237
|
-
const url =
|
|
252
|
+
const url = this.parseRequestURL(request)
|
|
238
253
|
|
|
239
254
|
// Store start time for duration calculation (using request URL as key)
|
|
240
255
|
const requestKey = `${request.method}-${url.pathname}-${startTime}`
|
|
@@ -275,7 +290,7 @@ export class FluxStackFramework {
|
|
|
275
290
|
|
|
276
291
|
// Setup onResponse hook
|
|
277
292
|
this.app.onAfterHandle(async ({ request, response, set }) => {
|
|
278
|
-
const url =
|
|
293
|
+
const url = this.parseRequestURL(request)
|
|
279
294
|
|
|
280
295
|
// Retrieve start time using the timing key
|
|
281
296
|
const requestKey = set.headers['x-request-timing-key']
|
|
@@ -329,7 +344,7 @@ export class FluxStackFramework {
|
|
|
329
344
|
|
|
330
345
|
this.app.onError(async ({ error, request, path, set }) => {
|
|
331
346
|
const startTime = Date.now()
|
|
332
|
-
const url =
|
|
347
|
+
const url = this.parseRequestURL(request)
|
|
333
348
|
|
|
334
349
|
const errorContext = {
|
|
335
350
|
request,
|
|
@@ -448,7 +463,7 @@ export class FluxStackFramework {
|
|
|
448
463
|
|
|
449
464
|
private async handleViteProxy(errorContext: any): Promise<Response> {
|
|
450
465
|
const vitePort = this.context.config.client?.port || 5173
|
|
451
|
-
const url =
|
|
466
|
+
const url = this.parseRequestURL(errorContext.request)
|
|
452
467
|
|
|
453
468
|
try {
|
|
454
469
|
const viteUrl = `http://localhost:${vitePort}${url.pathname}${url.search}`
|
package/core/framework/types.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Defines the main interfaces and types for the FluxStack framework
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { FluxStackConfig } from "
|
|
7
|
-
import type { Logger } from "
|
|
6
|
+
import type { FluxStackConfig } from "@/core/types"
|
|
7
|
+
import type { Logger } from "@/core/utils/logger/index"
|
|
8
8
|
|
|
9
9
|
export interface FluxStackFrameworkOptions {
|
|
10
10
|
config?: Partial<FluxStackConfig>
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
* Provides performance monitoring, metrics collection, and system monitoring
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { FluxStack, PluginContext, RequestContext, ResponseContext, ErrorContext } from "
|
|
7
|
-
import { MetricsCollector } from "
|
|
6
|
+
import type { FluxStack, PluginContext, RequestContext, ResponseContext, ErrorContext } from "@/core/plugins/types"
|
|
7
|
+
import { MetricsCollector } from "@/core/utils/monitoring"
|
|
8
|
+
import { appConfig } from '@/config/app.config'
|
|
9
|
+
import { monitoringConfig } from '@/config/monitoring.config'
|
|
8
10
|
import * as os from 'os'
|
|
9
11
|
import * as fs from 'fs'
|
|
10
12
|
import * as path from 'path'
|
|
@@ -63,6 +65,36 @@ export interface AlertThreshold {
|
|
|
63
65
|
|
|
64
66
|
type Plugin = FluxStack.Plugin
|
|
65
67
|
|
|
68
|
+
// Default configuration values (uses monitoringConfig from /config)
|
|
69
|
+
const DEFAULTS = {
|
|
70
|
+
enabled: monitoringConfig.monitoring.enabled,
|
|
71
|
+
httpMetrics: monitoringConfig.metrics.httpMetrics,
|
|
72
|
+
systemMetrics: monitoringConfig.metrics.systemMetrics,
|
|
73
|
+
customMetrics: monitoringConfig.metrics.customMetrics,
|
|
74
|
+
collectInterval: monitoringConfig.metrics.collectInterval,
|
|
75
|
+
retentionPeriod: monitoringConfig.metrics.retentionPeriod,
|
|
76
|
+
exporters: [
|
|
77
|
+
{
|
|
78
|
+
type: "console" as "console" | "prometheus" | "json" | "file",
|
|
79
|
+
interval: 30000,
|
|
80
|
+
enabled: monitoringConfig.metrics.exportToConsole
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: "prometheus" as "console" | "prometheus" | "json" | "file",
|
|
84
|
+
endpoint: "/metrics",
|
|
85
|
+
enabled: true,
|
|
86
|
+
format: "text" as const
|
|
87
|
+
}
|
|
88
|
+
] as MetricsExporter[],
|
|
89
|
+
thresholds: {
|
|
90
|
+
responseTime: 1000, // ms
|
|
91
|
+
errorRate: 0.05, // 5%
|
|
92
|
+
memoryUsage: 0.8, // 80%
|
|
93
|
+
cpuUsage: 0.8 // 80%
|
|
94
|
+
},
|
|
95
|
+
alerts: [] as AlertThreshold[]
|
|
96
|
+
}
|
|
97
|
+
|
|
66
98
|
export const monitoringPlugin: Plugin = {
|
|
67
99
|
name: "monitoring",
|
|
68
100
|
version: "1.0.0",
|
|
@@ -71,137 +103,20 @@ export const monitoringPlugin: Plugin = {
|
|
|
71
103
|
priority: 900, // Should run early to capture all metrics
|
|
72
104
|
category: "monitoring",
|
|
73
105
|
tags: ["monitoring", "metrics", "performance", "observability"],
|
|
74
|
-
dependencies: [],
|
|
75
|
-
|
|
76
|
-
configSchema: {
|
|
77
|
-
type: "object",
|
|
78
|
-
properties: {
|
|
79
|
-
enabled: {
|
|
80
|
-
type: "boolean",
|
|
81
|
-
description: "Enable monitoring plugin"
|
|
82
|
-
},
|
|
83
|
-
httpMetrics: {
|
|
84
|
-
type: "boolean",
|
|
85
|
-
description: "Collect HTTP request/response metrics"
|
|
86
|
-
},
|
|
87
|
-
systemMetrics: {
|
|
88
|
-
type: "boolean",
|
|
89
|
-
description: "Collect system metrics (memory, CPU, etc.)"
|
|
90
|
-
},
|
|
91
|
-
customMetrics: {
|
|
92
|
-
type: "boolean",
|
|
93
|
-
description: "Enable custom metrics collection"
|
|
94
|
-
},
|
|
95
|
-
collectInterval: {
|
|
96
|
-
type: "number",
|
|
97
|
-
minimum: 1000,
|
|
98
|
-
description: "Interval for collecting system metrics (ms)"
|
|
99
|
-
},
|
|
100
|
-
retentionPeriod: {
|
|
101
|
-
type: "number",
|
|
102
|
-
minimum: 60000,
|
|
103
|
-
description: "How long to retain metrics in memory (ms)"
|
|
104
|
-
},
|
|
105
|
-
exporters: {
|
|
106
|
-
type: "array",
|
|
107
|
-
items: {
|
|
108
|
-
type: "object",
|
|
109
|
-
properties: {
|
|
110
|
-
type: {
|
|
111
|
-
type: "string",
|
|
112
|
-
enum: ["prometheus", "json", "console", "file"]
|
|
113
|
-
},
|
|
114
|
-
endpoint: { type: "string" },
|
|
115
|
-
interval: { type: "number" },
|
|
116
|
-
enabled: { type: "boolean" },
|
|
117
|
-
format: {
|
|
118
|
-
type: "string",
|
|
119
|
-
enum: ["text", "json"]
|
|
120
|
-
},
|
|
121
|
-
filePath: { type: "string" }
|
|
122
|
-
},
|
|
123
|
-
required: ["type"]
|
|
124
|
-
},
|
|
125
|
-
description: "Metrics exporters configuration"
|
|
126
|
-
},
|
|
127
|
-
thresholds: {
|
|
128
|
-
type: "object",
|
|
129
|
-
properties: {
|
|
130
|
-
responseTime: { type: "number" },
|
|
131
|
-
errorRate: { type: "number" },
|
|
132
|
-
memoryUsage: { type: "number" },
|
|
133
|
-
cpuUsage: { type: "number" }
|
|
134
|
-
},
|
|
135
|
-
description: "Alert thresholds"
|
|
136
|
-
},
|
|
137
|
-
alerts: {
|
|
138
|
-
type: "array",
|
|
139
|
-
items: {
|
|
140
|
-
type: "object",
|
|
141
|
-
properties: {
|
|
142
|
-
metric: { type: "string" },
|
|
143
|
-
operator: {
|
|
144
|
-
type: "string",
|
|
145
|
-
enum: [">", "<", ">=", "<=", "==", "!="]
|
|
146
|
-
},
|
|
147
|
-
value: { type: "number" },
|
|
148
|
-
severity: {
|
|
149
|
-
type: "string",
|
|
150
|
-
enum: ["info", "warning", "error", "critical"]
|
|
151
|
-
},
|
|
152
|
-
message: { type: "string" }
|
|
153
|
-
},
|
|
154
|
-
required: ["metric", "operator", "value", "severity"]
|
|
155
|
-
},
|
|
156
|
-
description: "Custom alert configurations"
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
additionalProperties: false
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
defaultConfig: {
|
|
163
|
-
enabled: true,
|
|
164
|
-
httpMetrics: true,
|
|
165
|
-
systemMetrics: true,
|
|
166
|
-
customMetrics: true,
|
|
167
|
-
collectInterval: 5000,
|
|
168
|
-
retentionPeriod: 300000, // 5 minutes
|
|
169
|
-
exporters: [
|
|
170
|
-
{
|
|
171
|
-
type: "console",
|
|
172
|
-
interval: 30000,
|
|
173
|
-
enabled: false
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
type: "prometheus",
|
|
177
|
-
endpoint: "/metrics",
|
|
178
|
-
enabled: true,
|
|
179
|
-
format: "text"
|
|
180
|
-
}
|
|
181
|
-
],
|
|
182
|
-
thresholds: {
|
|
183
|
-
responseTime: 1000, // ms
|
|
184
|
-
errorRate: 0.05, // 5%
|
|
185
|
-
memoryUsage: 0.8, // 80%
|
|
186
|
-
cpuUsage: 0.8 // 80%
|
|
187
|
-
},
|
|
188
|
-
alerts: []
|
|
189
|
-
},
|
|
106
|
+
dependencies: [],
|
|
190
107
|
|
|
191
108
|
setup: async (context: PluginContext) => {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (!config.enabled) {
|
|
109
|
+
if (!DEFAULTS.enabled) {
|
|
195
110
|
context.logger.info('Monitoring plugin disabled by configuration')
|
|
196
111
|
return
|
|
197
112
|
}
|
|
198
113
|
|
|
199
114
|
context.logger.info('Initializing monitoring plugin', {
|
|
200
|
-
httpMetrics:
|
|
201
|
-
systemMetrics:
|
|
202
|
-
customMetrics:
|
|
203
|
-
exporters:
|
|
204
|
-
alerts:
|
|
115
|
+
httpMetrics: DEFAULTS.httpMetrics,
|
|
116
|
+
systemMetrics: DEFAULTS.systemMetrics,
|
|
117
|
+
customMetrics: DEFAULTS.customMetrics,
|
|
118
|
+
exporters: DEFAULTS.exporters.length,
|
|
119
|
+
alerts: DEFAULTS.alerts.length
|
|
205
120
|
})
|
|
206
121
|
|
|
207
122
|
// Initialize enhanced metrics registry
|
|
@@ -219,36 +134,34 @@ export const monitoringPlugin: Plugin = {
|
|
|
219
134
|
;(context as any).metricsCollector = metricsCollector
|
|
220
135
|
|
|
221
136
|
// Initialize HTTP metrics
|
|
222
|
-
if (
|
|
137
|
+
if (DEFAULTS.httpMetrics) {
|
|
223
138
|
initializeHttpMetrics(metricsRegistry, metricsCollector)
|
|
224
139
|
}
|
|
225
140
|
|
|
226
141
|
// Start system metrics collection
|
|
227
|
-
if (
|
|
228
|
-
startSystemMetricsCollection(context,
|
|
142
|
+
if (DEFAULTS.systemMetrics) {
|
|
143
|
+
startSystemMetricsCollection(context, metricsCollector)
|
|
229
144
|
}
|
|
230
145
|
|
|
231
146
|
// Setup metrics endpoint for Prometheus
|
|
232
|
-
setupMetricsEndpoint(context,
|
|
147
|
+
setupMetricsEndpoint(context, metricsRegistry, metricsCollector)
|
|
233
148
|
|
|
234
149
|
// Start metrics exporters
|
|
235
|
-
startMetricsExporters(context,
|
|
150
|
+
startMetricsExporters(context, metricsRegistry, metricsCollector)
|
|
236
151
|
|
|
237
152
|
// Setup metrics cleanup
|
|
238
|
-
setupMetricsCleanup(context,
|
|
153
|
+
setupMetricsCleanup(context, metricsRegistry)
|
|
239
154
|
|
|
240
155
|
// Setup alert monitoring
|
|
241
|
-
if (
|
|
242
|
-
setupAlertMonitoring(context,
|
|
156
|
+
if (DEFAULTS.alerts.length > 0) {
|
|
157
|
+
setupAlertMonitoring(context, metricsRegistry)
|
|
243
158
|
}
|
|
244
159
|
|
|
245
160
|
context.logger.info('Monitoring plugin initialized successfully')
|
|
246
161
|
},
|
|
247
162
|
|
|
248
163
|
onServerStart: async (context: PluginContext) => {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (config.enabled) {
|
|
164
|
+
if (DEFAULTS.enabled) {
|
|
252
165
|
context.logger.info('Monitoring plugin: Server monitoring started', {
|
|
253
166
|
pid: process.pid,
|
|
254
167
|
nodeVersion: process.version,
|
|
@@ -258,17 +171,15 @@ export const monitoringPlugin: Plugin = {
|
|
|
258
171
|
// Record server start metric
|
|
259
172
|
const metricsRegistry = (context as any).metricsRegistry as MetricsRegistry
|
|
260
173
|
if (metricsRegistry) {
|
|
261
|
-
recordCounter(metricsRegistry, 'server_starts_total', 1, {
|
|
262
|
-
version:
|
|
174
|
+
recordCounter(metricsRegistry, 'server_starts_total', 1, {
|
|
175
|
+
version: appConfig.version
|
|
263
176
|
})
|
|
264
177
|
}
|
|
265
178
|
}
|
|
266
179
|
},
|
|
267
180
|
|
|
268
181
|
onServerStop: async (context: PluginContext) => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (config.enabled) {
|
|
182
|
+
if (DEFAULTS.enabled) {
|
|
272
183
|
context.logger.info('Monitoring plugin: Server monitoring stopped')
|
|
273
184
|
|
|
274
185
|
// Record server stop metric
|
|
@@ -358,14 +269,13 @@ export const monitoringPlugin: Plugin = {
|
|
|
358
269
|
)
|
|
359
270
|
|
|
360
271
|
// Check thresholds and log warnings
|
|
361
|
-
|
|
362
|
-
if (config.thresholds.responseTime && duration > config.thresholds.responseTime) {
|
|
272
|
+
if (DEFAULTS.thresholds.responseTime && duration > DEFAULTS.thresholds.responseTime) {
|
|
363
273
|
const logger = (responseContext as any).logger || console
|
|
364
274
|
logger.warn(`Slow request detected: ${responseContext.method} ${responseContext.path} took ${duration}ms`, {
|
|
365
275
|
method: responseContext.method,
|
|
366
276
|
path: responseContext.path,
|
|
367
277
|
duration,
|
|
368
|
-
threshold:
|
|
278
|
+
threshold: DEFAULTS.thresholds.responseTime
|
|
369
279
|
})
|
|
370
280
|
}
|
|
371
281
|
},
|
|
@@ -410,12 +320,6 @@ export const monitoringPlugin: Plugin = {
|
|
|
410
320
|
|
|
411
321
|
// Helper functions
|
|
412
322
|
|
|
413
|
-
function getPluginConfig(context: any) {
|
|
414
|
-
// In a real implementation, this would get the config from the plugin context
|
|
415
|
-
const pluginConfig = context.config?.plugins?.config?.monitoring || {}
|
|
416
|
-
return { ...monitoringPlugin.defaultConfig, ...pluginConfig }
|
|
417
|
-
}
|
|
418
|
-
|
|
419
323
|
function getMetricsRegistry(context: any): MetricsRegistry | null {
|
|
420
324
|
// In a real implementation, this would get the registry from the plugin context
|
|
421
325
|
return (context as any).metricsRegistry || null
|
|
@@ -444,7 +348,7 @@ function initializeHttpMetrics(registry: MetricsRegistry, collector: MetricsColl
|
|
|
444
348
|
collector.createHistogram('http_response_size_bytes', 'HTTP response size in bytes', [100, 1000, 10000, 100000, 1000000])
|
|
445
349
|
}
|
|
446
350
|
|
|
447
|
-
function startSystemMetricsCollection(context: PluginContext,
|
|
351
|
+
function startSystemMetricsCollection(context: PluginContext, collector: MetricsCollector) {
|
|
448
352
|
const intervals: NodeJS.Timeout[] = []
|
|
449
353
|
|
|
450
354
|
// Initialize system metrics in collector
|
|
@@ -518,16 +422,16 @@ function startSystemMetricsCollection(context: PluginContext, config: any, colle
|
|
|
518
422
|
|
|
519
423
|
// Collect metrics immediately and then at intervals
|
|
520
424
|
collectSystemMetrics()
|
|
521
|
-
const interval = setInterval(collectSystemMetrics,
|
|
425
|
+
const interval = setInterval(collectSystemMetrics, DEFAULTS.collectInterval)
|
|
522
426
|
intervals.push(interval)
|
|
523
427
|
|
|
524
428
|
// Store intervals for cleanup
|
|
525
429
|
;(context as any).monitoringIntervals = intervals
|
|
526
430
|
}
|
|
527
431
|
|
|
528
|
-
function setupMetricsEndpoint(context: PluginContext,
|
|
432
|
+
function setupMetricsEndpoint(context: PluginContext, _registry: MetricsRegistry, collector: MetricsCollector) {
|
|
529
433
|
// Find Prometheus exporter configuration
|
|
530
|
-
const prometheusExporter =
|
|
434
|
+
const prometheusExporter = DEFAULTS.exporters.find((e: any) => e.type === 'prometheus' && e.enabled)
|
|
531
435
|
if (!prometheusExporter) return
|
|
532
436
|
|
|
533
437
|
const endpoint = prometheusExporter.endpoint || '/metrics'
|
|
@@ -547,10 +451,10 @@ function setupMetricsEndpoint(context: PluginContext, config: any, _registry: Me
|
|
|
547
451
|
}
|
|
548
452
|
}
|
|
549
453
|
|
|
550
|
-
function startMetricsExporters(context: PluginContext,
|
|
454
|
+
function startMetricsExporters(context: PluginContext, registry: MetricsRegistry, collector: MetricsCollector) {
|
|
551
455
|
const intervals: NodeJS.Timeout[] = (context as any).monitoringIntervals || []
|
|
552
456
|
|
|
553
|
-
for (const exporterConfig of
|
|
457
|
+
for (const exporterConfig of DEFAULTS.exporters) {
|
|
554
458
|
if (!exporterConfig.enabled) continue
|
|
555
459
|
|
|
556
460
|
const exportMetrics = () => {
|
|
@@ -588,11 +492,11 @@ function startMetricsExporters(context: PluginContext, config: any, registry: Me
|
|
|
588
492
|
;(context as any).monitoringIntervals = intervals
|
|
589
493
|
}
|
|
590
494
|
|
|
591
|
-
function setupAlertMonitoring(context: PluginContext,
|
|
495
|
+
function setupAlertMonitoring(context: PluginContext, registry: MetricsRegistry) {
|
|
592
496
|
const intervals: NodeJS.Timeout[] = (context as any).monitoringIntervals || []
|
|
593
497
|
|
|
594
498
|
const checkAlerts = () => {
|
|
595
|
-
for (const alert of
|
|
499
|
+
for (const alert of DEFAULTS.alerts) {
|
|
596
500
|
try {
|
|
597
501
|
const metricValue = getMetricValue(registry, alert.metric)
|
|
598
502
|
if (metricValue !== null && evaluateThreshold(metricValue, alert.operator, alert.value)) {
|
|
@@ -640,12 +544,12 @@ function setupAlertMonitoring(context: PluginContext, config: any, registry: Met
|
|
|
640
544
|
;(context as any).monitoringIntervals = intervals
|
|
641
545
|
}
|
|
642
546
|
|
|
643
|
-
function setupMetricsCleanup(context: PluginContext,
|
|
547
|
+
function setupMetricsCleanup(context: PluginContext, registry: MetricsRegistry) {
|
|
644
548
|
const intervals: NodeJS.Timeout[] = (context as any).monitoringIntervals || []
|
|
645
549
|
|
|
646
550
|
const cleanup = () => {
|
|
647
551
|
const now = Date.now()
|
|
648
|
-
const cutoff = now -
|
|
552
|
+
const cutoff = now - DEFAULTS.retentionPeriod
|
|
649
553
|
|
|
650
554
|
// Clean up old metrics
|
|
651
555
|
for (const [key, metric] of registry.counters.entries()) {
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { join } from "path"
|
|
2
2
|
import { statSync, existsSync } from "fs"
|
|
3
|
-
import type { Plugin, PluginContext } from "
|
|
3
|
+
import type { Plugin, PluginContext } from "@/core/plugins"
|
|
4
|
+
|
|
5
|
+
// Default configuration values
|
|
6
|
+
const DEFAULTS = {
|
|
7
|
+
enabled: true,
|
|
8
|
+
publicDir: "./dist/client",
|
|
9
|
+
indexFile: "index.html"
|
|
10
|
+
}
|
|
4
11
|
|
|
5
12
|
export const staticPlugin: Plugin = {
|
|
6
13
|
name: "static",
|
|
@@ -12,41 +19,14 @@ export const staticPlugin: Plugin = {
|
|
|
12
19
|
tags: ["static", "files", "spa"],
|
|
13
20
|
dependencies: [],
|
|
14
21
|
|
|
15
|
-
configSchema: {
|
|
16
|
-
type: "object",
|
|
17
|
-
properties: {
|
|
18
|
-
enabled: {
|
|
19
|
-
type: "boolean",
|
|
20
|
-
description: "Enable static file serving"
|
|
21
|
-
},
|
|
22
|
-
publicDir: {
|
|
23
|
-
type: "string",
|
|
24
|
-
description: "Directory for static files"
|
|
25
|
-
},
|
|
26
|
-
indexFile: {
|
|
27
|
-
type: "string",
|
|
28
|
-
description: "Index file for SPA routing"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
additionalProperties: false
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
defaultConfig: {
|
|
35
|
-
enabled: true,
|
|
36
|
-
publicDir: "./dist/client",
|
|
37
|
-
indexFile: "index.html"
|
|
38
|
-
},
|
|
39
|
-
|
|
40
22
|
setup: async (context: PluginContext) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (!config.enabled) {
|
|
23
|
+
if (!DEFAULTS.enabled) {
|
|
44
24
|
context.logger.info('Static files plugin disabled')
|
|
45
25
|
return
|
|
46
26
|
}
|
|
47
27
|
|
|
48
28
|
context.logger.info("Static files plugin activated", {
|
|
49
|
-
publicDir:
|
|
29
|
+
publicDir: DEFAULTS.publicDir
|
|
50
30
|
})
|
|
51
31
|
|
|
52
32
|
// Static fallback handler (runs last)
|
|
@@ -61,9 +41,9 @@ export const staticPlugin: Plugin = {
|
|
|
61
41
|
const isDev = context.utils.isDevelopment()
|
|
62
42
|
let baseDir: string
|
|
63
43
|
|
|
64
|
-
if (isDev && existsSync(
|
|
44
|
+
if (isDev && existsSync(DEFAULTS.publicDir)) {
|
|
65
45
|
// Development: use public directory
|
|
66
|
-
baseDir =
|
|
46
|
+
baseDir = DEFAULTS.publicDir
|
|
67
47
|
} else {
|
|
68
48
|
// Production: try paths in order of preference
|
|
69
49
|
if (existsSync('client')) {
|
|
@@ -74,13 +54,13 @@ export const staticPlugin: Plugin = {
|
|
|
74
54
|
baseDir = 'dist/client'
|
|
75
55
|
} else {
|
|
76
56
|
// Fallback to configured path
|
|
77
|
-
baseDir =
|
|
57
|
+
baseDir = DEFAULTS.publicDir
|
|
78
58
|
}
|
|
79
59
|
}
|
|
80
60
|
|
|
81
61
|
// Root or empty path → index.html
|
|
82
62
|
if (pathname === '/' || pathname === '') {
|
|
83
|
-
pathname = `/${
|
|
63
|
+
pathname = `/${DEFAULTS.indexFile}`
|
|
84
64
|
}
|
|
85
65
|
|
|
86
66
|
const filePath = join(baseDir, pathname)
|
|
@@ -97,7 +77,7 @@ export const staticPlugin: Plugin = {
|
|
|
97
77
|
}
|
|
98
78
|
|
|
99
79
|
// SPA fallback: serve index.html for non-file routes
|
|
100
|
-
const indexPath = join(baseDir,
|
|
80
|
+
const indexPath = join(baseDir, DEFAULTS.indexFile)
|
|
101
81
|
try {
|
|
102
82
|
statSync(indexPath) // Ensure index exists
|
|
103
83
|
return new Response(Bun.file(indexPath))
|
|
@@ -111,22 +91,13 @@ export const staticPlugin: Plugin = {
|
|
|
111
91
|
},
|
|
112
92
|
|
|
113
93
|
onServerStart: async (context: PluginContext) => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (config.enabled) {
|
|
94
|
+
if (DEFAULTS.enabled) {
|
|
117
95
|
context.logger.info(`Static files plugin ready`, {
|
|
118
|
-
publicDir:
|
|
119
|
-
indexFile:
|
|
96
|
+
publicDir: DEFAULTS.publicDir,
|
|
97
|
+
indexFile: DEFAULTS.indexFile
|
|
120
98
|
})
|
|
121
99
|
}
|
|
122
100
|
}
|
|
123
101
|
}
|
|
124
102
|
|
|
125
|
-
// Helper function to get plugin config
|
|
126
|
-
function getPluginConfig(context: PluginContext) {
|
|
127
|
-
const pluginConfig = context.config.plugins.config?.static || {}
|
|
128
|
-
return { ...staticPlugin.defaultConfig, ...pluginConfig }
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
103
|
export default staticPlugin
|