diff --git a/README.md b/README.md
index dabdc28..1132603 100644
--- a/README.md
+++ b/README.md
@@ -63,9 +63,9 @@ Easily configure your GitHub and Gitea connections, set up automatic mirroring s
See the [Quick Start Guide](docs/quickstart.md) for detailed instructions on getting up and running quickly.
-### Prerequisites
+-### Prerequisites
-- Node.js 22 or later
+- Bun 1.2.9 or later
- A GitHub account with a personal access token
- A Gitea instance with an access token
@@ -359,7 +359,7 @@ docker compose -f docker-compose.dev.yml up -d
## Technologies Used
- **Frontend**: Astro, React, Shadcn UI, Tailwind CSS v4
-- **Backend**: Node.js
+ - **Backend**: Bun
- **Database**: SQLite (default) or PostgreSQL
- **Caching/Queue**: Redis
- **API Integration**: GitHub API (Octokit), Gitea API
diff --git a/package.json b/package.json
index 9e206c4..aae84cf 100644
--- a/package.json
+++ b/package.json
@@ -3,31 +3,30 @@
"type": "module",
"version": "1.0.0",
"engines": {
- "node": ">=22.0.0"
+ "bun": ">=1.2.9"
},
"scripts": {
"setup": "pnpm install && pnpm manage-db init",
- "dev": "astro dev",
- "dev:clean": "pnpm cleanup-db && pnpm manage-db init && astro dev",
- "build": "astro build",
+ "dev": "bunx astro dev",
+ "dev:clean": "pnpm cleanup-db && pnpm manage-db init && bunx astro dev",
+ "build": "bunx astro build",
"cleanup-db": "rm -f gitea-mirror.db data/gitea-mirror.db",
- "manage-db": "tsx scripts/manage-db.ts",
- "init-db": "tsx scripts/manage-db.ts init",
- "check-db": "tsx scripts/manage-db.ts check",
- "fix-db": "tsx scripts/manage-db.ts fix",
- "reset-users": "tsx scripts/manage-db.ts reset-users",
- "preview": "astro preview",
- "start": "node dist/server/entry.mjs",
- "start:fresh": "pnpm cleanup-db && pnpm manage-db init && node dist/server/entry.mjs",
- "test": "vitest run",
- "test:watch": "vitest",
- "astro": "astro"
+ "manage-db": "bun scripts/manage-db.ts",
+ "init-db": "bun scripts/manage-db.ts init",
+ "check-db": "bun scripts/manage-db.ts check",
+ "fix-db": "bun scripts/manage-db.ts fix",
+ "reset-users": "bun scripts/manage-db.ts reset-users",
+ "preview": "bunx astro preview",
+ "start": "bun dist/server/entry.mjs",
+ "start:fresh": "pnpm cleanup-db && pnpm manage-db init && bun dist/server/entry.mjs",
+ "test": "bunx vitest run",
+ "test:watch": "bunx vitest",
+ "astro": "bunx astro"
},
"dependencies": {
"@astrojs/mdx": "^4.2.6",
"@astrojs/node": "^9.2.1",
"@astrojs/react": "^4.2.7",
- "@libsql/client": "^0.15.4",
"@octokit/rest": "^21.1.1",
"@radix-ui/react-avatar": "^1.1.4",
"@radix-ui/react-checkbox": "^1.1.5",
@@ -54,7 +53,6 @@
"cmdk": "^1.1.1",
"drizzle-orm": "^0.41.0",
"fuse.js": "^7.1.0",
- "ioredis": "^5.6.1",
"jsonwebtoken": "^9.0.2",
"lucide-react": "^0.488.0",
"next-themes": "^0.4.6",
@@ -73,12 +71,10 @@
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@types/bcryptjs": "^3.0.0",
- "@types/better-sqlite3": "^7.6.13",
"@types/jsonwebtoken": "^9.0.9",
"@types/superagent": "^8.1.9",
"@types/uuid": "^10.0.0",
"@vitejs/plugin-react": "^4.4.0",
- "better-sqlite3": "^9.6.0",
"jsdom": "^26.1.0",
"tsx": "^4.19.3",
"vitest": "^3.1.1"
diff --git a/src/content/docs/architecture.md b/src/content/docs/architecture.md
index 7b8b7a9..4045f4b 100644
--- a/src/content/docs/architecture.md
+++ b/src/content/docs/architecture.md
@@ -22,7 +22,7 @@ The application is built using:
- React: Component library for interactive UI elements
- Shadcn UI: UI component library built on Tailwind CSS
- SQLite: Database for storing configuration and state
-- Node.js: Runtime environment for the backend
+- Bun: Runtime environment for the backend
## Architecture Diagram
@@ -30,7 +30,7 @@ The application is built using:
graph TD
subgraph "Gitea Mirror"
Frontend["Frontend
(Astro)"]
- Backend["Backend
(Node.js)"]
+ Backend["Backend
(Bun)"]
Database["Database
(SQLite)"]
Frontend <--> Backend
@@ -60,9 +60,9 @@ Key frontend components:
- **Configuration**: Settings for GitHub and Gitea connections
- **Activity Log**: Detailed log of mirroring operations
-### Backend (Node.js)
+### Backend (Bun)
-The backend is built with Node.js and provides API endpoints for the frontend to interact with. It handles:
+The backend is built with Bun and provides API endpoints for the frontend to interact with. It handles:
- Authentication and user management
- GitHub API integration
diff --git a/src/content/docs/configuration.md b/src/content/docs/configuration.md
index 381ff41..ce4c713 100644
--- a/src/content/docs/configuration.md
+++ b/src/content/docs/configuration.md
@@ -23,7 +23,7 @@ The following environment variables can be used to configure Gitea Mirror:
| Variable | Description | Default Value | Example |
|----------|-------------|---------------|---------|
-| `NODE_ENV` | Node environment (development, production, test) | `development` | `production` |
+| `NODE_ENV` | Runtime environment (development, production, test) | `development` | `production` |
| `DATABASE_URL` | SQLite database URL | `sqlite://data/gitea-mirror.db` | `sqlite://path/to/your/database.db` |
| `JWT_SECRET` | Secret key for JWT authentication | `your-secret-key-change-this-in-production` | `your-secure-random-string` |
| `HOST` | Server host | `localhost` | `0.0.0.0` |
diff --git a/src/content/docs/quickstart.md b/src/content/docs/quickstart.md
index 8efa109..4ae544d 100644
--- a/src/content/docs/quickstart.md
+++ b/src/content/docs/quickstart.md
@@ -16,7 +16,7 @@ Before you begin, make sure you have:
1. A GitHub account with a personal access token
2. A Gitea instance with an access token
-3. Docker and docker-compose (recommended) or Node.js 18+ installed
+3. Docker and docker-compose (recommended) or Bun 1.2.9+ installed
## Installation Options
diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts
index 0ae592a..bb9307f 100644
--- a/src/lib/db/index.ts
+++ b/src/lib/db/index.ts
@@ -1,6 +1,6 @@
import { z } from "zod";
-import { createClient } from "@libsql/client";
-import { drizzle } from "drizzle-orm/libsql";
+import { Database } from "bun:sqlite";
+import { drizzle } from "drizzle-orm/bun-sqlite";
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
import path from "path";
@@ -11,11 +11,24 @@ const dataDir = path.join(process.cwd(), "data");
const dbUrl =
process.env.DATABASE_URL || `file:${path.join(dataDir, "gitea-mirror.db")}`;
-// Create a client connection to the database
-export const client = createClient({ url: dbUrl });
+// Create a SQLite database instance using Bun's native driver
+export const sqlite = new Database(dbUrl);
+
+// Simple async wrapper around Bun's SQLite API for compatibility
+export const client = {
+ async execute(sql: string, params?: any[]) {
+ const stmt = sqlite.query(sql);
+ if (/^\s*select/i.test(sql)) {
+ const rows = stmt.all(params ?? []);
+ return { rows } as { rows: any[] };
+ }
+ stmt.run(params ?? []);
+ return { rows: [] } as { rows: any[] };
+ },
+};
// Create a drizzle instance
-export const db = drizzle(client);
+export const db = drizzle(sqlite);
// Define the tables
export const users = sqliteTable("users", {
diff --git a/src/lib/redis.ts b/src/lib/redis.ts
index 6c59d9d..a5686e7 100644
--- a/src/lib/redis.ts
+++ b/src/lib/redis.ts
@@ -1,30 +1,23 @@
-import Redis from "ioredis";
+import { RedisClient } from "bun";
// Connect to Redis using REDIS_URL environment variable or default to redis://redis:6379
// This ensures we have a fallback URL when running with Docker Compose
-const redisUrl = process.env.REDIS_URL ?? 'redis://redis:6379';
+const redisUrl = process.env.REDIS_URL ?? "redis://redis:6379";
console.log(`Connecting to Redis at: ${redisUrl}`);
// Configure Redis client with connection options
-const redisOptions = {
- retryStrategy: (times: number) => {
- // Retry with exponential backoff up to 30 seconds
- const delay = Math.min(times * 100, 3000);
- console.log(`Redis connection attempt ${times} failed. Retrying in ${delay}ms...`);
- return delay;
- },
- maxRetriesPerRequest: 5,
- enableReadyCheck: true,
- connectTimeout: 10000,
+function createClient() {
+ return new RedisClient(redisUrl, {
+ autoReconnect: true,
+ });
+}
+
+export const redis = createClient();
+export const redisPublisher = createClient();
+export const redisSubscriber = createClient();
+
+redis.onconnect = () => console.log("Connected to Redis server");
+redis.onclose = (err) => {
+ if (err) console.error("Disconnected from Redis server:", err);
};
-
-export const redis = new Redis(redisUrl, redisOptions);
-export const redisPublisher = new Redis(redisUrl, redisOptions); // For publishing
-export const redisSubscriber = new Redis(redisUrl, redisOptions); // For subscribing
-
-// Log connection events
-redis.on('connect', () => console.log('Redis client connected'));
-redis.on('error', (err) => console.error('Redis client error:', err));
-redis.on('ready', () => console.log('Redis client ready'));
-redis.on('reconnecting', () => console.log('Redis client reconnecting...'));