A Prediction Market on the AT Protocol

feat(core/constants.ts): extract env and validate

Ciaran 0be5804e cfec48eb

+17 -10
+2 -1
drizzle.config.ts
··· 1 + import { ENV } from '@/core/constants'; 1 2 import 'dotenv/config'; 2 3 import { defineConfig } from 'drizzle-kit'; 3 4 ··· 6 7 schema: './src/db/index.ts', 7 8 dialect: 'postgresql', 8 9 dbCredentials: { 9 - url: process.env.DATABASE_URL!, 10 + url: ENV.DATABASE_URL, 10 11 }, 11 12 }); 12 13
-1
package.json
··· 15 15 "server:dev": "bun --watch src/server/index.ts", 16 16 "server:build": "bun build src/server/index.ts --compile --outfile build/server", 17 17 "build": "bun jetstream:build && bun web:build && bun server:build", 18 - "build:dev": "bun jetstream:build && LOCAL=1 bun web:build && bun server:build", 19 18 "test": "bun vitest" 20 19 }, 21 20 "devDependencies": {
+7
src/core/constants.ts
··· 1 + import { z } from "zod" 2 + 1 3 export enum Lexicon { 2 4 MARKET = 'za.co.ciaran.cumulus.market', 3 5 BET = 'za.co.ciaran.cumulus.bet', 4 6 RESOLUTION = 'za.co.ciaran.cumulus.resolution', 5 7 } 6 8 9 + export const ENV = z.object({ 10 + PORT: z.number(), 11 + BASE_URL: z.url(), 12 + DATABASE_URL: z.stringFormat("postgresql://", (val) => val.startsWith("postgresql://")), 13 + }).parse(process.env);
+2 -1
src/db/index.ts
··· 1 1 import { text, integer, json, pgTable, timestamp, pgEnum, index } from "drizzle-orm/pg-core"; 2 2 import { relations } from "drizzle-orm"; 3 3 import { drizzle } from "drizzle-orm/node-postgres"; 4 + import { ENV } from "@/core/constants"; 4 5 5 6 const SHARED_SCHEMA = { 6 7 uri: text().primaryKey().notNull(), ··· 55 56 }), 56 57 })); 57 58 58 - export const db = drizzle(process.env.DATABASE_URL!, { 59 + export const db = drizzle(ENV.DATABASE_URL, { 59 60 schema: { 60 61 marketsTable, 61 62 betsTable,
+2 -1
src/server/index.ts
··· 3 3 import { swagger } from '@elysiajs/swagger' 4 4 import { cors } from '@elysiajs/cors' 5 5 import { tryFindMarket, tryFindMarketBets, tryFindMarketResolutions, tryListMarkets } from "@/core/api"; 6 + import { ENV } from "@/core/constants"; 6 7 7 8 export const app = new Elysia() 8 9 .use(cors()) ··· 16 17 .get("/:uri/bets", async ({ params }) => await tryFindMarketBets(params.uri)) 17 18 .get("/:uri/resolutions", async ({ params }) => await tryFindMarketResolutions(params.uri)) 18 19 ) 19 - ).listen({ port: process.env.PORT!, hostname: "0.0.0.0" }) 20 + ).listen({ port: ENV.PORT, hostname: "0.0.0.0" }) 20 21 21 22 console.log(`> Server running on ${app.server?.protocol}://${app.server?.hostname}:${app.server?.port}`);
+4 -6
vite.config.ts
··· 6 6 import metadata from "./src/web/public/oauth-client-metadata.json" 7 7 8 8 const SERVER_HOST = "127.0.0.1"; 9 - const SERVER_PORT = process.env.LOCAL ? 8080 : 12520; 9 + const SERVER_PORT = 12520; 10 10 11 11 const atProtoOAuthPlugin: Plugin = { 12 12 name: "atproto-oauth-plugin", 13 13 config: (_conf, { command }) => { 14 - if (command === "build" && !process.env.LOCAL) { 14 + if (command === "build") { 15 15 process.env.VITE_OAUTH_CLIENT_ID = metadata.client_id; 16 16 process.env.VITE_OAUTH_REDIRECT_URI = metadata.redirect_uris[0]; 17 17 } else { 18 18 const redirectUri = `http://${SERVER_HOST}:${SERVER_PORT}${new URL(metadata.redirect_uris[0]!).pathname}` 19 - process.env.VITE_OAUTH_CLIENT_ID = 20 - `http://localhost?redirect_uri=${encodeURIComponent(redirectUri)}` + 21 - `&scope=${encodeURIComponent(metadata.scope)}`; 19 + process.env.VITE_OAUTH_CLIENT_ID = `http://localhost?redirect_uri=${encodeURIComponent(redirectUri)}&scope=${encodeURIComponent(metadata.scope)}`; 22 20 process.env.VITE_OAUTH_REDIRECT_URI = redirectUri; 23 21 } 24 22 process.env.VITE_OAUTH_SCOPE = metadata.scope; ··· 42 40 outDir: "../../dist", 43 41 emptyOutDir: true, 44 42 }, 45 - resolve: { 43 + resolve: { 46 44 alias: { 47 45 "@": path.resolve(__dirname, "./src/"), 48 46 }