TypeScript · 2782 bytes Raw Blame History
1 import Fastify from 'fastify';
2 import cors from '@fastify/cors';
3 import jwt from '@fastify/jwt';
4 import multipart from '@fastify/multipart';
5 import websocket from '@fastify/websocket';
6 import staticFiles from '@fastify/static';
7 import { loadConfig } from './config.js';
8 import { registerRoutes } from './routes/index.js';
9 import { errorHandler } from './middleware/error-handler.js';
10 import { authMiddleware } from './middleware/auth.js';
11 import { ZephyrFSClient } from './integration/zephyrfs-client.js';
12 import path from 'node:path';
13 import { fileURLToPath } from 'node:url';
14
15 const __filename = fileURLToPath(import.meta.url);
16 const __dirname = path.dirname(__filename);
17
18 async function createServer() {
19 const config = loadConfig();
20
21 const fastify = Fastify({
22 logger: {
23 level: config.logLevel,
24 transport: config.nodeEnv === 'development' ? {
25 target: 'pino-pretty',
26 options: {
27 translateTime: 'HH:MM:ss Z',
28 ignore: 'pid,hostname',
29 },
30 } : undefined,
31 },
32 });
33
34 // Initialize ZephyrFS client
35 const zephyrfsClient = new ZephyrFSClient(config.zephyrfsNodeUrl, {
36 timeout: config.zephyrfsNodeTimeout,
37 });
38
39 // Register plugins
40 await fastify.register(cors, {
41 origin: config.corsOrigins,
42 credentials: true,
43 });
44
45 await fastify.register(jwt, {
46 secret: config.jwtSecret,
47 });
48
49 await fastify.register(multipart, {
50 limits: {
51 fileSize: config.maxFileSize,
52 },
53 });
54
55 await fastify.register(websocket);
56
57 // Serve static files in production
58 if (config.nodeEnv === 'production') {
59 await fastify.register(staticFiles, {
60 root: path.join(__dirname, '../public'),
61 prefix: '/',
62 });
63 }
64
65 // Add context
66 fastify.decorate('zephyrfs', zephyrfsClient);
67 fastify.decorate('config', config);
68
69 // Register middleware
70 fastify.setErrorHandler(errorHandler);
71 await fastify.register(authMiddleware);
72
73 // Register routes
74 await fastify.register(registerRoutes, { prefix: '/api' });
75
76 return fastify;
77 }
78
79 async function start() {
80 try {
81 const config = loadConfig();
82 const server = await createServer();
83
84 await server.listen({
85 port: config.port,
86 host: config.host,
87 });
88
89 console.log(`🚀 ZephyrFS Web Server running on http://${config.host}:${config.port}`);
90 } catch (error) {
91 console.error('Failed to start server:', error);
92 process.exit(1);
93 }
94 }
95
96 // Handle graceful shutdown
97 process.on('SIGTERM', async () => {
98 console.log('Received SIGTERM, shutting down gracefully...');
99 process.exit(0);
100 });
101
102 process.on('SIGINT', async () => {
103 console.log('Received SIGINT, shutting down gracefully...');
104 process.exit(0);
105 });
106
107 if (import.meta.url === `file://${process.argv[1]}`) {
108 start();
109 }
110
111 export { createServer };