Some checks failed
Deploy to Production / Deploy to Server (push) Failing after 20s
- Include compiled TypeScript with new /impressum, /privacy, /terms routes - Temporary commit of dist files for Docker deployment
123 lines
4.6 KiB
JavaScript
123 lines
4.6 KiB
JavaScript
import Database from "better-sqlite3";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const DB_PATH = path.join(__dirname, "../../data/docfast.db");
|
|
class DatabaseService {
|
|
db;
|
|
constructor() {
|
|
this.db = new Database(DB_PATH);
|
|
this.initialize();
|
|
}
|
|
initialize() {
|
|
// Enable WAL mode for better performance
|
|
this.db.pragma("journal_mode = WAL");
|
|
// Create tables
|
|
this.db.exec(`
|
|
CREATE TABLE IF NOT EXISTS keys (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
email TEXT NOT NULL,
|
|
api_key TEXT UNIQUE NOT NULL,
|
|
tier TEXT NOT NULL CHECK (tier IN ('free', 'pro')),
|
|
created_at TEXT NOT NULL,
|
|
usage_count INTEGER DEFAULT 0,
|
|
usage_month TEXT NOT NULL,
|
|
stripe_customer_id TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_keys_api_key ON keys(api_key);
|
|
CREATE INDEX IF NOT EXISTS idx_keys_email ON keys(email);
|
|
CREATE INDEX IF NOT EXISTS idx_keys_stripe_customer_id ON keys(stripe_customer_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS usage (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
api_key TEXT NOT NULL,
|
|
endpoint TEXT NOT NULL,
|
|
timestamp TEXT NOT NULL,
|
|
FOREIGN KEY (api_key) REFERENCES keys(api_key)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_api_key ON usage(api_key);
|
|
CREATE INDEX IF NOT EXISTS idx_usage_timestamp ON usage(timestamp);
|
|
`);
|
|
}
|
|
// Key operations
|
|
insertKey(key) {
|
|
const stmt = this.db.prepare(`
|
|
INSERT INTO keys (email, api_key, tier, created_at, usage_count, usage_month, stripe_customer_id)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
`);
|
|
const result = stmt.run(key.email, key.api_key, key.tier, key.created_at, key.usage_count, key.usage_month, key.stripe_customer_id || null);
|
|
return { ...key, id: result.lastInsertRowid };
|
|
}
|
|
getKeyByApiKey(apiKey) {
|
|
const stmt = this.db.prepare("SELECT * FROM keys WHERE api_key = ?");
|
|
return stmt.get(apiKey);
|
|
}
|
|
getKeyByEmail(email, tier) {
|
|
const stmt = this.db.prepare("SELECT * FROM keys WHERE email = ? AND tier = ?");
|
|
return stmt.get(email, tier);
|
|
}
|
|
getKeyByStripeCustomerId(stripeCustomerId) {
|
|
const stmt = this.db.prepare("SELECT * FROM keys WHERE stripe_customer_id = ?");
|
|
return stmt.get(stripeCustomerId);
|
|
}
|
|
updateKeyTier(apiKey, tier) {
|
|
const stmt = this.db.prepare("UPDATE keys SET tier = ? WHERE api_key = ?");
|
|
const result = stmt.run(tier, apiKey);
|
|
return result.changes > 0;
|
|
}
|
|
deleteKeyByStripeCustomerId(stripeCustomerId) {
|
|
const stmt = this.db.prepare("DELETE FROM keys WHERE stripe_customer_id = ?");
|
|
const result = stmt.run(stripeCustomerId);
|
|
return result.changes > 0;
|
|
}
|
|
getAllKeys() {
|
|
const stmt = this.db.prepare("SELECT * FROM keys");
|
|
return stmt.all();
|
|
}
|
|
// Usage operations
|
|
insertUsage(usage) {
|
|
const stmt = this.db.prepare(`
|
|
INSERT INTO usage (api_key, endpoint, timestamp)
|
|
VALUES (?, ?, ?)
|
|
`);
|
|
const result = stmt.run(usage.api_key, usage.endpoint, usage.timestamp);
|
|
return { ...usage, id: result.lastInsertRowid };
|
|
}
|
|
getUsageForKey(apiKey, fromDate, toDate) {
|
|
let query = "SELECT * FROM usage WHERE api_key = ?";
|
|
const params = [apiKey];
|
|
if (fromDate && toDate) {
|
|
query += " AND timestamp >= ? AND timestamp <= ?";
|
|
params.push(fromDate, toDate);
|
|
}
|
|
else if (fromDate) {
|
|
query += " AND timestamp >= ?";
|
|
params.push(fromDate);
|
|
}
|
|
query += " ORDER BY timestamp DESC";
|
|
const stmt = this.db.prepare(query);
|
|
return stmt.all(...params);
|
|
}
|
|
// Utility method to migrate existing JSON data
|
|
migrateFromJson(jsonKeys) {
|
|
const insertStmt = this.db.prepare(`
|
|
INSERT OR IGNORE INTO keys (email, api_key, tier, created_at, usage_count, usage_month, stripe_customer_id)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
`);
|
|
const transaction = this.db.transaction((keys) => {
|
|
for (const key of keys) {
|
|
const currentMonth = new Date().toISOString().slice(0, 7); // YYYY-MM
|
|
insertStmt.run(key.email || "", key.key, key.tier, key.createdAt, 0, // reset usage count
|
|
currentMonth, key.stripeCustomerId || null);
|
|
}
|
|
});
|
|
transaction(jsonKeys);
|
|
}
|
|
close() {
|
|
this.db.close();
|
|
}
|
|
}
|
|
// Export singleton instance
|
|
export const db = new DatabaseService();
|