feat: make all hardcoded limits configurable via env vars

- bodyLimit: conditional on MAX_UPLOAD_SIZE_MB (0 = 1GB practical max)
- rate limiting: disabled when RATE_LIMIT_PER_MIN=0
- shutdown timeout: 8s → 30s
- upload plugin: no fileSize/files cap when env=0
- session duration: configurable via SESSION_DURATION_HOURS (default 168h)
- login attempts: configurable via LOGIN_ATTEMPT_LIMIT
- batch/pipeline/svg-to-raster: skip guard when MAX_BATCH_SIZE=0
- pipeline steps: configurable via MAX_PIPELINE_STEPS (0 = unlimited)
- user-files: remove 200 hard cap
- stitch canvas: configurable via MAX_CANVAS_PIXELS (0 = unlimited)
- PDF pages: configurable via MAX_PDF_PAGES (0 = unlimited)
- SVG size: configurable via MAX_SVG_SIZE_MB (0 = unlimited)
- logo size: configurable via MAX_LOGO_SIZE_KB (default 2048)
- worker threads: auto-detect via resolveWorkerThreads (0 = auto)
- megapixels: skip validation when MAX_MEGAPIXELS=0
- seam carving: remove 1200px dimension cap
- concurrency: auto-detect via resolveConcurrency (0 = auto)
This commit is contained in:
ashim-hq
2026-04-20 21:50:17 +08:00
parent be254f9ca6
commit 6746989aa1
14 changed files with 57 additions and 81 deletions
+9 -4
View File
@@ -18,6 +18,7 @@ import { z } from "zod";
import { env } from "../config.js";
import { db, schema } from "../db/index.js";
import { autoOrient } from "../lib/auto-orient.js";
import { resolveConcurrency } from "../lib/env.js";
import { formatZodErrors } from "../lib/errors.js";
import { isToolInstalled } from "../lib/feature-status.js";
import { validateImageBuffer } from "../lib/file-validation.js";
@@ -39,7 +40,9 @@ const pipelineDefinitionSchema = z.object({
steps: z
.array(pipelineStepSchema)
.min(1, "Pipeline must have at least one step")
.max(20, "Pipeline cannot exceed 20 steps"),
.refine((steps) => env.MAX_PIPELINE_STEPS === 0 || steps.length <= env.MAX_PIPELINE_STEPS, {
message: "Pipeline exceeds maximum steps",
}),
});
/** Schema for saving a pipeline. */
@@ -49,7 +52,9 @@ const savePipelineSchema = z.object({
steps: z
.array(pipelineStepSchema)
.min(1, "Pipeline must have at least one step")
.max(20, "Pipeline cannot exceed 20 steps"),
.refine((steps) => env.MAX_PIPELINE_STEPS === 0 || steps.length <= env.MAX_PIPELINE_STEPS, {
message: "Pipeline exceeds maximum steps",
}),
});
export async function registerPipelineRoutes(app: FastifyInstance): Promise<void> {
@@ -424,7 +429,7 @@ export async function registerPipelineRoutes(app: FastifyInstance): Promise<void
}
// Enforce batch size limit
if (files.length > env.MAX_BATCH_SIZE) {
if (env.MAX_BATCH_SIZE > 0 && files.length > env.MAX_BATCH_SIZE) {
return reply.status(400).send({
error: `Too many files. Maximum batch size is ${env.MAX_BATCH_SIZE}`,
});
@@ -499,7 +504,7 @@ export async function registerPipelineRoutes(app: FastifyInstance): Promise<void
updateJobProgress({ ...progress });
// ── Process files through the pipeline with concurrency control ──
const queue = new PQueue({ concurrency: env.CONCURRENT_JOBS });
const queue = new PQueue({ concurrency: resolveConcurrency(env) });
const results: ({ buffer: Buffer; filename: string } | null)[] = new Array(files.length).fill(
null,