[{"data":1,"prerenderedAt":23},["ShallowReactive",2],{"doc-flags":3},{"html":4,"headings":5},"\u003Cp>Turn parts of your app on and off from the HelpBites panel, without a deploy.\nHelpBites doesn't know what a flag gates. The keys are yours (\u003Ccode>ai_chat\u003C\u002Fcode>,\n\u003Ccode>new_checkout\u003C\u002Fcode>), and your app decides what each one does.\u003C\u002Fp>\n\u003Ch2 id=\"a-flag\">A flag\u003Ca class=\"heading-anchor\" href=\"#a-flag\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Field\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>key\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Your identifier: lowercase letters, digits, \u003Ccode>.\u003C\u002Fcode>, \u003Ccode>-\u003C\u002Fcode>, \u003Ccode>_\u003C\u002Fcode>, up to 64 characters.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>state\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>off\u003C\u002Fcode> is off for everyone, admins included. \u003Ccode>on\u003C\u002Fcode> is on for everyone. \u003Ccode>admins\u003C\u002Fcode> is on for your admins plus the \u003Ccode>allow\u003C\u002Fcode> list.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>fallback\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>What your app should assume when it can't reach HelpBites. The default is \u003Ccode>off\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>targets\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Free-form tags such as \u003Ccode>frontend\u003C\u002Fcode>, \u003Ccode>backend\u003C\u002Fcode> or \u003Ccode>ios\u003C\u002Fcode>. A client asks for its own target, and untagged flags go to every client.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>allow\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>User ids (your \u003Ccode>sub\u003C\u002Fcode>) or emails that count as admins for this flag, e.g. beta testers.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>description\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>A note for operators.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>\u003Cstrong>Who is an admin?\u003C\u002Fstrong> Your app decides. A server checks its own admin role. A\nbrowser that sends an identity token is an admin when the token carries\n\u003Ccode>role: &quot;admin&quot;\u003C\u002Fcode>. Anyone on the flag's \u003Ccode>allow\u003C\u002Fcode> list counts too, matched by \u003Ccode>sub\u003C\u002Fcode>\nor by \u003Ccode>email\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Manage flags under \u003Cstrong>Project → Flags\u003C\u002Fstrong>. You can also replace the whole list with\n\u003Ccode>PATCH \u002Fv1\u002Fadmin\u002Fprojects\u002F:id { flags: [...] }\u003C\u002Fcode> and an admin key.\u003C\u002Fp>\n\u003Ch2 id=\"reading-flags-get-v1flags\">Reading flags: \u003Ccode>GET \u002Fv1\u002Fflags\u003C\u002Fcode>\u003Ca class=\"heading-anchor\" href=\"#reading-flags-get-v1flags\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Add \u003Ccode>?target=frontend\u003C\u002Fcode> to get only that client's flags.\u003C\u002Fp>\n\u003Ch3 id=\"from-your-server-recommended\">From your server (recommended)\u003Ca class=\"heading-anchor\" href=\"#from-your-server-recommended\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Send the project secret. This returns every flag raw, \u003Ccode>allow\u003C\u002Fcode> list included,\nfor you to evaluate against your own users:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-js\">\u003Ccode>\u003Cspan class=\"shj-syn-kwd\">const\u003C\u002Fspan> { flags } \u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-syn-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-syn-func\">fetch\u003C\u002Fspan>(\u003Cspan class=\"shj-syn-str\">'https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fv1\u002Fflags?target=backend'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> {\n  headers\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> { authorization\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">`Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\">${\u003C\u002Fspan>process\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>env\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-num\">HELP_BITES_SECRET\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\">}\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">`\u003C\u002Fspan> }\n})\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">then\u003C\u002Fspan>(r \u003Cspan class=\"shj-syn-kwd\">=&gt;\u003C\u002Fspan> r\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">json\u003C\u002Fspan>())\n\u003Cspan class=\"shj-syn-cmnt\">\u002F\u002F { ai_chat: { state: 'admins', fallback: 'off', targets: ['backend'], allow: ['user_123'], description: '…' } }\n\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-kwd\">function\u003C\u002Fspan> \u003Cspan class=\"shj-syn-func\">isOn\u003C\u002Fspan>(state\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> flag\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> user) {\n  \u003Cspan class=\"shj-syn-kwd\">if\u003C\u002Fspan> (state \u003Cspan class=\"shj-syn-oper\">===\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'on'\u003C\u002Fspan>) \u003Cspan class=\"shj-syn-kwd\">return\u003C\u002Fspan> \u003Cspan class=\"shj-syn-bool\">true\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-kwd\">if\u003C\u002Fspan> (state \u003Cspan class=\"shj-syn-oper\">!==\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'admins'\u003C\u002Fspan>) \u003Cspan class=\"shj-syn-kwd\">return\u003C\u002Fspan> \u003Cspan class=\"shj-syn-bool\">false\u003C\u002Fspan>\n  \u003Cspan class=\"shj-syn-kwd\">return\u003C\u002Fspan> user\u003Cspan class=\"shj-syn-oper\">?.\u003C\u002Fspan>isAdmin \u003Cspan class=\"shj-syn-oper\">||\u003C\u002Fspan> flag\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>allow\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">includes\u003C\u002Fspan>(user\u003Cspan class=\"shj-syn-oper\">?.\u003C\u002Fspan>id) \u003Cspan class=\"shj-syn-oper\">||\u003C\u002Fspan> flag\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>allow\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">includes\u003C\u002Fspan>(user\u003Cspan class=\"shj-syn-oper\">?.\u003C\u002Fspan>email\u003Cspan class=\"shj-syn-oper\">?.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">toLowerCase\u003C\u002Fspan>())\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Never send the secret from a browser.\u003C\u002Fp>\n\u003Ch3 id=\"from-a-browser\">From a browser\u003Ca class=\"heading-anchor\" href=\"#from-a-browser\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>Send the identity token, which gives you \u003Ccode>enabled\u003C\u002Fcode> for that user. Or send\n\u003Ccode>?pk=&lt;public key&gt;\u003C\u002Fcode> for an anonymous visitor, for whom \u003Ccode>admins\u003C\u002Fcode> flags are off.\nBoth forms evaluate the flag for you and never return the \u003Ccode>allow\u003C\u002Fcode> list:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-js\">\u003Ccode>\u003Cspan class=\"shj-syn-kwd\">const\u003C\u002Fspan> { flags } \u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-syn-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-syn-func\">fetch\u003C\u002Fspan>(\u003Cspan class=\"shj-syn-str\">'https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fv1\u002Fflags?target=frontend'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> {\n  headers\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> { authorization\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">`Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\">${\u003C\u002Fspan>identityToken\u003Cspan class=\"shj-syn-kwd\">}\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">`\u003C\u002Fspan> }\n})\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">then\u003C\u002Fspan>(r \u003Cspan class=\"shj-syn-kwd\">=&gt;\u003C\u002Fspan> r\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">json\u003C\u002Fspan>())\n\u003Cspan class=\"shj-syn-cmnt\">\u002F\u002F { ai_chat: { state: 'admins', enabled: true, fallback: false, targets: ['frontend'] } }\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Identity-token requests count toward the project's request budget, which is\n600 per minute shared by every user. For busy apps, read flags on your server\nand pass the result down to the browser.\u003C\u002Fp>\n\u003Ch2 id=\"caching-and-outages\">Caching and outages\u003Ca class=\"heading-anchor\" href=\"#caching-and-outages\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Flags change when an operator clicks, not per request, so don't fetch on every\nrequest:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Cache the answer for about 30 seconds.\u003C\u002Fli>\n\u003Cli>If a refresh fails, keep serving the last good answer for a short grace\nperiod (a couple of minutes), so a single blip doesn't flip features.\u003C\u002Fli>\n\u003Cli>After that, use each flag's \u003Ccode>fallback\u003C\u002Fcode>, which the same response gave you.\u003C\u002Fli>\n\u003Cli>If you have never reached HelpBites, use your own defaults.\u003C\u002Fli>\n\u003Cli>Treat a flag you don't know as off.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Changes reach an app that caches like this within about 30 seconds.\u003C\u002Fp>\n",[6,10,13,17,20],{"id":7,"text":8,"level":9},"a-flag","A flag",2,{"id":11,"text":12,"level":9},"reading-flags-get-v1flags","Reading flags: GET \u002Fv1\u002Fflags",{"id":14,"text":15,"level":16},"from-your-server-recommended","From your server (recommended)",3,{"id":18,"text":19,"level":16},"from-a-browser","From a browser",{"id":21,"text":22,"level":9},"caching-and-outages","Caching and outages",1792677543075]