diff --git a/web/app/components/base/param-item/top-k-item.tsx b/web/app/components/base/param-item/top-k-item.tsx index 2692875df1..e9fb15cf5b 100644 --- a/web/app/components/base/param-item/top-k-item.tsx +++ b/web/app/components/base/param-item/top-k-item.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react' import * as React from 'react' import { useTranslation } from 'react-i18next' +import { env } from '@/env' import ParamItem from '.' type Props = { @@ -12,7 +13,7 @@ type Props = { } const maxTopK = (() => { - const configValue = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-top-k-max-value') || '', 10) + const configValue = Number.parseInt(env.NEXT_PUBLIC_TOP_K_MAX_VALUE || '', 10) if (configValue && !isNaN(configValue)) return configValue return 10 diff --git a/web/app/components/datasets/create/step-two/components/inputs.tsx b/web/app/components/datasets/create/step-two/components/inputs.tsx index 4568431356..8c33cb5f65 100644 --- a/web/app/components/datasets/create/step-two/components/inputs.tsx +++ b/web/app/components/datasets/create/step-two/components/inputs.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next' import Input from '@/app/components/base/input' import { InputNumber } from '@/app/components/base/input-number' import Tooltip from '@/app/components/base/tooltip' +import { env } from '@/env' const TextLabel: FC = (props) => { return @@ -46,7 +47,7 @@ export const DelimiterInput: FC = (props) => } export const MaxLengthInput: FC = (props) => { - const maxValue = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000', 10) + const maxValue = Number.parseInt(env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH || '4000', 10) const { t } = useTranslation() return ( diff --git a/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts b/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts index 503704276e..17c90c6735 100644 --- a/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts +++ b/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts @@ -1,5 +1,6 @@ import type { ParentMode, PreProcessingRule, ProcessRule, Rules, SummaryIndexSetting as SummaryIndexSettingType } from '@/models/datasets' import { useCallback, useRef, useState } from 'react' +import { env } from '@/env' import { ChunkingMode, ProcessMode } from '@/models/datasets' import escape from './escape' import unescape from './unescape' @@ -9,7 +10,7 @@ export const DEFAULT_SEGMENT_IDENTIFIER = '\\n\\n' export const DEFAULT_MAXIMUM_CHUNK_LENGTH = 1024 export const DEFAULT_OVERLAP = 50 export const MAXIMUM_CHUNK_TOKEN_LENGTH = Number.parseInt( - globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000', + env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH || '4000', 10, ) diff --git a/web/app/components/header/account-dropdown/index.tsx b/web/app/components/header/account-dropdown/index.tsx index 07dd0fca3d..983f9e434d 100644 --- a/web/app/components/header/account-dropdown/index.tsx +++ b/web/app/components/header/account-dropdown/index.tsx @@ -28,6 +28,7 @@ import { useGlobalPublicStore } from '@/context/global-public-context' import { useDocLink } from '@/context/i18n' import { useModalContext } from '@/context/modal-context' import { useProviderContext } from '@/context/provider-context' +import { env } from '@/env' import { useLogout } from '@/service/use-common' import { cn } from '@/utils/classnames' import AccountAbout from '../account-about' @@ -178,7 +179,7 @@ export default function AppSelector() { { - document?.body?.getAttribute('data-public-site-about') !== 'hide' && ( + env.NEXT_PUBLIC_SITE_ABOUT !== 'hide' && (
{ useEffect(() => { - const SENTRY_DSN = document?.body?.getAttribute('data-public-sentry-dsn') - if (!IS_DEV && SENTRY_DSN) { + const sentryDsn = env.NEXT_PUBLIC_SENTRY_DSN + if (!IS_DEV && sentryDsn) { Sentry.init({ - dsn: SENTRY_DSN, + dsn: sentryDsn, integrations: [ Sentry.browserTracingIntegration(), Sentry.replayIntegration(), diff --git a/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx b/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx index d00ace49bf..016e19c957 100644 --- a/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx +++ b/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import { InputNumber } from '@/app/components/base/input-number' import Switch from '@/app/components/base/switch' import Tooltip from '@/app/components/base/tooltip' +import { env } from '@/env' export type TopKAndScoreThresholdProps = { topK: number @@ -16,7 +17,7 @@ export type TopKAndScoreThresholdProps = { } const maxTopK = (() => { - const configValue = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-top-k-max-value') || '', 10) + const configValue = Number.parseInt(env.NEXT_PUBLIC_TOP_K_MAX_VALUE || '', 10) if (configValue && !isNaN(configValue)) return configValue return 10 diff --git a/web/app/layout.tsx b/web/app/layout.tsx index a642d73259..e6d720f443 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -5,9 +5,8 @@ import { Instrument_Serif } from 'next/font/google' import { NuqsAdapter } from 'nuqs/adapters/next/app' import GlobalPublicStoreProvider from '@/context/global-public-context' import { TanstackQueryInitializer } from '@/context/query-client' -import { env } from '@/env' +import { clientEnvKeys, env, getDatasetAttrKeyFromEnvKey } from '@/env' import { getLocaleOnServer } from '@/i18n-config/server' -import { DatasetAttr } from '@/types/feature' import { cn } from '@/utils/classnames' import { ToastProvider } from './components/base/toast' import BrowserInitializer from './components/browser-initializer' @@ -40,40 +39,7 @@ const LocaleLayout = async ({ children: React.ReactNode }) => { const locale = await getLocaleOnServer() - - const datasetMap: Record = { - [DatasetAttr.DATA_API_PREFIX]: env.NEXT_PUBLIC_API_PREFIX, - [DatasetAttr.DATA_PUBLIC_API_PREFIX]: env.NEXT_PUBLIC_PUBLIC_API_PREFIX, - [DatasetAttr.DATA_MARKETPLACE_API_PREFIX]: env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX, - [DatasetAttr.DATA_MARKETPLACE_URL_PREFIX]: env.NEXT_PUBLIC_MARKETPLACE_URL_PREFIX, - [DatasetAttr.DATA_PUBLIC_EDITION]: env.NEXT_PUBLIC_EDITION, - [DatasetAttr.DATA_PUBLIC_AMPLITUDE_API_KEY]: env.NEXT_PUBLIC_AMPLITUDE_API_KEY, - [DatasetAttr.DATA_PUBLIC_COOKIE_DOMAIN]: env.NEXT_PUBLIC_COOKIE_DOMAIN, - [DatasetAttr.DATA_PUBLIC_SUPPORT_MAIL_LOGIN]: env.NEXT_PUBLIC_SUPPORT_MAIL_LOGIN, - [DatasetAttr.DATA_PUBLIC_SENTRY_DSN]: env.NEXT_PUBLIC_SENTRY_DSN, - [DatasetAttr.DATA_PUBLIC_MAINTENANCE_NOTICE]: env.NEXT_PUBLIC_MAINTENANCE_NOTICE, - [DatasetAttr.DATA_PUBLIC_SITE_ABOUT]: env.NEXT_PUBLIC_SITE_ABOUT, - [DatasetAttr.DATA_PUBLIC_TEXT_GENERATION_TIMEOUT_MS]: env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS, - [DatasetAttr.DATA_PUBLIC_MAX_TOOLS_NUM]: env.NEXT_PUBLIC_MAX_TOOLS_NUM, - [DatasetAttr.DATA_PUBLIC_MAX_PARALLEL_LIMIT]: env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT, - [DatasetAttr.DATA_PUBLIC_TOP_K_MAX_VALUE]: env.NEXT_PUBLIC_TOP_K_MAX_VALUE, - [DatasetAttr.DATA_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH]: env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH, - [DatasetAttr.DATA_PUBLIC_LOOP_NODE_MAX_COUNT]: env.NEXT_PUBLIC_LOOP_NODE_MAX_COUNT, - [DatasetAttr.DATA_PUBLIC_MAX_ITERATIONS_NUM]: env.NEXT_PUBLIC_MAX_ITERATIONS_NUM, - [DatasetAttr.DATA_PUBLIC_MAX_TREE_DEPTH]: env.NEXT_PUBLIC_MAX_TREE_DEPTH, - [DatasetAttr.DATA_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME]: env.NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME, - [DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER]: env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER, - [DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL]: env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL, - [DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL]: env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL, - [DatasetAttr.DATA_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX]: env.NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX, - [DatasetAttr.NEXT_PUBLIC_ZENDESK_WIDGET_KEY]: env.NEXT_PUBLIC_ZENDESK_WIDGET_KEY, - [DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT]: env.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT, - [DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION]: env.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION, - [DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL]: env.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL, - [DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID]: env.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID, - [DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN]: env.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN, - [DatasetAttr.DATA_PUBLIC_BATCH_CONCURRENCY]: env.NEXT_PUBLIC_BATCH_CONCURRENCY, - } + const datasetMap = Object.fromEntries(clientEnvKeys.map(envKey => [getDatasetAttrKeyFromEnvKey(envKey), env[envKey]])) return ( diff --git a/web/config/index.ts b/web/config/index.ts index bc034378d1..5db483327a 100644 --- a/web/config/index.ts +++ b/web/config/index.ts @@ -4,25 +4,19 @@ import { env } from '@/env' import { PromptRole } from '@/models/debug' import { PipelineInputVarType } from '@/models/pipeline' import { AgentStrategy } from '@/types/app' -import { DatasetAttr } from '@/types/feature' import pkg from '../package.json' const getBooleanConfig = ( envVar: string | undefined, - dataAttrKey: DatasetAttr, defaultValue: boolean = true, ) => { if (envVar !== undefined && envVar !== '') return envVar === 'true' - const attrValue = globalThis.document?.body?.getAttribute(dataAttrKey) - if (attrValue !== undefined && attrValue !== '') - return attrValue === 'true' return defaultValue } const getNumberConfig = ( envVar: string | undefined, - dataAttrKey: DatasetAttr, defaultValue: number, ) => { if (envVar) { @@ -30,54 +24,37 @@ const getNumberConfig = ( if (!Number.isNaN(parsed) && parsed > 0) return parsed } - - const attrValue = globalThis.document?.body?.getAttribute(dataAttrKey) - if (attrValue) { - const parsed = Number.parseInt(attrValue) - if (!Number.isNaN(parsed) && parsed > 0) - return parsed - } return defaultValue } const getStringConfig = ( envVar: string | undefined, - dataAttrKey: DatasetAttr, defaultValue: string, ) => { if (envVar) return envVar - - const attrValue = globalThis.document?.body?.getAttribute(dataAttrKey) - if (attrValue) - return attrValue return defaultValue } export const API_PREFIX = getStringConfig( env.NEXT_PUBLIC_API_PREFIX, - DatasetAttr.DATA_API_PREFIX, 'http://localhost:5001/console/api', ) export const PUBLIC_API_PREFIX = getStringConfig( env.NEXT_PUBLIC_PUBLIC_API_PREFIX, - DatasetAttr.DATA_PUBLIC_API_PREFIX, 'http://localhost:5001/api', ) export const MARKETPLACE_API_PREFIX = getStringConfig( env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX, - DatasetAttr.DATA_MARKETPLACE_API_PREFIX, 'http://localhost:5002/api', ) export const MARKETPLACE_URL_PREFIX = getStringConfig( env.NEXT_PUBLIC_MARKETPLACE_URL_PREFIX, - DatasetAttr.DATA_MARKETPLACE_URL_PREFIX, '', ) const EDITION = getStringConfig( env.NEXT_PUBLIC_EDITION, - DatasetAttr.DATA_PUBLIC_EDITION, 'SELF_HOSTED', ) @@ -86,16 +63,15 @@ export const IS_CLOUD_EDITION = EDITION === 'CLOUD' export const AMPLITUDE_API_KEY = getStringConfig( env.NEXT_PUBLIC_AMPLITUDE_API_KEY, - DatasetAttr.DATA_PUBLIC_AMPLITUDE_API_KEY, '', ) export const IS_DEV = env.NODE_ENV === 'development' export const IS_PROD = env.NODE_ENV === 'production' -export const SUPPORT_MAIL_LOGIN = !!( - env.NEXT_PUBLIC_SUPPORT_MAIL_LOGIN - || globalThis.document?.body?.getAttribute('data-public-support-mail-login') +export const SUPPORT_MAIL_LOGIN = getBooleanConfig( + env.NEXT_PUBLIC_SUPPORT_MAIL_LOGIN, + false, ) export const TONE_LIST = [ @@ -163,13 +139,11 @@ export const LOCALE_COOKIE_NAME = 'locale' const COOKIE_DOMAIN = getStringConfig( env.NEXT_PUBLIC_COOKIE_DOMAIN, - DatasetAttr.DATA_PUBLIC_COOKIE_DOMAIN, '', ).trim() export const BATCH_CONCURRENCY = getNumberConfig( env.NEXT_PUBLIC_BATCH_CONCURRENCY, - DatasetAttr.DATA_PUBLIC_BATCH_CONCURRENCY, 5, // default ) @@ -355,58 +329,47 @@ export const JSON_SCHEMA_MAX_DEPTH = 10 export const MAX_TOOLS_NUM = getNumberConfig( env.NEXT_PUBLIC_MAX_TOOLS_NUM, - DatasetAttr.DATA_PUBLIC_MAX_TOOLS_NUM, 10, ) export const MAX_PARALLEL_LIMIT = getNumberConfig( env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT, - DatasetAttr.DATA_PUBLIC_MAX_PARALLEL_LIMIT, 10, ) export const TEXT_GENERATION_TIMEOUT_MS = getNumberConfig( env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS, - DatasetAttr.DATA_PUBLIC_TEXT_GENERATION_TIMEOUT_MS, 60000, ) export const LOOP_NODE_MAX_COUNT = getNumberConfig( env.NEXT_PUBLIC_LOOP_NODE_MAX_COUNT, - DatasetAttr.DATA_PUBLIC_LOOP_NODE_MAX_COUNT, 100, ) export const MAX_ITERATIONS_NUM = getNumberConfig( env.NEXT_PUBLIC_MAX_ITERATIONS_NUM, - DatasetAttr.DATA_PUBLIC_MAX_ITERATIONS_NUM, 99, ) export const MAX_TREE_DEPTH = getNumberConfig( env.NEXT_PUBLIC_MAX_TREE_DEPTH, - DatasetAttr.DATA_PUBLIC_MAX_TREE_DEPTH, 50, ) export const ALLOW_UNSAFE_DATA_SCHEME = getBooleanConfig( env.NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME, - DatasetAttr.DATA_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME, false, ) export const ENABLE_WEBSITE_JINAREADER = getBooleanConfig( env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER, - DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER, true, ) export const ENABLE_WEBSITE_FIRECRAWL = getBooleanConfig( env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL, - DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL, true, ) export const ENABLE_WEBSITE_WATERCRAWL = getBooleanConfig( env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL, - DatasetAttr.DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL, false, ) export const ENABLE_SINGLE_DOLLAR_LATEX = getBooleanConfig( env.NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX, - DatasetAttr.DATA_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX, false, ) @@ -416,39 +379,33 @@ export const validPassword = /^(?=.*[a-z])(?=.*\d)\S{8,}$/i export const ZENDESK_WIDGET_KEY = getStringConfig( env.NEXT_PUBLIC_ZENDESK_WIDGET_KEY, - DatasetAttr.NEXT_PUBLIC_ZENDESK_WIDGET_KEY, '', ) export const ZENDESK_FIELD_IDS = { ENVIRONMENT: getStringConfig( env.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT, - DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT, '', ), VERSION: getStringConfig( env.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION, - DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION, '', ), EMAIL: getStringConfig( env.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL, - DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL, '', ), WORKSPACE_ID: getStringConfig( env.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID, - DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID, '', ), PLAN: getStringConfig( env.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN, - DatasetAttr.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN, '', ), } export const APP_VERSION = pkg.version -export const IS_MARKETPLACE = globalThis.document?.body?.getAttribute('data-is-marketplace') === 'true' +export const IS_MARKETPLACE = env.NEXT_PUBLIC_IS_MARKETPLACE === 'true' export const RAG_PIPELINE_PREVIEW_CHUNK_NUM = 20 diff --git a/web/context/app-context.tsx b/web/context/app-context.tsx index 12000044d6..dfcada3423 100644 --- a/web/context/app-context.tsx +++ b/web/context/app-context.tsx @@ -10,6 +10,7 @@ import { setUserId, setUserProperties } from '@/app/components/base/amplitude' import { setZendeskConversationFields } from '@/app/components/base/zendesk/utils' import MaintenanceNotice from '@/app/components/header/maintenance-notice' import { ZENDESK_FIELD_IDS } from '@/config' +import { env } from '@/env' import { useCurrentWorkspace, useLangGeniusVersion, @@ -204,7 +205,7 @@ export const AppContextProvider: FC = ({ children }) => }} >
- {globalThis.document?.body?.getAttribute('data-public-maintenance-notice') && } + {env.NEXT_PUBLIC_MAINTENANCE_NOTICE && }
{children}
diff --git a/web/env.ts b/web/env.ts index f54f36b048..9f3bd64b21 100644 --- a/web/env.ts +++ b/web/env.ts @@ -1,7 +1,88 @@ import { createEnv } from '@t3-oss/env-nextjs' +import { kebabCase, replace } from 'string-ts' import { z } from 'zod' const optionalString = z.string().optional() +const CLIENT_ENV_PREFIX = 'NEXT_PUBLIC_' as const +type ClientSchema = Record<`${typeof CLIENT_ENV_PREFIX}${string}`, z.ZodType> + +const clientSchema = { + NEXT_PUBLIC_ALLOW_EMBED: optionalString, + NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME: optionalString, + NEXT_PUBLIC_AMPLITUDE_API_KEY: optionalString, + NEXT_PUBLIC_API_PREFIX: optionalString, + NEXT_PUBLIC_BASE_PATH: optionalString, + NEXT_PUBLIC_BATCH_CONCURRENCY: optionalString, + NEXT_PUBLIC_COOKIE_DOMAIN: optionalString, + NEXT_PUBLIC_CSP_WHITELIST: optionalString, + NEXT_PUBLIC_DEPLOY_ENV: optionalString, + NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON: optionalString, + NEXT_PUBLIC_EDITION: optionalString, + NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX: optionalString, + NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL: optionalString, + NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER: optionalString, + NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL: optionalString, + NEXT_PUBLIC_GITHUB_ACCESS_TOKEN: optionalString, + NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: optionalString, + NEXT_PUBLIC_IS_MARKETPLACE: optionalString, + NEXT_PUBLIC_LOOP_NODE_MAX_COUNT: optionalString, + NEXT_PUBLIC_MAINTENANCE_NOTICE: optionalString, + NEXT_PUBLIC_MARKETPLACE_API_PREFIX: optionalString, + NEXT_PUBLIC_MARKETPLACE_URL_PREFIX: optionalString, + NEXT_PUBLIC_MAX_ITERATIONS_NUM: optionalString, + NEXT_PUBLIC_MAX_PARALLEL_LIMIT: optionalString, + NEXT_PUBLIC_MAX_TOOLS_NUM: optionalString, + NEXT_PUBLIC_MAX_TREE_DEPTH: optionalString, + NEXT_PUBLIC_PUBLIC_API_PREFIX: optionalString, + NEXT_PUBLIC_SENTRY_DSN: optionalString, + NEXT_PUBLIC_SITE_ABOUT: optionalString, + NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: optionalString, + NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS: optionalString, + NEXT_PUBLIC_TOP_K_MAX_VALUE: optionalString, + NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON: optionalString, + NEXT_PUBLIC_WEB_PREFIX: optionalString, + NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL: optionalString, + NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT: optionalString, + NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN: optionalString, + NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION: optionalString, + NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID: optionalString, + NEXT_PUBLIC_ZENDESK_WIDGET_KEY: optionalString, +} satisfies ClientSchema + +export type ClientEnvKey = keyof typeof clientSchema + +type SnakeToKebabCase = S extends `${infer Head}_${infer Tail}` + ? `${Lowercase}-${SnakeToKebabCase}` + : Lowercase +type DatasetAttrKeyFromEnvKey = K extends `${typeof CLIENT_ENV_PREFIX}${infer Suffix}` + ? `data-${SnakeToKebabCase}` + : never + +export type ClientDatasetAttrKey = DatasetAttrKeyFromEnvKey + +export const clientEnvKeys = Object.keys(clientSchema) as ReadonlyArray + +const getClientEnvSuffix = (key: ClientEnvKey) => kebabCase(replace(key, CLIENT_ENV_PREFIX, '')) + +export const getDatasetAttrKeyFromEnvKey = (key: K) => { + const suffix = getClientEnvSuffix(key) + return `data-${suffix}` as const +} + +const getRuntimeEnvFromBody = (key: K) => { + if (typeof window === 'undefined') + return undefined + + const body = globalThis.document?.body + if (!body) + return undefined + + const value = body.getAttribute(getDatasetAttrKeyFromEnvKey(key)) + if (value !== null && value !== '') + return value + + return undefined +} export const env = createEnv({ server: { @@ -14,88 +95,49 @@ export const env = createEnv({ shared: { NODE_ENV: z.enum(['development', 'test', 'production']).default('development'), }, - client: { - NEXT_PUBLIC_ALLOW_EMBED: optionalString, - NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME: optionalString, - NEXT_PUBLIC_AMPLITUDE_API_KEY: optionalString, - NEXT_PUBLIC_API_PREFIX: optionalString, - NEXT_PUBLIC_BASE_PATH: optionalString, - NEXT_PUBLIC_BATCH_CONCURRENCY: optionalString, - NEXT_PUBLIC_COOKIE_DOMAIN: optionalString, - NEXT_PUBLIC_CSP_WHITELIST: optionalString, - NEXT_PUBLIC_DEPLOY_ENV: optionalString, - NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON: optionalString, - NEXT_PUBLIC_EDITION: optionalString, - NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX: optionalString, - NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL: optionalString, - NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER: optionalString, - NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL: optionalString, - NEXT_PUBLIC_GITHUB_ACCESS_TOKEN: optionalString, - NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: optionalString, - NEXT_PUBLIC_LOOP_NODE_MAX_COUNT: optionalString, - NEXT_PUBLIC_MAINTENANCE_NOTICE: optionalString, - NEXT_PUBLIC_MARKETPLACE_API_PREFIX: optionalString, - NEXT_PUBLIC_MARKETPLACE_URL_PREFIX: optionalString, - NEXT_PUBLIC_MAX_ITERATIONS_NUM: optionalString, - NEXT_PUBLIC_MAX_PARALLEL_LIMIT: optionalString, - NEXT_PUBLIC_MAX_TOOLS_NUM: optionalString, - NEXT_PUBLIC_MAX_TREE_DEPTH: optionalString, - NEXT_PUBLIC_PUBLIC_API_PREFIX: optionalString, - NEXT_PUBLIC_SENTRY_DSN: optionalString, - NEXT_PUBLIC_SITE_ABOUT: optionalString, - NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: optionalString, - NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS: optionalString, - NEXT_PUBLIC_TOP_K_MAX_VALUE: optionalString, - NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON: optionalString, - NEXT_PUBLIC_WEB_PREFIX: optionalString, - NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL: optionalString, - NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT: optionalString, - NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN: optionalString, - NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION: optionalString, - NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID: optionalString, - NEXT_PUBLIC_ZENDESK_WIDGET_KEY: optionalString, - }, + client: clientSchema, experimental__runtimeEnv: { NODE_ENV: process.env.NODE_ENV, - NEXT_PUBLIC_ALLOW_EMBED: process.env.NEXT_PUBLIC_ALLOW_EMBED, - NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME: process.env.NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME, - NEXT_PUBLIC_AMPLITUDE_API_KEY: process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY, - NEXT_PUBLIC_API_PREFIX: process.env.NEXT_PUBLIC_API_PREFIX, - NEXT_PUBLIC_BASE_PATH: process.env.NEXT_PUBLIC_BASE_PATH, - NEXT_PUBLIC_BATCH_CONCURRENCY: process.env.NEXT_PUBLIC_BATCH_CONCURRENCY, - NEXT_PUBLIC_COOKIE_DOMAIN: process.env.NEXT_PUBLIC_COOKIE_DOMAIN, - NEXT_PUBLIC_CSP_WHITELIST: process.env.NEXT_PUBLIC_CSP_WHITELIST, - NEXT_PUBLIC_DEPLOY_ENV: process.env.NEXT_PUBLIC_DEPLOY_ENV, - NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON: process.env.NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON, - NEXT_PUBLIC_EDITION: process.env.NEXT_PUBLIC_EDITION, - NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX: process.env.NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX, - NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL, - NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER, - NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL, - NEXT_PUBLIC_GITHUB_ACCESS_TOKEN: process.env.NEXT_PUBLIC_GITHUB_ACCESS_TOKEN, - NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: process.env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH, - NEXT_PUBLIC_LOOP_NODE_MAX_COUNT: process.env.NEXT_PUBLIC_LOOP_NODE_MAX_COUNT, - NEXT_PUBLIC_MAINTENANCE_NOTICE: process.env.NEXT_PUBLIC_MAINTENANCE_NOTICE, - NEXT_PUBLIC_MARKETPLACE_API_PREFIX: process.env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX, - NEXT_PUBLIC_MARKETPLACE_URL_PREFIX: process.env.NEXT_PUBLIC_MARKETPLACE_URL_PREFIX, - NEXT_PUBLIC_MAX_ITERATIONS_NUM: process.env.NEXT_PUBLIC_MAX_ITERATIONS_NUM, - NEXT_PUBLIC_MAX_PARALLEL_LIMIT: process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT, - NEXT_PUBLIC_MAX_TOOLS_NUM: process.env.NEXT_PUBLIC_MAX_TOOLS_NUM, - NEXT_PUBLIC_MAX_TREE_DEPTH: process.env.NEXT_PUBLIC_MAX_TREE_DEPTH, - NEXT_PUBLIC_PUBLIC_API_PREFIX: process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX, - NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN, - NEXT_PUBLIC_SITE_ABOUT: process.env.NEXT_PUBLIC_SITE_ABOUT, - NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: process.env.NEXT_PUBLIC_SUPPORT_MAIL_LOGIN, - NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS: process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS, - NEXT_PUBLIC_TOP_K_MAX_VALUE: process.env.NEXT_PUBLIC_TOP_K_MAX_VALUE, - NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON: process.env.NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON, - NEXT_PUBLIC_WEB_PREFIX: process.env.NEXT_PUBLIC_WEB_PREFIX, - NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL, - NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT, - NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN, - NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION, - NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID, - NEXT_PUBLIC_ZENDESK_WIDGET_KEY: process.env.NEXT_PUBLIC_ZENDESK_WIDGET_KEY, + NEXT_PUBLIC_ALLOW_EMBED: process.env.NEXT_PUBLIC_ALLOW_EMBED || getRuntimeEnvFromBody('NEXT_PUBLIC_ALLOW_EMBED'), + NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME: process.env.NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME || getRuntimeEnvFromBody('NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME'), + NEXT_PUBLIC_AMPLITUDE_API_KEY: process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY || getRuntimeEnvFromBody('NEXT_PUBLIC_AMPLITUDE_API_KEY'), + NEXT_PUBLIC_API_PREFIX: process.env.NEXT_PUBLIC_API_PREFIX || getRuntimeEnvFromBody('NEXT_PUBLIC_API_PREFIX'), + NEXT_PUBLIC_BASE_PATH: process.env.NEXT_PUBLIC_BASE_PATH || getRuntimeEnvFromBody('NEXT_PUBLIC_BASE_PATH'), + NEXT_PUBLIC_BATCH_CONCURRENCY: process.env.NEXT_PUBLIC_BATCH_CONCURRENCY || getRuntimeEnvFromBody('NEXT_PUBLIC_BATCH_CONCURRENCY'), + NEXT_PUBLIC_COOKIE_DOMAIN: process.env.NEXT_PUBLIC_COOKIE_DOMAIN || getRuntimeEnvFromBody('NEXT_PUBLIC_COOKIE_DOMAIN'), + NEXT_PUBLIC_CSP_WHITELIST: process.env.NEXT_PUBLIC_CSP_WHITELIST || getRuntimeEnvFromBody('NEXT_PUBLIC_CSP_WHITELIST'), + NEXT_PUBLIC_DEPLOY_ENV: process.env.NEXT_PUBLIC_DEPLOY_ENV || getRuntimeEnvFromBody('NEXT_PUBLIC_DEPLOY_ENV'), + NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON: process.env.NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON || getRuntimeEnvFromBody('NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON'), + NEXT_PUBLIC_EDITION: process.env.NEXT_PUBLIC_EDITION || getRuntimeEnvFromBody('NEXT_PUBLIC_EDITION'), + NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX: process.env.NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX || getRuntimeEnvFromBody('NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX'), + NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL || getRuntimeEnvFromBody('NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL'), + NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER || getRuntimeEnvFromBody('NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER'), + NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL: process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL || getRuntimeEnvFromBody('NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL'), + NEXT_PUBLIC_GITHUB_ACCESS_TOKEN: process.env.NEXT_PUBLIC_GITHUB_ACCESS_TOKEN || getRuntimeEnvFromBody('NEXT_PUBLIC_GITHUB_ACCESS_TOKEN'), + NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: process.env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH || getRuntimeEnvFromBody('NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH'), + NEXT_PUBLIC_IS_MARKETPLACE: process.env.NEXT_PUBLIC_IS_MARKETPLACE || getRuntimeEnvFromBody('NEXT_PUBLIC_IS_MARKETPLACE'), + NEXT_PUBLIC_LOOP_NODE_MAX_COUNT: process.env.NEXT_PUBLIC_LOOP_NODE_MAX_COUNT || getRuntimeEnvFromBody('NEXT_PUBLIC_LOOP_NODE_MAX_COUNT'), + NEXT_PUBLIC_MAINTENANCE_NOTICE: process.env.NEXT_PUBLIC_MAINTENANCE_NOTICE || getRuntimeEnvFromBody('NEXT_PUBLIC_MAINTENANCE_NOTICE'), + NEXT_PUBLIC_MARKETPLACE_API_PREFIX: process.env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX || getRuntimeEnvFromBody('NEXT_PUBLIC_MARKETPLACE_API_PREFIX'), + NEXT_PUBLIC_MARKETPLACE_URL_PREFIX: process.env.NEXT_PUBLIC_MARKETPLACE_URL_PREFIX || getRuntimeEnvFromBody('NEXT_PUBLIC_MARKETPLACE_URL_PREFIX'), + NEXT_PUBLIC_MAX_ITERATIONS_NUM: process.env.NEXT_PUBLIC_MAX_ITERATIONS_NUM || getRuntimeEnvFromBody('NEXT_PUBLIC_MAX_ITERATIONS_NUM'), + NEXT_PUBLIC_MAX_PARALLEL_LIMIT: process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT || getRuntimeEnvFromBody('NEXT_PUBLIC_MAX_PARALLEL_LIMIT'), + NEXT_PUBLIC_MAX_TOOLS_NUM: process.env.NEXT_PUBLIC_MAX_TOOLS_NUM || getRuntimeEnvFromBody('NEXT_PUBLIC_MAX_TOOLS_NUM'), + NEXT_PUBLIC_MAX_TREE_DEPTH: process.env.NEXT_PUBLIC_MAX_TREE_DEPTH || getRuntimeEnvFromBody('NEXT_PUBLIC_MAX_TREE_DEPTH'), + NEXT_PUBLIC_PUBLIC_API_PREFIX: process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX || getRuntimeEnvFromBody('NEXT_PUBLIC_PUBLIC_API_PREFIX'), + NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN || getRuntimeEnvFromBody('NEXT_PUBLIC_SENTRY_DSN'), + NEXT_PUBLIC_SITE_ABOUT: process.env.NEXT_PUBLIC_SITE_ABOUT || getRuntimeEnvFromBody('NEXT_PUBLIC_SITE_ABOUT'), + NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: process.env.NEXT_PUBLIC_SUPPORT_MAIL_LOGIN || getRuntimeEnvFromBody('NEXT_PUBLIC_SUPPORT_MAIL_LOGIN'), + NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS: process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS || getRuntimeEnvFromBody('NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS'), + NEXT_PUBLIC_TOP_K_MAX_VALUE: process.env.NEXT_PUBLIC_TOP_K_MAX_VALUE || getRuntimeEnvFromBody('NEXT_PUBLIC_TOP_K_MAX_VALUE'), + NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON: process.env.NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON || getRuntimeEnvFromBody('NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON'), + NEXT_PUBLIC_WEB_PREFIX: process.env.NEXT_PUBLIC_WEB_PREFIX || getRuntimeEnvFromBody('NEXT_PUBLIC_WEB_PREFIX'), + NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL || getRuntimeEnvFromBody('NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL'), + NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT || getRuntimeEnvFromBody('NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT'), + NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN || getRuntimeEnvFromBody('NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN'), + NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION || getRuntimeEnvFromBody('NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION'), + NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID: process.env.NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID || getRuntimeEnvFromBody('NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID'), + NEXT_PUBLIC_ZENDESK_WIDGET_KEY: process.env.NEXT_PUBLIC_ZENDESK_WIDGET_KEY || getRuntimeEnvFromBody('NEXT_PUBLIC_ZENDESK_WIDGET_KEY'), }, emptyStringAsUndefined: true, }) diff --git a/web/types/feature.ts b/web/types/feature.ts index 19980974da..a5c12a453e 100644 --- a/web/types/feature.ts +++ b/web/types/feature.ts @@ -107,37 +107,3 @@ export const defaultSystemFeatures: SystemFeatures = { enable_trial_app: false, enable_explore_banner: false, } - -export enum DatasetAttr { - DATA_API_PREFIX = 'data-api-prefix', - DATA_PUBLIC_API_PREFIX = 'data-public-api-prefix', - DATA_MARKETPLACE_API_PREFIX = 'data-marketplace-api-prefix', - DATA_MARKETPLACE_URL_PREFIX = 'data-marketplace-url-prefix', - DATA_PUBLIC_EDITION = 'data-public-edition', - DATA_PUBLIC_AMPLITUDE_API_KEY = 'data-public-amplitude-api-key', - DATA_PUBLIC_COOKIE_DOMAIN = 'data-public-cookie-domain', - DATA_PUBLIC_SUPPORT_MAIL_LOGIN = 'data-public-support-mail-login', - DATA_PUBLIC_SENTRY_DSN = 'data-public-sentry-dsn', - DATA_PUBLIC_MAINTENANCE_NOTICE = 'data-public-maintenance-notice', - DATA_PUBLIC_SITE_ABOUT = 'data-public-site-about', - DATA_PUBLIC_TEXT_GENERATION_TIMEOUT_MS = 'data-public-text-generation-timeout-ms', - DATA_PUBLIC_MAX_TOOLS_NUM = 'data-public-max-tools-num', - DATA_PUBLIC_MAX_PARALLEL_LIMIT = 'data-public-max-parallel-limit', - DATA_PUBLIC_TOP_K_MAX_VALUE = 'data-public-top-k-max-value', - DATA_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH = 'data-public-indexing-max-segmentation-tokens-length', - DATA_PUBLIC_LOOP_NODE_MAX_COUNT = 'data-public-loop-node-max-count', - DATA_PUBLIC_MAX_ITERATIONS_NUM = 'data-public-max-iterations-num', - DATA_PUBLIC_MAX_TREE_DEPTH = 'data-public-max-tree-depth', - DATA_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME = 'data-public-allow-unsafe-data-scheme', - DATA_PUBLIC_ENABLE_WEBSITE_JINAREADER = 'data-public-enable-website-jinareader', - DATA_PUBLIC_ENABLE_WEBSITE_FIRECRAWL = 'data-public-enable-website-firecrawl', - DATA_PUBLIC_ENABLE_WEBSITE_WATERCRAWL = 'data-public-enable-website-watercrawl', - DATA_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX = 'data-public-enable-single-dollar-latex', - NEXT_PUBLIC_ZENDESK_WIDGET_KEY = 'next-public-zendesk-widget-key', - NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT = 'next-public-zendesk-field-id-environment', - NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION = 'next-public-zendesk-field-id-version', - NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL = 'next-public-zendesk-field-id-email', - NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID = 'next-public-zendesk-field-id-workspace-id', - NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN = 'next-public-zendesk-field-id-plan', - DATA_PUBLIC_BATCH_CONCURRENCY = 'data-public-batch-concurrency', -}