[{"data":1,"prerenderedAt":2030},["ShallowReactive",2],{"bml-reference-islands":3},{"data":4,"body":5},{},{"type":6,"children":7},"root",[8,17,31,45,52,195,201,227,236,269,323,334,343,355,366,430,512,523,581,593,937,942,953,978,1037,1044,1062,1071,1089,1095,1114,1123,1162,1174,1180,1192,1201,1246,1255,1267,1273,1303,1309,1334,1356,1362,1421,1430,1442,1499,1504,1513,1562,1571,1583,1589,1594,1709,1719,1744,1753,1803,1819,1824,1833,1839,1871,1880,1913,1947,1972,1981,1999],{"type":9,"tag":10,"props":11,"children":13},"element","h1",{"id":12},"islands",[14],{"type":15,"value":16},"text","Islands",{"type":9,"tag":18,"props":19,"children":20},"p",{},[21,23,29],{"type":15,"value":22},"An ",{"type":9,"tag":24,"props":25,"children":26},"strong",{},[27],{"type":15,"value":28},"island",{"type":15,"value":30}," is a region that renders complete HTML on the server (SEO-safe) and\nthen mounts a small TypeScript component onto that existing DOM — progressive\nenhancement, never client-only content. (BML-SPEC-1 §9, BML-REQ-14.)",{"type":9,"tag":32,"props":33,"children":39},"pre",{"className":34,"code":36,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"language-bml","\u003Cisland name=\"sortable\" client=\"ts\" :id=\"id\">\n  \u003Cul ref=\"items\">\n    \u003Cfor item in listView.items>\n      \u003Cli :data-id=\"item.id\">{ item.label }\u003C\u002Fli>\n    \u003C\u002Ffor>\n  \u003C\u002Ful>\n\n  \u003Cscript client>\n    import Sortable from \"sortablejs\"\n    import { reorderList } from \".\u002Fgraphql\u002FReorderList\"\n\n    const id = ctx.props.id as string\n    const list = ctx.refs.items\n    const sortable = Sortable.create(list, {\n      group: ctx.scoped(\"items\"),         \u002F\u002F unique per instance — no cross-list dragging\n      onEnd: async () => {\n        const ids = [...list.children].map((li) => (li as HTMLElement).dataset.id!)\n        const { list: view } = await reorderList({ id, ids })\n        ctx.replace(list, view)           \u002F\u002F patch THIS instance's region\n      },\n    })\n    ctx.onUpdate(() => sortable.option(\"disabled\", false))  \u002F\u002F re-arm after a swap\n    ctx.onUnmount(() => sortable.destroy())\n  \u003C\u002Fscript>\n\u003C\u002Fisland>\n","bml","",[40],{"type":9,"tag":41,"props":42,"children":43},"code",{"__ignoreMap":38},[44],{"type":15,"value":36},{"type":9,"tag":46,"props":47,"children":49},"h2",{"id":48},"attributes",[50],{"type":15,"value":51},"Attributes",{"type":9,"tag":53,"props":54,"children":55},"table",{},[56,75],{"type":9,"tag":57,"props":58,"children":59},"thead",{},[60],{"type":9,"tag":61,"props":62,"children":63},"tr",{},[64,70],{"type":9,"tag":65,"props":66,"children":67},"th",{},[68],{"type":15,"value":69},"Attribute",{"type":9,"tag":65,"props":71,"children":72},{},[73],{"type":15,"value":74},"Meaning",{"type":9,"tag":76,"props":77,"children":78},"tbody",{},[79,96,119,135,165],{"type":9,"tag":61,"props":80,"children":81},{},[82,91],{"type":9,"tag":83,"props":84,"children":85},"td",{},[86],{"type":9,"tag":41,"props":87,"children":88},{"className":38},[89],{"type":15,"value":90},"name",{"type":9,"tag":83,"props":92,"children":93},{},[94],{"type":15,"value":95},"the island's name within its page\u002Fcomponent",{"type":9,"tag":61,"props":97,"children":98},{},[99,107],{"type":9,"tag":83,"props":100,"children":101},{},[102],{"type":9,"tag":41,"props":103,"children":104},{"className":38},[105],{"type":15,"value":106},"client=\"ts\"",{"type":9,"tag":83,"props":108,"children":109},{},[110,112,117],{"type":15,"value":111},"mount the inner ",{"type":9,"tag":41,"props":113,"children":114},{"className":38},[115],{"type":15,"value":116},"\u003Cscript client>",{"type":15,"value":118}," module on the web target",{"type":9,"tag":61,"props":120,"children":121},{},[122,130],{"type":9,"tag":83,"props":123,"children":124},{},[125],{"type":9,"tag":41,"props":126,"children":127},{"className":38},[128],{"type":15,"value":129},"hydrate=\"load|idle|visible\"",{"type":9,"tag":83,"props":131,"children":132},{},[133],{"type":15,"value":134},"reserved mount policy; the current runtime mounts on load",{"type":9,"tag":61,"props":136,"children":137},{},[138,146],{"type":9,"tag":83,"props":139,"children":140},{},[141],{"type":9,"tag":41,"props":142,"children":143},{"className":38},[144],{"type":15,"value":145},"render=\"request|prerender|deferred\"",{"type":9,"tag":83,"props":147,"children":148},{},[149,151,156,158,163],{"type":15,"value":150},"eager SSR (",{"type":9,"tag":41,"props":152,"children":153},{"className":38},[154],{"type":15,"value":155},"request",{"type":15,"value":157},"; ",{"type":9,"tag":41,"props":159,"children":160},{"className":38},[161],{"type":15,"value":162},"prerender",{"type":15,"value":164}," is currently equivalent) or a private render after the shell loads",{"type":9,"tag":61,"props":166,"children":167},{},[168,183],{"type":9,"tag":83,"props":169,"children":170},{},[171,176,178],{"type":9,"tag":41,"props":172,"children":173},{"className":38},[174],{"type":15,"value":175},":prop=\"expr\"",{"type":15,"value":177}," \u002F ",{"type":9,"tag":41,"props":179,"children":180},{"className":38},[181],{"type":15,"value":182},"prop=\"literal\"",{"type":9,"tag":83,"props":184,"children":185},{},[186,188,193],{"type":15,"value":187},"props serialized to the client (",{"type":9,"tag":41,"props":189,"children":190},{"className":38},[191],{"type":15,"value":192},"ctx.props.\u003Cname>",{"type":15,"value":194},")",{"type":9,"tag":46,"props":196,"children":198},{"id":197},"deferred-server-rendering",[199],{"type":15,"value":200},"Deferred server rendering",{"type":9,"tag":18,"props":202,"children":203},{},[204,206,211,213,218,220,225],{"type":15,"value":205},"Use ",{"type":9,"tag":41,"props":207,"children":208},{"className":38},[209],{"type":15,"value":210},"render=\"deferred\"",{"type":15,"value":212}," when an island's server-rendered HTML must be kept out of a cacheable page\nresponse. The initial response contains the island boundary and its ",{"type":9,"tag":41,"props":214,"children":215},{"className":38},[216],{"type":15,"value":217},"\u003Cfallback>",{"type":15,"value":219}," only. Once the\nbrowser runtime starts, it posts the boundary's explicit props and current page context to BML Server.\nBML Server resolves the caller's current token, installation, analytics session, route parameters,\nquery, and locale, then renders the island body. The fragment response always uses\n",{"type":9,"tag":41,"props":221,"children":222},{"className":38},[223],{"type":15,"value":224},"Cache-Control: private, no-store",{"type":15,"value":226},".",{"type":9,"tag":32,"props":228,"children":231},{"className":229,"code":230,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cpage route=\"\u002Faccount\u002F{accountId}\" cache=\"shared\" maxAge=\"30\" staleWhileRevalidate=\"300\">\n  \u003Chtml>\n    \u003Chead>\u003Ctitle>Account\u003C\u002Ftitle>\u003C\u002Fhead>\n    \u003Cbody>\n      \u003Ch1>Account\u003C\u002Fh1>\n\n      \u003Cisland name=\"account-summary\" render=\"deferred\" :id=\"accountId\">\n        \u003Cprop name=\"id\" type=\"String\" required\u002F>\n\n        \u003Cfallback>\n          \u003Csection aria-live=\"polite\">\n            \u003Cp>Loading account…\u003C\u002Fp>\n            \u003Cbutton type=\"button\" data-bml-deferred-retry>Retry\u003C\u002Fbutton>\n          \u003C\u002Fsection>\n        \u003C\u002Ffallback>\n\n        \u003Cscript server provides=\"account\">loadAccount(id)\u003C\u002Fscript>\n        \u003Csection>\n          \u003Ch2>{ account.displayName }\u003C\u002Fh2>\n          \u003Cp>{ account.summary }\u003C\u002Fp>\n        \u003C\u002Fsection>\n      \u003C\u002Fisland>\n    \u003C\u002Fbody>\n  \u003C\u002Fhtml>\n\u003C\u002Fpage>\n",[232],{"type":9,"tag":41,"props":233,"children":234},{"__ignoreMap":38},[235],{"type":15,"value":230},{"type":9,"tag":18,"props":237,"children":238},{},[239,241,246,248,253,255,260,262,267],{"type":15,"value":240},"Each deferred input needs a direct ",{"type":9,"tag":41,"props":242,"children":243},{"className":38},[244],{"type":15,"value":245},"\u003Cprop>",{"type":15,"value":247}," declaration and a matching island attribute. Props are\nthe only values copied from the shell render into the later request; enclosing page\u002Fcomponent local\nvariables do not cross that boundary. Route params are bound again from the posted pathname, and\nrequest data remains available through ",{"type":9,"tag":41,"props":249,"children":250},{"className":38},[251],{"type":15,"value":252},"RenderContext",{"type":15,"value":254},". Deferred props must be JSON-shaped values:\nstrings, booleans, finite numbers, null, lists, primitive arrays, and string-keyed maps. BML's wire\nformat preserves Kotlin numeric, character, list, map, and primitive-array types for the deferred\nrenderer, including inside lists and maps. Client scripts receive Kotlin ",{"type":9,"tag":41,"props":256,"children":257},{"className":38},[258],{"type":15,"value":259},"Long",{"type":15,"value":261}," values as JavaScript\n",{"type":9,"tag":41,"props":263,"children":264},{"className":38},[265],{"type":15,"value":266},"bigint",{"type":15,"value":268}," values so values outside JavaScript's safe-integer range remain exact. Declare those wire\ntypes directly: type aliases and custom application types must be expanded to their supported\nJSON-shaped type. On a shared page these props are part of the public cached shell, so they must not\ncontain private data.",{"type":9,"tag":18,"props":270,"children":271},{},[272,274,279,281,286,288,293,295,300,302,307,309,314,316,321],{"type":15,"value":273},"The fallback stays in place if the request fails. It is static server-rendered markup; the compiler\nrejects client scripts and declarative ",{"type":9,"tag":41,"props":275,"children":276},{"className":38},[277],{"type":15,"value":278},"@event",{"type":15,"value":280}," actions there, including behavior introduced through\ncomponents. Client refs belong in the deferred\nbody, which mounts after replacement. The boundary receives\n",{"type":9,"tag":41,"props":282,"children":283},{"className":38},[284],{"type":15,"value":285},"data-bml-deferred-state=\"error\"",{"type":15,"value":287}," and ",{"type":9,"tag":41,"props":289,"children":290},{"className":38},[291],{"type":15,"value":292},"data-bml-deferred-error",{"type":15,"value":294},"; an element marked\n",{"type":9,"tag":41,"props":296,"children":297},{"className":38},[298],{"type":15,"value":299},"data-bml-deferred-retry",{"type":15,"value":301}," retries only its nearest boundary. ",{"type":9,"tag":41,"props":303,"children":304},{"className":38},[305],{"type":15,"value":306},"refreshDeferred(root?)",{"type":15,"value":308}," requests a fresh\nrender for the current identity. After a completed sign-in or sign-out, call\n",{"type":9,"tag":41,"props":310,"children":311},{"className":38},[312],{"type":15,"value":313},"clearBmlClientState()",{"type":15,"value":315}," so BML replaces the old identity's server session and reloads the page to\nrecompute shell markup, deferred props, and fallback content. Identity cleanup and\nback\u002Fforward cache restoration clear\ninserted private DOM before reloading it. Sibling deferred boundaries load concurrently. When deferred\ncontent uses ",{"type":9,"tag":41,"props":317,"children":318},{"className":38},[319],{"type":15,"value":320},"server-session",{"type":15,"value":322}," state, the page response establishes that session before the browser starts\nthe deferred requests; those requests never create or replace it, and a successful stateful render renews\nthe same cookie. Such a page is private and cannot use shared shell caching. Eager islands and actions\noutside deferred boundaries mount while the private requests are still in flight. Nested deferred\nboundaries are discovered after their parent fragment arrives.",{"type":9,"tag":18,"props":324,"children":325},{},[326,328,332],{"type":15,"value":327},"Server actions work inside deferred content. Declare the live model inside the deferred scope so its\ninitialization, state marker, dispatcher, and optional ",{"type":9,"tag":41,"props":329,"children":330},{"className":38},[331],{"type":15,"value":320},{"type":15,"value":333}," state are all created by the\nprivate request:",{"type":9,"tag":32,"props":335,"children":338},{"className":336,"code":337,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cisland name=\"private-cart\" render=\"deferred\">\n  \u003Cscript server provides=\"cart\" scope=\"server-session\">my.site.CartModel()\u003C\u002Fscript>\n  \u003Cisland name=\"cart-view\">\n    \u003Cp>{ cart.itemCount } items\u003C\u002Fp>\n    \u003Cbutton @click=\"cart.clear\">Clear\u003C\u002Fbutton>\n  \u003C\u002Fisland>\n\u003C\u002Fisland>\n",[339],{"type":9,"tag":41,"props":340,"children":341},{"__ignoreMap":38},[342],{"type":15,"value":337},{"type":9,"tag":18,"props":344,"children":345},{},[346,348,353],{"type":15,"value":347},"Shared page caching is an independent opt-in. For example,\n",{"type":9,"tag":41,"props":349,"children":350},{"className":38},[351],{"type":15,"value":352},"cache=\"shared\" maxAge=\"30\" staleWhileRevalidate=\"300\"",{"type":15,"value":354}," renders the successful HTML shell in\npublic\u002Fanonymous context and sends:",{"type":9,"tag":32,"props":356,"children":361},{"className":357,"code":359,"filename":-1,"highlights":-1,"language":360,"meta":38},[358],"language-http","Cache-Control: public, max-age=0, must-revalidate\nCloudflare-CDN-Cache-Control: public, max-age=30, stale-while-revalidate=300\nETag: \"\u003Cstrong validator>\"\nVary: Accept-Language\n","http",[362],{"type":9,"tag":41,"props":363,"children":364},{"__ignoreMap":38},[365],{"type":15,"value":359},{"type":9,"tag":18,"props":367,"children":368},{},[369,374,376,381,383,388,390,395,397,401,403,408,409,414,416,421,423,428],{"type":9,"tag":41,"props":370,"children":371},{"className":38},[372],{"type":15,"value":373},"staleWhileRevalidate",{"type":15,"value":375}," defaults to ",{"type":9,"tag":41,"props":377,"children":378},{"className":38},[379],{"type":15,"value":380},"maxAge",{"type":15,"value":382},". Once the fresh interval expires, Cloudflare may serve\nthe cached shell immediately while it conditionally revalidates in the background. ",{"type":9,"tag":41,"props":384,"children":385},{"className":38},[386],{"type":15,"value":387},"s-maxage",{"type":15,"value":389}," is not\nsent because it implies proxy revalidation and prevents this stale response. The shell cannot\nuse ",{"type":9,"tag":41,"props":391,"children":392},{"className":38},[393],{"type":15,"value":394},"requireAuth",{"type":15,"value":396},", eager ",{"type":9,"tag":41,"props":398,"children":399},{"className":38},[400],{"type":15,"value":320},{"type":15,"value":402}," state, or identity-based feature flags. It receives no caller\ntoken, cookies, installation ID, or analytics session, and emits no per-visitor cookies. Query values\nremain part of the URL cache key. Locale varies by ",{"type":9,"tag":41,"props":404,"children":405},{"className":38},[406],{"type":15,"value":407},"?lang",{"type":15,"value":287},{"type":9,"tag":41,"props":410,"children":411},{"className":38},[412],{"type":15,"value":413},"Accept-Language",{"type":15,"value":415},"; the visitor locale\ncookie is deliberately ignored, and the response includes ",{"type":9,"tag":41,"props":417,"children":418},{"className":38},[419],{"type":15,"value":420},"Vary: Accept-Language",{"type":15,"value":422},". Development\nresponses and every error, redirect, or not-found outcome use ",{"type":9,"tag":41,"props":424,"children":425},{"className":38},[426],{"type":15,"value":427},"no-store",{"type":15,"value":429}," instead.",{"type":9,"tag":18,"props":431,"children":432},{},[433,435,440,442,447,449,454,456,461,462,467,469,474,476,480,482,486,488,492,493,497,499,503,505,510],{"type":15,"value":434},"By default BML hashes the completed public shell for its strong ",{"type":9,"tag":41,"props":436,"children":437},{"className":38},[438],{"type":15,"value":439},"ETag",{"type":15,"value":441},". Applications that keep\nBosca-backed public data in memory should pass a ",{"type":9,"tag":41,"props":443,"children":444},{"className":38},[445],{"type":15,"value":446},"BmlSharedCacheRevisionProvider",{"type":15,"value":448}," to ",{"type":9,"tag":41,"props":450,"children":451},{"className":38},[452],{"type":15,"value":453},"BmlServer",{"type":15,"value":455},".\nFor a page backed by one metadata or collection result, return its Bosca ",{"type":9,"tag":41,"props":457,"children":458},{"className":38},[459],{"type":15,"value":460},"etag",{"type":15,"value":287},{"type":9,"tag":41,"props":463,"children":464},{"className":38},[465],{"type":15,"value":466},"modified",{"type":15,"value":468},"\ninstant. For a list, ",{"type":9,"tag":41,"props":470,"children":471},{"className":38},[472],{"type":15,"value":473},"BmlSharedCacheRevision.fromNewestModified",{"type":15,"value":475}," selects the newest ",{"type":9,"tag":41,"props":477,"children":478},{"className":38},[479],{"type":15,"value":466},{"type":15,"value":481},"\ninstant and combines the ",{"type":9,"tag":41,"props":483,"children":484},{"className":38},[485],{"type":15,"value":460},{"type":15,"value":487}," values of every item tied at that instant; every visible item must\nsupply both values or the helper falls back to a completed-body validator. That list rule is valid\nwhen every content or membership change advances a visible item; otherwise use the containing\ncollection's ",{"type":9,"tag":41,"props":489,"children":490},{"className":38},[491],{"type":15,"value":460},{"type":15,"value":287},{"type":9,"tag":41,"props":494,"children":495},{"className":38},[496],{"type":15,"value":466},{"type":15,"value":498}," values. BML combines\nboth validator values with the route variant and a deterministic deployment revision covering the\nproject version, generated page and component source, asset map, and bundled CSS\u002FJS bytes. Replicas\nwith the same deployment therefore produce the same shell ",{"type":9,"tag":41,"props":500,"children":501},{"className":38},[502],{"type":15,"value":439},{"type":15,"value":504},". For a site without a localization\nsource, BML can answer a matching ",{"type":9,"tag":41,"props":506,"children":507},{"className":38},[508],{"type":15,"value":509},"If-None-Match",{"type":15,"value":511}," with 304 before rendering or GraphQL work. Localized\nsites render before validation so the validator covers the exact catalog snapshot used by the shell.\nBML verifies a pre-render data revision again after rendering and hashes the completed body if the\ncached snapshot changed during the render. After a\nBosca change event, update or evict the in-memory value and its validator\ntogether. Cloudflare observes it on the first request after the fresh interval expires; that\ntriggering request still receives the old shell while the background revalidation completes.",{"type":9,"tag":32,"props":513,"children":518},{"className":514,"code":516,"filename":-1,"highlights":-1,"language":517,"meta":38},[515],"language-kotlin","BmlServer(\n    project = project,\n    pages = BmlPages.all,\n    sharedCacheRevisionProvider = { request ->\n        publicPageCache.revision(request.pageRoute, request.params, request.query, request.locale)\n            ?.let { cached ->\n                BmlSharedCacheRevision(\n                    etag = cached.etag,\n                    lastModified = cached.modified,\n                )\n            }\n    },\n)\n","kotlin",[519],{"type":9,"tag":41,"props":520,"children":521},{"__ignoreMap":38},[522],{"type":15,"value":516},{"type":9,"tag":18,"props":524,"children":525},{},[526,528,533,535,540,542,546,548,553,555,560,562,567,569,573,575,579],{"type":15,"value":527},"Deferred islands do not make a page public by themselves. An ordinary page can use deferred islands\nwithout ",{"type":9,"tag":41,"props":529,"children":530},{"className":38},[531],{"type":15,"value":532},"cache=\"shared\"",{"type":15,"value":534},", and a shared page still needs the same public-data review as any other edge\ncached response. CDN rules must bypass ",{"type":9,"tag":41,"props":536,"children":537},{"className":38},[538],{"type":15,"value":539},"\u002F_bml\u002F**",{"type":15,"value":541},", authentication, action, and proxy requests. Purge\ncached shells when a deployment changes generated renderer IDs or referenced asset versions. The\nCloudflare Cache Rule must mark only reviewed public shell routes eligible, respect origin cache\nheaders, avoid an Edge Cache TTL override, and exclude ",{"type":9,"tag":41,"props":543,"children":544},{"className":38},[545],{"type":15,"value":539},{"type":15,"value":547},", GraphQL\u002Fproxy, authentication,\naction, and other private routes. In that rule's ",{"type":9,"tag":24,"props":549,"children":550},{},[551],{"type":15,"value":552},"Vary",{"type":15,"value":554}," settings, configure ",{"type":9,"tag":41,"props":556,"children":557},{"className":38},[558],{"type":15,"value":559},"accept-language",{"type":15,"value":561}," with\nthe ",{"type":9,"tag":41,"props":563,"children":564},{"className":38},[565],{"type":15,"value":566},"normalize",{"type":15,"value":568}," action. Cloudflare does not add ",{"type":9,"tag":41,"props":570,"children":571},{"className":38},[572],{"type":15,"value":413},{"type":15,"value":574}," to its cache key from the response\nheader alone; both the rule setting and BML's ",{"type":9,"tag":41,"props":576,"children":577},{"className":38},[578],{"type":15,"value":420},{"type":15,"value":580}," response are required.",{"type":9,"tag":46,"props":582,"children":584},{"id":583},"client-runtime-boscabml",[585,587,592],{"type":15,"value":586},"Client runtime (",{"type":9,"tag":41,"props":588,"children":589},{"className":38},[590],{"type":15,"value":591},"@bosca\u002Fbml",{"type":15,"value":194},{"type":9,"tag":53,"props":594,"children":595},{},[596,612],{"type":9,"tag":57,"props":597,"children":598},{},[599],{"type":9,"tag":61,"props":600,"children":601},{},[602,607],{"type":9,"tag":65,"props":603,"children":604},{},[605],{"type":15,"value":606},"API",{"type":9,"tag":65,"props":608,"children":609},{},[610],{"type":15,"value":611},"Purpose",{"type":9,"tag":76,"props":613,"children":614},{},[615,636,658,674,696,731,747,763,786,807,829,851,866,882,898,914],{"type":9,"tag":61,"props":616,"children":617},{},[618,626],{"type":9,"tag":83,"props":619,"children":620},{},[621],{"type":9,"tag":41,"props":622,"children":623},{"className":38},[624],{"type":15,"value":625},"defineIsland(name, (ctx) => …)",{"type":9,"tag":83,"props":627,"children":628},{},[629,631],{"type":15,"value":630},"register an island's client setup; runs once per instance with its own ",{"type":9,"tag":41,"props":632,"children":633},{"className":38},[634],{"type":15,"value":635},"ctx",{"type":9,"tag":61,"props":637,"children":638},{},[639,647],{"type":9,"tag":83,"props":640,"children":641},{},[642],{"type":9,"tag":41,"props":643,"children":644},{"className":38},[645],{"type":15,"value":646},"defineComponent(tag, (ctx) => …)",{"type":9,"tag":83,"props":648,"children":649},{},[650,652,657],{"type":15,"value":651},"register a wrapper-free component setup (normally compiler-generated from ",{"type":9,"tag":41,"props":653,"children":654},{"className":38},[655],{"type":15,"value":656},"\u003Cscript client scoped>",{"type":15,"value":194},{"type":9,"tag":61,"props":659,"children":660},{},[661,669],{"type":9,"tag":83,"props":662,"children":663},{},[664],{"type":9,"tag":41,"props":665,"children":666},{"className":38},[667],{"type":15,"value":668},"ctx.root",{"type":9,"tag":83,"props":670,"children":671},{},[672],{"type":15,"value":673},"this instance's root element (scope DOM access here)",{"type":9,"tag":61,"props":675,"children":676},{},[677,691],{"type":9,"tag":83,"props":678,"children":679},{},[680,685,686],{"type":9,"tag":41,"props":681,"children":682},{"className":38},[683],{"type":15,"value":684},"ctx.props",{"type":15,"value":177},{"type":9,"tag":41,"props":687,"children":688},{"className":38},[689],{"type":15,"value":690},"ctx.id",{"type":9,"tag":83,"props":692,"children":693},{},[694],{"type":15,"value":695},"server-passed props \u002F unique instance id",{"type":9,"tag":61,"props":697,"children":698},{},[699,719],{"type":9,"tag":83,"props":700,"children":701},{},[702,707,708,713,714],{"type":9,"tag":41,"props":703,"children":704},{"className":38},[705],{"type":15,"value":706},"ctx.refs",{"type":15,"value":177},{"type":9,"tag":41,"props":709,"children":710},{"className":38},[711],{"type":15,"value":712},"ctx.ref(name)",{"type":15,"value":177},{"type":9,"tag":41,"props":715,"children":716},{"className":38},[717],{"type":15,"value":718},"ctx.refsAll(name)",{"type":9,"tag":83,"props":720,"children":721},{},[722,724,729],{"type":15,"value":723},"compiler-typed ",{"type":9,"tag":41,"props":725,"children":726},{"className":38},[727],{"type":15,"value":728},"ref=\"…\"",{"type":15,"value":730}," elements \u002F dynamic or repeated lookup",{"type":9,"tag":61,"props":732,"children":733},{},[734,742],{"type":9,"tag":83,"props":735,"children":736},{},[737],{"type":9,"tag":41,"props":738,"children":739},{"className":38},[740],{"type":15,"value":741},"ctx.on(target, type, listener)",{"type":9,"tag":83,"props":743,"children":744},{},[745],{"type":15,"value":746},"add an event listener with automatic unmount cleanup",{"type":9,"tag":61,"props":748,"children":749},{},[750,758],{"type":9,"tag":83,"props":751,"children":752},{},[753],{"type":9,"tag":41,"props":754,"children":755},{"className":38},[756],{"type":15,"value":757},"ctx.dispatch(model.method(args…), options?)",{"type":9,"tag":83,"props":759,"children":760},{},[761],{"type":15,"value":762},"call this scope's server model; the compiler generates and types the dispatcher",{"type":9,"tag":61,"props":764,"children":765},{},[766,774],{"type":9,"tag":83,"props":767,"children":768},{},[769],{"type":9,"tag":41,"props":770,"children":771},{"className":38},[772],{"type":15,"value":773},"ctx.scoped(name)",{"type":9,"tag":83,"props":775,"children":776},{},[777,779,784],{"type":15,"value":778},"namespaced key (Sortable ",{"type":9,"tag":41,"props":780,"children":781},{"className":38},[782],{"type":15,"value":783},"group",{"type":15,"value":785},", storage, events)",{"type":9,"tag":61,"props":787,"children":788},{},[789,797],{"type":9,"tag":83,"props":790,"children":791},{},[792],{"type":9,"tag":41,"props":793,"children":794},{"className":38},[795],{"type":15,"value":796},"ctx.replace(target, html)",{"type":9,"tag":83,"props":798,"children":799},{},[800,802],{"type":15,"value":801},"patch a region (Element or root-relative selector) from server HTML, then fire ",{"type":9,"tag":41,"props":803,"children":804},{"className":38},[805],{"type":15,"value":806},"onUpdate",{"type":9,"tag":61,"props":808,"children":809},{},[810,824],{"type":9,"tag":83,"props":811,"children":812},{},[813,818,819],{"type":9,"tag":41,"props":814,"children":815},{"className":38},[816],{"type":15,"value":817},"ctx.onUpdate(cb)",{"type":15,"value":177},{"type":9,"tag":41,"props":820,"children":821},{"className":38},[822],{"type":15,"value":823},"ctx.onUnmount(cb)",{"type":9,"tag":83,"props":825,"children":826},{},[827],{"type":15,"value":828},"re-arm after a replace \u002F cleanup",{"type":9,"tag":61,"props":830,"children":831},{},[832,846],{"type":9,"tag":83,"props":833,"children":834},{},[835,840,841],{"type":9,"tag":41,"props":836,"children":837},{"className":38},[838],{"type":15,"value":839},"mountAll(scope?)",{"type":15,"value":177},{"type":9,"tag":41,"props":842,"children":843},{"className":38},[844],{"type":15,"value":845},"unmountAll(scope?)",{"type":9,"tag":83,"props":847,"children":848},{},[849],{"type":15,"value":850},"mount\u002Funmount islands under a scope",{"type":9,"tag":61,"props":852,"children":853},{},[854,861],{"type":9,"tag":83,"props":855,"children":856},{},[857],{"type":9,"tag":41,"props":858,"children":859},{"className":38},[860],{"type":15,"value":306},{"type":9,"tag":83,"props":862,"children":863},{},[864],{"type":15,"value":865},"privately re-render one deferred boundary or all deferred boundaries",{"type":9,"tag":61,"props":867,"children":868},{},[869,877],{"type":9,"tag":83,"props":870,"children":871},{},[872],{"type":9,"tag":41,"props":873,"children":874},{"className":38},[875],{"type":15,"value":876},"renderFragment(component, props)",{"type":9,"tag":83,"props":878,"children":879},{},[880],{"type":15,"value":881},"re-render a component on the server and get its HTML (sliver update)",{"type":9,"tag":61,"props":883,"children":884},{},[885,893],{"type":9,"tag":83,"props":886,"children":887},{},[888],{"type":9,"tag":41,"props":889,"children":890},{"className":38},[891],{"type":15,"value":892},"bosca.query \u002F bosca.mutate",{"type":9,"tag":83,"props":894,"children":895},{},[896],{"type":15,"value":897},"typed GraphQL against the configured endpoint (token via the auth library)",{"type":9,"tag":61,"props":899,"children":900},{},[901,909],{"type":9,"tag":83,"props":902,"children":903},{},[904],{"type":9,"tag":41,"props":905,"children":906},{"className":38},[907],{"type":15,"value":908},"configureBosca({ endpoint, getToken, getInstallationId, getAnalyticsSessionId })",{"type":9,"tag":83,"props":910,"children":911},{},[912],{"type":15,"value":913},"set the GraphQL endpoint, token provider, and optional installation and analytics session providers",{"type":9,"tag":61,"props":915,"children":916},{},[917,925],{"type":9,"tag":83,"props":918,"children":919},{},[920],{"type":9,"tag":41,"props":921,"children":922},{"className":38},[923],{"type":15,"value":924},"bmlContractCall(name, method, args)",{"type":9,"tag":83,"props":926,"children":927},{},[928,930,935],{"type":15,"value":929},"call a ",{"type":9,"tag":41,"props":931,"children":932},{"className":38},[933],{"type":15,"value":934},"\u003Ccontract>",{"type":15,"value":936}," method (optional server-side composition)",{"type":9,"tag":18,"props":938,"children":939},{},[940],{"type":15,"value":941},"After initializing browser analytics, connect its sink to BML in the site's client entry:",{"type":9,"tag":32,"props":943,"children":948},{"className":944,"code":946,"filename":-1,"highlights":-1,"language":947,"meta":38},[945],"language-ts","import { configureBosca } from '@bosca\u002Fbml'\n\n\u002F\u002F `sink` is the BoscaSink returned by the site's analytics initialization.\nconfigureBosca({\n  getInstallationId: () => sink.installationId,\n  getAnalyticsSessionId: () => sink.sessionId,\n})\n","ts",[949],{"type":9,"tag":41,"props":950,"children":951},{"__ignoreMap":38},[952],{"type":15,"value":946},{"type":9,"tag":18,"props":954,"children":955},{},[956,958,963,964,969,971,976],{"type":15,"value":957},"BML reads the getters for each GraphQL, action, contract, and fragment request and attaches\n",{"type":9,"tag":41,"props":959,"children":960},{"className":38},[961],{"type":15,"value":962},"X-Installation-ID",{"type":15,"value":287},{"type":9,"tag":41,"props":965,"children":966},{"className":38},[967],{"type":15,"value":968},"X-BA-Session-ID",{"type":15,"value":970}," when provided. The server uses a valid installation header\nbefore the ",{"type":9,"tag":41,"props":972,"children":973},{"className":38},[974],{"type":15,"value":975},"bml_iid",{"type":15,"value":977}," cookie and forwards both identities to GraphQL, including calls made during\nrendering. Missing or blank IDs add no header.",{"type":9,"tag":18,"props":979,"children":980},{},[981,983,987,989,994,996,1001,1003,1008,1010,1015,1017,1022,1024,1029,1031,1035],{"type":15,"value":982},"BML's request lifecycle resolves the analytics session from ",{"type":9,"tag":41,"props":984,"children":985},{"className":38},[986],{"type":15,"value":968},{"type":15,"value":988},", then the\n",{"type":9,"tag":41,"props":990,"children":991},{"className":38},[992],{"type":15,"value":993},"bml_asid",{"type":15,"value":995}," cookie. A normal private page render generates a ULID when neither supplies an ID. A shared\nshell cannot carry that cookie, so its runtime makes one private ",{"type":9,"tag":41,"props":997,"children":998},{"className":38},[999],{"type":15,"value":1000},"\u002F_bml\u002Fidentity",{"type":15,"value":1002}," request when no\nbrowser analytics identity exists, then starts all deferred renders concurrently. Deferred render\nrequests accept the established installation and analytics identities but never create either one.\nOnly the identity bootstrap sets the generated ID and an initial five-minute deadline\n(",{"type":9,"tag":41,"props":1004,"children":1005},{"className":38},[1006],{"type":15,"value":1007},"bml_asid_exp",{"type":15,"value":1009},") as browser session cookies, separate from the ",{"type":9,"tag":41,"props":1011,"children":1012},{"className":38},[1013],{"type":15,"value":1014},"bml_session",{"type":15,"value":1016}," island cookie. Existing\nIDs are forwarded without setting either cookie or interpreting their deadline; expiration and\nrotation belong to the client.\nNeither cookie has ",{"type":9,"tag":41,"props":1018,"children":1019},{"className":38},[1020],{"type":15,"value":1021},"Max-Age",{"type":15,"value":1023}," or ",{"type":9,"tag":41,"props":1025,"children":1026},{"className":38},[1027],{"type":15,"value":1028},"Expires",{"type":15,"value":1030},". Browser\nanalytics reads ",{"type":9,"tag":41,"props":1032,"children":1033},{"className":38},[1034],{"type":15,"value":993},{"type":15,"value":1036}," once during initialization. The SDK then owns session rotation and writes\nnew IDs back to that cookie. Activity advances the persisted deadline. Later page navigations\nreuse an unexpired session; an expired or missing deadline starts a new one. Explicit session\nheaders remain authoritative for client requests.\nAnonymous analytics neither reads nor updates this shared cookie.",{"type":9,"tag":1038,"props":1039,"children":1041},"h3",{"id":1040},"wrapper-free-component-setup",[1042],{"type":15,"value":1043},"Wrapper-free component setup",{"type":9,"tag":18,"props":1045,"children":1046},{},[1047,1049,1053,1055,1060],{"type":15,"value":1048},"Put ",{"type":9,"tag":41,"props":1050,"children":1051},{"className":38},[1052],{"type":15,"value":656},{"type":15,"value":1054}," in a component when its behavior belongs to each component instance.\nBML marks the component's existing root (it adds no wrapper), generates DOM types for authored refs,\nand unmounts listeners registered with ",{"type":9,"tag":41,"props":1056,"children":1057},{"className":38},[1058],{"type":15,"value":1059},"ctx.on",{"type":15,"value":1061}," when the root leaves the document:",{"type":9,"tag":32,"props":1063,"children":1066},{"className":1064,"code":1065,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Ccomponent tag=\"copy-button\">\n  \u003Cbutton ref=\"button\" type=\"button\">Copy\u003C\u002Fbutton>\n  \u003Cscript client scoped>\n    const button = ctx.refs.button \u002F\u002F HTMLButtonElement\n    ctx.on\u003CMouseEvent>(button, \"click\", () => navigator.clipboard.writeText(location.href))\n  \u003C\u002Fscript>\n\u003C\u002Fcomponent>\n",[1067],{"type":9,"tag":41,"props":1068,"children":1069},{"__ignoreMap":38},[1070],{"type":15,"value":1065},{"type":9,"tag":18,"props":1072,"children":1073},{},[1074,1076,1081,1083,1087],{"type":15,"value":1075},"Refs are root-local and may sit on the component root itself. Use ",{"type":9,"tag":41,"props":1077,"children":1078},{"className":38},[1079],{"type":15,"value":1080},"refsAll",{"type":15,"value":1082}," for a ref authored in a\nloop. A page-level ",{"type":9,"tag":41,"props":1084,"children":1085},{"className":38},[1086],{"type":15,"value":116},{"type":15,"value":1088}," remains a normal module for genuinely page-wide behavior.",{"type":9,"tag":1038,"props":1090,"children":1092},{"id":1091},"preserving-dom-across-updates",[1093],{"type":15,"value":1094},"Preserving DOM across updates",{"type":9,"tag":18,"props":1096,"children":1097},{},[1098,1100,1105,1107,1112],{"type":15,"value":1099},"Declarative actions and ",{"type":9,"tag":41,"props":1101,"children":1102},{"className":38},[1103],{"type":15,"value":1104},"ctx.replace",{"type":15,"value":1106}," normally replace the rendered region. Add a stable\n",{"type":9,"tag":41,"props":1108,"children":1109},{"className":38},[1110],{"type":15,"value":1111},"data-bml-preserve",{"type":15,"value":1113}," key when an element's existing DOM should survive that update:",{"type":9,"tag":32,"props":1115,"children":1118},{"className":1116,"code":1117,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cfor item in feed.items>\n  \u003Carticle data-bml-preserve=\"item-{ item.id }\">…\u003C\u002Farticle>\n\u003C\u002Ffor>\n",[1119],{"type":9,"tag":41,"props":1120,"children":1121},{"__ignoreMap":38},[1122],{"type":15,"value":1117},{"type":9,"tag":18,"props":1124,"children":1125},{},[1126,1128,1133,1135,1140,1142,1147,1149,1154,1155,1160],{"type":15,"value":1127},"When the next server fragment contains the same key on the same element type, BML moves the\nexisting element into its new position instead of recreating it. Its root attributes are refreshed\nfrom the server, while its child DOM, focus, media state, and client enhancements remain intact.\nKeys must be unique within the updated region. Retained nodes receive ",{"type":9,"tag":41,"props":1129,"children":1130},{"className":38},[1131],{"type":15,"value":1132},"data-bml-retained",{"type":15,"value":1134},", while\nnew preservation roots receive ",{"type":9,"tag":41,"props":1136,"children":1137},{"className":38},[1138],{"type":15,"value":1139},"data-bml-added",{"type":15,"value":1141},"; these markers can suppress old one-shot entrance\nanimations and highlight only the new batch. ",{"type":9,"tag":41,"props":1143,"children":1144},{"className":38},[1145],{"type":15,"value":1146},"ctx.onUpdate",{"type":15,"value":1148}," receives the same ",{"type":9,"tag":41,"props":1150,"children":1151},{"className":38},[1152],{"type":15,"value":1153},"added",{"type":15,"value":287},{"type":9,"tag":41,"props":1156,"children":1157},{"className":38},[1158],{"type":15,"value":1159},"retained",{"type":15,"value":1161},"\npreservation roots.",{"type":9,"tag":18,"props":1163,"children":1164},{},[1165,1167,1172],{"type":15,"value":1166},"Declarative action elements also receive ",{"type":9,"tag":41,"props":1168,"children":1169},{"className":38},[1170],{"type":15,"value":1171},"aria-busy=\"true\"",{"type":15,"value":1173}," while their request is in flight;\nbuttons are disabled for the same interval.",{"type":9,"tag":46,"props":1175,"children":1177},{"id":1176},"server-re-render-sliver-updates",[1178],{"type":15,"value":1179},"Server re-render (sliver updates)",{"type":9,"tag":18,"props":1181,"children":1182},{},[1183,1185,1190],{"type":15,"value":1184},"When you want the ",{"type":9,"tag":24,"props":1186,"children":1187},{},[1188],{"type":15,"value":1189},"server",{"type":15,"value":1191}," to render an update — keeping all logic and markup in one place,\nno client-side templating — POST the new state and swap the returned HTML. Request\u002Fresponse,\nno websockets:",{"type":9,"tag":32,"props":1193,"children":1196},{"className":1194,"code":1195,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cisland name=\"counter\" :start=\"0\">\n  \u003Cdiv data-view>\u003Ccounter-view :count=\"0\"\u002F>\u003C\u002Fdiv>\n  \u003Cbutton>increment\u003C\u002Fbutton>\n  \u003Cscript client>\n    let n = Number(ctx.props.start ?? 0)\n    ctx.root.querySelector(\"button\")?.addEventListener(\"click\", async () => {\n      n++\n      ctx.replace(\"[data-view]\", await renderFragment(\"counter-view\", { count: n }))\n    })\n  \u003C\u002Fscript>\n\u003C\u002Fisland>\n",[1197],{"type":9,"tag":41,"props":1198,"children":1199},{"__ignoreMap":38},[1200],{"type":15,"value":1195},{"type":9,"tag":18,"props":1202,"children":1203},{},[1204,1209,1211,1216,1218,1223,1225,1230,1232,1237,1239,1244],{"type":9,"tag":41,"props":1205,"children":1206},{"className":38},[1207],{"type":15,"value":1208},"renderFragment(tag, props)",{"type":15,"value":1210}," POSTs the props to ",{"type":9,"tag":41,"props":1212,"children":1213},{"className":38},[1214],{"type":15,"value":1215},"\u002F_bml\u002Frender\u002F\u003Ctag>",{"type":15,"value":1217},"; the server re-renders that\n",{"type":9,"tag":24,"props":1219,"children":1220},{},[1221],{"type":15,"value":1222},"one component",{"type":15,"value":1224}," with ",{"type":9,"tag":41,"props":1226,"children":1227},{"className":38},[1228],{"type":15,"value":1229},"propsFromJson",{"type":15,"value":1231}," decoding the state back to typed props, and returns the HTML\nfragment (with scope markers, no re-injected ",{"type":9,"tag":41,"props":1233,"children":1234},{"className":38},[1235],{"type":15,"value":1236},"\u003Cstyle>",{"type":15,"value":1238},"). It's the ",{"type":9,"tag":24,"props":1240,"children":1241},{},[1242],{"type":15,"value":1243},"same component code",{"type":15,"value":1245}," as the\nfirst render, so the markup stays consistent. Wire it up by passing the component renderers to the\nserver:",{"type":9,"tag":32,"props":1247,"children":1250},{"className":1248,"code":1249,"filename":-1,"highlights":-1,"language":517,"meta":38},[515],"BmlServer(\n  pages = bml.generated.BmlPages.all,\n  components = bml.generated.BmlComponents.all,\n  componentRenderers = bml.generated.BmlComponents.renderers, \u002F\u002F enables \u002F_bml\u002Frender\u002F\u003Ctag>\n  …\n).start()\n",[1251],{"type":9,"tag":41,"props":1252,"children":1253},{"__ignoreMap":38},[1254],{"type":15,"value":1249},{"type":9,"tag":18,"props":1256,"children":1257},{},[1258,1260,1265],{"type":15,"value":1259},"The forwarded ",{"type":9,"tag":41,"props":1261,"children":1262},{"className":38},[1263],{"type":15,"value":1264},"Authorization",{"type":15,"value":1266}," token lets the re-rendered component fetch data server-side, exactly\nlike a first render.",{"type":9,"tag":46,"props":1268,"children":1270},{"id":1269},"instance-isolation-reuse-safe",[1271],{"type":15,"value":1272},"Instance isolation (reuse-safe)",{"type":9,"tag":18,"props":1274,"children":1275},{},[1276,1278,1282,1284,1288,1290,1295,1297,1301],{"type":15,"value":1277},"Every island occurrence is an isolated instance: the setup's ",{"type":9,"tag":41,"props":1279,"children":1280},{"className":38},[1281],{"type":15,"value":635},{"type":15,"value":1283}," is scoped to its\nown DOM (",{"type":9,"tag":41,"props":1285,"children":1286},{"className":38},[1287],{"type":15,"value":668},{"type":15,"value":1289},"), the compiler rewrites in-island ",{"type":9,"tag":41,"props":1291,"children":1292},{"className":38},[1293],{"type":15,"value":1294},"id",{"type":15,"value":1296},"s to be unique, and\n",{"type":9,"tag":41,"props":1298,"children":1299},{"className":38},[1300],{"type":15,"value":773},{"type":15,"value":1302}," namespaces anything otherwise-global. So two instances of the same\nisland on one page never collide.",{"type":9,"tag":46,"props":1304,"children":1306},{"id":1305},"eager-rendering-live-data",[1307],{"type":15,"value":1308},"Eager rendering + live data",{"type":9,"tag":18,"props":1310,"children":1311},{},[1312,1314,1319,1321,1326,1328,1333],{"type":15,"value":1313},"The default ",{"type":9,"tag":41,"props":1315,"children":1316},{"className":38},[1317],{"type":15,"value":1318},"render=\"request\"",{"type":15,"value":1320}," mode emits complete server HTML with the page. ",{"type":9,"tag":41,"props":1322,"children":1323},{"className":38},[1324],{"type":15,"value":1325},"render=\"prerender\"",{"type":15,"value":1327},"\nis reserved and currently uses that same request-rendered path. Client code can fetch fresh data after\nmount and replace an island region through ",{"type":9,"tag":41,"props":1329,"children":1330},{"className":38},[1331],{"type":15,"value":1332},"ctx.replace(...)",{"type":15,"value":226},{"type":9,"tag":1335,"props":1336,"children":1337},"blockquote",{},[1338],{"type":9,"tag":18,"props":1339,"children":1340},{},[1341,1343,1347,1349,1354],{"type":15,"value":1342},"The client runtime (",{"type":9,"tag":41,"props":1344,"children":1345},{"className":38},[1346],{"type":15,"value":591},{"type":15,"value":1348},", BML-REQ-14) is implemented in ",{"type":9,"tag":41,"props":1350,"children":1351},{"className":38},[1352],{"type":15,"value":1353},"bml-runtime",{"type":15,"value":1355},"\n(TypeScript, vitest-tested: island lifecycle + GraphQL client). The compiler\u002Fserver\nemit the SSR markers + island wrappers it mounts onto; per-island bundling (esbuild)\nis BML-REQ-9.",{"type":9,"tag":46,"props":1357,"children":1359},{"id":1358},"declarative-and-programmatic-server-actions",[1360],{"type":15,"value":1361},"Declarative and programmatic server actions",{"type":9,"tag":18,"props":1363,"children":1364},{},[1365,1367,1372,1374,1379,1381,1386,1388,1393,1395,1400,1402,1406,1408,1413,1415,1419],{"type":15,"value":1366},"The zero-client-code path: a ",{"type":9,"tag":24,"props":1368,"children":1369},{},[1370],{"type":15,"value":1371},"live state",{"type":15,"value":1373}," is either a ",{"type":9,"tag":41,"props":1375,"children":1376},{"className":38},[1377],{"type":15,"value":1378},"@Serializable",{"type":15,"value":1380},", constructor-typed ",{"type":9,"tag":41,"props":1382,"children":1383},{"className":38},[1384],{"type":15,"value":1385},"provides",{"type":15,"value":1387},"\nmodel or an explicitly typed ",{"type":9,"tag":41,"props":1389,"children":1390},{"className":38},[1391],{"type":15,"value":1392},"\u003Cinject server>",{"type":15,"value":1394}," reflected by exactly one view ",{"type":9,"tag":41,"props":1396,"children":1397},{"className":38},[1398],{"type":15,"value":1399},"\u003Cisland>",{"type":15,"value":1401},". ",{"type":9,"tag":41,"props":1403,"children":1404},{"className":38},[1405],{"type":15,"value":278},{"type":15,"value":1407}," on\nany element (inside the island or not) runs a method on the model ",{"type":9,"tag":24,"props":1409,"children":1410},{},[1411],{"type":15,"value":1412},"server-side",{"type":15,"value":1414},"; the server persists\nthe model and re-renders the island, and the runtime swaps the view in. No ",{"type":9,"tag":41,"props":1416,"children":1417},{"className":38},[1418],{"type":15,"value":116},{"type":15,"value":1420}," at all.",{"type":9,"tag":32,"props":1422,"children":1425},{"className":1423,"code":1424,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cpage route=\"\u002Fcart\">\n  \u003Cscript server provides=\"cart\" scope=\"server-session\">bosca.bml.sample.Cart()\u003C\u002Fscript>\n  \u003Cisland name=\"cart-view\">\n    \u003Cp>{ cart.itemCount } item(s) in your cart\u003C\u002Fp>\n  \u003C\u002Fisland>\n  \u003Cbutton @click=\"cart.addItem\">Add item\u003C\u002Fbutton>\n  \u003Cbutton @click=\"cart.clear\">Clear\u003C\u002Fbutton>\n\u003C\u002Fpage>\n",[1426],{"type":9,"tag":41,"props":1427,"children":1428},{"__ignoreMap":38},[1429],{"type":15,"value":1424},{"type":9,"tag":18,"props":1431,"children":1432},{},[1433,1435,1440],{"type":15,"value":1434},"Every live model has one ",{"type":9,"tag":41,"props":1436,"children":1437},{"className":38},[1438],{"type":15,"value":1439},"scope",{"type":15,"value":1441},":",{"type":9,"tag":1443,"props":1444,"children":1445},"ul",{},[1446,1457,1474,1490],{"type":9,"tag":1447,"props":1448,"children":1449},"li",{},[1450,1455],{"type":9,"tag":41,"props":1451,"children":1452},{"className":38},[1453],{"type":15,"value":1454},"page",{"type":15,"value":1456}," is the default. The model JSON round-trips through the rendered page only; navigation or refresh\nuses the newly server-rendered model, which keeps GraphQL-backed state current.",{"type":9,"tag":1447,"props":1458,"children":1459},{},[1460,1465,1467,1472],{"type":9,"tag":41,"props":1461,"children":1462},{"className":38},[1463],{"type":15,"value":1464},"client-session",{"type":15,"value":1466}," mirrors the serialized model to browser ",{"type":9,"tag":41,"props":1468,"children":1469},{"className":38},[1470],{"type":15,"value":1471},"sessionStorage",{"type":15,"value":1473}," and restores it on the next\nrender. That saved model is authoritative for the browser session; BML does not merge it with new server data.",{"type":9,"tag":1447,"props":1475,"children":1476},{},[1477,1482,1483,1488],{"type":9,"tag":41,"props":1478,"children":1479},{"className":38},[1480],{"type":15,"value":1481},"client-local",{"type":15,"value":1466},{"type":9,"tag":41,"props":1484,"children":1485},{"className":38},[1486],{"type":15,"value":1487},"localStorage",{"type":15,"value":1489},". It has the same client-authoritative\nrestore behavior but survives tab closure and browser restarts. Do not use client storage for secrets.",{"type":9,"tag":1447,"props":1491,"children":1492},{},[1493,1497],{"type":9,"tag":41,"props":1494,"children":1495},{"className":38},[1496],{"type":15,"value":320},{"type":15,"value":1498}," keeps the model in the cookie-identified BML server session. Its value never reaches the client.",{"type":9,"tag":18,"props":1500,"children":1501},{},[1502],{"type":15,"value":1503},"The default may be written explicitly when the freshness requirement should be visible in the source:",{"type":9,"tag":32,"props":1505,"children":1508},{"className":1506,"code":1507,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cscript server provides=\"devices\" scope=\"page\">my.site.loadDevices()\u003C\u002Fscript>\n\u003Cscript server provides=\"draft\" scope=\"client-session\">my.site.DraftModel()\u003C\u002Fscript>\n\u003Cscript server provides=\"preferences\" scope=\"client-local\">my.site.PreferencesModel()\u003C\u002Fscript>\n\u003Cscript server provides=\"accountDraft\" scope=\"client-local\" clear-on-sign-out>my.site.AccountDraft()\u003C\u002Fscript>\n\u003Cscript server provides=\"cart\" scope=\"server-session\">my.site.CartModel()\u003C\u002Fscript>\n",[1509],{"type":9,"tag":41,"props":1510,"children":1511},{"__ignoreMap":38},[1512],{"type":15,"value":1507},{"type":9,"tag":18,"props":1514,"children":1515},{},[1516,1518,1523,1525,1529,1530,1534,1536,1540,1542,1547,1549,1553,1555,1560],{"type":15,"value":1517},"Client-backed models are readable by same-origin JavaScript. Add the bare ",{"type":9,"tag":41,"props":1519,"children":1520},{"className":38},[1521],{"type":15,"value":1522},"clear-on-sign-out",{"type":15,"value":1524}," marker\nonly to ",{"type":9,"tag":41,"props":1526,"children":1527},{"className":38},[1528],{"type":15,"value":1464},{"type":15,"value":1023},{"type":9,"tag":41,"props":1531,"children":1532},{"className":38},[1533],{"type":15,"value":1481},{"type":15,"value":1535}," models whose data belongs to the signed-in identity.\nAfter an explicit identity change completes, ",{"type":9,"tag":41,"props":1537,"children":1538},{"className":38},[1539],{"type":15,"value":313},{"type":15,"value":1541}," cancels old actions, clears only\nmarked browser models, asks the next stateful render to replace the opaque server session, and reloads\nby default so identity-dependent shell inputs are recomputed. Pass ",{"type":9,"tag":41,"props":1543,"children":1544},{"className":38},[1545],{"type":15,"value":1546},"{ reload: false }",{"type":15,"value":1548}," only when the\npage shell, deferred props, and fallback content are all identity-independent and the page has no\n",{"type":9,"tag":41,"props":1550,"children":1551},{"className":38},[1552],{"type":15,"value":320},{"type":15,"value":1554}," state. Do not bind either form directly to the auth client's ",{"type":9,"tag":41,"props":1556,"children":1557},{"className":38},[1558],{"type":15,"value":1559},"signedOut",{"type":15,"value":1561}," event: that\nevent can also follow a recoverable refresh failure. Unmarked BML browser storage and unrelated\napplication storage remain untouched.",{"type":9,"tag":32,"props":1563,"children":1566},{"className":1564,"code":1565,"filename":-1,"highlights":-1,"language":947,"meta":38},[945],"async function signOut(): Promise\u003Cvoid> {\n  await auth.signOut()\n  clearBmlClientState()\n}\n",[1567],{"type":9,"tag":41,"props":1568,"children":1569},{"__ignoreMap":38},[1570],{"type":15,"value":1565},{"type":9,"tag":18,"props":1572,"children":1573},{},[1574,1576,1581],{"type":15,"value":1575},"Server-session values expire through the configured cache TTL (30 minutes by default). The default\nin-memory store also expires page entries and keeps at most 256 page entries per active session;\nsite entries are not part of that page bound. Each state key is stored independently under the opaque\nsession id. If the session or one page entry has expired, the action returns ",{"type":9,"tag":41,"props":1577,"children":1578},{"className":38},[1579],{"type":15,"value":1580},"410 Gone",{"type":15,"value":1582}," and the runtime\nreloads without replaying it. Reload creates a new session or initializes only the missing page\nentry in a still-live session, preserving unrelated site state.",{"type":9,"tag":1038,"props":1584,"children":1586},{"id":1585},"arguments",[1587],{"type":15,"value":1588},"Arguments",{"type":9,"tag":18,"props":1590,"children":1591},{},[1592],{"type":15,"value":1593},"Action expressions take three kinds of arguments, decoded positionally on the server against the\nmodel method's own parameter types (String \u002F Int \u002F Long \u002F Boolean \u002F Double):",{"type":9,"tag":53,"props":1595,"children":1596},{},[1597,1618],{"type":9,"tag":57,"props":1598,"children":1599},{},[1600],{"type":9,"tag":61,"props":1601,"children":1602},{},[1603,1608,1613],{"type":9,"tag":65,"props":1604,"children":1605},{},[1606],{"type":15,"value":1607},"Argument",{"type":9,"tag":65,"props":1609,"children":1610},{},[1611],{"type":15,"value":1612},"Bound",{"type":9,"tag":65,"props":1614,"children":1615},{},[1616],{"type":15,"value":1617},"Example",{"type":9,"tag":76,"props":1619,"children":1620},{},[1621,1656,1680],{"type":9,"tag":61,"props":1622,"children":1623},{},[1624,1629,1641],{"type":9,"tag":83,"props":1625,"children":1626},{},[1627],{"type":15,"value":1628},"Kotlin expression",{"type":9,"tag":83,"props":1630,"children":1631},{},[1632,1634,1639],{"type":15,"value":1633},"at render time, into the element's ",{"type":9,"tag":41,"props":1635,"children":1636},{"className":38},[1637],{"type":15,"value":1638},"data-bml-args",{"type":15,"value":1640}," marker",{"type":9,"tag":83,"props":1642,"children":1643},{},[1644,1649,1651],{"type":9,"tag":41,"props":1645,"children":1646},{"className":38},[1647],{"type":15,"value":1648},"@click=\"list.remove(item.markId, ctx)\"",{"type":15,"value":1650}," inside a ",{"type":9,"tag":41,"props":1652,"children":1653},{"className":38},[1654],{"type":15,"value":1655},"\u003Cfor>",{"type":9,"tag":61,"props":1657,"children":1658},{},[1659,1667,1672],{"type":9,"tag":83,"props":1660,"children":1661},{},[1662],{"type":9,"tag":41,"props":1663,"children":1664},{"className":38},[1665],{"type":15,"value":1666},"form.\u003Cfield>",{"type":9,"tag":83,"props":1668,"children":1669},{},[1670],{"type":15,"value":1671},"at event time, from the bound form's field (checkbox → boolean)",{"type":9,"tag":83,"props":1673,"children":1674},{},[1675],{"type":9,"tag":41,"props":1676,"children":1677},{"className":38},[1678],{"type":15,"value":1679},"@submit=\"wall.share(form.groupId, form.title, ctx)\"",{"type":9,"tag":61,"props":1681,"children":1682},{},[1683,1690,1701],{"type":9,"tag":83,"props":1684,"children":1685},{},[1686],{"type":9,"tag":41,"props":1687,"children":1688},{"className":38},[1689],{"type":15,"value":635},{"type":9,"tag":83,"props":1691,"children":1692},{},[1693,1695,1699],{"type":15,"value":1694},"server-side — the dispatcher's ",{"type":9,"tag":41,"props":1696,"children":1697},{"className":38},[1698],{"type":15,"value":252},{"type":15,"value":1700}," (models that reach the data plane want it)",{"type":9,"tag":83,"props":1702,"children":1703},{},[1704],{"type":9,"tag":41,"props":1705,"children":1706},{"className":38},[1707],{"type":15,"value":1708},"@click=\"mark.toggle(ctx)\"",{"type":9,"tag":18,"props":1710,"children":1711},{},[1712,1717],{"type":9,"tag":41,"props":1713,"children":1714},{"className":38},[1715],{"type":15,"value":1716},"@submit",{"type":15,"value":1718}," binds the form's submit event (prevented; fields are read live), so a form inside the\nisland clears on the post-action re-render.",{"type":9,"tag":18,"props":1720,"children":1721},{},[1722,1724,1729,1731,1736,1737,1742],{"type":15,"value":1723},"Every DOM event is supported (",{"type":9,"tag":41,"props":1725,"children":1726},{"className":38},[1727],{"type":15,"value":1728},"@input",{"type":15,"value":1730},", ",{"type":9,"tag":41,"props":1732,"children":1733},{"className":38},[1734],{"type":15,"value":1735},"@change",{"type":15,"value":1730},{"type":9,"tag":41,"props":1738,"children":1739},{"className":38},[1740],{"type":15,"value":1741},"@ended",{"type":15,"value":1743},", custom events, and so on). Action\nmodifiers move common persistence behavior into the runtime:",{"type":9,"tag":32,"props":1745,"children":1748},{"className":1746,"code":1747,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cinput @input.debounce.250.coalesce=\"search.update(form.query)\"\u002F>\n\u003Cvideo @timeupdate.throttle.30000.coalesce.keepalive.pagehide=\"playback.save\"\u002F>\n",[1749],{"type":9,"tag":41,"props":1750,"children":1751},{"__ignoreMap":38},[1752],{"type":15,"value":1747},{"type":9,"tag":1443,"props":1754,"children":1755},{},[1756,1766,1776,1786],{"type":9,"tag":1447,"props":1757,"children":1758},{},[1759,1764],{"type":9,"tag":41,"props":1760,"children":1761},{"className":38},[1762],{"type":15,"value":1763},"debounce.\u003Cms>",{"type":15,"value":1765}," keeps the latest call after a quiet period.",{"type":9,"tag":1447,"props":1767,"children":1768},{},[1769,1774],{"type":9,"tag":41,"props":1770,"children":1771},{"className":38},[1772],{"type":15,"value":1773},"throttle.\u003Cms>",{"type":15,"value":1775}," sends at most once per interval and retains the latest pending call.",{"type":9,"tag":1447,"props":1777,"children":1778},{},[1779,1784],{"type":9,"tag":41,"props":1780,"children":1781},{"className":38},[1782],{"type":15,"value":1783},"coalesce",{"type":15,"value":1785}," turns calls arriving during an active request into one follow-up call with the latest arguments.",{"type":9,"tag":1447,"props":1787,"children":1788},{},[1789,1794,1796,1801],{"type":9,"tag":41,"props":1790,"children":1791},{"className":38},[1792],{"type":15,"value":1793},"keepalive",{"type":15,"value":1795}," makes the fetch unload-safe; ",{"type":9,"tag":41,"props":1797,"children":1798},{"className":38},[1799],{"type":15,"value":1800},"pagehide",{"type":15,"value":1802}," flushes a scheduled call with keepalive.",{"type":9,"tag":18,"props":1804,"children":1805},{},[1806,1811,1812,1817],{"type":9,"tag":41,"props":1807,"children":1808},{"className":38},[1809],{"type":15,"value":1810},"debounce",{"type":15,"value":287},{"type":9,"tag":41,"props":1813,"children":1814},{"className":38},[1815],{"type":15,"value":1816},"throttle",{"type":15,"value":1818}," are mutually exclusive. Unknown modifiers, invalid action expressions,\ndiscarded action receivers, and inconsistent argument counts are compile errors.",{"type":9,"tag":18,"props":1820,"children":1821},{},[1822],{"type":15,"value":1823},"When arguments come from client state, dispatch from an island or scoped component script. BML\nrewrites the model expression to a generated server dispatcher while preserving ordinary TypeScript:",{"type":9,"tag":32,"props":1825,"children":1828},{"className":1826,"code":1827,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Cscript client>\n  ctx.on\u003CCustomEvent\u003C{ position: number }>>(ctx.root, \"save-position\", (event) => {\n    ctx.dispatch(playback.save(event.detail.position), {\n      throttleMs: 30_000,\n      coalesce: true,\n      keepalive: true,\n      flushOnPageHide: true,\n    })\n  })\n\u003C\u002Fscript>\n",[1829],{"type":9,"tag":41,"props":1830,"children":1831},{"__ignoreMap":38},[1832],{"type":15,"value":1827},{"type":9,"tag":1038,"props":1834,"children":1836},{"id":1835},"component-models",[1837],{"type":15,"value":1838},"Component models",{"type":9,"tag":18,"props":1840,"children":1841},{},[1842,1844,1849,1851,1856,1858,1862,1864,1869],{"type":15,"value":1843},"A ",{"type":9,"tag":41,"props":1845,"children":1846},{"className":38},[1847],{"type":15,"value":1848},"\u003Ccomponent>",{"type":15,"value":1850}," can declare its own live state — one model ",{"type":9,"tag":24,"props":1852,"children":1853},{},[1854],{"type":15,"value":1855},"per instance",{"type":15,"value":1857},", so a card in a\n",{"type":9,"tag":41,"props":1859,"children":1860},{"className":38},[1861],{"type":15,"value":1655},{"type":15,"value":1863}," loop carries its own toggle without a page-level \"uber model\". The view island needs a\nper-instance ",{"type":9,"tag":41,"props":1865,"children":1866},{"className":38},[1867],{"type":15,"value":1868},":key",{"type":15,"value":1870}," (props are in scope):",{"type":9,"tag":32,"props":1872,"children":1875},{"className":1873,"code":1874,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Ccomponent tag=\"like-button\">\n  \u003Cprop name=\"id\" type=\"String\" required\u002F>\n  \u003Cprop name=\"on\" type=\"Boolean\" default=\"false\"\u002F>\n  \u003Cscript server provides=\"like\">myapp.LikeModel(id, on)\u003C\u002Fscript>\n  \u003Cisland name=\"like-view\" :key=\"id\">\n    \u003Cbutton @click=\"like.toggle(ctx)\">{ like.count }\u003C\u002Fbutton>\n  \u003C\u002Fisland>\n\u003C\u002Fcomponent>\n",[1876],{"type":9,"tag":41,"props":1877,"children":1878},{"__ignoreMap":38},[1879],{"type":15,"value":1874},{"type":9,"tag":18,"props":1881,"children":1882},{},[1883,1885,1890,1892,1897,1899,1904,1906,1911],{"type":15,"value":1884},"Component states register under a ",{"type":9,"tag":41,"props":1886,"children":1887},{"className":38},[1888],{"type":15,"value":1889},"\"\u003Ctag>.\u003Cprovides>\"",{"type":15,"value":1891}," prefix and dispatch by their full\nper-instance key (",{"type":9,"tag":41,"props":1893,"children":1894},{"className":38},[1895],{"type":15,"value":1896},"\"\u003Ctag>.\u003Cprovides>:\u003Ckey>\"",{"type":15,"value":1898},") — wire ",{"type":9,"tag":41,"props":1900,"children":1901},{"className":38},[1902],{"type":15,"value":1903},"BmlServer(componentIslandDispatchers = bml.generated.BmlIslands.componentDispatchers)",{"type":15,"value":1905},". Island content may reference ",{"type":9,"tag":24,"props":1907,"children":1908},{},[1909],{"type":15,"value":1910},"only the model",{"type":15,"value":1912},"\n(plus loop variables): the same markup re-renders on dispatch, when props no longer exist.",{"type":9,"tag":18,"props":1914,"children":1915},{},[1916,1917,1922,1924,1928,1929,1933,1935,1939,1941,1945],{"type":15,"value":205},{"type":9,"tag":41,"props":1918,"children":1919},{"className":38},[1920],{"type":15,"value":1921},"scope=\"site\"",{"type":15,"value":1923}," on a root component when the same model must be available across pages. Site\nscope remains component-bound; it does not create a global service. It changes the state identity\nfrom pathname-qualified to site-stable, requires durable ",{"type":9,"tag":41,"props":1925,"children":1926},{"className":38},[1927],{"type":15,"value":1464},{"type":15,"value":1730},{"type":9,"tag":41,"props":1930,"children":1931},{"className":38},[1932],{"type":15,"value":1481},{"type":15,"value":1934},", or\n",{"type":9,"tag":41,"props":1936,"children":1937},{"className":38},[1938],{"type":15,"value":320},{"type":15,"value":1940}," model storage, and permits a page to mount only the component action without its\nview. A site component has one stable model identity, so its island does not take ",{"type":9,"tag":41,"props":1942,"children":1943},{"className":38},[1944],{"type":15,"value":1868},{"type":15,"value":1946}," and the\ncomponent should render at most once on a page. The runtime restores and renders the model only\nwhere the view exists.",{"type":9,"tag":18,"props":1948,"children":1949},{},[1950,1952,1957,1959,1964,1966,1970],{"type":15,"value":1951},"This supports converting anonymous browser state during authentication without touching unrelated\npages. The model owns the local items, ",{"type":9,"tag":41,"props":1953,"children":1954},{"className":38},[1955],{"type":15,"value":1956},"sync(ctx)",{"type":15,"value":1958}," writes them to the authenticated server model and\nresets itself to its default, and the runtime removes the now-default local snapshot. Make ",{"type":9,"tag":41,"props":1960,"children":1961},{"className":38},[1962],{"type":15,"value":1963},"sync",{"type":15,"value":1965},"\nidempotent: a client can retry after the server commits but before the response arrives. Browser-backed\nstate is untrusted input, so ",{"type":9,"tag":41,"props":1967,"children":1968},{"className":38},[1969],{"type":15,"value":1963},{"type":15,"value":1971}," must validate and deduplicate item IDs and the server must enforce\nthe three-item access rule rather than trusting the stored count.",{"type":9,"tag":32,"props":1973,"children":1976},{"className":1974,"code":1975,"filename":-1,"highlights":-1,"language":37,"meta":38},[35],"\u003Ccomponent tag=\"free-access\" scope=\"site\">\n  \u003Cprop name=\"showUsage\" type=\"Boolean\" default=\"false\"\u002F>\n  \u003Cscript server provides=\"access\" scope=\"client-local\">my.site.FreeAccessModel()\u003C\u002Fscript>\n\n  \u003Cif showUsage>\n    \u003Cisland name=\"free-access-usage\">\n      \u003Cp>{ access.used } of 3 free items used\u003C\u002Fp>\n    \u003C\u002Fisland>\n  \u003C\u002Fif>\n\n  \u003Cmain>\n    \u003Cscript client scoped>\n      const unsubscribe = auth.on(\"signedIn\", () => ctx.dispatch(access.sync(ctx)))\n      ctx.onUnmount(unsubscribe)\n    \u003C\u002Fscript>\n  \u003C\u002Fmain>\n\u003C\u002Fcomponent>\n",[1977],{"type":9,"tag":41,"props":1978,"children":1979},{"__ignoreMap":38},[1980],{"type":15,"value":1975},{"type":9,"tag":18,"props":1982,"children":1983},{},[1984,1986,1991,1993,1997],{"type":15,"value":1985},"Generated client dispatch names ",{"type":9,"tag":41,"props":1987,"children":1988},{"className":38},[1989],{"type":15,"value":1990},"access",{"type":15,"value":1992}," explicitly, so scoped components with multiple models\nroute programmatic actions to the correct state. ",{"type":9,"tag":41,"props":1994,"children":1995},{"className":38},[1996],{"type":15,"value":635},{"type":15,"value":1998}," is injected on the server and is not sent as\nan action argument.",{"type":9,"tag":18,"props":2000,"children":2001},{},[2002,2004,2008,2010,2014,2016,2021,2023,2028],{"type":15,"value":2003},"Rules of thumb: one view island per state (v1); a state key must resolve to a constructor-typed\n",{"type":9,"tag":41,"props":2005,"children":2006},{"className":38},[2007],{"type":15,"value":1385},{"type":15,"value":2009}," or an explicitly typed ",{"type":9,"tag":41,"props":2011,"children":2012},{"className":38},[2013],{"type":15,"value":1392},{"type":15,"value":2015},"; anything the re-render needs must live in the\nmodel (a method can refetch via ",{"type":9,"tag":41,"props":2017,"children":2018},{"className":38},[2019],{"type":15,"value":2020},"ctx.gql",{"type":15,"value":2022}," and assign back to a ",{"type":9,"tag":41,"props":2024,"children":2025},{"className":38},[2026],{"type":15,"value":2027},"var",{"type":15,"value":2029},").",1790541170518]