feat: verify environment variables
This commit is contained in:
parent
51a9e678f0
commit
50e4ac33ef
@ -13,3 +13,6 @@ NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
|
||||
|
||||
# SENTRY
|
||||
NEXT_PUBLIC_SENTRY_DSN=
|
||||
|
||||
NEXT_PUBLIC_SITE_ABOUT=
|
||||
NEXT_PUBLIC_MAINTENANCE_NOTICE=
|
||||
|
@ -8,9 +8,7 @@ To start the web frontend service, you will need [Node.js v18.x (LTS)](https://n
|
||||
First, install the dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
# or
|
||||
yarn install --frozen-lockfile
|
||||
yarn install
|
||||
```
|
||||
|
||||
Then, configure the environment variables. Create a file named `.env.local` in the current directory and copy the contents from `.env.example`. Modify the values of these environment variables according to your requirements:
|
||||
@ -30,12 +28,16 @@ NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
|
||||
|
||||
# SENTRY
|
||||
NEXT_PUBLIC_SENTRY_DSN=
|
||||
|
||||
# optional
|
||||
NEXT_PUBLIC_SITE_ABOUT=
|
||||
NEXT_PUBLIC_MAINTENANCE_NOTICE=
|
||||
```
|
||||
|
||||
Finally, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
@ -48,17 +50,17 @@ You can start editing the file under folder `app`. The page auto-updates as you
|
||||
### Deploy on server
|
||||
First, build the app for production:
|
||||
```bash
|
||||
npm run build
|
||||
yarn run build
|
||||
```
|
||||
|
||||
Then, start the server:
|
||||
```bash
|
||||
npm run start
|
||||
yarn run start
|
||||
```
|
||||
|
||||
If you want to customize the host and port:
|
||||
```bash
|
||||
npm run start --port=3001 --host=0.0.0.0
|
||||
yarn run start --port=3001 --host=0.0.0.0
|
||||
```
|
||||
|
||||
## Lint Code
|
||||
|
@ -2,6 +2,7 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Github } from '@/app/components/base/icons/src/public/common'
|
||||
import type { GithubRepo } from '@/models/common'
|
||||
import { env } from '@/env'
|
||||
|
||||
const getStar = async () => {
|
||||
const res = await fetch('https://api.github.com/repos/langgenius/dify')
|
||||
@ -18,10 +19,10 @@ const GithubStar = () => {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
if (process.env.NODE_ENV === 'development')
|
||||
if (env.NODE_ENV === 'development')
|
||||
return
|
||||
|
||||
await setGithubRepo(await getStar())
|
||||
setGithubRepo(await getStar())
|
||||
setIsFetched(true)
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -2,14 +2,15 @@
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import { env } from '@/env'
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV === 'development'
|
||||
const isDevelopment = env.NEXT_PUBLIC_NODE_ENV === 'DEVELOPMENT'
|
||||
|
||||
const SentryInit = ({
|
||||
children,
|
||||
}: { children: React.ReactElement }) => {
|
||||
useEffect(() => {
|
||||
const SENTRY_DSN = document?.body?.getAttribute('data-public-sentry-dsn')
|
||||
const SENTRY_DSN = env.NEXT_PUBLIC_SENTRY_DSN
|
||||
if (!isDevelopment && SENTRY_DSN) {
|
||||
Sentry.init({
|
||||
dsn: SENTRY_DSN,
|
||||
|
@ -6,6 +6,7 @@ import Topbar from './components/base/topbar'
|
||||
import { getLocaleOnServer } from '@/i18n/server'
|
||||
import './styles/globals.css'
|
||||
import './styles/markdown.scss'
|
||||
import { env } from '@/env'
|
||||
|
||||
export const metadata = {
|
||||
title: 'Dify',
|
||||
@ -36,12 +37,8 @@ const LocaleLayout = ({
|
||||
</head>
|
||||
<body
|
||||
className="h-full select-auto"
|
||||
data-api-prefix={process.env.NEXT_PUBLIC_API_PREFIX}
|
||||
data-pubic-api-prefix={process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX}
|
||||
data-public-edition={process.env.NEXT_PUBLIC_EDITION}
|
||||
data-public-sentry-dsn={process.env.NEXT_PUBLIC_SENTRY_DSN}
|
||||
data-public-maintenance-notice={process.env.NEXT_PUBLIC_MAINTENANCE_NOTICE}
|
||||
data-public-site-about={process.env.NEXT_PUBLIC_SITE_ABOUT}
|
||||
data-public-maintenance-notice={env.NEXT_PUBLIC_MAINTENANCE_NOTICE}
|
||||
data-public-site-about={env.NEXT_PUBLIC_SITE_ABOUT}
|
||||
>
|
||||
<Topbar/>
|
||||
<BrowerInitor>
|
||||
|
@ -1,37 +1,14 @@
|
||||
/* eslint-disable import/no-mutable-exports */
|
||||
import { InputVarType } from '@/app/components/workflow/types'
|
||||
import { AgentStrategy } from '@/types/app'
|
||||
import { PromptRole } from '@/models/debug'
|
||||
import { env } from '@/env'
|
||||
|
||||
export let apiPrefix = ''
|
||||
export let publicApiPrefix = ''
|
||||
// NEXT_PUBLIC_API_PREFIX=/console/api NEXT_PUBLIC_PUBLIC_API_PREFIX=/api yarn run start
|
||||
|
||||
// NEXT_PUBLIC_API_PREFIX=/console/api NEXT_PUBLIC_PUBLIC_API_PREFIX=/api npm run start
|
||||
if (process.env.NEXT_PUBLIC_API_PREFIX && process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX) {
|
||||
apiPrefix = process.env.NEXT_PUBLIC_API_PREFIX
|
||||
publicApiPrefix = process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX
|
||||
}
|
||||
else if (
|
||||
globalThis.document?.body?.getAttribute('data-api-prefix')
|
||||
&& globalThis.document?.body?.getAttribute('data-pubic-api-prefix')
|
||||
) {
|
||||
// Not bulild can not get env from process.env.NEXT_PUBLIC_ in browser https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser
|
||||
apiPrefix = globalThis.document.body.getAttribute('data-api-prefix') as string
|
||||
publicApiPrefix = globalThis.document.body.getAttribute('data-pubic-api-prefix') as string
|
||||
}
|
||||
else {
|
||||
// const domainParts = globalThis.location?.host?.split('.');
|
||||
// in production env, the host is dify.app . In other env, the host is [dev].dify.app
|
||||
// const env = domainParts.length === 2 ? 'ai' : domainParts?.[0];
|
||||
apiPrefix = 'http://localhost:5001/console/api'
|
||||
publicApiPrefix = 'http://localhost:5001/api' // avoid browser private mode api cross origin
|
||||
}
|
||||
export const API_PREFIX: string = env.NEXT_PUBLIC_API_PREFIX
|
||||
export const PUBLIC_API_PREFIX: string = env.NEXT_PUBLIC_PUBLIC_API_PREFIX
|
||||
|
||||
export const API_PREFIX: string = apiPrefix
|
||||
export const PUBLIC_API_PREFIX: string = publicApiPrefix
|
||||
|
||||
const EDITION = process.env.NEXT_PUBLIC_EDITION || globalThis.document?.body?.getAttribute('data-public-edition') || 'SELF_HOSTED'
|
||||
export const IS_CE_EDITION = EDITION === 'SELF_HOSTED'
|
||||
export const IS_CE_EDITION = env.NEXT_PUBLIC_EDITION === 'SELF_HOSTED'
|
||||
|
||||
export const TONE_LIST = [
|
||||
{
|
||||
@ -156,28 +133,28 @@ export const DEFAULT_AGENT_SETTING = {
|
||||
}
|
||||
|
||||
export const DEFAULT_AGENT_PROMPT = {
|
||||
chat: `Respond to the human as helpfully and accurately as possible.
|
||||
chat: `Respond to the human as helpfully and accurately as possible.
|
||||
|
||||
{{instruction}}
|
||||
|
||||
|
||||
You have access to the following tools:
|
||||
|
||||
|
||||
{{tools}}
|
||||
|
||||
|
||||
Use a json blob to specify a tool by providing an {{TOOL_NAME_KEY}} key (tool name) and an {{ACTION_INPUT_KEY}} key (tool input).
|
||||
Valid "{{TOOL_NAME_KEY}}" values: "Final Answer" or {{tool_names}}
|
||||
|
||||
|
||||
Provide only ONE action per $JSON_BLOB, as shown:
|
||||
|
||||
|
||||
\`\`\`
|
||||
{
|
||||
"{{TOOL_NAME_KEY}}": $TOOL_NAME,
|
||||
"{{ACTION_INPUT_KEY}}": $ACTION_INPUT
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
|
||||
Follow this format:
|
||||
|
||||
|
||||
Question: input question to answer
|
||||
Thought: consider previous and subsequent steps
|
||||
Action:
|
||||
@ -194,10 +171,10 @@ export const DEFAULT_AGENT_PROMPT = {
|
||||
"{{ACTION_INPUT_KEY}}": "Final response to human"
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
|
||||
Begin! Reminder to ALWAYS respond with a valid json blob of a single action. Use tools if necessary. Respond directly if appropriate. Format is Action:\`\`\`$JSON_BLOB\`\`\`then Observation:.`,
|
||||
completion: `
|
||||
Respond to the human as helpfully and accurately as possible.
|
||||
Respond to the human as helpfully and accurately as possible.
|
||||
|
||||
{{instruction}}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import { fetchCurrentWorkspace, fetchLanggeniusVersion, fetchUserProfile } from
|
||||
import type { App } from '@/types/app'
|
||||
import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
|
||||
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
|
||||
import { env } from '@/env'
|
||||
|
||||
export type AppContextValue = {
|
||||
apps: App[]
|
||||
@ -91,7 +92,7 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
||||
const result = await userProfileResponse.json()
|
||||
setUserProfile(result)
|
||||
const current_version = userProfileResponse.headers.get('x-version')
|
||||
const current_env = process.env.NODE_ENV === 'development' ? 'DEVELOPMENT' : userProfileResponse.headers.get('x-env')
|
||||
const current_env = env.NODE_ENV === 'development' ? 'DEVELOPMENT' : userProfileResponse.headers.get('x-env')
|
||||
const versionData = await fetchLanggeniusVersion({ url: '/version', params: { current_version } })
|
||||
setLangeniusVersionInfo({ ...versionData, current_version, latest_version: versionData.version, current_env })
|
||||
}
|
||||
|
61
web/env.ts
Normal file
61
web/env.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { createEnv } from '@t3-oss/env-nextjs'
|
||||
import { z } from 'zod'
|
||||
import { upperCase } from 'lodash-es'
|
||||
|
||||
export const env = createEnv({
|
||||
/**
|
||||
* Specify your server-side environment variables schema here. This way you can ensure the app
|
||||
* isn't built with invalid env vars.
|
||||
*/
|
||||
server: {
|
||||
NODE_ENV: z
|
||||
.enum(['DEVELOPMENT', 'PRODUCTION'])
|
||||
.default('DEVELOPMENT'),
|
||||
},
|
||||
|
||||
/**
|
||||
* Specify your client-side environment variables schema here. This way you can ensure the app
|
||||
* isn't built with invalid env vars. To expose them to the client, prefix them with
|
||||
* `NEXT_PUBLIC_`.
|
||||
*/
|
||||
client: {
|
||||
NEXT_PUBLIC_DEPLOY_ENV: z
|
||||
.enum(['DEVELOPMENT', 'PRODUCTION']),
|
||||
NEXT_PUBLIC_EDITION: z
|
||||
.enum(['SELF_HOSTED']),
|
||||
NEXT_PUBLIC_API_PREFIX: z.string().url(),
|
||||
NEXT_PUBLIC_PUBLIC_API_PREFIX: z.string().url(),
|
||||
NEXT_PUBLIC_SENTRY_DSN: z.string().url().url().optional(),
|
||||
NEXT_PUBLIC_NODE_ENV: z
|
||||
.enum(['DEVELOPMENT', 'PRODUCTION'])
|
||||
.default('DEVELOPMENT'),
|
||||
NEXT_PUBLIC_MAINTENANCE_NOTICE: z.boolean().optional(),
|
||||
NEXT_PUBLIC_SITE_ABOUT: z.boolean().optional(),
|
||||
},
|
||||
|
||||
/**
|
||||
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
|
||||
* middlewares) or client-side so we need to destruct manually.
|
||||
*/
|
||||
runtimeEnv: {
|
||||
NODE_ENV: upperCase(process.env.NODE_ENV),
|
||||
NEXT_PUBLIC_NODE_ENV: upperCase(process.env.NODE_ENV),
|
||||
NEXT_PUBLIC_DEPLOY_ENV: process.env.NEXT_PUBLIC_DEPLOY_ENV,
|
||||
NEXT_PUBLIC_EDITION: process.env.NEXT_PUBLIC_EDITION,
|
||||
NEXT_PUBLIC_API_PREFIX: process.env.NEXT_PUBLIC_API_PREFIX,
|
||||
NEXT_PUBLIC_PUBLIC_API_PREFIX: process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX,
|
||||
NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
NEXT_PUBLIC_MAINTENANCE_NOTICE: process.env.NEXT_PUBLIC_MAINTENANCE_NOTICE,
|
||||
NEXT_PUBLIC_SITE_ABOUT: process.env.NEXT_PUBLIC_MAINTENANCE_NOTICE,
|
||||
},
|
||||
/**
|
||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
|
||||
* useful for Docker builds.
|
||||
*/
|
||||
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
||||
/**
|
||||
* Makes it so that empty strings are treated as undefined. `SOME_VAR: z.string()` and
|
||||
* `SOME_VAR=''` will throw an error.
|
||||
*/
|
||||
emptyStringAsUndefined: true,
|
||||
})
|
@ -1,5 +1,15 @@
|
||||
const { codeInspectorPlugin } = require('code-inspector-plugin')
|
||||
const withMDX = require('@next/mdx')({
|
||||
/**
|
||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
|
||||
* for Docker builds.
|
||||
*/
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { codeInspectorPlugin } from 'code-inspector-plugin'
|
||||
import mdx from '@next/mdx'
|
||||
import createJiti from 'jiti'
|
||||
const jiti = createJiti(fileURLToPath(import.meta.url))
|
||||
jiti('./env.ts')
|
||||
|
||||
const withMDX = mdx({
|
||||
extension: /\.mdx?$/,
|
||||
options: {
|
||||
// If you use remark-gfm, you'll need to use next.config.mjs
|
||||
@ -46,4 +56,4 @@ const nextConfig = {
|
||||
output: 'standalone',
|
||||
}
|
||||
|
||||
module.exports = withMDX(nextConfig)
|
||||
export default withMDX(nextConfig)
|
@ -9,7 +9,7 @@
|
||||
"lint": "next lint",
|
||||
"fix": "next lint --fix",
|
||||
"eslint-fix": "eslint --fix",
|
||||
"prepare": "cd ../ && node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky install ./web/.husky",
|
||||
"prepare": "npx only-allow yarn && cd ../ && node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky install ./web/.husky",
|
||||
"gen-icons": "node ./app/components/base/icons/script.js",
|
||||
"uglify-embed": "node ./bin/uglify-embed",
|
||||
"check-i18n": "node ./i18n/script.js"
|
||||
@ -28,6 +28,7 @@
|
||||
"@next/mdx": "^14.0.4",
|
||||
"@sentry/react": "^7.54.0",
|
||||
"@sentry/utils": "^7.54.0",
|
||||
"@t3-oss/env-nextjs": "^0.10.1",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"ahooks": "^3.7.5",
|
||||
@ -84,6 +85,7 @@
|
||||
"swr": "^2.1.0",
|
||||
"use-context-selector": "^1.4.1",
|
||||
"uuid": "^9.0.1",
|
||||
"zod": "^3.23.6",
|
||||
"zustand": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -112,11 +114,12 @@
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-next": "^14.0.4",
|
||||
"husky": "^8.0.3",
|
||||
"jiti": "^1.21.0",
|
||||
"lint-staged": "^13.2.2",
|
||||
"postcss": "^8.4.31",
|
||||
"sass": "^1.61.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "4.9.5",
|
||||
"typescript": "^5.4.5",
|
||||
"uglify-js": "^3.17.4"
|
||||
},
|
||||
"lint-staged": {
|
||||
@ -129,5 +132,6 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@4.2.1"
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
@ -34,7 +34,7 @@
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
"app/components/develop/Prose.jsx"
|
||||
"app/components/develop/Prose.jsx",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
|
17501
web/yarn.lock
17501
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user