Add multi-account OAuth, Obsidian integration, product assets, and test tooling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Garfield
2026-04-29 09:52:53 -04:00
parent 166f5d55a6
commit e3a272c332
67 changed files with 6204 additions and 94 deletions

81
src/db.ts Normal file
View File

@@ -0,0 +1,81 @@
import mysql from 'mysql2/promise';
const host = process.env.MYSQL_HOST || '127.0.0.1';
const port = parseInt(process.env.MYSQL_PORT || '3306', 10);
const user = process.env.MYSQL_USER || 'root';
const password = process.env.MYSQL_PASSWORD || '';
let pool: mysql.Pool | null = null;
export function getPool(): mysql.Pool {
if (!pool) {
throw new Error('Database pool not initialized. Call initDatabase() first.');
}
return pool;
}
export function isPoolReady(): boolean {
return pool !== null;
}
export async function initDatabase(): Promise<void> {
// Create database if it doesn't exist
const tmpConn = await mysql.createConnection({ host, port, user, password });
await tmpConn.execute('CREATE DATABASE IF NOT EXISTS hermes_oauth');
await tmpConn.end();
pool = mysql.createPool({
host,
port,
user,
password,
database: 'hermes_oauth',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
timezone: 'Z',
});
const db = await pool.getConnection();
try {
await db.execute(`
CREATE TABLE IF NOT EXISTS oauth_clients (
client_id VARCHAR(255) PRIMARY KEY,
client_secret VARCHAR(255) NOT NULL,
client_name VARCHAR(255),
redirect_urls JSON,
grant_types JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_used TIMESTAMP NULL,
is_static BOOLEAN DEFAULT FALSE,
INDEX idx_last_used (last_used)
)
`);
await db.execute(`
CREATE TABLE IF NOT EXISTS oauth_auth_codes (
code VARCHAR(255) PRIMARY KEY,
client_id VARCHAR(255),
redirect_uri TEXT,
expires_at TIMESTAMP,
used BOOLEAN DEFAULT FALSE,
INDEX idx_expires (expires_at)
)
`);
await db.execute(`
CREATE TABLE IF NOT EXISTS oauth_tokens (
token VARCHAR(255) PRIMARY KEY,
client_id VARCHAR(255),
token_type ENUM('access', 'refresh') DEFAULT 'access',
expires_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_expires (expires_at)
)
`);
} finally {
db.release();
}
console.log('[db] MySQL connected and schema initialized');
}