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.
- package/CHANGELOG.md +80 -0
- package/app/client/src/App.tsx +8 -0
- package/app/client/src/live/AuthDemo.tsx +4 -4
- package/core/build/bundler.ts +40 -26
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +92 -21
- package/core/cli/command-registry.ts +44 -46
- package/core/cli/commands/build.ts +11 -6
- package/core/cli/commands/create.ts +7 -5
- package/core/cli/commands/dev.ts +6 -5
- package/core/cli/commands/help.ts +3 -2
- package/core/cli/commands/make-plugin.ts +8 -7
- package/core/cli/commands/plugin-add.ts +60 -43
- package/core/cli/commands/plugin-deps.ts +73 -57
- package/core/cli/commands/plugin-list.ts +44 -41
- package/core/cli/commands/plugin-remove.ts +33 -22
- package/core/cli/generators/component.ts +770 -769
- package/core/cli/generators/controller.ts +9 -8
- package/core/cli/generators/index.ts +148 -146
- package/core/cli/generators/interactive.ts +228 -227
- package/core/cli/generators/plugin.ts +11 -10
- package/core/cli/generators/prompts.ts +83 -82
- package/core/cli/generators/route.ts +7 -6
- package/core/cli/generators/service.ts +10 -9
- package/core/cli/generators/template-engine.ts +2 -1
- package/core/cli/generators/types.ts +7 -7
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +9 -8
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/standalone.ts +18 -17
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +1 -0
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +72 -112
- package/core/framework/types.ts +2 -2
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +6 -3
- package/core/plugins/built-in/monitoring/index.ts +110 -68
- package/core/plugins/built-in/static/index.ts +2 -2
- package/core/plugins/built-in/swagger/index.ts +9 -9
- package/core/plugins/built-in/vite/index.ts +3 -3
- package/core/plugins/built-in/vite/vite-dev.ts +3 -3
- package/core/plugins/config.ts +50 -47
- package/core/plugins/discovery.ts +10 -4
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +206 -203
- package/core/plugins/manager.ts +21 -20
- package/core/plugins/registry.ts +76 -12
- package/core/plugins/types.ts +14 -14
- package/core/server/framework.ts +3 -189
- package/core/server/live/auto-generated-components.ts +11 -29
- package/core/server/live/index.ts +41 -31
- package/core/server/live/websocket-plugin.ts +11 -1
- package/core/server/middleware/elysia-helpers.ts +16 -15
- package/core/server/middleware/errorHandling.ts +14 -14
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +181 -180
- package/core/server/plugins/static-files-plugin.ts +4 -3
- package/core/server/plugins/swagger.ts +11 -8
- package/core/server/rooms/RoomBroadcaster.ts +11 -10
- package/core/server/rooms/RoomSystem.ts +14 -11
- package/core/server/services/BaseService.ts +7 -7
- package/core/server/services/ServiceContainer.ts +5 -5
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +28 -27
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/config.ts +5 -5
- package/core/types/index.ts +1 -1
- package/core/types/plugin.ts +2 -2
- package/core/types/types.ts +3 -3
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +10 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +30 -20
- package/core/utils/errors/index.ts +54 -46
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +19 -16
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +2 -2
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +13 -3
- package/core/utils/logger/startup-banner.ts +2 -2
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +67 -66
- package/core/utils/version.ts +1 -1
- package/package.json +104 -100
- package/playwright-report/index.html +85 -0
- package/playwright.config.ts +31 -0
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
- package/plugins/crypto-auth/client/components/index.ts +11 -11
- package/plugins/crypto-auth/client/index.ts +11 -11
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/vite.config.ts +13 -0
- package/app/client/.live-stubs/LiveAdminPanel.js +0 -5
- package/app/client/.live-stubs/LiveCounter.js +0 -9
- package/app/client/.live-stubs/LiveForm.js +0 -11
- package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
- package/app/client/.live-stubs/LivePingPong.js +0 -10
- package/app/client/.live-stubs/LiveRoomChat.js +0 -11
- package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
- package/app/client/.live-stubs/LiveUpload.js +0 -15
- package/app/server/live/register-components.ts +0 -19
- package/core/build/live-components-generator.ts +0 -321
- package/core/live/ComponentRegistry.ts +0 -403
- package/core/live/types.ts +0 -241
- 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 =
|
|
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> |
|
|
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 =
|
|
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
|
-
|
|
54
|
-
return new Elysia({ name }).derive(handler as any)
|
|
56
|
+
return new Elysia({ name }).derive(handler as never)
|
|
55
57
|
} else {
|
|
56
|
-
|
|
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,
|
|
75
|
+
export function createDerive<TDerived extends Record<string, unknown>>(options: {
|
|
75
76
|
name: string
|
|
76
|
-
derive: (context:
|
|
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 =
|
|
101
|
+
export function createGuard<TContext = unknown>(options: {
|
|
101
102
|
name: string
|
|
102
103
|
check: (context: TContext) => boolean | Promise<boolean>
|
|
103
|
-
onFail: (set:
|
|
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
|
|
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:
|
|
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 }:
|
|
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
|
|
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]:
|
|
11
|
+
[key: string]: unknown
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export interface Response {
|
|
15
15
|
status: (code: number) => Response
|
|
16
|
-
json: (data:
|
|
17
|
-
[key: string]:
|
|
16
|
+
json: (data: unknown) => Response
|
|
17
|
+
[key: string]: unknown
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export interface NextFunction {
|
|
21
|
-
(error?:
|
|
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?:
|
|
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
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
77
|
+
errorBody.stack = error.stack
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
// Include additional details if available
|
|
83
81
|
if (error.details) {
|
|
84
|
-
|
|
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?:
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"flux database:migrate
|
|
23
|
-
"flux database:migrate --
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"flux database:seed
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
"flux database:reset
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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 }:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|