create-fluxstack 1.16.0 → 1.17.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 +80 -0
- package/app/client/src/App.tsx +8 -0
- package/app/client/src/live/AuthDemo.tsx +4 -4
- package/core/build/bundler.ts +40 -26
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +92 -21
- package/core/cli/command-registry.ts +44 -46
- package/core/cli/commands/build.ts +11 -6
- package/core/cli/commands/create.ts +7 -5
- package/core/cli/commands/dev.ts +6 -5
- package/core/cli/commands/help.ts +3 -2
- package/core/cli/commands/make-plugin.ts +8 -7
- package/core/cli/commands/plugin-add.ts +60 -43
- package/core/cli/commands/plugin-deps.ts +73 -57
- package/core/cli/commands/plugin-list.ts +44 -41
- package/core/cli/commands/plugin-remove.ts +33 -22
- package/core/cli/generators/component.ts +770 -769
- package/core/cli/generators/controller.ts +9 -8
- package/core/cli/generators/index.ts +148 -146
- package/core/cli/generators/interactive.ts +228 -227
- package/core/cli/generators/plugin.ts +11 -10
- package/core/cli/generators/prompts.ts +83 -82
- package/core/cli/generators/route.ts +7 -6
- package/core/cli/generators/service.ts +10 -9
- package/core/cli/generators/template-engine.ts +2 -1
- package/core/cli/generators/types.ts +7 -7
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +9 -8
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/standalone.ts +18 -17
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +1 -0
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +73 -113
- package/core/framework/types.ts +2 -2
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +6 -3
- package/core/plugins/built-in/monitoring/index.ts +110 -68
- package/core/plugins/built-in/static/index.ts +2 -2
- package/core/plugins/built-in/swagger/index.ts +9 -9
- package/core/plugins/built-in/vite/index.ts +3 -3
- package/core/plugins/built-in/vite/vite-dev.ts +3 -3
- package/core/plugins/config.ts +50 -47
- package/core/plugins/discovery.ts +10 -4
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +206 -203
- package/core/plugins/manager.ts +21 -20
- package/core/plugins/registry.ts +76 -12
- package/core/plugins/types.ts +14 -14
- package/core/server/framework.ts +3 -189
- package/core/server/live/auto-generated-components.ts +11 -29
- package/core/server/live/index.ts +41 -31
- package/core/server/live/websocket-plugin.ts +11 -1
- package/core/server/middleware/elysia-helpers.ts +16 -15
- package/core/server/middleware/errorHandling.ts +14 -14
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +181 -180
- package/core/server/plugins/static-files-plugin.ts +4 -3
- package/core/server/plugins/swagger.ts +11 -8
- package/core/server/rooms/RoomBroadcaster.ts +11 -10
- package/core/server/rooms/RoomSystem.ts +14 -11
- package/core/server/services/BaseService.ts +7 -7
- package/core/server/services/ServiceContainer.ts +5 -5
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +28 -27
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/config.ts +5 -5
- package/core/types/index.ts +1 -1
- package/core/types/plugin.ts +2 -2
- package/core/types/types.ts +3 -3
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +10 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +30 -20
- package/core/utils/errors/index.ts +54 -46
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +19 -16
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +2 -2
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +13 -3
- package/core/utils/logger/startup-banner.ts +2 -2
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +67 -66
- package/core/utils/version.ts +1 -1
- package/package.json +104 -100
- package/playwright-report/index.html +85 -0
- package/playwright.config.ts +31 -0
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
- package/plugins/crypto-auth/client/components/index.ts +11 -11
- package/plugins/crypto-auth/client/index.ts +11 -11
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/vite.config.ts +13 -0
- package/app/client/.live-stubs/LiveAdminPanel.js +0 -5
- package/app/client/.live-stubs/LiveCounter.js +0 -9
- package/app/client/.live-stubs/LiveForm.js +0 -11
- package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
- package/app/client/.live-stubs/LivePingPong.js +0 -10
- package/app/client/.live-stubs/LiveRoomChat.js +0 -11
- package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
- package/app/client/.live-stubs/LiveUpload.js +0 -15
- package/app/server/live/register-components.ts +0 -19
- package/core/build/live-components-generator.ts +0 -321
- package/core/live/ComponentRegistry.ts +0 -403
- package/core/live/types.ts +0 -241
- package/workspace.json +0 -6
|
@@ -64,6 +64,42 @@ export interface AlertThreshold {
|
|
|
64
64
|
|
|
65
65
|
type Plugin = FluxStack.Plugin
|
|
66
66
|
|
|
67
|
+
/** Extended plugin context with monitoring-specific properties */
|
|
68
|
+
interface MonitoringPluginContext extends PluginContext {
|
|
69
|
+
metricsRegistry?: MetricsRegistry
|
|
70
|
+
metricsCollector?: MetricsCollector
|
|
71
|
+
monitoringConfig?: MonitoringOptions
|
|
72
|
+
monitoringIntervals?: NodeJS.Timeout[]
|
|
73
|
+
config: PluginContext['config'] & {
|
|
74
|
+
monitoring?: Record<string, unknown>
|
|
75
|
+
plugins?: { config?: { monitoring?: Partial<MonitoringOptions> } }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Extended request context with monitoring start time */
|
|
80
|
+
interface MonitoringRequestContext extends RequestContext {
|
|
81
|
+
monitoringStartTime?: number
|
|
82
|
+
metricsRegistry?: MetricsRegistry
|
|
83
|
+
metricsCollector?: MetricsCollector
|
|
84
|
+
logger?: { warn: (message: string, meta?: unknown) => void }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Extended response context with monitoring start time */
|
|
88
|
+
interface MonitoringResponseContext extends ResponseContext {
|
|
89
|
+
monitoringStartTime?: number
|
|
90
|
+
metricsRegistry?: MetricsRegistry
|
|
91
|
+
metricsCollector?: MetricsCollector
|
|
92
|
+
logger?: { warn: (message: string, meta?: unknown) => void }
|
|
93
|
+
monitoringConfig?: MonitoringOptions
|
|
94
|
+
context?: { monitoringConfig?: MonitoringOptions }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Extended error context with monitoring properties */
|
|
98
|
+
interface MonitoringErrorContext extends ErrorContext {
|
|
99
|
+
metricsRegistry?: MetricsRegistry
|
|
100
|
+
metricsCollector?: MetricsCollector
|
|
101
|
+
}
|
|
102
|
+
|
|
67
103
|
// Default configuration values (uses monitoringConfig from /config)
|
|
68
104
|
const DEFAULTS = {
|
|
69
105
|
enabled: monitoringConfig.monitoring.enabled,
|
|
@@ -94,53 +130,55 @@ const DEFAULTS = {
|
|
|
94
130
|
alerts: [] as AlertThreshold[]
|
|
95
131
|
}
|
|
96
132
|
|
|
97
|
-
type MonitoringOptions = typeof DEFAULTS
|
|
133
|
+
type MonitoringOptions = { [K in keyof typeof DEFAULTS]: typeof DEFAULTS[K] extends number ? number : typeof DEFAULTS[K] extends boolean ? boolean : typeof DEFAULTS[K] }
|
|
98
134
|
|
|
99
135
|
function mergeMonitoringOptions(base: MonitoringOptions, overrides: Partial<MonitoringOptions>): MonitoringOptions {
|
|
100
|
-
const result
|
|
136
|
+
const result = { ...base } as Record<string, unknown>
|
|
137
|
+
const baseRecord = base as Record<string, unknown>
|
|
101
138
|
|
|
102
139
|
for (const key of Object.keys(overrides) as (keyof MonitoringOptions)[]) {
|
|
103
|
-
const value = overrides[key]
|
|
140
|
+
const value = (overrides as Record<string, unknown>)[key]
|
|
104
141
|
if (value === undefined) continue
|
|
105
142
|
|
|
106
143
|
if (Array.isArray(value)) {
|
|
107
|
-
|
|
144
|
+
result[key] = value
|
|
108
145
|
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
109
|
-
|
|
146
|
+
result[key] = { ...(baseRecord[key] as object), ...(value as object) }
|
|
110
147
|
} else {
|
|
111
|
-
|
|
148
|
+
result[key] = value
|
|
112
149
|
}
|
|
113
150
|
}
|
|
114
151
|
|
|
115
|
-
return result
|
|
152
|
+
return result as unknown as MonitoringOptions
|
|
116
153
|
}
|
|
117
154
|
|
|
118
|
-
function resolveMonitoringOptions(source:
|
|
119
|
-
if (source
|
|
120
|
-
if (source
|
|
155
|
+
function resolveMonitoringOptions(source: MonitoringResponseContext | MonitoringPluginContext): MonitoringOptions {
|
|
156
|
+
if ('monitoringConfig' in source && source.monitoringConfig) return source.monitoringConfig
|
|
157
|
+
if ('context' in source && (source as MonitoringResponseContext).context?.monitoringConfig) return (source as MonitoringResponseContext).context!.monitoringConfig!
|
|
121
158
|
return DEFAULTS
|
|
122
159
|
}
|
|
123
160
|
|
|
124
|
-
function normalizeRuntimeMonitoringConfig(runtime:
|
|
161
|
+
function normalizeRuntimeMonitoringConfig(runtime: Record<string, unknown> | undefined): Partial<MonitoringOptions> {
|
|
125
162
|
if (!runtime) return {}
|
|
126
163
|
const overrides: Partial<MonitoringOptions> = {}
|
|
127
164
|
|
|
128
165
|
if (typeof runtime.enabled === 'boolean') overrides.enabled = runtime.enabled
|
|
129
|
-
if (runtime.metrics) {
|
|
130
|
-
|
|
131
|
-
overrides.
|
|
132
|
-
overrides.
|
|
133
|
-
overrides.
|
|
134
|
-
overrides.
|
|
166
|
+
if (runtime.metrics && typeof runtime.metrics === 'object') {
|
|
167
|
+
const metrics = runtime.metrics as Record<string, unknown>
|
|
168
|
+
if (typeof metrics.httpMetrics === 'boolean') overrides.httpMetrics = metrics.httpMetrics
|
|
169
|
+
if (typeof metrics.systemMetrics === 'boolean') overrides.systemMetrics = metrics.systemMetrics
|
|
170
|
+
if (typeof metrics.customMetrics === 'boolean') overrides.customMetrics = metrics.customMetrics
|
|
171
|
+
if (typeof metrics.collectInterval === 'number') overrides.collectInterval = metrics.collectInterval
|
|
172
|
+
if (typeof metrics.retentionPeriod === 'number') overrides.retentionPeriod = metrics.retentionPeriod
|
|
135
173
|
}
|
|
136
174
|
if (Array.isArray(runtime.exporters)) {
|
|
137
175
|
overrides.exporters = runtime.exporters as MetricsExporter[]
|
|
138
176
|
}
|
|
139
|
-
if (runtime.thresholds) {
|
|
140
|
-
overrides.thresholds = { ...DEFAULTS.thresholds, ...runtime.thresholds }
|
|
177
|
+
if (runtime.thresholds && typeof runtime.thresholds === 'object') {
|
|
178
|
+
overrides.thresholds = { ...DEFAULTS.thresholds, ...(runtime.thresholds as Record<string, number>) }
|
|
141
179
|
}
|
|
142
180
|
if (Array.isArray(runtime.alerts)) {
|
|
143
|
-
overrides.alerts = runtime.alerts
|
|
181
|
+
overrides.alerts = runtime.alerts as AlertThreshold[]
|
|
144
182
|
}
|
|
145
183
|
|
|
146
184
|
return overrides
|
|
@@ -172,8 +210,9 @@ export const monitoringPlugin: Plugin = {
|
|
|
172
210
|
defaultConfig: DEFAULTS,
|
|
173
211
|
|
|
174
212
|
setup: async (context: PluginContext) => {
|
|
175
|
-
const
|
|
176
|
-
const
|
|
213
|
+
const monCtx = context as MonitoringPluginContext
|
|
214
|
+
const runtimeOverrides = normalizeRuntimeMonitoringConfig(monCtx.config?.monitoring as Record<string, unknown> | undefined)
|
|
215
|
+
const pluginOverrides = monCtx.config?.plugins?.config?.monitoring as Partial<MonitoringOptions> | undefined
|
|
177
216
|
const resolvedConfig = mergeMonitoringOptions(
|
|
178
217
|
mergeMonitoringOptions(DEFAULTS, runtimeOverrides),
|
|
179
218
|
pluginOverrides || {}
|
|
@@ -200,9 +239,9 @@ export const monitoringPlugin: Plugin = {
|
|
|
200
239
|
|
|
201
240
|
const metricsCollector = new MetricsCollector()
|
|
202
241
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
242
|
+
monCtx.metricsRegistry = metricsRegistry
|
|
243
|
+
monCtx.metricsCollector = metricsCollector
|
|
244
|
+
monCtx.monitoringConfig = resolvedConfig
|
|
206
245
|
|
|
207
246
|
if (resolvedConfig.httpMetrics) {
|
|
208
247
|
initializeHttpMetrics(metricsRegistry, metricsCollector)
|
|
@@ -233,10 +272,10 @@ export const monitoringPlugin: Plugin = {
|
|
|
233
272
|
})
|
|
234
273
|
|
|
235
274
|
// Record server start metric
|
|
236
|
-
const metricsRegistry = (context as
|
|
275
|
+
const metricsRegistry = (context as MonitoringPluginContext).metricsRegistry
|
|
237
276
|
if (metricsRegistry) {
|
|
238
277
|
recordCounter(metricsRegistry, 'server_starts_total', 1, {
|
|
239
|
-
version: appConfig.version ?? '1.0.0'
|
|
278
|
+
version: (appConfig.version as string) ?? '1.0.0'
|
|
240
279
|
})
|
|
241
280
|
}
|
|
242
281
|
}
|
|
@@ -248,13 +287,14 @@ export const monitoringPlugin: Plugin = {
|
|
|
248
287
|
context.logger.info('Monitoring plugin: Server monitoring stopped')
|
|
249
288
|
|
|
250
289
|
// Record server stop metric
|
|
251
|
-
const
|
|
290
|
+
const monCtx = context as MonitoringPluginContext
|
|
291
|
+
const metricsRegistry = monCtx.metricsRegistry
|
|
252
292
|
if (metricsRegistry) {
|
|
253
293
|
recordCounter(metricsRegistry, 'server_stops_total', 1)
|
|
254
294
|
}
|
|
255
295
|
|
|
256
296
|
// Cleanup intervals
|
|
257
|
-
const intervals =
|
|
297
|
+
const intervals = monCtx.monitoringIntervals
|
|
258
298
|
if (intervals) {
|
|
259
299
|
intervals.forEach(interval => clearInterval(interval))
|
|
260
300
|
}
|
|
@@ -263,13 +303,14 @@ export const monitoringPlugin: Plugin = {
|
|
|
263
303
|
|
|
264
304
|
onRequest: async (requestContext: RequestContext) => {
|
|
265
305
|
const startTime = Date.now()
|
|
266
|
-
|
|
306
|
+
const monReqCtx = requestContext as MonitoringRequestContext
|
|
307
|
+
|
|
267
308
|
// Store start time for duration calculation
|
|
268
|
-
|
|
309
|
+
monReqCtx.monitoringStartTime = startTime
|
|
269
310
|
|
|
270
311
|
// Get metrics registry and collector from context
|
|
271
|
-
const metricsRegistry = getMetricsRegistry(
|
|
272
|
-
const metricsCollector = getMetricsCollector(
|
|
312
|
+
const metricsRegistry = getMetricsRegistry(monReqCtx)
|
|
313
|
+
const metricsCollector = getMetricsCollector(monReqCtx)
|
|
273
314
|
if (!metricsRegistry || !metricsCollector) return
|
|
274
315
|
|
|
275
316
|
// Record request metrics
|
|
@@ -289,17 +330,18 @@ export const monitoringPlugin: Plugin = {
|
|
|
289
330
|
|
|
290
331
|
// Record in collector as well
|
|
291
332
|
const counter = metricsCollector.getAllMetrics().get('http_requests_total')
|
|
292
|
-
if (counter &&
|
|
293
|
-
|
|
333
|
+
if (counter && 'inc' in counter && typeof counter.inc === 'function') {
|
|
334
|
+
counter.inc(1, { method: requestContext.method, path: requestContext.path })
|
|
294
335
|
}
|
|
295
336
|
},
|
|
296
337
|
|
|
297
338
|
onResponse: async (responseContext: ResponseContext) => {
|
|
298
|
-
const
|
|
299
|
-
const
|
|
339
|
+
const monResCtx = responseContext as MonitoringResponseContext
|
|
340
|
+
const metricsRegistry = getMetricsRegistry(monResCtx)
|
|
341
|
+
const metricsCollector = getMetricsCollector(monResCtx)
|
|
300
342
|
if (!metricsRegistry || !metricsCollector) return
|
|
301
343
|
|
|
302
|
-
const startTime =
|
|
344
|
+
const startTime = monResCtx.monitoringStartTime || responseContext.startTime
|
|
303
345
|
const duration = Date.now() - startTime
|
|
304
346
|
|
|
305
347
|
// Record response metrics
|
|
@@ -333,9 +375,9 @@ export const monitoringPlugin: Plugin = {
|
|
|
333
375
|
responseContext.size
|
|
334
376
|
)
|
|
335
377
|
|
|
336
|
-
const options = resolveMonitoringOptions(
|
|
378
|
+
const options = resolveMonitoringOptions(monResCtx)
|
|
337
379
|
if (options.thresholds.responseTime && duration > options.thresholds.responseTime) {
|
|
338
|
-
const logger =
|
|
380
|
+
const logger = monResCtx.logger || console
|
|
339
381
|
logger.warn(`Slow request detected: ${responseContext.method} ${responseContext.path} took ${duration}ms`, {
|
|
340
382
|
method: responseContext.method,
|
|
341
383
|
path: responseContext.path,
|
|
@@ -346,8 +388,9 @@ export const monitoringPlugin: Plugin = {
|
|
|
346
388
|
},
|
|
347
389
|
|
|
348
390
|
onError: async (errorContext: ErrorContext) => {
|
|
349
|
-
const
|
|
350
|
-
const
|
|
391
|
+
const monErrCtx = errorContext as MonitoringErrorContext
|
|
392
|
+
const metricsRegistry = getMetricsRegistry(monErrCtx)
|
|
393
|
+
const metricsCollector = getMetricsCollector(monErrCtx)
|
|
351
394
|
if (!metricsRegistry || !metricsCollector) return
|
|
352
395
|
|
|
353
396
|
// Record error metrics
|
|
@@ -373,9 +416,9 @@ export const monitoringPlugin: Plugin = {
|
|
|
373
416
|
|
|
374
417
|
// Increment error counter in collector
|
|
375
418
|
const errorCounter = metricsCollector.getAllMetrics().get('http_errors_total')
|
|
376
|
-
if (errorCounter &&
|
|
377
|
-
|
|
378
|
-
method: errorContext.method,
|
|
419
|
+
if (errorCounter && 'inc' in errorCounter && typeof errorCounter.inc === 'function') {
|
|
420
|
+
errorCounter.inc(1, {
|
|
421
|
+
method: errorContext.method,
|
|
379
422
|
path: errorContext.path,
|
|
380
423
|
error_type: errorContext.error.name
|
|
381
424
|
})
|
|
@@ -385,14 +428,12 @@ export const monitoringPlugin: Plugin = {
|
|
|
385
428
|
|
|
386
429
|
// Helper functions
|
|
387
430
|
|
|
388
|
-
function getMetricsRegistry(context:
|
|
389
|
-
|
|
390
|
-
return (context as any).metricsRegistry || null
|
|
431
|
+
function getMetricsRegistry(context: { metricsRegistry?: MetricsRegistry }): MetricsRegistry | null {
|
|
432
|
+
return context.metricsRegistry || null
|
|
391
433
|
}
|
|
392
434
|
|
|
393
|
-
function getMetricsCollector(context:
|
|
394
|
-
|
|
395
|
-
return (context as any).metricsCollector || null
|
|
435
|
+
function getMetricsCollector(context: { metricsCollector?: MetricsCollector }): MetricsCollector | null {
|
|
436
|
+
return context.metricsCollector || null
|
|
396
437
|
}
|
|
397
438
|
|
|
398
439
|
function initializeHttpMetrics(registry: MetricsRegistry, collector: MetricsCollector) {
|
|
@@ -435,7 +476,7 @@ function startSystemMetricsCollection(context: PluginContext, collector: Metrics
|
|
|
435
476
|
}
|
|
436
477
|
|
|
437
478
|
const collectSystemMetrics = () => {
|
|
438
|
-
const metricsRegistry = (context as
|
|
479
|
+
const metricsRegistry = (context as MonitoringPluginContext).metricsRegistry
|
|
439
480
|
if (!metricsRegistry) return
|
|
440
481
|
|
|
441
482
|
try {
|
|
@@ -488,22 +529,23 @@ function startSystemMetricsCollection(context: PluginContext, collector: Metrics
|
|
|
488
529
|
|
|
489
530
|
// Collect metrics immediately and then at intervals
|
|
490
531
|
collectSystemMetrics()
|
|
491
|
-
const interval = setInterval(collectSystemMetrics, options.collectInterval)
|
|
532
|
+
const interval = setInterval(collectSystemMetrics, options.collectInterval as number)
|
|
492
533
|
intervals.push(interval)
|
|
493
534
|
|
|
494
535
|
// Store intervals for cleanup
|
|
495
|
-
;(context as
|
|
536
|
+
;(context as MonitoringPluginContext).monitoringIntervals = intervals
|
|
496
537
|
}
|
|
497
538
|
|
|
498
539
|
function setupMetricsEndpoint(context: PluginContext, _registry: MetricsRegistry, collector: MetricsCollector, options: MonitoringOptions) {
|
|
499
|
-
const prometheusExporter = options.exporters.find((e
|
|
540
|
+
const prometheusExporter = options.exporters.find((e) => e.type === 'prometheus' && e.enabled)
|
|
500
541
|
if (!prometheusExporter) return
|
|
501
542
|
|
|
502
543
|
const endpoint = prometheusExporter.endpoint || '/metrics'
|
|
503
544
|
|
|
504
545
|
// Add metrics endpoint to the app
|
|
505
|
-
|
|
506
|
-
|
|
546
|
+
const app = context.app as Record<string, unknown>
|
|
547
|
+
if (app && typeof app.get === 'function') {
|
|
548
|
+
(app.get as Function)(endpoint, () => {
|
|
507
549
|
const prometheusData = collector.exportPrometheus()
|
|
508
550
|
return new Response(prometheusData, {
|
|
509
551
|
headers: {
|
|
@@ -517,7 +559,7 @@ function setupMetricsEndpoint(context: PluginContext, _registry: MetricsRegistry
|
|
|
517
559
|
}
|
|
518
560
|
|
|
519
561
|
function startMetricsExporters(context: PluginContext, registry: MetricsRegistry, collector: MetricsCollector, options: MonitoringOptions) {
|
|
520
|
-
const intervals: NodeJS.Timeout[] = (context as
|
|
562
|
+
const intervals: NodeJS.Timeout[] = (context as MonitoringPluginContext).monitoringIntervals || []
|
|
521
563
|
|
|
522
564
|
for (const exporterConfig of options.exporters) {
|
|
523
565
|
if (!exporterConfig.enabled) continue
|
|
@@ -554,11 +596,11 @@ function startMetricsExporters(context: PluginContext, registry: MetricsRegistry
|
|
|
554
596
|
}
|
|
555
597
|
}
|
|
556
598
|
|
|
557
|
-
;(context as
|
|
599
|
+
;(context as MonitoringPluginContext).monitoringIntervals = intervals
|
|
558
600
|
}
|
|
559
601
|
|
|
560
602
|
function setupAlertMonitoring(context: PluginContext, registry: MetricsRegistry, alerts: AlertThreshold[]) {
|
|
561
|
-
const intervals: NodeJS.Timeout[] = (context as
|
|
603
|
+
const intervals: NodeJS.Timeout[] = (context as MonitoringPluginContext).monitoringIntervals || []
|
|
562
604
|
|
|
563
605
|
const checkAlerts = () => {
|
|
564
606
|
for (const alert of alerts) {
|
|
@@ -606,15 +648,15 @@ function setupAlertMonitoring(context: PluginContext, registry: MetricsRegistry,
|
|
|
606
648
|
const interval = setInterval(checkAlerts, 30000)
|
|
607
649
|
intervals.push(interval)
|
|
608
650
|
|
|
609
|
-
;(context as
|
|
651
|
+
;(context as MonitoringPluginContext).monitoringIntervals = intervals
|
|
610
652
|
}
|
|
611
653
|
|
|
612
654
|
function setupMetricsCleanup(context: PluginContext, registry: MetricsRegistry, options: MonitoringOptions) {
|
|
613
|
-
const intervals: NodeJS.Timeout[] = (context as
|
|
655
|
+
const intervals: NodeJS.Timeout[] = (context as MonitoringPluginContext).monitoringIntervals || []
|
|
614
656
|
|
|
615
657
|
const cleanup = () => {
|
|
616
658
|
const now = Date.now()
|
|
617
|
-
const cutoff = now - (options.retentionPeriod ?? 3600000)
|
|
659
|
+
const cutoff = now - ((options.retentionPeriod as number) ?? 3600000)
|
|
618
660
|
|
|
619
661
|
// Clean up old metrics
|
|
620
662
|
for (const [key, metric] of registry.counters.entries()) {
|
|
@@ -640,7 +682,7 @@ function setupMetricsCleanup(context: PluginContext, registry: MetricsRegistry,
|
|
|
640
682
|
const interval = setInterval(cleanup, 60000)
|
|
641
683
|
intervals.push(interval)
|
|
642
684
|
|
|
643
|
-
;(context as
|
|
685
|
+
;(context as MonitoringPluginContext).monitoringIntervals = intervals
|
|
644
686
|
}
|
|
645
687
|
|
|
646
688
|
// Metrics recording functions
|
|
@@ -774,7 +816,7 @@ function evaluateThreshold(value: number, operator: string, threshold: number):
|
|
|
774
816
|
}
|
|
775
817
|
|
|
776
818
|
// Enhanced Exporters
|
|
777
|
-
function exportToConsole(registry: MetricsRegistry, collector: MetricsCollector, logger:
|
|
819
|
+
function exportToConsole(registry: MetricsRegistry, collector: MetricsCollector, logger: { info: (message: string, meta?: unknown) => void }) {
|
|
778
820
|
const metrics = {
|
|
779
821
|
counters: Array.from(registry.counters.values()),
|
|
780
822
|
gauges: Array.from(registry.gauges.values()),
|
|
@@ -795,7 +837,7 @@ function exportToConsole(registry: MetricsRegistry, collector: MetricsCollector,
|
|
|
795
837
|
})
|
|
796
838
|
}
|
|
797
839
|
|
|
798
|
-
function exportToPrometheus(_registry: MetricsRegistry, collector: MetricsCollector, config:
|
|
840
|
+
function exportToPrometheus(_registry: MetricsRegistry, collector: MetricsCollector, config: MetricsExporter, logger: { debug: (message: string, meta?: unknown) => void; error: (message: string, meta?: unknown) => void }) {
|
|
799
841
|
const prometheusData = collector.exportPrometheus()
|
|
800
842
|
|
|
801
843
|
if (config.endpoint && config.endpoint !== '/metrics') {
|
|
@@ -814,7 +856,7 @@ function exportToPrometheus(_registry: MetricsRegistry, collector: MetricsCollec
|
|
|
814
856
|
}
|
|
815
857
|
}
|
|
816
858
|
|
|
817
|
-
function exportToJson(registry: MetricsRegistry, collector: MetricsCollector, config:
|
|
859
|
+
function exportToJson(registry: MetricsRegistry, collector: MetricsCollector, config: MetricsExporter, logger: { info: (message: string, meta?: unknown) => void; error: (message: string, meta?: unknown) => void }) {
|
|
818
860
|
const data = {
|
|
819
861
|
timestamp: new Date().toISOString(),
|
|
820
862
|
system: collector.getSystemMetrics(),
|
|
@@ -840,7 +882,7 @@ function exportToJson(registry: MetricsRegistry, collector: MetricsCollector, co
|
|
|
840
882
|
}
|
|
841
883
|
}
|
|
842
884
|
|
|
843
|
-
function exportToFile(registry: MetricsRegistry, collector: MetricsCollector, config:
|
|
885
|
+
function exportToFile(registry: MetricsRegistry, collector: MetricsCollector, config: MetricsExporter, logger: { debug: (message: string, meta?: unknown) => void; warn: (message: string, meta?: unknown) => void; error: (message: string, meta?: unknown) => void }) {
|
|
844
886
|
if (!config.filePath) {
|
|
845
887
|
logger.warn('File exporter configured but no filePath specified')
|
|
846
888
|
return
|
|
@@ -30,7 +30,7 @@ export const staticPlugin: Plugin = {
|
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
// Static fallback handler (runs last)
|
|
33
|
-
const staticFallback = (c:
|
|
33
|
+
const staticFallback = (c: { request: Request }) => {
|
|
34
34
|
const req = c.request
|
|
35
35
|
if (!req) return
|
|
36
36
|
|
|
@@ -87,7 +87,7 @@ export const staticPlugin: Plugin = {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// Register as catch-all fallback (runs after all other routes)
|
|
90
|
-
context.app.all('*', staticFallback)
|
|
90
|
+
;(context.app as Record<string, Function>).all('*', staticFallback)
|
|
91
91
|
},
|
|
92
92
|
|
|
93
93
|
onServerStart: async (context: PluginContext) => {
|
|
@@ -33,7 +33,7 @@ export const swaggerPlugin: Plugin = {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Build servers list
|
|
36
|
-
const servers = parseServers(pluginsConfig.swaggerServers ?? '')
|
|
36
|
+
const servers = parseServers((pluginsConfig.swaggerServers as string) ?? '')
|
|
37
37
|
if (servers.length === 0) {
|
|
38
38
|
servers.push({
|
|
39
39
|
url: `http://${serverConfig.server.host}:${serverConfig.server.port}`,
|
|
@@ -43,16 +43,16 @@ export const swaggerPlugin: Plugin = {
|
|
|
43
43
|
|
|
44
44
|
// Swagger configuration
|
|
45
45
|
const config = {
|
|
46
|
-
path: pluginsConfig.swaggerPath ?? '/swagger',
|
|
46
|
+
path: (pluginsConfig.swaggerPath as string) ?? '/swagger',
|
|
47
47
|
documentation: {
|
|
48
48
|
info: {
|
|
49
|
-
title: pluginsConfig.swaggerTitle ?? appConfig.name ?? 'FluxStack API',
|
|
50
|
-
version: pluginsConfig.swaggerVersion ?? appConfig.version ?? '1.0.0',
|
|
51
|
-
description: pluginsConfig.swaggerDescription ?? 'API documentation'
|
|
49
|
+
title: (pluginsConfig.swaggerTitle as string) ?? (appConfig.name as string) ?? 'FluxStack API',
|
|
50
|
+
version: (pluginsConfig.swaggerVersion as string) ?? (appConfig.version as string) ?? '1.0.0',
|
|
51
|
+
description: (pluginsConfig.swaggerDescription as string) ?? 'API documentation'
|
|
52
52
|
},
|
|
53
53
|
servers
|
|
54
54
|
},
|
|
55
|
-
exclude: pluginsConfig.swaggerExcludePaths ?? [],
|
|
55
|
+
exclude: (pluginsConfig.swaggerExcludePaths as string[]) ?? [],
|
|
56
56
|
swaggerOptions: {
|
|
57
57
|
persistAuthorization: pluginsConfig.swaggerPersistAuthorization,
|
|
58
58
|
displayRequestDuration: pluginsConfig.swaggerDisplayRequestDuration,
|
|
@@ -64,8 +64,8 @@ export const swaggerPlugin: Plugin = {
|
|
|
64
64
|
|
|
65
65
|
// Add Basic Auth if enabled
|
|
66
66
|
if (pluginsConfig.swaggerAuthEnabled && pluginsConfig.swaggerAuthPassword) {
|
|
67
|
-
context.app.onBeforeHandle({ as: 'global' }, ({ request, set, path }: { request: Request; set:
|
|
68
|
-
if (!path.startsWith(pluginsConfig.swaggerPath ?? '/swagger')) return
|
|
67
|
+
;(context.app as Record<string, Function>).onBeforeHandle({ as: 'global' }, ({ request, set, path }: { request: Request; set: { status?: number; headers: Record<string, string> }; path: string }) => {
|
|
68
|
+
if (!path.startsWith((pluginsConfig.swaggerPath as string) ?? '/swagger')) return
|
|
69
69
|
|
|
70
70
|
const authHeader = request.headers.get('authorization')
|
|
71
71
|
if (!authHeader?.startsWith('Basic ')) {
|
|
@@ -89,7 +89,7 @@ export const swaggerPlugin: Plugin = {
|
|
|
89
89
|
context.logger.debug(`Swagger auth enabled (user: ${pluginsConfig.swaggerAuthUsername})`)
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
context.app.use(swagger(config))
|
|
92
|
+
;(context.app as Record<string, Function>).use(swagger(config))
|
|
93
93
|
context.logger.debug(`Swagger enabled at ${pluginsConfig.swaggerPath}`)
|
|
94
94
|
},
|
|
95
95
|
|
|
@@ -53,7 +53,7 @@ function createStaticFallback() {
|
|
|
53
53
|
// Discover base directory once
|
|
54
54
|
const baseDir = existsSync('client') ? 'client'
|
|
55
55
|
: existsSync('dist/client') ? 'dist/client'
|
|
56
|
-
: clientConfig.build.outDir ?? 'dist/client'
|
|
56
|
+
: (clientConfig.build.outDir as string) ?? 'dist/client'
|
|
57
57
|
|
|
58
58
|
// Pre-scan all files at startup — O(1) lookup per request
|
|
59
59
|
const fileMap = collectFiles(baseDir)
|
|
@@ -227,7 +227,7 @@ export const vitePlugin: Plugin = {
|
|
|
227
227
|
|
|
228
228
|
if (!IS_DEV) {
|
|
229
229
|
context.logger.debug("Production mode: static file serving enabled")
|
|
230
|
-
context.app.all('*', createStaticFallback())
|
|
230
|
+
;(context.app as Record<string, Function>).all('*', createStaticFallback())
|
|
231
231
|
return
|
|
232
232
|
}
|
|
233
233
|
|
|
@@ -249,7 +249,7 @@ export const vitePlugin: Plugin = {
|
|
|
249
249
|
onBeforeRoute: async (ctx: RequestContext) => {
|
|
250
250
|
if (!IS_DEV) return
|
|
251
251
|
|
|
252
|
-
const shouldSkip = (pluginsConfig.viteExcludePaths ?? []).some(prefix =>
|
|
252
|
+
const shouldSkip = ((pluginsConfig.viteExcludePaths ?? []) as string[]).some((prefix: string) =>
|
|
253
253
|
ctx.path === prefix || ctx.path.startsWith(prefix + '/')
|
|
254
254
|
)
|
|
255
255
|
|
|
@@ -13,8 +13,8 @@ let viteServer: ViteDevServer | null = null
|
|
|
13
13
|
* This file is only imported in development mode
|
|
14
14
|
*/
|
|
15
15
|
export async function setupViteDev(context: PluginContext): Promise<void> {
|
|
16
|
-
const vitePort = clientConfig.vite.port || 5173
|
|
17
|
-
const viteHost = clientConfig.vite.host || "localhost"
|
|
16
|
+
const vitePort = (clientConfig.vite.port as number) || 5173
|
|
17
|
+
const viteHost = (clientConfig.vite.host as string) || "localhost"
|
|
18
18
|
const logLevel = clientConfig.vite.logLevel as LogLevel
|
|
19
19
|
// Import group logger utilities
|
|
20
20
|
const { endGroup } = await import('@core/utils/logger/group-logger')
|
|
@@ -39,7 +39,7 @@ export async function setupViteDev(context: PluginContext): Promise<void> {
|
|
|
39
39
|
context.logger.debug('Hot reload coordination active')
|
|
40
40
|
|
|
41
41
|
// Store Vite config in context for later use
|
|
42
|
-
;(context as
|
|
42
|
+
;(context as PluginContext & { viteConfig?: { port: number; host: string; server: typeof viteServer } }).viteConfig = {
|
|
43
43
|
port: vitePort,
|
|
44
44
|
host: viteHost,
|
|
45
45
|
server: viteServer
|