Merge branch 'fix/openai-middleware-apikey-option' of https://github.com/rajarshidattapy/supermemory into fix/openai-middleware-apikey-option

This commit is contained in:
rajashidattapy 2026-07-21 18:47:54 +05:30
commit 9369e4ae68
7 changed files with 58 additions and 50 deletions

View file

@ -36,16 +36,7 @@ Before you begin, ensure you have the following installed:
# You'll need to add your API keys and database URLs
```
4. **Change proxy for local development**
Add this in your `proxy.ts`(apps/web) before retrieving the cookie (`getSessionCookie(request)`):
```ts
if (url.hostname === "localhost") {
return NextResponse.next();
}
5. **Start the Development Server**
4. **Start the Development Server**
```bash
bun run dev:local

View file

@ -18,7 +18,7 @@ import { motion } from "motion/react"
import { dmSansClassName } from "@/lib/fonts"
import { cn } from "@lib/utils"
import { Logo } from "@ui/assets/Logo"
import { resolveAuthRedirectUrl } from "@/lib/url-helpers"
import { getBackendUrl, resolveAuthRedirectUrl } from "@/lib/url-helpers"
import { Loader2 } from "lucide-react"
function isMcpOAuthAuthorizeContext(sp: Pick<URLSearchParams, "get">): boolean {
@ -276,7 +276,7 @@ export default function LoginPage() {
const token = formData.get("token") as string
const callbackURL = getCallbackURL()
router.push(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/api/auth/magic-link/verify?token=${token}&callbackURL=${encodeURIComponent(callbackURL)}`,
`${getBackendUrl()}/api/auth/magic-link/verify?token=${token}&callbackURL=${encodeURIComponent(callbackURL)}`,
)
}

View file

@ -67,6 +67,7 @@ import {
} from "@/lib/search-params"
import { getChatSpaceDisplayLabel } from "@/lib/chat-space-label"
import { getToolDocumentSpace } from "@/lib/plugin-space"
import { getBackendUrl } from "@/lib/url-helpers"
type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
type DocumentWithMemories = DocumentsResponse["documents"][0]
@ -134,6 +135,7 @@ export function AppExperience() {
const { viewMode, setViewMode } = useViewMode()
useLegacyViewRedirect()
const isCompanyBrain = useHasCompanyBrain()
const backendUrl = getBackendUrl()
// Slack OAuth redirects back here with ?slack=connected — toast then clean up.
useEffect(() => {
@ -331,7 +333,7 @@ export function AppExperience() {
queryFn: async (): Promise<SpaceHighlightsResponse> => {
const spaceId = selectedProject || "sm_project_default"
const forceRefresh = highlightsForceAt > 0
const cacheKey = `${process.env.NEXT_PUBLIC_BACKEND_URL}/v3/space-highlights?spaceId=${spaceId}`
const cacheKey = `${backendUrl}/v3/space-highlights?spaceId=${spaceId}`
if (!forceRefresh) {
const cache = await caches.open(HIGHLIGHTS_CACHE_NAME)
@ -345,22 +347,19 @@ export function AppExperience() {
}
}
const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/v3/space-highlights`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({
spaceId,
highlightsCount: 3,
questionsCount: 4,
includeHighlights: true,
includeQuestions: true,
forceRefresh,
}),
},
)
const response = await fetch(`${backendUrl}/v3/space-highlights`, {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify({
spaceId,
highlightsCount: 3,
questionsCount: 4,
includeHighlights: true,
includeQuestions: true,
forceRefresh,
}),
})
if (!response.ok) {
throw new Error("Failed to fetch space highlights")
@ -404,10 +403,9 @@ export function AppExperience() {
if (stored) return JSON.parse(stored) as MemoryOfDay
} catch {}
const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/v3/memory-of-day`,
{ credentials: "include" },
)
const response = await fetch(`${backendUrl}/v3/memory-of-day`, {
credentials: "include",
})
if (!response.ok) return null
const data = (await response.json()) as MemoryOfDay | null
if (data) {

View file

@ -1111,7 +1111,7 @@ export function ChatSidebar({
const params = new URLSearchParams({ projectId: chatProject })
if (historyScope === "all") params.set("scope", "all")
const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/chat/threads?${params.toString()}`,
`${chatApiBase}/chat/threads?${params.toString()}`,
{ credentials: "include" },
)
if (response.ok) {
@ -1123,7 +1123,7 @@ export function ChatSidebar({
} finally {
setIsLoadingThreads(false)
}
}, [chatProject, historyScope])
}, [chatApiBase, chatProject, historyScope])
useEffect(() => {
if (!isHistoryOpen) return
@ -1134,10 +1134,9 @@ export function ChatSidebar({
const loadThread = useCallback(
async (id: string) => {
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/chat/threads/${id}`,
{ credentials: "include" },
)
const response = await fetch(`${chatApiBase}/chat/threads/${id}`, {
credentials: "include",
})
if (response.ok) {
const data = await response.json()
const uiMessages = data.messages.map(
@ -1179,7 +1178,7 @@ export function ChatSidebar({
console.error("Failed to load thread:", error)
}
},
[setThreadId],
[chatApiBase, setThreadId],
)
// Auto-restore thread from URL on mount (e.g. reload or direct link)
@ -1197,7 +1196,7 @@ export function ChatSidebar({
async (threadId: string) => {
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/chat/threads/${threadId}`,
`${chatApiBase}/chat/threads/${threadId}`,
{ method: "DELETE", credentials: "include" },
)
if (response.ok) {
@ -1213,7 +1212,7 @@ export function ChatSidebar({
setConfirmingDeleteId(null)
}
},
[currentChatId, handleNewChat],
[chatApiBase, currentChatId, handleNewChat],
)
const formatRelativeTime = (isoString: string): string => {

View file

@ -10,6 +10,7 @@ import { $fetch } from "@lib/api"
import { useAuth } from "@lib/auth-context"
import { analytics } from "@/lib/analytics"
import { fetchSpaceSettings, spaceSettingsKey } from "@/hooks/use-space-context"
import { getBackendUrl } from "@/lib/url-helpers"
/** Pull the human-readable message out of a $fetch error (handles `{error}`/`{message}`/string). */
function fetchErrorMessage(err: unknown, fallback: string): string {
@ -500,14 +501,11 @@ export function useDocumentMutations({
}
formData.append("metadata", JSON.stringify({ sm_source: "consumer" }))
const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/v3/documents/file`,
{
method: "POST",
body: formData,
credentials: "include",
},
)
const response = await fetch(`${getBackendUrl()}/v3/documents/file`, {
method: "POST",
body: formData,
credentials: "include",
})
if (!response.ok) {
let message = "Failed to upload file"

View file

@ -1,7 +1,15 @@
const PROXY_LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "::1"])
const DEFAULT_BACKEND_URL = "https://api.supermemory.ai"
const DEV_APP_ORIGIN = "https://app.dev.supermemory.ai"
const PROD_APP_ORIGIN = "https://app.supermemory.ai"
export function getBackendUrl(): string {
return (process.env.NEXT_PUBLIC_BACKEND_URL ?? DEFAULT_BACKEND_URL).replace(
/\/+$/,
"",
)
}
export function getAppOriginForCurrentEnvironment(hostname?: string): string {
const currentHostname =
hostname ?? (typeof window !== "undefined" ? window.location.hostname : "")

View file

@ -2,6 +2,8 @@ import { getSessionCookie } from "better-auth/cookies"
import { NextResponse } from "next/server"
import { getPublicRequestUrl } from "@/lib/url-helpers"
const LOCAL_DEV_HOSTS = new Set(["localhost", "127.0.0.1", "::1"])
function getAuthSessionCookie(request: Request): string | null {
return (
getSessionCookie(request) ??
@ -16,6 +18,18 @@ export default async function proxy(request: Request) {
console.debug("[PROXY] Path:", url.pathname)
console.debug("[PROXY] Method:", request.method)
// Development builds only: getPublicRequestUrl trusts x-forwarded-host, so
// a hostname check alone could be spoofed in production to skip the /api
// 401 gate below. NODE_ENV is inlined at build time, making this dead code
// in production bundles.
if (
process.env.NODE_ENV === "development" &&
LOCAL_DEV_HOSTS.has(url.hostname)
) {
console.debug("[PROXY] Local dev host, allowing access")
return NextResponse.next()
}
const sessionCookie = getAuthSessionCookie(request)
console.debug("[PROXY] Session cookie exists:", !!sessionCookie)