|
1 | | -// Disable the following rule because this file is the intended place to declare |
2 | | -// and load all env variables. |
3 | | -/* eslint-disable n/no-process-env */ |
4 | | - |
5 | | -// Disable the following rule because variables in this file are only loaded at |
6 | | -// runtime and do not influence the build outputs, thus they need not be |
7 | | -// declared to turbo for it to be able to cache build outputs correctly. |
8 | | -/* eslint-disable turbo/no-undeclared-env-vars */ |
| 1 | +// biome-ignore-all lint/style/noProcessEnv: this file is the intended place to declare and load all env variables |
| 2 | +// biome-ignore-all lint/nursery/noUndeclaredEnvVars: most variables here are only loaded at runtime and do not influence the build outputs, thus they need not be declared to turbo for it to be able to cache build outputs correctly |
9 | 3 |
|
10 | 4 | import "server-only"; |
11 | 5 |
|
@@ -38,7 +32,31 @@ const transformOr = <T>( |
38 | 32 | const getOr = (key: string, defaultValue: string): string => |
39 | 33 | transform(key, (value) => value ?? defaultValue); |
40 | 34 |
|
41 | | -const asBoolean = (value: string): boolean => value.toLowerCase() === "true"; |
| 35 | +// Declared here rather than beside `MissingEnvironmentError` at the bottom of |
| 36 | +// the file because `asBoolean` runs during module evaluation, before a class |
| 37 | +// declared further down has left its temporal dead zone. |
| 38 | +class InvalidEnvironmentError extends Error { |
| 39 | + constructor(name: string, value: string, expected: string) { |
| 40 | + super( |
| 41 | + `Invalid value for environment variable ${name}: "${value}" (expected ${expected})!`, |
| 42 | + ); |
| 43 | + this.name = "InvalidEnvironmentError"; |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +const asBoolean = (key: string, value: string): boolean => { |
| 48 | + switch (value.toLowerCase()) { |
| 49 | + case "true": { |
| 50 | + return true; |
| 51 | + } |
| 52 | + case "false": { |
| 53 | + return false; |
| 54 | + } |
| 55 | + default: { |
| 56 | + throw new InvalidEnvironmentError(key, value, `"true" or "false"`); |
| 57 | + } |
| 58 | + } |
| 59 | +}; |
42 | 60 |
|
43 | 61 | /** |
44 | 62 | * Indicates that this server is the live customer-facing production server. |
@@ -79,10 +97,16 @@ export const PROXYCHECK_API_KEY = demandInProduction("PROXYCHECK_API_KEY"); |
79 | 97 | /** |
80 | 98 | * Shows the persistent banner announcing that OIS rewards are paused. Enabled |
81 | 99 | * by default; set `OIS_PAUSED=false` to remove the banner when rewards resume. |
| 100 | + * Anything other than `true` / `false` throws rather than defaulting, so a typo |
| 101 | + * can't silently drop a notice about ongoing slashing risk. |
82 | 102 | * `/` is statically prerendered, so this is baked in at build time -- flipping |
83 | 103 | * it needs a redeploy, not just an env var change. |
84 | 104 | */ |
85 | | -export const OIS_PAUSED = transformOr("OIS_PAUSED", asBoolean, true); |
| 105 | +export const OIS_PAUSED = transformOr( |
| 106 | + "OIS_PAUSED", |
| 107 | + (value) => asBoolean("OIS_PAUSED", value), |
| 108 | + true, |
| 109 | +); |
86 | 110 | // This needs to be a public key that has SOL in it all the time, it will be used as a payer in the transaction simulation to compute the claimable rewards |
87 | 111 | // such simulation fails when the payer has no funds. |
88 | 112 | export const SIMULATION_PAYER_ADDRESS = getOr( |
|
0 commit comments