fix(app): remove legacy and scoped namespace alias
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
@@ -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:",
|
||||
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -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,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) => {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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 });
|
||||
};
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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);
|
||||
}),
|
||||
});
|
||||
@@ -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,6 +1,6 @@
|
||||
import { type JWTPayload, jwtVerify } from "jose";
|
||||
|
||||
import { env } from "@/config";
|
||||
import { env } from "#api/config";
|
||||
|
||||
export type Session = {
|
||||
user: {
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user