105 lines
3.6 KiB
TypeScript
105 lines
3.6 KiB
TypeScript
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;
|
|
}
|