create-fluxstack 1.15.0 → 1.17.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 (142) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/LLMD/INDEX.md +4 -3
  3. package/LLMD/resources/live-binary-delta.md +507 -0
  4. package/LLMD/resources/live-components.md +1 -0
  5. package/LLMD/resources/live-rooms.md +731 -333
  6. package/app/client/src/App.tsx +23 -14
  7. package/app/client/src/components/AppLayout.tsx +4 -4
  8. package/app/client/src/live/AuthDemo.tsx +4 -4
  9. package/app/client/src/live/PingPongDemo.tsx +199 -0
  10. package/app/client/src/live/RoomChatDemo.tsx +187 -22
  11. package/app/client/src/live/SharedCounterDemo.tsx +142 -0
  12. package/app/server/live/LivePingPong.ts +61 -0
  13. package/app/server/live/LiveRoomChat.ts +106 -38
  14. package/app/server/live/LiveSharedCounter.ts +73 -0
  15. package/app/server/live/rooms/ChatRoom.ts +68 -0
  16. package/app/server/live/rooms/CounterRoom.ts +51 -0
  17. package/app/server/live/rooms/DirectoryRoom.ts +42 -0
  18. package/app/server/live/rooms/PingRoom.ts +40 -0
  19. package/core/build/bundler.ts +40 -26
  20. package/core/build/flux-plugins-generator.ts +325 -325
  21. package/core/build/index.ts +92 -21
  22. package/core/cli/command-registry.ts +44 -46
  23. package/core/cli/commands/build.ts +11 -6
  24. package/core/cli/commands/create.ts +7 -5
  25. package/core/cli/commands/dev.ts +6 -5
  26. package/core/cli/commands/help.ts +3 -2
  27. package/core/cli/commands/make-plugin.ts +8 -7
  28. package/core/cli/commands/plugin-add.ts +60 -43
  29. package/core/cli/commands/plugin-deps.ts +73 -57
  30. package/core/cli/commands/plugin-list.ts +44 -41
  31. package/core/cli/commands/plugin-remove.ts +33 -22
  32. package/core/cli/generators/component.ts +770 -769
  33. package/core/cli/generators/controller.ts +9 -8
  34. package/core/cli/generators/index.ts +148 -146
  35. package/core/cli/generators/interactive.ts +228 -227
  36. package/core/cli/generators/plugin.ts +11 -10
  37. package/core/cli/generators/prompts.ts +83 -82
  38. package/core/cli/generators/route.ts +7 -6
  39. package/core/cli/generators/service.ts +10 -9
  40. package/core/cli/generators/template-engine.ts +2 -1
  41. package/core/cli/generators/types.ts +7 -7
  42. package/core/cli/generators/utils.ts +191 -191
  43. package/core/cli/index.ts +9 -8
  44. package/core/cli/plugin-discovery.ts +2 -2
  45. package/core/client/hooks/useAuth.ts +48 -48
  46. package/core/client/index.ts +0 -16
  47. package/core/client/standalone.ts +18 -17
  48. package/core/client/state/createStore.ts +192 -192
  49. package/core/client/state/index.ts +14 -14
  50. package/core/config/index.ts +1 -0
  51. package/core/framework/client.ts +131 -131
  52. package/core/framework/index.ts +7 -7
  53. package/core/framework/server.ts +72 -112
  54. package/core/framework/types.ts +2 -2
  55. package/core/plugins/built-in/live-components/commands/create-live-component.ts +6 -3
  56. package/core/plugins/built-in/monitoring/index.ts +110 -68
  57. package/core/plugins/built-in/static/index.ts +2 -2
  58. package/core/plugins/built-in/swagger/index.ts +9 -9
  59. package/core/plugins/built-in/vite/index.ts +3 -3
  60. package/core/plugins/built-in/vite/vite-dev.ts +3 -3
  61. package/core/plugins/config.ts +50 -47
  62. package/core/plugins/discovery.ts +10 -4
  63. package/core/plugins/executor.ts +2 -2
  64. package/core/plugins/index.ts +206 -203
  65. package/core/plugins/manager.ts +21 -20
  66. package/core/plugins/registry.ts +76 -12
  67. package/core/plugins/types.ts +14 -14
  68. package/core/server/framework.ts +3 -189
  69. package/core/server/live/auto-generated-components.ts +11 -35
  70. package/core/server/live/index.ts +41 -36
  71. package/core/server/live/websocket-plugin.ts +48 -3
  72. package/core/server/middleware/elysia-helpers.ts +16 -15
  73. package/core/server/middleware/errorHandling.ts +14 -14
  74. package/core/server/middleware/index.ts +31 -31
  75. package/core/server/plugins/database.ts +181 -180
  76. package/core/server/plugins/static-files-plugin.ts +4 -3
  77. package/core/server/plugins/swagger.ts +11 -8
  78. package/core/server/rooms/RoomBroadcaster.ts +11 -10
  79. package/core/server/rooms/RoomSystem.ts +14 -11
  80. package/core/server/services/BaseService.ts +7 -7
  81. package/core/server/services/ServiceContainer.ts +5 -5
  82. package/core/server/services/index.ts +8 -8
  83. package/core/templates/create-project.ts +28 -27
  84. package/core/testing/index.ts +9 -9
  85. package/core/testing/setup.ts +73 -73
  86. package/core/types/api.ts +168 -168
  87. package/core/types/config.ts +5 -5
  88. package/core/types/index.ts +1 -1
  89. package/core/types/plugin.ts +2 -2
  90. package/core/types/types.ts +3 -3
  91. package/core/utils/build-logger.ts +324 -324
  92. package/core/utils/config-schema.ts +480 -480
  93. package/core/utils/env.ts +10 -8
  94. package/core/utils/errors/codes.ts +114 -114
  95. package/core/utils/errors/handlers.ts +30 -20
  96. package/core/utils/errors/index.ts +54 -46
  97. package/core/utils/errors/middleware.ts +113 -113
  98. package/core/utils/helpers.ts +19 -16
  99. package/core/utils/logger/colors.ts +114 -114
  100. package/core/utils/logger/config.ts +2 -2
  101. package/core/utils/logger/formatter.ts +82 -82
  102. package/core/utils/logger/group-logger.ts +101 -101
  103. package/core/utils/logger/index.ts +13 -3
  104. package/core/utils/logger/startup-banner.ts +2 -2
  105. package/core/utils/logger/winston-logger.ts +152 -152
  106. package/core/utils/monitoring/index.ts +211 -211
  107. package/core/utils/sync-version.ts +67 -66
  108. package/core/utils/version.ts +1 -1
  109. package/package.json +11 -6
  110. package/playwright-report/index.html +85 -0
  111. package/playwright.config.ts +31 -0
  112. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  113. package/plugins/crypto-auth/client/components/index.ts +11 -11
  114. package/plugins/crypto-auth/client/index.ts +11 -11
  115. package/plugins/crypto-auth/package.json +65 -65
  116. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  117. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +6 -5
  118. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +6 -5
  119. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +3 -3
  120. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  121. package/plugins/crypto-auth/server/middlewares.ts +19 -19
  122. package/tsconfig.json +4 -1
  123. package/vite.config.ts +13 -0
  124. package/app/client/.live-stubs/LiveAdminPanel.js +0 -5
  125. package/app/client/.live-stubs/LiveChat.js +0 -7
  126. package/app/client/.live-stubs/LiveCounter.js +0 -9
  127. package/app/client/.live-stubs/LiveForm.js +0 -11
  128. package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
  129. package/app/client/.live-stubs/LiveRoomChat.js +0 -10
  130. package/app/client/.live-stubs/LiveTodoList.js +0 -9
  131. package/app/client/.live-stubs/LiveUpload.js +0 -15
  132. package/app/client/src/live/ChatDemo.tsx +0 -107
  133. package/app/client/src/live/LiveDebuggerPanel.tsx +0 -779
  134. package/app/client/src/live/TodoListDemo.tsx +0 -158
  135. package/app/server/live/LiveChat.ts +0 -78
  136. package/app/server/live/LiveTodoList.ts +0 -110
  137. package/app/server/live/register-components.ts +0 -19
  138. package/core/build/live-components-generator.ts +0 -312
  139. package/core/client/components/LiveDebugger.tsx +0 -1324
  140. package/core/live/ComponentRegistry.ts +0 -403
  141. package/core/live/types.ts +0 -241
  142. package/workspace.json +0 -6
@@ -1,6 +1,20 @@
1
- import type { FluxStack, PluginManifest, PluginLoadResult, PluginDiscoveryOptions } from "./types"
1
+ import type { FluxStack, PluginManifest, PluginLoadResult, PluginDiscoveryOptions, PluginPriority } from "./types"
2
2
 
3
3
  type FluxStackPlugin = FluxStack.Plugin
4
+
5
+ const PRIORITY_MAP: Record<string, number> = {
6
+ highest: 1000,
7
+ high: 750,
8
+ normal: 500,
9
+ low: 250,
10
+ lowest: 0
11
+ }
12
+
13
+ function normalizePriority(priority?: number | PluginPriority): number {
14
+ if (typeof priority === 'number') return priority
15
+ if (typeof priority === 'string' && priority in PRIORITY_MAP) return PRIORITY_MAP[priority]
16
+ return 500 // default to normal
17
+ }
4
18
  import type { FluxStackConfig } from "@config"
5
19
  import type { Logger } from "@core/utils/logger"
6
20
  import { FluxStackError } from "@core/utils/errors"
@@ -223,6 +237,56 @@ export class PluginRegistry {
223
237
  return this.plugins.has(name)
224
238
  }
225
239
 
240
+ /**
241
+ * Register a plugin synchronously (no async hooks).
242
+ *
243
+ * Used by the framework to add plugins via .use() and during automatic
244
+ * plugin discovery, where the full async register() flow (which fires
245
+ * onPluginRegister hooks) is not needed — setup hooks run later in start().
246
+ */
247
+ registerSync(plugin: FluxStackPlugin): void {
248
+ if (this.plugins.has(plugin.name)) {
249
+ throw new FluxStackError(
250
+ `Plugin '${plugin.name}' is already registered`,
251
+ 'PLUGIN_ALREADY_REGISTERED',
252
+ 400
253
+ )
254
+ }
255
+
256
+ this.validatePlugin(plugin)
257
+ this.plugins.set(plugin.name, plugin)
258
+
259
+ if (plugin.dependencies) {
260
+ this.dependencies.set(plugin.name, plugin.dependencies)
261
+ }
262
+
263
+ this.updateLoadOrder()
264
+ }
265
+
266
+ /**
267
+ * Refresh the load order.
268
+ *
269
+ * Falls back to insertion-order if the topological sort fails
270
+ * (e.g. unresolvable external dependency listed but not yet registered).
271
+ */
272
+ refreshLoadOrder(): void {
273
+ try {
274
+ this.updateLoadOrder()
275
+ } catch {
276
+ this.loadOrder = Array.from(this.plugins.keys())
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Return a read-only snapshot of the internal plugin map.
282
+ *
283
+ * Allows the framework to iterate over registered plugins for dependency
284
+ * validation without reaching into private fields.
285
+ */
286
+ getPluginsMap(): ReadonlyMap<string, FluxStackPlugin> {
287
+ return this.plugins
288
+ }
289
+
226
290
  /**
227
291
  * Check which dependencies are missing from main package.json
228
292
  */
@@ -278,12 +342,12 @@ export class PluginRegistry {
278
342
  return true
279
343
  }
280
344
 
281
- if (allowedPlugins.length === 0) {
345
+ if ((allowedPlugins as string[]).length === 0) {
282
346
  this.logger?.warn(`NPM plugin '${pluginName}' blocked: No plugins in whitelist (PLUGINS_ALLOWED is empty)`)
283
347
  return false
284
348
  }
285
349
 
286
- if (!allowedPlugins.includes(pluginName)) {
350
+ if (!(allowedPlugins as string[]).includes(pluginName)) {
287
351
  this.logger?.warn(`NPM plugin '${pluginName}' blocked: Not in whitelist (PLUGINS_ALLOWED)`, {
288
352
  pluginName,
289
353
  allowedPlugins
@@ -299,8 +363,8 @@ export class PluginRegistry {
299
363
  getStats() {
300
364
  return {
301
365
  totalPlugins: this.plugins.size,
302
- enabledPlugins: this.config?.plugins.enabled?.length ?? 0,
303
- disabledPlugins: this.config?.plugins.disabled?.length ?? 0,
366
+ enabledPlugins: (this.config?.plugins.enabled as string[] | undefined)?.length ?? 0,
367
+ disabledPlugins: (this.config?.plugins.disabled as string[] | undefined)?.length ?? 0,
304
368
  conflicts: this.conflicts.length,
305
369
  loadOrder: this.loadOrder.length
306
370
  }
@@ -644,9 +708,11 @@ export class PluginRegistry {
644
708
  )
645
709
  }
646
710
 
647
- if (plugin.priority && typeof plugin.priority !== 'number') {
711
+ if (plugin.priority !== undefined
712
+ && typeof plugin.priority !== 'number'
713
+ && !(typeof plugin.priority === 'string' && plugin.priority in PRIORITY_MAP)) {
648
714
  throw new FluxStackError(
649
- 'Plugin priority must be a number',
715
+ `Plugin priority must be a number or one of: ${Object.keys(PRIORITY_MAP).join(', ')}`,
650
716
  'INVALID_PLUGIN_STRUCTURE',
651
717
  400
652
718
  )
@@ -656,7 +722,7 @@ export class PluginRegistry {
656
722
  /**
657
723
  * Validate plugin configuration against schema
658
724
  */
659
- private validatePluginConfig(plugin: FluxStackPlugin, config: any): void {
725
+ private validatePluginConfig(plugin: FluxStackPlugin, config: unknown): void {
660
726
  if (!plugin.configSchema) {
661
727
  return
662
728
  }
@@ -664,7 +730,7 @@ export class PluginRegistry {
664
730
  // Basic validation - in a real implementation, you'd use a proper JSON schema validator
665
731
  if (plugin.configSchema.required) {
666
732
  for (const requiredField of plugin.configSchema.required) {
667
- if (!(requiredField in config)) {
733
+ if (!(requiredField in (config as Record<string, unknown>))) {
668
734
  throw new FluxStackError(
669
735
  `Plugin '${plugin.name}' configuration missing required field: ${requiredField}`,
670
736
  'INVALID_PLUGIN_CONFIG',
@@ -741,9 +807,7 @@ export class PluginRegistry {
741
807
  ready.sort((a, b) => {
742
808
  const pluginA = this.plugins.get(a)
743
809
  const pluginB = this.plugins.get(b)
744
- const priorityA = typeof pluginA?.priority === 'number' ? pluginA.priority : 0
745
- const priorityB = typeof pluginB?.priority === 'number' ? pluginB.priority : 0
746
- return priorityB - priorityA
810
+ return normalizePriority(pluginB?.priority) - normalizePriority(pluginA?.priority)
747
811
  })
748
812
 
749
813
  for (const name of ready) {
@@ -36,9 +36,9 @@ export type PluginPriority = 'highest' | 'high' | 'normal' | 'low' | 'lowest' |
36
36
  export interface PluginContext {
37
37
  config: FluxStackConfig
38
38
  logger: Logger
39
- app: any // Elysia app
39
+ app: unknown // Elysia app
40
40
  utils: PluginUtils
41
- registry?: any // Plugin registry reference
41
+ registry?: unknown // Plugin registry reference
42
42
  }
43
43
 
44
44
  export interface PluginUtils {
@@ -49,8 +49,8 @@ export interface PluginUtils {
49
49
  isDevelopment: () => boolean
50
50
  getEnvironment: () => string
51
51
  createHash: (data: string) => string
52
- deepMerge: (target: any, source: any) => any
53
- validateSchema: (data: any, schema: any) => { valid: boolean; errors: string[] }
52
+ deepMerge: (target: Record<string, unknown>, source: Record<string, unknown>) => Record<string, unknown>
53
+ validateSchema: (data: Record<string, unknown>, schema: PluginConfigSchema) => { valid: boolean; errors: string[] }
54
54
  }
55
55
 
56
56
  export interface RequestContext {
@@ -60,8 +60,8 @@ export interface RequestContext {
60
60
  headers: Record<string, string>
61
61
  query: Record<string, string>
62
62
  params: Record<string, string>
63
- body?: any
64
- user?: any
63
+ body?: unknown
64
+ user?: unknown
65
65
  startTime: number
66
66
  handled?: boolean
67
67
  response?: Response
@@ -127,12 +127,12 @@ export interface PluginEventContext {
127
127
  pluginName: string
128
128
  pluginVersion?: string
129
129
  timestamp: number
130
- data?: any
130
+ data?: unknown
131
131
  }
132
132
 
133
133
  export interface PluginConfigSchema {
134
134
  type: 'object'
135
- properties: Record<string, any>
135
+ properties: Record<string, unknown>
136
136
  required?: string[]
137
137
  additionalProperties?: boolean
138
138
  }
@@ -203,7 +203,7 @@ export namespace FluxStack {
203
203
  * This property will be removed in a future major version.
204
204
  * Use the config/ folder structure for automatic type inference.
205
205
  */
206
- defaultConfig?: any
206
+ defaultConfig?: unknown
207
207
 
208
208
  // CLI commands
209
209
  commands?: CliCommand[]
@@ -252,7 +252,7 @@ export interface PluginHookResult {
252
252
  duration: number
253
253
  plugin: string
254
254
  hook: PluginHook
255
- context?: any
255
+ context?: unknown
256
256
  }
257
257
 
258
258
  export interface PluginMetrics {
@@ -319,7 +319,7 @@ export interface CliArgument {
319
319
  description: string
320
320
  required?: boolean
321
321
  type?: 'string' | 'number' | 'boolean'
322
- default?: any
322
+ default?: unknown
323
323
  choices?: string[]
324
324
  }
325
325
 
@@ -328,7 +328,7 @@ export interface CliOption {
328
328
  short?: string
329
329
  description: string
330
330
  type?: 'string' | 'number' | 'boolean' | 'array'
331
- default?: any
331
+ default?: unknown
332
332
  required?: boolean
333
333
  choices?: string[]
334
334
  }
@@ -343,7 +343,7 @@ export interface CliCommand {
343
343
  aliases?: string[]
344
344
  category?: string
345
345
  hidden?: boolean
346
- handler: (args: any[], options: any, context: CliContext) => Promise<void> | void
346
+ handler: (args: unknown[], options: Record<string, unknown>, context: CliContext) => Promise<void> | void
347
347
  }
348
348
 
349
349
  export interface CliContext {
@@ -369,7 +369,7 @@ export interface ActiveUpload {
369
369
  fileType?: string
370
370
  fileSize?: number
371
371
  totalChunks: number
372
- receivedChunks: Map<number, any>
372
+ receivedChunks: Map<number, unknown>
373
373
  startTime: number
374
374
  lastChunkTime?: number
375
375
  }
@@ -1,189 +1,3 @@
1
- import { Elysia } from "elysia"
2
- import { createHash as nodeCreateHash } from "crypto"
3
- import type { FluxStackConfig, FluxStackContext, Plugin } from "../types"
4
- import type { PluginContext, PluginUtils } from "../plugins/types"
5
- import { PluginManager } from "../plugins/manager"
6
- import { fluxStackConfig } from "@config"
7
- import { getEnvironmentInfo } from "../config"
8
- import { logger, type Logger } from "../utils/logger/index"
9
- import { createTimer, formatBytes, isProduction, isDevelopment } from "../utils/helpers"
10
-
11
- export class FluxStackFramework {
12
- private app: Elysia
13
- private context: FluxStackContext
14
- private pluginContext: PluginContext
15
- private plugins: Plugin[] = []
16
- private pluginManager: PluginManager
17
- private initialized = false
18
-
19
- constructor(config?: Partial<FluxStackConfig>) {
20
- // Load the full configuration
21
- const fullConfig = config ? { ...fluxStackConfig, ...config } : fluxStackConfig
22
- const envInfo = getEnvironmentInfo()
23
-
24
- this.context = {
25
- config: fullConfig,
26
- isDevelopment: envInfo.isDevelopment,
27
- isProduction: envInfo.isProduction,
28
- isTest: envInfo.isTest,
29
- environment: envInfo.name
30
- }
31
-
32
- this.app = new Elysia()
33
-
34
- // Create plugin utilities
35
- const pluginUtils: PluginUtils = {
36
- createTimer,
37
- formatBytes,
38
- isProduction,
39
- isDevelopment,
40
- getEnvironment: () => envInfo.name,
41
- createHash: (data: string) => nodeCreateHash('sha256').update(data).digest('hex'),
42
- deepMerge: (target: any, source: any) => {
43
- const result = { ...target }
44
- for (const key in source) {
45
- if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
46
- result[key] = pluginUtils.deepMerge(result[key] || {}, source[key])
47
- } else {
48
- result[key] = source[key]
49
- }
50
- }
51
- return result
52
- },
53
- validateSchema: (_data: any, _schema: any) => {
54
- // Simple validation - in a real implementation you'd use a proper schema validator
55
- try {
56
- // Basic validation logic
57
- return { valid: true, errors: [] }
58
- } catch (error) {
59
- return { valid: false, errors: [error instanceof Error ? error.message : 'Validation failed'] }
60
- }
61
- }
62
- }
63
-
64
- // Create plugin context
65
- this.pluginContext = {
66
- config: fullConfig,
67
- logger: logger as any,
68
- app: this.app,
69
- utils: pluginUtils
70
- }
71
-
72
- // Initialize plugin manager
73
- this.pluginManager = new PluginManager({
74
- config: fullConfig,
75
- logger: logger as any,
76
- app: this.app
77
- })
78
-
79
- this.setupCors()
80
- }
81
-
82
- private setupCors() {
83
- const cors = this.context.config.cors
84
-
85
- const allowedOrigins = cors.origins.length > 0 ? cors.origins : ['*']
86
- const allowAllMethods = cors.methods.length > 0 ? cors.methods.join(", ") : "GET,POST,PUT,DELETE,OPTIONS"
87
- const allowAllHeaders = cors.headers.length > 0 ? cors.headers.join(", ") : "Content-Type, Authorization"
88
-
89
- const resolveOrigin = (requestOrigin?: string | null) => {
90
- const origin = requestOrigin || allowedOrigins[0] || "*"
91
- if (allowedOrigins.includes("*")) {
92
- return cors.credentials ? origin : "*"
93
- }
94
- return allowedOrigins.includes(origin) ? origin : allowedOrigins[0] || origin
95
- }
96
-
97
- this.app
98
- .onRequest(({ request, set }) => {
99
- const origin = resolveOrigin(request.headers.get("origin"))
100
- set.headers["Access-Control-Allow-Origin"] = origin
101
- set.headers["Access-Control-Allow-Methods"] = allowAllMethods
102
- set.headers["Access-Control-Allow-Headers"] = allowAllHeaders
103
- set.headers["Vary"] = "Origin"
104
- if (cors.credentials) {
105
- set.headers["Access-Control-Allow-Credentials"] = "true"
106
- }
107
- if (cors.maxAge) {
108
- set.headers["Access-Control-Max-Age"] = cors.maxAge.toString()
109
- }
110
- })
111
- .options("*", ({ request, set }) => {
112
- set.status = 204
113
- const origin = resolveOrigin(request.headers.get("origin"))
114
- set.headers["Access-Control-Allow-Origin"] = origin
115
- set.headers["Access-Control-Allow-Methods"] = allowAllMethods
116
- set.headers["Access-Control-Allow-Headers"] = allowAllHeaders
117
- set.headers["Vary"] = "Origin"
118
- if (cors.credentials) {
119
- set.headers["Access-Control-Allow-Credentials"] = "true"
120
- }
121
- if (cors.maxAge) {
122
- set.headers["Access-Control-Max-Age"] = cors.maxAge.toString()
123
- }
124
- return ""
125
- })
126
- }
127
-
128
- use(plugin: Plugin) {
129
- this.plugins.push(plugin)
130
- if (plugin.setup) {
131
- plugin.setup(this.pluginContext)
132
- }
133
- return this
134
- }
135
-
136
- routes(routeModule: any) {
137
- this.app.use(routeModule)
138
- return this
139
- }
140
-
141
- getApp() {
142
- return this.app
143
- }
144
-
145
- getContext() {
146
- return this.context
147
- }
148
-
149
- async listen(callback?: () => void) {
150
- // Initialize plugins synchronously before starting server
151
- if (!this.initialized) {
152
- logger.debug('[FluxStack] Initializing automatic plugin discovery...')
153
-
154
- try {
155
- await this.pluginManager.initialize()
156
- const stats = this.pluginManager.getRegistry().getStats()
157
-
158
- logger.info('[FluxStack] Automatic plugins loaded successfully', {
159
- pluginCount: stats.totalPlugins,
160
- enabledPlugins: stats.enabledPlugins,
161
- disabledPlugins: stats.disabledPlugins
162
- })
163
-
164
- this.initialized = true
165
- } catch (error) {
166
- logger.error('[FluxStack] Failed to initialize automatic plugins', { error })
167
- throw error
168
- }
169
- }
170
-
171
- const port = this.context.config.server.port
172
- const apiPrefix = this.context.config.server.apiPrefix
173
-
174
- this.app.listen(port, () => {
175
- logger.info('[FluxStack] Server started on port ' + port, {
176
- apiPrefix,
177
- environment: this.context.environment,
178
- manualPlugins: this.plugins.length,
179
- automaticPlugins: this.pluginManager.getRegistry().getStats().totalPlugins
180
- })
181
- console.log(`🚀 API ready at http://localhost:${port}${apiPrefix}`)
182
- console.log(`📋 Health check: http://localhost:${port}${apiPrefix}/health`)
183
- console.log()
184
- callback?.()
185
- })
186
-
187
- return this
188
- }
189
- }
1
+ // Re-export from canonical location to maintain backwards compatibility
2
+ // The single source of truth is core/framework/server.ts
3
+ export { FluxStackFramework } from "../framework/server"
@@ -1,50 +1,26 @@
1
- // 🔥 Auto-generated Live Components Registration
2
- // This file is automatically generated during build time - DO NOT EDIT MANUALLY
3
- // Generated at: 2026-03-01T19:00:29.650Z
1
+ // Auto-generated Live Components Registration
2
+ // Generated by @fluxstack/live DO NOT EDIT MANUALLY
3
+ // Generated at: 2026-03-21T23:18:32.007Z
4
4
 
5
5
  import { LiveAdminPanel } from "@app/server/live/LiveAdminPanel"
6
- import { LiveChat } from "@app/server/live/LiveChat"
7
6
  import { LiveCounter } from "@app/server/live/LiveCounter"
8
7
  import { LiveForm } from "@app/server/live/LiveForm"
9
8
  import { LiveLocalCounter } from "@app/server/live/LiveLocalCounter"
9
+ import { LivePingPong } from "@app/server/live/LivePingPong"
10
10
  import { LiveProtectedChat } from "@app/server/live/LiveProtectedChat"
11
11
  import { LiveRoomChat } from "@app/server/live/LiveRoomChat"
12
- import { LiveTodoList } from "@app/server/live/LiveTodoList"
12
+ import { LiveSharedCounter } from "@app/server/live/LiveSharedCounter"
13
13
  import { LiveUpload } from "@app/server/live/LiveUpload"
14
- import { componentRegistry } from "@core/server/live"
15
14
 
16
- // Register all components statically for production bundle
17
- function registerAllComponents() {
18
- try {
19
- // Auto-generated component registrations
20
- componentRegistry.registerComponentClass('LiveAdminPanel', LiveAdminPanel)
21
- componentRegistry.registerComponentClass('LiveChat', LiveChat)
22
- componentRegistry.registerComponentClass('LiveCounter', LiveCounter)
23
- componentRegistry.registerComponentClass('LiveForm', LiveForm)
24
- componentRegistry.registerComponentClass('LiveLocalCounter', LiveLocalCounter)
25
- componentRegistry.registerComponentClass('LiveProtectedChat', LiveProtectedChat)
26
- componentRegistry.registerComponentClass('LiveRoomChat', LiveRoomChat)
27
- componentRegistry.registerComponentClass('LiveTodoList', LiveTodoList)
28
- componentRegistry.registerComponentClass('LiveUpload', LiveUpload)
29
-
30
- console.log('📝 Live components registered successfully! (9 components)')
31
- } catch (error) {
32
- console.warn('⚠️ Error registering components:', error)
33
- }
34
- }
35
-
36
- // Auto-register components
37
- registerAllComponents()
38
-
39
- // Export all components to ensure they're included in the bundle
40
- export {
15
+ // Component classes array for LiveServer({ components }) option
16
+ export const liveComponentClasses = [
41
17
  LiveAdminPanel,
42
- LiveChat,
43
18
  LiveCounter,
44
19
  LiveForm,
45
20
  LiveLocalCounter,
21
+ LivePingPong,
46
22
  LiveProtectedChat,
47
23
  LiveRoomChat,
48
- LiveTodoList,
49
- LiveUpload
50
- }
24
+ LiveSharedCounter,
25
+ LiveUpload,
26
+ ]
@@ -36,6 +36,25 @@ export type {
36
36
  // These lazily access the LiveServer instance created by the plugin
37
37
  import { liveServer, pendingAuthProviders } from './websocket-plugin'
38
38
  import type { LiveAuthProvider as _LiveAuthProvider } from '@fluxstack/live'
39
+ import type { ComponentRegistry as _ComponentRegistry } from '@fluxstack/live'
40
+ import type { WebSocketConnectionManager as _WebSocketConnectionManager } from '@fluxstack/live'
41
+ import type { RoomStateManager as _RoomStateManager } from '@fluxstack/live'
42
+ import type { LiveRoomManager as _LiveRoomManager } from '@fluxstack/live'
43
+ import type { RoomEventBus as _RoomEventBus } from '@fluxstack/live'
44
+ import type { FileUploadManager as _FileUploadManager } from '@fluxstack/live'
45
+ import type { PerformanceMonitor as _PerformanceMonitor } from '@fluxstack/live'
46
+ import type { StateSignatureManager as _StateSignatureManager } from '@fluxstack/live'
47
+ import type { LiveAuthManager as _LiveAuthManager } from '@fluxstack/live'
48
+
49
+ function requireLiveServer() {
50
+ if (!liveServer) {
51
+ throw new Error(
52
+ 'LiveComponents plugin not initialized. ' +
53
+ 'Ensure the live-components plugin is loaded before accessing Live singletons.'
54
+ )
55
+ }
56
+ return liveServer
57
+ }
39
58
 
40
59
  /**
41
60
  * Backward-compatible liveAuthManager.
@@ -43,7 +62,7 @@ import type { LiveAuthProvider as _LiveAuthProvider } from '@fluxstack/live'
43
62
  * then delegates to liveServer.authManager once available.
44
63
  * @deprecated Access via liveServer.authManager instead
45
64
  */
46
- export const liveAuthManager = {
65
+ export const liveAuthManager: Pick<_LiveAuthManager, 'authenticate' | 'hasProviders' | 'authorizeRoom' | 'authorizeAction' | 'authorizeComponent'> & { register: (provider: _LiveAuthProvider) => void } = {
47
66
  register(provider: _LiveAuthProvider) {
48
67
  if (liveServer) {
49
68
  liveServer.useAuth(provider)
@@ -51,54 +70,40 @@ export const liveAuthManager = {
51
70
  pendingAuthProviders.push(provider)
52
71
  }
53
72
  },
54
- get authenticate() { return liveServer!.authManager.authenticate.bind(liveServer!.authManager) },
55
- get hasProviders() { return liveServer!.authManager.hasProviders.bind(liveServer!.authManager) },
56
- get authorizeRoom() { return liveServer!.authManager.authorizeRoom.bind(liveServer!.authManager) },
57
- get authorizeAction() { return liveServer!.authManager.authorizeAction.bind(liveServer!.authManager) },
58
- get authorizeComponent() { return liveServer!.authManager.authorizeComponent.bind(liveServer!.authManager) },
59
- } as any
73
+ get authenticate() { return requireLiveServer().authManager.authenticate.bind(requireLiveServer().authManager) },
74
+ get hasProviders() { return requireLiveServer().authManager.hasProviders.bind(requireLiveServer().authManager) },
75
+ get authorizeRoom() { return requireLiveServer().authManager.authorizeRoom.bind(requireLiveServer().authManager) },
76
+ get authorizeAction() { return requireLiveServer().authManager.authorizeAction.bind(requireLiveServer().authManager) },
77
+ get authorizeComponent() { return requireLiveServer().authManager.authorizeComponent.bind(requireLiveServer().authManager) },
78
+ }
79
+
80
+ /** Helper to create a typed lazy proxy that delegates to a LiveServer property */
81
+ function createLazyProxy<T extends object>(accessor: () => T): T {
82
+ return new Proxy({} as T, {
83
+ get(_, prop) { return (accessor() as Record<string | symbol, unknown>)[prop] }
84
+ })
85
+ }
60
86
 
61
87
  /** @deprecated Access via liveServer.registry instead */
62
- export const componentRegistry = new Proxy({} as any, {
63
- get(_, prop) { return (liveServer!.registry as any)[prop] }
64
- })
88
+ export const componentRegistry = createLazyProxy<_ComponentRegistry>(() => requireLiveServer().registry)
65
89
 
66
90
  /** @deprecated Access via liveServer.connectionManager instead */
67
- export const connectionManager = new Proxy({} as any, {
68
- get(_, prop) { return (liveServer!.connectionManager as any)[prop] }
69
- })
91
+ export const connectionManager = createLazyProxy<_WebSocketConnectionManager>(() => requireLiveServer().connectionManager)
70
92
 
71
93
  /** @deprecated Access via liveServer.roomManager instead */
72
- export const liveRoomManager = new Proxy({} as any, {
73
- get(_, prop) { return (liveServer!.roomManager as any)[prop] }
74
- })
94
+ export const liveRoomManager = createLazyProxy<_LiveRoomManager>(() => requireLiveServer().roomManager)
75
95
 
76
96
  /** @deprecated Access via liveServer.roomEvents instead */
77
- export const roomEvents = new Proxy({} as any, {
78
- get(_, prop) { return (liveServer!.roomEvents as any)[prop] }
79
- })
97
+ export const roomEvents = createLazyProxy<_RoomEventBus>(() => requireLiveServer().roomEvents)
80
98
 
81
99
  /** @deprecated Access via liveServer.fileUploadManager instead */
82
- export const fileUploadManager = new Proxy({} as any, {
83
- get(_, prop) { return (liveServer!.fileUploadManager as any)[prop] }
84
- })
100
+ export const fileUploadManager = createLazyProxy<_FileUploadManager>(() => requireLiveServer().fileUploadManager)
85
101
 
86
102
  /** @deprecated Access via liveServer.performanceMonitor instead */
87
- export const performanceMonitor = new Proxy({} as any, {
88
- get(_, prop) { return (liveServer!.performanceMonitor as any)[prop] }
89
- })
103
+ export const performanceMonitor = createLazyProxy<_PerformanceMonitor>(() => requireLiveServer().performanceMonitor)
90
104
 
91
105
  /** @deprecated Access via liveServer.stateSignature instead */
92
- export const stateSignature = new Proxy({} as any, {
93
- get(_, prop) { return (liveServer!.stateSignature as any)[prop] }
94
- })
95
-
96
- /** @deprecated Access via liveServer.debugger instead */
97
- export const liveDebugger = new Proxy({} as any, {
98
- get(_, prop) { return (liveServer!.debugger as any)[prop] }
99
- })
106
+ export const stateSignature = createLazyProxy<_StateSignatureManager>(() => requireLiveServer().stateSignature)
100
107
 
101
108
  // Room state backward compat
102
- export const roomState = new Proxy({} as any, {
103
- get(_, prop) { return (liveServer!.roomManager as any)[prop] }
104
- })
109
+ export const roomState = createLazyProxy<_LiveRoomManager>(() => requireLiveServer().roomManager)