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
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# Type Safety Patterns
|
|
2
|
+
|
|
3
|
+
**Version:** 1.11.0 | **Updated:** 2025-02-08
|
|
4
|
+
|
|
5
|
+
## Quick Facts
|
|
6
|
+
|
|
7
|
+
- Eden Treaty provides **automatic type inference** from backend to frontend
|
|
8
|
+
- Response schemas in routes generate TypeScript types
|
|
9
|
+
- No manual type definitions needed for API calls
|
|
10
|
+
- Refactoring backend automatically updates frontend types
|
|
11
|
+
- Type errors caught at compile time, not runtime
|
|
12
|
+
|
|
13
|
+
## Eden Treaty Type Flow
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
graph LR
|
|
17
|
+
A[Backend Route] --> B[t.Object Schema]
|
|
18
|
+
B --> C[Response Type]
|
|
19
|
+
C --> D[Eden Treaty Client]
|
|
20
|
+
D --> E[Frontend api.users.get]
|
|
21
|
+
E --> F[Typed data & error]
|
|
22
|
+
|
|
23
|
+
style A fill:#e1f5ff
|
|
24
|
+
style B fill:#fff4e1
|
|
25
|
+
style C fill:#ffe1f5
|
|
26
|
+
style D fill:#e1ffe1
|
|
27
|
+
style E fill:#f5e1ff
|
|
28
|
+
style F fill:#ffe1e1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Backend Schema Definition
|
|
32
|
+
|
|
33
|
+
**Step 1: Define response schema in route**
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// app/server/routes/users.routes.ts
|
|
37
|
+
import { Elysia, t } from 'elysia'
|
|
38
|
+
|
|
39
|
+
const UserSchema = t.Object({
|
|
40
|
+
id: t.Number(),
|
|
41
|
+
name: t.String(),
|
|
42
|
+
email: t.String()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const GetUsersResponseSchema = t.Object({
|
|
46
|
+
success: t.Boolean(),
|
|
47
|
+
users: t.Array(UserSchema),
|
|
48
|
+
count: t.Number()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export const usersRoutes = new Elysia({ prefix: '/users' })
|
|
52
|
+
.get('/', async () => {
|
|
53
|
+
return {
|
|
54
|
+
success: true,
|
|
55
|
+
users: [],
|
|
56
|
+
count: 0
|
|
57
|
+
}
|
|
58
|
+
}, {
|
|
59
|
+
response: GetUsersResponseSchema // ← Type inference source
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Frontend Type Inference
|
|
64
|
+
|
|
65
|
+
**Step 2: Use Eden Treaty client**
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// app/client/src/lib/api.ts
|
|
69
|
+
import { createEdenClient } from '@core/client/api/eden'
|
|
70
|
+
import type { App } from '@server/app'
|
|
71
|
+
|
|
72
|
+
export const api = createEdenClient<App>()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Step 3: Make typed API calls**
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// app/client/src/pages/UsersPage.tsx
|
|
79
|
+
import { api } from '@/lib/api'
|
|
80
|
+
|
|
81
|
+
async function loadUsers() {
|
|
82
|
+
const { data, error } = await api.users.get()
|
|
83
|
+
|
|
84
|
+
// TypeScript knows the exact shape:
|
|
85
|
+
// data: { success: boolean, users: User[], count: number } | undefined
|
|
86
|
+
// error: Error | undefined
|
|
87
|
+
|
|
88
|
+
if (error) {
|
|
89
|
+
console.error('Failed to load users:', error)
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (data) {
|
|
94
|
+
// TypeScript knows data.users is User[]
|
|
95
|
+
console.log(`Loaded ${data.count} users`)
|
|
96
|
+
data.users.forEach(user => {
|
|
97
|
+
// TypeScript knows user has id, name, email
|
|
98
|
+
console.log(user.name, user.email)
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Type Inference Examples
|
|
105
|
+
|
|
106
|
+
### GET Request
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// Backend
|
|
110
|
+
.get('/users/:id', async ({ params }) => {
|
|
111
|
+
return {
|
|
112
|
+
success: true,
|
|
113
|
+
user: { id: 1, name: 'John', email: 'john@example.com' }
|
|
114
|
+
}
|
|
115
|
+
}, {
|
|
116
|
+
response: t.Object({
|
|
117
|
+
success: t.Boolean(),
|
|
118
|
+
user: UserSchema
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
// Frontend - automatic type inference
|
|
123
|
+
const { data } = await api.users({ id: '123' }).get()
|
|
124
|
+
// ^? { success: boolean, user: { id: number, name: string, email: string } } | undefined
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### POST Request with Body
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Backend
|
|
131
|
+
.post('/', async ({ body }) => {
|
|
132
|
+
return { success: true, user: createdUser }
|
|
133
|
+
}, {
|
|
134
|
+
body: t.Object({
|
|
135
|
+
name: t.String({ minLength: 2 }),
|
|
136
|
+
email: t.String({ format: 'email' })
|
|
137
|
+
}),
|
|
138
|
+
response: t.Object({
|
|
139
|
+
success: t.Boolean(),
|
|
140
|
+
user: UserSchema
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// Frontend - body type is inferred
|
|
145
|
+
const { data, error } = await api.users.post({
|
|
146
|
+
name: 'Jane Doe',
|
|
147
|
+
email: 'jane@example.com'
|
|
148
|
+
})
|
|
149
|
+
// TypeScript validates body matches schema
|
|
150
|
+
// TypeScript error if you pass { name: 123 } or forget email
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Multiple Status Codes
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// Backend
|
|
157
|
+
.post('/', async ({ body, set }) => {
|
|
158
|
+
if (!body.name) {
|
|
159
|
+
set.status = 400
|
|
160
|
+
return { success: false, error: 'Name required' }
|
|
161
|
+
}
|
|
162
|
+
set.status = 201
|
|
163
|
+
return { success: true, user: newUser }
|
|
164
|
+
}, {
|
|
165
|
+
body: CreateUserSchema,
|
|
166
|
+
response: {
|
|
167
|
+
201: t.Object({
|
|
168
|
+
success: t.Literal(true),
|
|
169
|
+
user: UserSchema
|
|
170
|
+
}),
|
|
171
|
+
400: t.Object({
|
|
172
|
+
success: t.Literal(false),
|
|
173
|
+
error: t.String()
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// Frontend - union type inferred
|
|
179
|
+
const { data } = await api.users.post({ name: 'John', email: 'john@example.com' })
|
|
180
|
+
// ^? { success: true, user: User } | { success: false, error: string } | undefined
|
|
181
|
+
|
|
182
|
+
// Type narrowing with discriminated union
|
|
183
|
+
if (data?.success) {
|
|
184
|
+
console.log(data.user.name) // TypeScript knows user exists
|
|
185
|
+
} else if (data) {
|
|
186
|
+
console.error(data.error) // TypeScript knows error exists
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Query Parameters
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Backend
|
|
194
|
+
.get('/', async ({ query }) => {
|
|
195
|
+
const page = Number(query.page) || 1
|
|
196
|
+
const limit = Number(query.limit) || 10
|
|
197
|
+
return { users: [], page, limit, total: 0 }
|
|
198
|
+
}, {
|
|
199
|
+
query: t.Object({
|
|
200
|
+
page: t.Optional(t.String()),
|
|
201
|
+
limit: t.Optional(t.String())
|
|
202
|
+
}),
|
|
203
|
+
response: t.Object({
|
|
204
|
+
users: t.Array(UserSchema),
|
|
205
|
+
page: t.Number(),
|
|
206
|
+
limit: t.Number(),
|
|
207
|
+
total: t.Number()
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
// Frontend - query params typed
|
|
212
|
+
const { data } = await api.users.get({
|
|
213
|
+
query: { page: '1', limit: '20' }
|
|
214
|
+
})
|
|
215
|
+
// ^? { users: User[], page: number, limit: number, total: number } | undefined
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Shared Types
|
|
219
|
+
|
|
220
|
+
For types used across client and server, define in `app/shared/types/`:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// app/shared/types/user.types.ts
|
|
224
|
+
export interface User {
|
|
225
|
+
id: number
|
|
226
|
+
name: string
|
|
227
|
+
email: string
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface CreateUserRequest {
|
|
231
|
+
name: string
|
|
232
|
+
email: string
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Use in backend:**
|
|
237
|
+
```typescript
|
|
238
|
+
import type { User, CreateUserRequest } from '@shared/types/user.types'
|
|
239
|
+
|
|
240
|
+
// Use for internal logic, not for schemas
|
|
241
|
+
async function createUser(data: CreateUserRequest): Promise<User> {
|
|
242
|
+
// ...
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Use in frontend:**
|
|
247
|
+
```typescript
|
|
248
|
+
import type { User } from '@shared/types/user.types'
|
|
249
|
+
|
|
250
|
+
function UserCard({ user }: { user: User }) {
|
|
251
|
+
return <div>{user.name}</div>
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Refactoring Safety
|
|
256
|
+
|
|
257
|
+
### Scenario: Add new field to User
|
|
258
|
+
|
|
259
|
+
**Step 1: Update backend schema**
|
|
260
|
+
```typescript
|
|
261
|
+
const UserSchema = t.Object({
|
|
262
|
+
id: t.Number(),
|
|
263
|
+
name: t.String(),
|
|
264
|
+
email: t.String(),
|
|
265
|
+
role: t.String() // ← New field
|
|
266
|
+
})
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Step 2: Frontend automatically gets type error**
|
|
270
|
+
```typescript
|
|
271
|
+
// This code now has TypeScript error:
|
|
272
|
+
function UserCard({ user }: { user: User }) {
|
|
273
|
+
return (
|
|
274
|
+
<div>
|
|
275
|
+
{user.name}
|
|
276
|
+
{user.role} // ← TypeScript error if User type doesn't include role
|
|
277
|
+
</div>
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Step 3: Update shared type**
|
|
283
|
+
```typescript
|
|
284
|
+
// app/shared/types/user.types.ts
|
|
285
|
+
export interface User {
|
|
286
|
+
id: number
|
|
287
|
+
name: string
|
|
288
|
+
email: string
|
|
289
|
+
role: string // ← Add field
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Step 4: All type errors resolved**
|
|
294
|
+
|
|
295
|
+
### Scenario: Change response structure
|
|
296
|
+
|
|
297
|
+
**Before:**
|
|
298
|
+
```typescript
|
|
299
|
+
response: t.Object({
|
|
300
|
+
users: t.Array(UserSchema)
|
|
301
|
+
})
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**After:**
|
|
305
|
+
```typescript
|
|
306
|
+
response: t.Object({
|
|
307
|
+
data: t.Object({
|
|
308
|
+
users: t.Array(UserSchema),
|
|
309
|
+
total: t.Number()
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Frontend code breaks at compile time:**
|
|
315
|
+
```typescript
|
|
316
|
+
const { data } = await api.users.get()
|
|
317
|
+
console.log(data.users) // ← TypeScript error: Property 'users' does not exist
|
|
318
|
+
// Did you mean 'data.data.users'?
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Common Type Issues and Solutions
|
|
322
|
+
|
|
323
|
+
### Issue 1: Missing Response Schema
|
|
324
|
+
|
|
325
|
+
**Problem:**
|
|
326
|
+
```typescript
|
|
327
|
+
.get('/users', async () => {
|
|
328
|
+
return { users: [] }
|
|
329
|
+
})
|
|
330
|
+
// No response schema defined
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Result:** Frontend loses type inference
|
|
334
|
+
```typescript
|
|
335
|
+
const { data } = await api.users.get()
|
|
336
|
+
// ^? any
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Solution:** Always define response schema
|
|
340
|
+
```typescript
|
|
341
|
+
.get('/users', async () => {
|
|
342
|
+
return { users: [] }
|
|
343
|
+
}, {
|
|
344
|
+
response: t.Object({
|
|
345
|
+
users: t.Array(UserSchema)
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Issue 2: Type Mismatch Between Schema and Return
|
|
351
|
+
|
|
352
|
+
**Problem:**
|
|
353
|
+
```typescript
|
|
354
|
+
.get('/users', async () => {
|
|
355
|
+
return { users: [], count: 0 } // Returns count
|
|
356
|
+
}, {
|
|
357
|
+
response: t.Object({
|
|
358
|
+
users: t.Array(UserSchema)
|
|
359
|
+
// Missing count in schema
|
|
360
|
+
})
|
|
361
|
+
})
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Result:** Runtime data doesn't match types
|
|
365
|
+
|
|
366
|
+
**Solution:** Keep schema and return value in sync
|
|
367
|
+
```typescript
|
|
368
|
+
response: t.Object({
|
|
369
|
+
users: t.Array(UserSchema),
|
|
370
|
+
count: t.Number() // ← Add to schema
|
|
371
|
+
})
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Issue 3: Using `any` Type
|
|
375
|
+
|
|
376
|
+
**Problem:**
|
|
377
|
+
```typescript
|
|
378
|
+
const { data } = await api.users.get() as any
|
|
379
|
+
data.anything // No type checking
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Solution:** Trust Eden Treaty inference
|
|
383
|
+
```typescript
|
|
384
|
+
const { data } = await api.users.get()
|
|
385
|
+
// data is properly typed, no need for 'as any'
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Issue 4: Wrapping Eden Treaty
|
|
389
|
+
|
|
390
|
+
**Problem:**
|
|
391
|
+
```typescript
|
|
392
|
+
// DON'T DO THIS
|
|
393
|
+
async function apiCall(endpoint: string) {
|
|
394
|
+
const response = await fetch(endpoint)
|
|
395
|
+
return response.json()
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Result:** Loses all type inference
|
|
400
|
+
|
|
401
|
+
**Solution:** Use Eden Treaty directly
|
|
402
|
+
```typescript
|
|
403
|
+
// DO THIS
|
|
404
|
+
const { data, error } = await api.users.get()
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Type Safety Best Practices
|
|
408
|
+
|
|
409
|
+
**DO:**
|
|
410
|
+
- ✅ Define response schema for every route
|
|
411
|
+
- ✅ Use `t.Object()` for all schemas
|
|
412
|
+
- ✅ Define shared types in `app/shared/types/`
|
|
413
|
+
- ✅ Let Eden Treaty infer types automatically
|
|
414
|
+
- ✅ Use discriminated unions for multiple response types
|
|
415
|
+
- ✅ Trust TypeScript errors - they prevent runtime bugs
|
|
416
|
+
|
|
417
|
+
**DON'T:**
|
|
418
|
+
- ❌ Omit response schemas
|
|
419
|
+
- ❌ Use `any` type
|
|
420
|
+
- ❌ Wrap Eden Treaty in custom functions
|
|
421
|
+
- ❌ Ignore TypeScript errors
|
|
422
|
+
- ❌ Manually type API responses
|
|
423
|
+
- ❌ Use `as` type assertions unless absolutely necessary
|
|
424
|
+
|
|
425
|
+
## Type Inference Checklist
|
|
426
|
+
|
|
427
|
+
When creating a new API endpoint:
|
|
428
|
+
|
|
429
|
+
1. ✅ Define request body schema (if POST/PUT/PATCH)
|
|
430
|
+
2. ✅ Define response schema with `t.Object()`
|
|
431
|
+
3. ✅ Define all possible status code responses
|
|
432
|
+
4. ✅ Test frontend call to verify type inference
|
|
433
|
+
5. ✅ Check TypeScript errors in IDE
|
|
434
|
+
6. ✅ Verify autocomplete works in frontend
|
|
435
|
+
|
|
436
|
+
## Related
|
|
437
|
+
|
|
438
|
+
- [Routes with Eden Treaty](../resources/routes-eden.md)
|
|
439
|
+
- [Project Structure](./project-structure.md)
|
|
440
|
+
- [Anti-Patterns](./anti-patterns.md)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Reference documentation directory
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# CLI Commands Reference
|
|
2
|
+
|
|
3
|
+
**Version:** 1.11.0 | **Updated:** 2025-02-08
|
|
4
|
+
|
|
5
|
+
## Quick Facts
|
|
6
|
+
|
|
7
|
+
- CLI entry: `bun run flux <command>` or directly via npm scripts
|
|
8
|
+
- Commands are modular, each in `core/cli/commands/`
|
|
9
|
+
- Plugins can register custom commands
|
|
10
|
+
- Aliases supported (e.g., `g` for `generate`)
|
|
11
|
+
|
|
12
|
+
## Development Commands
|
|
13
|
+
|
|
14
|
+
### dev
|
|
15
|
+
|
|
16
|
+
Start full-stack development server with hot reload.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bun run dev # Full-stack (default)
|
|
20
|
+
bun run dev --port 4000 # Custom backend port
|
|
21
|
+
bun run dev --frontend-only # Vite only (port 5173)
|
|
22
|
+
bun run dev --backend-only # Elysia only (port 3000)
|
|
23
|
+
bun run dev --frontend-port 8080 # Custom Vite port
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Option | Short | Type | Default | Description |
|
|
27
|
+
|--------|-------|------|---------|-------------|
|
|
28
|
+
| `--port` | `-p` | number | 3000 | Backend server port |
|
|
29
|
+
| `--frontend-port` | | number | 5173 | Frontend server port |
|
|
30
|
+
| `--frontend-only` | `-f` | boolean | false | Run only Vite dev server |
|
|
31
|
+
| `--backend-only` | `-b` | boolean | false | Run only Elysia server |
|
|
32
|
+
|
|
33
|
+
## Build Commands
|
|
34
|
+
|
|
35
|
+
### build
|
|
36
|
+
|
|
37
|
+
Build application for production.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun run build # Full build (frontend + backend)
|
|
41
|
+
bun run build --frontend-only # Vite build only
|
|
42
|
+
bun run build --backend-only # Server bundle only
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Option | Type | Default | Description |
|
|
46
|
+
|--------|------|---------|-------------|
|
|
47
|
+
| `--frontend-only` | boolean | false | Build only frontend |
|
|
48
|
+
| `--backend-only` | boolean | false | Build only backend |
|
|
49
|
+
| `--production` | boolean | true | Enable minification |
|
|
50
|
+
|
|
51
|
+
**Output:**
|
|
52
|
+
- Frontend: `dist/client/`
|
|
53
|
+
- Backend: `dist/server/`
|
|
54
|
+
- Config: `dist/config/`
|
|
55
|
+
|
|
56
|
+
## Generator Commands
|
|
57
|
+
|
|
58
|
+
### generate
|
|
59
|
+
|
|
60
|
+
Generate code from templates.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
bun run flux generate <type> <name> [options]
|
|
64
|
+
# Aliases: g, gen
|
|
65
|
+
|
|
66
|
+
bun run flux g controller user
|
|
67
|
+
bun run flux g component UserCard
|
|
68
|
+
bun run flux g service auth
|
|
69
|
+
bun run flux g route api/users
|
|
70
|
+
bun run flux g plugin my-plugin
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| Type | Description | Output Location |
|
|
74
|
+
|------|-------------|-----------------|
|
|
75
|
+
| `controller` | Business logic handler | `app/server/controllers/` |
|
|
76
|
+
| `route` | API endpoint | `app/server/routes/` |
|
|
77
|
+
| `component` | React component | `app/client/src/components/` |
|
|
78
|
+
| `service` | Reusable service | `app/server/services/` |
|
|
79
|
+
| `plugin` | FluxStack plugin | `plugins/` |
|
|
80
|
+
|
|
81
|
+
| Option | Short | Type | Description |
|
|
82
|
+
|--------|-------|------|-------------|
|
|
83
|
+
| `--path` | `-p` | string | Custom output path |
|
|
84
|
+
| `--template` | `-t` | string | Template variant |
|
|
85
|
+
| `--force` | `-f` | boolean | Overwrite existing |
|
|
86
|
+
| `--dry-run` | | boolean | Preview without creating |
|
|
87
|
+
|
|
88
|
+
### interactive (wizard)
|
|
89
|
+
|
|
90
|
+
Interactive generator with prompts.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
bun run flux interactive
|
|
94
|
+
# Walks through generation options step by step
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Plugin Management Commands
|
|
98
|
+
|
|
99
|
+
### plugin:add
|
|
100
|
+
|
|
101
|
+
Install and whitelist an NPM plugin securely.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
bun run flux plugin:add <plugin-name> [options]
|
|
105
|
+
|
|
106
|
+
bun run flux plugin:add fluxstack-plugin-auth
|
|
107
|
+
bun run flux plugin:add @acme/fplugin-payments --skip-audit
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
| Option | Description |
|
|
111
|
+
|--------|-------------|
|
|
112
|
+
| `--skip-audit` | Skip npm security audit |
|
|
113
|
+
| `--skip-confirmation` | Skip confirmation prompt |
|
|
114
|
+
|
|
115
|
+
**Actions performed:**
|
|
116
|
+
1. Validates plugin name
|
|
117
|
+
2. Runs npm audit (unless skipped)
|
|
118
|
+
3. Installs plugin
|
|
119
|
+
4. Enables `PLUGINS_DISCOVER_NPM=true`
|
|
120
|
+
5. Adds to `PLUGINS_ALLOWED` whitelist
|
|
121
|
+
|
|
122
|
+
### plugin:remove
|
|
123
|
+
|
|
124
|
+
Remove plugin from whitelist and optionally uninstall.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
bun run flux plugin:remove <plugin-name> [options]
|
|
128
|
+
# Alias: plugin:rm
|
|
129
|
+
|
|
130
|
+
bun run flux plugin:remove fluxstack-plugin-auth
|
|
131
|
+
bun run flux plugin:remove my-plugin --keep-installed
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
| Option | Description |
|
|
135
|
+
|--------|-------------|
|
|
136
|
+
| `--skip-confirmation` | Skip confirmation prompt |
|
|
137
|
+
| `--keep-installed` | Only remove from whitelist, keep package |
|
|
138
|
+
|
|
139
|
+
### plugin:list
|
|
140
|
+
|
|
141
|
+
List all plugins (installed, whitelisted, discovered).
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
bun run flux plugin:list [options]
|
|
145
|
+
# Alias: plugin:ls
|
|
146
|
+
|
|
147
|
+
bun run flux plugin:list
|
|
148
|
+
bun run flux plugin:list --installed
|
|
149
|
+
bun run flux plugin:list --whitelisted
|
|
150
|
+
bun run flux plugin:list --json
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Option | Description |
|
|
154
|
+
|--------|-------------|
|
|
155
|
+
| `--installed` | Show only installed NPM plugins |
|
|
156
|
+
| `--whitelisted` | Show only whitelisted plugins |
|
|
157
|
+
| `--json` | Output as JSON |
|
|
158
|
+
|
|
159
|
+
### plugin:deps
|
|
160
|
+
|
|
161
|
+
Manage plugin dependencies.
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
bun run flux plugin:deps <subcommand> [options]
|
|
165
|
+
|
|
166
|
+
bun run flux plugin:deps install # Install all plugin deps
|
|
167
|
+
bun run flux plugin:deps install --dry-run # Preview installation
|
|
168
|
+
bun run flux plugin:deps list # List plugin dependencies
|
|
169
|
+
bun run flux plugin:deps list --plugin crypto-auth # Specific plugin
|
|
170
|
+
bun run flux plugin:deps check # Check for conflicts
|
|
171
|
+
bun run flux plugin:deps clean # Remove unused deps
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
| Subcommand | Description |
|
|
175
|
+
|------------|-------------|
|
|
176
|
+
| `install` | Install plugin dependencies |
|
|
177
|
+
| `list` | Show plugin dependencies |
|
|
178
|
+
| `check` | Detect dependency conflicts |
|
|
179
|
+
| `clean` | Remove unused dependencies |
|
|
180
|
+
|
|
181
|
+
## Project Commands
|
|
182
|
+
|
|
183
|
+
### create
|
|
184
|
+
|
|
185
|
+
Create new FluxStack project (used by create-fluxstack).
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
bunx create-fluxstack my-app
|
|
189
|
+
bunx create-fluxstack my-app --no-git
|
|
190
|
+
bunx create-fluxstack my-app --no-install
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### make:plugin
|
|
194
|
+
|
|
195
|
+
Create a new plugin scaffold.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
bun run flux make:plugin <name>
|
|
199
|
+
|
|
200
|
+
bun run flux make:plugin my-custom-plugin
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Creates:**
|
|
204
|
+
```
|
|
205
|
+
plugins/my-custom-plugin/
|
|
206
|
+
├── index.ts # Plugin entry
|
|
207
|
+
├── config/ # Plugin config
|
|
208
|
+
└── README.md # Documentation
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Help Command
|
|
212
|
+
|
|
213
|
+
### help
|
|
214
|
+
|
|
215
|
+
Display help for commands.
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
bun run flux help
|
|
219
|
+
bun run flux help <command>
|
|
220
|
+
|
|
221
|
+
bun run flux help dev
|
|
222
|
+
bun run flux help generate
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## NPM Script Shortcuts
|
|
226
|
+
|
|
227
|
+
Standard npm scripts in `package.json`:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
bun run dev # flux dev
|
|
231
|
+
bun run build # flux build
|
|
232
|
+
bun run start # NODE_ENV=production bun dist/server/index.js
|
|
233
|
+
bun run test # vitest
|
|
234
|
+
bun run lint # eslint
|
|
235
|
+
bun run typecheck # tsc --noEmit
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Environment Variables for CLI
|
|
239
|
+
|
|
240
|
+
| Variable | Effect |
|
|
241
|
+
|----------|--------|
|
|
242
|
+
| `LOG_LEVEL` | Set log verbosity (debug, info, warn, error) |
|
|
243
|
+
| `NODE_ENV` | development/production mode |
|
|
244
|
+
| `FLUXSTACK_MODE` | full-stack/backend-only/frontend-only |
|
|
245
|
+
|
|
246
|
+
## Related
|
|
247
|
+
|
|
248
|
+
- [Build System](../core/build-system.md)
|
|
249
|
+
- [Plugin System](../core/plugin-system.md)
|
|
250
|
+
- [Project Structure](../patterns/project-structure.md)
|