Spaces:
Running
Running
Download src/routes/flow.js from Tataaicoltd/api: direct link, hf CLI and curl.
- Browser
- Download file 3.81 kB
-
https://huggingface.co/spaces/Tataaicoltd/api/resolve/main/src/routes/flow.js
- Command line
-
hf download hf://spaces/Tataaicoltd/api/src/routes/flow.js
-
curl -L -o flow.js https://huggingface.co/spaces/Tataaicoltd/api/resolve/main/src/routes/flow.js
3.81 kB
| import { Router } from 'express'; | |
| import { supabase } from '../supabase.js'; | |
| import { STATUSES, statusToInt, intToStatus } from '../status.js'; | |
| // Lightweight "flow" API for agents. Mounted at /flow/tickets. | |
| const router = Router(); | |
| const TABLE = 'ztickets'; | |
| // DB stores images as text (JSON array of URLs); expose as an array. | |
| function parseImages(v) { | |
| if (!v) return []; | |
| if (Array.isArray(v)) return v; | |
| try { | |
| const a = JSON.parse(v); | |
| return Array.isArray(a) ? a : []; | |
| } catch { | |
| return String(v).split(/[\n,]+/).map((s) => s.trim()).filter(Boolean); | |
| } | |
| } | |
| // GET /flow/tickets -> [{ id, title, status }] | |
| router.get('/', async (req, res) => { | |
| const { data, error } = await supabase | |
| .from(TABLE) | |
| .select('id, title, status') | |
| .order('sort', { ascending: true }) | |
| .order('id', { ascending: true }); | |
| if (error) return res.status(500).json({ error: error.message }); | |
| res.json(data.map((t) => ({ id: t.id, title: t.title, status: intToStatus(t.status) }))); | |
| }); | |
| // GET /flow/tickets/queue?project_name=<name> | |
| // Returns the next queued ticket for a project: status = 'queued', lowest sort first. | |
| // Defined before '/:id' so the literal path is not treated as an id. | |
| router.get('/queue', async (req, res) => { | |
| const projectName = req.query.project_name; | |
| if (!projectName) return res.status(400).json({ error: 'project_name is required' }); | |
| const { data: project, error: projErr } = await supabase | |
| .from('zprojects') | |
| .select('id, name') | |
| .eq('name', projectName) | |
| .maybeSingle(); | |
| if (projErr) return res.status(500).json({ error: projErr.message }); | |
| if (!project) return res.status(404).json({ error: `project not found: ${projectName}` }); | |
| const { data, error } = await supabase | |
| .from(TABLE) | |
| .select('*') | |
| .eq('projectid', project.id) | |
| .eq('status', statusToInt('queued')) | |
| .order('sort', { ascending: true }) | |
| .order('id', { ascending: true }) | |
| .limit(1) | |
| .maybeSingle(); | |
| if (error) return res.status(500).json({ error: error.message }); | |
| if (!data) return res.status(404).json({ error: 'no queued ticket found' }); | |
| res.json({ | |
| ...data, | |
| status: intToStatus(data.status), | |
| images: parseImages(data.images), | |
| project_name: project.name | |
| }); | |
| }); | |
| // GET /flow/tickets/:id -> { id, title, detail, status, message } | |
| router.get('/:id', async (req, res) => { | |
| const { data, error } = await supabase | |
| .from(TABLE) | |
| .select('id, title, detail, status, message') | |
| .eq('id', req.params.id) | |
| .single(); | |
| if (error) return res.status(404).json({ error: error.message }); | |
| res.json({ | |
| id: data.id, | |
| title: data.title, | |
| detail: data.detail, | |
| status: intToStatus(data.status), | |
| message: data.message | |
| }); | |
| }); | |
| // PUT /flow/tickets body: { id, status?, message?, detail? } -> updated ticket | |
| router.put('/', async (req, res) => { | |
| const { id, status, message, detail } = req.body; | |
| if (id === undefined || id === null || id === '') { | |
| return res.status(400).json({ error: 'id is required' }); | |
| } | |
| const payload = {}; | |
| if (status !== undefined) { | |
| if (!STATUSES.includes(status)) { | |
| return res.status(400).json({ error: `status must be one of ${STATUSES.join(', ')}` }); | |
| } | |
| payload.status = statusToInt(status); | |
| } | |
| if (message !== undefined) payload.message = message; | |
| if (detail !== undefined) payload.detail = detail; | |
| if (Object.keys(payload).length === 0) { | |
| return res.status(400).json({ error: 'nothing to update (provide status, message or detail)' }); | |
| } | |
| const { data, error } = await supabase | |
| .from(TABLE) | |
| .update(payload) | |
| .eq('id', id) | |
| .select() | |
| .single(); | |
| if (error) return res.status(500).json({ error: error.message }); | |
| res.json({ ...data, status: intToStatus(data.status) }); | |
| }); | |
| export default router; | |