import { Router } from 'express'; import { query, one } from '../db.js'; import { insertRow } from '../lib/sql.js'; import { h } from '../lib/respond.js'; import { requireAuth, type AuthedRequest } from '../middleware/auth.js'; import { triggerCloudBuild, getCloudBuildStatus } from '../functions/cloud-build.js'; const r = Router(); r.use(requireAuth); const uid = (req: AuthedRequest) => req.userId as string; function sanitizeSegment(segment: string, fallback: string) { const cleaned = segment.toLowerCase().replace(/[^a-z0-9_]/g, ''); if (!cleaned) return fallback; return /^[a-z]/.test(cleaned) ? cleaned : `app${cleaned}`; } function sanitizePackageName(raw: string | undefined, appName: string) { const fallback = ['com', 'app', sanitizeSegment(appName, 'mobile')]; const src = (raw || '').split('.').filter(Boolean); const segs = src.length ? src.map((s, i) => sanitizeSegment(s, fallback[i] || 'app')) : fallback; while (segs.length < 3) segs.push(fallback[segs.length] || 'app'); return segs.join('.'); } // POST /builds -> start a build r.post('/', h(async (req) => { const config = req.body || {}; const platform = config.platform || 'android'; const appName = config.appName || 'My App'; const packageName = sanitizePackageName(config.packageName, appName); const normalizedConfig = { ...config, packageName }; const build = await insertRow('app_builds', { user_id: uid(req as any), app_name: appName, package_name: packageName, website_url: config.websiteUrl, config: normalizedConfig, status: 'pending', progress: 0, }); try { const result = await triggerCloudBuild({ buildId: build.id, websiteUrl: config.websiteUrl, appName, platform, packageName, config: normalizedConfig, }); return { buildId: build.id, cloudBuildId: result.cloudBuildId, message: result.message }; } catch (e: any) { return { buildId: build.id, message: 'Build created but cloud trigger failed: ' + e.message }; } })); // GET /builds?limit= r.get('/', h(async (req) => { const limit = Math.min(parseInt(String(req.query.limit ?? '20'), 10) || 20, 200); return query( `SELECT * FROM public.app_builds WHERE user_id = $1 ORDER BY created_at DESC LIMIT $2`, [uid(req as any), limit] ); })); // GET /builds/:id/status r.get('/:id/status', h(async (req) => { const status = await getCloudBuildStatus(req.params.id); if (status) return status; return one(`SELECT * FROM public.app_builds WHERE id = $1 AND user_id = $2`, [req.params.id, uid(req as any)]); })); export default r;