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)
|
# Server
|
||||||
# In dev, the API auto-starts on an internal port; you always access localhost:1349
|
|
||||||
PORT=1349
|
PORT=1349
|
||||||
AUTH_ENABLED=true
|
AUTH_ENABLED=true
|
||||||
DEFAULT_USERNAME=admin
|
DEFAULT_USERNAME=admin
|
||||||
DEFAULT_PASSWORD=admin
|
DEFAULT_PASSWORD=admin
|
||||||
STORAGE_MODE=local
|
STORAGE_MODE=local
|
||||||
FILE_MAX_AGE_HOURS=24
|
|
||||||
CLEANUP_INTERVAL_MINUTES=30
|
# Cleanup
|
||||||
MAX_UPLOAD_SIZE_MB=100
|
FILE_MAX_AGE_HOURS=72
|
||||||
MAX_BATCH_SIZE=200
|
CLEANUP_INTERVAL_MINUTES=60
|
||||||
CONCURRENT_JOBS=3
|
|
||||||
MAX_MEGAPIXELS=100
|
# Upload & Batch (0 = unlimited)
|
||||||
RATE_LIMIT_PER_MIN=100
|
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
|
# Set to true in CI/dev to skip the forced password-change on the default admin
|
||||||
# SKIP_MUST_CHANGE_PASSWORD=false
|
# SKIP_MUST_CHANGE_PASSWORD=false
|
||||||
DB_PATH=./data/ashim.db
|
DB_PATH=./data/ashim.db
|
||||||
|
|||||||
+29
-8
@@ -1,3 +1,4 @@
|
|||||||
|
import { availableParallelism } from "node:os";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const envSchema = z.object({
|
const envSchema = z.object({
|
||||||
@@ -13,13 +14,13 @@ const envSchema = z.object({
|
|||||||
.default("false")
|
.default("false")
|
||||||
.transform((v) => v === "true"),
|
.transform((v) => v === "true"),
|
||||||
STORAGE_MODE: z.enum(["local", "s3"]).default("local"),
|
STORAGE_MODE: z.enum(["local", "s3"]).default("local"),
|
||||||
FILE_MAX_AGE_HOURS: z.coerce.number().default(24),
|
FILE_MAX_AGE_HOURS: z.coerce.number().default(72),
|
||||||
CLEANUP_INTERVAL_MINUTES: z.coerce.number().default(30),
|
CLEANUP_INTERVAL_MINUTES: z.coerce.number().default(60),
|
||||||
MAX_UPLOAD_SIZE_MB: z.coerce.number().default(100),
|
MAX_UPLOAD_SIZE_MB: z.coerce.number().default(0),
|
||||||
MAX_BATCH_SIZE: z.coerce.number().default(200),
|
MAX_BATCH_SIZE: z.coerce.number().default(0),
|
||||||
CONCURRENT_JOBS: z.coerce.number().default(3),
|
CONCURRENT_JOBS: z.coerce.number().default(0),
|
||||||
MAX_MEGAPIXELS: z.coerce.number().default(100),
|
MAX_MEGAPIXELS: z.coerce.number().default(0),
|
||||||
RATE_LIMIT_PER_MIN: z.coerce.number().default(100),
|
RATE_LIMIT_PER_MIN: z.coerce.number().default(0),
|
||||||
DB_PATH: z.string().default("./data/ashim.db"),
|
DB_PATH: z.string().default("./data/ashim.db"),
|
||||||
FILES_STORAGE_PATH: z.string().default("./data/files"),
|
FILES_STORAGE_PATH: z.string().default("./data/files"),
|
||||||
WORKSPACE_PATH: z.string().default("./tmp/workspace"),
|
WORKSPACE_PATH: z.string().default("./tmp/workspace"),
|
||||||
@@ -27,8 +28,18 @@ const envSchema = z.object({
|
|||||||
DEFAULT_LOCALE: z.string().default("en"),
|
DEFAULT_LOCALE: z.string().default("en"),
|
||||||
APP_NAME: z.string().default("ashim"),
|
APP_NAME: z.string().default("ashim"),
|
||||||
CORS_ORIGIN: z.string().default(""),
|
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"),
|
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>;
|
export type Env = z.infer<typeof envSchema>;
|
||||||
@@ -36,3 +47,13 @@ export type Env = z.infer<typeof envSchema>;
|
|||||||
export function loadEnv(): Env {
|
export function loadEnv(): Env {
|
||||||
return envSchema.parse(process.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_THEME=light \
|
||||||
DEFAULT_LOCALE=en \
|
DEFAULT_LOCALE=en \
|
||||||
APP_NAME="ashim" \
|
APP_NAME="ashim" \
|
||||||
FILE_MAX_AGE_HOURS=24 \
|
FILE_MAX_AGE_HOURS=72 \
|
||||||
CLEANUP_INTERVAL_MINUTES=30 \
|
CLEANUP_INTERVAL_MINUTES=60 \
|
||||||
MAX_UPLOAD_SIZE_MB=100 \
|
MAX_UPLOAD_SIZE_MB=0 \
|
||||||
MAX_BATCH_SIZE=200 \
|
MAX_BATCH_SIZE=0 \
|
||||||
CONCURRENT_JOBS=3 \
|
CONCURRENT_JOBS=0 \
|
||||||
MAX_MEGAPIXELS=100 \
|
MAX_MEGAPIXELS=0 \
|
||||||
RATE_LIMIT_PER_MIN=100 \
|
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
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
# NVIDIA Container Toolkit env vars (harmless on non-GPU systems)
|
# NVIDIA Container Toolkit env vars (harmless on non-GPU systems)
|
||||||
|
|||||||
@@ -21,7 +21,16 @@ services:
|
|||||||
- DEFAULT_USERNAME=admin
|
- DEFAULT_USERNAME=admin
|
||||||
- DEFAULT_PASSWORD=admin
|
- DEFAULT_PASSWORD=admin
|
||||||
- SKIP_MUST_CHANGE_PASSWORD=${SKIP_MUST_CHANGE_PASSWORD:-false}
|
- 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
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
||||||
|
|||||||
@@ -22,7 +22,16 @@ services:
|
|||||||
- DEFAULT_USERNAME=admin
|
- DEFAULT_USERNAME=admin
|
||||||
- DEFAULT_PASSWORD=admin
|
- DEFAULT_PASSWORD=admin
|
||||||
- SKIP_MUST_CHANGE_PASSWORD=${SKIP_MUST_CHANGE_PASSWORD:-false}
|
- 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
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:1349/api/v1/health"]
|
||||||
|
|||||||
Reference in New Issue
Block a user