import type { TypeBoxTypeProvider } from '@fastify/type-provider-typebox' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import FastifyAutoLoad from '@fastify/autoload' import FastifyCookie from '@fastify/cookie' import FastifyCors from '@fastify/cors' import FastifyMultipart from '@fastify/multipart' import FastifySensible from '@fastify/sensible' import FastifySwagger from '@fastify/swagger' import FastifyApiReference from '@scalar/fastify-api-reference' import Fastify from 'fastify' import { Prisma } from './prisma/generated-client/client.ts' import 'dotenv/config' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) const fastify = Fastify({ logger: true, }).withTypeProvider() fastify.register(FastifySensible) fastify.setErrorHandler((error, request, reply) => { if (error instanceof Prisma.PrismaClientValidationError) { reply.notAcceptable() return } if (error.statusCode) { reply.getHttpError(error.statusCode, error.message) return } reply.badRequest(error.message) }) fastify.register(FastifySwagger, { openapi: { info: { version: '1.0.0', title: 'Chad API', }, }, transform: ({ schema, url }) => { if (!url.startsWith('/chad')) return { schema, url } const transformedSchema: typeof schema = schema ?? {} const responseSchema: any = transformedSchema.response ?? {} responseSchema['4xx'] ??= { $ref: 'ResponseError' } responseSchema['5xx'] ??= { $ref: 'ResponseError' } transformedSchema.response = responseSchema return { schema: transformedSchema, url } }, refResolver: { buildLocalReference(json, _baseUri, _fragment, i) { if (!json.title && json.$id) { json.title = json.$id } if (!json.description) { json.description = json.title } if (!json.$id) { return `def-${i}` } return json.$id.toString() }, }, }) fastify.register(FastifyApiReference, { routePrefix: '/reference', configuration: { showOperationId: true, showDeveloperTools: 'never', pageTitle: 'Chad API', customCss: ` .scalar-mcp-layer, .agent-button-container, .t-doc__sidebar > div > button:last-child { display: none !important; } `, }, }) fastify.register(FastifyCors, { origin: [ 'http://localhost:3000', 'http://tauri.localhost', 'https://koptilnya.xyz', 'https://chad.koptilnya.xyz', ], methods: ['PATCH', 'PUT', 'OPTIONS', 'GET', 'POST', 'DELETE'], credentials: true, }) fastify.register(FastifyCookie) fastify.register(FastifyMultipart) fastify.register(FastifyAutoLoad, { dir: join(__dirname, 'plugins'), maxDepth: 1, }) fastify.register(FastifyAutoLoad, { dir: join(__dirname, 'routes'), options: { prefix: 'chad' }, }) ;(async () => { const port = process.env.PORT ? Number(process.env.PORT) : 4000 try { await fastify.listen({ port, host: '0.0.0.0' }) } catch (err) { fastify.log.error(err) process.exit(1) } })()