chore: prepare production deploy with API hardening and Railway adapter
* Harden API routes with rate limits, upload cap, and edit dedupe. Protect expensive endpoints from abuse, reject oversized mood uploads, dedupe concurrent edit-images calls, and surface Kakao search failures instead of silent mock fallback. Co-authored-by: Cursor <cursoragent@cursor.com> * chore: switch to adapter-node for Railway deploy --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,16 +1,31 @@
|
||||
import { createJob, updateJob } from '$lib/server/flowerFlow/jobStore.js';
|
||||
import { analyzeImageMood } from '$lib/server/gemini/vision.js';
|
||||
import { isGeminiConfigured } from '$lib/server/gemini/client.js';
|
||||
import { json, readUserInput, toErrorResponse } from '$lib/server/http.js';
|
||||
import { RATE_LIMITS } from '$lib/server/rateLimit.js';
|
||||
import { MAX_MOOD_IMAGE_BYTES, MAX_MOOD_IMAGE_LABEL } from '$lib/server/uploadLimits.js';
|
||||
import { enforceRateLimit, json, readUserInput, toErrorResponse } from '$lib/server/http.js';
|
||||
|
||||
/** @type {import('./$types').RequestHandler} */
|
||||
export async function POST({ request }) {
|
||||
export async function POST({ request, getClientAddress }) {
|
||||
try {
|
||||
const limited = enforceRateLimit(getClientAddress(), RATE_LIMITS.moodAnalysis, 'mood-analysis');
|
||||
if (limited) return limited;
|
||||
|
||||
const formData = await request.formData();
|
||||
const image = formData.get('image');
|
||||
|
||||
if (!(image instanceof File)) {
|
||||
return json({ error: 'image file is required' }, 400);
|
||||
return json({ error: 'image file is required', code: 'bad_request' }, 400);
|
||||
}
|
||||
|
||||
if (image.size > MAX_MOOD_IMAGE_BYTES) {
|
||||
return json(
|
||||
{
|
||||
error: `Image must be ${MAX_MOOD_IMAGE_LABEL} or smaller.`,
|
||||
code: 'bad_request'
|
||||
},
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
const userInput = readUserInput(formData);
|
||||
|
||||
Reference in New Issue
Block a user