import type { StoreCapabilities } from 'brainerce'; /** * Fallback used until `getStoreCapabilities()` resolves, and whenever the call * fails. Matches the platform default (`SalesChannel.lowStockThreshold`), so a * store that never reaches the endpoint behaves exactly as it did before * capabilities were wired in — it never renders a broken or empty badge. */ export const DEFAULT_LOW_STOCK_THRESHOLD = 5; /** * The subset of {@link StoreCapabilities} the storefront actually renders from. * Operational channel state (granted API scopes, sandbox payment flags, * reservation strategy) is deliberately dropped: it tells a reader how the * merchant's channel is provisioned and has no role in what a shopper sees. * * Uses indexed access on `StoreCapabilities` for nested types so this stays in * step with the SDK without restating its shapes. */ export interface PublicStoreCapabilities { /** Whether to call out low stock at all. False means the merchant switched the urgency messaging off. */ lowStockWarning: boolean; /** Units at or below which stock counts as low. */ lowStockThreshold: number; /** Whether "email me when this is back" should be offered on sold-out items. */ stockAlertsEnabled: boolean; /** Minutes a checkout reservation is held before it expires. */ reservationTimeout: number; /** Which optional features the merchant enabled — coupons, loyalty, shipping zones, and so on. */ features: StoreCapabilities['features']; } /** * Project a raw capabilities response onto {@link PublicStoreCapabilities}. * Add a field here only after confirming it is non-sensitive and that a * storefront component actually needs it. */ export function pickPublicCapabilities(raw: StoreCapabilities): PublicStoreCapabilities { return { lowStockWarning: raw.connection.lowStockWarning, lowStockThreshold: raw.connection.lowStockThreshold, stockAlertsEnabled: raw.connection.stockAlertsEnabled, reservationTimeout: raw.connection.reservationTimeout, features: raw.features, }; } /** * Resolve the low-stock threshold a badge should use. * * Three cases, in order: * 1. Capabilities not loaded yet, or the fetch failed (`null`) — fall back to * {@link DEFAULT_LOW_STOCK_THRESHOLD} so the first paint is correct. * 2. The merchant turned the low-stock warning off — return `0`. Stock counts * as low only at or below the threshold, and an in-stock item always has at * least one unit, so nothing is ever flagged low. The item still renders its * normal in-stock label; no string is left blank. * 3. Otherwise, the merchant's configured threshold. */ export function resolveLowStockThreshold( capabilities: PublicStoreCapabilities | null | undefined ): number { if (!capabilities) return DEFAULT_LOW_STOCK_THRESHOLD; return capabilities.lowStockWarning ? capabilities.lowStockThreshold : 0; }