1import { normalizePlanPricingResources } from '../../../shared/plan-resources.js'; 2 3const createPlanPricingLoader = ({ now = Date.now, ttlMs = 60_000 } = {}) => { 4 const caches = new WeakMap(); 5 6 return async (fetcher, { force = false } = {}) => { 7 if (!fetcher || typeof fetcher.getJson !== 'function') { 8 throw new Error('Missing plan pricing fetcher'); 9 } 10 let cache = caches.get(fetcher); 11 if (!cache) { 12 cache = { plans: null, expiresAt: 0, pending: null }; 13 caches.set(fetcher, cache); 14 } 15 if (cache.pending) { 16 return cache.pending; 17 } 18 if (!force && cache.plans && now() < cache.expiresAt) { 19 return cache.plans; 20 } 21 22 cache.pending = Promise.resolve() 23 .then(() => fetcher.getJson('/api/plan_pricings', { cacheMode: 'no-store', credentials: 'include' })) 24 .then((plans) => { 25 if (!Array.isArray(plans)) { 26 throw new Error('Invalid plan pricing response'); 27 } 28 // Include unavailable plans: existing cart items can still reference them. 29 cache.plans = plans.map(normalizePlanPricingResources); 30 cache.expiresAt = now() + ttlMs; 31 return cache.plans; 32 }) 33 .finally(() => { 34 cache.pending = null; 35 }); 36 return cache.pending; 37 }; 38}; 39 40const loadPlanPricingCatalog = createPlanPricingLoader(); 41 42export { createPlanPricingLoader, loadPlanPricingCatalog };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.