Files
vps-tracker/apps/api/src/index.ts
T
DenozordecandCursor 7f91bc3624
Docker / build (push) Has been cancelled
feat(api, web): добавить поддержку уведомлений и журнал уведомлений
Добавлены новые функции для отправки уведомлений через Telegram и webhook, включая настройки для интервалов уведомлений и проверки uptime. Реализован журнал уведомлений для отслеживания статуса отправленных сообщений. Обновлены схемы и интерфейсы для поддержки новых полей и функционала.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 00:36:05 +07:00

96 lines
2.9 KiB
TypeScript

import Fastify from 'fastify'
import cors from '@fastify/cors'
import sensible from '@fastify/sensible'
import staticPlugin from '@fastify/static'
import { existsSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { getDb } from '@cfdm/db'
import { dataRoutes } from './routes/data.js'
import { vpsRoutes } from './routes/vps.js'
import { providersRoutes } from './routes/providers.js'
import { providerAccountsRoutes } from './routes/provider-accounts.js'
import { paymentsRoutes } from './routes/payments.js'
import { balanceLedgerRoutes } from './routes/balance-ledger.js'
import { settingsRoutes } from './routes/settings.js'
import { syncRoutes } from './routes/sync.js'
import { projectsRoutes } from './routes/projects.js'
import { backupRoutes } from './routes/backup.js'
import { ratesProxyRoutes } from './routes/rates-proxy.js'
import { migrateRoutes } from './routes/migrate.js'
import { dashboardRoutes } from './routes/dashboard.js'
import { auditRoutes } from './routes/audit.js'
import { notificationsRoutes } from './routes/notifications.js'
import { startScheduler } from './services/scheduler.js'
const __dirname = dirname(fileURLToPath(import.meta.url))
export interface BuildAppOptions {
dbPath?: string
staticDir?: string
}
export async function buildApp(opts: BuildAppOptions = {}) {
if (opts.dbPath) process.env.DB_PATH = opts.dbPath
getDb()
const app = Fastify({
logger: process.env.NODE_ENV !== 'production',
})
await app.register(cors, { origin: true })
await app.register(sensible)
await app.register(dataRoutes)
await app.register(vpsRoutes)
await app.register(providersRoutes)
await app.register(providerAccountsRoutes)
await app.register(paymentsRoutes)
await app.register(balanceLedgerRoutes)
await app.register(settingsRoutes)
await app.register(syncRoutes)
await app.register(projectsRoutes)
await app.register(backupRoutes)
await app.register(ratesProxyRoutes)
await app.register(migrateRoutes)
await app.register(dashboardRoutes)
await app.register(auditRoutes)
await app.register(notificationsRoutes)
const staticDir = opts.staticDir ?? join(__dirname, '..', '..', 'web', 'dist')
if (existsSync(staticDir)) {
await app.register(staticPlugin, {
root: staticDir,
prefix: '/',
wildcard: false,
})
app.setNotFoundHandler((req, reply) => {
if (req.url.startsWith('/api')) {
reply.code(404).send({ error: { code: 'NOT_FOUND', message: 'Not found' } })
return
}
reply.sendFile('index.html')
})
}
return app
}
async function start() {
const port = Number(process.env.PORT ?? 3001)
const app = await buildApp()
startScheduler()
try {
await app.listen({ port, host: '0.0.0.0' })
} catch (err) {
app.log.error(err)
process.exit(1)
}
}
if (!process.env.VITEST) {
void start()
}