diff --git a/backend/package.json b/backend/package.json index e5a0a49..ba8913f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,57 +1,46 @@ { "name": "@curatedotfun/backend", "version": "0.0.1", - "packageManager": "bun@1.0.27", - "type": "module", "scripts": { - "build": "bun build ./src/index.ts --target=bun --outdir=dist --format=esm --external './src/external' && cp -r src/external dist/external/", - "start": "bun run dist/index.js", - "dev": "bun run --watch src/index.ts", - "test": "bun test", - "test:watch": "bun test --watch", - "db:generate": "bun drizzle-kit generate", - "db:migrate": "bun drizzle-kit migrate", - "db:push": "bun drizzle-kit push", - "db:pull": "bun drizzle-kit pull", - "db:check": "bun drizzle-kit check", - "db:up": "bun drizzle-kit up", - "db:studio": "bun drizzle-kit studio" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "build": "rspack build", + "start": "node dist/main.js", + "dev": "rspack serve --hot", + "test": "jest", + "test:watch": "jest --watch", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + "db:push": "drizzle-kit push", + "db:pull": "drizzle-kit pull", + "db:check": "drizzle-kit check", + "db:up": "drizzle-kit up", + "db:studio": "drizzle-kit studio" }, "devDependencies": { + "@module-federation/enhanced": "^0.8.9", + "@module-federation/node": "^2.6.22", + "@module-federation/runtime": "0.8.9", + "@module-federation/dts-plugin": "^0.8.9", + "@rspack/cli": "^1.2.2", + "@rspack/core": "^1.2.2", + "@types/better-sqlite3": "^7.6.9", + "@types/jest": "^29.5.12", "@types/ora": "^3.2.0", - "bun-types": "^1.1.43", "drizzle-kit": "^0.30.1", "jest": "^29.7.0", "jest-mock-extended": "^4.0.0-beta1", "ts-jest": "^29.2.5", - "ts-node": "^10.9.1", "typescript": "^5.3.3" }, "dependencies": { - "@elysiajs/cors": "^1.2.0", - "@elysiajs/static": "^1.2.0", - "@elysiajs/swagger": "^1.2.0", + "@hono/node-server": "^1.13.8", + "@hono/swagger-ui": "^0.5.0", + "@hono/zod-validator": "^0.4.2", "@libsql/client": "^0.14.0", - "@types/cors": "^2.8.17", "agent-twitter-client": "^0.0.16", - "cors": "^2.8.5", + "better-sqlite3": "^9.4.0", "dotenv": "^16.0.3", "drizzle-orm": "^0.38.3", - "elysia": "^1.2.10", - "elysia-helmet": "^2.0.0", - "express": "^4.18.2", + "hono": "^4.6.20", "ora": "^8.1.1", "winston": "^3.17.0", "winston-console-format": "^1.0.8" diff --git a/backend/rspack.config.cjs b/backend/rspack.config.cjs new file mode 100644 index 0000000..db42a2a --- /dev/null +++ b/backend/rspack.config.cjs @@ -0,0 +1,43 @@ +const { UniversalFederationPlugin } = require('@module-federation/node'); + +/** @type {import('@rspack/core').Configuration} */ +const config = { + target: 'async-node', + entry: { + main: './src/index.ts', + }, + output: { + publicPath: 'http://localhost:3001/', + library: { type: 'commonjs-module' }, + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: [/node_modules/], + loader: 'builtin:swc-loader', + options: { + jsc: { + parser: { + syntax: 'typescript', + }, + }, + }, + type: 'javascript/auto', + }, + ], + }, + plugins: [ + new UniversalFederationPlugin({ + remoteType: 'script', + isServer: true, + name: 'host', + useRuntimePlugin: true, + }) + ], + resolve: { + extensions: ['.ts', '.js'], + } +}; + +module.exports = config; diff --git a/backend/src/index.ts b/backend/src/index.ts index 0fc5ac6..0d7ad2d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,10 +1,13 @@ -import { cors } from "@elysiajs/cors"; -import { staticPlugin } from "@elysiajs/static"; -import { swagger } from "@elysiajs/swagger"; +import { Hono } from "hono"; +import { cors } from "hono/cors"; +import { logger as honoLogger } from "hono/logger"; +import { secureHeaders } from "hono/secure-headers"; +import { serve } from "@hono/node-server"; +import { serveStatic } from "@hono/node-server/serve-static"; +import { swaggerUI } from "@hono/swagger-ui"; import dotenv from "dotenv"; -import { Elysia } from "elysia"; -import { helmet } from "elysia-helmet"; import path from "path"; +import { promises as fs } from "fs"; import configService, { validateEnv } from "./config/config"; import RssPlugin from "./external/rss"; import { db } from "./services/db"; @@ -87,198 +90,184 @@ export async function main() { // Initialize server startSpinner("server", "Starting server..."); - const app = new Elysia() - .use( - helmet({ - contentSecurityPolicy: { - directives: { - defaultSrc: ["'self'"], - imgSrc: ["'self'", "data:", "https:"], - fontSrc: ["'self'", "data:", "https:"], - }, - }, - crossOriginEmbedderPolicy: false, - crossOriginResourcePolicy: { policy: "cross-origin" }, - xFrameOptions: { action: "sameorigin" }, - }), - ) - .use( - cors({ - origin: ALLOWED_ORIGINS, - methods: ["GET", "POST"], - }), - ) - .use(swagger()) - // Include test routes in development - .use(process.env.NODE_ENV === "development" ? testRoutes : new Elysia()) - .get("/health", () => new Response("OK", { status: 200 })) + const app = new Hono(); + + // Middleware + app.use("*", honoLogger()); + app.use("*", cors({ + origin: ALLOWED_ORIGINS, + allowMethods: ["GET", "POST"], + })); + app.use("*", secureHeaders({ + contentSecurityPolicy: { + defaultSrc: ["'self'"], + imgSrc: ["'self'", "data:", "https:"], + fontSrc: ["'self'", "data:", "https:"], + }, + crossOriginEmbedderPolicy: false, + crossOriginResourcePolicy: "cross-origin", + xFrameOptions: "sameorigin", + })); + + // Swagger UI + app.use("/swagger/*", swaggerUI({ url: "/api/swagger.json" })); + + // Include test routes in development + if (process.env.NODE_ENV === "development") { + app.route("/", testRoutes); + } + + app.get("/health", (c) => c.text("OK", 200)) // API Routes - .get("/api/twitter/last-tweet-id", () => { - if (!twitterService) { - throw new Error("Twitter service not available"); - } - const lastTweetId = twitterService.getLastCheckedTweetId(); - return { lastTweetId }; - }) - .post( - "/api/twitter/last-tweet-id", - async ({ body }: { body: { tweetId: string } }) => { - if (!twitterService) { - throw new Error("Twitter service not available"); - } - if ( - !body?.tweetId || - typeof body.tweetId !== "string" || - !body.tweetId.match(/^\d+$/) - ) { - throw new Error("Invalid tweetId format"); - } - await twitterService.setLastCheckedTweetId(body.tweetId); - return { success: true }; - }, - ) - .get( - "/api/submission/:submissionId", - ({ - params: { submissionId }, - }: { - params: { submissionId: string }; - }) => { - const content = db.getSubmission(submissionId); - if (!content) { - throw new Error(`Content not found: ${submissionId}`); - } - return content; - }, - ) - .get("/api/submissions", () => { - return db.getAllSubmissions(); - }) - .get( - "/api/submissions/:feedId", - ({ params: { feedId } }: { params: { feedId: string } }) => { - const config = configService.getConfig(); - const feed = config.feeds.find( - (f) => f.id.toLowerCase() === feedId.toLowerCase(), - ); - if (!feed) { - throw new Error(`Feed not found: ${feedId}`); - } - return db.getSubmissionsByFeed(feedId); - }, - ) - .get( - "/api/feed/:feedId", - ({ params: { feedId } }: { params: { feedId: string } }) => { - const config = configService.getConfig(); - const feed = config.feeds.find( - (f) => f.id.toLowerCase() === feedId.toLowerCase(), - ); - if (!feed) { - throw new Error(`Feed not found: ${feedId}`); - } + app.get("/api/twitter/last-tweet-id", async (c) => { + if (!twitterService) { + throw new Error("Twitter service not available"); + } + const lastTweetId = twitterService.getLastCheckedTweetId(); + return c.json({ lastTweetId }); + }) + app.post("/api/twitter/last-tweet-id", async (c) => { + if (!twitterService) { + throw new Error("Twitter service not available"); + } + const body = await c.req.json(); + if ( + !body?.tweetId || + typeof body.tweetId !== "string" || + !body.tweetId.match(/^\d+$/) + ) { + throw new Error("Invalid tweetId format"); + } + await twitterService.setLastCheckedTweetId(body.tweetId); + return c.json({ success: true }); + }) + app.get("/api/submission/:submissionId", (c) => { + const submissionId = c.req.param("submissionId"); + const content = db.getSubmission(submissionId); + if (!content) { + throw new Error(`Content not found: ${submissionId}`); + } + return c.json(content); + }) + app.get("/api/submissions", (c) => { + return c.json(db.getAllSubmissions()); + }) + app.get("/api/submissions/:feedId", (c) => { + const feedId = c.req.param("feedId"); + const config = configService.getConfig(); + const feed = config.feeds.find( + (f) => f.id.toLowerCase() === feedId.toLowerCase(), + ); + if (!feed) { + throw new Error(`Feed not found: ${feedId}`); + } + return c.json(db.getSubmissionsByFeed(feedId)); + }) + app.get("/api/feed/:feedId", (c) => { + const feedId = c.req.param("feedId"); + const config = configService.getConfig(); + const feed = config.feeds.find( + (f) => f.id.toLowerCase() === feedId.toLowerCase(), + ); + if (!feed) { + throw new Error(`Feed not found: ${feedId}`); + } + return c.json(db.getSubmissionsByFeed(feedId)); + }) + app.get("/api/config", async (c) => { + const rawConfig = await configService.getRawConfig(); + return c.json(rawConfig); + }) + app.get("/api/feeds", async (c) => { + const rawConfig = await configService.getRawConfig(); + return c.json(rawConfig.feeds); + }) + app.get("/api/config/:feedId", (c) => { + const feedId = c.req.param("feedId"); + const config = configService.getConfig(); + const feed = config.feeds.find((f) => f.id === feedId); + if (!feed) { + throw new Error(`Feed not found: ${feedId}`); + } + return c.json(feed); + }) + app.get("/plugin/rss/:feedId", (c) => { + const feedId = c.req.param("feedId"); + if (!distributionService) { + throw new Error("Distribution service not available"); + } + const rssPlugin = distributionService.getPlugin("rss"); + if (!rssPlugin || !(rssPlugin instanceof RssPlugin)) { + throw new Error("RSS plugin not found or invalid"); + } - return db.getSubmissionsByFeed(feedId); - }, - ) - .get("/api/config", async () => { - const rawConfig = await configService.getRawConfig(); - return rawConfig; - }) - .get("/api/feeds", async () => { - const rawConfig = await configService.getRawConfig(); - return rawConfig.feeds; - }) - .get( - "/api/config/:feedId", - ({ params: { feedId } }: { params: { feedId: string } }) => { - const config = configService.getConfig(); - const feed = config.feeds.find((f) => f.id === feedId); - if (!feed) { - throw new Error(`Feed not found: ${feedId}`); - } - return feed; - }, - ) - .get( - "/plugin/rss/:feedId", - ({ params: { feedId } }: { params: { feedId: string } }) => { - if (!distributionService) { - throw new Error("Distribution service not available"); - } - const rssPlugin = distributionService.getPlugin("rss"); - if (!rssPlugin || !(rssPlugin instanceof RssPlugin)) { - throw new Error("RSS plugin not found or invalid"); - } + const service = rssPlugin.getServices().get(feedId); + if (!service) { + throw new Error("RSS service not initialized for this feed"); + } - const service = rssPlugin.getServices().get(feedId); - if (!service) { - throw new Error("RSS service not initialized for this feed"); - } + return c.json(service.getItems()); + }) + // app.post("/api/feeds/:feedId/process", async (c) => { + // const feedId = c.req.param("feedId"); + // // Get feed config + // const config = configService.getConfig(); + // const feed = config.feeds.find((f) => f.id === feedId); + // if (!feed) { + // throw new Error(`Feed not found: ${feedId}`); + // } - return service.getItems(); - }, - ) - // .post( - // "/api/feeds/:feedId/process", - // async ({ params: { feedId } }: { params: { feedId: string } }) => { - // // Get feed config - // const config = configService.getConfig(); - // const feed = config.feeds.find((f) => f.id === feedId); - // if (!feed) { - // throw new Error(`Feed not found: ${feedId}`); - // } + // // Get approved submissions for this feed + // const submissions = db + // .getSubmissionsByFeed(feedId) + // .filter((sub) => + // db + // .getFeedsBySubmission(sub.tweetId) + // .some((feed) => feed.status === "approved"), + // ); - // // Get approved submissions for this feed - // const submissions = db - // .getSubmissionsByFeed(feedId) - // .filter((sub) => - // db - // .getFeedsBySubmission(sub.tweetId) - // .some((feed) => feed.status === "approved"), - // ); + // if (submissions.length === 0) { + // return c.json({ processed: 0 }); + // } - // if (submissions.length === 0) { - // return { processed: 0 }; - // } + // // Process each submission through stream output + // let processed = 0; + // if (!distributionService) { + // throw new Error("Distribution service not available"); + // } + // for (const submission of submissions) { + // try { + // await distributionService.processStreamOutput( + // feedId, + // submission.tweetId, + // submission.content, + // ); + // processed++; + // } catch (error) { + // logger.error( + // `Error processing submission ${submission.tweetId}:`, + // error, + // ); + // } + // } - // // Process each submission through stream output - // let processed = 0; - // if (!distributionService) { - // throw new Error("Distribution service not available"); - // } - // for (const submission of submissions) { - // try { - // await distributionService.processStreamOutput( - // feedId, - // submission.tweetId, - // submission.content, - // ); - // processed++; - // } catch (error) { - // logger.error( - // `Error processing submission ${submission.tweetId}:`, - // error, - // ); - // } - // } + // return c.json({ processed }); + // }); + // Serve static files + app.use("/*", serveStatic({ root: FRONTEND_DIST_PATH })); + + // Serve index.html for all other routes (SPA fallback) + app.get("/*", async (c) => { + const content = await fs.readFile(`${FRONTEND_DIST_PATH}/index.html`, 'utf-8'); + return c.html(content); + }); - // return { processed }; - // }, - // ) - // This was the most annoying thing to set up and debug. Serves our frontend and handles routing. alwaysStatic is essential. - .use( - staticPlugin({ - assets: FRONTEND_DIST_PATH, - prefix: "/", - alwaysStatic: true, - }), - ) - .get("/*", () => Bun.file(`${FRONTEND_DIST_PATH}/index.html`)) - .listen({ - port: PORT, - hostname: "0.0.0.0", - }); + // Start the server + serve({ + fetch: app.fetch.bind(app), + port: PORT, + hostname: "0.0.0.0" + }); succeedSpinner("server", `Server running on port ${PORT}`); diff --git a/backend/src/routes/test.ts b/backend/src/routes/test.ts index 58dcd50..3bfa2a9 100644 --- a/backend/src/routes/test.ts +++ b/backend/src/routes/test.ts @@ -1,5 +1,5 @@ import { Tweet } from "agent-twitter-client"; -import { Elysia } from "elysia"; +import { Hono } from "hono"; import { MockTwitterService } from "../__tests__/mocks/twitter-service.mock"; // Create a single mock instance to maintain state @@ -29,16 +29,16 @@ const createTweet = ( }; }; -export const testRoutes = new Elysia({ prefix: "/api/test" }) - .guard({ - beforeHandle: ({ request }) => { - // Only allow in development and test environments - if (process.env.NODE_ENV === "production") { - return new Response("Not found", { status: 404 }); - } - }, +export const testRoutes = new Hono() + .use("/api/test/*", async (c, next) => { + // Only allow in development and test environments + if (process.env.NODE_ENV === "production") { + return c.text("Not found", 404); + } + await next(); }) - .post("/tweets", async ({ body }) => { + .post("/api/test/tweets", async (c) => { + const body = await c.req.json(); const { id, text, username, inReplyToStatusId, hashtags } = body as { id: string; text: string; @@ -48,11 +48,11 @@ export const testRoutes = new Elysia({ prefix: "/api/test" }) }; const tweet = createTweet(id, text, username, inReplyToStatusId, hashtags); mockTwitterService.addMockTweet(tweet); - return tweet; + return c.json(tweet); }) - .post("/reset", () => { + .post("/api/test/reset", (c) => { mockTwitterService.clearMockTweets(); - return { success: true }; + return c.json({ success: true }); }); // Export for use in tests and for replacing the real service diff --git a/backend/src/services/db/index.ts b/backend/src/services/db/index.ts index fccc27b..f93e2eb 100644 --- a/backend/src/services/db/index.ts +++ b/backend/src/services/db/index.ts @@ -1,8 +1,8 @@ -import { Database } from "bun:sqlite"; -import { BunSQLiteDatabase, drizzle } from "drizzle-orm/bun-sqlite"; +import Database from "better-sqlite3"; +import { BetterSQLite3Database, drizzle } from "drizzle-orm/better-sqlite3"; import { join } from "node:path"; -import { logger } from "utils/logger"; +import { logger } from "../../utils/logger"; import { DBOperations } from "./operations"; import * as queries from "./queries"; @@ -14,19 +14,19 @@ import { TwitterCookie, TwitterSubmission, SubmissionStatus, -} from "types/twitter"; +} from "../../types/twitter"; import * as rssQueries from "../rss/queries"; import * as twitterQueries from "../twitter/queries"; export class DatabaseService { - private db: BunSQLiteDatabase; + private db: BetterSQLite3Database; private operations: DBOperations; private static readonly DB_PATH = process.env.DATABASE_URL?.replace("file:", "") || join(".db", "submissions.sqlite"); constructor() { - const sqlite = new Database(DatabaseService.DB_PATH, { create: true }); - this.db = drizzle(sqlite); + const sqlite = new Database(DatabaseService.DB_PATH); + this.db = drizzle(sqlite, { logger: process.env.NODE_ENV === "development" }); this.operations = new DBOperations(this.db); } diff --git a/backend/src/services/db/operations.ts b/backend/src/services/db/operations.ts index 616a10c..6913868 100644 --- a/backend/src/services/db/operations.ts +++ b/backend/src/services/db/operations.ts @@ -1,4 +1,4 @@ -import { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite"; +import { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; import { RssItem, saveRssItem, @@ -8,7 +8,7 @@ import { // These are made available for plugins export class DBOperations { - constructor(private db: BunSQLiteDatabase) {} + constructor(private db: BetterSQLite3Database) {} // RSS Operations saveRssItem(feedId: string, item: RssItem): void { diff --git a/backend/src/services/db/queries.ts b/backend/src/services/db/queries.ts index 03ed5b9..fdf1778 100644 --- a/backend/src/services/db/queries.ts +++ b/backend/src/services/db/queries.ts @@ -1,12 +1,12 @@ import { and, eq, sql } from "drizzle-orm"; -import { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite"; +import { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; import { SubmissionFeed, Moderation, TwitterSubmission, SubmissionStatus, TwitterSubmissionWithFeedData, -} from "types/twitter"; +} from "../../types/twitter"; import { feedPlugins, feeds, @@ -18,7 +18,7 @@ import { import { DbQueryResult, DbFeedQueryResult } from "./types"; export function upsertFeeds( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, feedsToUpsert: { id: string; name: string; description?: string }[], ) { return db.transaction(() => { @@ -43,7 +43,7 @@ export function upsertFeeds( } export function saveSubmissionToFeed( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, submissionId: string, feedId: string, status: SubmissionStatus = SubmissionStatus.PENDING, @@ -59,7 +59,7 @@ export function saveSubmissionToFeed( } export function getFeedsBySubmission( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, submissionId: string, ): SubmissionFeed[] { const results = db @@ -73,14 +73,14 @@ export function getFeedsBySubmission( .where(eq(submissionFeeds.submissionId, submissionId)) .all(); - return results.map((result) => ({ + return results.map((result: any) => ({ ...result, moderationResponseTweetId: result.moderationResponseTweetId ?? undefined, })); } export function saveSubmission( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, submission: TwitterSubmission, ) { return db.insert(submissions).values({ @@ -98,7 +98,7 @@ export function saveSubmission( } export function saveModerationAction( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, moderation: Moderation, ) { return db.insert(moderationHistory).values({ @@ -112,7 +112,7 @@ export function saveModerationAction( } export function getModerationHistory( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, tweetId: string, ): Moderation[] { const results = db @@ -137,7 +137,7 @@ export function getModerationHistory( .orderBy(moderationHistory.createdAt) .all(); - return results.map((result) => ({ + return results.map((result: any) => ({ tweetId: result.tweetId, feedId: result.feedId, adminId: result.adminId, @@ -149,7 +149,7 @@ export function getModerationHistory( } export function updateSubmissionFeedStatus( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, submissionId: string, feedId: string, status: SubmissionStatus, @@ -171,7 +171,7 @@ export function updateSubmissionFeedStatus( } export function getSubmission( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, tweetId: string, ): TwitterSubmission | null { const results = db @@ -244,7 +244,7 @@ export function getSubmission( }; } -export function getAllSubmissions(db: BunSQLiteDatabase): TwitterSubmission[] { +export function getAllSubmissions(db: BetterSQLite3Database): TwitterSubmission[] { const results = db .select({ s: { @@ -323,7 +323,7 @@ export function getAllSubmissions(db: BunSQLiteDatabase): TwitterSubmission[] { } export function cleanupOldSubmissionCounts( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, date: string, ) { return db @@ -332,7 +332,7 @@ export function cleanupOldSubmissionCounts( } export function getDailySubmissionCount( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, userId: string, date: string, ): number { @@ -351,7 +351,7 @@ export function getDailySubmissionCount( } export function incrementDailySubmissionCount( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, userId: string, ) { const today = new Date().toISOString().split("T")[0]; @@ -376,7 +376,7 @@ export function incrementDailySubmissionCount( } export function removeFromSubmissionFeed( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, submissionId: string, feedId: string, ) { @@ -392,7 +392,7 @@ export function removeFromSubmissionFeed( // Feed Plugin queries export function getFeedPlugin( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, feedId: string, pluginId: string, ) { @@ -406,7 +406,7 @@ export function getFeedPlugin( } export function upsertFeedPlugin( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, feedId: string, pluginId: string, config: Record, @@ -428,7 +428,7 @@ export function upsertFeedPlugin( } export function getSubmissionsByFeed( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, feedId: string, ): (TwitterSubmission & { status: SubmissionStatus; diff --git a/backend/src/services/rss/queries.ts b/backend/src/services/rss/queries.ts index dcfab3e..d6cef47 100644 --- a/backend/src/services/rss/queries.ts +++ b/backend/src/services/rss/queries.ts @@ -1,5 +1,5 @@ import { and, eq, sql } from "drizzle-orm"; -import { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite"; +import { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; import { rssItems } from "./schema"; export interface RssItem { @@ -11,7 +11,7 @@ export interface RssItem { } export function saveRssItem( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, feedId: string, item: RssItem, ) { @@ -26,7 +26,7 @@ export function saveRssItem( } export function getRssItems( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, feedId: string, limit: number = 100, ): RssItem[] { @@ -48,7 +48,7 @@ export function getRssItems( } export function deleteOldRssItems( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, feedId: string, limit: number = 100, ) { diff --git a/backend/src/services/twitter/client.ts b/backend/src/services/twitter/client.ts index 0243dd4..4d02b6f 100644 --- a/backend/src/services/twitter/client.ts +++ b/backend/src/services/twitter/client.ts @@ -1,5 +1,5 @@ import { Scraper, SearchMode, Tweet } from "agent-twitter-client"; -import { TwitterCookie } from "types/twitter"; +import { TwitterCookie } from "../../types/twitter"; import { logger } from "../../utils/logger"; import { db } from "../db"; diff --git a/backend/src/services/twitter/queries.ts b/backend/src/services/twitter/queries.ts index 8b91788..787fed1 100644 --- a/backend/src/services/twitter/queries.ts +++ b/backend/src/services/twitter/queries.ts @@ -1,9 +1,9 @@ import { eq } from "drizzle-orm"; import { twitterCache, twitterCookies } from "./schema"; -import { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite"; +import { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; // Twitter Cookie Management -export function getTwitterCookies(db: BunSQLiteDatabase, username: string) { +export function getTwitterCookies(db: BetterSQLite3Database, username: string) { return db .select() .from(twitterCookies) @@ -12,7 +12,7 @@ export function getTwitterCookies(db: BunSQLiteDatabase, username: string) { } export function setTwitterCookies( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, username: string, cookiesJson: string, ) { @@ -31,17 +31,17 @@ export function setTwitterCookies( }); } -export function deleteTwitterCookies(db: BunSQLiteDatabase, username: string) { +export function deleteTwitterCookies(db: BetterSQLite3Database, username: string) { return db.delete(twitterCookies).where(eq(twitterCookies.username, username)); } // Twitter Cache Management -export function getTwitterCacheValue(db: BunSQLiteDatabase, key: string) { +export function getTwitterCacheValue(db: BetterSQLite3Database, key: string) { return db.select().from(twitterCache).where(eq(twitterCache.key, key)).get(); } export function setTwitterCacheValue( - db: BunSQLiteDatabase, + db: BetterSQLite3Database, key: string, value: string, ) { @@ -60,10 +60,10 @@ export function setTwitterCacheValue( }); } -export function deleteTwitterCacheValue(db: BunSQLiteDatabase, key: string) { +export function deleteTwitterCacheValue(db: BetterSQLite3Database, key: string) { return db.delete(twitterCache).where(eq(twitterCache.key, key)); } -export function clearTwitterCache(db: BunSQLiteDatabase) { +export function clearTwitterCache(db: BetterSQLite3Database) { return db.delete(twitterCache); } diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 2e6c2a8..3f90201 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -19,5 +19,5 @@ "types": ["bun-types"] }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "tests"] + "exclude": ["node_modules", "dist", "tests"], } diff --git a/bun.lockb b/bun.lockb index 3bd9461..5da0480 100755 Binary files a/bun.lockb and b/bun.lockb differ