@veloxts/core 0.1.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/LICENSE +21 -0
- package/README.md +573 -0
- package/dist/app.d.ts +235 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +380 -0
- package/dist/app.js.map +1 -0
- package/dist/context.d.ts +88 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +57 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +298 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +294 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +182 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +121 -0
- package/dist/plugin.js.map +1 -0
- package/dist/types.d.ts +118 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config.d.ts +181 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +99 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/lifecycle.d.ts +78 -0
- package/dist/utils/lifecycle.d.ts.map +1 -0
- package/dist/utils/lifecycle.js +128 -0
- package/dist/utils/lifecycle.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 VeloxTS Framework Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
# @veloxts/core
|
|
2
|
+
|
|
3
|
+
Foundation package for the VeloxTS framework - provides the core Fastify wrapper, plugin system, and base context.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @veloxts/core
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @veloxts/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createVeloxApp } from '@veloxts/core';
|
|
17
|
+
|
|
18
|
+
// Create application
|
|
19
|
+
const app = await createVeloxApp({
|
|
20
|
+
port: 3000,
|
|
21
|
+
host: '0.0.0.0',
|
|
22
|
+
logger: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Start server
|
|
26
|
+
await app.start();
|
|
27
|
+
console.log(`Server running on ${app.address}`);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Core API
|
|
31
|
+
|
|
32
|
+
### `createVeloxApp(config?)`
|
|
33
|
+
|
|
34
|
+
Creates a new VeloxTS application instance with sensible defaults.
|
|
35
|
+
|
|
36
|
+
**Configuration Options:**
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
interface VeloxAppConfig {
|
|
40
|
+
port?: number; // Port to listen on (default: 3000)
|
|
41
|
+
host?: string; // Host to bind to (default: '0.0.0.0')
|
|
42
|
+
logger?: boolean | object; // Enable logging (default: true in dev)
|
|
43
|
+
fastify?: FastifyOptions; // Additional Fastify options
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Example:**
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const app = await createVeloxApp({
|
|
51
|
+
port: 4000,
|
|
52
|
+
host: '127.0.0.1',
|
|
53
|
+
logger: {
|
|
54
|
+
level: 'info',
|
|
55
|
+
prettyPrint: true,
|
|
56
|
+
},
|
|
57
|
+
fastify: {
|
|
58
|
+
requestTimeout: 30000,
|
|
59
|
+
bodyLimit: 1048576 * 10, // 10MB
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Returns:** Promise resolving to `VeloxApp` instance
|
|
65
|
+
|
|
66
|
+
### VeloxApp Instance
|
|
67
|
+
|
|
68
|
+
The application instance provides methods for lifecycle management:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface VeloxApp {
|
|
72
|
+
server: FastifyInstance; // Underlying Fastify server
|
|
73
|
+
config: VeloxAppConfig; // Application configuration
|
|
74
|
+
isRunning: boolean; // Server running state
|
|
75
|
+
address: string | null; // Server address if running
|
|
76
|
+
|
|
77
|
+
// Methods
|
|
78
|
+
start(): Promise<void>; // Start the server
|
|
79
|
+
stop(): Promise<void>; // Stop the server gracefully
|
|
80
|
+
register(plugin, options?): Promise<void>; // Register a plugin
|
|
81
|
+
onShutdown(handler): void; // Add shutdown handler
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Example:**
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const app = await createVeloxApp();
|
|
89
|
+
|
|
90
|
+
// Register plugins
|
|
91
|
+
await app.register(databasePlugin);
|
|
92
|
+
await app.register(routerPlugin);
|
|
93
|
+
|
|
94
|
+
// Add shutdown hook
|
|
95
|
+
app.onShutdown(async () => {
|
|
96
|
+
console.log('Cleaning up resources...');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Start server
|
|
100
|
+
await app.start();
|
|
101
|
+
console.log(`Server running at ${app.address}`);
|
|
102
|
+
|
|
103
|
+
// Graceful shutdown
|
|
104
|
+
process.on('SIGTERM', async () => {
|
|
105
|
+
await app.stop();
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Plugin System
|
|
110
|
+
|
|
111
|
+
VeloxTS's plugin system extends functionality while maintaining type safety and encapsulation.
|
|
112
|
+
|
|
113
|
+
### Defining Plugins
|
|
114
|
+
|
|
115
|
+
Use `definePlugin()` to create reusable plugins:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { definePlugin } from '@veloxts/core';
|
|
119
|
+
import { PrismaClient } from '@prisma/client';
|
|
120
|
+
|
|
121
|
+
export const databasePlugin = definePlugin({
|
|
122
|
+
name: '@myapp/database',
|
|
123
|
+
version: '1.0.0',
|
|
124
|
+
async register(server, options) {
|
|
125
|
+
const db = new PrismaClient();
|
|
126
|
+
|
|
127
|
+
// Decorate server with database client
|
|
128
|
+
server.decorate('db', db);
|
|
129
|
+
|
|
130
|
+
// Add lifecycle hook
|
|
131
|
+
server.addHook('onClose', async () => {
|
|
132
|
+
await db.$disconnect();
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Extending Context
|
|
139
|
+
|
|
140
|
+
Use TypeScript declaration merging to extend the base context:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import type { PrismaClient } from '@prisma/client';
|
|
144
|
+
|
|
145
|
+
declare module '@veloxts/core' {
|
|
146
|
+
interface BaseContext {
|
|
147
|
+
db: PrismaClient;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Now `ctx.db` is available in all route handlers with full type safety.
|
|
153
|
+
|
|
154
|
+
### Registering Plugins
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// Register with app instance
|
|
158
|
+
await app.register(databasePlugin);
|
|
159
|
+
|
|
160
|
+
// Register with options
|
|
161
|
+
await app.register(databasePlugin, {
|
|
162
|
+
connectionString: process.env.DATABASE_URL,
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Plugin Example: Database Integration
|
|
167
|
+
|
|
168
|
+
Complete example integrating Prisma:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { definePlugin, type BaseContext } from '@veloxts/core';
|
|
172
|
+
import { PrismaClient } from '@prisma/client';
|
|
173
|
+
|
|
174
|
+
// Define plugin
|
|
175
|
+
export const databasePlugin = definePlugin({
|
|
176
|
+
name: '@myapp/database',
|
|
177
|
+
version: '1.0.0',
|
|
178
|
+
async register(server, options) {
|
|
179
|
+
const prisma = new PrismaClient({
|
|
180
|
+
log: options?.log || ['error'],
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Test connection
|
|
184
|
+
await prisma.$connect();
|
|
185
|
+
|
|
186
|
+
// Decorate Fastify instance
|
|
187
|
+
server.decorate('db', prisma);
|
|
188
|
+
|
|
189
|
+
// Graceful shutdown
|
|
190
|
+
server.addHook('onClose', async () => {
|
|
191
|
+
await prisma.$disconnect();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
console.log('Database connected');
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Extend context
|
|
199
|
+
declare module '@veloxts/core' {
|
|
200
|
+
interface BaseContext {
|
|
201
|
+
db: PrismaClient;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Use in app
|
|
206
|
+
const app = await createVeloxApp();
|
|
207
|
+
await app.register(databasePlugin);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Context System
|
|
211
|
+
|
|
212
|
+
The context object provides request-scoped state accessible throughout the request lifecycle.
|
|
213
|
+
|
|
214
|
+
### Base Context
|
|
215
|
+
|
|
216
|
+
Every request has a base context:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
interface BaseContext {
|
|
220
|
+
request: FastifyRequest; // Fastify request object
|
|
221
|
+
reply: FastifyReply; // Fastify reply object
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Accessing Context
|
|
226
|
+
|
|
227
|
+
Context is available in route handlers:
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
app.server.get('/users', async (request, reply) => {
|
|
231
|
+
// Access base context
|
|
232
|
+
const { request: req, reply: rep } = request.context;
|
|
233
|
+
|
|
234
|
+
// Access plugin-extended properties
|
|
235
|
+
const users = await request.context.db.user.findMany();
|
|
236
|
+
|
|
237
|
+
return users;
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Context in Procedures
|
|
242
|
+
|
|
243
|
+
When using `@veloxts/router`, context is passed to procedure handlers:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { procedure } from '@veloxts/router';
|
|
247
|
+
|
|
248
|
+
const getUsers = procedure()
|
|
249
|
+
.query(async ({ ctx }) => {
|
|
250
|
+
// ctx has type BaseContext with extensions
|
|
251
|
+
return ctx.db.user.findMany();
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Error Handling
|
|
256
|
+
|
|
257
|
+
VeloxTS provides structured error classes for consistent API responses.
|
|
258
|
+
|
|
259
|
+
### Error Classes
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import {
|
|
263
|
+
VeloxError,
|
|
264
|
+
ValidationError,
|
|
265
|
+
NotFoundError,
|
|
266
|
+
UnauthorizedError,
|
|
267
|
+
ForbiddenError,
|
|
268
|
+
} from '@veloxts/core';
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### `VeloxError`
|
|
272
|
+
|
|
273
|
+
Base error class with status code:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
throw new VeloxError('Something went wrong', 500);
|
|
277
|
+
|
|
278
|
+
// Response:
|
|
279
|
+
// {
|
|
280
|
+
// "error": "Something went wrong",
|
|
281
|
+
// "statusCode": 500
|
|
282
|
+
// }
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### `ValidationError`
|
|
286
|
+
|
|
287
|
+
Validation errors with field-level details:
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
throw new ValidationError('Invalid input', {
|
|
291
|
+
email: 'Must be a valid email address',
|
|
292
|
+
age: 'Must be at least 18',
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Response:
|
|
296
|
+
// {
|
|
297
|
+
// "error": "Invalid input",
|
|
298
|
+
// "statusCode": 400,
|
|
299
|
+
// "fields": {
|
|
300
|
+
// "email": "Must be a valid email address",
|
|
301
|
+
// "age": "Must be at least 18"
|
|
302
|
+
// }
|
|
303
|
+
// }
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### `NotFoundError`
|
|
307
|
+
|
|
308
|
+
Resource not found errors:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
throw new NotFoundError('User', userId);
|
|
312
|
+
|
|
313
|
+
// Response:
|
|
314
|
+
// {
|
|
315
|
+
// "error": "User not found",
|
|
316
|
+
// "statusCode": 404,
|
|
317
|
+
// "resource": "User",
|
|
318
|
+
// "id": "123"
|
|
319
|
+
// }
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### `UnauthorizedError`
|
|
323
|
+
|
|
324
|
+
Authentication required:
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
throw new UnauthorizedError('Invalid credentials');
|
|
328
|
+
|
|
329
|
+
// Response:
|
|
330
|
+
// {
|
|
331
|
+
// "error": "Invalid credentials",
|
|
332
|
+
// "statusCode": 401
|
|
333
|
+
// }
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### `ForbiddenError`
|
|
337
|
+
|
|
338
|
+
Insufficient permissions:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
throw new ForbiddenError('Insufficient permissions');
|
|
342
|
+
|
|
343
|
+
// Response:
|
|
344
|
+
// {
|
|
345
|
+
// "error": "Insufficient permissions",
|
|
346
|
+
// "statusCode": 403
|
|
347
|
+
// }
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Error Handler Example
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
import { VeloxError, NotFoundError } from '@veloxts/core';
|
|
354
|
+
|
|
355
|
+
app.server.get('/users/:id', async (request, reply) => {
|
|
356
|
+
try {
|
|
357
|
+
const user = await request.context.db.user.findUnique({
|
|
358
|
+
where: { id: request.params.id },
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
if (!user) {
|
|
362
|
+
throw new NotFoundError('User', request.params.id);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return user;
|
|
366
|
+
} catch (error) {
|
|
367
|
+
if (error instanceof VeloxError) {
|
|
368
|
+
// VeloxError is automatically handled by Fastify
|
|
369
|
+
throw error;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Handle unexpected errors
|
|
373
|
+
throw new VeloxError('Internal server error', 500);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Configuration
|
|
379
|
+
|
|
380
|
+
### Default Configuration
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
{
|
|
384
|
+
port: 3000,
|
|
385
|
+
host: '0.0.0.0',
|
|
386
|
+
logger: process.env.NODE_ENV !== 'production',
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Environment-Based Configuration
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
const app = await createVeloxApp({
|
|
394
|
+
port: Number(process.env.PORT) || 3000,
|
|
395
|
+
host: process.env.HOST || '0.0.0.0',
|
|
396
|
+
logger: process.env.NODE_ENV !== 'production',
|
|
397
|
+
fastify: {
|
|
398
|
+
trustProxy: process.env.TRUST_PROXY === 'true',
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Production Configuration
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
const app = await createVeloxApp({
|
|
407
|
+
port: 3000,
|
|
408
|
+
host: '0.0.0.0',
|
|
409
|
+
logger: {
|
|
410
|
+
level: 'warn',
|
|
411
|
+
prettyPrint: false,
|
|
412
|
+
},
|
|
413
|
+
fastify: {
|
|
414
|
+
trustProxy: true,
|
|
415
|
+
requestTimeout: 30000,
|
|
416
|
+
bodyLimit: 1048576, // 1MB
|
|
417
|
+
disableRequestLogging: true,
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Lifecycle Management
|
|
423
|
+
|
|
424
|
+
### Graceful Shutdown
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
const app = await createVeloxApp();
|
|
428
|
+
|
|
429
|
+
// Add custom shutdown handlers
|
|
430
|
+
app.onShutdown(async () => {
|
|
431
|
+
console.log('Cleaning up resources...');
|
|
432
|
+
await database.disconnect();
|
|
433
|
+
await cache.flush();
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Handle SIGTERM (e.g., from Kubernetes, Docker)
|
|
437
|
+
process.on('SIGTERM', async () => {
|
|
438
|
+
console.log('SIGTERM received, shutting down gracefully...');
|
|
439
|
+
await app.stop();
|
|
440
|
+
process.exit(0);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// Handle SIGINT (Ctrl+C)
|
|
444
|
+
process.on('SIGINT', async () => {
|
|
445
|
+
console.log('SIGINT received, shutting down gracefully...');
|
|
446
|
+
await app.stop();
|
|
447
|
+
process.exit(0);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
await app.start();
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Startup and Shutdown Hooks
|
|
454
|
+
|
|
455
|
+
Plugins can register lifecycle hooks:
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
export const lifecyclePlugin = definePlugin({
|
|
459
|
+
name: 'lifecycle',
|
|
460
|
+
version: '1.0.0',
|
|
461
|
+
async register(server, options) {
|
|
462
|
+
// Called when server starts listening
|
|
463
|
+
server.addHook('onListen', async () => {
|
|
464
|
+
console.log('Server is listening');
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// Called when server is closing
|
|
468
|
+
server.addHook('onClose', async () => {
|
|
469
|
+
console.log('Server is closing');
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
// Called for each request
|
|
473
|
+
server.addHook('onRequest', async (request, reply) => {
|
|
474
|
+
console.log(`Request: ${request.method} ${request.url}`);
|
|
475
|
+
});
|
|
476
|
+
},
|
|
477
|
+
});
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Advanced Usage
|
|
481
|
+
|
|
482
|
+
### Custom Fastify Instance
|
|
483
|
+
|
|
484
|
+
For advanced scenarios, you can pass a custom Fastify instance:
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
import Fastify from 'fastify';
|
|
488
|
+
|
|
489
|
+
const fastify = Fastify({
|
|
490
|
+
logger: true,
|
|
491
|
+
requestIdHeader: 'x-request-id',
|
|
492
|
+
trustProxy: true,
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
const app = await createVeloxApp({ fastify });
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Accessing Fastify Directly
|
|
499
|
+
|
|
500
|
+
The underlying Fastify instance is available via `app.server`:
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
const app = await createVeloxApp();
|
|
504
|
+
|
|
505
|
+
// Add Fastify plugins
|
|
506
|
+
await app.server.register(fastifyCors, {
|
|
507
|
+
origin: true,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// Add raw routes
|
|
511
|
+
app.server.get('/custom', async (request, reply) => {
|
|
512
|
+
return { message: 'Custom route' };
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
## Practical Examples
|
|
517
|
+
|
|
518
|
+
### Complete Application Setup
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
import { createVeloxApp } from '@veloxts/core';
|
|
522
|
+
import { createDatabasePlugin } from '@veloxts/orm';
|
|
523
|
+
import { registerRestRoutes } from '@veloxts/router';
|
|
524
|
+
import { PrismaClient } from '@prisma/client';
|
|
525
|
+
import { userProcedures } from './procedures/users';
|
|
526
|
+
|
|
527
|
+
// Initialize
|
|
528
|
+
const prisma = new PrismaClient();
|
|
529
|
+
const app = await createVeloxApp({
|
|
530
|
+
port: Number(process.env.PORT) || 3000,
|
|
531
|
+
logger: true,
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
// Register database plugin
|
|
535
|
+
await app.register(createDatabasePlugin({ client: prisma }));
|
|
536
|
+
|
|
537
|
+
// Register API routes
|
|
538
|
+
await registerRestRoutes(app.server, {
|
|
539
|
+
prefix: '/api',
|
|
540
|
+
procedures: {
|
|
541
|
+
users: userProcedures,
|
|
542
|
+
},
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// Graceful shutdown
|
|
546
|
+
const shutdown = async () => {
|
|
547
|
+
await app.stop();
|
|
548
|
+
process.exit(0);
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
process.on('SIGTERM', shutdown);
|
|
552
|
+
process.on('SIGINT', shutdown);
|
|
553
|
+
|
|
554
|
+
// Start server
|
|
555
|
+
await app.start();
|
|
556
|
+
console.log(`Server running at ${app.address}`);
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## Related Packages
|
|
560
|
+
|
|
561
|
+
- [@veloxts/router](/packages/router) - Procedure-based routing
|
|
562
|
+
- [@veloxts/validation](/packages/validation) - Schema validation with Zod
|
|
563
|
+
- [@veloxts/orm](/packages/orm) - Prisma integration
|
|
564
|
+
- [@veloxts/client](/packages/client) - Type-safe frontend API client
|
|
565
|
+
- [@veloxts/cli](/packages/cli) - Developer tooling
|
|
566
|
+
|
|
567
|
+
## TypeScript Support
|
|
568
|
+
|
|
569
|
+
All exports are fully typed with comprehensive JSDoc documentation. The package includes type definitions and declaration maps for excellent IDE support.
|
|
570
|
+
|
|
571
|
+
## License
|
|
572
|
+
|
|
573
|
+
MIT
|