mirror of
https://github.com/linsa-io/linsa.git
synced 2026-07-20 18:51:10 +02:00
165 lines
4.9 KiB
TypeScript
165 lines
4.9 KiB
TypeScript
import { createFileRoute } from "@tanstack/react-router"
|
|
import { eq } from "drizzle-orm"
|
|
import { getDb } from "@/db/connection"
|
|
import { users, streams } from "@/db/schema"
|
|
import crypto from "node:crypto"
|
|
|
|
const json = (data: unknown, status = 200) =>
|
|
new Response(JSON.stringify(data), {
|
|
status,
|
|
headers: { "content-type": "application/json" },
|
|
})
|
|
|
|
const getServerContext = () => {
|
|
try {
|
|
const { getServerContext: gsc } = require("@tanstack/react-start/server") as {
|
|
getServerContext: () => { cloudflare?: { env?: Record<string, unknown> } } | null
|
|
}
|
|
return gsc()
|
|
} catch {}
|
|
return null
|
|
}
|
|
|
|
const resolveDatabaseUrl = () => {
|
|
const ctx = getServerContext()
|
|
const env = ctx?.cloudflare?.env as Record<string, string> | undefined
|
|
if (env?.DATABASE_URL) return env.DATABASE_URL
|
|
if (process.env.DATABASE_URL) return process.env.DATABASE_URL
|
|
throw new Error("DATABASE_URL is not configured")
|
|
}
|
|
|
|
// Get user from session cookie
|
|
async function getSessionUser(request: Request) {
|
|
const cookie = request.headers.get("cookie")
|
|
if (!cookie) return null
|
|
|
|
// Parse session token from cookie
|
|
const sessionMatch = cookie.match(/better-auth\.session_token=([^;]+)/)
|
|
if (!sessionMatch) return null
|
|
|
|
const sessionToken = decodeURIComponent(sessionMatch[1])
|
|
const database = getDb(resolveDatabaseUrl())
|
|
|
|
// Look up session and get user
|
|
const result = await database.execute<{ userId: string }>(
|
|
`SELECT "userId" FROM sessions WHERE token = $1 AND "expiresAt" > NOW()`,
|
|
[sessionToken]
|
|
)
|
|
|
|
if (!result.rows.length) return null
|
|
|
|
const user = await database.query.users.findFirst({
|
|
where: eq(users.id, result.rows[0].userId),
|
|
})
|
|
|
|
return user
|
|
}
|
|
|
|
export const Route = createFileRoute("/api/stream/settings")({
|
|
server: {
|
|
handlers: {
|
|
// GET - Fetch current user's stream settings
|
|
GET: async ({ request }) => {
|
|
const user = await getSessionUser(request)
|
|
if (!user) {
|
|
return json({ error: "Unauthorized" }, 401)
|
|
}
|
|
|
|
const database = getDb(resolveDatabaseUrl())
|
|
|
|
let stream = await database.query.streams.findFirst({
|
|
where: eq(streams.user_id, user.id),
|
|
})
|
|
|
|
// If no stream exists, create one
|
|
if (!stream) {
|
|
const streamKey = crypto.randomUUID()
|
|
const [newStream] = await database
|
|
.insert(streams)
|
|
.values({
|
|
user_id: user.id,
|
|
stream_key: streamKey,
|
|
title: "Live Stream",
|
|
})
|
|
.returning()
|
|
stream = newStream
|
|
}
|
|
|
|
return json({
|
|
id: stream.id,
|
|
title: stream.title,
|
|
description: stream.description,
|
|
cloudflare_live_input_uid: stream.cloudflare_live_input_uid,
|
|
cloudflare_customer_code: stream.cloudflare_customer_code,
|
|
hls_url: stream.hls_url,
|
|
stream_key: stream.stream_key,
|
|
})
|
|
},
|
|
|
|
// PUT - Update stream settings
|
|
PUT: async ({ request }) => {
|
|
const user = await getSessionUser(request)
|
|
if (!user) {
|
|
return json({ error: "Unauthorized" }, 401)
|
|
}
|
|
|
|
const body = await request.json()
|
|
const {
|
|
title,
|
|
description,
|
|
cloudflare_live_input_uid,
|
|
cloudflare_customer_code,
|
|
} = body
|
|
|
|
const database = getDb(resolveDatabaseUrl())
|
|
|
|
// Get or create stream
|
|
let stream = await database.query.streams.findFirst({
|
|
where: eq(streams.user_id, user.id),
|
|
})
|
|
|
|
if (!stream) {
|
|
const streamKey = crypto.randomUUID()
|
|
const [newStream] = await database
|
|
.insert(streams)
|
|
.values({
|
|
user_id: user.id,
|
|
stream_key: streamKey,
|
|
title: title || "Live Stream",
|
|
description,
|
|
cloudflare_live_input_uid,
|
|
cloudflare_customer_code,
|
|
})
|
|
.returning()
|
|
stream = newStream
|
|
} else {
|
|
// Update existing stream
|
|
const [updatedStream] = await database
|
|
.update(streams)
|
|
.set({
|
|
title: title ?? stream.title,
|
|
description: description ?? stream.description,
|
|
cloudflare_live_input_uid: cloudflare_live_input_uid ?? stream.cloudflare_live_input_uid,
|
|
cloudflare_customer_code: cloudflare_customer_code ?? stream.cloudflare_customer_code,
|
|
updated_at: new Date(),
|
|
})
|
|
.where(eq(streams.id, stream.id))
|
|
.returning()
|
|
stream = updatedStream
|
|
}
|
|
|
|
return json({
|
|
success: true,
|
|
stream: {
|
|
id: stream.id,
|
|
title: stream.title,
|
|
description: stream.description,
|
|
cloudflare_live_input_uid: stream.cloudflare_live_input_uid,
|
|
cloudflare_customer_code: stream.cloudflare_customer_code,
|
|
},
|
|
})
|
|
},
|
|
},
|
|
},
|
|
})
|