diff --git a/packages/web/src/components/ProfileSidebar.tsx b/packages/web/src/components/ProfileSidebar.tsx
index 9f6efeee..687a3458 100644
--- a/packages/web/src/components/ProfileSidebar.tsx
+++ b/packages/web/src/components/ProfileSidebar.tsx
@@ -23,28 +23,17 @@ export function ProfileSidebar({ user, isLive, viewerCount, children }: ProfileS
{/* Profile Header */}
- {/* Avatar and Live Badge */}
+ {/* Name and Live Badge */}
- {user.image ? (
-
-

+
+
+
{displayName}
{isLive && (
-
+
Live
)}
- ) : isLive ? (
-
- ) : null}
-
-
{displayName}
@{user.username}
diff --git a/packages/web/src/lib/jazz/schema.ts b/packages/web/src/lib/jazz/schema.ts
index 6d3758bf..108c6a1d 100644
--- a/packages/web/src/lib/jazz/schema.ts
+++ b/packages/web/src/lib/jazz/schema.ts
@@ -151,6 +151,21 @@ export type StreamRecording = z.infer
*/
export const StreamRecordingList = co.list(StreamRecording)
+/**
+ * Cloudflare Stream configuration
+ */
+export const CloudflareStreamConfig = co.map({
+ /** Cloudflare Live Input UID (permanent, doesn't change between connections) */
+ liveInputUid: z.string(),
+ /** Cloudflare customer code (e.g., xctsztqzu046isdc) */
+ customerCode: z.string(),
+ /** Stream name/title */
+ name: z.string(),
+ /** Last updated timestamp */
+ updatedAt: z.number(),
+})
+export type CloudflareStreamConfig = co.loaded
+
/**
* Viewer account root - stores any viewer-specific data
*/
@@ -163,6 +178,8 @@ export const ViewerRoot = co.map({
glideCanvas: GlideCanvasList,
/** Live stream recordings */
streamRecordings: StreamRecordingList,
+ /** Cloudflare Stream configuration */
+ cloudflareConfig: co.optional(CloudflareStreamConfig),
})
/**
diff --git a/packages/web/src/routes/api/jazz.cloudflare-config.ts b/packages/web/src/routes/api/jazz.cloudflare-config.ts
new file mode 100644
index 00000000..4d01556f
--- /dev/null
+++ b/packages/web/src/routes/api/jazz.cloudflare-config.ts
@@ -0,0 +1,42 @@
+import { json } from "@tanstack/react-start"
+import type { APIContext } from "@tanstack/react-router"
+
+/**
+ * Get or set Cloudflare stream configuration from Jazz
+ *
+ * GET: Returns current Cloudflare Live Input UID
+ * PUT: Updates Cloudflare Live Input UID
+ */
+export async function GET({ request, context }: APIContext) {
+ try {
+ // For now, return the hardcoded value
+ // TODO: Read from Jazz when worker is set up
+ return json({
+ liveInputUid: "bb7858eafc85de6c92963f3817477b5d",
+ customerCode: "xctsztqzu046isdc",
+ name: "linsa-nikiv",
+ updatedAt: Date.now(),
+ })
+ } catch (error) {
+ return json({ error: "Failed to fetch config" }, { status: 500 })
+ }
+}
+
+export async function PUT({ request, context }: APIContext) {
+ try {
+ const body = await request.json()
+ const { liveInputUid, customerCode, name } = body
+
+ // TODO: Write to Jazz when worker is set up
+ // For now, just return success
+ return json({
+ success: true,
+ liveInputUid,
+ customerCode,
+ name,
+ updatedAt: Date.now(),
+ })
+ } catch (error) {
+ return json({ error: "Failed to update config" }, { status: 500 })
+ }
+}
diff --git a/packages/web/src/routes/api/stream-recording.ts b/packages/web/src/routes/api/stream-recording.ts
index 7d6a558b..f0f81c6b 100644
--- a/packages/web/src/routes/api/stream-recording.ts
+++ b/packages/web/src/routes/api/stream-recording.ts
@@ -6,7 +6,9 @@ import { promises as fs } from "fs"
* Chunks are stored temporarily and then synced to Jazz FileStream by client
*/
-const STORAGE_PATH = "/Users/nikiv/fork-i/garden-co/jazz/glide-storage/stream-recordings"
+const STORAGE_PATH =
+ process.env.STREAM_RECORDINGS_PATH ||
+ "/var/lib/jazz/stream-recordings"
interface StreamChunk {
streamId: string
diff --git a/packages/web/src/routes/api/streams.$username.check-hls.ts b/packages/web/src/routes/api/streams.$username.check-hls.ts
index 5659fd54..ef69d869 100644
--- a/packages/web/src/routes/api/streams.$username.check-hls.ts
+++ b/packages/web/src/routes/api/streams.$username.check-hls.ts
@@ -66,6 +66,32 @@ export const Route = createFileRoute("/api/streams/$username/check-hls")({
}
try {
+ // Hardcoded config for nikiv (stored in Jazz, not Postgres)
+ if (username === "nikiv") {
+ const hlsUrl = buildCloudflareHlsUrl("bb7858eafc85de6c92963f3817477b5d", "xctsztqzu046isdc")
+
+ const res = await fetch(hlsUrl, { cache: "no-store" })
+
+ if (!res.ok) {
+ return json({
+ isLive: false,
+ hlsUrl,
+ status: res.status,
+ error: "HLS not available",
+ })
+ }
+
+ const manifest = await res.text()
+ const isLive = isHlsPlaylistLive(manifest)
+
+ return json({
+ isLive,
+ hlsUrl,
+ status: res.status,
+ manifestLength: manifest.length,
+ })
+ }
+
const database = getDb(resolveDatabaseUrl())
const user = await database.query.users.findFirst({