create-fluxstack 1.18.1 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/LLMD/INDEX.md +1 -1
- package/LLMD/MAINTENANCE.md +197 -197
- package/LLMD/MIGRATION.md +44 -1
- package/LLMD/agent.md +20 -7
- package/LLMD/config/declarative-system.md +268 -268
- package/LLMD/config/environment-vars.md +3 -6
- package/LLMD/config/runtime-reload.md +401 -401
- package/LLMD/core/build-system.md +599 -599
- package/LLMD/core/framework-lifecycle.md +249 -229
- package/LLMD/core/plugin-system.md +154 -100
- package/LLMD/patterns/anti-patterns.md +397 -397
- package/LLMD/patterns/project-structure.md +264 -264
- package/LLMD/patterns/type-safety.md +61 -5
- package/LLMD/reference/cli-commands.md +31 -7
- package/LLMD/reference/plugin-hooks.md +4 -2
- package/LLMD/reference/troubleshooting.md +364 -364
- package/LLMD/resources/controllers.md +465 -465
- package/LLMD/resources/live-auth.md +178 -1
- package/LLMD/resources/live-binary-delta.md +3 -1
- package/LLMD/resources/live-components.md +1192 -1041
- package/LLMD/resources/live-logging.md +3 -1
- package/LLMD/resources/live-rooms.md +1 -1
- package/LLMD/resources/live-upload.md +228 -181
- package/LLMD/resources/plugins-external.md +8 -7
- package/LLMD/resources/rest-auth.md +290 -290
- package/LLMD/resources/routes-eden.md +254 -254
- package/app/client/src/App.tsx +7 -7
- package/app/client/src/components/AppLayout.tsx +60 -23
- package/app/client/src/components/ColorWheel.tsx +195 -0
- package/app/client/src/components/DemoPage.tsx +5 -3
- package/app/client/src/components/LiveUploadWidget.tsx +1 -1
- package/app/client/src/components/ThemePicker.tsx +307 -0
- package/app/client/src/config/theme.config.ts +127 -0
- package/app/client/src/hooks/useThemeClock.ts +66 -0
- package/app/client/src/index.css +193 -0
- package/app/client/src/lib/theme-clock.ts +201 -0
- package/app/client/src/live/AuthDemo.tsx +9 -9
- package/app/client/src/live/CounterDemo.tsx +10 -10
- package/app/client/src/live/FormDemo.tsx +8 -8
- package/app/client/src/live/PingPongDemo.tsx +10 -10
- package/app/client/src/live/RoomChatDemo.tsx +10 -10
- package/app/client/src/live/SharedCounterDemo.tsx +5 -5
- package/app/client/src/pages/ApiTestPage.tsx +5 -5
- package/app/client/src/pages/HomePage.tsx +12 -12
- package/app/server/index.ts +8 -0
- package/app/server/live/auto-generated-components.ts +1 -1
- package/core/build/index.ts +1 -1
- package/core/cli/command-registry.ts +1 -1
- package/core/cli/commands/build.ts +25 -6
- package/core/cli/commands/plugin-deps.ts +1 -2
- package/core/cli/generators/plugin.ts +433 -581
- package/core/framework/server.ts +22 -8
- package/core/index.ts +6 -5
- package/core/plugins/index.ts +71 -199
- package/core/plugins/types.ts +76 -461
- package/core/server/index.ts +1 -1
- package/core/utils/logger/startup-banner.ts +26 -4
- package/create-fluxstack.ts +216 -107
- package/package.json +108 -107
- package/tsconfig.json +2 -1
- package/core/plugins/config.ts +0 -356
- package/core/plugins/dependency-manager.ts +0 -481
- package/core/plugins/discovery.ts +0 -379
- package/core/plugins/executor.ts +0 -353
- package/core/plugins/manager.ts +0 -645
- package/core/plugins/module-resolver.ts +0 -227
- package/core/plugins/registry.ts +0 -913
- package/vitest.config.live.ts +0 -69
|
@@ -1,254 +1,254 @@
|
|
|
1
|
-
# Routes with Eden Treaty
|
|
2
|
-
|
|
3
|
-
**Version:** 1.
|
|
4
|
-
|
|
5
|
-
## Quick Facts
|
|
6
|
-
|
|
7
|
-
- Routes use Elysia with `t.Object()` validation schemas
|
|
8
|
-
- **Response schemas are REQUIRED** for Eden Treaty type inference
|
|
9
|
-
- Frontend gets automatic type inference via Eden Treaty
|
|
10
|
-
- Route grouping uses `prefix` option
|
|
11
|
-
- Validation happens automatically via schemas
|
|
12
|
-
|
|
13
|
-
## Route Definition Pattern
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { Elysia, t } from 'elysia'
|
|
17
|
-
|
|
18
|
-
export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
|
|
19
|
-
.get('/', async () => {
|
|
20
|
-
// Handler logic
|
|
21
|
-
return { success: true, users: [], count: 0 }
|
|
22
|
-
}, {
|
|
23
|
-
detail: {
|
|
24
|
-
summary: 'Get All Users',
|
|
25
|
-
description: 'Retrieves a list of all registered users',
|
|
26
|
-
tags: ['Users', 'CRUD']
|
|
27
|
-
},
|
|
28
|
-
response: t.Object({
|
|
29
|
-
success: t.Boolean(),
|
|
30
|
-
users: t.Array(UserSchema),
|
|
31
|
-
count: t.Number()
|
|
32
|
-
})
|
|
33
|
-
})
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Schema Definition
|
|
37
|
-
|
|
38
|
-
Define schemas at the top of route files:
|
|
39
|
-
|
|
40
|
-
```typescript
|
|
41
|
-
const UserSchema = t.Object({
|
|
42
|
-
id: t.Number(),
|
|
43
|
-
name: t.String(),
|
|
44
|
-
email: t.String()
|
|
45
|
-
}, {
|
|
46
|
-
description: 'User object'
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
const CreateUserRequestSchema = t.Object({
|
|
50
|
-
name: t.String({ minLength: 2, description: 'User name (minimum 2 characters)' }),
|
|
51
|
-
email: t.String({ format: 'email', description: 'Valid email address' })
|
|
52
|
-
}, {
|
|
53
|
-
description: 'Request body for creating a new user'
|
|
54
|
-
})
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Response Schema (REQUIRED!)
|
|
58
|
-
|
|
59
|
-
**Every route MUST define a response schema** for Eden Treaty type inference:
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
.get('/users', async () => {
|
|
63
|
-
return { success: true, users: [] }
|
|
64
|
-
}, {
|
|
65
|
-
response: t.Object({
|
|
66
|
-
success: t.Boolean(),
|
|
67
|
-
users: t.Array(UserSchema)
|
|
68
|
-
})
|
|
69
|
-
})
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Without response schema, frontend loses type inference.
|
|
73
|
-
|
|
74
|
-
## Multiple Status Code Responses
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
.post('/', async ({ body, set }) => {
|
|
78
|
-
// Validation error
|
|
79
|
-
if (!body.name) {
|
|
80
|
-
set.status = 400
|
|
81
|
-
return { success: false, error: 'Name required' }
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Success
|
|
85
|
-
set.status = 201
|
|
86
|
-
return { success: true, user: newUser }
|
|
87
|
-
}, {
|
|
88
|
-
body: CreateUserRequestSchema,
|
|
89
|
-
response: {
|
|
90
|
-
201: t.Object({
|
|
91
|
-
success: t.Literal(true),
|
|
92
|
-
user: UserSchema
|
|
93
|
-
}),
|
|
94
|
-
400: t.Object({
|
|
95
|
-
success: t.Literal(false),
|
|
96
|
-
error: t.String()
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Route Parameters
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
.get('/:id', async ({ params }) => {
|
|
106
|
-
const id = Number(params.id)
|
|
107
|
-
return { success: true, user: foundUser }
|
|
108
|
-
}, {
|
|
109
|
-
params: t.Object({
|
|
110
|
-
id: t.String({ description: 'User ID' })
|
|
111
|
-
}),
|
|
112
|
-
response: {
|
|
113
|
-
200: GetUserResponseSchema,
|
|
114
|
-
404: ErrorResponseSchema
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Request Body Validation
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
.post('/', async ({ body }) => {
|
|
123
|
-
// body is automatically validated against schema
|
|
124
|
-
const user = await createUser(body)
|
|
125
|
-
return { success: true, user }
|
|
126
|
-
}, {
|
|
127
|
-
body: t.Object({
|
|
128
|
-
name: t.String({ minLength: 2 }),
|
|
129
|
-
email: t.String({ format: 'email' })
|
|
130
|
-
}),
|
|
131
|
-
response: CreateUserResponseSchema
|
|
132
|
-
})
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Route Grouping
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// Main API routes with prefix
|
|
139
|
-
export const apiRoutes = new Elysia({ prefix: "/api" })
|
|
140
|
-
.get("/health", () => ({ status: "ok" }), {
|
|
141
|
-
response: t.Object({ status: t.String() })
|
|
142
|
-
})
|
|
143
|
-
// Register sub-routes
|
|
144
|
-
.use(usersRoutes)
|
|
145
|
-
.use(postsRoutes)
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Frontend Usage (Eden Treaty)
|
|
149
|
-
|
|
150
|
-
Once routes are defined with response schemas, frontend gets automatic type inference:
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
import { api } from '@/lib/eden-api'
|
|
154
|
-
|
|
155
|
-
// GET request - types inferred from response schema
|
|
156
|
-
const { data, error } = await api.users.get()
|
|
157
|
-
// data: { success: boolean, users: User[], count: number } | undefined
|
|
158
|
-
// error: Error | undefined
|
|
159
|
-
|
|
160
|
-
// POST request - body type inferred from body schema
|
|
161
|
-
const { data, error } = await api.users.post({
|
|
162
|
-
name: 'John Doe',
|
|
163
|
-
email: 'john@example.com'
|
|
164
|
-
})
|
|
165
|
-
// TypeScript validates body matches CreateUserRequestSchema
|
|
166
|
-
|
|
167
|
-
// Path parameters
|
|
168
|
-
const { data } = await api.users({ id: '123' }).get()
|
|
169
|
-
|
|
170
|
-
// Query parameters
|
|
171
|
-
const { data } = await api.users.get({
|
|
172
|
-
query: { page: 1, limit: 10 }
|
|
173
|
-
})
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
## Type Flow Diagram
|
|
177
|
-
|
|
178
|
-
```
|
|
179
|
-
Backend Route Definition
|
|
180
|
-
↓
|
|
181
|
-
t.Object() Schema (response)
|
|
182
|
-
↓
|
|
183
|
-
Eden Treaty Type Inference
|
|
184
|
-
↓
|
|
185
|
-
Frontend api.users.get()
|
|
186
|
-
↓
|
|
187
|
-
Typed { data, error }
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## Common Validation Types
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
// String validations
|
|
194
|
-
t.String({ minLength: 2, maxLength: 100 })
|
|
195
|
-
t.String({ format: 'email' })
|
|
196
|
-
t.String({ pattern: '^[a-z]+$' })
|
|
197
|
-
|
|
198
|
-
// Number validations
|
|
199
|
-
t.Number({ minimum: 0, maximum: 100 })
|
|
200
|
-
t.Integer()
|
|
201
|
-
|
|
202
|
-
// Arrays
|
|
203
|
-
t.Array(t.String())
|
|
204
|
-
t.Array(UserSchema, { minItems: 1 })
|
|
205
|
-
|
|
206
|
-
// Optional fields
|
|
207
|
-
t.Optional(t.String())
|
|
208
|
-
|
|
209
|
-
// Unions (multiple types)
|
|
210
|
-
t.Union([
|
|
211
|
-
t.Object({ success: t.Literal(true), data: t.Any() }),
|
|
212
|
-
t.Object({ success: t.Literal(false), error: t.String() })
|
|
213
|
-
])
|
|
214
|
-
|
|
215
|
-
// Enums
|
|
216
|
-
t.Union([t.Literal('active'), t.Literal('inactive')])
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## OpenAPI Documentation
|
|
220
|
-
|
|
221
|
-
The `detail` object generates OpenAPI/Swagger documentation:
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
.get('/users', handler, {
|
|
225
|
-
detail: {
|
|
226
|
-
summary: 'Get All Users',
|
|
227
|
-
description: 'Retrieves a list of all registered users',
|
|
228
|
-
tags: ['Users', 'CRUD']
|
|
229
|
-
},
|
|
230
|
-
response: ResponseSchema
|
|
231
|
-
})
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Access Swagger UI at `/swagger` when server is running.
|
|
235
|
-
|
|
236
|
-
## Critical Rules
|
|
237
|
-
|
|
238
|
-
**ALWAYS:**
|
|
239
|
-
- Define response schema for every route
|
|
240
|
-
- Use `t.Object()` for validation
|
|
241
|
-
- Set `set.status` for non-200 responses
|
|
242
|
-
- Define schemas at file top for reusability
|
|
243
|
-
|
|
244
|
-
**NEVER:**
|
|
245
|
-
- Omit response schema (breaks type inference)
|
|
246
|
-
- Use plain objects without `t.Object()`
|
|
247
|
-
- Forget to validate user input
|
|
248
|
-
- Mix route logic with business logic (use controllers)
|
|
249
|
-
|
|
250
|
-
## Related
|
|
251
|
-
|
|
252
|
-
- [Controllers & Services](./controllers.md)
|
|
253
|
-
- [Type Safety Patterns](../patterns/type-safety.md)
|
|
254
|
-
- [Anti-Patterns](../patterns/anti-patterns.md)
|
|
1
|
+
# Routes with Eden Treaty
|
|
2
|
+
|
|
3
|
+
**Version:** 1.19.0 | **Updated:** 2026-04-14
|
|
4
|
+
|
|
5
|
+
## Quick Facts
|
|
6
|
+
|
|
7
|
+
- Routes use Elysia with `t.Object()` validation schemas
|
|
8
|
+
- **Response schemas are REQUIRED** for Eden Treaty type inference
|
|
9
|
+
- Frontend gets automatic type inference via Eden Treaty
|
|
10
|
+
- Route grouping uses `prefix` option
|
|
11
|
+
- Validation happens automatically via schemas
|
|
12
|
+
|
|
13
|
+
## Route Definition Pattern
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { Elysia, t } from 'elysia'
|
|
17
|
+
|
|
18
|
+
export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
|
|
19
|
+
.get('/', async () => {
|
|
20
|
+
// Handler logic
|
|
21
|
+
return { success: true, users: [], count: 0 }
|
|
22
|
+
}, {
|
|
23
|
+
detail: {
|
|
24
|
+
summary: 'Get All Users',
|
|
25
|
+
description: 'Retrieves a list of all registered users',
|
|
26
|
+
tags: ['Users', 'CRUD']
|
|
27
|
+
},
|
|
28
|
+
response: t.Object({
|
|
29
|
+
success: t.Boolean(),
|
|
30
|
+
users: t.Array(UserSchema),
|
|
31
|
+
count: t.Number()
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Schema Definition
|
|
37
|
+
|
|
38
|
+
Define schemas at the top of route files:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
const UserSchema = t.Object({
|
|
42
|
+
id: t.Number(),
|
|
43
|
+
name: t.String(),
|
|
44
|
+
email: t.String()
|
|
45
|
+
}, {
|
|
46
|
+
description: 'User object'
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const CreateUserRequestSchema = t.Object({
|
|
50
|
+
name: t.String({ minLength: 2, description: 'User name (minimum 2 characters)' }),
|
|
51
|
+
email: t.String({ format: 'email', description: 'Valid email address' })
|
|
52
|
+
}, {
|
|
53
|
+
description: 'Request body for creating a new user'
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Response Schema (REQUIRED!)
|
|
58
|
+
|
|
59
|
+
**Every route MUST define a response schema** for Eden Treaty type inference:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
.get('/users', async () => {
|
|
63
|
+
return { success: true, users: [] }
|
|
64
|
+
}, {
|
|
65
|
+
response: t.Object({
|
|
66
|
+
success: t.Boolean(),
|
|
67
|
+
users: t.Array(UserSchema)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Without response schema, frontend loses type inference.
|
|
73
|
+
|
|
74
|
+
## Multiple Status Code Responses
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
.post('/', async ({ body, set }) => {
|
|
78
|
+
// Validation error
|
|
79
|
+
if (!body.name) {
|
|
80
|
+
set.status = 400
|
|
81
|
+
return { success: false, error: 'Name required' }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Success
|
|
85
|
+
set.status = 201
|
|
86
|
+
return { success: true, user: newUser }
|
|
87
|
+
}, {
|
|
88
|
+
body: CreateUserRequestSchema,
|
|
89
|
+
response: {
|
|
90
|
+
201: t.Object({
|
|
91
|
+
success: t.Literal(true),
|
|
92
|
+
user: UserSchema
|
|
93
|
+
}),
|
|
94
|
+
400: t.Object({
|
|
95
|
+
success: t.Literal(false),
|
|
96
|
+
error: t.String()
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Route Parameters
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
.get('/:id', async ({ params }) => {
|
|
106
|
+
const id = Number(params.id)
|
|
107
|
+
return { success: true, user: foundUser }
|
|
108
|
+
}, {
|
|
109
|
+
params: t.Object({
|
|
110
|
+
id: t.String({ description: 'User ID' })
|
|
111
|
+
}),
|
|
112
|
+
response: {
|
|
113
|
+
200: GetUserResponseSchema,
|
|
114
|
+
404: ErrorResponseSchema
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Request Body Validation
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
.post('/', async ({ body }) => {
|
|
123
|
+
// body is automatically validated against schema
|
|
124
|
+
const user = await createUser(body)
|
|
125
|
+
return { success: true, user }
|
|
126
|
+
}, {
|
|
127
|
+
body: t.Object({
|
|
128
|
+
name: t.String({ minLength: 2 }),
|
|
129
|
+
email: t.String({ format: 'email' })
|
|
130
|
+
}),
|
|
131
|
+
response: CreateUserResponseSchema
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Route Grouping
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// Main API routes with prefix
|
|
139
|
+
export const apiRoutes = new Elysia({ prefix: "/api" })
|
|
140
|
+
.get("/health", () => ({ status: "ok" }), {
|
|
141
|
+
response: t.Object({ status: t.String() })
|
|
142
|
+
})
|
|
143
|
+
// Register sub-routes
|
|
144
|
+
.use(usersRoutes)
|
|
145
|
+
.use(postsRoutes)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Frontend Usage (Eden Treaty)
|
|
149
|
+
|
|
150
|
+
Once routes are defined with response schemas, frontend gets automatic type inference:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { api } from '@/lib/eden-api'
|
|
154
|
+
|
|
155
|
+
// GET request - types inferred from response schema
|
|
156
|
+
const { data, error } = await api.users.get()
|
|
157
|
+
// data: { success: boolean, users: User[], count: number } | undefined
|
|
158
|
+
// error: Error | undefined
|
|
159
|
+
|
|
160
|
+
// POST request - body type inferred from body schema
|
|
161
|
+
const { data, error } = await api.users.post({
|
|
162
|
+
name: 'John Doe',
|
|
163
|
+
email: 'john@example.com'
|
|
164
|
+
})
|
|
165
|
+
// TypeScript validates body matches CreateUserRequestSchema
|
|
166
|
+
|
|
167
|
+
// Path parameters
|
|
168
|
+
const { data } = await api.users({ id: '123' }).get()
|
|
169
|
+
|
|
170
|
+
// Query parameters
|
|
171
|
+
const { data } = await api.users.get({
|
|
172
|
+
query: { page: 1, limit: 10 }
|
|
173
|
+
})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Type Flow Diagram
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
Backend Route Definition
|
|
180
|
+
↓
|
|
181
|
+
t.Object() Schema (response)
|
|
182
|
+
↓
|
|
183
|
+
Eden Treaty Type Inference
|
|
184
|
+
↓
|
|
185
|
+
Frontend api.users.get()
|
|
186
|
+
↓
|
|
187
|
+
Typed { data, error }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Common Validation Types
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// String validations
|
|
194
|
+
t.String({ minLength: 2, maxLength: 100 })
|
|
195
|
+
t.String({ format: 'email' })
|
|
196
|
+
t.String({ pattern: '^[a-z]+$' })
|
|
197
|
+
|
|
198
|
+
// Number validations
|
|
199
|
+
t.Number({ minimum: 0, maximum: 100 })
|
|
200
|
+
t.Integer()
|
|
201
|
+
|
|
202
|
+
// Arrays
|
|
203
|
+
t.Array(t.String())
|
|
204
|
+
t.Array(UserSchema, { minItems: 1 })
|
|
205
|
+
|
|
206
|
+
// Optional fields
|
|
207
|
+
t.Optional(t.String())
|
|
208
|
+
|
|
209
|
+
// Unions (multiple types)
|
|
210
|
+
t.Union([
|
|
211
|
+
t.Object({ success: t.Literal(true), data: t.Any() }),
|
|
212
|
+
t.Object({ success: t.Literal(false), error: t.String() })
|
|
213
|
+
])
|
|
214
|
+
|
|
215
|
+
// Enums
|
|
216
|
+
t.Union([t.Literal('active'), t.Literal('inactive')])
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## OpenAPI Documentation
|
|
220
|
+
|
|
221
|
+
The `detail` object generates OpenAPI/Swagger documentation:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
.get('/users', handler, {
|
|
225
|
+
detail: {
|
|
226
|
+
summary: 'Get All Users',
|
|
227
|
+
description: 'Retrieves a list of all registered users',
|
|
228
|
+
tags: ['Users', 'CRUD']
|
|
229
|
+
},
|
|
230
|
+
response: ResponseSchema
|
|
231
|
+
})
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Access Swagger UI at `/swagger` when server is running.
|
|
235
|
+
|
|
236
|
+
## Critical Rules
|
|
237
|
+
|
|
238
|
+
**ALWAYS:**
|
|
239
|
+
- Define response schema for every route
|
|
240
|
+
- Use `t.Object()` for validation
|
|
241
|
+
- Set `set.status` for non-200 responses
|
|
242
|
+
- Define schemas at file top for reusability
|
|
243
|
+
|
|
244
|
+
**NEVER:**
|
|
245
|
+
- Omit response schema (breaks type inference)
|
|
246
|
+
- Use plain objects without `t.Object()`
|
|
247
|
+
- Forget to validate user input
|
|
248
|
+
- Mix route logic with business logic (use controllers)
|
|
249
|
+
|
|
250
|
+
## Related
|
|
251
|
+
|
|
252
|
+
- [Controllers & Services](./controllers.md)
|
|
253
|
+
- [Type Safety Patterns](../patterns/type-safety.md)
|
|
254
|
+
- [Anti-Patterns](../patterns/anti-patterns.md)
|
package/app/client/src/App.tsx
CHANGED
|
@@ -21,11 +21,11 @@ function NotFoundPage() {
|
|
|
21
21
|
<h1 className="text-6xl font-black text-white mb-4">404</h1>
|
|
22
22
|
<p className="text-xl text-gray-400 mb-6">Pagina nao encontrada</p>
|
|
23
23
|
<p className="text-sm text-gray-500 mb-8">
|
|
24
|
-
O caminho <code className="text-
|
|
24
|
+
O caminho <code className="text-theme">{window.location.pathname}</code> nao existe.
|
|
25
25
|
</p>
|
|
26
26
|
<a
|
|
27
27
|
href="/"
|
|
28
|
-
className="px-6 py-3 rounded-xl bg-
|
|
28
|
+
className="px-6 py-3 rounded-xl bg-theme-muted border border-theme-active text-theme hover:bg-theme-muted transition-all"
|
|
29
29
|
>
|
|
30
30
|
Voltar ao inicio
|
|
31
31
|
</a>
|
|
@@ -129,7 +129,7 @@ function AppContent() {
|
|
|
129
129
|
path="/form"
|
|
130
130
|
element={
|
|
131
131
|
<DemoPage
|
|
132
|
-
note={<>? Este formul?rio usa <code className="text-
|
|
132
|
+
note={<>? Este formul?rio usa <code className="text-theme">Live.use()</code> - cada campo sincroniza automaticamente com o servidor!</>}
|
|
133
133
|
>
|
|
134
134
|
<FormDemo />
|
|
135
135
|
</DemoPage>
|
|
@@ -155,7 +155,7 @@ function AppContent() {
|
|
|
155
155
|
path="/shared-counter"
|
|
156
156
|
element={
|
|
157
157
|
<DemoPage
|
|
158
|
-
note={<>Contador compartilhado usando <code className="text-
|
|
158
|
+
note={<>Contador compartilhado usando <code className="text-theme">LiveRoom</code> - abra em varias abas!</>}
|
|
159
159
|
>
|
|
160
160
|
<SharedCounterDemo />
|
|
161
161
|
</DemoPage>
|
|
@@ -165,7 +165,7 @@ function AppContent() {
|
|
|
165
165
|
path="/room-chat"
|
|
166
166
|
element={
|
|
167
167
|
<DemoPage
|
|
168
|
-
note={<>Chat com múltiplas salas usando o sistema <code className="text-
|
|
168
|
+
note={<>Chat com múltiplas salas usando o sistema <code className="text-theme">$room</code>.</>}
|
|
169
169
|
>
|
|
170
170
|
<RoomChatDemo />
|
|
171
171
|
</DemoPage>
|
|
@@ -175,7 +175,7 @@ function AppContent() {
|
|
|
175
175
|
path="/auth"
|
|
176
176
|
element={
|
|
177
177
|
<DemoPage
|
|
178
|
-
note={<>🔒 Sistema de autenticação declarativo para Live Components com <code className="text-
|
|
178
|
+
note={<>🔒 Sistema de autenticação declarativo para Live Components com <code className="text-theme">$auth</code>!</>}
|
|
179
179
|
>
|
|
180
180
|
<AuthDemo />
|
|
181
181
|
</DemoPage>
|
|
@@ -185,7 +185,7 @@ function AppContent() {
|
|
|
185
185
|
path="/ping-pong"
|
|
186
186
|
element={
|
|
187
187
|
<DemoPage
|
|
188
|
-
note={<>Latency demo com <code className="text-
|
|
188
|
+
note={<>Latency demo com <code className="text-theme-secondary">msgpack</code> binary codec - mensagens binárias no WebSocket!</>}
|
|
189
189
|
>
|
|
190
190
|
<PingPongDemo />
|
|
191
191
|
</DemoPage>
|