Files
MineGeo/lib/catalog.ts
pavel444-byte 0e4412c99b
Some checks failed
Deploy MineGeo to Dokploy / deploy (push) Failing after 6m16s
Revert profile cosmetics and GeoCoin currency
2026-10-15 18:32:18 +05:00

127 lines
4.1 KiB
TypeScript

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 | null;
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,avatar_path,name_glow,glow_color,role,bug_finder,custom_prefix,custom_prefix_icon",
)
.in("id", [
...new Set(
maps
.map((m) => m.owner_id)
.filter((id): id is string => id !== null),
),
]),
)
: [];
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 ??
(m.owner_id ? "Explorer" : "Deleted player"),
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([
map.owner_id
? admin()
.from("profiles")
.select(
"display_name,avatar_path,name_glow,glow_color,role,bug_finder,custom_prefix,custom_prefix_icon",
)
.eq("id", map.owner_id)
.maybeSingle()
: Promise.resolve({ data: null }),
mediaUrls([map.cover_path, map.map_path]),
]);
return {
...map,
credit:
owner.data?.display_name ??
(map.owner_id ? "Explorer" : "Deleted player"),
creditGlow: owner.data?.name_glow ?? false,
creditAppearance: owner.data ?? undefined,
image: signed[0],
mapImage: signed[1],
};
}