mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: add FEATURE_NOT_INSTALLED guard to all 10 remaining AI tool routes
The guard was only present on restore-photo.ts and the createToolRoute factory. All other AI tools used custom route handlers that bypassed the check entirely, allowing requests to reach the Python sidecar even when the feature bundle was not installed. This adds an early 501 response before any multipart parsing or file processing.
This commit is contained in:
@@ -2,9 +2,11 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { blurFaces } from "@ashim/ai";
|
import { blurFaces } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
import { updateSingleFileProgress } from "../progress.js";
|
import { updateSingleFileProgress } from "../progress.js";
|
||||||
@@ -13,6 +15,18 @@ import { registerToolProcessFn } from "../tool-factory.js";
|
|||||||
/** Face detection and blurring route. */
|
/** Face detection and blurring route. */
|
||||||
export function registerBlurFaces(app: FastifyInstance) {
|
export function registerBlurFaces(app: FastifyInstance) {
|
||||||
app.post("/api/v1/tools/blur-faces", async (request: FastifyRequest, reply: FastifyReply) => {
|
app.post("/api/v1/tools/blur-faces", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "blur-faces";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { colorize } from "@ashim/ai";
|
import { colorize } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { decodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { resolveOutputFormat } from "../../lib/output-format.js";
|
import { resolveOutputFormat } from "../../lib/output-format.js";
|
||||||
@@ -20,6 +22,18 @@ import { registerToolProcessFn } from "../tool-factory.js";
|
|||||||
*/
|
*/
|
||||||
export function registerColorize(app: FastifyInstance) {
|
export function registerColorize(app: FastifyInstance) {
|
||||||
app.post("/api/v1/tools/colorize", async (request: FastifyRequest, reply: FastifyReply) => {
|
app.post("/api/v1/tools/colorize", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "colorize";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { enhanceFaces } from "@ashim/ai";
|
import { enhanceFaces } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { decodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
@@ -15,6 +17,18 @@ import { registerToolProcessFn } from "../tool-factory.js";
|
|||||||
/** Face enhancement route using GFPGAN/CodeFormer. */
|
/** Face enhancement route using GFPGAN/CodeFormer. */
|
||||||
export function registerEnhanceFaces(app: FastifyInstance) {
|
export function registerEnhanceFaces(app: FastifyInstance) {
|
||||||
app.post("/api/v1/tools/enhance-faces", async (request: FastifyRequest, reply: FastifyReply) => {
|
app.post("/api/v1/tools/enhance-faces", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "enhance-faces";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { inpaint } from "@ashim/ai";
|
import { inpaint } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
@@ -30,6 +32,18 @@ const BROWSER_PREVIEWABLE = new Set(["png", "jpg", "jpeg", "webp", "gif", "avif"
|
|||||||
*/
|
*/
|
||||||
export function registerEraseObject(app: FastifyInstance) {
|
export function registerEraseObject(app: FastifyInstance) {
|
||||||
app.post("/api/v1/tools/erase-object", async (request: FastifyRequest, reply: FastifyReply) => {
|
app.post("/api/v1/tools/erase-object", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "erase-object";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let imageBuffer: Buffer | null = null;
|
let imageBuffer: Buffer | null = null;
|
||||||
let maskBuffer: Buffer | null = null;
|
let maskBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { noiseRemoval } from "@ashim/ai";
|
import { noiseRemoval } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { decodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
@@ -26,6 +28,18 @@ const settingsSchema = z.object({
|
|||||||
*/
|
*/
|
||||||
export function registerNoiseRemoval(app: FastifyInstance) {
|
export function registerNoiseRemoval(app: FastifyInstance) {
|
||||||
app.post("/api/v1/tools/noise-removal", async (request: FastifyRequest, reply: FastifyReply) => {
|
app.post("/api/v1/tools/noise-removal", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "noise-removal";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import { basename } from "node:path";
|
import { basename } from "node:path";
|
||||||
import { extractText } from "@ashim/ai";
|
import { extractText } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { formatZodErrors } from "../../lib/errors.js";
|
import { formatZodErrors } from "../../lib/errors.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
import { updateSingleFileProgress } from "../progress.js";
|
import { updateSingleFileProgress } from "../progress.js";
|
||||||
@@ -22,6 +24,18 @@ const settingsSchema = z.object({
|
|||||||
*/
|
*/
|
||||||
export function registerOcr(app: FastifyInstance) {
|
export function registerOcr(app: FastifyInstance) {
|
||||||
app.post("/api/v1/tools/ocr", async (request: FastifyRequest, reply: FastifyReply) => {
|
app.post("/api/v1/tools/ocr", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "ocr";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { readFile, writeFile } from "node:fs/promises";
|
import { readFile, writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { detectFaceLandmarks, removeBackground } from "@ashim/ai";
|
import { detectFaceLandmarks, removeBackground } from "@ashim/ai";
|
||||||
import { PASSPORT_SPECS, PRINT_LAYOUTS } from "@ashim/shared";
|
import { getBundleForTool, PASSPORT_SPECS, PRINT_LAYOUTS, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
import { formatZodErrors } from "../../lib/errors.js";
|
import { formatZodErrors } from "../../lib/errors.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { decodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { createWorkspace, getWorkspacePath } from "../../lib/workspace.js";
|
import { createWorkspace, getWorkspacePath } from "../../lib/workspace.js";
|
||||||
@@ -124,6 +125,18 @@ export function registerPassportPhoto(app: FastifyInstance) {
|
|||||||
app.post(
|
app.post(
|
||||||
"/api/v1/tools/passport-photo/analyze",
|
"/api/v1/tools/passport-photo/analyze",
|
||||||
async (request: FastifyRequest, reply: FastifyReply) => {
|
async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "passport-photo";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let clientJobId: string | null = null;
|
let clientJobId: string | null = null;
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { removeRedEye } from "@ashim/ai";
|
import { removeRedEye } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
import { updateSingleFileProgress } from "../progress.js";
|
import { updateSingleFileProgress } from "../progress.js";
|
||||||
@@ -15,6 +17,18 @@ export function registerRedEyeRemoval(app: FastifyInstance) {
|
|||||||
app.post(
|
app.post(
|
||||||
"/api/v1/tools/red-eye-removal",
|
"/api/v1/tools/red-eye-removal",
|
||||||
async (request: FastifyRequest, reply: FastifyReply) => {
|
async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "red-eye-removal";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { readFile, writeFile } from "node:fs/promises";
|
import { readFile, writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { removeBackground } from "@ashim/ai";
|
import { removeBackground } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
import { applyEffects } from "../../lib/bg-effects.js";
|
import { applyEffects } from "../../lib/bg-effects.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { decodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { createWorkspace, getWorkspacePath } from "../../lib/workspace.js";
|
import { createWorkspace, getWorkspacePath } from "../../lib/workspace.js";
|
||||||
@@ -41,6 +43,18 @@ export function registerRemoveBackground(app: FastifyInstance) {
|
|||||||
app.post(
|
app.post(
|
||||||
"/api/v1/tools/remove-background",
|
"/api/v1/tools/remove-background",
|
||||||
async (request: FastifyRequest, reply: FastifyReply) => {
|
async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "remove-background";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { randomUUID } from "node:crypto";
|
|||||||
import { writeFile } from "node:fs/promises";
|
import { writeFile } from "node:fs/promises";
|
||||||
import { basename, join } from "node:path";
|
import { basename, join } from "node:path";
|
||||||
import { upscale } from "@ashim/ai";
|
import { upscale } from "@ashim/ai";
|
||||||
|
import { getBundleForTool, TOOL_BUNDLE_MAP } from "@ashim/shared";
|
||||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { autoOrient } from "../../lib/auto-orient.js";
|
import { autoOrient } from "../../lib/auto-orient.js";
|
||||||
|
import { isToolInstalled } from "../../lib/feature-status.js";
|
||||||
import { validateImageBuffer } from "../../lib/file-validation.js";
|
import { validateImageBuffer } from "../../lib/file-validation.js";
|
||||||
import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js";
|
import { decodeHeic, encodeHeic } from "../../lib/heic-converter.js";
|
||||||
import { createWorkspace } from "../../lib/workspace.js";
|
import { createWorkspace } from "../../lib/workspace.js";
|
||||||
@@ -18,6 +20,18 @@ import { registerToolProcessFn } from "../tool-factory.js";
|
|||||||
*/
|
*/
|
||||||
export function registerUpscale(app: FastifyInstance) {
|
export function registerUpscale(app: FastifyInstance) {
|
||||||
app.post("/api/v1/tools/upscale", async (request: FastifyRequest, reply: FastifyReply) => {
|
app.post("/api/v1/tools/upscale", async (request: FastifyRequest, reply: FastifyReply) => {
|
||||||
|
const toolId = "upscale";
|
||||||
|
if (!isToolInstalled(toolId)) {
|
||||||
|
const bundle = getBundleForTool(toolId);
|
||||||
|
return reply.status(501).send({
|
||||||
|
error: "Feature not installed",
|
||||||
|
code: "FEATURE_NOT_INSTALLED",
|
||||||
|
feature: TOOL_BUNDLE_MAP[toolId],
|
||||||
|
featureName: bundle?.name ?? toolId,
|
||||||
|
estimatedSize: bundle?.estimatedSize ?? "unknown",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let fileBuffer: Buffer | null = null;
|
let fileBuffer: Buffer | null = null;
|
||||||
let filename = "image";
|
let filename = "image";
|
||||||
let settingsRaw: string | null = null;
|
let settingsRaw: string | null = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user