mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: unlimited by default — env vars default to 0 (unlimited)
Add 10 new configurable env vars (MAX_WORKER_THREADS, PROCESSING_TIMEOUT_S, MAX_PIPELINE_STEPS, MAX_CANVAS_PIXELS, MAX_SVG_SIZE_MB, MAX_LOGO_SIZE_KB, MAX_SPLIT_GRID, MAX_PDF_PAGES, SESSION_DURATION_HOURS, LOGIN_ATTEMPT_LIMIT). Change existing defaults: MAX_UPLOAD_SIZE_MB=0, MAX_BATCH_SIZE=0, MAX_MEGAPIXELS=0, RATE_LIMIT_PER_MIN=0, MAX_USERS=0, CONCURRENT_JOBS=0. Zero means unlimited/auto-detect throughout the application.
This commit is contained in:
+30
-9
@@ -1,17 +1,38 @@
|
||||
# Server port (used in production / Docker)
|
||||
# In dev, the API auto-starts on an internal port; you always access localhost:1349
|
||||
# Server
|
||||
PORT=1349
|
||||
AUTH_ENABLED=true
|
||||
DEFAULT_USERNAME=admin
|
||||
DEFAULT_PASSWORD=admin
|
||||
STORAGE_MODE=local
|
||||
FILE_MAX_AGE_HOURS=24
|
||||
CLEANUP_INTERVAL_MINUTES=30
|
||||
MAX_UPLOAD_SIZE_MB=100
|
||||
MAX_BATCH_SIZE=200
|
||||
CONCURRENT_JOBS=3
|
||||
MAX_MEGAPIXELS=100
|
||||
RATE_LIMIT_PER_MIN=100
|
||||
|
||||
# Cleanup
|
||||
FILE_MAX_AGE_HOURS=72
|
||||
CLEANUP_INTERVAL_MINUTES=60
|
||||
|
||||
# Upload & Batch (0 = unlimited)
|
||||
MAX_UPLOAD_SIZE_MB=0
|
||||
MAX_BATCH_SIZE=0
|
||||
CONCURRENT_JOBS=0
|
||||
MAX_MEGAPIXELS=0
|
||||
|
||||
# Rate limiting (0 = disabled)
|
||||
RATE_LIMIT_PER_MIN=0
|
||||
|
||||
# Users (0 = unlimited)
|
||||
MAX_USERS=0
|
||||
|
||||
# Processing (0 = auto/unlimited)
|
||||
MAX_WORKER_THREADS=0
|
||||
PROCESSING_TIMEOUT_S=0
|
||||
MAX_PIPELINE_STEPS=0
|
||||
MAX_CANVAS_PIXELS=0
|
||||
MAX_SVG_SIZE_MB=0
|
||||
MAX_LOGO_SIZE_KB=2048
|
||||
MAX_SPLIT_GRID=100
|
||||
MAX_PDF_PAGES=0
|
||||
SESSION_DURATION_HOURS=168
|
||||
LOGIN_ATTEMPT_LIMIT=10
|
||||
|
||||
# Set to true in CI/dev to skip the forced password-change on the default admin
|
||||
# SKIP_MUST_CHANGE_PASSWORD=false
|
||||
DB_PATH=./data/ashim.db
|
||||
|
||||
+29
-8
@@ -1,3 +1,4 @@
|
||||
import { availableParallelism } from "node:os";
|
||||
import { z } from "zod";
|
||||
|
||||
const envSchema = z.object({
|
||||
@@ -13,13 +14,13 @@ const envSchema = z.object({
|
||||
.default("false")
|
||||
.transform((v) => v === "true"),
|
||||
STORAGE_MODE: z.enum(["local", "s3"]).default("local"),
|
||||
FILE_MAX_AGE_HOURS: z.coerce.number().default(24),
|
||||
CLEANUP_INTERVAL_MINUTES: z.coerce.number().default(30),
|
||||
MAX_UPLOAD_SIZE_MB: z.coerce.number().default(100),
|
||||
MAX_BATCH_SIZE: z.coerce.number().default(200),
|
||||
CONCURRENT_JOBS: z.coerce.number().default(3),
|
||||
MAX_MEGAPIXELS: z.coerce.number().default(100),
|
||||
RATE_LIMIT_PER_MIN: z.coerce.number().default(100),
|
||||
FILE_MAX_AGE_HOURS: z.coerce.number().default(72),
|
||||
CLEANUP_INTERVAL_MINUTES: z.coerce.number().default(60),
|
||||
MAX_UPLOAD_SIZE_MB: z.coerce.number().default(0),
|
||||
MAX_BATCH_SIZE: z.coerce.number().default(0),
|
||||
CONCURRENT_JOBS: z.coerce.number().default(0),
|
||||
MAX_MEGAPIXELS: z.coerce.number().default(0),
|
||||
RATE_LIMIT_PER_MIN: z.coerce.number().default(0),
|
||||
DB_PATH: z.string().default("./data/ashim.db"),
|
||||
FILES_STORAGE_PATH: z.string().default("./data/files"),
|
||||
WORKSPACE_PATH: z.string().default("./tmp/workspace"),
|
||||
@@ -27,8 +28,18 @@ const envSchema = z.object({
|
||||
DEFAULT_LOCALE: z.string().default("en"),
|
||||
APP_NAME: z.string().default("ashim"),
|
||||
CORS_ORIGIN: z.string().default(""),
|
||||
MAX_USERS: z.coerce.number().default(5),
|
||||
MAX_USERS: z.coerce.number().default(0),
|
||||
LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default("info"),
|
||||
MAX_WORKER_THREADS: z.coerce.number().default(0),
|
||||
PROCESSING_TIMEOUT_S: z.coerce.number().default(0),
|
||||
MAX_PIPELINE_STEPS: z.coerce.number().default(0),
|
||||
MAX_CANVAS_PIXELS: z.coerce.number().default(0),
|
||||
MAX_SVG_SIZE_MB: z.coerce.number().default(0),
|
||||
MAX_LOGO_SIZE_KB: z.coerce.number().default(2048),
|
||||
MAX_SPLIT_GRID: z.coerce.number().default(100),
|
||||
MAX_PDF_PAGES: z.coerce.number().default(0),
|
||||
SESSION_DURATION_HOURS: z.coerce.number().default(168),
|
||||
LOGIN_ATTEMPT_LIMIT: z.coerce.number().default(10),
|
||||
});
|
||||
|
||||
export type Env = z.infer<typeof envSchema>;
|
||||
@@ -36,3 +47,13 @@ export type Env = z.infer<typeof envSchema>;
|
||||
export function loadEnv(): Env {
|
||||
return envSchema.parse(process.env);
|
||||
}
|
||||
|
||||
export function resolveConcurrency(env: Env): number {
|
||||
if (env.CONCURRENT_JOBS > 0) return env.CONCURRENT_JOBS;
|
||||
return Math.max(2, availableParallelism() - 1);
|
||||
}
|
||||
|
||||
export function resolveWorkerThreads(env: Env): number {
|
||||
if (env.MAX_WORKER_THREADS > 0) return env.MAX_WORKER_THREADS;
|
||||
return Math.max(2, availableParallelism() - 1);
|
||||
}
|
||||
|
||||
+18
-7
@@ -228,13 +228,24 @@ ENV PORT=1349 \
|
||||
DEFAULT_THEME=light \
|
||||
DEFAULT_LOCALE=en \
|
||||
APP_NAME="ashim" \
|
||||
FILE_MAX_AGE_HOURS=24 \
|
||||
CLEANUP_INTERVAL_MINUTES=30 \
|
||||
MAX_UPLOAD_SIZE_MB=100 \
|
||||
MAX_BATCH_SIZE=200 \
|
||||
CONCURRENT_JOBS=3 \
|
||||
MAX_MEGAPIXELS=100 \
|
||||
RATE_LIMIT_PER_MIN=100 \
|
||||
FILE_MAX_AGE_HOURS=72 \
|
||||
CLEANUP_INTERVAL_MINUTES=60 \
|
||||
MAX_UPLOAD_SIZE_MB=0 \
|
||||
MAX_BATCH_SIZE=0 \
|
||||
CONCURRENT_JOBS=0 \
|
||||
MAX_MEGAPIXELS=0 \
|
||||
RATE_LIMIT_PER_MIN=0 \
|
||||
MAX_USERS=0 \
|
||||
MAX_WORKER_THREADS=0 \
|
||||
PROCESSING_TIMEOUT_S=0 \
|
||||
MAX_PIPELINE_STEPS=0 \
|
||||
MAX_CANVAS_PIXELS=0 \
|
||||
MAX_SVG_SIZE_MB=0 \
|
||||
MAX_LOGO_SIZE_KB=2048 \
|
||||
MAX_SPLIT_GRID=100 \
|
||||
MAX_PDF_PAGES=0 \
|
||||
SESSION_DURATION_HOURS=168 \
|
||||
LOGIN_ATTEMPT_LIMIT=10 \
|
||||
LOG_LEVEL=debug
|
||||
|
||||
# NVIDIA Container Toolkit env vars (harmless on non-GPU systems)
|
||||
|
||||
@@ -21,7 +21,16 @@ services:
|
||||
- DEFAULT_USERNAME=admin
|
||||
- DEFAULT_PASSWORD=admin
|
||||
- SKIP_MUST_CHANGE_PASSWORD=${SKIP_MUST_CHANGE_PASSWORD:-false}
|
||||
- RATE_LIMIT_PER_MIN=${RATE_LIMIT_PER_MIN:-50000}
|
||||
- MAX_UPLOAD_SIZE_MB=${MAX_UPLOAD_SIZE_MB:-0}
|
||||
- MAX_BATCH_SIZE=${MAX_BATCH_SIZE:-0}
|
||||
- MAX_MEGAPIXELS=${MAX_MEGAPIXELS:-0}
|
||||
- CONCURRENT_JOBS=${CONCURRENT_JOBS:-0}
|
||||
- MAX_WORKER_THREADS=${MAX_WORKER_THREADS:-0}
|
||||
- PROCESSING_TIMEOUT_S=${PROCESSING_TIMEOUT_S:-0}
|
||||
- MAX_PIPELINE_STEPS=${MAX_PIPELINE_STEPS:-0}
|
||||
- RATE_LIMIT_PER_MIN=${RATE_LIMIT_PER_MIN:-0}
|
||||
- MAX_USERS=${MAX_USERS:-0}
|
||||
- SESSION_DURATION_HOURS=${SESSION_DURATION_HOURS:-168}
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
||||
|
||||
@@ -22,7 +22,16 @@ services:
|
||||
- DEFAULT_USERNAME=admin
|
||||
- DEFAULT_PASSWORD=admin
|
||||
- SKIP_MUST_CHANGE_PASSWORD=${SKIP_MUST_CHANGE_PASSWORD:-false}
|
||||
- RATE_LIMIT_PER_MIN=${RATE_LIMIT_PER_MIN:-50000}
|
||||
- MAX_UPLOAD_SIZE_MB=${MAX_UPLOAD_SIZE_MB:-0}
|
||||
- MAX_BATCH_SIZE=${MAX_BATCH_SIZE:-0}
|
||||
- MAX_MEGAPIXELS=${MAX_MEGAPIXELS:-0}
|
||||
- CONCURRENT_JOBS=${CONCURRENT_JOBS:-0}
|
||||
- MAX_WORKER_THREADS=${MAX_WORKER_THREADS:-0}
|
||||
- PROCESSING_TIMEOUT_S=${PROCESSING_TIMEOUT_S:-0}
|
||||
- MAX_PIPELINE_STEPS=${MAX_PIPELINE_STEPS:-0}
|
||||
- RATE_LIMIT_PER_MIN=${RATE_LIMIT_PER_MIN:-0}
|
||||
- MAX_USERS=${MAX_USERS:-0}
|
||||
- SESSION_DURATION_HOURS=${SESSION_DURATION_HOURS:-168}
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
||||
|
||||
Reference in New Issue
Block a user