import { NextResponse } from "next/server"; import { defineQuery } from "next-sanity"; import { getAuthToken, medusaAuthFetch } from "@/lib/auth"; import { getAllProducts } from "@/lib/medusa"; import { sanity } from "@/lib/sanity"; import { formatDisplayName } from "@/lib/variants"; const RELEASES_BY_CATALOG_NOS_QUERY = defineQuery(` *[_type == "release" && catalogNo in $catalogNos]{ catalogNo, name, albumArtist, "slug": slug.current, albumCover, releaseDate, genre, instrumentation } `); const MEDUSA_URL = process.env.MEDUSA_URL ?? process.env.NEXT_PUBLIC_MEDUSA_URL ?? "http://localhost:9000"; const API_KEY = process.env.MEDUSA_PUBLISHABLE_KEY ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? ""; type Order = { id: string }; type RawDownload = { product_title?: string; variant_title?: string; sku?: string; download_url?: string; }; type RawUpcoming = { product_title?: string; variant_title?: string; sku?: string; release_date?: string; }; type SanityRelease = { catalogNo: string; name: string; albumArtist: string; slug: string; albumCover: unknown; releaseDate: string | null; genre: string[] | null; instrumentation: string[] | null; }; export async function GET() { const token = await getAuthToken(); if (!token) { return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); } try { // Fetch all customer orders const ordersData = await medusaAuthFetch<{ orders: Order[] }>( "/store/orders", ); const allDownloads: RawDownload[] = []; const allUpcoming: RawUpcoming[] = []; // For each order, fetch digital downloads via the custom Medusa endpoint for (const order of ordersData.orders ?? []) { try { const res = await fetch( `${MEDUSA_URL}/store/order-downloads?order_id=${encodeURIComponent(order.id)}`, { headers: { "x-publishable-api-key": API_KEY, Authorization: `Bearer ${token}`, }, }, ); if (res.ok) { const data = await res.json(); if (data.downloads?.length) allDownloads.push(...data.downloads); if (data.upcoming?.length) allUpcoming.push(...data.upcoming); } } catch { // Non-critical — skip individual order failures } } // Fetch grant-based downloads (admin-granted access without an order) try { const grantsData = await medusaAuthFetch<{ downloads: RawDownload[] }>( "/store/customers/me/download-grants", ); if (grantsData.downloads?.length) allDownloads.push(...grantsData.downloads); } catch { // Non-critical — grants may not exist or endpoint may not be available } // Deduplicate by SKU const seenDownloads = new Set(); const uniqueDownloads = allDownloads.filter((d) => { if (!d.sku || seenDownloads.has(d.sku)) return false; seenDownloads.add(d.sku); return true; }); const seenUpcoming = new Set(); const uniqueUpcoming = allUpcoming.filter((u) => { if (!u.sku || seenUpcoming.has(u.sku)) return false; seenUpcoming.add(u.sku); return true; }); // Build product_title → catalogue_number map via Medusa products const titleToCatalogNo = new Map(); try { const products = await getAllProducts(); for (const p of products) { if (p.metadata?.catalogue_number && typeof p.metadata.catalogue_number === "string") { titleToCatalogNo.set(p.title, p.metadata.catalogue_number); } } } catch { // Non-critical — cards will just miss Sanity data } // Query Sanity for matching releases const catalogNos = [...new Set(titleToCatalogNo.values())]; const catalogNoToRelease = new Map(); if (catalogNos.length > 0) { try { const releases = await sanity.fetch( RELEASES_BY_CATALOG_NOS_QUERY, { catalogNos }, ); for (const r of releases) { catalogNoToRelease.set(r.catalogNo, r); } } catch { // Non-critical — cards will render without covers } } // Helper to look up Sanity data for a product title function getSanityData(productTitle?: string) { if (!productTitle) return null; const catalogNo = titleToCatalogNo.get(productTitle); if (!catalogNo) return null; return catalogNoToRelease.get(catalogNo) ?? null; } // Helper to build enriched base fields from Sanity data function enrichedBase(productTitle: string) { const release = getSanityData(productTitle); return { product_title: productTitle, albumCover: release?.albumCover ?? null, albumArtist: release?.albumArtist ?? null, slug: release?.slug ?? null, catalogNo: release?.catalogNo ?? null, releaseDate: release?.releaseDate ?? null, genre: release?.genre ?? [], instrumentation: release?.instrumentation ?? [], }; } // Group downloads by product_title, enriched with Sanity data const downloadGroups = new Map & { formats: { variant_title: string; sku: string; download_url: string }[]; }>(); for (const dl of uniqueDownloads) { const title = dl.product_title ?? "Unknown"; const existing = downloadGroups.get(title); const fmt = { variant_title: formatDisplayName(dl.sku ?? "") ?? dl.variant_title ?? "", sku: dl.sku ?? "", download_url: dl.download_url ?? "", }; if (existing) { existing.formats.push(fmt); } else { downloadGroups.set(title, { ...enrichedBase(title), formats: [fmt] }); } } // Group upcoming by product_title, enriched with Sanity data const upcomingGroups = new Map & { release_date: string; formats: { variant_title: string; sku: string }[]; }>(); for (const up of uniqueUpcoming) { const title = up.product_title ?? "Unknown"; const existing = upcomingGroups.get(title); const fmt = { variant_title: formatDisplayName(up.sku ?? "") ?? up.variant_title ?? "", sku: up.sku ?? "", }; if (existing) { existing.formats.push(fmt); } else { upcomingGroups.set(title, { ...enrichedBase(title), release_date: up.release_date ?? "", formats: [fmt], }); } } return NextResponse.json({ downloads: Array.from(downloadGroups.values()), upcoming: Array.from(upcomingGroups.values()), }); } catch (e) { console.error("[account:downloads]", (e as Error).message); return NextResponse.json( { error: "Failed to fetch downloads" }, { status: 500 }, ); } }