create-fluxstack 1.16.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 (119) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/app/client/src/App.tsx +8 -0
  3. package/app/client/src/live/AuthDemo.tsx +4 -4
  4. package/core/build/bundler.ts +40 -26
  5. package/core/build/flux-plugins-generator.ts +325 -325
  6. package/core/build/index.ts +92 -21
  7. package/core/cli/command-registry.ts +44 -46
  8. package/core/cli/commands/build.ts +11 -6
  9. package/core/cli/commands/create.ts +7 -5
  10. package/core/cli/commands/dev.ts +6 -5
  11. package/core/cli/commands/help.ts +3 -2
  12. package/core/cli/commands/make-plugin.ts +8 -7
  13. package/core/cli/commands/plugin-add.ts +60 -43
  14. package/core/cli/commands/plugin-deps.ts +73 -57
  15. package/core/cli/commands/plugin-list.ts +44 -41
  16. package/core/cli/commands/plugin-remove.ts +33 -22
  17. package/core/cli/generators/component.ts +770 -769
  18. package/core/cli/generators/controller.ts +9 -8
  19. package/core/cli/generators/index.ts +148 -146
  20. package/core/cli/generators/interactive.ts +228 -227
  21. package/core/cli/generators/plugin.ts +11 -10
  22. package/core/cli/generators/prompts.ts +83 -82
  23. package/core/cli/generators/route.ts +7 -6
  24. package/core/cli/generators/service.ts +10 -9
  25. package/core/cli/generators/template-engine.ts +2 -1
  26. package/core/cli/generators/types.ts +7 -7
  27. package/core/cli/generators/utils.ts +191 -191
  28. package/core/cli/index.ts +9 -8
  29. package/core/cli/plugin-discovery.ts +2 -2
  30. package/core/client/hooks/useAuth.ts +48 -48
  31. package/core/client/standalone.ts +18 -17
  32. package/core/client/state/createStore.ts +192 -192
  33. package/core/client/state/index.ts +14 -14
  34. package/core/config/index.ts +1 -0
  35. package/core/framework/client.ts +131 -131
  36. package/core/framework/index.ts +7 -7
  37. package/core/framework/server.ts +72 -112
  38. package/core/framework/types.ts +2 -2
  39. package/core/plugins/built-in/live-components/commands/create-live-component.ts +6 -3
  40. package/core/plugins/built-in/monitoring/index.ts +110 -68
  41. package/core/plugins/built-in/static/index.ts +2 -2
  42. package/core/plugins/built-in/swagger/index.ts +9 -9
  43. package/core/plugins/built-in/vite/index.ts +3 -3
  44. package/core/plugins/built-in/vite/vite-dev.ts +3 -3
  45. package/core/plugins/config.ts +50 -47
  46. package/core/plugins/discovery.ts +10 -4
  47. package/core/plugins/executor.ts +2 -2
  48. package/core/plugins/index.ts +206 -203
  49. package/core/plugins/manager.ts +21 -20
  50. package/core/plugins/registry.ts +76 -12
  51. package/core/plugins/types.ts +14 -14
  52. package/core/server/framework.ts +3 -189
  53. package/core/server/live/auto-generated-components.ts +11 -29
  54. package/core/server/live/index.ts +41 -31
  55. package/core/server/live/websocket-plugin.ts +11 -1
  56. package/core/server/middleware/elysia-helpers.ts +16 -15
  57. package/core/server/middleware/errorHandling.ts +14 -14
  58. package/core/server/middleware/index.ts +31 -31
  59. package/core/server/plugins/database.ts +181 -180
  60. package/core/server/plugins/static-files-plugin.ts +4 -3
  61. package/core/server/plugins/swagger.ts +11 -8
  62. package/core/server/rooms/RoomBroadcaster.ts +11 -10
  63. package/core/server/rooms/RoomSystem.ts +14 -11
  64. package/core/server/services/BaseService.ts +7 -7
  65. package/core/server/services/ServiceContainer.ts +5 -5
  66. package/core/server/services/index.ts +8 -8
  67. package/core/templates/create-project.ts +28 -27
  68. package/core/testing/index.ts +9 -9
  69. package/core/testing/setup.ts +73 -73
  70. package/core/types/api.ts +168 -168
  71. package/core/types/config.ts +5 -5
  72. package/core/types/index.ts +1 -1
  73. package/core/types/plugin.ts +2 -2
  74. package/core/types/types.ts +3 -3
  75. package/core/utils/build-logger.ts +324 -324
  76. package/core/utils/config-schema.ts +480 -480
  77. package/core/utils/env.ts +10 -8
  78. package/core/utils/errors/codes.ts +114 -114
  79. package/core/utils/errors/handlers.ts +30 -20
  80. package/core/utils/errors/index.ts +54 -46
  81. package/core/utils/errors/middleware.ts +113 -113
  82. package/core/utils/helpers.ts +19 -16
  83. package/core/utils/logger/colors.ts +114 -114
  84. package/core/utils/logger/config.ts +2 -2
  85. package/core/utils/logger/formatter.ts +82 -82
  86. package/core/utils/logger/group-logger.ts +101 -101
  87. package/core/utils/logger/index.ts +13 -3
  88. package/core/utils/logger/startup-banner.ts +2 -2
  89. package/core/utils/logger/winston-logger.ts +152 -152
  90. package/core/utils/monitoring/index.ts +211 -211
  91. package/core/utils/sync-version.ts +67 -66
  92. package/core/utils/version.ts +1 -1
  93. package/package.json +104 -100
  94. package/playwright-report/index.html +85 -0
  95. package/playwright.config.ts +31 -0
  96. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  97. package/plugins/crypto-auth/client/components/index.ts +11 -11
  98. package/plugins/crypto-auth/client/index.ts +11 -11
  99. package/plugins/crypto-auth/package.json +65 -65
  100. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  101. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +6 -5
  102. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +6 -5
  103. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +3 -3
  104. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  105. package/plugins/crypto-auth/server/middlewares.ts +19 -19
  106. package/vite.config.ts +13 -0
  107. package/app/client/.live-stubs/LiveAdminPanel.js +0 -5
  108. package/app/client/.live-stubs/LiveCounter.js +0 -9
  109. package/app/client/.live-stubs/LiveForm.js +0 -11
  110. package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
  111. package/app/client/.live-stubs/LivePingPong.js +0 -10
  112. package/app/client/.live-stubs/LiveRoomChat.js +0 -11
  113. package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
  114. package/app/client/.live-stubs/LiveUpload.js +0 -15
  115. package/app/server/live/register-components.ts +0 -19
  116. package/core/build/live-components-generator.ts +0 -321
  117. package/core/live/ComponentRegistry.ts +0 -403
  118. package/core/live/types.ts +0 -241
  119. package/workspace.json +0 -6
@@ -8,7 +8,7 @@ import { Elysia } from 'elysia'
8
8
  /**
9
9
  * Options for creating middleware
10
10
  */
11
- export interface MiddlewareOptions<TContext = any> {
11
+ export interface MiddlewareOptions<TContext = unknown> {
12
12
  /** Unique name for the middleware (required for Elysia) */
13
13
  name: string
14
14
 
@@ -16,7 +16,7 @@ export interface MiddlewareOptions<TContext = any> {
16
16
  * Handler function that runs before the route handler.
17
17
  * Return undefined to continue, or return a response to block execution.
18
18
  */
19
- handler: (context: TContext) => void | Promise<void> | any | Promise<any>
19
+ handler: (context: TContext) => void | Promise<void> | unknown | Promise<unknown>
20
20
 
21
21
  /**
22
22
  * If true, uses derive() instead of onBeforeHandle().
@@ -44,17 +44,18 @@ export interface MiddlewareOptions<TContext = any> {
44
44
  * app.use(myAuth)
45
45
  * ```
46
46
  */
47
- export function createMiddleware<TContext = any>(
47
+ export function createMiddleware<TContext = unknown>(
48
48
  options: MiddlewareOptions<TContext>
49
49
  ) {
50
50
  const { name, handler, nonBlocking = false } = options
51
51
 
52
+ // Elysia's derive/onBeforeHandle have complex overloaded type signatures
53
+ // that cannot be satisfied by a generic TContext handler. We cast through
54
+ // 'never' to bridge the generic handler with Elysia's strict internal types.
52
55
  if (nonBlocking) {
53
- // Non-blocking: use derive() - adds to context without stopping execution
54
- return new Elysia({ name }).derive(handler as any)
56
+ return new Elysia({ name }).derive(handler as never)
55
57
  } else {
56
- // Blocking: use onBeforeHandle() - can stop execution by returning a response
57
- return new Elysia({ name }).onBeforeHandle(handler as any)
58
+ return new Elysia({ name }).onBeforeHandle(handler as never)
58
59
  }
59
60
  }
60
61
 
@@ -71,9 +72,9 @@ export function createMiddleware<TContext = any>(
71
72
  * app.use(addTimestamp).get('/', ({ timestamp }) => ({ timestamp }))
72
73
  * ```
73
74
  */
74
- export function createDerive<TDerived extends Record<string, any>>(options: {
75
+ export function createDerive<TDerived extends Record<string, unknown>>(options: {
75
76
  name: string
76
- derive: (context: any) => TDerived | Promise<TDerived>
77
+ derive: (context: unknown) => TDerived | Promise<TDerived>
77
78
  }) {
78
79
  return new Elysia({ name: options.name }).derive(options.derive)
79
80
  }
@@ -97,16 +98,16 @@ export function createDerive<TDerived extends Record<string, any>>(options: {
97
98
  * app.use(requireAdmin).get('/admin', () => 'Admin panel')
98
99
  * ```
99
100
  */
100
- export function createGuard<TContext = any>(options: {
101
+ export function createGuard<TContext = unknown>(options: {
101
102
  name: string
102
103
  check: (context: TContext) => boolean | Promise<boolean>
103
- onFail: (set: any, context: TContext) => any
104
+ onFail: (set: unknown, context: TContext) => unknown
104
105
  }) {
105
106
  return new Elysia({ name: options.name })
106
107
  .onBeforeHandle(async (ctx) => {
107
108
  const passed = await options.check(ctx as TContext)
108
109
  if (!passed) {
109
- return options.onFail((ctx as any).set, ctx as TContext)
110
+ return options.onFail((ctx as unknown as TContext & { set: unknown }).set, ctx as unknown as TContext)
110
111
  }
111
112
  })
112
113
  }
@@ -128,14 +129,14 @@ export function createRateLimit(options: {
128
129
  name: string
129
130
  maxRequests: number
130
131
  windowMs: number
131
- keyGenerator?: (context: any) => string
132
+ keyGenerator?: (context: unknown) => string
132
133
  message?: string
133
134
  }) {
134
135
  const {
135
136
  name,
136
137
  maxRequests,
137
138
  windowMs,
138
- keyGenerator = ({ request }: any) =>
139
+ keyGenerator = ({ request }: { request: Request }) =>
139
140
  request.headers.get('x-forwarded-for') ||
140
141
  request.headers.get('x-real-ip') ||
141
142
  'unknown',
@@ -171,7 +172,7 @@ export function createRateLimit(options: {
171
172
  requests.set(key, { count: 1, resetTime: now + windowMs })
172
173
  } else if (entry.count >= maxRequests) {
173
174
  // Rate limit exceeded
174
- ;(ctx as any).set.status = 429
175
+ ;(ctx as { set: { status: number } }).set.status = 429
175
176
  return {
176
177
  success: false,
177
178
  error: 'RATE_LIMIT_EXCEEDED',
@@ -8,17 +8,17 @@ export interface Request {
8
8
  url: string
9
9
  method: string
10
10
  ip?: string
11
- [key: string]: any
11
+ [key: string]: unknown
12
12
  }
13
13
 
14
14
  export interface Response {
15
15
  status: (code: number) => Response
16
- json: (data: any) => Response
17
- [key: string]: any
16
+ json: (data: unknown) => Response
17
+ [key: string]: unknown
18
18
  }
19
19
 
20
20
  export interface NextFunction {
21
- (error?: any): void
21
+ (error?: unknown): void
22
22
  }
23
23
  import type { Logger } from '@core/utils/logger/index'
24
24
 
@@ -31,7 +31,7 @@ export interface ErrorHandlingOptions {
31
31
  export interface FluxStackError extends Error {
32
32
  statusCode?: number
33
33
  code?: string
34
- details?: any
34
+ details?: unknown
35
35
  }
36
36
 
37
37
  /**
@@ -66,24 +66,24 @@ export function errorHandlingMiddleware(options: ErrorHandlingOptions = {}) {
66
66
 
67
67
  // Default error response
68
68
  const statusCode = error.statusCode || 500
69
- const response: any = {
70
- error: {
71
- message: error.message || 'Internal Server Error',
72
- code: error.code || 'INTERNAL_ERROR',
73
- statusCode
74
- }
69
+ const errorBody: Record<string, unknown> = {
70
+ message: error.message || 'Internal Server Error',
71
+ code: error.code || 'INTERNAL_ERROR',
72
+ statusCode
75
73
  }
76
74
 
77
75
  // Include stack trace in development
78
76
  if (includeStack && error.stack) {
79
- response.error.stack = error.stack
77
+ errorBody.stack = error.stack
80
78
  }
81
79
 
82
80
  // Include additional details if available
83
81
  if (error.details) {
84
- response.error.details = error.details
82
+ errorBody.details = error.details
85
83
  }
86
84
 
85
+ const response = { error: errorBody }
86
+
87
87
  res.status(statusCode).json(response)
88
88
  }
89
89
  }
@@ -122,7 +122,7 @@ export function createError(
122
122
  message: string,
123
123
  statusCode: number = 500,
124
124
  code?: string,
125
- details?: any
125
+ details?: unknown
126
126
  ): FluxStackError {
127
127
  const error = new Error(message) as FluxStackError
128
128
  error.statusCode = statusCode
@@ -1,32 +1,32 @@
1
- /**
2
- * Core Server Middleware
3
- * FluxStack middleware infrastructure exports
4
- */
5
-
6
- export {
7
- errorHandlingMiddleware,
8
- notFoundMiddleware,
9
- createError,
10
- asyncHandler
11
- } from './errorHandling'
12
-
13
- export type {
14
- ErrorHandlingOptions,
15
- FluxStackError
16
- } from './errorHandling'
17
-
18
- // Elysia Middleware Helpers
19
- export {
20
- createMiddleware,
21
- createDerive,
22
- createGuard,
23
- createRateLimit,
24
- composeMiddleware,
25
- isDevelopment,
26
- isProduction,
27
- isTest
28
- } from './elysia-helpers'
29
-
30
- export type {
31
- MiddlewareOptions
1
+ /**
2
+ * Core Server Middleware
3
+ * FluxStack middleware infrastructure exports
4
+ */
5
+
6
+ export {
7
+ errorHandlingMiddleware,
8
+ notFoundMiddleware,
9
+ createError,
10
+ asyncHandler
11
+ } from './errorHandling'
12
+
13
+ export type {
14
+ ErrorHandlingOptions,
15
+ FluxStackError
16
+ } from './errorHandling'
17
+
18
+ // Elysia Middleware Helpers
19
+ export {
20
+ createMiddleware,
21
+ createDerive,
22
+ createGuard,
23
+ createRateLimit,
24
+ composeMiddleware,
25
+ isDevelopment,
26
+ isProduction,
27
+ isTest
28
+ } from './elysia-helpers'
29
+
30
+ export type {
31
+ MiddlewareOptions
32
32
  } from './elysia-helpers'
@@ -1,181 +1,182 @@
1
- import type { FluxStack, PluginContext, CliCommand, Plugin } from "../../plugins/types"
2
-
3
- // Database plugin with CLI commands
4
- export const databasePlugin: Plugin = {
5
- name: "database",
6
- description: "Database management plugin with CLI commands",
7
- author: "FluxStack Team",
8
- category: "data",
9
-
10
- setup: (context: PluginContext) => {
11
- context.logger.info("Database plugin initialized")
12
- },
13
-
14
- commands: [
15
- {
16
- name: "migrate",
17
- description: "Run database migrations",
18
- category: "Database",
19
- usage: "flux database:migrate [options]",
20
- examples: [
21
- "flux database:migrate # Run all pending migrations",
22
- "flux database:migrate --rollback # Rollback last migration",
23
- "flux database:migrate --to 001 # Migrate to specific version"
24
- ],
25
- options: [
26
- {
27
- name: "rollback",
28
- short: "r",
29
- description: "Rollback the last migration",
30
- type: "boolean"
31
- },
32
- {
33
- name: "to",
34
- description: "Migrate to specific version",
35
- type: "string"
36
- },
37
- {
38
- name: "dry-run",
39
- description: "Show what would be migrated without executing",
40
- type: "boolean"
41
- }
42
- ],
43
- handler: async (args, options, context) => {
44
- if (options["dry-run"]) {
45
- console.log("🔍 Dry run mode - showing planned migrations:")
46
- }
47
-
48
- if (options.rollback) {
49
- console.log("⬇️ Rolling back last migration...")
50
- // Simulate rollback
51
- await new Promise(resolve => setTimeout(resolve, 1000))
52
- console.log("✅ Rollback completed")
53
- } else if (options.to) {
54
- console.log(`📈 Migrating to version: ${options.to}`)
55
- // Simulate migration to version
56
- await new Promise(resolve => setTimeout(resolve, 1500))
57
- console.log(`✅ Migrated to version ${options.to}`)
58
- } else {
59
- console.log("📈 Running all pending migrations...")
60
- // Simulate migration
61
- await new Promise(resolve => setTimeout(resolve, 2000))
62
- console.log("✅ All migrations completed")
63
- }
64
- }
65
- },
66
- {
67
- name: "seed",
68
- description: "Seed the database with initial data",
69
- category: "Database",
70
- usage: "flux database:seed [seeder]",
71
- examples: [
72
- "flux database:seed # Run all seeders",
73
- "flux database:seed users # Run specific seeder"
74
- ],
75
- arguments: [
76
- {
77
- name: "seeder",
78
- description: "Specific seeder to run",
79
- required: false,
80
- type: "string"
81
- }
82
- ],
83
- options: [
84
- {
85
- name: "force",
86
- short: "f",
87
- description: "Force seeding even if data exists",
88
- type: "boolean"
89
- }
90
- ],
91
- handler: async (args, options, context) => {
92
- const [seeder] = args
93
-
94
- if (seeder) {
95
- console.log(`🌱 Running seeder: ${seeder}`)
96
- console.log(` Force mode: ${options.force ? 'ON' : 'OFF'}`)
97
- } else {
98
- console.log("🌱 Running all seeders...")
99
- }
100
-
101
- // Simulate seeding
102
- await new Promise(resolve => setTimeout(resolve, 1500))
103
- console.log("✅ Database seeded successfully")
104
- }
105
- },
106
- {
107
- name: "reset",
108
- description: "Reset the database (drop all tables and recreate)",
109
- category: "Database",
110
- usage: "flux database:reset [options]",
111
- examples: [
112
- "flux database:reset # Reset and migrate",
113
- "flux database:reset --seed # Reset, migrate and seed"
114
- ],
115
- options: [
116
- {
117
- name: "seed",
118
- short: "s",
119
- description: "Run seeders after reset",
120
- type: "boolean"
121
- },
122
- {
123
- name: "confirm",
124
- description: "Skip confirmation prompt",
125
- type: "boolean"
126
- }
127
- ],
128
- handler: async (args, options, context) => {
129
- if (!options.confirm) {
130
- console.log("⚠️ WARNING: This will delete all data in the database!")
131
- console.log("Use --confirm to skip this prompt.")
132
- return
133
- }
134
-
135
- console.log("🗑️ Dropping all tables...")
136
- await new Promise(resolve => setTimeout(resolve, 1000))
137
-
138
- console.log("📈 Running migrations...")
139
- await new Promise(resolve => setTimeout(resolve, 1500))
140
-
141
- if (options.seed) {
142
- console.log("🌱 Running seeders...")
143
- await new Promise(resolve => setTimeout(resolve, 1000))
144
- }
145
-
146
- console.log("✅ Database reset completed")
147
- }
148
- },
149
- {
150
- name: "status",
151
- description: "Show database migration status",
152
- category: "Database",
153
- aliases: ["info"],
154
- handler: async (args, options, context) => {
155
- console.log("📊 Database Status:")
156
- console.log("------------------")
157
- console.log("Connected: ✅ Yes")
158
- console.log("Tables: 15")
159
- console.log("Last migration: 2024_01_15_create_users_table")
160
- console.log("Pending migrations: 2")
161
- console.log("Database size: 2.3 MB")
162
- }
163
- }
164
- ]
165
- }
166
-
167
- // Utility functions that could be used by the plugin
168
- export async function runMigration(version?: string): Promise<void> {
169
- // Actual migration logic would go here
170
- console.log(`Running migration ${version || 'all'}`)
171
- }
172
-
173
- export async function rollbackMigration(): Promise<void> {
174
- // Actual rollback logic would go here
175
- console.log("Rolling back migration")
176
- }
177
-
178
- export async function seedDatabase(seeder?: string): Promise<void> {
179
- // Actual seeding logic would go here
180
- console.log(`Seeding database ${seeder || 'all'}`)
1
+ import type { FluxStack, PluginContext, CliCommand, Plugin } from "../../plugins/types"
2
+ import { logger } from "@core/utils/logger"
3
+
4
+ // Database plugin with CLI commands
5
+ export const databasePlugin: Plugin = {
6
+ name: "database",
7
+ description: "Database management plugin with CLI commands",
8
+ author: "FluxStack Team",
9
+ category: "data",
10
+
11
+ setup: (context: PluginContext) => {
12
+ context.logger.info("Database plugin initialized")
13
+ },
14
+
15
+ commands: [
16
+ {
17
+ name: "migrate",
18
+ description: "Run database migrations",
19
+ category: "Database",
20
+ usage: "flux database:migrate [options]",
21
+ examples: [
22
+ "flux database:migrate # Run all pending migrations",
23
+ "flux database:migrate --rollback # Rollback last migration",
24
+ "flux database:migrate --to 001 # Migrate to specific version"
25
+ ],
26
+ options: [
27
+ {
28
+ name: "rollback",
29
+ short: "r",
30
+ description: "Rollback the last migration",
31
+ type: "boolean"
32
+ },
33
+ {
34
+ name: "to",
35
+ description: "Migrate to specific version",
36
+ type: "string"
37
+ },
38
+ {
39
+ name: "dry-run",
40
+ description: "Show what would be migrated without executing",
41
+ type: "boolean"
42
+ }
43
+ ],
44
+ handler: async (args, options, context) => {
45
+ if (options["dry-run"]) {
46
+ logger.info("Dry run mode - showing planned migrations:")
47
+ }
48
+
49
+ if (options.rollback) {
50
+ logger.info("Rolling back last migration...")
51
+ // Simulate rollback
52
+ await new Promise(resolve => setTimeout(resolve, 1000))
53
+ logger.info("Rollback completed")
54
+ } else if (options.to) {
55
+ logger.info(`Migrating to version: ${options.to}`)
56
+ // Simulate migration to version
57
+ await new Promise(resolve => setTimeout(resolve, 1500))
58
+ logger.info(`Migrated to version ${options.to}`)
59
+ } else {
60
+ logger.info("Running all pending migrations...")
61
+ // Simulate migration
62
+ await new Promise(resolve => setTimeout(resolve, 2000))
63
+ logger.info("All migrations completed")
64
+ }
65
+ }
66
+ },
67
+ {
68
+ name: "seed",
69
+ description: "Seed the database with initial data",
70
+ category: "Database",
71
+ usage: "flux database:seed [seeder]",
72
+ examples: [
73
+ "flux database:seed # Run all seeders",
74
+ "flux database:seed users # Run specific seeder"
75
+ ],
76
+ arguments: [
77
+ {
78
+ name: "seeder",
79
+ description: "Specific seeder to run",
80
+ required: false,
81
+ type: "string"
82
+ }
83
+ ],
84
+ options: [
85
+ {
86
+ name: "force",
87
+ short: "f",
88
+ description: "Force seeding even if data exists",
89
+ type: "boolean"
90
+ }
91
+ ],
92
+ handler: async (args, options, context) => {
93
+ const [seeder] = args
94
+
95
+ if (seeder) {
96
+ logger.info(`Running seeder: ${seeder}`)
97
+ logger.info(` Force mode: ${options.force ? 'ON' : 'OFF'}`)
98
+ } else {
99
+ logger.info("Running all seeders...")
100
+ }
101
+
102
+ // Simulate seeding
103
+ await new Promise(resolve => setTimeout(resolve, 1500))
104
+ logger.info("Database seeded successfully")
105
+ }
106
+ },
107
+ {
108
+ name: "reset",
109
+ description: "Reset the database (drop all tables and recreate)",
110
+ category: "Database",
111
+ usage: "flux database:reset [options]",
112
+ examples: [
113
+ "flux database:reset # Reset and migrate",
114
+ "flux database:reset --seed # Reset, migrate and seed"
115
+ ],
116
+ options: [
117
+ {
118
+ name: "seed",
119
+ short: "s",
120
+ description: "Run seeders after reset",
121
+ type: "boolean"
122
+ },
123
+ {
124
+ name: "confirm",
125
+ description: "Skip confirmation prompt",
126
+ type: "boolean"
127
+ }
128
+ ],
129
+ handler: async (args, options, context) => {
130
+ if (!options.confirm) {
131
+ logger.warn("WARNING: This will delete all data in the database!")
132
+ logger.info("Use --confirm to skip this prompt.")
133
+ return
134
+ }
135
+
136
+ logger.info("Dropping all tables...")
137
+ await new Promise(resolve => setTimeout(resolve, 1000))
138
+
139
+ logger.info("Running migrations...")
140
+ await new Promise(resolve => setTimeout(resolve, 1500))
141
+
142
+ if (options.seed) {
143
+ logger.info("Running seeders...")
144
+ await new Promise(resolve => setTimeout(resolve, 1000))
145
+ }
146
+
147
+ logger.info("Database reset completed")
148
+ }
149
+ },
150
+ {
151
+ name: "status",
152
+ description: "Show database migration status",
153
+ category: "Database",
154
+ aliases: ["info"],
155
+ handler: async (args, options, context) => {
156
+ logger.info("Database Status:")
157
+ logger.info("------------------")
158
+ logger.info("Connected: Yes")
159
+ logger.info("Tables: 15")
160
+ logger.info("Last migration: 2024_01_15_create_users_table")
161
+ logger.info("Pending migrations: 2")
162
+ logger.info("Database size: 2.3 MB")
163
+ }
164
+ }
165
+ ]
166
+ }
167
+
168
+ // Utility functions that could be used by the plugin
169
+ export async function runMigration(version?: string): Promise<void> {
170
+ // Actual migration logic would go here
171
+ logger.info(`Running migration ${version || 'all'}`)
172
+ }
173
+
174
+ export async function rollbackMigration(): Promise<void> {
175
+ // Actual rollback logic would go here
176
+ logger.info("Rolling back migration")
177
+ }
178
+
179
+ export async function seedDatabase(seeder?: string): Promise<void> {
180
+ // Actual seeding logic would go here
181
+ logger.info(`Seeding database ${seeder || 'all'}`)
181
182
  }
@@ -76,7 +76,7 @@ export const staticFilesPlugin: Plugin = {
76
76
  const enableUploads = pluginsConfig.staticEnableUploads
77
77
 
78
78
  // Async handler — uses Bun.file() APIs instead of Node fs
79
- const serveFile = (baseDir: string, isUpload: boolean) => async ({ params, set, request }: any) => {
79
+ const serveFile = (baseDir: string, isUpload: boolean) => async ({ params, set, request }: { params: Record<string, string>; set: { status: number; headers: Record<string, string> }; request: Request }) => {
80
80
  const requestedPath: string = params['*'] || ''
81
81
 
82
82
  // Reject null bytes early — prevents filesystem confusion
@@ -155,15 +155,16 @@ export const staticFilesPlugin: Plugin = {
155
155
  }
156
156
 
157
157
  // Register routes based on config flags
158
+ const app = context.app as import('elysia').Elysia
158
159
  if (enablePublic) {
159
160
  await mkdir(publicDir, { recursive: true })
160
- context.app.get('/api/static/*', serveFile(publicDir, false))
161
+ app.get('/api/static/*', serveFile(publicDir, false) as never)
161
162
  context.logger.debug('Static public files route registered: /api/static/*')
162
163
  }
163
164
 
164
165
  if (enableUploads) {
165
166
  await mkdir(uploadsDir, { recursive: true })
166
- context.app.get('/api/uploads/*', serveFile(uploadsDir, true))
167
+ app.get('/api/uploads/*', serveFile(uploadsDir, true) as never)
167
168
  context.logger.debug('Static uploads route registered: /api/uploads/*')
168
169
  }
169
170