@veloxts/web 0.6.23 → 0.6.26
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/README.md +1 -540
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -2,546 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Early Preview (v0.6.x)** - APIs are stabilizing but may still change. Use with caution in production.
|
|
4
4
|
|
|
5
|
-
React Server Components integration for
|
|
6
|
-
|
|
7
|
-
## Overview
|
|
8
|
-
|
|
9
|
-
`@veloxts/web` enables full-stack React applications with VeloxTS by:
|
|
10
|
-
|
|
11
|
-
- Embedding Fastify API routes inside Vinxi's HTTP infrastructure
|
|
12
|
-
- Providing React Server Components with streaming support
|
|
13
|
-
- Implementing Laravel-inspired file-based routing
|
|
14
|
-
- Bridging server actions to tRPC procedures
|
|
15
|
-
- Type-safe server actions with Zod validation
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
pnpm add @veloxts/web react@19 react-dom@19
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Quick Start
|
|
24
|
-
|
|
25
|
-
### 1. Create your Vinxi configuration
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
// app.config.ts
|
|
29
|
-
import { defineVeloxApp } from '@veloxts/web';
|
|
30
|
-
|
|
31
|
-
export default defineVeloxApp({
|
|
32
|
-
port: 3030,
|
|
33
|
-
apiHandler: './src/api.handler',
|
|
34
|
-
serverEntry: './src/entry.server',
|
|
35
|
-
clientEntry: './src/entry.client',
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### 2. Create the API handler
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
// src/api.handler.ts
|
|
43
|
-
import { createApiRouter } from '@veloxts/web';
|
|
44
|
-
import { createApp } from '@veloxts/core';
|
|
45
|
-
import { userProcedures } from './procedures/users';
|
|
46
|
-
|
|
47
|
-
const app = await createApp();
|
|
48
|
-
// Register your procedures...
|
|
49
|
-
|
|
50
|
-
export default createApiRouter({
|
|
51
|
-
app,
|
|
52
|
-
basePath: '/api',
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 3. Create pages
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
// app/pages/index.tsx
|
|
60
|
-
export default async function HomePage() {
|
|
61
|
-
return (
|
|
62
|
-
<div>
|
|
63
|
-
<h1>Welcome to VeloxTS</h1>
|
|
64
|
-
<p>Full-stack TypeScript with React Server Components</p>
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Server Actions
|
|
71
|
-
|
|
72
|
-
### Basic Action with Validation
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// src/actions/users.ts
|
|
76
|
-
import { action } from '@veloxts/web';
|
|
77
|
-
import { z } from 'zod';
|
|
78
|
-
|
|
79
|
-
// Define a server action with input/output validation
|
|
80
|
-
export const createUser = action()
|
|
81
|
-
.input(z.object({
|
|
82
|
-
name: z.string().min(1),
|
|
83
|
-
email: z.string().email(),
|
|
84
|
-
}))
|
|
85
|
-
.output(z.object({
|
|
86
|
-
id: z.string(),
|
|
87
|
-
name: z.string(),
|
|
88
|
-
email: z.string(),
|
|
89
|
-
createdAt: z.string(),
|
|
90
|
-
}))
|
|
91
|
-
.handler(async (input) => {
|
|
92
|
-
// Create user in database
|
|
93
|
-
const user = await db.user.create({
|
|
94
|
-
data: { name: input.name, email: input.email },
|
|
95
|
-
});
|
|
96
|
-
return {
|
|
97
|
-
id: user.id,
|
|
98
|
-
name: user.name,
|
|
99
|
-
email: user.email,
|
|
100
|
-
createdAt: user.createdAt.toISOString(),
|
|
101
|
-
};
|
|
102
|
-
});
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Protected Actions (Require Authentication)
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
// src/actions/profile.ts
|
|
109
|
-
import { action } from '@veloxts/web';
|
|
110
|
-
import { z } from 'zod';
|
|
111
|
-
|
|
112
|
-
export const updateProfile = action()
|
|
113
|
-
.input(z.object({
|
|
114
|
-
name: z.string().min(1),
|
|
115
|
-
bio: z.string().optional(),
|
|
116
|
-
}))
|
|
117
|
-
.protected() // Requires authentication
|
|
118
|
-
.handler(async (input, ctx) => {
|
|
119
|
-
// ctx.user is guaranteed to exist
|
|
120
|
-
return await db.user.update({
|
|
121
|
-
where: { id: ctx.user.id },
|
|
122
|
-
data: input,
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Using Actions in React Components
|
|
128
|
-
|
|
129
|
-
```tsx
|
|
130
|
-
// app/pages/users/new.tsx
|
|
131
|
-
'use client';
|
|
132
|
-
|
|
133
|
-
import { createUser } from '@/actions/users';
|
|
134
|
-
|
|
135
|
-
export default function NewUserPage() {
|
|
136
|
-
async function handleSubmit(formData: FormData) {
|
|
137
|
-
const result = await createUser({
|
|
138
|
-
name: formData.get('name') as string,
|
|
139
|
-
email: formData.get('email') as string,
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
if (result.success) {
|
|
143
|
-
console.log('Created user:', result.data);
|
|
144
|
-
} else {
|
|
145
|
-
console.error('Error:', result.error.message);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return (
|
|
150
|
-
<form action={handleSubmit}>
|
|
151
|
-
<input name="name" placeholder="Name" required />
|
|
152
|
-
<input name="email" type="email" placeholder="Email" required />
|
|
153
|
-
<button type="submit">Create User</button>
|
|
154
|
-
</form>
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## tRPC Bridge
|
|
160
|
-
|
|
161
|
-
Connect server actions to existing tRPC procedures with full type safety.
|
|
162
|
-
|
|
163
|
-
### Setup
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
// src/actions/bridge.ts
|
|
167
|
-
import { createTrpcBridge } from '@veloxts/web';
|
|
168
|
-
import type { AppRouter } from '@/trpc/router';
|
|
169
|
-
|
|
170
|
-
// Create a type-safe bridge to your tRPC router
|
|
171
|
-
export const bridge = createTrpcBridge<AppRouter>({
|
|
172
|
-
trpcBase: '/trpc',
|
|
173
|
-
});
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Create Actions from Procedures
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
// src/actions/users.ts
|
|
180
|
-
import { bridge } from './bridge';
|
|
181
|
-
|
|
182
|
-
// Type-safe: 'users.get' is validated against AppRouter
|
|
183
|
-
export const getUser = bridge.createAction('users.get');
|
|
184
|
-
|
|
185
|
-
// With options
|
|
186
|
-
export const updateUser = bridge.createAction('users.update', {
|
|
187
|
-
requireAuth: true,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// Protected shorthand
|
|
191
|
-
export const deleteUser = bridge.createProtectedAction('users.delete');
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Custom Action with Multiple Procedure Calls
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
// src/actions/checkout.ts
|
|
198
|
-
import { bridge } from './bridge';
|
|
199
|
-
import { z } from 'zod';
|
|
200
|
-
|
|
201
|
-
export const checkout = bridge.handler(
|
|
202
|
-
async (input, ctx, call) => {
|
|
203
|
-
// Call multiple procedures in sequence
|
|
204
|
-
const cart = await call('cart.get', { userId: ctx.user.id });
|
|
205
|
-
|
|
206
|
-
if (!cart.success) {
|
|
207
|
-
throw new Error('Cart not found');
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const order = await call('orders.create', {
|
|
211
|
-
items: cart.data.items,
|
|
212
|
-
total: cart.data.total,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
await call('cart.clear', { userId: ctx.user.id });
|
|
216
|
-
|
|
217
|
-
return order.data;
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
input: z.object({ paymentMethod: z.string() }),
|
|
221
|
-
requireAuth: true,
|
|
222
|
-
}
|
|
223
|
-
);
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## File-Based Routing
|
|
227
|
-
|
|
228
|
-
Routes are derived from the file structure in `app/pages/`:
|
|
229
|
-
|
|
230
|
-
| File Path | Route Pattern | Description |
|
|
231
|
-
|-----------|--------------|-------------|
|
|
232
|
-
| `index.tsx` | `/` | Home page |
|
|
233
|
-
| `about.tsx` | `/about` | Static page |
|
|
234
|
-
| `users/index.tsx` | `/users` | List page |
|
|
235
|
-
| `users/[id].tsx` | `/users/:id` | Dynamic segment |
|
|
236
|
-
| `users/[id]/edit.tsx` | `/users/:id/edit` | Nested dynamic |
|
|
237
|
-
| `docs/[...slug].tsx` | `/docs/*` | Catch-all route |
|
|
238
|
-
| `(auth)/login.tsx` | `/login` | Route group (no /auth prefix) |
|
|
239
|
-
| `(marketing)/pricing.tsx` | `/pricing` | Another route group |
|
|
240
|
-
|
|
241
|
-
### Dynamic Routes
|
|
242
|
-
|
|
243
|
-
```tsx
|
|
244
|
-
// app/pages/users/[id].tsx
|
|
245
|
-
interface PageProps {
|
|
246
|
-
params: { id: string };
|
|
247
|
-
searchParams: Record<string, string | string[]>;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export default async function UserPage({ params }: PageProps) {
|
|
251
|
-
const user = await db.user.findUnique({
|
|
252
|
-
where: { id: params.id },
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
if (!user) {
|
|
256
|
-
return <div>User not found</div>;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return (
|
|
260
|
-
<div>
|
|
261
|
-
<h1>{user.name}</h1>
|
|
262
|
-
<p>{user.email}</p>
|
|
263
|
-
</div>
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Catch-All Routes
|
|
269
|
-
|
|
270
|
-
```tsx
|
|
271
|
-
// app/pages/docs/[...slug].tsx
|
|
272
|
-
interface PageProps {
|
|
273
|
-
params: { '*': string }; // e.g., "getting-started/installation"
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export default async function DocsPage({ params }: PageProps) {
|
|
277
|
-
const slugParts = params['*'].split('/');
|
|
278
|
-
const doc = await loadDoc(slugParts);
|
|
279
|
-
|
|
280
|
-
return <article dangerouslySetInnerHTML={{ __html: doc.html }} />;
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### Layouts
|
|
285
|
-
|
|
286
|
-
Create `_layout.tsx` files for shared layouts:
|
|
287
|
-
|
|
288
|
-
```tsx
|
|
289
|
-
// app/pages/_layout.tsx (root layout)
|
|
290
|
-
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
291
|
-
return (
|
|
292
|
-
<html lang="en">
|
|
293
|
-
<head>
|
|
294
|
-
<meta charSet="UTF-8" />
|
|
295
|
-
<title>My App</title>
|
|
296
|
-
</head>
|
|
297
|
-
<body>
|
|
298
|
-
<nav>{/* Navigation */}</nav>
|
|
299
|
-
<main>{children}</main>
|
|
300
|
-
<footer>{/* Footer */}</footer>
|
|
301
|
-
</body>
|
|
302
|
-
</html>
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// app/pages/(dashboard)/_layout.tsx (group layout)
|
|
307
|
-
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
|
|
308
|
-
return (
|
|
309
|
-
<div className="dashboard">
|
|
310
|
-
<aside>{/* Sidebar */}</aside>
|
|
311
|
-
<div className="content">{children}</div>
|
|
312
|
-
</div>
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
## SSR Rendering
|
|
318
|
-
|
|
319
|
-
### Basic SSR Setup
|
|
320
|
-
|
|
321
|
-
```typescript
|
|
322
|
-
// src/entry.server.tsx
|
|
323
|
-
import { createSsrRouter, createFileRouter, renderToStream } from '@veloxts/web';
|
|
324
|
-
|
|
325
|
-
const fileRouter = createFileRouter({
|
|
326
|
-
pagesDir: 'app/pages',
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
export default createSsrRouter({
|
|
330
|
-
resolveRoute: (path) => fileRouter.match(path),
|
|
331
|
-
render: (match, request) => renderToStream(match, request, {
|
|
332
|
-
bootstrapScripts: ['/_build/client.js'],
|
|
333
|
-
}),
|
|
334
|
-
});
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### With Initial Data
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
// src/entry.server.tsx
|
|
341
|
-
export default createSsrRouter({
|
|
342
|
-
resolveRoute: (path) => fileRouter.match(path),
|
|
343
|
-
render: async (match, request) => {
|
|
344
|
-
// Fetch data for the page
|
|
345
|
-
const user = await getCurrentUser(request);
|
|
346
|
-
|
|
347
|
-
return renderToStream(match, request, {
|
|
348
|
-
bootstrapScripts: ['/_build/client.js'],
|
|
349
|
-
initialData: { user },
|
|
350
|
-
});
|
|
351
|
-
},
|
|
352
|
-
});
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
## Client Hydration
|
|
356
|
-
|
|
357
|
-
### Basic Hydration
|
|
358
|
-
|
|
359
|
-
```typescript
|
|
360
|
-
// src/entry.client.tsx
|
|
361
|
-
import { hydrate } from '@veloxts/web';
|
|
362
|
-
import App from './App';
|
|
363
|
-
|
|
364
|
-
hydrate(<App />);
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
### With Initial Data
|
|
368
|
-
|
|
369
|
-
```typescript
|
|
370
|
-
// src/entry.client.tsx
|
|
371
|
-
import { hydrate, getInitialData } from '@veloxts/web';
|
|
372
|
-
import App from './App';
|
|
373
|
-
|
|
374
|
-
const result = hydrate(<App />);
|
|
375
|
-
|
|
376
|
-
// Access initial data from server
|
|
377
|
-
const initialData = result.initialData;
|
|
378
|
-
// Or use the helper
|
|
379
|
-
const data = getInitialData<{ user: User }>();
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
### Custom Error Handling
|
|
383
|
-
|
|
384
|
-
```typescript
|
|
385
|
-
// src/entry.client.tsx
|
|
386
|
-
import { hydrate } from '@veloxts/web';
|
|
387
|
-
import App from './App';
|
|
388
|
-
|
|
389
|
-
hydrate(<App />, {
|
|
390
|
-
onRecoverableError: (error) => {
|
|
391
|
-
// Custom error reporting
|
|
392
|
-
console.error('Hydration error:', error);
|
|
393
|
-
reportToSentry(error);
|
|
394
|
-
},
|
|
395
|
-
});
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
## Error Handling
|
|
399
|
-
|
|
400
|
-
### Action Error Codes
|
|
401
|
-
|
|
402
|
-
Server actions return typed results with error codes:
|
|
403
|
-
|
|
404
|
-
```typescript
|
|
405
|
-
type ActionErrorCode =
|
|
406
|
-
| 'VALIDATION_ERROR' // Input validation failed
|
|
407
|
-
| 'UNAUTHORIZED' // Not authenticated
|
|
408
|
-
| 'FORBIDDEN' // Not authorized
|
|
409
|
-
| 'NOT_FOUND' // Resource not found
|
|
410
|
-
| 'CONFLICT' // Duplicate/conflict error
|
|
411
|
-
| 'RATE_LIMITED' // Too many requests
|
|
412
|
-
| 'BAD_REQUEST' // Invalid request
|
|
413
|
-
| 'INTERNAL_ERROR'; // Server error
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### Handling Errors in Components
|
|
417
|
-
|
|
418
|
-
```tsx
|
|
419
|
-
import { createUser } from '@/actions/users';
|
|
420
|
-
|
|
421
|
-
async function handleCreate(data: FormData) {
|
|
422
|
-
const result = await createUser({
|
|
423
|
-
name: data.get('name') as string,
|
|
424
|
-
email: data.get('email') as string,
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
if (!result.success) {
|
|
428
|
-
switch (result.error.code) {
|
|
429
|
-
case 'VALIDATION_ERROR':
|
|
430
|
-
setErrors(result.error.message);
|
|
431
|
-
break;
|
|
432
|
-
case 'CONFLICT':
|
|
433
|
-
setErrors('Email already exists');
|
|
434
|
-
break;
|
|
435
|
-
case 'RATE_LIMITED':
|
|
436
|
-
setErrors('Too many attempts. Please wait.');
|
|
437
|
-
break;
|
|
438
|
-
default:
|
|
439
|
-
setErrors('Something went wrong');
|
|
440
|
-
}
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// Success
|
|
445
|
-
router.push(`/users/${result.data.id}`);
|
|
446
|
-
}
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
### Custom Error Handler
|
|
450
|
-
|
|
451
|
-
```typescript
|
|
452
|
-
import { action } from '@veloxts/web';
|
|
453
|
-
|
|
454
|
-
export const riskyAction = action()
|
|
455
|
-
.input(z.object({ id: z.string() }))
|
|
456
|
-
.onError((error, ctx) => {
|
|
457
|
-
// Custom error handling
|
|
458
|
-
logError(error, { userId: ctx.user?.id });
|
|
459
|
-
|
|
460
|
-
// Return custom error response
|
|
461
|
-
return {
|
|
462
|
-
success: false,
|
|
463
|
-
error: {
|
|
464
|
-
code: 'INTERNAL_ERROR',
|
|
465
|
-
message: 'Operation failed. Please try again.',
|
|
466
|
-
},
|
|
467
|
-
};
|
|
468
|
-
})
|
|
469
|
-
.handler(async (input) => {
|
|
470
|
-
// Handler logic
|
|
471
|
-
});
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
## API Reference
|
|
475
|
-
|
|
476
|
-
### Actions
|
|
477
|
-
|
|
478
|
-
| Export | Description |
|
|
479
|
-
|--------|-------------|
|
|
480
|
-
| `action()` | Create a server action with fluent builder API |
|
|
481
|
-
| `createAction()` | Low-level action creator |
|
|
482
|
-
| `createTrpcBridge()` | Create a tRPC bridge for calling procedures |
|
|
483
|
-
|
|
484
|
-
### Routing
|
|
485
|
-
|
|
486
|
-
| Export | Description |
|
|
487
|
-
|--------|-------------|
|
|
488
|
-
| `createFileRouter()` | Create file-based router |
|
|
489
|
-
| `createSsrRouter()` | Create SSR request handler |
|
|
490
|
-
| `createApiRouter()` | Create API route handler |
|
|
491
|
-
| `createClientRouter()` | Create client-side router |
|
|
492
|
-
|
|
493
|
-
### Rendering
|
|
494
|
-
|
|
495
|
-
| Export | Description |
|
|
496
|
-
|--------|-------------|
|
|
497
|
-
| `renderToStream()` | Render React to streaming response |
|
|
498
|
-
| `hydrate()` | Hydrate server-rendered React |
|
|
499
|
-
| `getInitialData()` | Get initial data passed from server |
|
|
500
|
-
| `Document` | Default HTML document component |
|
|
501
|
-
|
|
502
|
-
### Utilities
|
|
503
|
-
|
|
504
|
-
| Export | Description |
|
|
505
|
-
|--------|-------------|
|
|
506
|
-
| `escapeHtml()` | Escape HTML special characters (XSS prevention) |
|
|
507
|
-
| `isSuccess()` | Type guard for successful action results |
|
|
508
|
-
| `isError()` | Type guard for error action results |
|
|
509
|
-
|
|
510
|
-
## Architecture
|
|
511
|
-
|
|
512
|
-
```
|
|
513
|
-
┌─────────────────────────────────────────────────────────┐
|
|
514
|
-
│ Vinxi (HTTP Entry Point) │
|
|
515
|
-
├─────────────────────────────────────────────────────────┤
|
|
516
|
-
│ /api/* → Fastify (Embedded via createApiRouter) │
|
|
517
|
-
│ /trpc/* → tRPC (via Fastify adapter) │
|
|
518
|
-
│ /_build/* → Static Assets (Vite client bundle) │
|
|
519
|
-
│ /* → RSC Renderer (React Flight streaming) │
|
|
520
|
-
└─────────────────────────────────────────────────────────┘
|
|
521
|
-
│
|
|
522
|
-
▼
|
|
523
|
-
┌─────────────────────────────────────────────────────────┐
|
|
524
|
-
│ Server Actions (via tRPC Bridge) │
|
|
525
|
-
├─────────────────────────────────────────────────────────┤
|
|
526
|
-
│ action() → Validated handlers with Zod schemas │
|
|
527
|
-
│ bridge.call → Type-safe procedure invocation │
|
|
528
|
-
│ ctx.user → Authenticated user from session │
|
|
529
|
-
└─────────────────────────────────────────────────────────┘
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
## Requirements
|
|
533
|
-
|
|
534
|
-
- Node.js 20+
|
|
535
|
-
- React 19+
|
|
536
|
-
- TypeScript 5.5+
|
|
537
|
-
|
|
538
|
-
## Status
|
|
539
|
-
|
|
540
|
-
**v0.5.0** - Production ready for MVP applications.
|
|
541
|
-
|
|
542
|
-
- 615 tests passing
|
|
543
|
-
- 94.4% code coverage
|
|
544
|
-
- Full TypeScript support with zero `any` types
|
|
5
|
+
React Server Components integration for VeloxTS Framework using Vinxi - provides file-based routing, streaming SSR, server actions with Zod validation, and tRPC bridge. Learn more at [@veloxts/velox](https://www.npmjs.com/package/@veloxts/velox).
|
|
545
6
|
|
|
546
7
|
## License
|
|
547
8
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/web",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.26",
|
|
4
4
|
"description": "React Server Components integration for VeloxTS framework using Vinxi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"react": ">=19.2.0",
|
|
43
43
|
"react-dom": ">=19.2.0",
|
|
44
|
-
"@veloxts/auth": "0.6.
|
|
45
|
-
"@veloxts/
|
|
46
|
-
"@veloxts/
|
|
47
|
-
"@veloxts/
|
|
44
|
+
"@veloxts/auth": "0.6.26",
|
|
45
|
+
"@veloxts/client": "0.6.26",
|
|
46
|
+
"@veloxts/core": "0.6.26",
|
|
47
|
+
"@veloxts/router": "0.6.26"
|
|
48
48
|
},
|
|
49
49
|
"peerDependenciesMeta": {
|
|
50
50
|
"@veloxts/auth": {
|
|
@@ -67,10 +67,10 @@
|
|
|
67
67
|
"react-server-dom-webpack": "19.2.3",
|
|
68
68
|
"typescript": "5.9.3",
|
|
69
69
|
"vitest": "4.0.16",
|
|
70
|
-
"@veloxts/
|
|
71
|
-
"@veloxts/
|
|
72
|
-
"@veloxts/router": "0.6.
|
|
73
|
-
"@veloxts/
|
|
70
|
+
"@veloxts/client": "0.6.26",
|
|
71
|
+
"@veloxts/auth": "0.6.26",
|
|
72
|
+
"@veloxts/router": "0.6.26",
|
|
73
|
+
"@veloxts/core": "0.6.26"
|
|
74
74
|
},
|
|
75
75
|
"keywords": [
|
|
76
76
|
"velox",
|