SPB Git forge

spb/market-atlas

Public
12commits 1branches 0releases
1.1 MBsize
maindefault branch
10 days agolast push
TypeScript 96.7% SQL 1.6% CSS 0.8% JavaScript 0.5%
2.4 KB · 58 lines typescript
Raw Blame History
1import { mkdirSync } from "node:fs";2import { resolve } from "node:path";34function env(name: string, fallback?: string): string {5  const v = process.env[name];6  if (v === undefined || v === "") {7    if (fallback !== undefined) return fallback;8    throw new Error(`missing environment variable ${name}`);9  }10  return v;11}1213export type Role = "all" | "api" | "worker";1415export const config = {16  appEnv: env("APP_ENV", "development"),17  isProd: env("APP_ENV", "development") === "production",18  siteUrl: env("MA_SITE_URL", "http://localhost:8390"),19  apiHost: env("MA_API_HOST", "127.0.0.1"),20  apiPort: Number(env("MA_API_PORT", "8391")),21  role: env("MA_ROLE", "all") as Role,22  databaseUrl: env("DATABASE_URL", "postgres://localhost:5432/market_atlas"),23  dataDir: resolve(env("MA_DATA_DIR", "./data")),24  adminToken: env("MA_ADMIN_TOKEN", ""),25  /** When set, the API process is the public edge: /v1/* served locally, everything else proxied to the Next.js web app. */26  webUpstream: env("MA_WEB_UPSTREAM", ""),27  logJson: env("MA_LOG_JSON", "0") === "1",28  contactEmail: env("MA_CONTACT_EMAIL", "contact@market-atlas.co"),29  userAgent: `MarketAtlas/0.1 (+https://www.market-atlas.co; ${env("MA_CONTACT_EMAIL", "contact@market-atlas.co")})`,30  disabledConnectors: new Set(31    env("MA_DISABLED_CONNECTORS", "")32      .split(",")33      .map((s) => s.trim())34      .filter(Boolean),35  ),36  rawSampleRate: Number(env("MA_RAW_SAMPLE_RATE", "0.02")),37  observationRetentionDays: Number(env("MA_OBSERVATION_RETENTION_DAYS", "45")),38  /** Observation writer batching. */39  writerFlushMs: 1000,40  writerMaxBatch: 2000, // 17 columns × 2000 rows stays under Postgres' 65,535 bind-parameter limit41  /** Consensus: observations older than this (ms) are excluded for REALTIME sources. */42  consensusFreshWindowMs: 15_000,43  /**44   * Persistence sampling for REALTIME streaming ticks: at most one stored observation per45   * (source, instrument, field) per interval. Consensus/events still see every tick in memory.46   * 0 disables sampling (store everything).47   */48  tickPersistIntervalMs: Number(env("MA_TICK_PERSIST_INTERVAL_MS", "2000")),49  version: "0.1.0",50};5152export function ensureDataDirs(): void {53  for (const d of ["raw", "archive", "backups", "logs", "cache"]) mkdirSync(resolve(config.dataDir, d), { recursive: true });54}5556export const runsWorker = () => config.role === "all" || config.role === "worker";57export const runsApi = () => config.role === "all" || config.role === "api";58