88 lines
3.6 KiB
TypeScript
88 lines
3.6 KiB
TypeScript
import "dotenv/config";
|
|
|
|
function env(key: string, defaultValue?: string): string {
|
|
const v = process.env[key];
|
|
if (v !== undefined) return v;
|
|
if (defaultValue !== undefined) return defaultValue;
|
|
throw new Error(`Missing required env: ${key}`);
|
|
}
|
|
|
|
function envInt(key: string, defaultValue: number): number {
|
|
const v = process.env[key];
|
|
if (v === undefined) return defaultValue;
|
|
const n = parseInt(v, 10);
|
|
if (Number.isNaN(n)) throw new Error(`Invalid integer env: ${key}`);
|
|
return n;
|
|
}
|
|
|
|
function envBool(key: string, defaultValue: boolean): boolean {
|
|
const v = process.env[key];
|
|
if (v === undefined) return defaultValue;
|
|
return v === "true" || v === "1";
|
|
}
|
|
|
|
export const config = {
|
|
port: envInt("PORT", 3001),
|
|
trustProxy: envBool("TRUST_PROXY", false),
|
|
allowedOrigins: (process.env.ALLOWED_ORIGINS ?? process.env.FRONTEND_URL ?? "http://localhost:5173,http://localhost:5174").split(",").map((s) => s.trim()),
|
|
|
|
// Database: omit DATABASE_URL for SQLite; set for Postgres
|
|
databaseUrl: process.env.DATABASE_URL as string | undefined,
|
|
sqlitePath: process.env.SQLITE_PATH ?? "./data/faucet.db",
|
|
|
|
// Security
|
|
hmacIpSecret: env("HMAC_IP_SECRET"),
|
|
jwtSecret: env("JWT_SECRET", process.env.HMAC_IP_SECRET ?? ""),
|
|
jwtExpiresInSeconds: envInt("JWT_EXPIRES_IN_SECONDS", 86400 * 7), // 7 days
|
|
nip98MaxSkewSeconds: envInt("NIP98_MAX_SKEW_SECONDS", 300),
|
|
nonceTtlSeconds: envInt("NONCE_TTL_SECONDS", 600),
|
|
|
|
// Faucet economics
|
|
faucetEnabled: envBool("FAUCET_ENABLED", true),
|
|
emergencyStop: envBool("EMERGENCY_STOP", false),
|
|
faucetMinSats: envInt("FAUCET_MIN_SATS", 1),
|
|
faucetMaxSats: envInt("FAUCET_MAX_SATS", 5),
|
|
payoutWeightSmall: envInt("PAYOUT_WEIGHT_SMALL", 50),
|
|
payoutWeightMedium: envInt("PAYOUT_WEIGHT_MEDIUM", 30),
|
|
payoutWeightLarge: envInt("PAYOUT_WEIGHT_LARGE", 15),
|
|
payoutWeightJackpot: envInt("PAYOUT_WEIGHT_JACKPOT", 5),
|
|
payoutSmallSats: envInt("PAYOUT_SMALL_SATS", 10),
|
|
payoutMediumSats: envInt("PAYOUT_MEDIUM_SATS", 25),
|
|
payoutLargeSats: envInt("PAYOUT_LARGE_SATS", 50),
|
|
payoutJackpotSats: envInt("PAYOUT_JACKPOT_SATS", 100),
|
|
dailyBudgetSats: envInt("DAILY_BUDGET_SATS", 10000),
|
|
maxClaimsPerDay: envInt("MAX_CLAIMS_PER_DAY", 100),
|
|
minWalletBalanceSats: envInt("MIN_WALLET_BALANCE_SATS", 1000),
|
|
|
|
// Eligibility
|
|
minAccountAgeDays: envInt("MIN_ACCOUNT_AGE_DAYS", 14),
|
|
minActivityScore: envInt("MIN_ACTIVITY_SCORE", 30),
|
|
minNotesCount: envInt("MIN_NOTES_COUNT", 5),
|
|
minFollowingCount: envInt("MIN_FOLLOWING_COUNT", 10),
|
|
minFollowersCount: envInt("MIN_FOLLOWERS_COUNT", 0),
|
|
activityLookbackDays: envInt("ACTIVITY_LOOKBACK_DAYS", 90),
|
|
|
|
// Cooldowns
|
|
cooldownDays: envInt("COOLDOWN_DAYS", 7),
|
|
ipCooldownDays: envInt("IP_COOLDOWN_DAYS", 7),
|
|
maxClaimsPerIpPerPeriod: envInt("MAX_CLAIMS_PER_IP_PER_PERIOD", 1),
|
|
|
|
// Nostr (defaults include relays common for remote signers / NIP-05)
|
|
nostrRelays: (process.env.NOSTR_RELAYS ?? "wss://relay.damus.io,wss://relay.nostr.band,wss://relay.getalby.com,wss://nos.lol").split(",").map((s) => s.trim()),
|
|
relayTimeoutMs: envInt("RELAY_TIMEOUT_MS", 5000),
|
|
maxEventsFetch: envInt("MAX_EVENTS_FETCH", 500),
|
|
metadataCacheHours: envInt("METADATA_CACHE_HOURS", 24),
|
|
|
|
// LNbits
|
|
lnbitsBaseUrl: env("LNBITS_BASE_URL").replace(/\/$/, ""),
|
|
lnbitsAdminKey: env("LNBITS_ADMIN_KEY"),
|
|
lnbitsWalletId: env("LNBITS_WALLET_ID"),
|
|
depositLightningAddress: process.env.DEPOSIT_LIGHTNING_ADDRESS ?? "",
|
|
depositLnurlp: process.env.DEPOSIT_LNURLP ?? "",
|
|
cashuRedeemApiUrl: (process.env.CASHU_REDEEM_API_URL ?? "https://cashu-redeem.azzamo.net").replace(/\/$/, ""),
|
|
};
|
|
|
|
export function usePostgres(): boolean {
|
|
return Boolean(config.databaseUrl);
|
|
}
|