export interface MarketplaceClientOptions { baseUrl: string; productId: string; getAccessToken: () => string; } export interface MarketplaceListing { id: string; title: string; description: string; category: string; author: string; downloads: number; } function joinUrl(base: string, path: string): string { const b = base.replace(/\/$/, ""); const p = path.startsWith("/") ? path : `/${path}`; return `${b}${p}`; } function headers(opts: MarketplaceClientOptions): HeadersInit { return { Authorization: `Bearer ${opts.getAccessToken()}`, "X-Product-Id": opts.productId, Accept: "application/json", "Content-Type": "application/json", }; } async function parseJson(res: Response): Promise { if (!res.ok) { const text = await res.text(); throw new Error(`HTTP ${res.status}: ${text || res.statusText}`); } return res.json() as Promise; } export function createMarketplaceClient(opts: MarketplaceClientOptions) { const { baseUrl } = opts; return { async listListings(listOpts?: { category?: string; }): Promise { const q = new URLSearchParams(); if (listOpts?.category !== undefined && listOpts.category !== "") { q.set("category", listOpts.category); } const query = q.toString(); const path = query.length > 0 ? `/marketplace/listings?${query}` : "/marketplace/listings"; const res = await fetch(joinUrl(baseUrl, path), { method: "GET", headers: headers(opts), }); return parseJson(res); }, async installListing( listingId: string ): Promise<{ success: boolean }> { const res = await fetch( joinUrl( baseUrl, `/marketplace/listings/${encodeURIComponent(listingId)}/install` ), { method: "POST", headers: headers(opts), body: "{}" } ); return parseJson<{ success: boolean }>(res); }, }; }