forked from Astrea-Payouts/astrea
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenv.ts
More file actions
72 lines (65 loc) · 2.39 KB
/
Copy pathenv.ts
File metadata and controls
72 lines (65 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { z } from "zod";
import {
HORIZON_URL,
STELLAR_ACCOUNT_ID,
STELLAR_NETWORK_PASSPHRASE,
} from "./stellar-network";
// Single source of truth for which Stellar network the app targets.
// Deliberately NEXT_PUBLIC_ (not a secret) so server and client can never
// disagree about network — a duplicated STELLAR_NETWORK + a separate
// NEXT_PUBLIC_STELLAR_NETWORK would let them drift, which is exactly the
// testnet/mainnet mix-up failure mode documented in docs/architecture.md.
// The network → passphrase/Horizon mapping itself lives in stellar-network.ts
// (client-safe) so it isn't duplicated between the server and client configs.
const serverSchema = z.object({
NEXT_PUBLIC_STELLAR_NETWORK: z
.enum(["testnet", "mainnet"])
.default("testnet"),
// Explicit gate per docs/architecture.md ("mainnet behind explicit gate") —
// setting NEXT_PUBLIC_STELLAR_NETWORK=mainnet alone is not enough.
ALLOW_MAINNET: z
.enum(["true", "false"])
.default("false")
.transform((v) => v === "true"),
TW_API_URL: z.url().default("https://dev.api.trustlesswork.com"),
TW_API_KEY: z
.string()
.min(
1,
"TW_API_KEY is required — request one at https://dapp.trustlesswork.com",
),
USDC_ISSUER: z
.string()
.regex(
STELLAR_ACCOUNT_ID,
"USDC_ISSUER must be a Stellar account ID (starts with G, 56 chars)",
),
USDC_SYMBOL: z.string().min(1).default("USDC"),
});
function parseEnv() {
const parsed = serverSchema.safeParse(process.env);
if (!parsed.success) {
const issues = parsed.error.issues
.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`)
.join("\n");
throw new Error(`Invalid environment configuration:\n${issues}`);
}
const data = parsed.data;
if (data.NEXT_PUBLIC_STELLAR_NETWORK === "mainnet" && !data.ALLOW_MAINNET) {
throw new Error(
"NEXT_PUBLIC_STELLAR_NETWORK=mainnet requires ALLOW_MAINNET=true to be set " +
"explicitly. This is a deliberate gate (docs/architecture.md), not a bug — " +
"remove ALLOW_MAINNET or set it to true only when you mean it.",
);
}
return {
...data,
networkPassphrase: STELLAR_NETWORK_PASSPHRASE,
horizonUrl: HORIZON_URL,
};
}
// Parsed once at module load — any invalid/missing var fails the boot
// immediately (a Next.js server action, route handler, or script importing
// this module) rather than surfacing as a confusing runtime error deep in
// an escrow call.
export const env = parseEnv();