Skip to content

Commit fc5c89a

Browse files
committed
refactor(config): centralize backend configuration with Zod validation
1 parent 86508ce commit fc5c89a

2 files changed

Lines changed: 84 additions & 1 deletion

File tree

config.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import dotenv from 'dotenv';
2+
import { z } from 'zod';
3+
4+
dotenv.config();
5+
6+
/**
7+
* Configuration Schema for the StellarStream Backend/Watcher.
8+
* Uses Zod for runtime validation and type inference.
9+
*/
10+
const envSchema = z.object({
11+
/**
12+
* The URL of the Stellar/Soroban RPC endpoint.
13+
* @example "https://soroban-testnet.stellar.org"
14+
*/
15+
STELLAR_RPC_URL: z.string().url({ message: "STELLAR_RPC_URL must be a valid URL." }),
16+
17+
/**
18+
* The network passphrase for the target Stellar network.
19+
* Defaults to Testnet if not provided.
20+
*/
21+
STELLAR_NETWORK_PASSPHRASE: z
22+
.string()
23+
.default("Test SDF Network ; September 2015"),
24+
25+
/**
26+
* The ID of the StellarStream smart contract (C...).
27+
* Must be a 56-character string starting with 'C'.
28+
*/
29+
CONTRACT_ID: z
30+
.string()
31+
.length(56, "CONTRACT_ID must be exactly 56 characters.")
32+
.startsWith("C", "CONTRACT_ID must start with 'C'."),
33+
34+
/**
35+
* Frequency of polling the RPC for new events in milliseconds.
36+
* @default 5000
37+
*/
38+
POLL_INTERVAL_MS: z.coerce
39+
.number()
40+
.int()
41+
.positive()
42+
.default(5000),
43+
44+
/**
45+
* Maximum number of retry attempts for transient RPC failures.
46+
* @default 3
47+
*/
48+
MAX_RETRIES: z.coerce
49+
.number()
50+
.int()
51+
.min(0)
52+
.default(3),
53+
54+
/**
55+
* Initial delay for exponential backoff in milliseconds.
56+
* @default 2000
57+
*/
58+
RETRY_DELAY_MS: z.coerce
59+
.number()
60+
.int()
61+
.min(0)
62+
.default(2000),
63+
64+
/**
65+
* Number of ledgers to stay behind the tip for safety against reorgs.
66+
* @default 10
67+
*/
68+
SAFETY_MARGIN: z.coerce
69+
.number()
70+
.int()
71+
.min(0)
72+
.default(10),
73+
});
74+
75+
/**
76+
* Validated configuration object.
77+
* All services should import this object rather than accessing process.env directly.
78+
*/
79+
export const config = envSchema.parse(process.env);
80+
81+
export type Config = z.infer<typeof envSchema>;

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"private": true,
66
"dependencies": {
77
"next": "14.0.0",
8+
"dotenv": "^16.4.5",
89
"react": "^18.2.0",
910
"react-dom": "^18.2.0",
1011
"@radix-ui/react-dialog": "^1.0.5",
@@ -14,7 +15,8 @@
1415
"tailwindcss": "^3.3.0",
1516
"autoprefixer": "^10.4.16",
1617
"postcss": "^8.4.31",
17-
"clsx": "^2.0.0"
18+
"clsx": "^2.0.0",
19+
"zod": "^3.23.8"
1820
},
1921
"devDependencies": {
2022
"@types/node": "^20.8.0",

0 commit comments

Comments
 (0)