diff --git a/libs/environment/src/hooks/use-environment.ts b/libs/environment/src/hooks/use-environment.ts index bf74887a8..5d908fc60 100644 --- a/libs/environment/src/hooks/use-environment.ts +++ b/libs/environment/src/hooks/use-environment.ts @@ -12,7 +12,7 @@ import { NodeCheckDocument, NodeCheckTimeUpdateDocument, } from '../utils/__generated__/NodeCheck'; -import type { Environment } from '../types'; +import type { Environment, FeatureFlags } from '../types'; import { Networks } from '../types'; import { compileErrors } from '../utils/compile-errors'; import { envSchema } from '../utils/validate-environment'; @@ -39,8 +39,11 @@ const VERSION = 1; export const STORAGE_KEY = `vega_url_${VERSION}`; const SUBSCRIPTION_TIMEOUT = 3000; +export const FLAGS = compileFeatureFlags(); + export const useEnvironment = create()((set, get) => ({ ...compileEnvVars(), + ...compileFeatureFlags(), nodes: [], status: 'default', error: null, @@ -372,6 +375,23 @@ function compileEnvVars() { return env; } +function compileFeatureFlags(): FeatureFlags { + return { + CONSOLE_ICEBERG_ORDERS: truthy.includes( + windowOrDefault('NX_CONSOLE_ICEBERG_ORDERS') + ), + CONSOLE_STOP_ORDERS: truthy.includes( + windowOrDefault('NX_CONSOLE_STOP_ORDERS') + ), + CONSOLE_SUCCESSOR_MARKETS: truthy.includes( + windowOrDefault('NX_CONSOLE_SUCCESSOR_MARKETS') + ), + CONSOLE_PRODUCT_PERPETUALS: truthy.includes( + windowOrDefault('NX_CONSOLE_PRODUCT_PERPETUALS') + ), + }; +} + function parseNetworks(value?: string) { if (value) { try { @@ -414,7 +434,7 @@ function getEtherscanUrl( export function windowOrDefault(key: string, defaultValue?: string) { if (typeof window !== 'undefined') { - // @ts-ignore avoid conflic in env + // @ts-ignore avoid conflict in env if (window._env_ && window._env_[key]) { // @ts-ignore presence has been check above return window._env_[key]; @@ -422,3 +442,5 @@ export function windowOrDefault(key: string, defaultValue?: string) { } return defaultValue || undefined; } + +const truthy = ['1', 'true']; diff --git a/libs/environment/src/types.ts b/libs/environment/src/types.ts index 91f0e78ca..6e9a3f94a 100644 --- a/libs/environment/src/types.ts +++ b/libs/environment/src/types.ts @@ -1,6 +1,9 @@ import type z from 'zod'; import type { tomlConfigSchema } from './utils/validate-configuration'; -import type { envSchema } from './utils/validate-environment'; +import type { + envSchema, + featureFlagsSchema, +} from './utils/validate-environment'; export enum Networks { VALIDATOR_TESTNET = 'VALIDATOR_TESTNET', @@ -12,5 +15,6 @@ export enum Networks { MAINNET = 'MAINNET', } export type Environment = z.infer; +export type FeatureFlags = z.infer; export type Configuration = z.infer; export const CUSTOM_NODE_KEY = 'custom' as const; diff --git a/libs/environment/src/utils/validate-environment.ts b/libs/environment/src/utils/validate-environment.ts index b6343bf72..b38b2e3fd 100644 --- a/libs/environment/src/utils/validate-environment.ts +++ b/libs/environment/src/utils/validate-environment.ts @@ -10,62 +10,69 @@ export enum Networks { MAINNET = 'MAINNET', } -const schemaObject = { - VEGA_URL: z.optional(z.string()), - VEGA_WALLET_URL: z.optional(z.string()), - VEGA_CONFIG_URL: z.optional(z.string()), - GIT_BRANCH: z.optional(z.string()), - GIT_COMMIT_HASH: z.optional(z.string()), - GIT_ORIGIN_URL: z.optional(z.string()), - GITHUB_FEEDBACK_URL: z.optional(z.string()), - ORACLE_PROOFS_URL: z.optional(z.string().url()), - VEGA_ENV: z.nativeEnum(Networks), - VEGA_CONSOLE_URL: z.optional(z.string()), - VEGA_EXPLORER_URL: z.optional(z.string()), - VEGA_TOKEN_URL: z.optional(z.string()), - VEGA_DOCS_URL: z.optional(z.string()), - VEGA_NETWORKS: z - .object( - Object.keys(Networks).reduce( - (acc, env) => ({ - ...acc, - [env]: z.optional(z.string()), - }), - {} - ) as Record> - ) - .strict({ - message: `All keys in NX_VEGA_NETWORKS must represent a valid environment: ${Object.keys( - Networks - ).join(' | ')}`, - }), - ETHEREUM_PROVIDER_URL: z.string().url({ - message: - 'The NX_ETHEREUM_PROVIDER_URL environment variable must be a valid url', - }), - ETHERSCAN_URL: z.string().url({ - message: 'The NX_ETHERSCAN_URL environment variable must be a valid url', - }), - HOSTED_WALLET_URL: z.optional(z.string()), - MAINTENANCE_PAGE: z.optional(z.boolean()), - ETH_LOCAL_PROVIDER_URL: z.optional(z.string()), - ETH_WALLET_MNEMONIC: z.optional(z.string()), - ANNOUNCEMENTS_CONFIG_URL: z.optional(z.string()), - VEGA_INCIDENT_URL: z.optional(z.string()), - APP_VERSION: z.optional(z.string()), - SENTRY_DSN: z.optional(z.string()), - TENDERMINT_URL: z.optional(z.string()), - TENDERMINT_WEBSOCKET_URL: z.optional(z.string()), -}; - // combine schema above with custom rule to ensure either // VEGA_URL or VEGA_CONFIG_URL are provided -export const envSchema = z.object(schemaObject).refine( - (data) => { - return !(!data.VEGA_URL && !data.VEGA_CONFIG_URL); - }, - { - message: - 'Must provide either NX_VEGA_CONFIG_URL or NX_VEGA_URL in the environment.', - } -); +export const envSchema = z + .object({ + VEGA_URL: z.optional(z.string()), + VEGA_WALLET_URL: z.optional(z.string()), + VEGA_CONFIG_URL: z.optional(z.string()), + GIT_BRANCH: z.optional(z.string()), + GIT_COMMIT_HASH: z.optional(z.string()), + GIT_ORIGIN_URL: z.optional(z.string()), + GITHUB_FEEDBACK_URL: z.optional(z.string()), + ORACLE_PROOFS_URL: z.optional(z.string().url()), + VEGA_ENV: z.nativeEnum(Networks), + VEGA_CONSOLE_URL: z.optional(z.string()), + VEGA_EXPLORER_URL: z.optional(z.string()), + VEGA_TOKEN_URL: z.optional(z.string()), + VEGA_DOCS_URL: z.optional(z.string()), + VEGA_NETWORKS: z + .object( + Object.keys(Networks).reduce( + (acc, env) => ({ + ...acc, + [env]: z.optional(z.string()), + }), + {} + ) as Record> + ) + .strict({ + message: `All keys in NX_VEGA_NETWORKS must represent a valid environment: ${Object.keys( + Networks + ).join(' | ')}`, + }), + ETHEREUM_PROVIDER_URL: z.string().url({ + message: + 'The NX_ETHEREUM_PROVIDER_URL environment variable must be a valid url', + }), + ETHERSCAN_URL: z.string().url({ + message: 'The NX_ETHERSCAN_URL environment variable must be a valid url', + }), + HOSTED_WALLET_URL: z.optional(z.string()), + MAINTENANCE_PAGE: z.optional(z.boolean()), + ETH_LOCAL_PROVIDER_URL: z.optional(z.string()), + ETH_WALLET_MNEMONIC: z.optional(z.string()), + ANNOUNCEMENTS_CONFIG_URL: z.optional(z.string()), + VEGA_INCIDENT_URL: z.optional(z.string()), + APP_VERSION: z.optional(z.string()), + SENTRY_DSN: z.optional(z.string()), + TENDERMINT_URL: z.optional(z.string()), + TENDERMINT_WEBSOCKET_URL: z.optional(z.string()), + }) + .refine( + (data) => { + return !(!data.VEGA_URL && !data.VEGA_CONFIG_URL); + }, + { + message: + 'Must provide either NX_VEGA_CONFIG_URL or NX_VEGA_URL in the environment.', + } + ); + +export const featureFlagsSchema = z.object({ + CONSOLE_SUCCESSOR_MARKETS: z.optional(z.boolean()), + CONSOLE_STOP_ORDERS: z.optional(z.boolean()), + CONSOLE_ICEBERG_ORDERS: z.optional(z.boolean()), + CONSOLE_PRODUCT_PERPETUALS: z.optional(z.boolean()), +});