1(function (global) { 2 "use strict"; 3 4 var cache = { profile: null, entitlements: null }; 5 6 /** 7 * Prefer /app/profile over /app/profiles/me. 8 * WHY: some API builds treat "me" as :id and return "Invalid profile ID". 9 */ 10 async function fetchProfile(signal) { 11 var primary = await FruitiAPI.apiRequest("/app/profile", { signal: signal }); 12 if (!primary.ok) { 13 var secondary = await FruitiAPI.apiRequest("/app/profiles/me", { signal: signal }); 14 if ( 15 !secondary.ok && 16 FruitiDiscovery && 17 FruitiDiscovery.isInvalidProfileIdError(secondary) 18 ) { 19 throw Object.assign(new Error(primary.message || secondary.message), { 20 status: primary.status || secondary.status, 21 result: primary, 22 code: "PROFILE_LOOKUP_FAILED", 23 }); 24 } 25 primary = secondary; 26 } 27 if (!primary.ok) { 28 throw Object.assign(new Error(primary.message), { 29 status: primary.status, 30 result: primary, 31 code: "PROFILE_LOOKUP_FAILED", 32 }); 33 } 34 cache.profile = primary.data; 35 return primary.data; 36 } 37 38 async function fetchEntitlements(signal) { 39 var res = await FruitiAPI.apiRequest("/app/me/entitlements", { signal: signal }); 40 if (!res.ok) { 41 throw Object.assign(new Error(res.message), { status: res.status, result: res }); 42 } 43 cache.entitlements = res.data; 44 return res.data; 45 } 46 47 function mapEntitlement(data) { 48 var root = data || {}; 49 // Live API returns { fruitiPlus: { isActive, source, ... } }; tests/legacy may be flat. 50 var d = 51 root.fruitiPlus && typeof root.fruitiPlus === "object" 52 ? root.fruitiPlus 53 : root; 54 var active = 55 d.isActive === true || 56 d.active === true || 57 d.hasFruitiPlus === true || 58 d.fruitiPlusActive === true || 59 String(d.status || "").toLowerCase() === "active" || 60 String(d.entitlement || "").toLowerCase() === "fruiti_plus" || 61 String(root.status || "").toLowerCase() === "active"; 62 var trial = 63 d.isTrial === true || 64 String(d.status || "").toLowerCase() === "trial" || 65 String(d.period || "").toLowerCase() === "trial"; 66 var expired = 67 d.isExpired === true || 68 String(d.status || "").toLowerCase() === "expired"; 69 var status = "none"; 70 if (active && trial) status = "trial"; 71 else if (active) status = "active"; 72 else if (expired) status = "expired"; 73 return { 74 status: status, 75 expiresAt: d.expiresAt || d.expiryDate || d.currentPeriodEnd || root.expiresAt || null, 76 raw: root, 77 }; 78 } 79 80 function getCachedProfile() { 81 return cache.profile; 82 } 83 84 function setCachedProfile(profile) { 85 cache.profile = profile || null; 86 return cache.profile; 87 } 88 89 global.FruitiCurrentUser = { 90 fetchProfile: fetchProfile, 91 fetchEntitlements: fetchEntitlements, 92 mapEntitlement: mapEntitlement, 93 getCachedProfile: getCachedProfile, 94 setCachedProfile: setCachedProfile, 95 }; 96})(window);
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.