fix(app): remove legacy and scoped namespace alias

This commit is contained in:
2025-11-14 11:56:34 +02:00
parent 085851527e
commit 4ec2a608b1
681 changed files with 655 additions and 36825 deletions
+1 -1
View File
@@ -3,5 +3,5 @@ BASANGO_API_HOST=localhost
BASANGO_API_PORT=3080
BASANGO_API_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
BASANGO_API_KEY=your_api_key_here
BASANGO_CRAWLER_KEY=dev
BASANGO_CRAWLER_TOKEN=dev
BASANGO_JWT_SECRET=your_jwt_secret_here
-1
View File
@@ -11,7 +11,6 @@
"ai": "^5.0.89",
"camelcase-keys": "^10.0.1",
"date-fns": "catalog:",
"hono": "^4.10.4",
"hono-rate-limiter": "^0.4.2",
"jose": "^6.1.0",
"zod": "catalog:",
+1 -1
View File
@@ -27,7 +27,7 @@ export const { env, config } = defineConfig({
"BASANGO_API_PORT",
"BASANGO_API_ALLOWED_ORIGINS",
"BASANGO_API_KEY",
"BASANGO_CRAWLER_KEY",
"BASANGO_CRAWLER_TOKEN",
"BASANGO_JWT_SECRET",
],
path: path.join(PROJECT_DIR, ".env"),
+17 -4
View File
@@ -2,15 +2,28 @@ import { trpcServer } from "@hono/trpc-server";
import { OpenAPIHono } from "@hono/zod-openapi";
import { Scalar } from "@scalar/hono-api-reference";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { secureHeaders } from "hono/secure-headers";
import { config, env } from "@/config";
import { routers } from "@/rest/routers";
import { createTRPCContext } from "@/trpc/init";
import { appRouter } from "@/trpc/routers/_app";
import { config, env } from "#api/config";
import { routers } from "#api/rest/routers";
import { createTRPCContext } from "#api/trpc/init";
import { appRouter } from "#api/trpc/routers/_app";
const app = new OpenAPIHono();
app.use(async (c, next) => {
const data = await c.req.json();
console.log("Incoming Request:", {
data: data,
headers: c.req.header,
method: c.req.method,
url: c.req.url,
});
return next();
});
app.use(secureHeaders());
app.use(
+2 -2
View File
@@ -1,7 +1,7 @@
import type { MiddlewareHandler } from "hono";
import { HTTPException } from "hono/http-exception";
import { env } from "@/config";
import { env } from "#api/config";
export const withCrawlerAuth: MiddlewareHandler = async (c, next) => {
const token = c.req.header("Authorization");
@@ -10,7 +10,7 @@ export const withCrawlerAuth: MiddlewareHandler = async (c, next) => {
throw new HTTPException(401, { message: "Authorization header required" });
}
if (token !== env("BASANGO_CRAWLER_KEY")) {
if (token !== env("BASANGO_CRAWLER_TOKEN")) {
throw new HTTPException(403, { message: "Invalid token" });
}
+1 -1
View File
@@ -1,6 +1,6 @@
import type { MiddlewareHandler } from "hono";
import type { Scope } from "@/utils/scopes";
import type { Scope } from "#api/utils/scopes";
export const withRequiredScope = (...requiredScopes: Scope[]): MiddlewareHandler => {
return async (c, next) => {
+8 -7
View File
@@ -1,10 +1,11 @@
import { createArticle } from "@basango/db/queries";
import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
import { withCrawlerAuth } from "@/rest/middlewares/crawler";
import type { Context } from "@/rest/types";
import { createArticleResponseSchema, createArticleSchema } from "@/schemas/articles";
import { validateResponse } from "@/utils/response";
import { withCrawlerAuth } from "#api/rest/middlewares/crawler";
import { withDatabase } from "#api/rest/middlewares/db";
import type { Context } from "#api/rest/types";
import { createArticleResponseSchema, createArticleSchema } from "#api/schemas/articles";
import { validateResponse } from "#api/utils/response";
const app = new OpenAPIHono<Context>();
@@ -12,7 +13,7 @@ app.openapi(
createRoute({
description: "Store a new crawled article in the database.",
method: "post",
middleware: [withCrawlerAuth],
middleware: [withCrawlerAuth, withDatabase],
operationId: "CreateArticle",
path: "/",
request: {
@@ -40,8 +41,8 @@ app.openapi(
}),
async (c) => {
const db = c.get("db");
const body = c.req.valid("json");
const result = await createArticle(db, { ...body });
const input = c.req.valid("json");
const result = await createArticle(db, input);
return c.json(
validateResponse(result, createArticleResponseSchema) as { id: string; sourceId: string },
+2 -2
View File
@@ -1,8 +1,8 @@
import { OpenAPIHono } from "@hono/zod-openapi";
import { articlesRouter } from "@/rest/routers/articles";
import { articlesRouter } from "#api/rest/routers/articles";
const routers = new OpenAPIHono();
const routers: OpenAPIHono = new OpenAPIHono();
routers.route("/articles", articlesRouter);
+9 -41
View File
@@ -1,38 +1,5 @@
import { z } from "@hono/zod-openapi";
const sentimentSchema = z.enum(["positive", "neutral", "negative"]).openapi({
default: "neutral",
description: "The sentiment of the article content.",
});
const readingTimeSchema = z.number().min(1).openapi({
description: "The estimated reading time of the article in minutes.",
example: 5,
});
const tokenStatisticsSchema = z.object({
body: z.number().min(0).openapi({
description: "The number of tokens in the article body.",
example: 350,
}),
categories: z.number().min(0).openapi({
description: "The number of tokens in the article categories.",
example: 25,
}),
excerpt: z.number().min(0).openapi({
description: "The number of tokens in the article excerpt.",
example: 50,
}),
title: z.number().min(0).openapi({
description: "The number of tokens in the article title.",
example: 15,
}),
total: z.number().min(0).openapi({
description: "The total number of tokens in the article.",
example: 440,
}),
});
const metadataSchema = z.object({
description: z.string().optional().openapi({
description: "A brief description or summary of the article.",
@@ -54,10 +21,14 @@ export const createArticleSchema = z
description: "The main content of the article.",
example: "This is the body of the article...",
}),
categories: z.array(z.string()).openapi({
description: "The categories or tags associated with the article.",
example: ["Technology", "AI"],
}),
categories: z
.array(z.string())
.openapi({
description: "The categories or tags associated with the article.",
example: ["Technology", "AI"],
})
.optional()
.default([]),
hash: z.string().min(1).openapi({
description: "The unique hash of the article link.",
example: "d41d8cd98f00b204e9800998ecf8427e",
@@ -71,17 +42,14 @@ export const createArticleSchema = z
description: "The publication date of the article.",
example: "2023-01-01T00:00:00Z",
}),
readingTime: readingTimeSchema.optional(),
sentiment: sentimentSchema.optional().optional().default("neutral"),
sourceId: z.string().openapi({
description: "The unique identifier of the source from which the article was crawled.",
example: "source-123",
example: "radiookapi.net",
}),
title: z.string().min(1).openapi({
description: "The title of the article.",
example: "The Rise of AI",
}),
tokenStatistics: tokenStatisticsSchema.optional(),
})
.openapi("CreateArticle");
+4 -4
View File
@@ -3,10 +3,10 @@ import { initTRPC } from "@trpc/server";
import type { Context } from "hono";
import superjson from "superjson";
import { withAuthentication } from "@/trpc/middlewares/auth";
import { withDatabase } from "@/trpc/middlewares/db";
import { Session, verifyAccessToken } from "@/utils/auth";
import { getGeoContext } from "@/utils/geo";
import { withAuthentication } from "#api/trpc/middlewares/auth";
import { withDatabase } from "#api/trpc/middlewares/db";
import { Session, verifyAccessToken } from "#api/utils/auth";
import { getGeoContext } from "#api/utils/geo";
type TRPCContext = {
session: Session | null;
+1 -1
View File
@@ -2,7 +2,7 @@ import type { Database } from "@basango/db/client";
// import { TRPCError } from "@trpc/server";
import type { Session } from "@/utils/auth";
import type { Session } from "#api/utils/auth";
export const withAuthentication = async <TReturn>(opts: {
ctx: {
+2 -4
View File
@@ -1,6 +1,6 @@
import { type Database, db } from "@basango/db/client";
import type { Session } from "@/utils/auth";
import type { Session } from "#api/utils/auth";
export const withDatabase = async <TReturn>(opts: {
ctx: {
@@ -17,7 +17,5 @@ export const withDatabase = async <TReturn>(opts: {
const { ctx, next } = opts;
ctx.db = db;
const result = await next({ ctx });
return result;
return await next({ ctx });
};
+4 -3
View File
@@ -1,13 +1,14 @@
import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server";
import { createTRPCRouter } from "@/trpc/init";
import { sourcesRouter } from "@/trpc/routers/sources";
import { createTRPCRouter } from "#api/trpc/init";
import { articlesRouter } from "#api/trpc/routers/articles";
import { sourcesRouter } from "#api/trpc/routers/sources";
export const appRouter = createTRPCRouter({
articles: articlesRouter,
sources: sourcesRouter,
});
// export type definition of API
export type AppRouter = typeof appRouter;
export type RouterOutputs = inferRouterOutputs<AppRouter>;
export type RouterInputs = inferRouterInputs<AppRouter>;
+10
View File
@@ -0,0 +1,10 @@
import { createArticle } from "@basango/db/queries";
import { createArticleSchema } from "#api/schemas/articles";
import { createTRPCRouter, protectedProcedure } from "#api/trpc/init";
export const articlesRouter = createTRPCRouter({
create: protectedProcedure.input(createArticleSchema).mutation(async ({ ctx, input }) => {
return createArticle(ctx.db, input);
}),
});
+20 -5
View File
@@ -1,11 +1,18 @@
import { createSource, getSourceById, getSources, updateSource } from "@basango/db/queries";
import {
createSource,
getSourceById,
getSourceCategoryShares,
getSourcePublicationGraph,
getSources,
updateSource,
} from "@basango/db/queries";
import { createSourceSchema, getSourceSchema, updateSourceSchema } from "@/schemas/sources";
import { createTRPCRouter, protectedProcedure } from "@/trpc/init";
import { createSourceSchema, getSourceSchema, updateSourceSchema } from "#api/schemas/sources";
import { createTRPCRouter, protectedProcedure } from "#api/trpc/init";
export const sourcesRouter = createTRPCRouter({
create: protectedProcedure.input(createSourceSchema).mutation(async ({ ctx, input }) => {
return createSource(ctx.db, { ...input });
return createSource(ctx.db, input);
}),
get: protectedProcedure.query(async ({ ctx }) => getSources(ctx.db)),
@@ -14,7 +21,15 @@ export const sourcesRouter = createTRPCRouter({
return getSourceById(ctx.db, input.id);
}),
getCategoryShares: protectedProcedure.input(getSourceSchema).query(async ({ ctx, input }) => {
return getSourceCategoryShares(ctx.db, input.id);
}),
getPublicationGraph: protectedProcedure.input(getSourceSchema).query(async ({ ctx, input }) => {
return getSourcePublicationGraph(ctx.db, input.id);
}),
update: protectedProcedure.input(updateSourceSchema).mutation(async ({ ctx, input }) => {
return updateSource(ctx.db, { ...input });
return updateSource(ctx.db, input);
}),
});
+1 -1
View File
@@ -1,6 +1,6 @@
import { type JWTPayload, jwtVerify } from "jose";
import { env } from "@/config";
import { env } from "#api/config";
export type Session = {
user: {
+6 -3
View File
@@ -1,11 +1,14 @@
{
"compilerOptions": {
"baseUrl": ".",
"composite": true,
"incremental": true,
"paths": {
"@/*": ["./src/*", "../../packages/db/src/*"]
"@basango/db": ["../../packages/db/src/*"],
"#api/*": ["./src/*"],
"#db/*": ["../../packages/db/src/*"]
}
},
"extends": "@basango/tsconfig/base.json",
"include": ["src"],
"references": []
"include": ["src"]
}