create-fluxstack 1.0.1 → 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 (100) hide show
  1. package/create-fluxstack.ts +2 -3
  2. package/package.json +1 -1
  3. package/.env +0 -30
  4. package/LICENSE +0 -21
  5. package/app/client/README.md +0 -69
  6. package/app/client/frontend-only.ts +0 -12
  7. package/app/client/index.html +0 -13
  8. package/app/client/public/vite.svg +0 -1
  9. package/app/client/src/App.css +0 -883
  10. package/app/client/src/App.tsx +0 -669
  11. package/app/client/src/assets/react.svg +0 -1
  12. package/app/client/src/components/TestPage.tsx +0 -453
  13. package/app/client/src/index.css +0 -51
  14. package/app/client/src/lib/eden-api.ts +0 -110
  15. package/app/client/src/main.tsx +0 -10
  16. package/app/client/src/vite-env.d.ts +0 -1
  17. package/app/client/tsconfig.app.json +0 -43
  18. package/app/client/tsconfig.json +0 -7
  19. package/app/client/tsconfig.node.json +0 -25
  20. package/app/server/app.ts +0 -10
  21. package/app/server/backend-only.ts +0 -15
  22. package/app/server/controllers/users.controller.ts +0 -69
  23. package/app/server/index.ts +0 -104
  24. package/app/server/routes/index.ts +0 -25
  25. package/app/server/routes/users.routes.ts +0 -121
  26. package/app/server/types/index.ts +0 -1
  27. package/app/shared/types/index.ts +0 -18
  28. package/bun.lock +0 -1053
  29. package/core/__tests__/integration.test.ts +0 -227
  30. package/core/build/index.ts +0 -186
  31. package/core/cli/command-registry.ts +0 -334
  32. package/core/cli/index.ts +0 -394
  33. package/core/cli/plugin-discovery.ts +0 -200
  34. package/core/client/standalone.ts +0 -57
  35. package/core/config/__tests__/config-loader.test.ts +0 -591
  36. package/core/config/__tests__/config-merger.test.ts +0 -657
  37. package/core/config/__tests__/env-converter.test.ts +0 -372
  38. package/core/config/__tests__/env-processor.test.ts +0 -431
  39. package/core/config/__tests__/env.test.ts +0 -452
  40. package/core/config/__tests__/integration.test.ts +0 -418
  41. package/core/config/__tests__/loader.test.ts +0 -331
  42. package/core/config/__tests__/schema.test.ts +0 -129
  43. package/core/config/__tests__/validator.test.ts +0 -318
  44. package/core/config/env-dynamic.ts +0 -326
  45. package/core/config/env.ts +0 -597
  46. package/core/config/index.ts +0 -317
  47. package/core/config/loader.ts +0 -546
  48. package/core/config/runtime-config.ts +0 -322
  49. package/core/config/schema.ts +0 -694
  50. package/core/config/validator.ts +0 -540
  51. package/core/framework/__tests__/server.test.ts +0 -233
  52. package/core/framework/client.ts +0 -132
  53. package/core/framework/index.ts +0 -8
  54. package/core/framework/server.ts +0 -501
  55. package/core/framework/types.ts +0 -63
  56. package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
  57. package/core/plugins/__tests__/manager.test.ts +0 -398
  58. package/core/plugins/__tests__/monitoring.test.ts +0 -401
  59. package/core/plugins/__tests__/registry.test.ts +0 -335
  60. package/core/plugins/built-in/index.ts +0 -142
  61. package/core/plugins/built-in/logger/index.ts +0 -180
  62. package/core/plugins/built-in/monitoring/README.md +0 -193
  63. package/core/plugins/built-in/monitoring/index.ts +0 -912
  64. package/core/plugins/built-in/static/index.ts +0 -289
  65. package/core/plugins/built-in/swagger/index.ts +0 -229
  66. package/core/plugins/built-in/vite/index.ts +0 -316
  67. package/core/plugins/config.ts +0 -348
  68. package/core/plugins/discovery.ts +0 -350
  69. package/core/plugins/executor.ts +0 -351
  70. package/core/plugins/index.ts +0 -195
  71. package/core/plugins/manager.ts +0 -583
  72. package/core/plugins/registry.ts +0 -424
  73. package/core/plugins/types.ts +0 -254
  74. package/core/server/framework.ts +0 -123
  75. package/core/server/index.ts +0 -8
  76. package/core/server/plugins/database.ts +0 -182
  77. package/core/server/plugins/logger.ts +0 -47
  78. package/core/server/plugins/swagger.ts +0 -34
  79. package/core/server/standalone.ts +0 -91
  80. package/core/templates/create-project.ts +0 -455
  81. package/core/types/api.ts +0 -169
  82. package/core/types/build.ts +0 -174
  83. package/core/types/config.ts +0 -68
  84. package/core/types/index.ts +0 -127
  85. package/core/types/plugin.ts +0 -94
  86. package/core/utils/__tests__/errors.test.ts +0 -139
  87. package/core/utils/__tests__/helpers.test.ts +0 -297
  88. package/core/utils/__tests__/logger.test.ts +0 -141
  89. package/core/utils/env-runtime-v2.ts +0 -232
  90. package/core/utils/env-runtime.ts +0 -252
  91. package/core/utils/errors/codes.ts +0 -115
  92. package/core/utils/errors/handlers.ts +0 -63
  93. package/core/utils/errors/index.ts +0 -81
  94. package/core/utils/helpers.ts +0 -180
  95. package/core/utils/index.ts +0 -18
  96. package/core/utils/logger/index.ts +0 -161
  97. package/core/utils/logger.ts +0 -106
  98. package/core/utils/monitoring/index.ts +0 -212
  99. package/tsconfig.json +0 -51
  100. 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
- }