create-fluxstack 1.0.0 → 1.0.2

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 (101) hide show
  1. package/create-fluxstack.ts +32 -17
  2. package/package-template.json +51 -0
  3. package/package.json +2 -1
  4. package/.env +0 -30
  5. package/LICENSE +0 -21
  6. package/app/client/README.md +0 -69
  7. package/app/client/frontend-only.ts +0 -12
  8. package/app/client/index.html +0 -13
  9. package/app/client/public/vite.svg +0 -1
  10. package/app/client/src/App.css +0 -883
  11. package/app/client/src/App.tsx +0 -669
  12. package/app/client/src/assets/react.svg +0 -1
  13. package/app/client/src/components/TestPage.tsx +0 -453
  14. package/app/client/src/index.css +0 -51
  15. package/app/client/src/lib/eden-api.ts +0 -110
  16. package/app/client/src/main.tsx +0 -10
  17. package/app/client/src/vite-env.d.ts +0 -1
  18. package/app/client/tsconfig.app.json +0 -43
  19. package/app/client/tsconfig.json +0 -7
  20. package/app/client/tsconfig.node.json +0 -25
  21. package/app/server/app.ts +0 -10
  22. package/app/server/backend-only.ts +0 -15
  23. package/app/server/controllers/users.controller.ts +0 -69
  24. package/app/server/index.ts +0 -104
  25. package/app/server/routes/index.ts +0 -25
  26. package/app/server/routes/users.routes.ts +0 -121
  27. package/app/server/types/index.ts +0 -1
  28. package/app/shared/types/index.ts +0 -18
  29. package/bun.lock +0 -1053
  30. package/core/__tests__/integration.test.ts +0 -227
  31. package/core/build/index.ts +0 -186
  32. package/core/cli/command-registry.ts +0 -334
  33. package/core/cli/index.ts +0 -394
  34. package/core/cli/plugin-discovery.ts +0 -200
  35. package/core/client/standalone.ts +0 -57
  36. package/core/config/__tests__/config-loader.test.ts +0 -591
  37. package/core/config/__tests__/config-merger.test.ts +0 -657
  38. package/core/config/__tests__/env-converter.test.ts +0 -372
  39. package/core/config/__tests__/env-processor.test.ts +0 -431
  40. package/core/config/__tests__/env.test.ts +0 -452
  41. package/core/config/__tests__/integration.test.ts +0 -418
  42. package/core/config/__tests__/loader.test.ts +0 -331
  43. package/core/config/__tests__/schema.test.ts +0 -129
  44. package/core/config/__tests__/validator.test.ts +0 -318
  45. package/core/config/env-dynamic.ts +0 -326
  46. package/core/config/env.ts +0 -597
  47. package/core/config/index.ts +0 -317
  48. package/core/config/loader.ts +0 -546
  49. package/core/config/runtime-config.ts +0 -322
  50. package/core/config/schema.ts +0 -694
  51. package/core/config/validator.ts +0 -540
  52. package/core/framework/__tests__/server.test.ts +0 -233
  53. package/core/framework/client.ts +0 -132
  54. package/core/framework/index.ts +0 -8
  55. package/core/framework/server.ts +0 -501
  56. package/core/framework/types.ts +0 -63
  57. package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
  58. package/core/plugins/__tests__/manager.test.ts +0 -398
  59. package/core/plugins/__tests__/monitoring.test.ts +0 -401
  60. package/core/plugins/__tests__/registry.test.ts +0 -335
  61. package/core/plugins/built-in/index.ts +0 -142
  62. package/core/plugins/built-in/logger/index.ts +0 -180
  63. package/core/plugins/built-in/monitoring/README.md +0 -193
  64. package/core/plugins/built-in/monitoring/index.ts +0 -912
  65. package/core/plugins/built-in/static/index.ts +0 -289
  66. package/core/plugins/built-in/swagger/index.ts +0 -229
  67. package/core/plugins/built-in/vite/index.ts +0 -316
  68. package/core/plugins/config.ts +0 -348
  69. package/core/plugins/discovery.ts +0 -350
  70. package/core/plugins/executor.ts +0 -351
  71. package/core/plugins/index.ts +0 -195
  72. package/core/plugins/manager.ts +0 -583
  73. package/core/plugins/registry.ts +0 -424
  74. package/core/plugins/types.ts +0 -254
  75. package/core/server/framework.ts +0 -123
  76. package/core/server/index.ts +0 -8
  77. package/core/server/plugins/database.ts +0 -182
  78. package/core/server/plugins/logger.ts +0 -47
  79. package/core/server/plugins/swagger.ts +0 -34
  80. package/core/server/standalone.ts +0 -91
  81. package/core/templates/create-project.ts +0 -455
  82. package/core/types/api.ts +0 -169
  83. package/core/types/build.ts +0 -174
  84. package/core/types/config.ts +0 -68
  85. package/core/types/index.ts +0 -127
  86. package/core/types/plugin.ts +0 -94
  87. package/core/utils/__tests__/errors.test.ts +0 -139
  88. package/core/utils/__tests__/helpers.test.ts +0 -297
  89. package/core/utils/__tests__/logger.test.ts +0 -141
  90. package/core/utils/env-runtime-v2.ts +0 -232
  91. package/core/utils/env-runtime.ts +0 -252
  92. package/core/utils/errors/codes.ts +0 -115
  93. package/core/utils/errors/handlers.ts +0 -63
  94. package/core/utils/errors/index.ts +0 -81
  95. package/core/utils/helpers.ts +0 -180
  96. package/core/utils/index.ts +0 -18
  97. package/core/utils/logger/index.ts +0 -161
  98. package/core/utils/logger.ts +0 -106
  99. package/core/utils/monitoring/index.ts +0 -212
  100. package/tsconfig.json +0 -51
  101. package/vite.config.ts +0 -42
@@ -1,583 +0,0 @@
1
- /**
2
- * Plugin Manager
3
- * Handles plugin lifecycle, execution, and context management
4
- */
5
-
6
- import type {
7
- Plugin,
8
- PluginContext,
9
- PluginHook,
10
- PluginHookResult,
11
- PluginMetrics,
12
- PluginExecutionContext,
13
- HookExecutionOptions,
14
- RequestContext,
15
- ResponseContext,
16
- ErrorContext,
17
- BuildContext
18
- } from "./types"
19
- import type { FluxStackConfig } from "../config/schema"
20
- import type { Logger } from "../utils/logger/index"
21
- import { PluginRegistry } from "./registry"
22
- import { createPluginUtils } from "./config"
23
- import { FluxStackError } from "../utils/errors"
24
- import { EventEmitter } from "events"
25
-
26
- export interface PluginManagerConfig {
27
- config: FluxStackConfig
28
- logger: Logger
29
- app?: any
30
- }
31
-
32
- export class PluginManager extends EventEmitter {
33
- private registry: PluginRegistry
34
- private config: FluxStackConfig
35
- private logger: Logger
36
- private app?: any
37
- private metrics: Map<string, PluginMetrics> = new Map()
38
- private contexts: Map<string, PluginContext> = new Map()
39
- private initialized = false
40
-
41
- constructor(options: PluginManagerConfig) {
42
- super()
43
- this.config = options.config
44
- this.logger = options.logger
45
- this.app = options.app
46
-
47
- this.registry = new PluginRegistry({
48
- logger: this.logger,
49
- config: this.config
50
- })
51
- }
52
-
53
- /**
54
- * Initialize the plugin manager
55
- */
56
- async initialize(): Promise<void> {
57
- if (this.initialized) {
58
- return
59
- }
60
-
61
- this.logger.info('Initializing plugin manager')
62
-
63
- try {
64
- // Discover and load plugins
65
- await this.discoverPlugins()
66
-
67
- // Setup plugin contexts
68
- this.setupPluginContexts()
69
-
70
- // Execute setup hooks
71
- await this.executeHook('setup')
72
-
73
- this.initialized = true
74
- this.logger.info('Plugin manager initialized successfully', {
75
- totalPlugins: this.registry.getStats().totalPlugins
76
- })
77
- } catch (error) {
78
- this.logger.error('Failed to initialize plugin manager', { error })
79
- throw error
80
- }
81
- }
82
-
83
- /**
84
- * Shutdown the plugin manager
85
- */
86
- async shutdown(): Promise<void> {
87
- if (!this.initialized) {
88
- return
89
- }
90
-
91
- this.logger.info('Shutting down plugin manager')
92
-
93
- try {
94
- await this.executeHook('onServerStop')
95
- this.initialized = false
96
- this.logger.info('Plugin manager shut down successfully')
97
- } catch (error) {
98
- this.logger.error('Error during plugin manager shutdown', { error })
99
- }
100
- }
101
-
102
- /**
103
- * Get the plugin registry
104
- */
105
- getRegistry(): PluginRegistry {
106
- return this.registry
107
- }
108
-
109
- /**
110
- * Register a plugin
111
- */
112
- async registerPlugin(plugin: Plugin): Promise<void> {
113
- await this.registry.register(plugin)
114
- this.setupPluginContext(plugin)
115
-
116
- if (this.initialized && plugin.setup) {
117
- await this.executePluginHook(plugin, 'setup')
118
- }
119
- }
120
-
121
- /**
122
- * Unregister a plugin
123
- */
124
- unregisterPlugin(name: string): void {
125
- this.registry.unregister(name)
126
- this.contexts.delete(name)
127
- this.metrics.delete(name)
128
- }
129
-
130
- /**
131
- * Execute a hook on all plugins
132
- */
133
- async executeHook(
134
- hook: PluginHook,
135
- context?: any,
136
- options: HookExecutionOptions = {}
137
- ): Promise<PluginHookResult[]> {
138
- const {
139
- timeout = 30000,
140
- parallel = false,
141
- stopOnError = false,
142
- retries = 0
143
- } = options
144
-
145
- const results: PluginHookResult[] = []
146
- const loadOrder = this.registry.getLoadOrder()
147
- const enabledPlugins = this.getEnabledPlugins()
148
-
149
- this.logger.debug(`Executing hook '${hook}' on ${enabledPlugins.length} plugins`, {
150
- hook,
151
- plugins: enabledPlugins.map(p => p.name),
152
- parallel,
153
- timeout
154
- })
155
-
156
- const executePlugin = async (plugin: Plugin): Promise<PluginHookResult> => {
157
- if (!enabledPlugins.includes(plugin)) {
158
- return {
159
- success: true,
160
- duration: 0,
161
- plugin: plugin.name,
162
- hook
163
- }
164
- }
165
-
166
- return this.executePluginHook(plugin, hook, context, { timeout, retries })
167
- }
168
-
169
- try {
170
- if (parallel) {
171
- // Execute all plugins in parallel
172
- const promises = loadOrder
173
- .map(name => this.registry.get(name))
174
- .filter(Boolean)
175
- .map(plugin => executePlugin(plugin!))
176
-
177
- const settled = await Promise.allSettled(promises)
178
-
179
- for (const result of settled) {
180
- if (result.status === 'fulfilled') {
181
- results.push(result.value)
182
- } else {
183
- results.push({
184
- success: false,
185
- error: result.reason,
186
- duration: 0,
187
- plugin: 'unknown',
188
- hook
189
- })
190
- }
191
- }
192
- } else {
193
- // Execute plugins sequentially
194
- for (const pluginName of loadOrder) {
195
- const plugin = this.registry.get(pluginName)
196
- if (!plugin) continue
197
-
198
- const result = await executePlugin(plugin)
199
- results.push(result)
200
-
201
- if (!result.success && stopOnError) {
202
- this.logger.error(`Hook execution stopped due to error in plugin '${plugin.name}'`, {
203
- hook,
204
- plugin: plugin.name,
205
- error: result.error
206
- })
207
- break
208
- }
209
- }
210
- }
211
-
212
- // Emit hook completion event
213
- this.emit('hook:after', { hook, results, context })
214
-
215
- return results
216
- } catch (error) {
217
- this.logger.error(`Hook '${hook}' execution failed`, { error })
218
- this.emit('hook:error', { hook, error, context })
219
- throw error
220
- }
221
- }
222
-
223
- /**
224
- * Execute a specific hook on a specific plugin
225
- */
226
- async executePluginHook(
227
- plugin: Plugin,
228
- hook: PluginHook,
229
- context?: any,
230
- options: { timeout?: number; retries?: number } = {}
231
- ): Promise<PluginHookResult> {
232
- const { timeout = 30000, retries = 0 } = options
233
- const startTime = Date.now()
234
-
235
- // Check if plugin implements this hook
236
- const hookFunction = plugin[hook]
237
- if (!hookFunction || typeof hookFunction !== 'function') {
238
- return {
239
- success: true,
240
- duration: 0,
241
- plugin: plugin.name,
242
- hook
243
- }
244
- }
245
-
246
- this.emit('hook:before', { plugin: plugin.name, hook, context })
247
-
248
- let attempt = 0
249
- let lastError: Error | undefined
250
-
251
- while (attempt <= retries) {
252
- try {
253
- const pluginContext = this.getPluginContext(plugin.name)
254
- const executionContext: PluginExecutionContext = {
255
- plugin,
256
- hook,
257
- startTime: Date.now(),
258
- timeout,
259
- retries
260
- }
261
-
262
- // Create timeout promise
263
- const timeoutPromise = new Promise<never>((_, reject) => {
264
- setTimeout(() => {
265
- reject(new FluxStackError(
266
- `Plugin '${plugin.name}' hook '${hook}' timed out after ${timeout}ms`,
267
- 'PLUGIN_TIMEOUT',
268
- 408
269
- ))
270
- }, timeout)
271
- })
272
-
273
- // Execute the hook with appropriate context
274
- let hookPromise: Promise<any>
275
-
276
- switch (hook) {
277
- case 'setup':
278
- case 'onServerStart':
279
- case 'onServerStop':
280
- hookPromise = Promise.resolve(hookFunction(pluginContext as any))
281
- break
282
- case 'onRequest':
283
- case 'onResponse':
284
- case 'onError':
285
- hookPromise = Promise.resolve(hookFunction(context as any))
286
- break
287
- case 'onBuild':
288
- case 'onBuildComplete':
289
- hookPromise = Promise.resolve(hookFunction(context as any))
290
- break
291
- default:
292
- hookPromise = Promise.resolve(hookFunction(context || pluginContext))
293
- }
294
-
295
- // Race between hook execution and timeout
296
- await Promise.race([hookPromise, timeoutPromise])
297
-
298
- const duration = Date.now() - startTime
299
-
300
- // Update metrics
301
- this.updatePluginMetrics(plugin.name, hook, duration, true)
302
-
303
- this.logger.debug(`Plugin '${plugin.name}' hook '${hook}' completed successfully`, {
304
- plugin: plugin.name,
305
- hook,
306
- duration,
307
- attempt: attempt + 1
308
- })
309
-
310
- return {
311
- success: true,
312
- duration,
313
- plugin: plugin.name,
314
- hook,
315
- context: executionContext
316
- }
317
-
318
- } catch (error) {
319
- lastError = error instanceof Error ? error : new Error(String(error))
320
- attempt++
321
-
322
- this.logger.warn(`Plugin '${plugin.name}' hook '${hook}' failed (attempt ${attempt}/${retries + 1})`, {
323
- plugin: plugin.name,
324
- hook,
325
- error: lastError.message,
326
- attempt
327
- })
328
-
329
- if (attempt <= retries) {
330
- // Wait before retry (exponential backoff)
331
- await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt - 1) * 1000))
332
- }
333
- }
334
- }
335
-
336
- const duration = Date.now() - startTime
337
-
338
- // Update metrics
339
- this.updatePluginMetrics(plugin.name, hook, duration, false)
340
-
341
- this.emit('plugin:error', { plugin: plugin.name, hook, error: lastError })
342
-
343
- return {
344
- success: false,
345
- error: lastError,
346
- duration,
347
- plugin: plugin.name,
348
- hook
349
- }
350
- }
351
-
352
- /**
353
- * Get plugin metrics
354
- */
355
- getPluginMetrics(pluginName?: string): PluginMetrics | Map<string, PluginMetrics> {
356
- if (pluginName) {
357
- return this.metrics.get(pluginName) || {
358
- loadTime: 0,
359
- setupTime: 0,
360
- hookExecutions: new Map(),
361
- errors: 0,
362
- warnings: 0
363
- }
364
- }
365
- return this.metrics
366
- }
367
-
368
- /**
369
- * Get enabled plugins
370
- */
371
- private getEnabledPlugins(): Plugin[] {
372
- const allPlugins = this.registry.getAll()
373
- const enabledNames = this.config.plugins.enabled
374
- const disabledNames = this.config.plugins.disabled
375
-
376
- return allPlugins.filter(plugin => {
377
- // If explicitly disabled, exclude
378
- if (disabledNames.includes(plugin.name)) {
379
- return false
380
- }
381
-
382
- // If enabled list is empty, include all non-disabled
383
- if (enabledNames.length === 0) {
384
- return true
385
- }
386
-
387
- // Otherwise, only include if explicitly enabled
388
- return enabledNames.includes(plugin.name)
389
- })
390
- }
391
-
392
- /**
393
- * Discover and load plugins
394
- */
395
- private async discoverPlugins(): Promise<void> {
396
- try {
397
- const results = await this.registry.discoverPlugins({
398
- includeBuiltIn: true,
399
- includeExternal: true
400
- })
401
-
402
- let loaded = 0
403
- let failed = 0
404
-
405
- for (const result of results) {
406
- if (result.success) {
407
- loaded++
408
- if (result.warnings && result.warnings.length > 0) {
409
- this.logger.warn(`Plugin '${result.plugin?.name}' loaded with warnings`, {
410
- warnings: result.warnings
411
- })
412
- }
413
- } else {
414
- failed++
415
- this.logger.error(`Failed to load plugin: ${result.error}`)
416
- }
417
- }
418
-
419
- this.logger.info('Plugin discovery completed', { loaded, failed })
420
- } catch (error) {
421
- this.logger.error('Plugin discovery failed', { error })
422
- throw error
423
- }
424
- }
425
-
426
- /**
427
- * Setup plugin contexts for all plugins
428
- */
429
- private setupPluginContexts(): void {
430
- const plugins = this.registry.getAll()
431
-
432
- for (const plugin of plugins) {
433
- this.setupPluginContext(plugin)
434
- }
435
- }
436
-
437
- /**
438
- * Setup context for a specific plugin
439
- */
440
- private setupPluginContext(plugin: Plugin): void {
441
- // Plugin config available but not used in current implementation
442
- // const pluginConfig = this.config.plugins.config[plugin.name] || {}
443
- // const mergedConfig = { ...plugin.defaultConfig, ...pluginConfig }
444
-
445
- const context: PluginContext = {
446
- config: this.config,
447
- logger: this.logger.child({ plugin: plugin.name }),
448
- app: this.app,
449
- utils: createPluginUtils(this.logger),
450
- registry: this.registry
451
- }
452
-
453
- this.contexts.set(plugin.name, context)
454
-
455
- // Initialize metrics
456
- this.metrics.set(plugin.name, {
457
- loadTime: 0,
458
- setupTime: 0,
459
- hookExecutions: new Map(),
460
- errors: 0,
461
- warnings: 0
462
- })
463
- }
464
-
465
- /**
466
- * Get plugin context
467
- */
468
- private getPluginContext(pluginName: string): PluginContext {
469
- const context = this.contexts.get(pluginName)
470
- if (!context) {
471
- throw new FluxStackError(
472
- `Plugin context not found for '${pluginName}'`,
473
- 'PLUGIN_CONTEXT_NOT_FOUND',
474
- 500
475
- )
476
- }
477
- return context
478
- }
479
-
480
- /**
481
- * Update plugin metrics
482
- */
483
- private updatePluginMetrics(
484
- pluginName: string,
485
- hook: PluginHook,
486
- duration: number,
487
- success: boolean
488
- ): void {
489
- const metrics = this.metrics.get(pluginName)
490
- if (!metrics) return
491
-
492
- // Update hook execution count
493
- const currentCount = metrics.hookExecutions.get(hook) || 0
494
- metrics.hookExecutions.set(hook, currentCount + 1)
495
-
496
- // Update error/success counts
497
- if (success) {
498
- if (hook === 'setup') {
499
- metrics.setupTime = duration
500
- }
501
- } else {
502
- metrics.errors++
503
- }
504
-
505
- metrics.lastExecution = new Date()
506
- }
507
- }
508
-
509
- /**
510
- * Create request context from HTTP request
511
- */
512
- export function createRequestContext(request: Request, additionalData: any = {}): RequestContext {
513
- const url = new URL(request.url)
514
-
515
- return {
516
- request,
517
- path: url.pathname,
518
- method: request.method,
519
- headers: (() => {
520
- const headers: Record<string, string> = {}
521
- request.headers.forEach((value, key) => {
522
- headers[key] = value
523
- })
524
- return headers
525
- })(),
526
- query: Object.fromEntries(url.searchParams.entries()),
527
- params: {},
528
- startTime: Date.now(),
529
- ...additionalData
530
- }
531
- }
532
-
533
- /**
534
- * Create response context from request context and response
535
- */
536
- export function createResponseContext(
537
- requestContext: RequestContext,
538
- response: Response,
539
- additionalData: any = {}
540
- ): ResponseContext {
541
- return {
542
- ...requestContext,
543
- response,
544
- statusCode: response.status,
545
- duration: Date.now() - requestContext.startTime,
546
- size: parseInt(response.headers.get('content-length') || '0'),
547
- ...additionalData
548
- }
549
- }
550
-
551
- /**
552
- * Create error context from request context and error
553
- */
554
- export function createErrorContext(
555
- requestContext: RequestContext,
556
- error: Error,
557
- additionalData: any = {}
558
- ): ErrorContext {
559
- return {
560
- ...requestContext,
561
- error,
562
- duration: Date.now() - requestContext.startTime,
563
- handled: false,
564
- ...additionalData
565
- }
566
- }
567
-
568
- /**
569
- * Create build context
570
- */
571
- export function createBuildContext(
572
- target: string,
573
- outDir: string,
574
- mode: 'development' | 'production',
575
- config: FluxStackConfig
576
- ): BuildContext {
577
- return {
578
- target,
579
- outDir,
580
- mode,
581
- config
582
- }
583
- }