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
100
dist/services/keys.js
vendored
Normal file
100
dist/services/keys.js
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import { randomBytes } from "crypto";
|
||||
import logger from "./logger.js";
|
||||
import pool from "./db.js";
|
||||
// In-memory cache for fast lookups, synced with PostgreSQL
|
||||
let keysCache = [];
|
||||
export async function loadKeys() {
|
||||
try {
|
||||
const result = await pool.query("SELECT key, tier, email, created_at, stripe_customer_id FROM api_keys");
|
||||
keysCache = result.rows.map((r) => ({
|
||||
key: r.key,
|
||||
tier: r.tier,
|
||||
email: r.email,
|
||||
createdAt: r.created_at instanceof Date ? r.created_at.toISOString() : r.created_at,
|
||||
stripeCustomerId: r.stripe_customer_id || undefined,
|
||||
}));
|
||||
}
|
||||
catch (err) {
|
||||
logger.error({ err }, "Failed to load keys from PostgreSQL");
|
||||
keysCache = [];
|
||||
}
|
||||
// Also load seed keys from env
|
||||
const envKeys = process.env.API_KEYS?.split(",").map((k) => k.trim()).filter(Boolean) || [];
|
||||
for (const k of envKeys) {
|
||||
if (!keysCache.find((e) => e.key === k)) {
|
||||
const entry = { key: k, tier: "pro", email: "seed@docfast.dev", createdAt: new Date().toISOString() };
|
||||
keysCache.push(entry);
|
||||
// Upsert into DB
|
||||
await pool.query(`INSERT INTO api_keys (key, tier, email, created_at) VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (key) DO NOTHING`, [k, "pro", "seed@docfast.dev", new Date().toISOString()]).catch(() => { });
|
||||
}
|
||||
}
|
||||
}
|
||||
export function isValidKey(key) {
|
||||
return keysCache.some((k) => k.key === key);
|
||||
}
|
||||
export function getKeyInfo(key) {
|
||||
return keysCache.find((k) => k.key === key);
|
||||
}
|
||||
export function isProKey(key) {
|
||||
const info = getKeyInfo(key);
|
||||
return info?.tier === "pro";
|
||||
}
|
||||
function generateKey(prefix) {
|
||||
return `${prefix}_${randomBytes(24).toString("hex")}`;
|
||||
}
|
||||
export async function createFreeKey(email) {
|
||||
if (email) {
|
||||
const existing = keysCache.find((k) => k.email === email && k.tier === "free");
|
||||
if (existing)
|
||||
return existing;
|
||||
}
|
||||
const entry = {
|
||||
key: generateKey("df_free"),
|
||||
tier: "free",
|
||||
email: email || "",
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
await pool.query("INSERT INTO api_keys (key, tier, email, created_at) VALUES ($1, $2, $3, $4)", [entry.key, entry.tier, entry.email, entry.createdAt]);
|
||||
keysCache.push(entry);
|
||||
return entry;
|
||||
}
|
||||
export async function createProKey(email, stripeCustomerId) {
|
||||
const existing = keysCache.find((k) => k.stripeCustomerId === stripeCustomerId);
|
||||
if (existing) {
|
||||
existing.tier = "pro";
|
||||
await pool.query("UPDATE api_keys SET tier = 'pro' WHERE key = $1", [existing.key]);
|
||||
return existing;
|
||||
}
|
||||
const entry = {
|
||||
key: generateKey("df_pro"),
|
||||
tier: "pro",
|
||||
email,
|
||||
createdAt: new Date().toISOString(),
|
||||
stripeCustomerId,
|
||||
};
|
||||
await pool.query("INSERT INTO api_keys (key, tier, email, created_at, stripe_customer_id) VALUES ($1, $2, $3, $4, $5)", [entry.key, entry.tier, entry.email, entry.createdAt, entry.stripeCustomerId]);
|
||||
keysCache.push(entry);
|
||||
return entry;
|
||||
}
|
||||
export async function revokeByCustomer(stripeCustomerId) {
|
||||
const idx = keysCache.findIndex((k) => k.stripeCustomerId === stripeCustomerId);
|
||||
if (idx >= 0) {
|
||||
const key = keysCache[idx].key;
|
||||
keysCache.splice(idx, 1);
|
||||
await pool.query("DELETE FROM api_keys WHERE key = $1", [key]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
export function getAllKeys() {
|
||||
return [...keysCache];
|
||||
}
|
||||
export async function updateKeyEmail(apiKey, newEmail) {
|
||||
const entry = keysCache.find((k) => k.key === apiKey);
|
||||
if (!entry)
|
||||
return false;
|
||||
entry.email = newEmail;
|
||||
await pool.query("UPDATE api_keys SET email = $1 WHERE key = $2", [newEmail, apiKey]);
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue