create-fluxstack 1.10.1 → 1.12.1
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 +161 -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 +127 -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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { existsSync } from 'fs'
|
|
2
2
|
import { join } from 'path'
|
|
3
|
-
import type { FluxStack } from '
|
|
3
|
+
import type { FluxStack } from '@core/plugins/types'
|
|
4
4
|
import { cliRegistry } from './command-registry'
|
|
5
|
-
import { logger } from '
|
|
5
|
+
import { logger } from '@core/utils/logger'
|
|
6
6
|
|
|
7
7
|
export class CliPluginDiscovery {
|
|
8
8
|
private loadedPlugins = new Set<string>()
|
|
@@ -16,6 +16,9 @@ export interface LiveComponentsContextValue {
|
|
|
16
16
|
// Send message and wait for specific response
|
|
17
17
|
sendMessageAndWait: (message: WebSocketMessage, timeout?: number) => Promise<WebSocketResponse>
|
|
18
18
|
|
|
19
|
+
// Send binary data and wait for response (for file uploads)
|
|
20
|
+
sendBinaryAndWait: (data: ArrayBuffer, requestId: string, timeout?: number) => Promise<WebSocketResponse>
|
|
21
|
+
|
|
19
22
|
// Register message listener for a component
|
|
20
23
|
registerComponent: (componentId: string, callback: (message: WebSocketResponse) => void) => () => void
|
|
21
24
|
|
|
@@ -155,6 +158,25 @@ export function LiveComponentsProvider({
|
|
|
155
158
|
return
|
|
156
159
|
}
|
|
157
160
|
|
|
161
|
+
// Broadcast messages should go to ALL components (not just sender)
|
|
162
|
+
if (response.type === 'BROADCAST') {
|
|
163
|
+
// Send to all registered components in the same room
|
|
164
|
+
const registeredComponents = Array.from(componentCallbacksRef.current.keys())
|
|
165
|
+
log('📡 Broadcast routing:', {
|
|
166
|
+
sender: response.componentId,
|
|
167
|
+
registeredComponents,
|
|
168
|
+
totalRegistered: registeredComponents.length
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
componentCallbacksRef.current.forEach((callback, compId) => {
|
|
172
|
+
// Don't send back to the sender component
|
|
173
|
+
if (compId !== response.componentId) {
|
|
174
|
+
callback(response)
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
|
|
158
180
|
// Route message to specific component
|
|
159
181
|
if (response.componentId) {
|
|
160
182
|
const callback = componentCallbacksRef.current.get(response.componentId)
|
|
@@ -165,14 +187,6 @@ export function LiveComponentsProvider({
|
|
|
165
187
|
}
|
|
166
188
|
}
|
|
167
189
|
|
|
168
|
-
// Broadcast messages (no specific componentId)
|
|
169
|
-
if (response.type === 'BROADCAST' && !response.componentId) {
|
|
170
|
-
// Send to all registered components
|
|
171
|
-
componentCallbacksRef.current.forEach(callback => {
|
|
172
|
-
callback(response)
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
|
|
176
190
|
} catch (error) {
|
|
177
191
|
log('❌ Failed to parse message', error)
|
|
178
192
|
setError('Failed to parse message')
|
|
@@ -331,6 +345,43 @@ export function LiveComponentsProvider({
|
|
|
331
345
|
})
|
|
332
346
|
}, [log, generateRequestId])
|
|
333
347
|
|
|
348
|
+
// Send binary data and wait for response (for file uploads)
|
|
349
|
+
const sendBinaryAndWait = useCallback(async (
|
|
350
|
+
data: ArrayBuffer,
|
|
351
|
+
requestId: string,
|
|
352
|
+
timeout: number = 10000
|
|
353
|
+
): Promise<WebSocketResponse> => {
|
|
354
|
+
return new Promise((resolve, reject) => {
|
|
355
|
+
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
|
|
356
|
+
reject(new Error('WebSocket is not connected'))
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Set up timeout
|
|
361
|
+
const timeoutHandle = setTimeout(() => {
|
|
362
|
+
pendingRequestsRef.current.delete(requestId)
|
|
363
|
+
reject(new Error(`Binary request timeout after ${timeout}ms`))
|
|
364
|
+
}, timeout)
|
|
365
|
+
|
|
366
|
+
// Store pending request
|
|
367
|
+
pendingRequestsRef.current.set(requestId, {
|
|
368
|
+
resolve,
|
|
369
|
+
reject,
|
|
370
|
+
timeout: timeoutHandle
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
// Send as binary frame
|
|
375
|
+
wsRef.current.send(data)
|
|
376
|
+
log('📤 Sent binary data', { requestId, size: data.byteLength })
|
|
377
|
+
} catch (error) {
|
|
378
|
+
clearTimeout(timeoutHandle)
|
|
379
|
+
pendingRequestsRef.current.delete(requestId)
|
|
380
|
+
reject(error)
|
|
381
|
+
}
|
|
382
|
+
})
|
|
383
|
+
}, [log])
|
|
384
|
+
|
|
334
385
|
// Register component callback
|
|
335
386
|
const registerComponent = useCallback((
|
|
336
387
|
componentId: string,
|
|
@@ -375,6 +426,7 @@ export function LiveComponentsProvider({
|
|
|
375
426
|
connectionId,
|
|
376
427
|
sendMessage,
|
|
377
428
|
sendMessageAndWait,
|
|
429
|
+
sendBinaryAndWait,
|
|
378
430
|
registerComponent,
|
|
379
431
|
unregisterComponent,
|
|
380
432
|
reconnect,
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eden Treaty Client Factory
|
|
3
|
+
* Creates a type-safe API client with sensible defaults
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { treaty, type Treaty } from '@elysiajs/eden'
|
|
7
|
+
import type { Elysia } from 'elysia'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Any Elysia application type
|
|
11
|
+
* Used as constraint for the createEdenClient generic
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
type AnyElysiaApp = Elysia<any, any, any, any, any, any, any>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Configuration options for the Eden client
|
|
18
|
+
*/
|
|
19
|
+
export interface EdenClientOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Custom function to get the base URL
|
|
22
|
+
* @default Uses window.location.origin or 'http://localhost:3000'
|
|
23
|
+
*/
|
|
24
|
+
getBaseUrl?: () => string
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Custom function to get the auth token
|
|
28
|
+
* @default Reads from localStorage.getItem('accessToken')
|
|
29
|
+
*/
|
|
30
|
+
getAuthToken?: () => string | null
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Callback when a 401 Unauthorized response is received
|
|
34
|
+
* @default Removes accessToken from localStorage
|
|
35
|
+
*/
|
|
36
|
+
onUnauthorized?: () => void
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Enable request/response logging in development
|
|
40
|
+
* @default true in development, false in production
|
|
41
|
+
*/
|
|
42
|
+
enableLogging?: boolean
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* localStorage key for the access token
|
|
46
|
+
* @default 'accessToken'
|
|
47
|
+
*/
|
|
48
|
+
tokenKey?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Default base URL getter
|
|
53
|
+
*/
|
|
54
|
+
export function getDefaultBaseUrl(): string {
|
|
55
|
+
if (typeof window === 'undefined') return 'http://localhost:3000'
|
|
56
|
+
return window.location.origin
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create a default auth token getter
|
|
61
|
+
*/
|
|
62
|
+
function createDefaultGetAuthToken(tokenKey: string): () => string | null {
|
|
63
|
+
return () => {
|
|
64
|
+
if (typeof window === 'undefined') return null
|
|
65
|
+
return localStorage.getItem(tokenKey)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create a default unauthorized handler
|
|
71
|
+
*/
|
|
72
|
+
function createDefaultOnUnauthorized(tokenKey: string): () => void {
|
|
73
|
+
return () => {
|
|
74
|
+
if (typeof window !== 'undefined') {
|
|
75
|
+
console.warn('🔒 Token expired')
|
|
76
|
+
localStorage.removeItem(tokenKey)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Check if we're in development mode
|
|
83
|
+
*/
|
|
84
|
+
function isDev(): boolean {
|
|
85
|
+
try {
|
|
86
|
+
return import.meta.env?.DEV ?? false
|
|
87
|
+
} catch {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Create an Eden Treaty client with authentication and logging
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* import { createEdenClient } from '@core/client/api/eden'
|
|
98
|
+
* import type { App } from '@server/app'
|
|
99
|
+
*
|
|
100
|
+
* // Basic usage
|
|
101
|
+
* export const api = createEdenClient<App>()
|
|
102
|
+
*
|
|
103
|
+
* // With custom options
|
|
104
|
+
* export const api = createEdenClient<App>({
|
|
105
|
+
* onUnauthorized: () => {
|
|
106
|
+
* window.location.href = '/login'
|
|
107
|
+
* }
|
|
108
|
+
* })
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function createEdenClient<TApp extends AnyElysiaApp>(
|
|
112
|
+
options: EdenClientOptions = {}
|
|
113
|
+
) {
|
|
114
|
+
const {
|
|
115
|
+
getBaseUrl = getDefaultBaseUrl,
|
|
116
|
+
tokenKey = 'accessToken',
|
|
117
|
+
enableLogging = isDev(),
|
|
118
|
+
} = options
|
|
119
|
+
|
|
120
|
+
const getAuthToken = options.getAuthToken ?? createDefaultGetAuthToken(tokenKey)
|
|
121
|
+
const onUnauthorized = options.onUnauthorized ?? createDefaultOnUnauthorized(tokenKey)
|
|
122
|
+
|
|
123
|
+
const client = treaty<TApp>(getBaseUrl(), {
|
|
124
|
+
// Dynamic headers for every request
|
|
125
|
+
headers(_path, _options) {
|
|
126
|
+
const token = getAuthToken()
|
|
127
|
+
return token ? { Authorization: `Bearer ${token}` } : undefined
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
// Custom fetcher with logging and error handling
|
|
131
|
+
fetcher: (async (url: string | URL | Request, init?: RequestInit) => {
|
|
132
|
+
if (enableLogging) {
|
|
133
|
+
console.log(`🌐 ${init?.method ?? 'GET'} ${url}`)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const res = await fetch(url, init)
|
|
137
|
+
|
|
138
|
+
if (enableLogging) {
|
|
139
|
+
console.log(`📡 ${url} → ${res.status}`)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Handle 401 Unauthorized
|
|
143
|
+
if (res.status === 401) {
|
|
144
|
+
onUnauthorized()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return res
|
|
148
|
+
}) as typeof fetch
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// Return the .api property for direct access to endpoints
|
|
152
|
+
// Type inference works automatically from the TApp generic
|
|
153
|
+
return client.api as Treaty.Create<TApp>['api']
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Extract user-friendly error message from Eden Treaty errors
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const { data, error } = await api.users.get()
|
|
162
|
+
* if (error) {
|
|
163
|
+
* toast.error(getErrorMessage(error))
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export function getErrorMessage(error: unknown): string {
|
|
168
|
+
// Eden Treaty error format
|
|
169
|
+
if (error && typeof error === 'object' && 'value' in error) {
|
|
170
|
+
const edenError = error as { value?: { message?: string; userMessage?: string } }
|
|
171
|
+
return edenError.value?.userMessage || edenError.value?.message || 'An error occurred'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Standard Error
|
|
175
|
+
if (error instanceof Error) {
|
|
176
|
+
return error.message
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return 'An unexpected error occurred'
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Re-export treaty for advanced usage
|
|
183
|
+
export { treaty } from '@elysiajs/eden'
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// 🔥 FluxStack Live - Hook para componentes real-time
|
|
2
|
+
//
|
|
3
|
+
// Uso:
|
|
4
|
+
// import { Live } from '@/core/client'
|
|
5
|
+
// import { LiveForm } from '@server/live/LiveForm'
|
|
6
|
+
//
|
|
7
|
+
// // Sem estado inicial - usa defaultState do componente
|
|
8
|
+
// const form = Live.use(LiveForm)
|
|
9
|
+
//
|
|
10
|
+
// // Com estado inicial parcial (override)
|
|
11
|
+
// const form = Live.use(LiveForm, { name: 'João' })
|
|
12
|
+
//
|
|
13
|
+
// return (
|
|
14
|
+
// <input {...form.$field('name', { syncOn: 'blur' })} />
|
|
15
|
+
// <button onClick={() => form.submit()}>Enviar</button>
|
|
16
|
+
// )
|
|
17
|
+
//
|
|
18
|
+
// 🔥 Broadcasts Tipados (Discriminated Union):
|
|
19
|
+
// // No servidor, defina a interface de broadcasts:
|
|
20
|
+
// export interface LiveFormBroadcasts {
|
|
21
|
+
// FORM_SUBMITTED: { formId: string; data: any }
|
|
22
|
+
// FIELD_CHANGED: { field: string; value: any }
|
|
23
|
+
// }
|
|
24
|
+
//
|
|
25
|
+
// // No cliente, use com tipagem automática (discriminated union):
|
|
26
|
+
// import { LiveForm, type LiveFormBroadcasts } from '@server/live/LiveForm'
|
|
27
|
+
//
|
|
28
|
+
// const form = Live.use(LiveForm)
|
|
29
|
+
// form.$onBroadcast<LiveFormBroadcasts>((event) => {
|
|
30
|
+
// switch (event.type) {
|
|
31
|
+
// case 'FORM_SUBMITTED':
|
|
32
|
+
// console.log(event.data.formId) // ✅ Tipado como string!
|
|
33
|
+
// break
|
|
34
|
+
// case 'FIELD_CHANGED':
|
|
35
|
+
// console.log(event.data.field) // ✅ Tipado como string!
|
|
36
|
+
// break
|
|
37
|
+
// }
|
|
38
|
+
// })
|
|
39
|
+
|
|
40
|
+
import { useLiveComponent } from '../hooks/useLiveComponent'
|
|
41
|
+
import type { UseLiveComponentOptions, LiveProxy, LiveProxyWithBroadcasts } from '../hooks/useLiveComponent'
|
|
42
|
+
|
|
43
|
+
// ===== Tipos para Inferência do Servidor =====
|
|
44
|
+
|
|
45
|
+
// Extrai o defaultState estático da classe
|
|
46
|
+
type ExtractDefaultState<T> = T extends { defaultState: infer S }
|
|
47
|
+
? S extends Record<string, any> ? S : Record<string, any>
|
|
48
|
+
: Record<string, any>
|
|
49
|
+
|
|
50
|
+
// Extrai o State da classe do servidor (via instance.state)
|
|
51
|
+
type ExtractState<T> = T extends { new(...args: any[]): { state: infer S } }
|
|
52
|
+
? S extends Record<string, any> ? S : Record<string, any>
|
|
53
|
+
: ExtractDefaultState<T>
|
|
54
|
+
|
|
55
|
+
// Extrai as Actions (métodos públicos async) da classe do servidor
|
|
56
|
+
type ExtractActions<T> = T extends { new(...args: any[]): infer Instance }
|
|
57
|
+
? {
|
|
58
|
+
[K in keyof Instance as Instance[K] extends (...args: any[]) => Promise<any>
|
|
59
|
+
? K extends 'setState' | 'getState' | 'getValue' | 'setValue' | 'setValues' | 'getSnapshot'
|
|
60
|
+
? never
|
|
61
|
+
: K
|
|
62
|
+
: never
|
|
63
|
+
]: Instance[K]
|
|
64
|
+
}
|
|
65
|
+
: Record<string, never>
|
|
66
|
+
|
|
67
|
+
// ===== Opções do Live.use() =====
|
|
68
|
+
|
|
69
|
+
interface LiveUseOptions<TState> extends UseLiveComponentOptions {
|
|
70
|
+
/** Estado inicial para o componente */
|
|
71
|
+
initialState?: Partial<TState>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ===== Hook Principal =====
|
|
75
|
+
|
|
76
|
+
function useLive<
|
|
77
|
+
T extends { new(...args: any[]): any; defaultState?: Record<string, any>; componentName: string },
|
|
78
|
+
TBroadcasts extends Record<string, any> = Record<string, any>
|
|
79
|
+
>(
|
|
80
|
+
ComponentClass: T,
|
|
81
|
+
options?: LiveUseOptions<ExtractState<T>>
|
|
82
|
+
): LiveProxyWithBroadcasts<ExtractState<T>, ExtractActions<T>, TBroadcasts> {
|
|
83
|
+
// Use static componentName (required for production builds with minification)
|
|
84
|
+
const componentName = ComponentClass.componentName
|
|
85
|
+
|
|
86
|
+
// Usa defaultState da classe se não passar initialState
|
|
87
|
+
const defaultState = (ComponentClass as any).defaultState || {}
|
|
88
|
+
const { initialState, ...restOptions } = options || {}
|
|
89
|
+
const mergedState = { ...defaultState, ...initialState } as ExtractState<T>
|
|
90
|
+
|
|
91
|
+
return useLiveComponent<ExtractState<T>, ExtractActions<T>, TBroadcasts>(
|
|
92
|
+
componentName,
|
|
93
|
+
mergedState,
|
|
94
|
+
restOptions
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ===== Export =====
|
|
99
|
+
|
|
100
|
+
export const Live = {
|
|
101
|
+
use: useLive
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export default Live
|
package/core/client/fluxstack.ts
CHANGED
|
@@ -4,14 +4,6 @@
|
|
|
4
4
|
// Re-export everything from the main index
|
|
5
5
|
export * from './index'
|
|
6
6
|
|
|
7
|
-
// Convenience aliases for common hooks and utilities
|
|
8
|
-
export {
|
|
9
|
-
useHybridLiveComponent as useLive,
|
|
10
|
-
useWebSocket as useWS,
|
|
11
|
-
useChunkedUpload as useUpload,
|
|
12
|
-
StateValidator as Validator
|
|
13
|
-
} from './index'
|
|
14
|
-
|
|
15
7
|
// Default export for easy importing
|
|
16
8
|
import * as FluxStack from './index'
|
|
17
|
-
export default FluxStack
|
|
9
|
+
export default FluxStack
|