create-fluxstack 1.10.1 → 1.12.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/.dockerignore +1 -2
- package/Dockerfile +8 -8
- package/LLMD/INDEX.md +64 -0
- package/LLMD/MAINTENANCE.md +197 -0
- package/LLMD/MIGRATION.md +156 -0
- package/LLMD/config/.gitkeep +1 -0
- package/LLMD/config/declarative-system.md +268 -0
- package/LLMD/config/environment-vars.md +327 -0
- package/LLMD/config/runtime-reload.md +401 -0
- package/LLMD/core/.gitkeep +1 -0
- package/LLMD/core/build-system.md +599 -0
- package/LLMD/core/framework-lifecycle.md +229 -0
- package/LLMD/core/plugin-system.md +451 -0
- package/LLMD/patterns/.gitkeep +1 -0
- package/LLMD/patterns/anti-patterns.md +297 -0
- package/LLMD/patterns/project-structure.md +264 -0
- package/LLMD/patterns/type-safety.md +440 -0
- package/LLMD/reference/.gitkeep +1 -0
- package/LLMD/reference/cli-commands.md +250 -0
- package/LLMD/reference/plugin-hooks.md +357 -0
- package/LLMD/reference/routing.md +39 -0
- package/LLMD/reference/troubleshooting.md +364 -0
- package/LLMD/resources/.gitkeep +1 -0
- package/LLMD/resources/controllers.md +465 -0
- package/LLMD/resources/live-components.md +703 -0
- package/LLMD/resources/live-rooms.md +482 -0
- package/LLMD/resources/live-upload.md +130 -0
- package/LLMD/resources/plugins-external.md +617 -0
- package/LLMD/resources/routes-eden.md +254 -0
- package/README.md +37 -17
- package/app/client/index.html +0 -1
- package/app/client/src/App.tsx +107 -150
- package/app/client/src/components/AppLayout.tsx +68 -0
- package/app/client/src/components/BackButton.tsx +13 -0
- package/app/client/src/components/DemoPage.tsx +20 -0
- package/app/client/src/components/LiveUploadWidget.tsx +204 -0
- package/app/client/src/lib/eden-api.ts +85 -60
- package/app/client/src/live/ChatDemo.tsx +107 -0
- package/app/client/src/live/CounterDemo.tsx +206 -0
- package/app/client/src/live/FormDemo.tsx +119 -0
- package/app/client/src/live/RoomChatDemo.tsx +242 -0
- package/app/client/src/live/UploadDemo.tsx +21 -0
- package/app/client/src/main.tsx +4 -1
- package/app/client/src/pages/ApiTestPage.tsx +108 -0
- package/app/client/src/pages/HomePage.tsx +76 -0
- package/app/server/app.ts +1 -4
- package/app/server/controllers/users.controller.ts +36 -44
- package/app/server/index.ts +25 -35
- package/app/server/live/LiveChat.ts +77 -0
- package/app/server/live/LiveCounter.ts +67 -0
- package/app/server/live/LiveForm.ts +63 -0
- package/app/server/live/LiveLocalCounter.ts +32 -0
- package/app/server/live/LiveRoomChat.ts +285 -0
- package/app/server/live/LiveUpload.ts +81 -0
- package/app/server/routes/index.ts +3 -1
- package/app/server/routes/room.routes.ts +117 -0
- package/app/server/routes/users.routes.ts +35 -27
- package/app/shared/types/index.ts +14 -2
- package/config/app.config.ts +2 -62
- package/config/client.config.ts +2 -95
- package/config/database.config.ts +2 -99
- package/config/fluxstack.config.ts +25 -45
- package/config/index.ts +57 -38
- package/config/monitoring.config.ts +2 -114
- package/config/plugins.config.ts +2 -80
- package/config/server.config.ts +2 -68
- package/config/services.config.ts +2 -130
- package/config/system/app.config.ts +29 -0
- package/config/system/build.config.ts +49 -0
- package/config/system/client.config.ts +68 -0
- package/config/system/database.config.ts +17 -0
- package/config/system/fluxstack.config.ts +114 -0
- package/config/{logger.config.ts → system/logger.config.ts} +3 -1
- package/config/system/monitoring.config.ts +114 -0
- package/config/system/plugins.config.ts +84 -0
- package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
- package/config/system/server.config.ts +68 -0
- package/config/system/services.config.ts +46 -0
- package/config/{system.config.ts → system/system.config.ts} +1 -1
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +39 -27
- package/core/build/live-components-generator.ts +3 -3
- package/core/build/optimizer.ts +235 -235
- package/core/cli/command-registry.ts +6 -4
- package/core/cli/commands/build.ts +79 -0
- package/core/cli/commands/create.ts +54 -0
- package/core/cli/commands/dev.ts +101 -0
- package/core/cli/commands/help.ts +34 -0
- package/core/cli/commands/index.ts +34 -0
- package/core/cli/commands/make-plugin.ts +90 -0
- package/core/cli/commands/plugin-add.ts +197 -0
- package/core/cli/commands/plugin-deps.ts +2 -2
- package/core/cli/commands/plugin-list.ts +208 -0
- package/core/cli/commands/plugin-remove.ts +170 -0
- package/core/cli/generators/component.ts +769 -769
- package/core/cli/generators/controller.ts +1 -1
- package/core/cli/generators/index.ts +146 -146
- package/core/cli/generators/interactive.ts +227 -227
- package/core/cli/generators/plugin.ts +2 -2
- package/core/cli/generators/prompts.ts +82 -82
- package/core/cli/generators/route.ts +6 -6
- package/core/cli/generators/service.ts +2 -2
- package/core/cli/generators/template-engine.ts +4 -3
- package/core/cli/generators/types.ts +2 -2
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +115 -686
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/LiveComponentsProvider.tsx +60 -8
- package/core/client/api/eden.ts +183 -0
- package/core/client/api/index.ts +11 -0
- package/core/client/components/Live.tsx +104 -0
- package/core/client/fluxstack.ts +1 -9
- package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/hooks/useChunkedUpload.ts +85 -35
- package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
- package/core/client/hooks/useLiveComponent.ts +800 -0
- package/core/client/hooks/useLiveUpload.ts +71 -0
- package/core/client/hooks/useRoom.ts +409 -0
- package/core/client/hooks/useRoomProxy.ts +382 -0
- package/core/client/index.ts +17 -68
- package/core/client/standalone-entry.ts +8 -0
- package/core/client/standalone.ts +74 -53
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +70 -291
- package/core/config/schema.ts +42 -723
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +47 -40
- package/core/framework/types.ts +2 -2
- package/core/index.ts +23 -4
- package/core/live/ComponentRegistry.ts +3 -3
- package/core/live/types.ts +77 -0
- package/core/plugins/built-in/index.ts +134 -134
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1066
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +111 -47
- package/core/plugins/built-in/static/index.ts +1 -1
- package/core/plugins/built-in/swagger/index.ts +68 -265
- package/core/plugins/built-in/vite/index.ts +85 -185
- package/core/plugins/built-in/vite/vite-dev.ts +10 -16
- package/core/plugins/config.ts +9 -7
- package/core/plugins/dependency-manager.ts +31 -1
- package/core/plugins/discovery.ts +19 -7
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +203 -203
- package/core/plugins/manager.ts +27 -39
- package/core/plugins/module-resolver.ts +19 -8
- package/core/plugins/registry.ts +255 -19
- package/core/plugins/types.ts +20 -53
- package/core/server/framework.ts +66 -43
- package/core/server/index.ts +15 -15
- package/core/server/live/ComponentRegistry.ts +78 -71
- package/core/server/live/FileUploadManager.ts +23 -10
- package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
- package/core/server/live/LiveRoomManager.ts +261 -0
- package/core/server/live/RoomEventBus.ts +234 -0
- package/core/server/live/RoomStateManager.ts +172 -0
- package/core/server/live/StateSignature.ts +643 -643
- package/core/server/live/WebSocketConnectionManager.ts +30 -19
- package/core/server/live/auto-generated-components.ts +21 -9
- package/core/server/live/index.ts +14 -0
- package/core/server/live/websocket-plugin.ts +214 -67
- package/core/server/middleware/elysia-helpers.ts +7 -2
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +180 -180
- package/core/server/plugins/static-files-plugin.ts +69 -69
- package/core/server/plugins/swagger.ts +1 -1
- package/core/server/rooms/RoomBroadcaster.ts +357 -0
- package/core/server/rooms/RoomSystem.ts +463 -0
- package/core/server/rooms/index.ts +13 -0
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +12 -12
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/build.ts +219 -219
- package/core/types/config.ts +56 -26
- package/core/types/index.ts +4 -4
- package/core/types/plugin.ts +107 -107
- package/core/types/types.ts +353 -14
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +2 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +36 -1
- package/core/utils/errors/index.ts +49 -5
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +6 -16
- package/core/utils/index.ts +17 -17
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +13 -9
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +6 -1
- package/core/utils/logger/stack-trace.ts +3 -1
- package/core/utils/logger/startup-banner.ts +82 -82
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +66 -66
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +8 -7
- package/package.json +12 -13
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
- 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/config/index.ts +1 -1
- package/plugins/crypto-auth/index.ts +4 -4
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/index.ts +21 -21
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/tsconfig.api-strict.json +16 -0
- package/tsconfig.json +48 -52
- package/{app/client/tsconfig.node.json → tsconfig.node.json} +25 -25
- package/types/global.d.ts +29 -29
- package/types/vitest.d.ts +8 -8
- package/vite.config.ts +38 -62
- package/vitest.config.live.ts +10 -9
- package/vitest.config.ts +29 -17
- package/app/client/README.md +0 -69
- package/app/client/SIMPLIFICATION.md +0 -140
- package/app/client/frontend-only.ts +0 -12
- package/app/client/src/live/FileUploadExample.tsx +0 -359
- package/app/client/src/live/MinimalLiveClock.tsx +0 -47
- package/app/client/src/live/QuickUploadTest.tsx +0 -193
- package/app/client/tsconfig.app.json +0 -45
- package/app/client/tsconfig.json +0 -7
- package/app/client/zustand-setup.md +0 -65
- package/app/server/backend-only.ts +0 -18
- package/app/server/live/LiveClockComponent.ts +0 -215
- package/app/server/live/LiveFileUploadComponent.ts +0 -77
- package/app/server/routes/env-test.ts +0 -110
- package/core/client/hooks/index.ts +0 -7
- package/core/client/hooks/useHybridLiveComponent.ts +0 -685
- package/core/client/hooks/useTypedLiveComponent.ts +0 -133
- package/core/client/hooks/useWebSocket.ts +0 -361
- package/core/config/env.ts +0 -546
- package/core/config/loader.ts +0 -522
- package/core/config/runtime-config.ts +0 -327
- package/core/config/validator.ts +0 -540
- package/core/server/backend-entry.ts +0 -51
- package/core/server/standalone.ts +0 -106
- package/core/utils/regenerate-files.ts +0 -69
- package/fluxstack.config.ts +0 -354
package/core/framework/client.ts
CHANGED
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FluxStack Client Framework Utilities
|
|
3
|
-
* Provides client-side utilities and integrations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { FluxStackConfig } from "../types"
|
|
7
|
-
|
|
8
|
-
export interface ClientFrameworkOptions {
|
|
9
|
-
config: FluxStackConfig
|
|
10
|
-
baseUrl?: string
|
|
11
|
-
timeout?: number
|
|
12
|
-
retries?: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export class FluxStackClient {
|
|
16
|
-
private config: FluxStackConfig
|
|
17
|
-
private baseUrl: string
|
|
18
|
-
private timeout: number
|
|
19
|
-
private retries: number
|
|
20
|
-
|
|
21
|
-
constructor(options: ClientFrameworkOptions) {
|
|
22
|
-
this.config = options.config
|
|
23
|
-
this.baseUrl = options.baseUrl || `http://localhost:${options.config.server.port}`
|
|
24
|
-
this.timeout = options.timeout || 10000
|
|
25
|
-
this.retries = options.retries || 3
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Create a configured fetch client
|
|
29
|
-
createFetchClient() {
|
|
30
|
-
return async (url: string, options: RequestInit = {}) => {
|
|
31
|
-
const fullUrl = url.startsWith('http') ? url : `${this.baseUrl}${url}`
|
|
32
|
-
|
|
33
|
-
const requestOptions: RequestInit = {
|
|
34
|
-
...options,
|
|
35
|
-
headers: {
|
|
36
|
-
'Content-Type': 'application/json',
|
|
37
|
-
...options.headers
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Add timeout
|
|
42
|
-
const controller = new AbortController()
|
|
43
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout)
|
|
44
|
-
requestOptions.signal = controller.signal
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const response = await fetch(fullUrl, requestOptions)
|
|
48
|
-
clearTimeout(timeoutId)
|
|
49
|
-
|
|
50
|
-
if (!response.ok) {
|
|
51
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return response
|
|
55
|
-
} catch (error) {
|
|
56
|
-
clearTimeout(timeoutId)
|
|
57
|
-
throw error
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Create API client with retry logic
|
|
63
|
-
createApiClient() {
|
|
64
|
-
const fetchClient = this.createFetchClient()
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
get: async <T>(url: string): Promise<T> => {
|
|
68
|
-
return this.withRetry(async () => {
|
|
69
|
-
const response = await fetchClient(url, { method: 'GET' })
|
|
70
|
-
return response.json()
|
|
71
|
-
})
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
post: async <T>(url: string, data: any): Promise<T> => {
|
|
75
|
-
return this.withRetry(async () => {
|
|
76
|
-
const response = await fetchClient(url, {
|
|
77
|
-
method: 'POST',
|
|
78
|
-
body: JSON.stringify(data)
|
|
79
|
-
})
|
|
80
|
-
return response.json()
|
|
81
|
-
})
|
|
82
|
-
},
|
|
83
|
-
|
|
84
|
-
put: async <T>(url: string, data: any): Promise<T> => {
|
|
85
|
-
return this.withRetry(async () => {
|
|
86
|
-
const response = await fetchClient(url, {
|
|
87
|
-
method: 'PUT',
|
|
88
|
-
body: JSON.stringify(data)
|
|
89
|
-
})
|
|
90
|
-
return response.json()
|
|
91
|
-
})
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
delete: async <T>(url: string): Promise<T> => {
|
|
95
|
-
return this.withRetry(async () => {
|
|
96
|
-
const response = await fetchClient(url, { method: 'DELETE' })
|
|
97
|
-
return response.json()
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private async withRetry<T>(fn: () => Promise<T>): Promise<T> {
|
|
104
|
-
let lastError: Error
|
|
105
|
-
|
|
106
|
-
for (let attempt = 1; attempt <= this.retries; attempt++) {
|
|
107
|
-
try {
|
|
108
|
-
return await fn()
|
|
109
|
-
} catch (error) {
|
|
110
|
-
lastError = error as Error
|
|
111
|
-
|
|
112
|
-
if (attempt === this.retries) {
|
|
113
|
-
throw lastError
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Exponential backoff
|
|
117
|
-
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000)
|
|
118
|
-
await new Promise(resolve => setTimeout(resolve, delay))
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
throw lastError!
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
getConfig(): FluxStackConfig {
|
|
126
|
-
return this.config
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
getBaseUrl(): string {
|
|
130
|
-
return this.baseUrl
|
|
131
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* FluxStack Client Framework Utilities
|
|
3
|
+
* Provides client-side utilities and integrations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { FluxStackConfig } from "../types"
|
|
7
|
+
|
|
8
|
+
export interface ClientFrameworkOptions {
|
|
9
|
+
config: FluxStackConfig
|
|
10
|
+
baseUrl?: string
|
|
11
|
+
timeout?: number
|
|
12
|
+
retries?: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class FluxStackClient {
|
|
16
|
+
private config: FluxStackConfig
|
|
17
|
+
private baseUrl: string
|
|
18
|
+
private timeout: number
|
|
19
|
+
private retries: number
|
|
20
|
+
|
|
21
|
+
constructor(options: ClientFrameworkOptions) {
|
|
22
|
+
this.config = options.config
|
|
23
|
+
this.baseUrl = options.baseUrl || `http://localhost:${options.config.server.port}`
|
|
24
|
+
this.timeout = options.timeout || 10000
|
|
25
|
+
this.retries = options.retries || 3
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Create a configured fetch client
|
|
29
|
+
createFetchClient() {
|
|
30
|
+
return async (url: string, options: RequestInit = {}) => {
|
|
31
|
+
const fullUrl = url.startsWith('http') ? url : `${this.baseUrl}${url}`
|
|
32
|
+
|
|
33
|
+
const requestOptions: RequestInit = {
|
|
34
|
+
...options,
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
...options.headers
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Add timeout
|
|
42
|
+
const controller = new AbortController()
|
|
43
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout)
|
|
44
|
+
requestOptions.signal = controller.signal
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const response = await fetch(fullUrl, requestOptions)
|
|
48
|
+
clearTimeout(timeoutId)
|
|
49
|
+
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return response
|
|
55
|
+
} catch (error) {
|
|
56
|
+
clearTimeout(timeoutId)
|
|
57
|
+
throw error
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Create API client with retry logic
|
|
63
|
+
createApiClient() {
|
|
64
|
+
const fetchClient = this.createFetchClient()
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
get: async <T>(url: string): Promise<T> => {
|
|
68
|
+
return this.withRetry(async () => {
|
|
69
|
+
const response = await fetchClient(url, { method: 'GET' })
|
|
70
|
+
return response.json()
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
post: async <T>(url: string, data: any): Promise<T> => {
|
|
75
|
+
return this.withRetry(async () => {
|
|
76
|
+
const response = await fetchClient(url, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
body: JSON.stringify(data)
|
|
79
|
+
})
|
|
80
|
+
return response.json()
|
|
81
|
+
})
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
put: async <T>(url: string, data: any): Promise<T> => {
|
|
85
|
+
return this.withRetry(async () => {
|
|
86
|
+
const response = await fetchClient(url, {
|
|
87
|
+
method: 'PUT',
|
|
88
|
+
body: JSON.stringify(data)
|
|
89
|
+
})
|
|
90
|
+
return response.json()
|
|
91
|
+
})
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
delete: async <T>(url: string): Promise<T> => {
|
|
95
|
+
return this.withRetry(async () => {
|
|
96
|
+
const response = await fetchClient(url, { method: 'DELETE' })
|
|
97
|
+
return response.json()
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private async withRetry<T>(fn: () => Promise<T>): Promise<T> {
|
|
104
|
+
let lastError: Error
|
|
105
|
+
|
|
106
|
+
for (let attempt = 1; attempt <= this.retries; attempt++) {
|
|
107
|
+
try {
|
|
108
|
+
return await fn()
|
|
109
|
+
} catch (error) {
|
|
110
|
+
lastError = error as Error
|
|
111
|
+
|
|
112
|
+
if (attempt === this.retries) {
|
|
113
|
+
throw lastError
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Exponential backoff
|
|
117
|
+
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000)
|
|
118
|
+
await new Promise(resolve => setTimeout(resolve, delay))
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
throw lastError!
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
getConfig(): FluxStackConfig {
|
|
126
|
+
return this.config
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
getBaseUrl(): string {
|
|
130
|
+
return this.baseUrl
|
|
131
|
+
}
|
|
132
132
|
}
|
package/core/framework/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FluxStack Framework Core
|
|
3
|
-
* Main exports for the framework components
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export { FluxStackFramework } from "./server"
|
|
7
|
-
export { FluxStackClient } from "./client"
|
|
1
|
+
/**
|
|
2
|
+
* FluxStack Framework Core
|
|
3
|
+
* Main exports for the framework components
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { FluxStackFramework } from "./server"
|
|
7
|
+
export { FluxStackClient } from "./client"
|
|
8
8
|
export * from "./types"
|
package/core/framework/server.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Elysia } from "elysia"
|
|
2
|
-
import type { FluxStackConfig, FluxStackContext } from "
|
|
3
|
-
import type { FluxStack, PluginContext, PluginUtils } from "
|
|
4
|
-
import { PluginRegistry } from "
|
|
5
|
-
import { PluginManager } from "
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
2
|
+
import type { FluxStackConfig, FluxStackContext } from "@core/types"
|
|
3
|
+
import type { FluxStack, PluginContext, PluginUtils } from "@core/plugins/types"
|
|
4
|
+
import { PluginRegistry } from "@core/plugins/registry"
|
|
5
|
+
import { PluginManager } from "@core/plugins/manager"
|
|
6
|
+
import { fluxStackConfig } from "@config"
|
|
7
|
+
import { getEnvironmentInfo } from "@core/config"
|
|
8
|
+
import { logger } from "@core/utils/logger"
|
|
9
|
+
import { displayStartupBanner, type StartupInfo } from "@core/utils/logger/startup-banner"
|
|
10
|
+
import { componentRegistry } from "@core/server/live/ComponentRegistry"
|
|
11
|
+
import { FluxStackError } from "@core/utils/errors"
|
|
12
|
+
import { createTimer, formatBytes, isProduction, isDevelopment } from "@core/utils/helpers"
|
|
13
|
+
import type { Plugin } from "@core/plugins"
|
|
13
14
|
|
|
14
15
|
export class FluxStackFramework {
|
|
15
16
|
private app: Elysia
|
|
@@ -37,7 +38,7 @@ export class FluxStackFramework {
|
|
|
37
38
|
|
|
38
39
|
constructor(config?: Partial<FluxStackConfig>) {
|
|
39
40
|
// Load the full configuration
|
|
40
|
-
const fullConfig = config ? { ...
|
|
41
|
+
const fullConfig = config ? { ...fluxStackConfig, ...config } : fluxStackConfig
|
|
41
42
|
const envInfo = getEnvironmentInfo()
|
|
42
43
|
|
|
43
44
|
this.context = {
|
|
@@ -203,7 +204,7 @@ export class FluxStackFramework {
|
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
private setupCors() {
|
|
206
|
-
const
|
|
207
|
+
const cors = this.context.config.cors
|
|
207
208
|
|
|
208
209
|
this.app
|
|
209
210
|
.onRequest(({ set }) => {
|
|
@@ -283,9 +284,9 @@ export class FluxStackFramework {
|
|
|
283
284
|
|
|
284
285
|
// Pass through all other stderr output
|
|
285
286
|
if (typeof encoding === 'function') {
|
|
286
|
-
return originalStderrWrite.call(process.stderr, chunk, encoding)
|
|
287
|
+
return (originalStderrWrite as Function).call(process.stderr, chunk, encoding)
|
|
287
288
|
} else {
|
|
288
|
-
return originalStderrWrite.call(process.stderr, chunk, encoding, callback)
|
|
289
|
+
return (originalStderrWrite as Function).call(process.stderr, chunk, encoding, callback)
|
|
289
290
|
}
|
|
290
291
|
}
|
|
291
292
|
|
|
@@ -450,47 +451,53 @@ export class FluxStackFramework {
|
|
|
450
451
|
}
|
|
451
452
|
|
|
452
453
|
private setupErrorHandling() {
|
|
453
|
-
|
|
454
|
-
logger: this.pluginContext.logger,
|
|
455
|
-
isDevelopment: this.context.isDevelopment
|
|
456
|
-
})
|
|
457
|
-
|
|
458
|
-
this.app.onError(async ({ error, request, path, set }) => {
|
|
459
|
-
const startTime = Date.now()
|
|
454
|
+
this.app.onError(async ({ error, request, code, set }) => {
|
|
460
455
|
const url = this.parseRequestURL(request)
|
|
461
456
|
|
|
457
|
+
// Let plugins handle errors first (e.g. Vite SPA fallback)
|
|
462
458
|
const errorContext = {
|
|
463
459
|
request,
|
|
464
460
|
path: url.pathname,
|
|
465
461
|
method: request.method,
|
|
466
|
-
headers: (() => {
|
|
467
|
-
const headers: Record<string, string> = {}
|
|
468
|
-
request.headers.forEach((value: string, key: string) => {
|
|
469
|
-
headers[key] = value
|
|
470
|
-
})
|
|
471
|
-
return headers
|
|
472
|
-
})(),
|
|
473
|
-
query: Object.fromEntries(url.searchParams.entries()),
|
|
474
|
-
params: {},
|
|
475
462
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
476
|
-
duration: Date.now() - startTime,
|
|
477
463
|
handled: false,
|
|
478
|
-
startTime
|
|
464
|
+
startTime: Date.now()
|
|
479
465
|
}
|
|
480
466
|
|
|
481
|
-
// Execute onError hooks for all plugins - allow them to handle the error
|
|
482
467
|
const handledResponse = await this.executePluginErrorHooks(errorContext)
|
|
483
|
-
|
|
484
|
-
// If a plugin handled the error, return the response
|
|
485
468
|
if (handledResponse) {
|
|
486
469
|
return handledResponse
|
|
487
470
|
}
|
|
488
471
|
|
|
489
|
-
//
|
|
472
|
+
// For Elysia's own errors (validation, not found, parse), let them pass through
|
|
473
|
+
// Elysia sets proper status codes and messages natively
|
|
474
|
+
if (code === 'VALIDATION' || code === 'PARSE' || code === 'NOT_FOUND') {
|
|
475
|
+
return
|
|
476
|
+
}
|
|
490
477
|
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
|
|
478
|
+
// For FluxStackErrors, use their status code and message
|
|
479
|
+
if (error instanceof FluxStackError) {
|
|
480
|
+
set.status = error.statusCode
|
|
481
|
+
return {
|
|
482
|
+
error: error.code,
|
|
483
|
+
message: error.userMessage || error.message,
|
|
484
|
+
...(this.context.isDevelopment && { stack: error.stack })
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Log unexpected errors (actual 500s)
|
|
489
|
+
logger.error(`Unhandled error: ${error instanceof Error ? error.message : String(error)}`, {
|
|
490
|
+
path: url.pathname,
|
|
491
|
+
method: request.method
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
set.status = 500
|
|
495
|
+
return {
|
|
496
|
+
error: 'INTERNAL_SERVER_ERROR',
|
|
497
|
+
message: this.context.isDevelopment
|
|
498
|
+
? (error instanceof Error ? error.message : String(error))
|
|
499
|
+
: 'An unexpected error occurred'
|
|
500
|
+
}
|
|
494
501
|
})
|
|
495
502
|
}
|
|
496
503
|
|
package/core/framework/types.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Defines the main interfaces and types for the FluxStack framework
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { FluxStackConfig } from "
|
|
7
|
-
import type { Logger } from "
|
|
6
|
+
import type { FluxStackConfig } from "@core/types"
|
|
7
|
+
import type { Logger } from "@core/utils/logger/index"
|
|
8
8
|
|
|
9
9
|
export interface FluxStackFrameworkOptions {
|
|
10
10
|
config?: Partial<FluxStackConfig>
|
package/core/index.ts
CHANGED
|
@@ -28,9 +28,28 @@ export { PluginDiscovery, pluginDiscovery } from './plugins/discovery'
|
|
|
28
28
|
export { PluginManager } from './plugins/manager'
|
|
29
29
|
export { PluginUtils } from './plugins'
|
|
30
30
|
|
|
31
|
-
// Utilities
|
|
32
|
-
export
|
|
33
|
-
|
|
31
|
+
// Utilities (avoid wildcard export to prevent type duplication)
|
|
32
|
+
export {
|
|
33
|
+
LOGGER_CONFIG,
|
|
34
|
+
LOG,
|
|
35
|
+
WARN,
|
|
36
|
+
ERROR,
|
|
37
|
+
DEBUG,
|
|
38
|
+
START,
|
|
39
|
+
SUCCESS,
|
|
40
|
+
IMPORTANT,
|
|
41
|
+
SECTION,
|
|
42
|
+
request as logRequest,
|
|
43
|
+
plugin as logPlugin,
|
|
44
|
+
framework as logFramework,
|
|
45
|
+
time as logTime,
|
|
46
|
+
timeEnd as logTimeEnd,
|
|
47
|
+
clearCache as clearLoggerCache,
|
|
48
|
+
logger,
|
|
49
|
+
log
|
|
50
|
+
} from './utils/logger'
|
|
51
|
+
export type { Logger } from './utils/logger'
|
|
52
|
+
// Note: BuildError types already exported via ./server
|
|
34
53
|
|
|
35
54
|
// Version
|
|
36
|
-
export { FLUXSTACK_VERSION } from './utils/version'
|
|
55
|
+
export { FLUXSTACK_VERSION } from './utils/version'
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
BroadcastMessage,
|
|
7
7
|
ComponentDefinition,
|
|
8
8
|
WebSocketData
|
|
9
|
-
} from '
|
|
9
|
+
} from '@core/types/types'
|
|
10
10
|
|
|
11
11
|
export class ComponentRegistry {
|
|
12
12
|
private components = new Map<string, LiveComponent>()
|
|
@@ -17,7 +17,7 @@ export class ComponentRegistry {
|
|
|
17
17
|
|
|
18
18
|
// Register component definition
|
|
19
19
|
registerComponent<TState>(definition: ComponentDefinition<TState>) {
|
|
20
|
-
this.definitions.set(definition.name, definition)
|
|
20
|
+
this.definitions.set(definition.name, definition as unknown as ComponentDefinition)
|
|
21
21
|
console.log(`📝 Registered component: ${definition.name}`)
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -35,7 +35,7 @@ export class ComponentRegistry {
|
|
|
35
35
|
|
|
36
36
|
if (!fs.existsSync(componentsPath)) {
|
|
37
37
|
// In production, components are already bundled - no need to auto-discover
|
|
38
|
-
const { appConfig } = await import('
|
|
38
|
+
const { appConfig } = await import('@config')
|
|
39
39
|
if (appConfig.env !== 'production') {
|
|
40
40
|
console.log(`⚠️ Components path not found: ${componentsPath}`)
|
|
41
41
|
}
|
package/core/live/types.ts
CHANGED
|
@@ -150,6 +150,83 @@ export abstract class LiveComponent<TState = ComponentState> {
|
|
|
150
150
|
public getSerializableState(): TState {
|
|
151
151
|
return this.state
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
// ===== Livewire-style Actions =====
|
|
155
|
+
// These are automatically available for all LiveComponents
|
|
156
|
+
// Used by useLivewire() hook for transparent property access
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Set a single state property value
|
|
160
|
+
* Used by useLivewire() proxy for transparent property assignment
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* // Frontend with useLivewire:
|
|
164
|
+
* clock.format = '12h' // Automatically calls setValue({ key: 'format', value: '12h' })
|
|
165
|
+
*/
|
|
166
|
+
async setValue<K extends keyof TState>(payload: { key: K; value: TState[K] }): Promise<{ success: boolean; key: K; value: TState[K] }> {
|
|
167
|
+
const { key, value } = payload
|
|
168
|
+
|
|
169
|
+
// Validate that the key exists in state
|
|
170
|
+
const stateObj = this.state as Record<string, unknown>
|
|
171
|
+
if (!(String(key) in stateObj)) {
|
|
172
|
+
throw new Error(`Property '${String(key)}' does not exist in component state`)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.setState({ [key]: value } as unknown as Partial<TState>)
|
|
176
|
+
|
|
177
|
+
return { success: true, key, value }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Set multiple state properties at once
|
|
182
|
+
* Useful for batch updates
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* await clock.$call('setValues', { format: '12h', showSeconds: false })
|
|
186
|
+
*/
|
|
187
|
+
async setValues(payload: Partial<TState>): Promise<{ success: boolean; updated: (keyof TState)[] }> {
|
|
188
|
+
const stateObj = this.state as Record<string, unknown>
|
|
189
|
+
const validKeys = Object.keys(payload).filter(key => key in stateObj) as (keyof TState)[]
|
|
190
|
+
|
|
191
|
+
if (validKeys.length === 0) {
|
|
192
|
+
throw new Error('No valid properties to update')
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const updates = validKeys.reduce((acc, key) => {
|
|
196
|
+
acc[key] = payload[key] as TState[keyof TState]
|
|
197
|
+
return acc
|
|
198
|
+
}, {} as Partial<TState>)
|
|
199
|
+
|
|
200
|
+
this.setState(updates)
|
|
201
|
+
|
|
202
|
+
return { success: true, updated: validKeys }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get a single state property value
|
|
207
|
+
* Useful for getting computed/derived values from server
|
|
208
|
+
*/
|
|
209
|
+
async getValue<K extends keyof TState>(payload: { key: K }): Promise<{ success: boolean; key: K; value: TState[K] }> {
|
|
210
|
+
const { key } = payload
|
|
211
|
+
|
|
212
|
+
const stateObj = this.state as Record<string, unknown>
|
|
213
|
+
if (!(String(key) in stateObj)) {
|
|
214
|
+
throw new Error(`Property '${String(key)}' does not exist in component state`)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { success: true, key, value: this.state[key] }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get all state values (snapshot)
|
|
222
|
+
*/
|
|
223
|
+
async getSnapshot(): Promise<{ success: boolean; state: TState; timestamp: number }> {
|
|
224
|
+
return {
|
|
225
|
+
success: true,
|
|
226
|
+
state: this.getSerializableState(),
|
|
227
|
+
timestamp: Date.now()
|
|
228
|
+
}
|
|
229
|
+
}
|
|
153
230
|
}
|
|
154
231
|
|
|
155
232
|
// Utility types for better TypeScript experience
|