import "server-only"; import { admin, required } from "./supabase"; import { z } from "zod"; import { ServiceError } from "./service-error"; export type MapListing = { id: string; name: string; description: string; source: "plugin" | "fabric"; state: string; parent_dataset_id: string | null; contribution_status: string | null; allow_contributions: boolean; contribution_server_address: string | null; update_state: string | null; bounds: { minX: number; minZ: number; maxX: number; maxZ: number }; panorama_count: number; server_id: string; owner_id: string; cover_path: string | null; map_path: string | null; rejection_reason: string | null; report_strikes: number; banned_at: string | null; ban_reason: string | null; image?: string; mapImage?: string; credit?: string; creditGlow?: boolean; creditAppearance?: import("../shared/profile-appearance").ProfileAppearance; }; export async function mediaUrl(path: string | null, expires = 3600) { return (await mediaUrls([path], expires))[0]; } export async function mediaUrls(paths: (string | null)[], expires = 3600) { const unique = [...new Set(paths.filter((path): path is string => !!path))]; if (!unique.length) return paths.map(() => null); const { data, error } = await admin() .storage.from("minegeo-media") .createSignedUrls(unique, expires); if (error || !data || data.some((item) => item.error || !item.signedUrl)) throw new ServiceError( "Map images are temporarily unavailable. Please try again.", ); const signed = new Map( data.map((item, index) => [unique[index], item.signedUrl]), ); return paths.map((path) => (path ? (signed.get(path) ?? null) : null)); } export async function catalog() { const client = admin(); const maps = required( await client .from("datasets") .select("*") .eq("state", "published") .order("created_at", { ascending: false }), ) as unknown as MapListing[]; const servers = required( await client.from("catalog_servers").select("*"), ) as { id: string; name: string; address: string | null }[]; const owners = maps.length ? required( await client .from("profiles") .select( "id,display_name,name_glow,glow_color,role,bug_finder,custom_prefix,custom_prefix_icon", ) .in("id", [...new Set(maps.map((m) => m.owner_id))]), ) : []; const signed = await mediaUrls( maps.flatMap((map) => [map.map_path || map.cover_path, map.map_path]), ); return maps.map((m, index) => ({ ...m, credit: owners.find((p) => p.id === m.owner_id)?.display_name ?? "Explorer", creditGlow: owners.find((p) => p.id === m.owner_id)?.name_glow ?? false, creditAppearance: owners.find((p) => p.id === m.owner_id), image: signed[index * 2] ?? undefined, mapImage: signed[index * 2 + 1] ?? undefined, server: servers.find((s) => s.id === m.server_id), })); } export async function getMap(id: string) { if (!z.string().uuid().safeParse(id).success) return null; const result = await admin() .from("datasets") .select("*") .eq("id", id) .eq("state", "published") .maybeSingle(); if (result.error) required(result); if (!result.data) return null; const map = result.data as unknown as MapListing; const [owner, signed] = await Promise.all([ admin() .from("profiles") .select( "display_name,name_glow,glow_color,role,bug_finder,custom_prefix,custom_prefix_icon", ) .eq("id", map.owner_id) .maybeSingle(), mediaUrls([map.cover_path, map.map_path]), ]); return { ...map, credit: owner.data?.display_name ?? "Explorer", creditGlow: owner.data?.name_glow ?? false, creditAppearance: owner.data ?? undefined, image: signed[0], mapImage: signed[1], }; }