refactor: improve maintainability by reducing LOC/reuse

This commit is contained in:
2026-03-28 16:52:19 +04:00
parent 8831c9c7b4
commit 6dcb5c0a52
29 changed files with 311 additions and 468 deletions
+2 -49
View File
@@ -1,4 +1,5 @@
import postgres from "postgres";
import { migrate as sharedMigrate } from "../../shared/db";
const sql = postgres(process.env.DATABASE_URL ?? "postgres://pingql:pingql@localhost:5432/pingql", {
max: 10,
@@ -9,53 +10,5 @@ const sql = postgres(process.env.DATABASE_URL ?? "postgres://pingql:pingql@local
export default sql;
export async function migrate() {
// Plan columns on accounts (may already exist from API/web migrations)
await sql`ALTER TABLE accounts ADD COLUMN IF NOT EXISTS plan_expires_at TIMESTAMPTZ`;
await sql`ALTER TABLE accounts ADD COLUMN IF NOT EXISTS plan_stack JSONB NOT NULL DEFAULT '[]'`;
await sql`
CREATE TABLE IF NOT EXISTS payments (
id BIGSERIAL PRIMARY KEY,
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
plan TEXT NOT NULL,
months INTEGER,
amount_usd NUMERIC(10,2) NOT NULL,
coin TEXT NOT NULL,
amount_crypto TEXT NOT NULL,
address TEXT NOT NULL,
derivation_index INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ DEFAULT now(),
paid_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ NOT NULL,
txid TEXT
)
`;
await sql`ALTER TABLE payments ADD COLUMN IF NOT EXISTS amount_received TEXT NOT NULL DEFAULT '0'`;
await sql`
CREATE TABLE IF NOT EXISTS payment_txs (
id BIGSERIAL PRIMARY KEY,
payment_id BIGINT NOT NULL REFERENCES payments(id) ON DELETE CASCADE,
txid TEXT NOT NULL,
amount TEXT NOT NULL,
confirmed BOOLEAN NOT NULL DEFAULT false,
detected_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(payment_id, txid)
)
`;
await sql`CREATE INDEX IF NOT EXISTS idx_payment_txs_payment ON payment_txs(payment_id)`;
await sql`CREATE INDEX IF NOT EXISTS idx_payment_txs_txid ON payment_txs(txid)`;
await sql`CREATE INDEX IF NOT EXISTS idx_payments_status ON payments(status)`;
await sql`CREATE INDEX IF NOT EXISTS idx_payments_account ON payments(account_id)`;
await sql`ALTER TABLE payments ADD COLUMN IF NOT EXISTS receipt_html TEXT`;
// Derivation index should be unique per coin, not globally
await sql`DROP INDEX IF EXISTS payments_derivation_index_key`;
await sql`CREATE UNIQUE INDEX IF NOT EXISTS idx_payments_coin_derivation ON payments(coin, derivation_index)`;
console.log("Pay DB ready");
await sharedMigrate(sql);
}
+1 -6
View File
@@ -5,12 +5,7 @@ import { checkPayments, expireProPlans } from "./monitor";
await migrate();
const SECURITY_HEADERS = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Strict-Transport-Security": "max-age=63072000; includeSubDomains",
"Referrer-Policy": "strict-origin-when-cross-origin",
};
import { SECURITY_HEADERS } from "../../shared/auth";
const CORS_ORIGIN = process.env.CORS_ORIGINS?.split(",") ?? ["https://pingql.com"];
+1 -4
View File
@@ -2,7 +2,7 @@
/// States: pending → underpaid → confirming → paid | expired
import sql from "./db";
import { getAddressInfo, getAddressInfoBulk } from "./freedom";
import { COINS } from "./plans";
import { COINS, planTier } from "../../shared/plans";
import { generateReceipt } from "./receipt";
const SOCK_API = process.env.FREEDOM_SOCK ?? "https://sock-v1.freedom.st";
@@ -226,9 +226,6 @@ interface StackEntry { plan: string; remaining_days: number | null }
interface AccountState { plan: string; plan_expires_at: Date | null; plan_stack: StackEntry[] }
interface AccountUpdate { plan: string; plan_expires_at: Date | null; plan_stack: StackEntry[] }
const PLAN_RANK: Record<string, number> = { free: 0, pro: 1, lifetime: 1, pro2x: 2, pro4x: 3 };
function planTier(plan: string): number { return PLAN_RANK[plan] ?? 0; }
export function insertIntoStack(stack: StackEntry[], entry: StackEntry): StackEntry[] {
const result = stack.slice();
// Merge if same plan already exists
-19
View File
@@ -1,19 +0,0 @@
// Pro pricing — base $12/mo, multiplied for 2x/4x
export const PRO_MONTHLY_USD = 12;
export const LIFETIME_USD = 140;
export const PLANS: Record<string, { label: string; monthlyUsd?: number; priceUsd?: number }> = {
pro: { label: "Pro", monthlyUsd: PRO_MONTHLY_USD },
pro2x: { label: "Pro 2x", monthlyUsd: PRO_MONTHLY_USD * 2 },
pro4x: { label: "Pro 4x", monthlyUsd: PRO_MONTHLY_USD * 4 },
lifetime: { label: "Lifetime", priceUsd: LIFETIME_USD },
};
export const COINS: Record<string, { label: string; ticker: string; confirmations: number; uri: string }> = {
btc: { label: "Bitcoin", ticker: "BTC", confirmations: 1, uri: "bitcoin" },
ltc: { label: "Litecoin", ticker: "LTC", confirmations: 1, uri: "litecoin" },
doge: { label: "Dogecoin", ticker: "DOGE", confirmations: 1, uri: "dogecoin" },
dash: { label: "Dash", ticker: "DASH", confirmations: 1, uri: "dash" },
bch: { label: "Bitcoin Cash", ticker: "BCH", confirmations: 0, uri: "bitcoincash" },
xec: { label: "eCash", ticker: "XEC", confirmations: 0, uri: "ecash" },
};
+1 -1
View File
@@ -1,5 +1,5 @@
import sql from "./db";
import { COINS } from "./plans";
import { COINS } from "../../shared/plans";
export async function generateReceipt(paymentId: number): Promise<string> {
const [payment] = await sql`SELECT * FROM payments WHERE id = ${paymentId}`;
+4 -17
View File
@@ -2,33 +2,20 @@ import { Elysia, t } from "elysia";
import sql from "./db";
import { derive } from "./address";
import { getExchangeRates, getAvailableCoins, fetchQrBase64 } from "./freedom";
import { PLANS, COINS } from "./plans";
import { PLAN_PRICING as PLANS, COINS } from "../../shared/plans";
import { generateReceipt } from "./receipt";
import { watchPayment } from "./monitor";
// Resolve account from key (same logic as API/web apps)
async function resolveKey(key: string): Promise<{ accountId: string; keyId: string | null; plan: string } | null> {
const [account] = await sql`SELECT id, plan FROM accounts WHERE key = ${key}`;
if (account) return { accountId: account.id, keyId: null, plan: account.plan };
const [apiKey] = await sql`SELECT k.id, k.account_id, a.plan FROM api_keys k JOIN accounts a ON a.id = k.account_id WHERE k.key = ${key}`;
if (apiKey) return { accountId: apiKey.account_id, keyId: apiKey.id, plan: apiKey.plan };
return null;
}
import { resolveKey as sharedResolveKey, extractAuthKey } from "../../shared/auth";
function requireAuth(app: Elysia) {
return app
.derive(async ({ headers, cookie, set }) => {
const authHeader = headers["authorization"] ?? "";
const bearer = authHeader.match(/^bearer\s+(.+)$/i)?.[1]?.trim();
const cookieKey = cookie?.pingql_key?.value;
const key = bearer || cookieKey;
const key = extractAuthKey(headers, cookie);
if (!key) {
set.status = 401;
return { accountId: null as string | null, keyId: null as string | null, plan: "free" };
}
const resolved = await resolveKey(key);
const resolved = await sharedResolveKey(sql, key, { trackUsage: false });
if (resolved) return resolved;
set.status = 401;
return { accountId: null as string | null, keyId: null as string | null, plan: "free" };