feat: Add built dist files with EU compliance routes
Some checks failed
Deploy to Production / Deploy to Server (push) Failing after 20s
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
This commit is contained in:
parent
5ef8f34133
commit
1ef8f5743c
21 changed files with 2179 additions and 0 deletions
123
dist/services/database.js
vendored
Normal file
123
dist/services/database.js
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
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();
|
||||
Loading…
Add table
Add a link
Reference in a new issue