From 38ddbf8bc17af1ae442d6c4e0e43f5715a60e1ce Mon Sep 17 00:00:00 2001 From: Christomatt Date: Tue, 3 Feb 2026 01:27:46 +0100 Subject: [PATCH] feat: Introduce runtime configuration for domain and enhance S3 storage settings with public base URL and Contabo support. --- docker-compose.yml | 3 ++ src/app/api/auth/register/route.ts | 2 + src/app/api/bots/route.ts | 1 + src/app/api/config/route.ts | 7 ++++ src/app/api/media/upload/route.ts | 1 + src/app/chat/page.tsx | 5 ++- src/app/explore/page.tsx | 5 ++- src/app/layout.tsx | 21 +++++----- src/app/login/page.tsx | 60 +++++++++++++++++++++------- src/app/search/page.tsx | 5 ++- src/app/u/[handle]/page.tsx | 8 ++-- src/components/Compose.tsx | 5 ++- src/components/PostCard.tsx | 16 +++++--- src/components/Sidebar.tsx | 5 ++- src/db/schema.ts | 3 +- src/lib/auth/index.ts | 3 ++ src/lib/config.ts | 33 ++++++++++++++++ src/lib/contexts/ConfigContext.tsx | 63 ++++++++++++++++++++++++++++++ src/lib/storage/s3.ts | 18 +++++++-- src/lib/utils/handle.ts | 28 +++++++++++++ 20 files changed, 244 insertions(+), 48 deletions(-) create mode 100644 src/app/api/config/route.ts create mode 100644 src/lib/config.ts create mode 100644 src/lib/contexts/ConfigContext.tsx diff --git a/docker-compose.yml b/docker-compose.yml index b42f2fa..393c408 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -72,6 +72,9 @@ services: # Port configuration (auto or specific port) PORT: ${PORT:-3000} + # S3 Storage public URL (for custom S3 providers like R2, B2, Contabo) + STORAGE_PUBLIC_BASE_URL: ${STORAGE_PUBLIC_BASE_URL:-} + # Node environment NODE_ENV: production volumes: diff --git a/src/app/api/auth/register/route.ts b/src/app/api/auth/register/route.ts index 1f07db1..9d237cb 100644 --- a/src/app/api/auth/register/route.ts +++ b/src/app/api/auth/register/route.ts @@ -15,6 +15,7 @@ const registerSchema = z.object({ // S3-compatible storage credentials storageProvider: z.string().min(1), storageEndpoint: z.string().nullable().optional(), + storagePublicBaseUrl: z.string().nullable().optional(), storageRegion: z.string().min(1), storageBucket: z.string().min(1), storageAccessKey: z.string().min(10), @@ -71,6 +72,7 @@ export async function POST(request: Request) { data.displayName, data.storageProvider, data.storageEndpoint || null, + data.storagePublicBaseUrl || null, data.storageRegion, data.storageBucket, data.storageAccessKey, diff --git a/src/app/api/bots/route.ts b/src/app/api/bots/route.ts index 20de418..f59c3e7 100644 --- a/src/app/api/bots/route.ts +++ b/src/app/api/bots/route.ts @@ -78,6 +78,7 @@ export async function POST(request: Request) { botAvatarUrl = await generateAndUploadAvatarToUserStorage( botHandle, user.storageEndpoint || undefined, + user.storagePublicBaseUrl || undefined, user.storageRegion || 'auto', user.storageBucket, accessKeyId, diff --git a/src/app/api/config/route.ts b/src/app/api/config/route.ts new file mode 100644 index 0000000..3fa48ad --- /dev/null +++ b/src/app/api/config/route.ts @@ -0,0 +1,7 @@ +import { NextResponse } from 'next/server'; + +export async function GET() { + return NextResponse.json({ + domain: process.env.NEXT_PUBLIC_NODE_DOMAIN || process.env.NODE_DOMAIN || 'localhost:3000', + }); +} diff --git a/src/app/api/media/upload/route.ts b/src/app/api/media/upload/route.ts index 47c9f44..c70193e 100644 --- a/src/app/api/media/upload/route.ts +++ b/src/app/api/media/upload/route.ts @@ -64,6 +64,7 @@ export async function POST(req: NextRequest) { file.type, user.storageProvider as any, user.storageEndpoint, + user.storagePublicBaseUrl, user.storageRegion || 'us-east-1', user.storageBucket || '', user.storageAccessKeyEncrypted, diff --git a/src/app/chat/page.tsx b/src/app/chat/page.tsx index 52d31e2..fed52e7 100644 --- a/src/app/chat/page.tsx +++ b/src/app/chat/page.tsx @@ -4,7 +4,7 @@ import { useState, useEffect, useRef } from 'react'; import { useAuth } from '@/lib/contexts/AuthContext'; import { signedAPI } from '@/lib/api/signed-fetch'; import { ArrowLeft, Send, Loader2, MessageCircle, Search, Plus, Trash2, MoreVertical } from 'lucide-react'; -import { formatFullHandle } from '@/lib/utils/handle'; +import { useFormattedHandle } from '@/lib/utils/handle'; import { useRouter, useSearchParams } from 'next/navigation'; interface Conversation { @@ -43,6 +43,7 @@ export default function ChatPage() { // Chat Data State const [conversations, setConversations] = useState([]); const [selectedConversation, setSelectedConversation] = useState(null); + const selectedHandle = selectedConversation ? useFormattedHandle(selectedConversation.participant2.handle) : ''; const [messages, setMessages] = useState([]); const [newMessage, setNewMessage] = useState(''); const [loading, setLoading] = useState(true); @@ -389,7 +390,7 @@ export default function ChatPage() {
{selectedConversation.participant2.displayName}
- {formatFullHandle(selectedConversation.participant2.handle)} + {selectedHandle}