Wardrobe/server/index.js
jif2.zhang 38b5e3190a init: Wardrobe 衣物管理系统 - 项目首页、OTA 升级、Android CI/CD
- 响应式项目首页 (Landing, 含 R2 APK 下载) + 路由 /home 调整
- OTA 升级: tauri-plugin-hotswap (lib.rs/main.rs 拆分, 客户端热替换)
- OTA 服务端 (check/bundle/manifest-web) + build-ota/genkey/upload 脚本
- 密钥/凭据统一存配置中心 (signing + ota + cloudflare 分组)
- Android CI (android-* 分支) + OTA CI (手动触发), 产物上传 R2
- 修复 tsc/构建阻塞问题
2026-09-11 15:46:42 +08:00

44 lines
1.4 KiB
JavaScript

import 'dotenv/config'
import path from 'node:path'
import fs from 'node:fs'
import express from 'express'
import cors from 'cors'
import otaRouter from './routes/ota.js'
// 默认 3002: 与 iboard (3001) 同机部署时不冲突
const PORT = Number(process.env.PORT) || 3002
const DIST_DIR = path.join(process.cwd(), 'dist')
const HAS_DIST = fs.existsSync(DIST_DIR)
const app = express()
app.use(cors())
app.use(express.json())
// 健康检查
app.get('/api/health', (_req, res) => res.json({ ok: true, ts: Date.now() }))
// OTA 接口公开 (检查/下载更新不需要登录), 必须挂载在最前面
app.use('/api', otaRouter)
// 静态资源 (Vite build 产物)
if (HAS_DIST) {
app.use(express.static(DIST_DIR, { index: false, maxAge: '1h', etag: true }))
// SPA fallback: 非 /api/* 的请求一律返回 index.html, 由前端路由处理
app.get(/^\/(?!api\/).*/, (_req, res, next) => {
const indexHtml = path.join(DIST_DIR, 'index.html')
if (!fs.existsSync(indexHtml)) return next()
res.sendFile(indexHtml)
})
}
// 统一错误处理
app.use((err, _req, res, _next) => {
console.error('[api error]', err)
res.status(500).json({ error: err.message || '服务器内部错误' })
})
app.listen(PORT, () => {
console.log(`[wardrobe-api] listening on http://127.0.0.1:${PORT}`)
console.log(`[wardrobe-api] static dist: ${HAS_DIST ? DIST_DIR : '(not built, API only)'}`)
})