import express from 'express'; import { readFileSync } from 'node:fs'; // @ts-ignore import { XMLHttpRequest } from 'xmlhttprequest'; // @ts-ignore globalThis.XMLHttpRequest = XMLHttpRequest; // Polyfill localStorage for Parse SDK const memoryStorage = { _data: new Map(), getItem(key: string) { return this._data.get(key) || null; }, setItem(key: string, value: string) { this._data.set(key, String(value)); }, removeItem(key: string) { this._data.delete(key); }, clear() { this._data.clear(); }, key(index: number) { return Array.from(this._data.keys())[index] || null; }, get length() { return this._data.size; } }; // @ts-ignore globalThis.localStorage = memoryStorage; /** * 注意:生产/客户实例正式入口是 fmode-server 加载 api/routes.ts。 * 本 server.ts 仅作本地开发壳,不挂载直连上游的 Sorftime/TikHub token。 */ function getConfig() { try { const configPath = process.env.NODE_ENV === 'test' ? './config.test.json' : './config.json'; const configContent = readFileSync(configPath, 'utf-8'); return JSON.parse(configContent); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; console.warn('Config file not found, using defaults:', errorMessage); return { parse: { port: 3000, appId: 'TARGET_PARSE_APP_ID', serverURL: 'http://localhost:3000/parse' } }; } } const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); async function startServer() { const config = getConfig(); const PORT = process.env.PORT || config.parse?.port || 3000; const Parse = require('parse'); Parse.initialize(config.parse.appId); Parse.serverURL = `http://localhost:${PORT}/parse`; Parse.masterKey = config.parse.masterKey; // @ts-ignore globalThis.Parse = Parse; app.use((req: any, res: any, next: () => void) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`); next(); }); app.get('/health', (req: any, res: any) => { res.json({ status: 'healthy', instance: 'TARGET-voc-instance', timestamp: new Date().toISOString(), uptime: process.uptime() }); }); app.get('/', (req: any, res: any) => { res.json({ message: 'TARGET VOC Instance - dev shell', version: '1.0.0-customer-relay', note: 'Production uses fmode-server + api/routes.ts', endpoints: ['/api', '/health', '/parse'] }); }); // 开发壳可选挂载 api/routes(正式环境由 fmode-server 自动扫描) try { const apiRouter = (await import('./api/routes.ts')).default; app.use('/api', apiRouter); console.log('[DevShell] /api mounted from api/routes.ts'); } catch (e: any) { console.warn('[DevShell] api/routes.ts not mounted in this runtime:', e?.message || e); } app.use((req: any, res: any) => { res.status(404).json({ message: 'Not Found', path: req.path, method: req.method }); }); app.use((err: any, req: any, res: any, next: any) => { console.error('Error:', err?.message || err); res.status(500).json({ message: 'Internal Server Error', error: err?.message }); }); app.listen(PORT, () => { console.log(`[TARGET-voc-instance] listening on :${PORT}`); }); } startServer().catch((err) => { console.error('Failed to start server:', err); process.exit(1); });