1/* src/public/js/spaces-entitlement.js â THE ONE SPACES ENTITLEMENT RULE 2 * (R12-SPACES-STUDIO, Alex 4 Oct 2026). 3 * 4 * Alex: "we currently have courses, games, and challenges already in the plan⦠5 * for free community customers⦠We don't take any of those features away but 6 * Spaces becomes a paid product that you need to be on the Studio plan for." 7 * 8 * Loaded by the coach app as a plain script (window.SpacesEntitlement) AND 9 * required by the server (src/services/spaces-beta.js), so the client, the 10 * server and the member site all ask exactly this function. Nothing else 11 * decides it; nothing re-derives it. 12 * 13 * THE RULE, on a features object: 14 * 15 * features.spaces !== true â 'none' (no beta) 16 * features.spaces === true AND 17 * (features.spaces_override === true â 'open' (an admin tester) 18 * OR studio) â 'open' (Studio + beta) 19 * features.spaces === true, no Studio, no override â 'frozen' 20 * 21 * · `features.spaces` is THE beta key, written only by spaces-beta.setSpacesBeta() 22 * (R12-SPACES-FUNNEL's one writer): the admin switches, and the Stripe webhook 23 * when a coach pays through Peter's Studio link. 24 * · `features.spaces_override` is the admin's "Spaces without Studio" tick-box 25 * (feature-registry.js). Migration 952 set it for every account that held the 26 * beta before this rule, and for the owner of our own coaches' community, so 27 * nobody testing today loses Spaces. 28 * · `studio` is NOT a stored flag. The server works it out from the plans the 29 * business holds (live-allowance.hasStudio: the `platform` plan, through the 30 * one shared entitlement predicate) and hands the coach app the answer as 31 * `features.spaces_studio` on the COPY of features it is shown at sign-in, 32 * exactly as courses and the lifetime website are overlaid. Never written. 33 * 34 * 'frozen' is the downgrade state: the coach's spaces stay where they are and 35 * their members keep reading what they bought, but the coach cannot create or 36 * edit and nothing new is sold or started (docs/projects/spaces-studio/BUILD.md §4). 37 */ 38(function (root, factory) { 39 var api = factory(); 40 if (typeof module === 'object' && module.exports) module.exports = api; 41 else root.SpacesEntitlement = api; 42}(typeof self !== 'undefined' ? self : this, function () { 43 'use strict'; 44 45 function _features(x) { 46 var o = (x && typeof x === 'object') ? x : {}; 47 return (o.features && typeof o.features === 'object') ? o.features : o; 48 } 49 50 /** 51 * @param {object} featuresOrCustomer a features object, or a row carrying one 52 * @param {boolean} [studio] does the business hold Studio? When omitted, the 53 * coach app's overlaid `features.spaces_studio` answers. 54 * @returns {'open'|'frozen'|'none'} 55 */ 56 function state(featuresOrCustomer, studio) { 57 var f = _features(featuresOrCustomer); 58 if (f.spaces !== true) return 'none'; 59 if (f.spaces_override === true) return 'open'; 60 var s = (typeof studio === 'boolean') ? studio : (f.spaces_studio === true); 61 return s ? 'open' : 'frozen'; 62 } 63 64 function open(featuresOrCustomer, studio) { return state(featuresOrCustomer, studio) === 'open'; } 65 function frozen(featuresOrCustomer, studio) { return state(featuresOrCustomer, studio) === 'frozen'; } 66 67 return { state: state, open: open, frozen: frozen }; 68}));
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.