chore: remove files importing pruned packages (ai, cms, cognitive-context)

Step 3 pruned packages/{ai,cms,cognitive-context} but left whole
route groups + feature modules that depended on them. Those files
were unbuildable since that prune. Removes them now so the workspace
can be validated:

Route groups:
- apps/web/src/app/[locale]/(apps)/{chat,image,pdf,tts}/
- apps/web/src/app/[locale]/(marketing)/blog/

Feature modules:
- apps/web/src/modules/{chat,image,pdf,tts,common/ai,marketing/blog}/
- packages/api/src/modules/ai/  (chat, image, pdf, stt, tts, router)

3 stragglers remain (separate handoff to claudemesh-2):
- apps/web/src/app/[locale]/(marketing)/legal/[slug]/page.tsx  (cms)
- apps/web/src/app/sitemap.ts                                   (cms)
- apps/web/src/modules/common/layout/credits/index.tsx          (ai)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-04 22:02:26 +01:00
parent 8ce8b04e75
commit 1f094c4c53
122 changed files with 0 additions and 11536 deletions

View File

@@ -1,48 +0,0 @@
import { Hono } from "hono";
import {
getUserChats,
deleteChat,
getChat,
streamChat,
getChatMessagesWithAttachments,
} from "@turbostarter/ai/chat/api";
import { chatMessageSchema } from "@turbostarter/ai/chat/schema";
import { getCreditsDeduction } from "@turbostarter/ai/chat/utils";
import { deductCredits, enforceAuth, rateLimiter, validate } from "../../middleware";
import type { User } from "@turbostarter/auth";
const chatsRouter = new Hono<{
Variables: {
user: User;
};
}>()
.post(
"/",
enforceAuth,
rateLimiter,
validate("json", chatMessageSchema),
async (c) => {
const input = c.req.valid("json");
const creditsAmount = getCreditsDeduction(input.metadata.options, input.parts);
// Deduct credits
await deductCredits(creditsAmount, "chat")(c, async () => { /* noop */ });
return streamChat({
...input,
signal: c.req.raw.signal,
userId: c.var.user.id,
});
},
)
.get("/", enforceAuth, async (c) => c.json(await getUserChats(c.var.user.id)))
.delete("/:id", enforceAuth, async (c) => c.json(await deleteChat(c.req.param("id"))))
.get("/:id", enforceAuth, async (c) => c.json((await getChat(c.req.param("id"))) ?? null))
.get("/:id/messages", enforceAuth, async (c) =>
c.json(await getChatMessagesWithAttachments(c.req.param("id"))),
);
export const chatRouter = new Hono().route("/chats", chatsRouter);

View File

@@ -1,89 +0,0 @@
import { Hono } from "hono";
import * as z from "zod";
import { Credits } from "@turbostarter/ai/credits/utils";
import {
createGeneration,
generateImages,
getGeneration,
getGenerationImages,
getImages,
} from "@turbostarter/ai/image/api";
import { imageGenerationSchema } from "@turbostarter/ai/image/schema";
import { deductCredits, enforceAuth, rateLimiter, validate } from "../../middleware";
import { withTimeout } from "../../utils";
import type { User } from "@turbostarter/auth";
const generationsRouter = new Hono<{
Variables: {
user: User;
};
}>()
.post(
"/",
enforceAuth,
validate("json", imageGenerationSchema),
async (c) => {
const input = c.req.valid("json");
const creditsAmount = input.options.count * Credits.COST.DEFAULT;
// Deduct credits
await deductCredits(creditsAmount, "image-generation")(c, async () => { /* noop */ });
return c.json(
await createGeneration({
userId: c.var.user.id,
...input,
...input.options,
}),
);
},
)
.post("/:id/images", enforceAuth, rateLimiter, async (c) =>
c.json(
await withTimeout(
generateImages({
id: c.req.param("id"),
abortSignal: c.req.raw.signal,
}),
55 * 1000,
),
),
)
.get("/:id", enforceAuth, async (c) =>
c.json((await getGeneration(c.req.param("id"))) ?? null),
)
.get("/:id/images", enforceAuth, async (c) =>
c.json(await getGenerationImages(c.req.param("id"))),
);
const imagesRouter = new Hono<{
Variables: {
user: User;
};
}>().get(
"/",
enforceAuth,
validate(
"query",
z
.object({
limit: z.number().optional(),
cursor: z.coerce.date().optional(),
})
.optional(),
),
async (c) =>
c.json(
await getImages({
userId: c.var.user.id,
...c.req.valid("query"),
}),
),
);
export const imageRouter = new Hono()
.route("/generations", generationsRouter)
.route("/images", imagesRouter);

View File

@@ -1,254 +0,0 @@
import { Hono } from "hono";
import * as z from "zod";
import { Credits } from "@turbostarter/ai/credits/utils";
import {
createChat,
deleteChat,
getChat,
getChatDocuments,
getChatMessages,
getDocument,
getUserChats,
streamChatWithDocuments,
} from "@turbostarter/ai/pdf/api";
import { pdfMessageSchema } from "@turbostarter/ai/pdf/schema";
import {
searchWithCitations,
getCitationUnitsForChunk,
getCitationUnitById,
} from "@turbostarter/ai/pdf/search";
import {
insertPdfChatSchema,
insertPdfDocumentSchema,
} from "@turbostarter/db/schema/pdf";
import { deductCredits, enforceAuth, rateLimiter, validate } from "../../middleware";
import type { User } from "@turbostarter/auth";
const createChatSchema = z.object({
...insertPdfChatSchema.omit({ userId: true }).shape,
...insertPdfDocumentSchema.omit({ chatId: true }).shape,
});
type _CreateChatInput = z.infer<typeof createChatSchema>;
// ============================================================================
// Search Schemas
// ============================================================================
const searchInputSchema = z.object({
query: z.string().min(1),
documentId: z.string(),
limit: z.number().min(1).max(20).optional(),
threshold: z.number().min(0).max(1).optional(),
});
type _SearchInput = z.infer<typeof searchInputSchema>;
const chatsRouter = new Hono<{
Variables: {
user: User;
};
}>()
.post(
"/",
enforceAuth,
rateLimiter,
validate("json", createChatSchema),
async (c) => {
const input = c.req.valid("json");
// Deduct credits
await deductCredits(Credits.COST.DEFAULT, "pdf-chat")(c, async () => { /* noop */ });
return c.json(
await createChat({
...input,
userId: c.var.user.id,
}),
);
},
)
.get("/", enforceAuth, async (c) => c.json(await getUserChats(c.var.user.id)))
.get("/:id", enforceAuth, async (c) =>
c.json((await getChat(c.req.param("id"))) ?? null),
)
.delete("/:id", enforceAuth, async (c) =>
c.json(await deleteChat(c.req.param("id"))),
)
.post(
"/:id/messages",
enforceAuth,
rateLimiter,
validate("json", pdfMessageSchema),
async (c) => {
const input = c.req.valid("json");
const chatId = c.req.param("id");
// Get documents for this chat to enable document-specific search
const documents = await getChatDocuments(chatId);
const documentIds = documents.map((d) => d.id);
console.log(`📝 POST /:id/messages - chatId: ${chatId}, documents found: ${documents.length}, documentIds:`, documentIds);
// Deduct credits
await deductCredits(Credits.COST.DEFAULT, "pdf-chat")(c, async () => { /* noop */ });
return streamChatWithDocuments({
...input,
signal: c.req.raw.signal,
chatId,
documentIds,
});
},
)
.get("/:id/messages", enforceAuth, async (c) =>
c.json(await getChatMessages(c.req.param("id"))),
)
.get("/:id/documents", enforceAuth, async (c) =>
c.json(await getChatDocuments(c.req.param("id"))),
);
// ============================================================================
// Embeddings Router
// ============================================================================
const embeddingsRouter = new Hono<{
Variables: {
user: User;
};
}>()
.get("/:id", enforceAuth, async (c) => {
const { getEmbeddingById } = await import("@turbostarter/ai/pdf/embeddings");
const embedding = await getEmbeddingById(c.req.param("id"));
if (!embedding) {
return c.json({ error: "Embedding not found" }, 404);
}
return c.json(embedding);
});
// ============================================================================
// Search Router (WF-0028 Dual-Resolution Search)
// ============================================================================
const searchRouter = new Hono<{
Variables: {
user: User;
};
}>()
.post(
"/",
enforceAuth,
validate("json", searchInputSchema),
async (c) => {
const input = c.req.valid("json");
const results = await searchWithCitations(input.query, input.documentId, {
limit: input.limit,
threshold: input.threshold,
});
return c.json({ data: results });
},
)
// NOTE: More specific route must come BEFORE generic :chunkId route
.get("/citation-units/single/:id", enforceAuth, async (c) => {
const unitId = c.req.param("id");
const unit = await getCitationUnitById(unitId);
if (!unit) {
return c.json({ error: "Citation unit not found" }, 404);
}
return c.json({ data: unit });
})
.get("/citation-units/:chunkId", enforceAuth, async (c) => {
const chunkId = c.req.param("chunkId");
const units = await getCitationUnitsForChunk(chunkId);
return c.json({ data: units });
});
// ============================================================================
// Documents Router (document status and management)
// ============================================================================
const documentsRouter = new Hono<{
Variables: {
user: User;
};
}>()
.get("/:id/status", enforceAuth, async (c) => {
const document = await getDocument(c.req.param("id"));
if (!document) {
return c.json({ error: "Document not found" }, 404);
}
return c.json({
id: document.id,
processingStatus: document.processingStatus,
processingError: document.processingError,
});
});
// ============================================================================
// Diagnostics Router (for debugging embedding issues)
// ============================================================================
const diagnosticsRouter = new Hono<{
Variables: {
user: User;
};
}>()
.get("/chat/:chatId", enforceAuth, async (c) => {
const { sql } = await import("@turbostarter/db");
const { db } = await import("@turbostarter/db/server");
const chatId = c.req.param("chatId");
// Get documents for this chat
const documents = await getChatDocuments(chatId);
if (documents.length === 0) {
return c.json({ error: "No documents found for chat", chatId });
}
// Get embedding counts per document
const diagnostics = await Promise.all(
documents.map(async (doc) => {
const countResult = await db.execute<{ count: string }>(sql`
SELECT COUNT(*) as count FROM pdf.embedding WHERE document_id = ${doc.id}
`);
const rows = Array.isArray(countResult) ? countResult : [];
const count = parseInt(rows[0]?.count ?? "0", 10);
// Get sample content
const sampleResult = await db.execute<{ content: string; page_number: number }>(sql`
SELECT LEFT(content, 100) as content, page_number
FROM pdf.embedding
WHERE document_id = ${doc.id}
LIMIT 2
`);
const samples = Array.isArray(sampleResult) ? sampleResult : [];
return {
documentId: doc.id,
documentName: doc.name,
embeddingCount: count,
samples: samples.map(s => ({
preview: s.content,
page: s.page_number,
})),
};
})
);
return c.json({
chatId,
documentCount: documents.length,
documents: diagnostics,
totalEmbeddings: diagnostics.reduce((sum, d) => sum + d.embeddingCount, 0),
});
});
export const pdfRouter = new Hono()
.route("/chats", chatsRouter)
.route("/documents", documentsRouter)
.route("/embeddings", embeddingsRouter)
.route("/search", searchRouter)
.route("/diagnostics", diagnosticsRouter);

View File

@@ -1,20 +0,0 @@
import { Hono } from "hono";
import { getUserCredits } from "@turbostarter/ai/credits/server";
import { enforceAuth } from "../../middleware";
import { chatRouter } from "./chat";
import { imageRouter } from "./image";
import { pdfRouter } from "./pdf";
import { sttRouter } from "./stt";
import { ttsRouter } from "./tts";
export const aiRouter = new Hono()
.use(enforceAuth)
.route("/chat", chatRouter)
.route("/pdf", pdfRouter)
.route("/image", imageRouter)
.route("/tts", ttsRouter)
.route("/stt", sttRouter)
.get("/credits", async (c) => c.json(await getUserCredits(c.var.user.id)));

View File

@@ -1,55 +0,0 @@
import { Hono } from "hono";
import { Credits } from "@turbostarter/ai/credits/utils";
import { transcribe } from "@turbostarter/ai/stt/api";
import { transcriptionOptionsSchema } from "@turbostarter/ai/stt/schema";
import { deductCredits, enforceAuth, rateLimiter } from "../../middleware";
import type { User } from "@turbostarter/auth";
export const sttRouter = new Hono<{
Variables: {
user: User;
};
}>().post("/", enforceAuth, rateLimiter, async (c) => {
console.log("[STT] Request received");
// Use Hono's typed FormData methods to work across different runtime environments
const formData = await c.req.formData();
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
const audioFile = ((formData as any).get?.("audio") ?? (formData as any).getAll?.("audio")?.[0]) as File | null;
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
console.log("[STT] Audio file:", audioFile ? `${audioFile.name} (${audioFile.size} bytes, ${audioFile.type})` : "null");
if (!audioFile) {
return c.json({ error: "No audio file provided" }, 400);
}
// Parse optional parameters
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
const fd = formData as any;
const language = (fd.get?.("language") ?? fd.getAll?.("language")?.[0]) as string | null;
const prompt = (fd.get?.("prompt") ?? fd.getAll?.("prompt")?.[0]) as string | null;
/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
const options = transcriptionOptionsSchema.parse({
language: language ?? undefined,
prompt: prompt ?? undefined,
});
// Deduct credits
console.log("[STT] Deducting credits...");
await deductCredits(Credits.COST.DEFAULT, "speech-to-text")(c, async () => { /* noop */ });
console.log("[STT] Credits deducted, calling OpenAI Whisper...");
try {
const result = await transcribe(audioFile, options);
console.log("[STT] Transcription successful:", result.text.substring(0, 50));
return c.json(result);
} catch (error) {
console.error("[STT] Transcription error:", error);
throw error;
}
});

View File

@@ -1,40 +0,0 @@
import { Hono } from "hono";
import { Credits } from "@turbostarter/ai/credits/utils";
import { getVoices, textToSpeech } from "@turbostarter/ai/tts/api";
import { ttsSchema } from "@turbostarter/ai/tts/schema";
import { deductCredits, enforceAuth, rateLimiter, validate } from "../../middleware";
import type { User } from "@turbostarter/auth";
export const ttsRouter = new Hono<{
Variables: {
user: User;
};
}>()
.post(
"/",
enforceAuth,
rateLimiter,
validate("json", ttsSchema),
async (c) => {
const input = c.req.valid("json");
// Deduct credits
await deductCredits(Credits.COST.HIGH, "text-to-speech")(c, async () => { /* noop */ });
return new Response(
(await textToSpeech(input)) as unknown as ConstructorParameters<
typeof Response
>[0],
{
headers: { "Content-Type": "audio/mpeg" },
},
);
},
)
.get("/voices", enforceAuth, async (c) => {
const voices = await getVoices();
return c.json(voices);
});