create-fluxstack 1.5.5 → 1.7.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.
Files changed (60) hide show
  1. package/README.md +172 -215
  2. package/app/client/src/App.tsx +45 -19
  3. package/app/client/src/components/FluxStackConfig.tsx +1 -1
  4. package/app/client/src/components/HybridLiveCounter.tsx +1 -1
  5. package/app/client/src/components/LiveClock.tsx +1 -1
  6. package/app/client/src/components/MainLayout.tsx +0 -2
  7. package/app/client/src/components/SidebarNavigation.tsx +1 -1
  8. package/app/client/src/components/SystemMonitor.tsx +16 -10
  9. package/app/client/src/components/UserProfile.tsx +1 -1
  10. package/app/server/live/FluxStackConfig.ts +2 -1
  11. package/app/server/live/LiveClockComponent.ts +8 -7
  12. package/app/server/live/SidebarNavigation.ts +2 -1
  13. package/app/server/live/SystemMonitor.ts +1 -0
  14. package/app/server/live/UserProfileComponent.ts +36 -30
  15. package/config/server.config.ts +1 -0
  16. package/core/cli/command-registry.ts +10 -10
  17. package/core/cli/commands/plugin-deps.ts +13 -5
  18. package/core/cli/plugin-discovery.ts +1 -1
  19. package/core/client/LiveComponentsProvider.tsx +414 -0
  20. package/core/client/hooks/useHybridLiveComponent.ts +194 -530
  21. package/core/client/index.ts +16 -0
  22. package/core/framework/server.ts +144 -63
  23. package/core/index.ts +4 -1
  24. package/core/plugins/built-in/monitoring/index.ts +1 -1
  25. package/core/plugins/built-in/static/index.ts +1 -1
  26. package/core/plugins/built-in/swagger/index.ts +1 -1
  27. package/core/plugins/built-in/vite/index.ts +1 -1
  28. package/core/plugins/config.ts +1 -1
  29. package/core/plugins/discovery.ts +1 -1
  30. package/core/plugins/executor.ts +1 -1
  31. package/core/plugins/index.ts +1 -0
  32. package/core/server/live/ComponentRegistry.ts +3 -1
  33. package/core/server/live/WebSocketConnectionManager.ts +14 -4
  34. package/core/server/live/websocket-plugin.ts +453 -434
  35. package/core/server/middleware/elysia-helpers.ts +3 -5
  36. package/core/server/plugins/database.ts +1 -1
  37. package/core/server/plugins/static-files-plugin.ts +1 -1
  38. package/core/types/index.ts +1 -1
  39. package/core/types/plugin.ts +1 -1
  40. package/core/types/types.ts +6 -2
  41. package/core/utils/logger/colors.ts +4 -4
  42. package/core/utils/logger/index.ts +37 -4
  43. package/core/utils/logger/winston-logger.ts +1 -1
  44. package/core/utils/sync-version.ts +61 -0
  45. package/core/utils/version.ts +6 -5
  46. package/package.json +5 -3
  47. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +1 -1
  48. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  49. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +1 -1
  50. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +1 -1
  51. package/vite.config.ts +8 -0
  52. package/.dockerignore +0 -50
  53. package/CRYPTO-AUTH-MIDDLEWARE-GUIDE.md +0 -475
  54. package/CRYPTO-AUTH-MIDDLEWARES.md +0 -473
  55. package/CRYPTO-AUTH-USAGE.md +0 -491
  56. package/EXEMPLO-ROTA-PROTEGIDA.md +0 -347
  57. package/QUICK-START-CRYPTO-AUTH.md +0 -221
  58. package/app/client/src/components/Teste.tsx +0 -104
  59. package/app/server/live/TesteComponent.ts +0 -87
  60. package/test-crypto-auth.ts +0 -101
@@ -1,5 +1,21 @@
1
1
  // 🔥 FluxStack Client Core - Main Export
2
2
 
3
+ // Live Components Provider (Singleton WebSocket Connection)
4
+ export {
5
+ LiveComponentsProvider,
6
+ useLiveComponents,
7
+ // Deprecated exports for backward compatibility
8
+ WebSocketProvider,
9
+ useWebSocketContext
10
+ } from './LiveComponentsProvider'
11
+ export type {
12
+ LiveComponentsProviderProps,
13
+ LiveComponentsContextValue,
14
+ // Deprecated types for backward compatibility
15
+ WebSocketProviderProps,
16
+ WebSocketContextValue
17
+ } from './LiveComponentsProvider'
18
+
3
19
  // Hooks
4
20
  export { useWebSocket } from './hooks/useWebSocket'
5
21
  export { useHybridLiveComponent } from './hooks/useHybridLiveComponent'
@@ -1,6 +1,6 @@
1
1
  import { Elysia } from "elysia"
2
2
  import type { FluxStackConfig, FluxStackContext } from "../types"
3
- import type { Plugin, PluginContext, PluginUtils } from "../plugins/types"
3
+ import type { FluxStack, PluginContext, PluginUtils } from "../plugins/types"
4
4
  import { PluginRegistry } from "../plugins/registry"
5
5
  import { PluginManager } from "../plugins/manager"
6
6
  import { getConfigSync, getEnvironmentInfo } from "../config"
@@ -16,6 +16,7 @@ export class FluxStackFramework {
16
16
  private pluginManager: PluginManager
17
17
  private pluginContext: PluginContext
18
18
  private isStarted: boolean = false
19
+ private requestTimings: Map<string, number> = new Map()
19
20
 
20
21
  constructor(config?: Partial<FluxStackConfig>) {
21
22
  // Load the full configuration
@@ -32,7 +33,7 @@ export class FluxStackFramework {
32
33
 
33
34
  this.app = new Elysia()
34
35
  this.pluginRegistry = new PluginRegistry()
35
-
36
+
36
37
 
37
38
 
38
39
  // Create plugin utilities
@@ -68,22 +69,33 @@ export class FluxStackFramework {
68
69
  }
69
70
  }
70
71
 
71
- // Create a logger wrapper that implements the full Logger interface
72
- const pluginLogger = {
73
- debug: (message: string, meta?: any) => logger.debug(message, meta),
74
- info: (message: string, meta?: any) => logger.info(message, meta),
75
- warn: (message: string, meta?: any) => logger.warn(message, meta),
76
- error: (message: string, meta?: any) => logger.error(message, meta),
77
- child: (context: any) => (logger as any).child ? (logger as any).child(context) : logger,
78
- time: (label: string) => (logger as any).time(label),
79
- timeEnd: (label: string) => (logger as any).timeEnd(label),
72
+ // Create plugin-compatible logger interface
73
+ interface PluginLogger {
74
+ debug: (message: string, meta?: unknown) => void
75
+ info: (message: string, meta?: unknown) => void
76
+ warn: (message: string, meta?: unknown) => void
77
+ error: (message: string, meta?: unknown) => void
78
+ child: (context: Record<string, unknown>) => PluginLogger
79
+ time: (label: string) => void
80
+ timeEnd: (label: string) => void
81
+ request: (method: string, path: string, status?: number, duration?: number) => void
82
+ }
83
+
84
+ const pluginLogger: PluginLogger = {
85
+ debug: (message: string, meta?: unknown) => logger.debug(message, meta),
86
+ info: (message: string, meta?: unknown) => logger.info(message, meta),
87
+ warn: (message: string, meta?: unknown) => logger.warn(message, meta),
88
+ error: (message: string, meta?: unknown) => logger.error(message, meta),
89
+ child: (context: Record<string, unknown>) => pluginLogger,
90
+ time: (label: string) => logger.time(label),
91
+ timeEnd: (label: string) => logger.timeEnd(label),
80
92
  request: (method: string, path: string, status?: number, duration?: number) =>
81
93
  logger.request(method, path, status, duration)
82
94
  }
83
95
 
84
96
  this.pluginContext = {
85
97
  config: fullConfig,
86
- logger: pluginLogger,
98
+ logger: pluginLogger as any,
87
99
  app: this.app,
88
100
  utils: pluginUtils
89
101
  }
@@ -97,6 +109,7 @@ export class FluxStackFramework {
97
109
 
98
110
  this.setupCors()
99
111
  this.setupHeadHandler()
112
+ this.setupElysiaHeadBugFilter()
100
113
  this.setupHooks()
101
114
  this.setupErrorHandling()
102
115
 
@@ -104,7 +117,7 @@ export class FluxStackFramework {
104
117
  environment: envInfo.name,
105
118
  port: fullConfig.server.port
106
119
  })
107
-
120
+
108
121
  // Initialize automatic plugin discovery in background
109
122
  this.initializeAutomaticPlugins().catch(error => {
110
123
  logger.error('Failed to initialize automatic plugins', { error })
@@ -147,7 +160,7 @@ export class FluxStackFramework {
147
160
  // Global HEAD handler to prevent Elysia's automatic HEAD conversion bug
148
161
  this.app.head("*", ({ request, set }) => {
149
162
  const url = new URL(request.url)
150
-
163
+
151
164
  // Handle API routes
152
165
  if (url.pathname.startsWith(this.context.config.server.apiPrefix)) {
153
166
  set.status = 200
@@ -155,7 +168,7 @@ export class FluxStackFramework {
155
168
  set.headers['Content-Length'] = '0'
156
169
  return ""
157
170
  }
158
-
171
+
159
172
  // Handle static files (assume they're HTML if no extension)
160
173
  const isStatic = url.pathname === '/' || !url.pathname.includes('.')
161
174
  if (isStatic) {
@@ -165,7 +178,7 @@ export class FluxStackFramework {
165
178
  set.headers['Cache-Control'] = 'no-cache'
166
179
  return ""
167
180
  }
168
-
181
+
169
182
  // Handle other file types
170
183
  set.status = 200
171
184
  set.headers['Content-Type'] = 'application/octet-stream'
@@ -174,12 +187,61 @@ export class FluxStackFramework {
174
187
  })
175
188
  }
176
189
 
190
+ private setupElysiaHeadBugFilter() {
191
+ // Only filter in development mode to avoid affecting production logs
192
+ if (process.env.NODE_ENV !== 'development') {
193
+ return
194
+ }
195
+
196
+ // Store original stderr.write to restore if needed
197
+ const originalStderrWrite = process.stderr.write
198
+
199
+ // Override stderr.write to filter Elysia HEAD bug errors
200
+ process.stderr.write = function (
201
+ chunk: string | Uint8Array,
202
+ encoding?: BufferEncoding | ((error?: Error) => void),
203
+ callback?: (error?: Error) => void
204
+ ): boolean {
205
+ const str = chunk.toString()
206
+
207
+ // Filter out known Elysia HEAD bug error patterns
208
+ if (str.includes("TypeError: undefined is not an object (evaluating '_res.headers.set')") ||
209
+ str.includes("HEAD - / failed") ||
210
+ (str.includes("HEAD - ") && str.includes(" failed"))) {
211
+ // Silently ignore these specific errors
212
+ if (typeof encoding === 'function') {
213
+ encoding() // encoding is actually the callback
214
+ } else if (callback) {
215
+ callback()
216
+ }
217
+ return true
218
+ }
219
+
220
+ // Pass through all other stderr output
221
+ if (typeof encoding === 'function') {
222
+ return originalStderrWrite.call(process.stderr, chunk, encoding)
223
+ } else {
224
+ return originalStderrWrite.call(process.stderr, chunk, encoding, callback)
225
+ }
226
+ }
227
+
228
+ // Store reference to restore original behavior if needed
229
+ ; (this as any)._originalStderrWrite = originalStderrWrite
230
+ }
231
+
177
232
  private setupHooks() {
178
233
  // Setup onRequest hook and onBeforeRoute hook
179
234
  this.app.onRequest(async ({ request, set }) => {
180
235
  const startTime = Date.now()
181
236
  const url = new URL(request.url)
182
-
237
+
238
+ // Store start time for duration calculation (using request URL as key)
239
+ const requestKey = `${request.method}-${url.pathname}-${startTime}`
240
+ this.requestTimings.set(requestKey, startTime)
241
+
242
+ // Store key in set.headers for retrieval in onAfterHandle
243
+ set.headers['x-request-timing-key'] = requestKey
244
+
183
245
  const requestContext = {
184
246
  request,
185
247
  path: url.pathname,
@@ -197,24 +259,33 @@ export class FluxStackFramework {
197
259
  handled: false,
198
260
  response: undefined
199
261
  }
200
-
262
+
201
263
  // Execute onRequest hooks for all plugins first (logging, auth, etc.)
202
264
  await this.executePluginHooks('onRequest', requestContext)
203
-
265
+
204
266
  // Execute onBeforeRoute hooks - allow plugins to handle requests before routing
205
267
  const handledResponse = await this.executePluginBeforeRouteHooks(requestContext)
206
-
268
+
207
269
  // If a plugin handled the request, return the response
208
270
  if (handledResponse) {
209
271
  return handledResponse
210
272
  }
211
273
  })
212
274
 
213
- // Setup onResponse hook
275
+ // Setup onResponse hook
214
276
  this.app.onAfterHandle(async ({ request, response, set }) => {
215
- const startTime = Date.now()
216
277
  const url = new URL(request.url)
217
-
278
+
279
+ // Retrieve start time using the timing key
280
+ const requestKey = set.headers['x-request-timing-key']
281
+ const startTime = requestKey ? this.requestTimings.get(String(requestKey)) : undefined
282
+ const duration = startTime ? Date.now() - startTime : 0
283
+
284
+ // Clean up timing entry
285
+ if (requestKey) {
286
+ this.requestTimings.delete(String(requestKey))
287
+ }
288
+
218
289
  const responseContext = {
219
290
  request,
220
291
  path: url.pathname,
@@ -229,11 +300,21 @@ export class FluxStackFramework {
229
300
  query: Object.fromEntries(url.searchParams.entries()),
230
301
  params: {},
231
302
  response,
232
- statusCode: (response as any)?.status || set.status || 200,
233
- duration: Date.now() - startTime,
303
+ statusCode: Number((response as any)?.status || set.status || 200),
304
+ duration,
234
305
  startTime
235
306
  }
236
-
307
+
308
+ // Log the request automatically (if not disabled in config)
309
+ if (this.context.config.server.enableRequestLogging !== false) {
310
+ // Ensure status is always a number (HTTP status code)
311
+ const status = typeof responseContext.statusCode === 'number'
312
+ ? responseContext.statusCode
313
+ : Number(set.status) || 200
314
+
315
+ logger.request(request.method, url.pathname, status, duration)
316
+ }
317
+
237
318
  // Execute onResponse hooks for all plugins
238
319
  await this.executePluginHooks('onResponse', responseContext)
239
320
  })
@@ -248,7 +329,7 @@ export class FluxStackFramework {
248
329
  this.app.onError(async ({ error, request, path, set }) => {
249
330
  const startTime = Date.now()
250
331
  const url = new URL(request.url)
251
-
332
+
252
333
  const errorContext = {
253
334
  request,
254
335
  path: url.pathname,
@@ -267,17 +348,17 @@ export class FluxStackFramework {
267
348
  handled: false,
268
349
  startTime
269
350
  }
270
-
351
+
271
352
  // Execute onError hooks for all plugins - allow them to handle the error
272
353
  const handledResponse = await this.executePluginErrorHooks(errorContext)
273
-
354
+
274
355
  // If a plugin handled the error, return the response
275
356
  if (handledResponse) {
276
357
  return handledResponse
277
358
  }
278
-
359
+
279
360
  // Vite proxy logic is now handled by the Vite plugin via onBeforeRoute hook
280
-
361
+
281
362
  // Convert Elysia error to standard Error if needed
282
363
  const standardError = error instanceof Error ? error : new Error(String(error))
283
364
  return errorHandler(standardError, request, path)
@@ -286,18 +367,18 @@ export class FluxStackFramework {
286
367
 
287
368
  private async executePluginHooks(hookName: string, context: any): Promise<void> {
288
369
  const loadOrder = this.pluginRegistry.getLoadOrder()
289
-
370
+
290
371
  for (const pluginName of loadOrder) {
291
372
  const plugin = this.pluginRegistry.get(pluginName)
292
373
  if (!plugin) continue
293
-
374
+
294
375
  const hookFn = (plugin as any)[hookName]
295
376
  if (typeof hookFn === 'function') {
296
377
  try {
297
378
  await hookFn(context)
298
379
  } catch (error) {
299
- logger.error(`Plugin '${pluginName}' ${hookName} hook failed`, {
300
- error: (error as Error).message
380
+ logger.error(`Plugin '${pluginName}' ${hookName} hook failed`, {
381
+ error: (error as Error).message
301
382
  })
302
383
  }
303
384
  }
@@ -306,86 +387,86 @@ export class FluxStackFramework {
306
387
 
307
388
  private async executePluginBeforeRouteHooks(requestContext: any): Promise<Response | null> {
308
389
  const loadOrder = this.pluginRegistry.getLoadOrder()
309
-
390
+
310
391
  for (const pluginName of loadOrder) {
311
392
  const plugin = this.pluginRegistry.get(pluginName)
312
393
  if (!plugin) continue
313
-
394
+
314
395
  const onBeforeRouteFn = (plugin as any).onBeforeRoute
315
396
  if (typeof onBeforeRouteFn === 'function') {
316
397
  try {
317
398
  await onBeforeRouteFn(requestContext)
318
-
399
+
319
400
  // If this plugin handled the request, return the response
320
401
  if (requestContext.handled && requestContext.response) {
321
402
  return requestContext.response
322
403
  }
323
404
  } catch (error) {
324
- logger.error(`Plugin '${pluginName}' onBeforeRoute hook failed`, {
325
- error: (error as Error).message
405
+ logger.error(`Plugin '${pluginName}' onBeforeRoute hook failed`, {
406
+ error: (error as Error).message
326
407
  })
327
408
  }
328
409
  }
329
410
  }
330
-
411
+
331
412
  return null
332
413
  }
333
414
 
334
415
  private async executePluginErrorHooks(errorContext: any): Promise<Response | null> {
335
416
  const loadOrder = this.pluginRegistry.getLoadOrder()
336
-
417
+
337
418
  for (const pluginName of loadOrder) {
338
419
  const plugin = this.pluginRegistry.get(pluginName)
339
420
  if (!plugin) continue
340
-
421
+
341
422
  const onErrorFn = (plugin as any).onError
342
423
  if (typeof onErrorFn === 'function') {
343
424
  try {
344
425
  await onErrorFn(errorContext)
345
-
426
+
346
427
  // If this plugin handled the error, check if it provides a response
347
428
  if (errorContext.handled) {
348
429
  // For Vite plugin, we'll handle the proxy here
349
430
  if (pluginName === 'vite' && errorContext.error.constructor.name === 'NotFoundError') {
350
431
  return await this.handleViteProxy(errorContext)
351
432
  }
352
-
433
+
353
434
  // For other plugins, return a basic success response
354
435
  return new Response('OK', { status: 200 })
355
436
  }
356
437
  } catch (error) {
357
- logger.error(`Plugin '${pluginName}' onError hook failed`, {
358
- error: (error as Error).message
438
+ logger.error(`Plugin '${pluginName}' onError hook failed`, {
439
+ error: (error as Error).message
359
440
  })
360
441
  }
361
442
  }
362
443
  }
363
-
444
+
364
445
  return null
365
446
  }
366
447
 
367
448
  private async handleViteProxy(errorContext: any): Promise<Response> {
368
449
  const vitePort = this.context.config.client?.port || 5173
369
450
  const url = new URL(errorContext.request.url)
370
-
451
+
371
452
  try {
372
453
  const viteUrl = `http://localhost:${vitePort}${url.pathname}${url.search}`
373
-
454
+
374
455
  // Forward request to Vite
375
456
  const response = await fetch(viteUrl, {
376
457
  method: errorContext.method,
377
458
  headers: errorContext.headers
378
459
  })
379
-
460
+
380
461
  // Return a proper Response object with all headers and status
381
462
  const body = await response.arrayBuffer()
382
-
463
+
383
464
  return new Response(body, {
384
465
  status: response.status,
385
466
  statusText: response.statusText,
386
467
  headers: response.headers
387
468
  })
388
-
469
+
389
470
  } catch (viteError) {
390
471
  // If Vite fails, return error response
391
472
  return new Response(`Vite server not ready on port ${vitePort}. Error: ${viteError}`, {
@@ -401,16 +482,16 @@ export class FluxStackFramework {
401
482
  if (this.pluginRegistry.has(plugin.name)) {
402
483
  throw new Error(`Plugin '${plugin.name}' is already registered`)
403
484
  }
404
-
485
+
405
486
  // Store plugin without calling setup - setup will be called in start()
406
487
  // We need to manually set the plugin since register() is async but we need sync
407
488
  (this.pluginRegistry as any).plugins.set(plugin.name, plugin)
408
-
489
+
409
490
  // Update dependencies tracking
410
- if (plugin.dependencies) {
411
- (this.pluginRegistry as any).dependencies.set(plugin.name, plugin.dependencies)
491
+ if ((plugin as FluxStack.Plugin).dependencies) {
492
+ (this.pluginRegistry as any).dependencies.set(plugin.name, (plugin as FluxStack.Plugin).dependencies)
412
493
  }
413
-
494
+
414
495
  // Update load order by calling the private method
415
496
  try {
416
497
  (this.pluginRegistry as any).updateLoadOrder()
@@ -418,12 +499,12 @@ export class FluxStackFramework {
418
499
  // Fallback: create basic load order
419
500
  const plugins = (this.pluginRegistry as any).plugins as Map<string, Plugin>
420
501
  const loadOrder = Array.from(plugins.keys())
421
- ;(this.pluginRegistry as any).loadOrder = loadOrder
502
+ ; (this.pluginRegistry as any).loadOrder = loadOrder
422
503
  }
423
-
504
+
424
505
  logger.debug(`Plugin '${plugin.name}' registered`, {
425
- version: plugin.version,
426
- dependencies: plugin.dependencies
506
+ version: (plugin as FluxStack.Plugin).version,
507
+ dependencies: (plugin as FluxStack.Plugin).dependencies
427
508
  })
428
509
  return this
429
510
  } catch (error) {
@@ -445,7 +526,7 @@ export class FluxStackFramework {
445
526
 
446
527
  try {
447
528
  // Validate plugin dependencies before starting
448
- const plugins = (this.pluginRegistry as any).plugins as Map<string, Plugin>
529
+ const plugins = (this.pluginRegistry as any).plugins as Map<string, FluxStack.Plugin>
449
530
  for (const [pluginName, plugin] of plugins) {
450
531
  if (plugin.dependencies) {
451
532
  for (const depName of plugin.dependencies) {
package/core/index.ts CHANGED
@@ -8,6 +8,7 @@ export * from './server/services/index.js'
8
8
  export * from './server/middleware/index.js'
9
9
 
10
10
  // Client exports
11
+ export * from './client/index.js'
11
12
  export * from './client/state/index.js'
12
13
  export * from './client/hooks/index.js'
13
14
 
@@ -22,4 +23,6 @@ export * from './framework/server.js'
22
23
  export * from './framework/client.js'
23
24
  export * from './plugins/index.js'
24
25
  export * from './utils/logger/index.js'
25
- export * from './utils/errors/index.js'
26
+ export * from './utils/errors/index.js'// Ve
27
+ rsion exports
28
+ export { FLUXSTACK_VERSION, getVersion, getVersionInfo } from './utils/version.js'
@@ -3,7 +3,7 @@
3
3
  * Provides performance monitoring, metrics collection, and system monitoring
4
4
  */
5
5
 
6
- import type { Plugin, PluginContext, RequestContext, ResponseContext, ErrorContext } from "../../types"
6
+ import type { FluxStack, PluginContext, RequestContext, ResponseContext, ErrorContext } from "../../types"
7
7
  import { MetricsCollector } from "../../../utils/monitoring"
8
8
  import * as os from 'os'
9
9
  import * as fs from 'fs'
@@ -1,6 +1,6 @@
1
1
  import { join, extname } from "path"
2
2
  import { existsSync, statSync } from "fs"
3
- import type { Plugin, PluginContext } from "../../types"
3
+ import type { FluxStack, PluginContext } from "../../types"
4
4
 
5
5
  export const staticPlugin: Plugin = {
6
6
  name: "static",
@@ -1,5 +1,5 @@
1
1
  import { swagger } from '@elysiajs/swagger'
2
- import type { Plugin, PluginContext } from '../../types'
2
+ import type { FluxStack, PluginContext } from '../../types'
3
3
 
4
4
  export const swaggerPlugin: Plugin = {
5
5
  name: 'swagger',
@@ -1,4 +1,4 @@
1
- import type { Plugin, PluginContext, RequestContext } from "../../types"
1
+ import type { FluxStack, PluginContext, RequestContext } from "../../types"
2
2
  import { createServer, type ViteDevServer } from 'vite'
3
3
 
4
4
  let viteServer: ViteDevServer | null = null
@@ -3,7 +3,7 @@
3
3
  * Handles plugin-specific configuration validation and management
4
4
  */
5
5
 
6
- import type { Plugin, PluginConfigSchema, PluginValidationResult } from "./types"
6
+ import type { FluxStack, PluginConfigSchema, PluginValidationResult } from "./types"
7
7
  import type { FluxStackConfig } from "../config/schema"
8
8
  import type { Logger } from "../utils/logger/index"
9
9
 
@@ -3,7 +3,7 @@
3
3
  * Handles automatic discovery and loading of plugins from various sources
4
4
  */
5
5
 
6
- import type { Plugin, PluginManifest, PluginLoadResult, PluginDiscoveryOptions } from "./types"
6
+ import type { FluxStack, PluginManifest, PluginLoadResult, PluginDiscoveryOptions } from "./types"
7
7
  import type { Logger } from "../utils/logger/index"
8
8
  import { readdir, readFile } from "fs/promises"
9
9
  import { join, resolve } from "path"
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import type {
7
- Plugin,
7
+ FluxStack,
8
8
  PluginHook,
9
9
  PluginHookResult,
10
10
  PluginPriority,
@@ -27,6 +27,7 @@ export type {
27
27
  BuildContext
28
28
  } from './types'
29
29
 
30
+ export type { FluxStack }
30
31
  export type Plugin = FluxStack.Plugin
31
32
 
32
33
  // Plugin registry
@@ -794,12 +794,14 @@ export class ComponentRegistry {
794
794
  }
795
795
 
796
796
  // Update component activity
797
- updateComponentActivity(componentId: string): void {
797
+ updateComponentActivity(componentId: string): boolean {
798
798
  const metadata = this.metadata.get(componentId)
799
799
  if (metadata) {
800
800
  metadata.lastActivity = new Date()
801
801
  metadata.state = 'active'
802
+ return true
802
803
  }
804
+ return false
803
805
  }
804
806
 
805
807
  // Record component metrics
@@ -134,7 +134,17 @@ export class WebSocketConnectionManager extends EventEmitter {
134
134
  if (!metrics) return
135
135
 
136
136
  // Handle incoming messages
137
- ws.on('message', (data: any) => {
137
+ const addListener = (event: string, handler: (...args: any[]) => void) => {
138
+ if (typeof ws.on === 'function') {
139
+ ws.on(event, handler)
140
+ } else if (typeof ws.addEventListener === 'function') {
141
+ ws.addEventListener(event as any, handler as any)
142
+ } else if (typeof ws.addListener === 'function') {
143
+ ws.addListener(event, handler)
144
+ }
145
+ }
146
+
147
+ addListener('message', (data: any) => {
138
148
  metrics.messagesReceived++
139
149
  metrics.lastActivity = new Date()
140
150
  metrics.bytesTransferred += Buffer.byteLength(data)
@@ -143,20 +153,20 @@ export class WebSocketConnectionManager extends EventEmitter {
143
153
  })
144
154
 
145
155
  // Handle connection close
146
- ws.on('close', () => {
156
+ addListener('close', () => {
147
157
  metrics.status = 'disconnected'
148
158
  this.handleConnectionClose(connectionId)
149
159
  })
150
160
 
151
161
  // Handle connection errors
152
- ws.on('error', (error: Error) => {
162
+ addListener('error', (error: Error) => {
153
163
  metrics.errorCount++
154
164
  metrics.status = 'error'
155
165
  this.handleConnectionError(connectionId, error)
156
166
  })
157
167
 
158
168
  // Handle pong responses for latency measurement
159
- ws.on('pong', () => {
169
+ addListener('pong', () => {
160
170
  const now = Date.now()
161
171
  const pingTime = (ws as any)._pingTime
162
172
  if (pingTime) {