diff --git a/.env.example b/.env.example index 1140858..0ab55ca 100644 --- a/.env.example +++ b/.env.example @@ -1,34 +1,60 @@ # ============================================ # Anchor API variables # ============================================ +# Base URL for anchor platform REST API (optional) ANCHOR_API_BASE_URL=https://api.example.com/anchor # ============================================ # Stellar / Soroban Network # ============================================ +# Target network: testnet or mainnet (optional, used by some utilities) STELLAR_NETWORK=testnet +# Horizon server URL (optional, used by horizon helpers) STELLAR_RPC_URL=https://soroban-testnet.stellar.org +# Soroban RPC endpoint for server-side calls (required for RPC features) SOROBAN_RPC_URL=https://soroban-testnet.stellar.org +# Stellar network passphrase matching SOROBAN_RPC_URL (required) SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015 # ============================================ # Contract IDs (Testnet placeholders) # ============================================ -INSURANCE_CONTRACT_ID=CACDYF3CYMJEJTIVFESQYZTN67GO2R5D5IUABTCUG3HXQSRXCSOROBAN +# Remittance split contract ID (optional) +REMITTANCE_SPLIT_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# Savings goals contract ID (optional) +SAVINGS_GOALS_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# Bill payments contract ID (optional) +BILL_PAYMENTS_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# Insurance contract ID (optional) +INSURANCE_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# Family wallet contract ID (optional) +FAMILY_WALLET_CONTRACT_ID=CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# Legacy or alternative variable names used by some modules (optional) REMITTANCE_CONTRACT_ID=CACDYF3CYMJEJTIVFESQYZTN67GO2R5D5IUABTCUG3HXQSRXCSOROBAN SAVINGS_CONTRACT_ID=CACDYF3CYMJEJTIVFESQYZTN67GO2R5D5IUABTCUG3HXQSRXCSOROBAN BILLS_CONTRACT_ID=CACDYF3CYMJEJTIVFESQYZTN67GO2R5D5IUABTCUG3HXQSRXCSOROBAN # ============================================ -# Session Encryption (MUST be 32+ characters) +# Session / Auth Secrets # ============================================ +# Iron-session password (32+ chars) if using custom session SESSION_PASSWORD=supersecurelongsessionpasswordatleast32characters!! +# NextAuth secret or generic session secret (optional, if using NextAuth or alt auth) +NEXTAUTH_SECRET= +SESSION_SECRET= # ============================================ # Auth Secret (used in tests / API) # ============================================ AUTH_SECRET=test-secret-for-local-dev-only +# ============================================ +# Database configuration +# ============================================ +# Database connection URL (Postgres/Prisma), or POSTGRES_URL alternative +DATABASE_URL= +POSTGRES_URL= + # ============================================ # Anchor Webhook Secret # ============================================ diff --git a/README.md b/README.md index 5988d99..815abab 100644 --- a/README.md +++ b/README.md @@ -222,36 +222,45 @@ All API routes are serverless functions deployed alongside the frontend. ### Environment Variables -Create a `.env.local` file in the root directory with the following variables: +Create a `.env.local` file in the root directory. See `.env.example` for a complete, documented list. Server-side configuration is centralized in [env.ts](file:///c:/Users/DELL/Desktop/Remitwise-Frontend/lib/env.ts). ```bash -# Stellar Network Configuration -NEXT_PUBLIC_STELLAR_NETWORK=testnet # or 'mainnet' -NEXT_PUBLIC_HORIZON_URL=https://horizon-testnet.stellar.org -NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org - -# Contract IDs (deployed Soroban contracts) -NEXT_PUBLIC_REMITTANCE_SPLIT_CONTRACT_ID= -NEXT_PUBLIC_SAVINGS_GOALS_CONTRACT_ID= -NEXT_PUBLIC_BILL_PAYMENTS_CONTRACT_ID= -NEXT_PUBLIC_INSURANCE_CONTRACT_ID= -NEXT_PUBLIC_FAMILY_WALLET_CONTRACT_ID= - -# Authentication -AUTH_SECRET=your-secret-key-here # Generate with: openssl rand -base64 32 -SESSION_COOKIE_NAME=remitwise-session -SESSION_MAX_AGE=86400 # 24 hours in seconds - -# API Configuration -API_RATE_LIMIT=100 # requests per minute -API_TIMEOUT=30000 # milliseconds - -# Optional: Anchor Platform -ANCHOR_PLATFORM_URL= -ANCHOR_PLATFORM_API_KEY= +# Soroban RPC (required for on-chain features) +SOROBAN_RPC_URL=https://soroban-testnet.stellar.org +SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015 + +# Contract IDs (optional; required to enable specific features) +REMITTANCE_SPLIT_CONTRACT_ID= +SAVINGS_GOALS_CONTRACT_ID= +BILL_PAYMENTS_CONTRACT_ID= +INSURANCE_CONTRACT_ID= +FAMILY_WALLET_CONTRACT_ID= + +# Database (optional; required if using the DB-backed features) +DATABASE_URL= +# or +POSTGRES_URL= + +# Auth secrets (optional; required if using NextAuth or alt auth) +NEXTAUTH_SECRET= +SESSION_SECRET= + +# Anchor API (optional; required if integrating an anchor) +ANCHOR_API_BASE_URL= ``` -See `.env.example` for a complete list of configuration options. +Client-side variables for UI behavior continue to use the `NEXT_PUBLIC_*` prefix as needed. + +Required variables by feature: +- Core Soroban connectivity: SOROBAN_RPC_URL, SOROBAN_NETWORK_PASSPHRASE +- Remittance split: REMITTANCE_SPLIT_CONTRACT_ID +- Savings goals: SAVINGS_GOALS_CONTRACT_ID +- Bill payments: BILL_PAYMENTS_CONTRACT_ID +- Insurance: INSURANCE_CONTRACT_ID +- Family wallet: FAMILY_WALLET_CONTRACT_ID +- Database-backed features: DATABASE_URL or POSTGRES_URL +- Anchor integrations: ANCHOR_API_BASE_URL +- NextAuth-based flows (if enabled): NEXTAUTH_SECRET or SESSION_SECRET ### API Middleware Configuration diff --git a/lib/env.ts b/lib/env.ts new file mode 100644 index 0000000..f8b4e94 --- /dev/null +++ b/lib/env.ts @@ -0,0 +1,41 @@ +import { z } from "zod"; + +const EnvSchema = z.object({ + SOROBAN_RPC_URL: z + .string() + .default("https://soroban-testnet.stellar.org"), + SOROBAN_NETWORK_PASSPHRASE: z + .string() + .default("Test SDF Network ; September 2015"), + REMITTANCE_SPLIT_CONTRACT_ID: z.string().optional().default(""), + SAVINGS_GOALS_CONTRACT_ID: z.string().optional().default(""), + BILL_PAYMENTS_CONTRACT_ID: z.string().optional().default(""), + INSURANCE_CONTRACT_ID: z.string().optional().default(""), + FAMILY_WALLET_CONTRACT_ID: z.string().optional().default(""), + DATABASE_URL: z + .string() + .optional() + .default(process.env.POSTGRES_URL ?? ""), + POSTGRES_URL: z.string().optional().default(""), + NEXTAUTH_SECRET: z + .string() + .optional() + .default(process.env.SESSION_SECRET ?? ""), + SESSION_SECRET: z.string().optional().default(""), + ANCHOR_API_BASE_URL: z.string().optional().default(""), +}); + +const parsed = EnvSchema.parse(process.env); + +export type Env = z.infer; + +export const env: Env = parsed; + +export function requireEnv(keys: Array): void { + for (const k of keys) { + const v = parsed[k]; + if (typeof v === "string" && v.trim() === "") { + throw new Error(`Missing required environment variable: ${k as string}`); + } + } +} diff --git a/lib/soroban/client.ts b/lib/soroban/client.ts index 9dbd4a8..5e9bcbe 100644 --- a/lib/soroban/client.ts +++ b/lib/soroban/client.ts @@ -15,14 +15,14 @@ */ import { SorobanRpc, Networks } from "@stellar/stellar-sdk"; +import { env } from "@/lib/env"; // ── Configuration ───────────────────────────────────────────────────────────── -const RPC_URL = - process.env.SOROBAN_RPC_URL ?? "https://soroban-testnet.stellar.org"; +const RPC_URL = env.SOROBAN_RPC_URL ?? "https://soroban-testnet.stellar.org"; const NETWORK_PASSPHRASE = - process.env.SOROBAN_NETWORK_PASSPHRASE ?? Networks.TESTNET; + env.SOROBAN_NETWORK_PASSPHRASE ?? Networks.TESTNET; /** How long (ms) to wait for a single RPC call before aborting. */ const TIMEOUT_MS = 10_000; @@ -42,7 +42,7 @@ let _server: SorobanRpc.Server | null = null; export function getServer(): SorobanRpc.Server { if (!_server) { _server = new SorobanRpc.Server(RPC_URL, { - allowHttp: RPC_URL.startsWith("http://"), // only allow plain HTTP for local dev + allowHttp: RPC_URL.startsWith("http://"), }); } return _server; @@ -140,4 +140,4 @@ export class SorobanClientError extends Error { this.name = "SorobanClientError"; this.cause = cause; } -} \ No newline at end of file +}