Compare commits
No commits in common. "dynamicIPv2" and "main" have entirely different histories.
dynamicIPv
...
main
43
.env.local
43
.env.local
|
|
@ -1,43 +0,0 @@
|
||||||
# Supabase Public
|
|
||||||
NEXT_PUBLIC_SUPABASE_URL=http://67.223.119.33:8000
|
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlLWRlbW8iLCJleHAiOjIwNjI5MjU1NjUsImlhdCI6MTc0NzU2NTU2NX0.l08_BczmnaDNCur8AK0Z-X6MZOHNNRWh7ij5aN6sLgU
|
|
||||||
|
|
||||||
# Supabase Private
|
|
||||||
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UtZGVtbyIsImV4cCI6MjA2MjkyNTU2NSwiaWF0IjoxNzQ3NTY1NTY1fQ.18Lxnd9JrkNyV9q38l_8oQB8pwtZK8JwpLwpH2b4JaA
|
|
||||||
|
|
||||||
# Ollama
|
|
||||||
#NEXT_PUBLIC_OLLAMA_URL=http://localhost:11434
|
|
||||||
|
|
||||||
#sglang
|
|
||||||
NEXT_PUBLIC_OLLAMA_URL=http://183.36.35.42:30000
|
|
||||||
|
|
||||||
#NEXT_PUBLIC_OLLAMA_URL=http://127.0.0.1:8000
|
|
||||||
#NEXT_PUBLIC_OLLAMA_URL=http://127.0.0.1:23333
|
|
||||||
|
|
||||||
# API Keys (Optional: Entering an API key here overrides the API keys globally for all users.)
|
|
||||||
OPENAI_API_KEY=
|
|
||||||
ANTHROPIC_API_KEY=
|
|
||||||
GOOGLE_GEMINI_API_KEY=
|
|
||||||
MISTRAL_API_KEY=
|
|
||||||
GROQ_API_KEY=
|
|
||||||
PERPLEXITY_API_KEY=
|
|
||||||
OPENROUTER_API_KEY=
|
|
||||||
|
|
||||||
# OpenAI API Information
|
|
||||||
NEXT_PUBLIC_OPENAI_ORGANIZATION_ID=
|
|
||||||
|
|
||||||
# Azure API Information
|
|
||||||
AZURE_OPENAI_API_KEY=
|
|
||||||
AZURE_OPENAI_ENDPOINT=
|
|
||||||
AZURE_GPT_35_TURBO_NAME=
|
|
||||||
AZURE_GPT_45_VISION_NAME=
|
|
||||||
AZURE_GPT_45_TURBO_NAME=
|
|
||||||
AZURE_EMBEDDINGS_NAME=
|
|
||||||
|
|
||||||
# General Configuration (Optional)
|
|
||||||
EMAIL_DOMAIN_WHITELIST=
|
|
||||||
EMAIL_WHITELIST=
|
|
||||||
|
|
||||||
# File size limit for uploads in bytes
|
|
||||||
NEXT_PUBLIC_USER_FILE_SIZE_LIMIT=104857600
|
|
||||||
~
|
|
||||||
41
b.sh
41
b.sh
|
|
@ -1,41 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 设置变量
|
|
||||||
REPO_NAME="chatdesk-ui"
|
|
||||||
TAG="1.0.0"
|
|
||||||
IMAGE_NAME="chatdesk-ui:$TAG"
|
|
||||||
CONTAINER_NAME="chatdesk-ui"
|
|
||||||
|
|
||||||
# 停止并删除旧的容器实例
|
|
||||||
echo "Stopping and removing any running containers of $REPO_NAME:$TAG..."
|
|
||||||
docker ps -q --filter "ancestor=$REPO_NAME:$TAG" | xargs -r docker stop
|
|
||||||
docker ps -a -q --filter "ancestor=$REPO_NAME:$TAG" | xargs -r docker rm
|
|
||||||
|
|
||||||
# 删除镜像
|
|
||||||
echo "Removing image $REPO_NAME:$TAG..."
|
|
||||||
docker rmi $IMAGE_NAME
|
|
||||||
|
|
||||||
# 执行 git pull 获取最新代码
|
|
||||||
echo "Pulling the latest code from the repository..."
|
|
||||||
git pull
|
|
||||||
|
|
||||||
# 重建 Docker 镜像
|
|
||||||
echo "Building the Docker image $IMAGE_NAME..."
|
|
||||||
docker build \
|
|
||||||
--build-arg http_proxy=http://127.0.0.1:7890 \
|
|
||||||
--build-arg https_proxy=http://127.0.0.1:7890 \
|
|
||||||
--network=host \
|
|
||||||
--no-cache \
|
|
||||||
-t $IMAGE_NAME .
|
|
||||||
|
|
||||||
# 运行新镜像
|
|
||||||
echo "Running the container with the new image..."
|
|
||||||
docker run -d \
|
|
||||||
-e SUPABASE_URL=http://67.223.119.33:8000 \
|
|
||||||
-p 3030:3030 \
|
|
||||||
-p 8000:8000 \
|
|
||||||
--name $CONTAINER_NAME \
|
|
||||||
$IMAGE_NAME
|
|
||||||
|
|
||||||
echo "Deployment complete."
|
|
||||||
|
|
||||||
|
|
@ -33,4 +33,4 @@ EMAIL_DOMAIN_WHITELIST=
|
||||||
EMAIL_WHITELIST=
|
EMAIL_WHITELIST=
|
||||||
|
|
||||||
# File size limit for uploads in bytes
|
# File size limit for uploads in bytes
|
||||||
NEXT_PUBLIC_USER_FILE_SIZE_LIMIT=104857600
|
NEXT_PUBLIC_USER_FILE_SIZE_LIMIT=10485760
|
||||||
|
|
@ -3,14 +3,16 @@ import { GlobalState } from "@/components/utility/global-state"
|
||||||
import { Providers } from "@/components/utility/providers"
|
import { Providers } from "@/components/utility/providers"
|
||||||
import TranslationsProvider from "@/components/utility/translations-provider"
|
import TranslationsProvider from "@/components/utility/translations-provider"
|
||||||
import initTranslations from "@/lib/i18n"
|
import initTranslations from "@/lib/i18n"
|
||||||
|
import { Database } from "@/supabase/types"
|
||||||
import { getSupabaseServerClient } from "@/lib/supabase/server"
|
import { getSupabaseServerClient } from "@/lib/supabase/server"
|
||||||
import { Metadata, Viewport } from "next"
|
import { Metadata, Viewport } from "next"
|
||||||
import { Inter } from "next/font/google"
|
import { Inter } from "next/font/google"
|
||||||
import { cookies } from "next/headers"
|
import { cookies } from "next/headers"
|
||||||
import { ReactNode } from "react"
|
import { ReactNode } from "react"
|
||||||
import "./globals.css"
|
import "./globals.css"
|
||||||
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
import Script from "next/script"
|
||||||
import { Suspense } from "react"
|
import { Suspense } from "react"
|
||||||
import { RuntimeEnvScript } from "@/components/utility/runtime-env-provider"
|
|
||||||
|
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] })
|
const inter = Inter({ subsets: ["latin"] })
|
||||||
|
|
@ -26,6 +28,26 @@ interface RootLayoutProps {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 新增的 `getValidSupabaseUrl` 函数,带有超时机制和错误处理
|
||||||
|
async function getValidSupabaseUrl(): Promise<string> {
|
||||||
|
let url = getRuntimeEnv("SUPABASE_URL");
|
||||||
|
const timeout = Date.now() + 30000; // 设置最大等待时间为30秒
|
||||||
|
|
||||||
|
while (!url || !url.includes(":")) { // 检查是否包含合法的 IP 和端口
|
||||||
|
if (Date.now() > timeout) {
|
||||||
|
throw new Error("获取有效的 Supabase URL 超时");
|
||||||
|
}
|
||||||
|
console.log("等待有效的 Supabase URL...");
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000)); // 每1秒检查一次
|
||||||
|
url = getRuntimeEnv("SUPABASE_URL");
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params: { locale }
|
params: { locale }
|
||||||
}: {
|
}: {
|
||||||
|
|
@ -91,6 +113,16 @@ export default async function RootLayout({
|
||||||
console.log(`🍪 Cookie: ${cookie.name} = ${cookie.value}`);
|
console.log(`🍪 Cookie: ${cookie.name} = ${cookie.value}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let supabaseUrl = "";
|
||||||
|
try {
|
||||||
|
// 等待直到获取到有效的 Supabase URL
|
||||||
|
supabaseUrl = await getValidSupabaseUrl();
|
||||||
|
//console.log("==========>获取到有效的 Supabase URL: ", supabaseUrl);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Supabase URL 获取失败:", error);
|
||||||
|
return <div>Failed to fetch Supabase configuration, please try again later.</div>; // 出现错误时返回一个友好的提示
|
||||||
|
}
|
||||||
|
|
||||||
const supabase = getSupabaseServerClient()
|
const supabase = getSupabaseServerClient()
|
||||||
const { data, error } = await supabase.auth.getSession();
|
const { data, error } = await supabase.auth.getSession();
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
@ -105,7 +137,10 @@ export default async function RootLayout({
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<RuntimeEnvScript />
|
<Script
|
||||||
|
src="/env.js"
|
||||||
|
strategy="beforeInteractive" // 确保在 React 启动之前加载
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body className={inter.className}>
|
<body className={inter.className}>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { get } from "@vercel/edge-config"
|
||||||
import { Metadata } from "next"
|
import { Metadata } from "next"
|
||||||
import { cookies, headers } from "next/headers"
|
import { cookies, headers } from "next/headers"
|
||||||
import { redirect } from "next/navigation"
|
import { redirect } from "next/navigation"
|
||||||
import { getRuntimeEnv } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
import { PostgrestError } from '@supabase/supabase-js';
|
import { PostgrestError } from '@supabase/supabase-js';
|
||||||
|
|
||||||
import initTranslations from "@/lib/i18n";
|
import initTranslations from "@/lib/i18n";
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { checkApiKey, getServerProfile } from "@/lib/server/server-chat-helpers"
|
||||||
import { ServerRuntime } from "next"
|
import { ServerRuntime } from "next"
|
||||||
import OpenAI from "openai"
|
import OpenAI from "openai"
|
||||||
|
|
||||||
//export const runtime: ServerRuntime = "edge"
|
export const runtime: ServerRuntime = "edge"
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@ import { OpenAIStream, StreamingTextResponse } from "ai"
|
||||||
import { ServerRuntime } from "next"
|
import { ServerRuntime } from "next"
|
||||||
import OpenAI from "openai"
|
import OpenAI from "openai"
|
||||||
import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions.mjs"
|
import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions.mjs"
|
||||||
import { getRuntimeEnvForRouterAPI } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
|
|
||||||
//export const runtime: ServerRuntime = "edge"
|
export const runtime: ServerRuntime = "edge"
|
||||||
export const runtime = "nodejs"
|
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
const json = await request.json()
|
const json = await request.json()
|
||||||
|
|
@ -21,10 +20,10 @@ export async function POST(request: Request) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const supabaseAdmin = createClient<Database>(
|
const supabaseAdmin = createClient<Database>(
|
||||||
getRuntimeEnvForRouterAPI("SUPABASE_URL") ?? "http://localhost:8000",
|
getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||||
)
|
)
|
||||||
|
|
||||||
const { data: customModel, error } = await supabaseAdmin
|
const { data: customModel, error } = await supabaseAdmin
|
||||||
.from("models")
|
.from("models")
|
||||||
.select("*")
|
.select("*")
|
||||||
|
|
@ -32,7 +31,6 @@ export async function POST(request: Request) {
|
||||||
.single()
|
.single()
|
||||||
|
|
||||||
if (!customModel) {
|
if (!customModel) {
|
||||||
console.error("❌ No custom model found:", error)
|
|
||||||
throw new Error(error.message)
|
throw new Error(error.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { ServerRuntime } from "next"
|
||||||
import OpenAI from "openai"
|
import OpenAI from "openai"
|
||||||
import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions.mjs"
|
import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions.mjs"
|
||||||
|
|
||||||
//export const runtime: ServerRuntime = "edge"
|
export const runtime: ServerRuntime = "edge"
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
const json = await request.json()
|
const json = await request.json()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { ServerRuntime } from "next"
|
||||||
import OpenAI from "openai"
|
import OpenAI from "openai"
|
||||||
import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions.mjs"
|
import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions.mjs"
|
||||||
|
|
||||||
//export const runtime: ServerRuntime = "edge"
|
export const runtime: ServerRuntime = "edge"
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
const json = await request.json()
|
const json = await request.json()
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,9 @@ import { FileItemChunk } from "@/types"
|
||||||
import { createClient } from "@supabase/supabase-js"
|
import { createClient } from "@supabase/supabase-js"
|
||||||
import { NextResponse } from "next/server"
|
import { NextResponse } from "next/server"
|
||||||
import OpenAI from "openai"
|
import OpenAI from "openai"
|
||||||
import { getRuntimeEnvForRouterAPI } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
import { generateBgeM3Embedding } from "@/lib/generate-bgem3-embedding"
|
import { generateBgeM3Embedding } from "@/lib/generate-bgem3-embedding"
|
||||||
|
|
||||||
export const runtime = "nodejs"
|
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
const json = await req.json()
|
const json = await req.json()
|
||||||
const { text, fileId, embeddingsProvider, fileExtension } = json as {
|
const { text, fileId, embeddingsProvider, fileExtension } = json as {
|
||||||
|
|
@ -22,7 +20,7 @@ export async function POST(req: Request) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const supabaseAdmin = createClient<Database>(
|
const supabaseAdmin = createClient<Database>(
|
||||||
getRuntimeEnvForRouterAPI("SUPABASE_URL") ?? "http://localhost:8000",
|
getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,13 @@ import { FileItemChunk } from "@/types"
|
||||||
import { createClient } from "@supabase/supabase-js"
|
import { createClient } from "@supabase/supabase-js"
|
||||||
import { NextResponse } from "next/server"
|
import { NextResponse } from "next/server"
|
||||||
import OpenAI from "openai"
|
import OpenAI from "openai"
|
||||||
import { getRuntimeEnvForRouterAPI } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
export const runtime = "nodejs"
|
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const supabaseAdmin = createClient<Database>(
|
const supabaseAdmin = createClient<Database>(
|
||||||
getRuntimeEnvForRouterAPI("SUPABASE_URL") ?? "http://localhost:8000",
|
getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ import { checkApiKey, getServerProfile } from "@/lib/server/server-chat-helpers"
|
||||||
import { Database } from "@/supabase/types"
|
import { Database } from "@/supabase/types"
|
||||||
import { createClient } from "@supabase/supabase-js"
|
import { createClient } from "@supabase/supabase-js"
|
||||||
import OpenAI from "openai"
|
import OpenAI from "openai"
|
||||||
import { getRuntimeEnvForRouterAPI } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
export const runtime = "nodejs"
|
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
|
|
||||||
|
|
@ -24,12 +22,13 @@ export async function POST(request: Request) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const rawSupaUrl = getRuntimeEnvForRouterAPI("SUPABASE_URL") ?? "http://localhost:8000"
|
const rawSupaUrl = getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000"
|
||||||
const supaUrlObj = new URL(rawSupaUrl)
|
const supaUrlObj = new URL(rawSupaUrl)
|
||||||
supaUrlObj.port = "8000"
|
supaUrlObj.port = "8000"
|
||||||
|
|
||||||
const supabaseAdmin = createClient<Database>(
|
const supabaseAdmin = createClient<Database>(
|
||||||
supaUrlObj.origin,
|
supaUrlObj.origin,
|
||||||
|
// getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Database } from "@/supabase/types"
|
import { Database } from "@/supabase/types"
|
||||||
import { createClient } from "@supabase/supabase-js"
|
import { createClient } from "@supabase/supabase-js"
|
||||||
import { getRuntimeEnvForRouterAPI } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
export const runtime = "nodejs"
|
export const runtime = "edge"
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
const json = await request.json()
|
const json = await request.json()
|
||||||
|
|
@ -12,7 +12,7 @@ export async function POST(request: Request) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const supabaseAdmin = createClient<Database>(
|
const supabaseAdmin = createClient<Database>(
|
||||||
getRuntimeEnvForRouterAPI("SUPABASE_URL") ?? "http://localhost:8000",
|
getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import { Database } from "@/supabase/types"
|
import { Database } from "@/supabase/types"
|
||||||
import { createClient } from "@supabase/supabase-js"
|
import { createClient } from "@supabase/supabase-js"
|
||||||
import { getRuntimeEnvForRouterAPI } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
// export const runtime = "edge"
|
export const runtime = "edge"
|
||||||
export const runtime = "nodejs"
|
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
const json = await request.json()
|
const json = await request.json()
|
||||||
|
|
@ -13,7 +12,7 @@ export async function POST(request: Request) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const supabaseAdmin = createClient<Database>(
|
const supabaseAdmin = createClient<Database>(
|
||||||
getRuntimeEnvForRouterAPI("SUPABASE_URL") ?? "http://localhost:8000",
|
getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import {
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { v4 as uuidv4 } from "uuid"
|
import { v4 as uuidv4 } from "uuid"
|
||||||
import { getRuntimeEnv } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig"
|
||||||
|
|
||||||
|
|
||||||
type RetrievedFileItem = Tables<"file_items"> & {
|
type RetrievedFileItem = Tables<"file_items"> & {
|
||||||
|
|
|
||||||
|
|
@ -812,7 +812,7 @@ export const ProfileSettings: FC<ProfileSettingsProps> = ({}) => {
|
||||||
<div className="flex items-center space-x-1">
|
<div className="flex items-center space-x-1">
|
||||||
<ThemeSwitcher />
|
<ThemeSwitcher />
|
||||||
|
|
||||||
{/* <WithTooltip
|
<WithTooltip
|
||||||
display={
|
display={
|
||||||
<div>
|
<div>
|
||||||
{t("profile.downloadTooltip")}
|
{t("profile.downloadTooltip")}
|
||||||
|
|
@ -825,7 +825,7 @@ export const ProfileSettings: FC<ProfileSettingsProps> = ({}) => {
|
||||||
onClick={exportLocalStorageAsJSON}
|
onClick={exportLocalStorageAsJSON}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/> */}
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ml-auto space-x-2">
|
<div className="ml-auto space-x-2">
|
||||||
|
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
// // app/_runtime-env-provider.tsx ← 文件放 app 根,保证是 Server 组件
|
|
||||||
// import { headers } from "next/headers" // ① 仅在服务器端可调用
|
|
||||||
// import { useServerInsertedHTML } from "next/navigation" // ② 往最终 HTML 插入标签
|
|
||||||
// import React from "react"
|
|
||||||
|
|
||||||
// // ------------------- 带全链路调试日志的版本 -------------------
|
|
||||||
// export function RuntimeEnvProvider({ children }: { children: React.ReactNode }) {
|
|
||||||
// /* ──────────────── 1. 解析协议 ──────────────── */
|
|
||||||
// const h = headers() // <-- Node 边界:读取当前请求头
|
|
||||||
// console.log("[RuntimeEnv] Raw headers:", Object.fromEntries(h.entries()))
|
|
||||||
|
|
||||||
// const proto =
|
|
||||||
// h.get("x-forwarded-proto") ?? // 走 Nginx / 反代时最可靠
|
|
||||||
// (h.get("host")?.includes(":443") ? "https" : "http")// 没有反代时根据端口猜
|
|
||||||
// console.log("[RuntimeEnv] Resolved protocol:", proto)
|
|
||||||
|
|
||||||
// /* ──────────────── 2. 解析主机名 ──────────────── */
|
|
||||||
// const rawHost = h.get("x-forwarded-host") ?? h.get("host")!
|
|
||||||
// console.log("[RuntimeEnv] rawHost :", rawHost)
|
|
||||||
|
|
||||||
// // 多层反代时 x-forwarded-host 可能是 "a.com, b.com"
|
|
||||||
// // host 可能附带端口,须砍掉
|
|
||||||
// const hostname = rawHost.split(",")[0].split(":")[0].trim()
|
|
||||||
// console.log("[RuntimeEnv] hostname :", hostname)
|
|
||||||
|
|
||||||
// /* ──────────────── 3. 拼最终 URL (端口固定 8000) ──────────────── */
|
|
||||||
// const supabaseUrl = `${proto}://${hostname}:8000`
|
|
||||||
// console.log("[RuntimeEnv] supabaseUrl to inject:", supabaseUrl)
|
|
||||||
|
|
||||||
// /* ──────────────── 4. 把脚本塞进 HTML ──────────────── */
|
|
||||||
// useServerInsertedHTML(() => {
|
|
||||||
// // 这一段在 React 把 HTML flush 给客户端之前执行一次
|
|
||||||
// console.log("[RuntimeEnv] <script> tag inserted into HTML")
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <script
|
|
||||||
// // 行内脚本:window.RUNTIME_ENV.SUPABASE_URL = "<url>"
|
|
||||||
// dangerouslySetInnerHTML={{
|
|
||||||
// __html: `window.RUNTIME_ENV = { SUPABASE_URL: ${JSON.stringify(
|
|
||||||
// supabaseUrl,
|
|
||||||
// )} };`,
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// )
|
|
||||||
// })
|
|
||||||
|
|
||||||
// /* ──────────────── 5. 渲染子节点 ──────────────── */
|
|
||||||
// return <>{children}</> // Provider 本身不渲染 UI,只负责注入脚本
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// app/_runtime-env-provider.tsx (务必保持在 app 目录 ➜ Server 组件)
|
|
||||||
// import { headers } from "next/headers"
|
|
||||||
// import { useServerInsertedHTML } from "next/navigation"
|
|
||||||
// import React from "react"
|
|
||||||
|
|
||||||
// export function RuntimeEnvProvider({ children }: { children: React.ReactNode }) {
|
|
||||||
// /* 解析请求头 */
|
|
||||||
// const h = headers()
|
|
||||||
// console.log("[RuntimeEnv] Raw headers:", Object.fromEntries(h.entries()))
|
|
||||||
|
|
||||||
// const proto =
|
|
||||||
// h.get("x-forwarded-proto") ??
|
|
||||||
// (h.get("host")?.includes(":443") ? "https" : "http")
|
|
||||||
// console.log("[RuntimeEnv] Resolved protocol:", proto)
|
|
||||||
|
|
||||||
// const rawHost = h.get("x-forwarded-host") ?? h.get("host")!
|
|
||||||
// console.log("[RuntimeEnv] rawHost :", rawHost)
|
|
||||||
|
|
||||||
// const hostname = rawHost.split(",")[0].split(":")[0].trim()
|
|
||||||
// console.log("[RuntimeEnv] hostname :", hostname)
|
|
||||||
|
|
||||||
// const supabaseUrl = `${proto}://${hostname}:8000`
|
|
||||||
// console.log("[RuntimeEnv] supabaseUrl to inject:", supabaseUrl)
|
|
||||||
|
|
||||||
// /* 把脚本塞进 HTML(这一行如果不打印,说明没执行) */
|
|
||||||
// useServerInsertedHTML(() => {
|
|
||||||
// console.log("[RuntimeEnv] <script> tag inserted into HTML")
|
|
||||||
// return (
|
|
||||||
// <script
|
|
||||||
// id="runtime-env" /* 方便 View-Source 检查 */
|
|
||||||
// dangerouslySetInnerHTML={{
|
|
||||||
// __html: `window.RUNTIME_ENV = { SUPABASE_URL: ${JSON.stringify(
|
|
||||||
// supabaseUrl,
|
|
||||||
// )} }; console.log('[Client] window.RUNTIME_ENV =', window.RUNTIME_ENV);`,
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// )
|
|
||||||
// })
|
|
||||||
|
|
||||||
// return <>{children}</>
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// components/utility/runtime-env-script.tsx
|
|
||||||
import { headers } from "next/headers"
|
|
||||||
|
|
||||||
export function RuntimeEnvScript() {
|
|
||||||
const h = headers()
|
|
||||||
|
|
||||||
const proto = h.get("x-forwarded-proto") ?? (h.get("host")?.includes(":443") ? "https" : "http")
|
|
||||||
const rawHost = h.get("x-forwarded-host") ?? h.get("host")!
|
|
||||||
const hostname = rawHost.split(",")[0].split(":")[0].trim()
|
|
||||||
|
|
||||||
const supabaseUrl = `${proto}://${hostname}:8000`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<script
|
|
||||||
id="runtime-env"
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: `window.RUNTIME_ENV = { SUPABASE_URL: ${JSON.stringify(supabaseUrl)} };`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -9,17 +9,13 @@ export const uploadFile = async (
|
||||||
file_id: string
|
file_id: string
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
// const SIZE_LIMIT = parseInt(
|
const SIZE_LIMIT = parseInt(
|
||||||
// process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT || "104857600"
|
process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT || "10000000"
|
||||||
// )
|
)
|
||||||
const SIZE_LIMIT = Number(process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT) || 104857600;
|
|
||||||
|
|
||||||
console.log(`[uploadFile] 获取到参数: NEXT_PUBLIC_USER_FILE_SIZE_LIMIT=${process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT}, SIZE_LIMIT=${SIZE_LIMIT}, file.size=${file.size}`);
|
|
||||||
|
|
||||||
|
|
||||||
if (file.size > SIZE_LIMIT) {
|
if (file.size > SIZE_LIMIT) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`File must be less than ${Math.floor(SIZE_LIMIT / 1048576)}MB`
|
`File must be less than ${Math.floor(SIZE_LIMIT / 1000000)}MB`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
import { getServerRuntimeUrl } from "@/lib/lib/runtime-url"
|
import { getRuntimeEnv } from "@/lib/ipconfig"
|
||||||
|
|
||||||
export async function generateBgeM3Embedding(text: string): Promise<number[] | null> {
|
export async function generateBgeM3Embedding(text: string): Promise<number[] | null> {
|
||||||
try {
|
try {
|
||||||
// ✅ 使用服务端真实 URL(自动取协议/host)→ 端口强制为 8001
|
// 取 Supabase URL 或本地默认
|
||||||
const apiUrl = `${getServerRuntimeUrl("8001")}/v1/embeddings`
|
const supaUrl = getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000"
|
||||||
|
// 构造 Embedding 服务地址:同 host + 8001 端口
|
||||||
|
const urlObj = new URL(supaUrl)
|
||||||
|
urlObj.port = "8001" // 强制改成 8001
|
||||||
|
const apiUrl = `${urlObj.origin}/v1/embeddings`
|
||||||
console.debug("......[generateBgeM3Embedding] apiUrl =", apiUrl)
|
console.debug("......[generateBgeM3Embedding] apiUrl =", apiUrl)
|
||||||
|
|
||||||
const response = await fetch(apiUrl, {
|
const response = await fetch(apiUrl, {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// lib/ipconfig.ts
|
||||||
|
// export function getRuntimeEnv(key: string): string | undefined {
|
||||||
|
// if (typeof window !== "undefined" && typeof window.RUNTIME_ENV !== "undefined") {
|
||||||
|
// return window.RUNTIME_ENV[key];
|
||||||
|
// }
|
||||||
|
// return process.env[key];
|
||||||
|
// }
|
||||||
|
|
||||||
|
let _env: Record<string, string> | null = null
|
||||||
|
|
||||||
|
// 最大重试次数
|
||||||
|
const MAX_RETRIES = 5
|
||||||
|
// 每次重试的延时(毫秒)
|
||||||
|
const RETRY_DELAY = 1000
|
||||||
|
|
||||||
|
export function getRuntimeEnv(key: string): string | undefined {
|
||||||
|
//console.log("============>>Getting Supabase API URL.")
|
||||||
|
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
if (!_env && typeof window.RUNTIME_ENV !== "undefined") {
|
||||||
|
_env = window.RUNTIME_ENV
|
||||||
|
console.log("[browser-side] Retrieved API endpoint from window.RUNTIME_ENV:", _env)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试读取缓存的 _env
|
||||||
|
if (_env) {
|
||||||
|
console.log("[browser-side] Returning cached API from _env:", _env)
|
||||||
|
return _env[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[browser-side] No window.RUNTIME_ENV found in browser, _env=", _env)
|
||||||
|
|
||||||
|
let retries = 0
|
||||||
|
// 定义一个同步延时重试的函数
|
||||||
|
const tryGetEnvSync = () => {
|
||||||
|
if (typeof window.RUNTIME_ENV !== "undefined") {
|
||||||
|
_env = window.RUNTIME_ENV
|
||||||
|
console.log("[browser-side] Retrieved API endpoint from window.RUNTIME_ENV:", _env)
|
||||||
|
return _env[key] // 成功获取,返回结果
|
||||||
|
} else {
|
||||||
|
retries += 1
|
||||||
|
if (retries <= MAX_RETRIES) {
|
||||||
|
console.log(`[browser-side] Retry ${retries}/${MAX_RETRIES} - Retrying in ${RETRY_DELAY}ms...`)
|
||||||
|
// 延时并重试
|
||||||
|
setTimeout(tryGetEnvSync, RETRY_DELAY)
|
||||||
|
} else {
|
||||||
|
console.log("[browser-side] Failed to retrieve window.RUNTIME_ENV after retries.")
|
||||||
|
return undefined // 重试次数耗尽,返回 undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tryGetEnvSync() // 调用同步重试方法
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务端始终动态读取 process.env
|
||||||
|
const val = process.env[key]
|
||||||
|
//console.log("[server-side] Falling back to process.env for key:", key, "value:", val)
|
||||||
|
return val // 服务端直接返回 process.env 的值
|
||||||
|
}
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
// lib/runtime-url.ts
|
|
||||||
import { headers } from "next/headers"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回服务端当前请求的 base url,支持自定义端口
|
|
||||||
* 示例: getServerRuntimeUrl("8001") => http://host:8001
|
|
||||||
*/
|
|
||||||
export function getServerRuntimeUrl(port = "8000"): string {
|
|
||||||
const h = headers()
|
|
||||||
const proto = h.get("x-forwarded-proto") ?? (h.get("host")?.includes(":443") ? "https" : "http")
|
|
||||||
const rawHost = h.get("x-forwarded-host") ?? h.get("host")!
|
|
||||||
const hostname = rawHost.split(",")[0].split(":")[0].trim()
|
|
||||||
return `${proto}://${hostname}:${port}`
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
// lib/runtime-env/client.ts
|
|
||||||
export function getRuntimeEnvCSR(key: string): string | undefined {
|
|
||||||
return (window as any).RUNTIME_ENV?.[key]
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
// lib/runtime-env/index.ts
|
|
||||||
export function getRuntimeEnv(key: string): string | undefined {
|
|
||||||
if (typeof window === "undefined") {
|
|
||||||
const { getRuntimeEnvSSR } = require("./server")
|
|
||||||
return getRuntimeEnvSSR(key)
|
|
||||||
} else {
|
|
||||||
const { getRuntimeEnvCSR } = require("./client")
|
|
||||||
return getRuntimeEnvCSR(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRuntimeEnvForRouterAPI(key: string): string | undefined {
|
|
||||||
return process.env[key]
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
// lib/runtime-env/get-runtime-env-server.ts
|
|
||||||
|
|
||||||
export async function loadSupabaseUrl(): Promise<string | undefined> {
|
|
||||||
const { headers } = await import("next/headers")
|
|
||||||
const h = headers()
|
|
||||||
|
|
||||||
const proto = h.get("x-forwarded-proto") ?? (h.get("host")?.includes(":443") ? "https" : "http")
|
|
||||||
const rawHost = h.get("x-forwarded-host") ?? h.get("host")!
|
|
||||||
const hostname = rawHost.split(",")[0].split(":")[0].trim()
|
|
||||||
|
|
||||||
return `${proto}://${hostname}:8000`
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { Database, Tables } from "@/supabase/types"
|
import { Database, Tables } from "@/supabase/types"
|
||||||
import { VALID_ENV_KEYS } from "@/types/valid-keys"
|
import { VALID_ENV_KEYS } from "@/types/valid-keys"
|
||||||
|
//import { createServerClient } from "@supabase/ssr"
|
||||||
import { getSupabaseServerClient } from "@/lib/supabase/server"
|
import { getSupabaseServerClient } from "@/lib/supabase/server"
|
||||||
import { cookies } from "next/headers"
|
import { cookies } from "next/headers"
|
||||||
import { getRuntimeEnv } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
export async function getServerProfile() {
|
export async function getServerProfile() {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,91 @@
|
||||||
|
// import { createBrowserClient } from "@supabase/ssr"
|
||||||
|
// import { getRuntimeEnv } from "@/lib/ipconfig"
|
||||||
|
// import { Database } from "@/supabase/types"
|
||||||
|
|
||||||
|
// export const supabase = createBrowserClient<Database>(
|
||||||
|
// getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
|
// process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||||
|
// )
|
||||||
|
|
||||||
|
|
||||||
|
// // lib/supabase/browser-client.ts
|
||||||
|
// import { createBrowserClient } from "@supabase/ssr"
|
||||||
|
// import { getRuntimeEnv } from "@/lib/ipconfig"
|
||||||
|
// import { Database } from "@/supabase/types"
|
||||||
|
|
||||||
|
// // 动态获取 URL,防止静态打包成 localhost:8000
|
||||||
|
// let supabaseUrl = getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000"
|
||||||
|
|
||||||
|
// // 如果 URL 不是 http://localhost:8000 且不为 undefined,则存储到 localStorage
|
||||||
|
// if (supabaseUrl !== "http://localhost:8000" && supabaseUrl !== undefined) {
|
||||||
|
// localStorage.setItem("supabaseUrl", supabaseUrl)
|
||||||
|
// } else {
|
||||||
|
// // 如果是 http://localhost:8000 或者 undefined,则从 localStorage 获取
|
||||||
|
// const storedUrl = localStorage.getItem("supabaseUrl")
|
||||||
|
// if (storedUrl && storedUrl !== "http://localhost:8000") {
|
||||||
|
// supabaseUrl = storedUrl
|
||||||
|
// } else {
|
||||||
|
// supabaseUrl = "http://localhost:8000"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 打印获取的 URL
|
||||||
|
// console.log("=======>>Supabase URL:", supabaseUrl);
|
||||||
|
|
||||||
|
// // 编译时固定匿名 key(前端安全公开)
|
||||||
|
// const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||||
|
|
||||||
|
// // 导出单例,兼容所有调用旧代码方式
|
||||||
|
// export const supabase = createBrowserClient<Database>(
|
||||||
|
// supabaseUrl,
|
||||||
|
// supabaseAnonKey
|
||||||
|
// )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { createBrowserClient } from "@supabase/ssr"
|
import { createBrowserClient } from "@supabase/ssr"
|
||||||
|
import { getRuntimeEnv } from "@/lib/ipconfig"
|
||||||
import { Database } from "@/supabase/types"
|
import { Database } from "@/supabase/types"
|
||||||
|
|
||||||
let supabaseUrl = "http://localhost:8000"
|
// 动态获取 URL,防止静态打包成 localhost:8000
|
||||||
|
let supabaseUrl = getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000"
|
||||||
|
|
||||||
if (typeof window === "undefined") {
|
// 仅在浏览器端使用 localStorage
|
||||||
// ✅ SSR 时动态加载,不会触发 headers() 静态报错
|
if (typeof window !== "undefined") {
|
||||||
const load = async () => {
|
// 如果 URL 不是 http://localhost:8000 且不为 undefined,则存储到 localStorage
|
||||||
const { loadSupabaseUrl } = await import("@/lib/runtime-env/server")
|
if (supabaseUrl !== "http://localhost:8000" && supabaseUrl !== undefined) {
|
||||||
const url = await loadSupabaseUrl()
|
localStorage.setItem("supabaseUrl", supabaseUrl)
|
||||||
if (url) {
|
|
||||||
supabaseUrl = url
|
|
||||||
console.log("[SSR] SUPABASE_URL =", supabaseUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 注意:不能阻塞同步逻辑,只是设置变量
|
|
||||||
load()
|
|
||||||
} else {
|
|
||||||
const runtimeEnv = (window as any).RUNTIME_ENV
|
|
||||||
const envUrl = runtimeEnv?.SUPABASE_URL
|
|
||||||
|
|
||||||
if (envUrl && envUrl !== "http://localhost:8000") {
|
|
||||||
supabaseUrl = envUrl
|
|
||||||
localStorage.setItem("supabaseUrl", envUrl)
|
|
||||||
} else {
|
} else {
|
||||||
const stored = localStorage.getItem("supabaseUrl")
|
// 如果是 http://localhost:8000 或者 undefined,则从 localStorage 获取
|
||||||
if (stored && stored !== "http://localhost:8000") {
|
const storedUrl = localStorage.getItem("supabaseUrl")
|
||||||
supabaseUrl = stored
|
if (storedUrl && storedUrl !== "http://localhost:8000") {
|
||||||
|
supabaseUrl = storedUrl
|
||||||
|
} else {
|
||||||
|
supabaseUrl = "http://localhost:8000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
console.log("[CSR] SUPABASE_URL =", supabaseUrl)
|
// 如果在服务器端,使用默认或从环境变量获取的 URL
|
||||||
|
console.log("[server-side] Falling back to default supabaseUrl:", supabaseUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打印获取的 URL
|
||||||
|
console.log("=======>>Supabase URL:", supabaseUrl);
|
||||||
|
|
||||||
|
// 编译时固定匿名 key(前端安全公开)
|
||||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||||
|
|
||||||
|
// 导出单例,兼容所有调用旧代码方式
|
||||||
export const supabase = createBrowserClient<Database>(
|
export const supabase = createBrowserClient<Database>(
|
||||||
supabaseUrl,
|
supabaseUrl,
|
||||||
supabaseAnonKey
|
supabaseAnonKey
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,15 @@
|
||||||
|
// import { createBrowserClient } from "@supabase/ssr"
|
||||||
|
// import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
|
// export const createClient = () =>
|
||||||
|
// createBrowserClient(
|
||||||
|
// getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
|
// process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||||
|
// )
|
||||||
|
|
||||||
|
|
||||||
import { createBrowserClient } from "@supabase/ssr"
|
import { createBrowserClient } from "@supabase/ssr"
|
||||||
import { getRuntimeEnv } from "@/lib/runtime-env"
|
import { getRuntimeEnv } from "@/lib/ipconfig"
|
||||||
|
|
||||||
export const createClient = () =>
|
export const createClient = () =>
|
||||||
createBrowserClient(
|
createBrowserClient(
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,6 @@
|
||||||
import { createServerClient, type CookieOptions } from "@supabase/ssr"
|
import { createServerClient, type CookieOptions } from "@supabase/ssr"
|
||||||
import { NextResponse, type NextRequest } from "next/server"
|
import { NextResponse, type NextRequest } from "next/server"
|
||||||
|
import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
// ✅ 用 headers 构造 host,不再使用 getRuntimeEnv
|
|
||||||
function getSupabaseUrlFromRequest(req: NextRequest, port = "8000"): string {
|
|
||||||
const proto =
|
|
||||||
req.headers.get("x-forwarded-proto") ??
|
|
||||||
(req.headers.get("host")?.includes(":443") ? "https" : "http")
|
|
||||||
|
|
||||||
const rawHost = req.headers.get("x-forwarded-host") ?? req.headers.get("host")!
|
|
||||||
const hostname = rawHost.split(",")[0].split(":")[0].trim()
|
|
||||||
return `${proto}://${hostname}:${port}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createClient = (request: NextRequest) => {
|
export const createClient = (request: NextRequest) => {
|
||||||
// Create an unmodified response
|
// Create an unmodified response
|
||||||
|
|
@ -21,7 +11,7 @@ export const createClient = (request: NextRequest) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const supabase = createServerClient(
|
const supabase = createServerClient(
|
||||||
getSupabaseUrlFromRequest(request), // ✅ 这里改了,其他全保留
|
getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||||
{
|
{
|
||||||
cookies: {
|
cookies: {
|
||||||
|
|
@ -29,14 +19,40 @@ export const createClient = (request: NextRequest) => {
|
||||||
return request.cookies.get(name)?.value
|
return request.cookies.get(name)?.value
|
||||||
},
|
},
|
||||||
set(name: string, value: string, options: CookieOptions) {
|
set(name: string, value: string, options: CookieOptions) {
|
||||||
request.cookies.set({ name, value, ...options })
|
// If the cookie is updated, update the cookies for the request and response
|
||||||
response = NextResponse.next({ request: { headers: request.headers } })
|
request.cookies.set({
|
||||||
response.cookies.set({ name, value, ...options })
|
name,
|
||||||
|
value,
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
response = NextResponse.next({
|
||||||
|
request: {
|
||||||
|
headers: request.headers
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.cookies.set({
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
...options
|
||||||
|
})
|
||||||
},
|
},
|
||||||
remove(name: string, options: CookieOptions) {
|
remove(name: string, options: CookieOptions) {
|
||||||
request.cookies.set({ name, value: "", ...options })
|
// If the cookie is removed, update the cookies for the request and response
|
||||||
response = NextResponse.next({ request: { headers: request.headers } })
|
request.cookies.set({
|
||||||
response.cookies.set({ name, value: "", ...options })
|
name,
|
||||||
|
value: "",
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
response = NextResponse.next({
|
||||||
|
request: {
|
||||||
|
headers: request.headers
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response.cookies.set({
|
||||||
|
name,
|
||||||
|
value: "",
|
||||||
|
...options
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,52 @@
|
||||||
|
// import { createServerClient, type CookieOptions } from "@supabase/ssr"
|
||||||
|
// import { cookies } from "next/headers"
|
||||||
|
// import { getRuntimeEnv } from "@/lib/ipconfig" // 新增引入
|
||||||
|
|
||||||
|
// export const createClient = (cookieStore: ReturnType<typeof cookies>) => {
|
||||||
|
// return createServerClient(
|
||||||
|
// getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000",
|
||||||
|
// process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||||
|
// {
|
||||||
|
// cookies: {
|
||||||
|
// get(name: string) {
|
||||||
|
// return cookieStore.get(name)?.value
|
||||||
|
// },
|
||||||
|
// set(name: string, value: string, options: CookieOptions) {
|
||||||
|
// try {
|
||||||
|
// cookieStore.set({ name, value, ...options })
|
||||||
|
// } catch (error) {
|
||||||
|
// // The `set` method was called from a Server Component.
|
||||||
|
// // This can be ignored if you have middleware refreshing
|
||||||
|
// // user sessions.
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// remove(name: string, options: CookieOptions) {
|
||||||
|
// try {
|
||||||
|
// cookieStore.set({ name, value: "", ...options })
|
||||||
|
// } catch (error) {
|
||||||
|
// // The `delete` method was called from a Server Component.
|
||||||
|
// // This can be ignored if you have middleware refreshing
|
||||||
|
// // user sessions.
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import { createServerClient, type CookieOptions } from "@supabase/ssr"
|
import { createServerClient, type CookieOptions } from "@supabase/ssr"
|
||||||
import { cookies, headers } from "next/headers"
|
import { cookies } from "next/headers"
|
||||||
|
import { getRuntimeEnv } from "@/lib/ipconfig"
|
||||||
import { Database } from "@/supabase/types"
|
import { Database } from "@/supabase/types"
|
||||||
|
|
||||||
function getDynamicSupabaseUrl(): string {
|
export function getSupabaseServerClient() {
|
||||||
const h = headers()
|
const supabaseUrl = getRuntimeEnv("SUPABASE_URL") ?? "http://localhost:8000"
|
||||||
const proto = h.get("x-forwarded-proto") ?? (h.get("host")?.includes(":443") ? "https" : "http")
|
|
||||||
const rawHost = h.get("x-forwarded-host") ?? h.get("host")!
|
|
||||||
const hostname = rawHost.split(",")[0].split(":")[0].trim()
|
|
||||||
return `${proto}://${hostname}:8000`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getSupabaseServerClient(urlOverride?: string) {
|
|
||||||
const supabaseUrl = urlOverride ?? getDynamicSupabaseUrl()
|
|
||||||
|
|
||||||
console.log(`✅ Supabase URL [Server]: ${supabaseUrl}`)
|
|
||||||
|
|
||||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||||
if (!supabaseAnonKey) {
|
|
||||||
throw new Error("⛔️ NEXT_PUBLIC_SUPABASE_ANON_KEY 未设置")
|
|
||||||
}
|
|
||||||
|
|
||||||
const cookieStore = cookies()
|
const cookieStore = cookies()
|
||||||
|
|
||||||
|
|
@ -30,12 +58,12 @@ export function getSupabaseServerClient(urlOverride?: string) {
|
||||||
set(name: string, value: string, options: CookieOptions) {
|
set(name: string, value: string, options: CookieOptions) {
|
||||||
try {
|
try {
|
||||||
cookieStore.set({ name, value, ...options })
|
cookieStore.set({ name, value, ...options })
|
||||||
} catch {}
|
} catch (_) {}
|
||||||
},
|
},
|
||||||
remove(name: string, options: CookieOptions) {
|
remove(name: string, options: CookieOptions) {
|
||||||
try {
|
try {
|
||||||
cookieStore.set({ name, value: "", ...options })
|
cookieStore.set({ name, value: "", ...options })
|
||||||
} catch {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -39,14 +39,7 @@ CREATE TABLE IF NOT EXISTS profiles (
|
||||||
|
|
||||||
-- INDEXES --
|
-- INDEXES --
|
||||||
|
|
||||||
DO $$
|
CREATE INDEX idx_profiles_user_id ON profiles (user_id);
|
||||||
BEGIN
|
|
||||||
IF NOT EXISTS (
|
|
||||||
SELECT 1 FROM pg_indexes WHERE indexname = 'idx_profiles_user_id'
|
|
||||||
) THEN
|
|
||||||
CREATE INDEX idx_profiles_user_id ON profiles (user_id);
|
|
||||||
END IF;
|
|
||||||
END $$;
|
|
||||||
|
|
||||||
-- RLS --
|
-- RLS --
|
||||||
|
|
||||||
|
|
@ -159,7 +152,7 @@ EXECUTE PROCEDURE delete_old_profile_image();
|
||||||
|
|
||||||
-- STORAGE --
|
-- STORAGE --
|
||||||
|
|
||||||
INSERT INTO storage.buckets (id, name, public) VALUES ('profile_images', 'profile_images', true) ON CONFLICT (id) DO NOTHING;
|
INSERT INTO storage.buckets (id, name, public) VALUES ('profile_images', 'profile_images', true);
|
||||||
|
|
||||||
CREATE POLICY "Allow public read access on profile images"
|
CREATE POLICY "Allow public read access on profile images"
|
||||||
ON storage.objects FOR SELECT
|
ON storage.objects FOR SELECT
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ set -e
|
||||||
# 标记文件路径(使用系统级目录)
|
# 标记文件路径(使用系统级目录)
|
||||||
FLAG_DIR="/var/lib/db-init"
|
FLAG_DIR="/var/lib/db-init"
|
||||||
FLAG_FILE="$FLAG_DIR/.db_initialized"
|
FLAG_FILE="$FLAG_DIR/.db_initialized"
|
||||||
LOG_FILE="/var/log/postgres-init.log"
|
|
||||||
|
|
||||||
# 数据库连接配置
|
# 数据库连接配置
|
||||||
export PGUSER=supabase_admin
|
export PGUSER=supabase_admin
|
||||||
|
|
@ -13,46 +12,28 @@ export PGHOST=127.0.0.1
|
||||||
export PGPORT=5432
|
export PGPORT=5432
|
||||||
export PGDATABASE=postgres
|
export PGDATABASE=postgres
|
||||||
|
|
||||||
# 创建标记目录和日志目录
|
# 提前创建标记目录
|
||||||
mkdir -p "$FLAG_DIR"
|
mkdir -p "$FLAG_DIR"
|
||||||
mkdir -p "$(dirname "$LOG_FILE")"
|
|
||||||
|
|
||||||
# 如果标记已存在,跳过执行
|
# 如果标记已存在,跳过执行
|
||||||
if [ -f "$FLAG_FILE" ]; then
|
if [ -f "$FLAG_FILE" ]; then
|
||||||
echo "✅ Database has already been initialized, skipping." | tee -a "$LOG_FILE"
|
echo "✅ Database has already been initialized, skipping."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🚀 Starting database initialization..." | tee -a "$LOG_FILE"
|
echo "🚀 Starting database initialization..."
|
||||||
|
|
||||||
# 封装重试逻辑
|
|
||||||
retry_until_success() {
|
|
||||||
local sql_file="$1"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
echo " ▶ Executing $sql_file" | tee -a "$LOG_FILE"
|
|
||||||
|
|
||||||
if psql -v ON_ERROR_STOP=1 -f "$sql_file" >> "$LOG_FILE" 2>&1; then
|
|
||||||
echo " ✅ Success: $sql_file" | tee -a "$LOG_FILE"
|
|
||||||
break
|
|
||||||
else
|
|
||||||
echo " ❌ ERROR in $sql_file" | tee -a "$LOG_FILE"
|
|
||||||
echo " 🔁 Retrying in 5 seconds..." | tee -a "$LOG_FILE"
|
|
||||||
sleep 5
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# 执行 migrations
|
# 执行 migrations
|
||||||
echo "📂 Running migrations..." | tee -a "$LOG_FILE"
|
echo "📂 Running migrations..."
|
||||||
for file in $(ls /supabase/chatdesk/supabase/migrations/*.sql | sort); do
|
for file in $(ls /supabase/chatdesk/supabase/migrations/*.sql | sort); do
|
||||||
retry_until_success "$file"
|
echo " ▶ Executing $file"
|
||||||
|
psql -f "$file"
|
||||||
done
|
done
|
||||||
|
|
||||||
# 执行 seed.sql
|
# 执行 seed.sql
|
||||||
echo "🌱 Running seed.sql..." | tee -a "$LOG_FILE"
|
echo "🌱 Running seed.sql..."
|
||||||
retry_until_success /supabase/chatdesk/supabase/seed.sql
|
psql -f /supabase/chatdesk/supabase/seed.sql
|
||||||
|
|
||||||
# 写入初始化标记
|
# 写入初始化标记
|
||||||
touch "$FLAG_FILE"
|
touch "$FLAG_FILE"
|
||||||
echo "✅ Database initialization complete. Marked as initialized at $FLAG_FILE" | tee -a "$LOG_FILE"
|
echo "✅ Database initialization complete. Marked as initialized at $FLAG_FILE"
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# 标记文件路径(使用系统级目录)
|
|
||||||
FLAG_DIR="/var/lib/db-init"
|
|
||||||
FLAG_FILE="$FLAG_DIR/.db_initialized"
|
|
||||||
|
|
||||||
# 数据库连接配置
|
|
||||||
export PGUSER=supabase_admin
|
|
||||||
export PGPASSWORD=postgres
|
|
||||||
export PGHOST=127.0.0.1
|
|
||||||
export PGPORT=5432
|
|
||||||
export PGDATABASE=postgres
|
|
||||||
|
|
||||||
# 提前创建标记目录
|
|
||||||
mkdir -p "$FLAG_DIR"
|
|
||||||
|
|
||||||
# 如果标记已存在,跳过执行
|
|
||||||
if [ -f "$FLAG_FILE" ]; then
|
|
||||||
echo "✅ Database has already been initialized, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "🚀 Starting database initialization..."
|
|
||||||
|
|
||||||
# 执行 migrations
|
|
||||||
echo "📂 Running migrations..."
|
|
||||||
for file in $(ls /supabase/chatdesk/supabase/migrations/*.sql | sort); do
|
|
||||||
echo " ▶ Executing $file"
|
|
||||||
psql -f "$file"
|
|
||||||
done
|
|
||||||
|
|
||||||
# 执行 seed.sql
|
|
||||||
echo "🌱 Running seed.sql..."
|
|
||||||
psql -f /supabase/chatdesk/supabase/seed.sql
|
|
||||||
|
|
||||||
# 写入初始化标记
|
|
||||||
touch "$FLAG_FILE"
|
|
||||||
echo "✅ Database initialization complete. Marked as initialized at $FLAG_FILE"
|
|
||||||
|
|
@ -9,7 +9,7 @@ export DATABASE_URL="postgres://supabase_admin:postgres@127.0.0.1:5432/postgres"
|
||||||
#export DATABASE_POOL_URL="postgresql://postgres:postgres@127.0.0.1:6432/postgres"
|
#export DATABASE_POOL_URL="postgresql://postgres:postgres@127.0.0.1:6432/postgres"
|
||||||
#export DB_INSTALL_ROLES="true"
|
#export DB_INSTALL_ROLES="true"
|
||||||
export STORAGE_BACKEND="file"
|
export STORAGE_BACKEND="file"
|
||||||
export FILE_SIZE_LIMIT=104857600 # 100 * 1024 * 1024
|
export FILE_SIZE_LIMIT=52428800 # 50 * 1024 * 1024
|
||||||
export FILE_STORAGE_BACKEND_PATH="/var/lib/storage"
|
export FILE_STORAGE_BACKEND_PATH="/var/lib/storage"
|
||||||
export DB_INSTALL_ROLES="true"
|
export DB_INSTALL_ROLES="true"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue