Introduces a logger.ts module emitting slog-compatible JSON lines to stderr. Replaces silent catch blocks and console.error calls throughout minio.ts, pocketbase.ts, hooks.server.ts, login, books, browse, and all API routes so auth/registration failures, MinIO presign errors, and scraper proxy failures are now visible in container logs.
65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
/**
|
|
* POST /api/scrape
|
|
*
|
|
* Proxies scrape requests to the Go scraper backend.
|
|
* Admin-only — returns 403 if the authenticated user is not an admin.
|
|
*
|
|
* Request body (JSON):
|
|
* { "url": "https://novelfire.net/book/..." } — scrape a single book
|
|
* {} — scrape the full catalogue
|
|
*
|
|
* Responses mirror the Go scraper:
|
|
* 202 Accepted — job enqueued
|
|
* 409 Conflict — a scrape job is already running
|
|
* 400 Bad Request
|
|
* 403 Forbidden — not an admin
|
|
*/
|
|
|
|
import { json, error } from '@sveltejs/kit';
|
|
import type { RequestHandler } from './$types';
|
|
import { env } from '$env/dynamic/private';
|
|
import { log } from '$lib/server/logger';
|
|
|
|
const SCRAPER_URL = env.SCRAPER_API_URL ?? 'http://localhost:8080';
|
|
|
|
export const POST: RequestHandler = async ({ request, locals }) => {
|
|
// Admin guard
|
|
if (!locals.user || locals.user.role !== 'admin') {
|
|
throw error(403, 'Forbidden');
|
|
}
|
|
|
|
let body: { url?: string } = {};
|
|
try {
|
|
body = await request.json();
|
|
} catch {
|
|
// empty body is fine — means "scrape all"
|
|
}
|
|
|
|
// Decide which scraper endpoint to call
|
|
const isBookScrape = typeof body.url === 'string' && body.url.length > 0;
|
|
const endpoint = isBookScrape ? '/scrape/book' : '/scrape';
|
|
|
|
const upstream = `${SCRAPER_URL}${endpoint}`;
|
|
let res: Response;
|
|
try {
|
|
res = await fetch(upstream, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: isBookScrape ? JSON.stringify({ url: body.url }) : undefined
|
|
});
|
|
} catch (e) {
|
|
log.error('scrape', 'scraper proxy network error', { endpoint, err: String(e) });
|
|
throw error(502, 'Could not reach scraper');
|
|
}
|
|
|
|
if (!res.ok && res.status >= 500) {
|
|
const text = await res.text().catch(() => '');
|
|
log.error('scrape', 'scraper returned error', { endpoint, status: res.status, body: text });
|
|
}
|
|
|
|
const data = await res.json().catch(() => ({}));
|
|
|
|
// Pass through the status code from the Go scraper (202, 409, 400, …)
|
|
return json(data, { status: res.status });
|
|
};
|