import type { IPaywall, NamiProductDetails } from '@namiml/sdk-core'; import { NamiPaywallManager, logger } from '@namiml/sdk-core'; import { expoPurchaseAdapter } from '../adapters'; // Accumulated store product details, keyed by product_ref_id (== sku_ref_id). const productsById = new Map(); // Serializes backfill runs so concurrent launches/prefetches don't double-fetch // or race the map (parity with the Apple SDK's backfillTaskLock). let pending: Promise = Promise.resolve(false); /** Collect unique store product ids (sku_ref_id) from the given paywalls' sku menus. */ export function collectSkuRefIds(paywalls: IPaywall[]): string[] { const ids = new Set(); for (const paywall of paywalls ?? []) { for (const menu of paywall?.sku_menus ?? []) { for (const sku of menu?.products ?? []) { if (sku?.sku_ref_id) ids.add(sku.sku_ref_id); } } } return [...ids]; } /** * Fetch store product details for any of `skuRefIds` not already loaded, merge them into * the accumulated set, and push the union to core via NamiPaywallManager.setProductDetails. * Serialized; returns whether new products were added. Never throws. */ export function backfill(skuRefIds: string[]): Promise { pending = pending.then(() => backfillOnce(skuRefIds)); return pending; } async function backfillOnce(skuRefIds: string[]): Promise { const missing = [...new Set(skuRefIds)].filter((id) => id && !productsById.has(id)); if (!missing.length) return false; try { const products = await expoPurchaseAdapter.getProducts(missing); let added = false; for (const product of products ?? []) { if (product?.product_ref_id) { productsById.set(product.product_ref_id, product); added = true; } } if (added) { NamiPaywallManager.setProductDetails([...productsById.values()]); } return added; } catch (error) { logger.warn('[NamiExpo] Failed to load store products.', error); return false; } } /** Clear accumulated products. Called on Nami.reset so reconfigure doesn't serve stale data. */ export function reset(): void { pending = pending.then(() => { productsById.clear(); return false; }); }