import { Hono } from 'hono'; import type { Context } from 'hono'; import { tokenService } from './token-service'; // PERMANENT: Jobs API routes // Provides access to job data from PocketBase // Requires authentication (valid PB token) // // Dependencies: // - tokenService for PB token retrieval // - process.env.POCKETBASE_URL for PB API endpoint const JOBS_COLLECTION = 'pbc_1407612689'; // // Endpoints: // - GET /api/jobs - List jobs with pagination, filtering, field selection export function createJobsRoutes(): Hono { const router = new Hono(); // GET /api/jobs - Fetch jobs from PocketBase // Query params: // - page: Page number (default 1) // - perPage: Items per page (default 50, max 1000) // - fields: Comma-separated field names to return (optional, for cache optimization) // - filter: PocketBase filter syntax (optional) // - sort: Sort field (default -Job_Number) router.get('/', async (c: Context) => { try { // Get token (assume present after login) const tokens = await tokenService.getTokens(); const pbToken = tokens?.pbToken; // Parse query params const page = parseInt(c.req.query('page') || '1'); const perPage = Math.min(parseInt(c.req.query('perPage') || '50'), 1000); const fields = c.req.query('fields'); // Optional: comma-separated field names const filter = c.req.query('filter'); // Optional: PocketBase filter const sort = c.req.query('sort') || '-Job_Number'; // Build PocketBase API URL const pbUrl = new URL(`${process.env.POCKETBASE_URL}/api/collections/${JOBS_COLLECTION}/records`); pbUrl.searchParams.set('page', page.toString()); pbUrl.searchParams.set('perPage', perPage.toString()); pbUrl.searchParams.set('sort', sort); if (fields) { pbUrl.searchParams.set('fields', fields); } if (filter) { pbUrl.searchParams.set('filter', filter); } // Fetch from PocketBase // temporary: dev-only SSL bypass; global rejectUnauthorized already set, keep here as explicit const response = await fetch(pbUrl.toString(), { headers: pbToken ? { 'Authorization': `Bearer ${pbToken}` } : {}, // @ts-ignore Bun TLS option tls: { rejectUnauthorized: false } }); if (!response.ok) { const errorText = await response.text(); console.error('PocketBase jobs fetch failed:', response.status, errorText); return c.json({ error: 'Failed to fetch jobs from PocketBase' }, response.status); } const data = await response.json(); return c.json(data); } catch (err) { console.error('Jobs API error:', (err as Error)?.message); return c.json({ error: 'Internal server error' }, 500); } }); // GET /api/jobs/:id - Fetch single job by ID router.get('/:id', async (c: Context) => { try { // Check authentication const tokens = await tokenService.getTokens(); const pbToken = tokens?.pbToken; const jobId = c.req.param('id'); const pbUrl = `${process.env.POCKETBASE_URL}/api/collections/${JOBS_COLLECTION}/records/${jobId}`; // Fetch from PocketBase const response = await fetch(pbUrl, { headers: pbToken ? { 'Authorization': `Bearer ${pbToken}` } : {} }); if (!response.ok) { return c.json({ error: 'Job not found' }, 404); } const data = await response.json(); return c.json(data); } catch (err) { console.error('Job fetch error:', (err as Error)?.message); return c.json({ error: 'Internal server error' }, 500); } }); return router; }