diff --git a/apps/masterbots.ai/.env.local b/apps/masterbots.ai/.env.local
index f7715790..173f5035 100644
--- a/apps/masterbots.ai/.env.local
+++ b/apps/masterbots.ai/.env.local
@@ -8,7 +8,6 @@ NEXT_PUBLIC_APP_ENV=test
# AUTH_REDIRECT_PROXY_URL=https://YOURAPP.vercel.app/api/auth
# https://hasura.io/learn/graphql/hasura-authentication/integrations/nextjs-auth/
-NEXTAUTH_URL=http://localhost:3000
AUTH_SECRET=bb755cba466058b2e6a195541468e84c
JWT_TOKEN_EXPIRATION=2630016
diff --git a/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx b/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx
index 811d8fae..3cf95e88 100644
--- a/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx
+++ b/apps/masterbots.ai/app/(browse)/[category]/[threadId]/page.tsx
@@ -3,6 +3,8 @@ import { ThreadAccordion } from '@/components/shared/thread-accordion'
import { CategoryTabs } from '@/components/shared/category-tabs/category-tabs'
import { SearchInput } from '@/components/shared/search-input'
+export { generateMbMetadata as generateMetadata } from '@/lib/metadata'
+
export default async function ThreadPage({ params }: ThreadPageProps) {
const categories = await getCategories()
const thread = await getThread({
diff --git a/apps/masterbots.ai/app/(browse)/page.tsx b/apps/masterbots.ai/app/(browse)/page.tsx
index 0a7613de..4e8870dd 100644
--- a/apps/masterbots.ai/app/(browse)/page.tsx
+++ b/apps/masterbots.ai/app/(browse)/page.tsx
@@ -1,11 +1,18 @@
import { ThreadList } from '@/components/shared/thread-list'
import { CategoryTabs } from '@/components/shared/category-tabs/category-tabs'
import { SearchInput } from '@/components/shared/search-input'
-import { getBrowseThreads, getCategories } from '@/services/hasura'
+import { getBrowseThreads, getCategories, getThread } from '@/services/hasura'
import { Card } from '@/components/ui/card'
import { decodeQuery } from '@/lib/url'
+import { permanentRedirect } from 'next/navigation'
+import { getThreadLink } from '@/lib/threads'
export default async function HomePage({ searchParams }: HomePageProps) {
+ if (searchParams.threadId) {
+ const thread = await getThread({ threadId: searchParams.threadId })
+ permanentRedirect(getThreadLink({ thread }))
+ }
+
const categories = await getCategories()
const query = searchParams.query ? decodeQuery(searchParams.query) : null
const limit = searchParams.limit ? parseInt(searchParams.limit) : 20
@@ -44,5 +51,10 @@ export default async function HomePage({ searchParams }: HomePageProps) {
}
interface HomePageProps {
- searchParams?: { query: string; page: string; limit: string }
+ searchParams?: {
+ query: string
+ page: string
+ limit: string
+ threadId: string
+ }
}
diff --git a/apps/masterbots.ai/app/og/route.tsx b/apps/masterbots.ai/app/og/route.tsx
new file mode 100644
index 00000000..a7ebd824
--- /dev/null
+++ b/apps/masterbots.ai/app/og/route.tsx
@@ -0,0 +1,58 @@
+import { ImageResponse } from '@vercel/og'
+import { NextRequest } from 'next/server'
+import { GeistMono } from 'geist/font/mono' // Import the GeistMono font
+
+export const runtime = 'edge'
+
+export async function GET(req: NextRequest) {
+ const { searchParams } = req.nextUrl
+ const postTitle = searchParams.get('title')
+
+ // You may need to convert GeistMono or fetch it as ArrayBuffer if needed
+ // const font = GeistMono; // Assuming GeistMono can be directly used, modify as needed
+
+ return new ImageResponse(
+ (
+
+ ),
+ {
+ width: 1920,
+ height: 1080
+ // Optionally, if font needs to be loaded as data
+ // fonts: [
+ // {
+ // name: 'GeistMono',
+ // data: font, // Assuming font data is handled accordingly
+ // style: 'normal'
+ // }
+ // ]
+ }
+ )
+}
diff --git a/apps/masterbots.ai/components/layout/footer-ct.tsx b/apps/masterbots.ai/components/layout/footer-ct.tsx
index 50cdde07..d0fd3e2a 100644
--- a/apps/masterbots.ai/components/layout/footer-ct.tsx
+++ b/apps/masterbots.ai/components/layout/footer-ct.tsx
@@ -1,3 +1,4 @@
+import Link from 'next/link'
import type { ElementType } from 'react'
export default function FooterCT({ nonFooterTag }: { nonFooterTag?: boolean }) {
@@ -24,13 +25,13 @@ export default function FooterCT({ nonFooterTag }: { nonFooterTag?: boolean }) {
>
robohash.org
- {' • '}
-
terms & policies
-
+
)
diff --git a/apps/masterbots.ai/components/routes/c/chat-input-new.tsx b/apps/masterbots.ai/components/routes/c/chat-input-new.tsx
index 546d3358..a3d28164 100644
--- a/apps/masterbots.ai/components/routes/c/chat-input-new.tsx
+++ b/apps/masterbots.ai/components/routes/c/chat-input-new.tsx
@@ -25,7 +25,6 @@ export interface ChatInputProps
showReload?: boolean
placeholder: string
className?: string
- showSubmitButton: boolean
}
export function ChatInputNew({
diff --git a/apps/masterbots.ai/components/bot-params-form.tsx b/apps/masterbots.ai/components/shared/bot-params-form.tsx
similarity index 100%
rename from apps/masterbots.ai/components/bot-params-form.tsx
rename to apps/masterbots.ai/components/shared/bot-params-form.tsx
diff --git a/apps/masterbots.ai/lib/metadata.ts b/apps/masterbots.ai/lib/metadata.ts
new file mode 100644
index 00000000..5942030e
--- /dev/null
+++ b/apps/masterbots.ai/lib/metadata.ts
@@ -0,0 +1,48 @@
+import { getThread } from '@/services/hasura';
+import type { Metadata } from 'next';
+import { format } from 'date-fns';
+import { getThreadLink } from './threads';
+
+export async function generateMbMetadata({
+ params,
+}): Promise {
+ const thread = await getThread({threadId: params.threadId})
+ if (!thread) return
+
+
+ const firstQuestion=
+ thread.messages.find(m => m.role === 'user')?.content || 'not found'
+ const firstResponse =
+ thread.messages.find(m => m.role === 'assistant')?.content || 'not found'
+
+ const data = {
+ title: firstQuestion,
+ publishedAt: thread.updatedAt, // format(thread.updatedAt, 'MMMM dd, yyyy'),
+ summary: firstResponse,
+ image: `https://alpha.masterbots.ai/og?title=${encodeURIComponent(firstQuestion)}`,
+ pathname: getThreadLink({thread:thread, chat:false})
+ }
+
+ return {
+ title:data.title,
+ description:data.summary,
+ openGraph: {
+ title:data.title,
+ description:data.summary,
+ type: 'article',
+ publishedTime: data.publishedAt,
+ url: `https://alpha.masterbots.ai/${data.pathname}`,
+ images: [
+ {
+ url: data.image,
+ },
+ ],
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title:data.title,
+ description:data.summary,
+ images: [data.image],
+ },
+ };
+}
\ No newline at end of file
diff --git a/apps/masterbots.ai/lib/threads.ts b/apps/masterbots.ai/lib/threads.ts
index 466f6648..042ebcbf 100644
--- a/apps/masterbots.ai/lib/threads.ts
+++ b/apps/masterbots.ai/lib/threads.ts
@@ -82,6 +82,6 @@ export function getAllUserMessagesAsStringArray(
return cleanMessages.join(', ')
}
-export function getThreadLink({chat=false, thread}:{chat:boolean, thread: Thread}){
+export function getThreadLink({chat=false, thread}:{chat?:boolean, thread: Thread}){
return chat ? `/c/${toSlug(thread.chatbot.name)}/${thread.threadId}` : `/${toSlug(thread.chatbot.categories[0]?.category.name)}/${thread.threadId}`
}
\ No newline at end of file
diff --git a/apps/masterbots.ai/package.json b/apps/masterbots.ai/package.json
index cd9f0db6..ad348eee 100644
--- a/apps/masterbots.ai/package.json
+++ b/apps/masterbots.ai/package.json
@@ -39,7 +39,7 @@
"@supabase/ssr": "^0.1.0",
"@tanstack/react-query": "^5.29.0",
"@vercel/analytics": "^1.1.1",
- "@vercel/og": "^0.5.20",
+ "@vercel/og": "^0.6.2",
"ai": "^2.2.25",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
diff --git a/bun.lockb b/bun.lockb
index cbc47fe0..df9b6152 100755
Binary files a/bun.lockb and b/bun.lockb differ