@symbo.ls/brender 3.14.660 → 3.14.662

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # @symbo.ls/brender
2
2
 
3
+ ## 3.14.662
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixes for the 42 issues reported while building xma.info (FW-XMA-EXCEPTIONS-UPSTREAM-1).
8
+
9
+ Behaviour changes (check these first):
10
+
11
+ - CSS precedence across `extends`: a later layer's shorthand that states a longhand now beats a longhand an earlier layer declared (`borderWidth: '0'` no longer loses to a base `borderBottomWidth`; a derived `border: 'hairline solid …'` now paints over a base `borderWidth: '0'`). Positional shorthands (`background`, `transition`, `font`, `flex`, `grid`…) never remove a base longhand. A `:focus-visible` longhand (`outlineColor`) now paints over Link/Focusable's ring.
12
+ - Built-in `Img` no longer copies `alt` into `title`. `Link` leaves Ctrl/Cmd/Shift/Alt, middle, `target` and `download` clicks to the browser.
13
+ - `X<` breakpoints start at N.02px, so no width matches both `X` and `X<`.
14
+ - Helmet renders the head as the merge of mounted layers: keys a page leaves out fall back instead of staying from the previous page.
15
+ - `smbls build` with `"brender": true` pre-renders again (it rendered nothing since 3.14.6): every static route is written, `/*` becomes `404.html`, `:param` routes are skipped and listed, and the build exits 1 when no route renders.
16
+ - `onStateInit`, `onStateCreated` and `onBeforeStateUpdate` run again (`onBeforeStateUpdate` returning `false` cancels the update).
17
+ - `onWindowLoad` runs once right after creation when the page had already loaded.
18
+ - The first render no longer forces a style+layout pass per microtask.
19
+ - socket.io-client loads only when a sync transport is configured; the ESM build ships it as `dist/smbls.socket-io-client.esm.js` (keep it beside `smbls.esm.js`).
20
+
21
+ New, opt-in:
22
+
23
+ - `designSystem.focusableRing`; `vars` and top-level `'--x'` keys set reactive custom properties; `fill`/`stroke` are CSS outside `<svg>`; attributes inside `.isX` / `'!isX'` blocks apply.
24
+ - Design-system tokens resolve inside `style: {}` blocks; `sizes` tokens negate (`-hairline2`) and publish `--size-<name>`.
25
+ - `fetchpriority` and every multi-word attribute work flat in both spellings.
26
+ - `inertOutside`, the `Bridge` host for DOM-owning libraries, element events with `{ capture, passive, once, selector, handler }`, `TooltipLayer` for `[data-tooltip]` nodes.
27
+ - Router `scrollRestoration: 'restore'`; guards that refuse Back/Forward put the address back; lazy route groups (`context.lazy`, `el.call('loadLazy')`).
28
+ - Fetch: `el.call('invalidateQueries')` and friends, `invalidates` on rpc, `fetch.early` pre-boot requests, `fetch.reads` anonymous GET reads without a CORS preflight.
29
+ - Polyglot `setLang` switches text, `<html lang>` and fonts in one frame; `getPendingLang`.
30
+ - `s.$settled()` / `settled()` await the DOM a state write produces; `onMediaQueryChange` takes design-system media keys; the `animation` shorthand resolves tokens.
31
+ - `smbls/ssr` entry for server rendering; `smbls push` publishes `new URL('<path>', import.meta.url)` assets.
32
+ - frank-audit: FA105 per-tag, FA410 (history writes), wider FA701; opt-in FA211, FA810, FA811, FA812; unknown `--rule` ids are reported.
33
+
34
+ - Updated dependencies [95d31cb]
35
+ - Updated dependencies [13c4922]
36
+ - Updated dependencies
37
+ - @symbo.ls/css@3.14.774
38
+ - smbls@3.14.827
39
+ - @symbo.ls/utils@3.14.784
40
+ - @symbo.ls/fetch@3.14.662
41
+ - @symbo.ls/helmet@3.14.669
42
+ - @symbo.ls/element@3.14.799
43
+ - @symbo.ls/scratch@3.14.786
44
+ - @symbo.ls/default-config@3.14.785
45
+
3
46
  ## 3.14.658
4
47
 
5
48
  ### Patch Changes
package/dist/esm/env.js CHANGED
@@ -1 +1 @@
1
- import{parseHTML as i}from"linkedom";const c=(r="<!DOCTYPE html><html><head></head><body></body></html>")=>{const{window:e,document:l}=i(r);e.requestAnimationFrame||(e.requestAnimationFrame=o=>{const t=setTimeout(o,0);return t?.unref&&t.unref(),t}),e.cancelAnimationFrame||(e.cancelAnimationFrame=o=>clearTimeout(o)),e.history||(e.history={pushState:()=>{},replaceState:()=>{},state:null}),e.location||(e.location={pathname:"/",search:"",hash:"",origin:"http://localhost"}),e.URL||(e.URL=URL),e.scrollTo||(e.scrollTo=()=>{});const a=()=>{const o={};return{getItem:t=>o[t]??null,setItem:(t,s)=>{o[t]=String(s)},removeItem:t=>{delete o[t]},clear:()=>{for(const t in o)delete o[t]},get length(){return Object.keys(o).length},key:t=>Object.keys(o)[t]??null}};return e.localStorage||(e.localStorage=a()),e.sessionStorage||(e.sessionStorage=a()),globalThis.localStorage||(globalThis.localStorage=e.localStorage),globalThis.sessionStorage||(globalThis.sessionStorage=e.sessionStorage),e.MutationObserver||(e.MutationObserver=class{constructor(){}observe(){}disconnect(){}takeRecords(){return[]}}),globalThis.window=e,globalThis.document=l,globalThis.Node=e.Node||globalThis.Node,globalThis.Element=e.Element||globalThis.Element,globalThis.HTMLElement=e.HTMLElement||globalThis.HTMLElement,globalThis.MutationObserver=e.MutationObserver,globalThis.Window=e.constructor,{window:e,document:l}};export{c as createEnv};
1
+ import{parseHTML as n}from"linkedom";const c=(s="<!DOCTYPE html><html><head></head><body></body></html>")=>{const{window:e,document:l}=n(s);e.requestAnimationFrame||(e.requestAnimationFrame=o=>{const t=setTimeout(o,0);return t?.unref&&t.unref(),t}),e.cancelAnimationFrame||(e.cancelAnimationFrame=o=>clearTimeout(o)),e.history||(e.history={pushState:()=>{},replaceState:()=>{},state:null}),e.location||(e.location={pathname:"/",search:"",hash:"",origin:"http://localhost",protocol:"http:",host:"localhost",hostname:"localhost",port:"",href:"http://localhost/"}),e.URL||(e.URL=URL),e.scrollTo||(e.scrollTo=()=>{});const a=()=>{const o={};return{getItem:t=>o[t]??null,setItem:(t,r)=>{o[t]=String(r)},removeItem:t=>{delete o[t]},clear:()=>{for(const t in o)delete o[t]},get length(){return Object.keys(o).length},key:t=>Object.keys(o)[t]??null}};return e.localStorage||(e.localStorage=a()),e.sessionStorage||(e.sessionStorage=a()),globalThis.localStorage||(globalThis.localStorage=e.localStorage),globalThis.sessionStorage||(globalThis.sessionStorage=e.sessionStorage),e.MutationObserver||(e.MutationObserver=class{constructor(){}observe(){}disconnect(){}takeRecords(){return[]}}),globalThis.window=e,globalThis.document=l,globalThis.Node=e.Node||globalThis.Node,globalThis.Element=e.Element||globalThis.Element,globalThis.HTMLElement=e.HTMLElement||globalThis.HTMLElement,globalThis.MutationObserver=e.MutationObserver,globalThis.Window=e.constructor,{window:e,document:l}};export{c as createEnv};
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- import{createEnv as e}from"./env.js";import{resetKeys as r,assignKeys as t,mapKeysToElements as o}from"./keys.js";import{loadProject as a,loadAndRenderAll as m}from"./load.js";import{render as d,renderElement as n,renderRoute as l,renderPage as p,resetGlobalCSSCache as i,getAccumulatedEmotionCSS as c,replaceEmotionCSS as f}from"./render.js";import{extractMetadata as s,generateHeadHtml as S}from"./metadata.js";import{collectBrNodes as g,hydrate as E}from"./hydrate.js";import{generateSitemap as h}from"./sitemap.js";import{prefetchPageData as u,injectPrefetchedState as y}from"./prefetch.js";var b={createEnv:e,resetKeys:r,assignKeys:t,mapKeysToElements:o,loadProject:a,loadAndRenderAll:m,render:d,renderElement:n,renderRoute:l,renderPage:p,resetGlobalCSSCache:i,getAccumulatedEmotionCSS:c,replaceEmotionCSS:f,extractMetadata:s,generateHeadHtml:S,collectBrNodes:g,hydrate:E,generateSitemap:h,prefetchPageData:u,injectPrefetchedState:y};export{t as assignKeys,g as collectBrNodes,e as createEnv,b as default,s as extractMetadata,S as generateHeadHtml,h as generateSitemap,c as getAccumulatedEmotionCSS,E as hydrate,y as injectPrefetchedState,m as loadAndRenderAll,a as loadProject,o as mapKeysToElements,u as prefetchPageData,d as render,n as renderElement,p as renderPage,l as renderRoute,f as replaceEmotionCSS,i as resetGlobalCSSCache,r as resetKeys};
1
+ import{createEnv as e}from"./env.js";import{resetKeys as r,assignKeys as t,mapKeysToElements as o}from"./keys.js";import{loadProject as m,loadAndRenderAll as a}from"./load.js";import{render as l,renderElement as n,renderRoute as p,renderPage as d,resetGlobalCSSCache as i,getAccumulatedEmotionCSS as c,replaceEmotionCSS as f}from"./render.js";import{extractMetadata as s,generateHeadHtml as S}from"./metadata.js";import{collectBrNodes as g,hydrate as h}from"./hydrate.js";import{generateSitemap as E}from"./sitemap.js";import{prefetchPageData as u,injectPrefetchedState as y}from"./prefetch.js";import{composeIntoShell as C}from"./shell.js";var B={createEnv:e,resetKeys:r,assignKeys:t,mapKeysToElements:o,loadProject:m,loadAndRenderAll:a,render:l,renderElement:n,renderRoute:p,renderPage:d,resetGlobalCSSCache:i,getAccumulatedEmotionCSS:c,replaceEmotionCSS:f,extractMetadata:s,generateHeadHtml:S,collectBrNodes:g,hydrate:h,generateSitemap:E,prefetchPageData:u,injectPrefetchedState:y,composeIntoShell:C};export{t as assignKeys,g as collectBrNodes,C as composeIntoShell,e as createEnv,B as default,s as extractMetadata,S as generateHeadHtml,E as generateSitemap,c as getAccumulatedEmotionCSS,h as hydrate,y as injectPrefetchedState,a as loadAndRenderAll,m as loadProject,o as mapKeysToElements,u as prefetchPageData,l as render,n as renderElement,d as renderPage,p as renderRoute,f as replaceEmotionCSS,i as resetGlobalCSSCache,r as resetKeys};
@@ -1 +1 @@
1
- const h=t=>typeof t=="function",b=t=>Array.isArray(t),y=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),S=(t,r)=>{if(t){if(h(t))try{return t({state:r||{},call:()=>{},__ref:{}},r||{})}catch{return}return t}},_=(t,r)=>{if(!t)return null;if(typeof t=="string")return{from:t,method:"select"};const n=h(t)?null:{...t};return!n||(n.method||(n.method="select"),h(n.params)&&(n.params=S(n.params,r)),n.method==="insert"||n.method==="update"||n.method==="upsert"||n.method==="delete")||n.on&&n.on!=="create"?null:n},A=(t,r="")=>{if(!t||typeof t!="object")return[];if(h(t))return[];const n=[],s=t.state||{};if(t.fetch){const e=b(t.fetch)?t.fetch:[t.fetch];for(const c of e){const o=_(c,s);o&&n.push({config:o,stateKey:o.as,path:r,elementState:s})}}for(const e in t)e==="fetch"||e==="state"||e==="props"||e==="attr"||e==="on"||e==="define"||e==="childExtends"||e==="childProps"||e==="childrenAs"||e.charAt(0)>="A"&&e.charAt(0)<="Z"&&y(t[e])&&n.push(...A(t[e],r?`${r}.${e}`:e));return n},w=async t=>null,k=async(t,r)=>{try{const{method:n,from:s,params:e,transform:c,limit:o,offset:i,order:l,single:u}=r;let f;n==="rpc"?f=await t.rpc({from:s,params:e}):f=await t.select({from:s,select:r.select,params:e,limit:o,offset:i,order:l,single:u});let a=f?.data??null;if(f?.error)return null;if(a&&c&&h(c))try{a=c(a)}catch{}return a}catch{return null}},x=async(t,r="/",n={})=>{const e=(t.pages||{})[r];if(!e)return new Map;const c=t.config||t.settings||{},o=c.fetch||t.fetch||c.db||t.db;if(!o)return new Map;const i=await w(o);if(!i)return new Map;const l=A(e);if(!l.length)return new Map;const u=new Map,f=await Promise.allSettled(l.map(async({config:a,stateKey:p,path:m})=>{const g=await k(i,a);if(g!==null){const d=u.get(m)||{};p?d[p]=g:y(g)&&Object.assign(d,g),u.set(m,d)}}));return u},M=async t=>{const r=t.config||{},n=r.polyglot||t.polyglot;if(!n?.fetch)return null;const s=r.fetch||t.fetch||r.db||t.db;if(!s)return null;const e=await w(s);if(!e)return null;const c=n.fetch,o=c.rpc||c.from||"get_translations_if_changed",i=n.languages||[n.defaultLang||"en"],l={},u=await Promise.allSettled(i.map(async f=>{try{const a=await e.rpc({from:o,params:{p_lang:f,p_cached_version:0}});if(a.error||!a.data)return;const p=a.data;p.translations&&(l[f]=p.translations)}catch(a){console.warn("[brender] SSR translation fetch failed:",a.message)}}));return Object.keys(l).length?l:null},j=(t,r)=>{if(!(!t||typeof t!="object")){for(const n in t)if(!(n==="state"||n==="fetch"||n==="props"||n==="attr"||n==="on"||n==="define"||n==="childExtends"||n==="childProps"||n==="childrenAs")&&n.charAt(0)>="A"&&n.charAt(0)<="Z"&&y(t[n])){const s=t[n],e=s.state&&typeof s.state=="object"?{...r,...s.state}:r;if(h(s.children))try{const c={state:e,call:i=>{if(i==="getActiveLang"||i==="getLang")return e?.lang||"ka";if(i==="polyglot")return arguments[1]||""},__ref:{}},o=s.children(c,e);b(o)&&o.length>0&&(s.children=o)}catch{}j(s,e)}}},P=(t,r)=>{if(!(!r||!r.size))for(const[n,s]of r){let e=t;if(n){const c=n.split(".");for(const o of c){if(!e||typeof e!="object")break;e=e[o]}}e&&typeof e=="object"&&((!e.state||typeof e.state!="object")&&(e.state={}),Object.assign(e.state,s),j(e,e.state))}};export{M as fetchSSRTranslations,P as injectPrefetchedState,x as prefetchPageData};
1
+ const o=t=>typeof t=="function",b=t=>Array.isArray(t),g=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),j=(t,r)=>{if(t){if(o(t))try{return t({state:r||{},call:()=>{},__ref:{}},r||{})}catch{return}return t}},k=(t,r)=>{if(!t)return null;if(typeof t=="string")return{from:t,method:"select"};const e=o(t)?null:{...t};return!e||(e.method||(e.method="select"),o(e.params)&&(e.params=j(e.params,r)),e.method==="insert"||e.method==="update"||e.method==="upsert"||e.method==="delete")||e.on&&e.on!=="create"?null:e},S=(t,r="")=>{if(!t||typeof t!="object")return[];if(o(t))return[];const e=[],s=t.state||{};if(t.fetch){const n=b(t.fetch)?t.fetch:[t.fetch];for(const c of n){const a=k(c,s);a&&e.push({config:a,stateKey:a.as,path:r,elementState:s})}}for(const n in t)n==="fetch"||n==="state"||n==="props"||n==="attr"||n==="on"||n==="define"||n==="childExtends"||n==="childProps"||n==="childrenAs"||n.charAt(0)>="A"&&n.charAt(0)<="Z"&&g(t[n])&&e.push(...S(t[n],r?`${r}.${n}`:n));return e},M=["rest","local"],w=new WeakMap,A=async t=>{if(!t)return null;if(g(t)&&(o(t.select)||o(t.rpc)))return t;const r=typeof t=="string"?{adapter:t}:t;if(!g(r)||typeof r.adapter!="string")return null;if(w.has(r))return w.get(r);const e=(async()=>{let s;try{s=await import("@symbo.ls/fetch")}catch{return null}if(!(o(s.hasAdapter)?s.hasAdapter(r.adapter):M.includes(r.adapter)))return null;try{return await s.resolveDb(r)}catch(c){return console.warn(`[brender] SSR adapter "${r.adapter}" unavailable: ${c.message}`),null}})();return w.set(r,e),e},P=async(t,r)=>{try{const{method:e,from:s,params:n,transform:c,limit:a,offset:l,order:u,single:h,headers:d,baseUrl:i}=r;let f;if(e==="rpc"){if(!o(t.rpc))return null;f=await t.rpc({from:s,params:n,headers:d,baseUrl:i})}else{if(!o(t.select))return null;f=await t.select({from:s,select:r.select,params:n,limit:a,offset:l,order:u,single:h,headers:d,baseUrl:i})}let p=f?.data??null;if(f?.error)return null;if(p&&c&&o(c))try{p=c(p)}catch{}return p}catch{return null}},x=async(t,r="/",e={})=>{const n=(t.pages||{})[r];if(!n)return new Map;const c=t.config||t.settings||{},a=c.fetch||t.fetch||c.db||t.db;if(!a)return new Map;const l=await A(a);if(!l)return new Map;const u=S(n);if(!u.length)return new Map;const h=new Map,d=await Promise.allSettled(u.map(async({config:i,stateKey:f,path:p})=>{const y=await P(l,i);if(y!==null){const m=h.get(p)||{};f?m[f]=y:g(y)&&Object.assign(m,y),h.set(p,m)}}));return h},E=async t=>{const r=t.config||{},e=r.polyglot||t.polyglot;if(!e?.fetch)return null;const s=r.fetch||t.fetch||r.db||t.db;if(!s)return null;const n=await A(s);if(!n)return null;const c=e.fetch,a=c.rpc||c.from||"get_translations_if_changed",l=e.languages||[e.defaultLang||"en"],u={},h=await Promise.allSettled(l.map(async d=>{try{if(!o(n.rpc))return;const i=await n.rpc({from:a,params:{p_lang:d,p_cached_version:0}});if(i.error||!i.data)return;const f=i.data;f.translations&&(u[d]=f.translations)}catch(i){console.warn("[brender] SSR translation fetch failed:",i.message)}}));return Object.keys(u).length?u:null},_=(t,r)=>{if(!(!t||typeof t!="object")){for(const e in t)if(!(e==="state"||e==="fetch"||e==="props"||e==="attr"||e==="on"||e==="define"||e==="childExtends"||e==="childProps"||e==="childrenAs")&&e.charAt(0)>="A"&&e.charAt(0)<="Z"&&g(t[e])){const s=t[e],n=s.state&&typeof s.state=="object"?{...r,...s.state}:r;if(o(s.children))try{const c={state:n,call:l=>{if(l==="getActiveLang"||l==="getLang")return n?.lang||"ka";if(l==="polyglot")return arguments[1]||""},__ref:{}},a=s.children(c,n);b(a)&&a.length>0&&(s.children=a)}catch{}_(s,n)}}},D=(t,r)=>{if(!(!r||!r.size))for(const[e,s]of r){let n=t;if(e){const c=e.split(".");for(const a of c){if(!n||typeof n!="object")break;n=n[a]}}n&&typeof n=="object"&&((!n.state||typeof n.state!="object")&&(n.state={}),Object.assign(n.state,s),_(n,n.state))}};export{A as createSSRAdapter,E as fetchSSRTranslations,D as injectPrefetchedState,x as prefetchPageData};
@@ -1,9 +1,21 @@
1
- import{resolve as d,join as tt,dirname as q}from"path";import{existsSync as b,unlinkSync as _t,readFileSync as K,realpathSync as kt}from"fs";import{resolvePackageEntry as $t}from"./packageEntry.js";import{tmpdir as Ct}from"os";import{randomBytes as Tt}from"crypto";import{createRequire as et}from"module";import{createEnv as nt}from"./env.js";import{resetKeys as st,assignKeys as rt,mapKeysToElements as it}from"./keys.js";import{extractMetadata as ct,generateHeadHtml as Ot}from"./metadata.js";import"./hydrate.js";import{prefetchPageData as Lt,injectPrefetchedState as At,fetchSSRTranslations as Pt}from"./prefetch.js";let z=null;const It=async()=>{if(z)return z;try{return z=(await import("@symbo.ls/funcql")).funcqlPlugin,z}catch{return null}};import"linkedom";import{reset as qt}from"@symbo.ls/css";const ot=(t,e)=>{if(!t||!e)return;if(t[e]!==void 0)return t[e];const o=e.split(".");let s=t;for(const r of o){if(s==null||typeof s!="object")return;s=s[r]}return s},vt=function(t,e){if(!t)return"";const o=this?.context,s=o?.polyglot,r=e||s?.defaultLang||"en";if(s?.translations){const c=s.translations[r];if(c){const i=ot(c,t);if(i!==void 0)return i}}const p=this?.state?.root||o?.state?.root;if(p?.translations){const c=p.translations[r];if(c){const i=ot(c,t);if(i!==void 0)return i}}const f=s?.defaultLang||"en";if(f!==r&&s?.translations){const c=s.translations[f];if(c){const i=ot(c,t);if(i!==void 0)return i}}return t},lt=function(){const t=this?.context;return this?.state?.root?.lang||t?.polyglot?.defaultLang||"en"},M=(t,e=new WeakMap)=>{if(t===null||typeof t!="object")return t;if(e.has(t))return e.get(t);if(Array.isArray(t)){const s=[];e.set(t,s);for(const r of t)s.push(typeof r=="object"&&r!==null?M(r,e):r);return s}const o={};e.set(t,o);for(const s of Object.keys(t)){const r=t[s];o[s]=typeof r=="object"&&r!==null?M(r,e):r}return o},at=()=>{const t=new WeakSet;return(e,o)=>{if(typeof o!="function"){if(typeof o=="object"&&o!==null){if(t.has(o))return;t.add(o)}return o}}};let N=null;try{import.meta.url&&(N=et(import.meta.url))}catch{}const ft=()=>{if(!import.meta.url||!N)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:i=>i};const t=kt(new URL(".",import.meta.url).pathname),e=d(t,"../..");if(b(d(e,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:e};let s;try{const i=N.resolve("smbls/package.json");s=q(i)}catch{let i=t;for(;i!==q(i);){const n=d(i,"node_modules","smbls");if(b(d(n,"package.json"))){s=n;break}i=q(i)}}let r=N;if(s)try{r=et(d(s,"package.json"))}catch{}let p,f=process.cwd();for(;f!==q(f);){if(b(d(f,"package.json"))){p=f;break}f=q(f)}let c=r;if(p)try{c=et(d(p,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:s,brenderDir:t,projectRoot:p,_smblsRequire:r,_projectRequire:c}},G=(t,e)=>{const o=t.isMonorepo?[N]:[t._smblsRequire,t._projectRequire,N].filter(Boolean);for(const s of o)try{return s.resolve(e)}catch{}return null},fe=(t,e,...o)=>{if(t.isMonorepo)return d(t.monorepoRoot,"packages",e,...o);const s=G(t,`${e}/package.json`);return s?d(q(s),...o):null},ue=(t,e,...o)=>{if(t.isMonorepo)return d(t.monorepoRoot,"plugins",e,...o);const s=G(t,`@symbo.ls/${e}/package.json`);return s?d(q(s),...o):null},H=(t,e,...o)=>{if(t.isMonorepo){for(const r of["packages","plugins"]){const p=d(t.monorepoRoot,r,e,...o);if(b(p))return p}return null}const s=G(t,`@symbo.ls/${e}/package.json`);return s?d(q(s),...o):null},Y=(t,e,...o)=>{if(t.isMonorepo)return d(t.monorepoRoot,"packages","domql","packages",e,...o);const s=G(t,`@symbo.ls/${e}/package.json`);return s?d(q(s),...o):null};let Z=null;const Et=async()=>{if(Z)return Z;const t=ft();if(!N)try{const c=await import("./dist/createDomql.bundled.mjs");return Z=c,c}catch(c){throw new Error(`brender: pre-bundled createDomql not available in bundled runtime: ${c.message}`)}let e;if(t.isMonorepo)e=d(t.monorepoRoot,"packages","smbls","src","createDomql.js");else if(t.smblsRoot){const c=d(t.smblsRoot,"src","createDomql.js"),i=d(t.smblsRoot,"dist","esm","src","createDomql.js");e=b(c)?c:i}if(!e||!b(e))throw new Error(`brender: cannot find createDomql.js (isMonorepo=${t.isMonorepo}, entry=${e})`);const o=await import("esbuild"),s=tt(Ct(),`br_createDomql_${Tt(6).toString("hex")}.mjs`),r=$t,p={name:"workspace-resolve",setup(c){c.onResolve({filter:/^smbls/},i=>{const n=i.path.replace(/^smbls\/?/,""),l=t.isMonorepo?d(t.monorepoRoot,"packages","smbls"):t.smblsRoot;if(!l)return;if(!n){const m=r(l);return m?{path:m}:void 0}const u=d(l,n);if(b(u))return{path:u};if(b(u+".js"))return{path:u+".js"};const a=d(u,"index.js");if(b(a))return{path:a}}),c.onResolve({filter:/^domql$/},i=>{if(t.isMonorepo){const n=d(t.monorepoRoot,"packages","domql","src","index.js");if(b(n))return{path:n};const l=d(t.monorepoRoot,"packages","domql","index.js");if(b(l))return{path:l}}else try{const n=_require.resolve("domql/package.json"),l=r(q(n));if(l)return{path:l}}catch{}}),c.onResolve({filter:/^@symbo\.ls\//},i=>{const n=i.path.replace("@symbo.ls/","");if(n==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(t.isMonorepo){for(const u of["packages","plugins"]){const a=d(t.monorepoRoot,u,n,"src","index.js");if(b(a))return{path:a};const m=d(t.monorepoRoot,u,n,"index.js");if(b(m))return{path:m}}const l=d(t.monorepoRoot,"packages","default-config","blank","index.js");if(n==="default-config"&&b(l))return{path:l}}else{const l=H(t,n,"src","index.js");if(l&&b(l))return{path:l};const u=H(t,n,"index.js");if(u&&b(u))return{path:u};if(n==="default-config"){const a=H(t,"default-config","blank","index.js");if(a&&b(a))return{path:a}}}}),c.onResolve({filter:/^@domql\//},i=>{const n=i.path.replace("@symbo.ls/","");if(t.isMonorepo){const l=d(t.monorepoRoot,"packages","domql","packages",n,"src","index.js");if(b(l))return{path:l};const u=d(t.monorepoRoot,"packages","domql","packages",n,"index.js");if(b(u))return{path:u}}else{const l=Y(t,n,"src","index.js");if(l&&b(l))return{path:l};const u=Y(t,n,"index.js");if(u&&b(u))return{path:u}}}),c.onResolve({filter:/^css-in-props/},i=>{let n;if(t.isMonorepo)n=d(t.monorepoRoot,"packages","css-in-props");else{const a=G(t,"css-in-props/package.json");a&&(n=q(a))}if(!n)return;const l=i.path.replace(/^css-in-props\/?/,"");if(l){const a=d(n,l),m=d(a,"index.js");if(b(m))return{path:m};if(b(a+".js"))return{path:a+".js"};if(b(a))return{path:a}}const u=r(n);if(u)return{path:u}}),c.onResolve({filter:/^@emotion\//},i=>{let n;if(t.isMonorepo)n=d(t.monorepoRoot,"node_modules",i.path);else{const l=G(t,`${i.path}/package.json`);if(!l)return;n=q(l)}if(b(n)){const l=d(n,"package.json");if(b(l))try{const u=JSON.parse(K(l,"utf8")),a=u.module||u.main||"dist/emotion-css.esm.js";return{path:d(n,a)}}catch{}return{path:n}}}),c.onResolve({filter:/\.json$/},i=>{if(i.resolveDir){const n=d(i.resolveDir,i.path);if(b(n))return{path:n}}}),c.onLoad({filter:/smbls\/.*options\.js$/},async i=>{if(!i.path.includes("smbls/")||!i.path.endsWith("options.js"))return;let n=K(i.path,"utf8");return n=n.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),n=n.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:n,loader:"js"}}),c.onLoad({filter:/smbls\/.*init\.js$/},async i=>{if(!i.path.includes("smbls/")||!i.path.endsWith("init.js"))return;let n=K(i.path,"utf8");return n=n.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:n,loader:"js"}}),c.onLoad({filter:/.*/,namespace:"brender-stub"},()=>({contents:"export const SyncComponent = {}; export const Inspect = {}; export const Notifications = {}; export const syncPlugin = () => ({}); export const notificationsPlugin = () => ({}); export const seedRawDesignSystem = () => {}; export const inspectPlugin = () => ({}); export default {}",loader:"js"})),c.onLoad({filter:/smbls\/src\/router\.js$/},async i=>{let n=K(i.path,"utf8");return n=n.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:n,loader:"js"}}),c.onLoad({filter:/fetchOnCreate\.js$/},async i=>{if(!i.path.includes("smbls/"))return;let n=K(i.path,"utf8");return n=n.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:n,loader:"js"}})}};await o.build({entryPoints:[e],bundle:!0,format:"esm",platform:"node",outfile:s,write:!0,logLevel:"warning",plugins:[p],nodePaths:t.isMonorepo?[d(t.monorepoRoot,"node_modules")]:[...t.smblsRoot?[d(t.smblsRoot,"node_modules")]:[],...t.projectRoot?[d(t.projectRoot,"node_modules")]:[],...t.smblsRoot?[d(t.smblsRoot,"..","..","node_modules")]:[]].filter(c=>b(c)),supported:{"import-attributes":!1},external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker","linkedom"]});const f=await import(`file://${s}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",s);else try{_t(s)}catch{}return Z=f,f},Dt={Box:{},Focusable:{},Block:{display:"block"},Inline:{display:"inline"},Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Link:{tag:"a",attr:{href:t=>t.href,target:t=>t.target,rel:t=>t.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:t=>{let e=t.src;return typeof e=="string"&&e.includes("{{")&&(e=t.call("replaceLiteralsWithObjectFields",e,t.state)),e},alt:t=>t.alt,loading:t=>t.loading}},Image:{extends:"Img"},Button:{tag:"button"},FocusableComponent:{tag:"button"},Form:{tag:"form"},Input:{tag:"input"},TextArea:{tag:"textarea"},Textarea:{tag:"textarea"},Select:{tag:"select"},Label:{tag:"label"},Iframe:{tag:"iframe"},Video:{tag:"video"},Audio:{tag:"audio"},Canvas:{tag:"canvas"},Span:{tag:"span"},P:{tag:"p"},H1:{tag:"h1"},H2:{tag:"h2"},H3:{tag:"h3"},H4:{tag:"h4"},H5:{tag:"h5"},H6:{tag:"h6"},Svg:{tag:"svg",attr:{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"}},Text:{tag:"span"}},ut=(t,e="")=>{if(!t||!t.__ref)return{};const o={},s=t.__ref.__brKey;if(s&&(o[e===""?"__root":e]=s),t.__ref.__children)for(const r of t.__ref.__children){const p=t[r];if(p&&p.__ref){const f=e===""?r:`${e}.${r}`;Object.assign(o,ut(p,f))}}return o},pt=async(t,e={})=>{const{route:o="/",pathname:s,state:r,context:p,prefetch:f=!1}=e,c=s||o,i=globalThis.location,n=globalThis.window;(!globalThis.location||globalThis.location.pathname!==c)&&(globalThis.location={pathname:c,href:c,search:"",hash:"",origin:""}),globalThis.window||(globalThis.window={location:globalThis.location});let l;if(f)try{const y=t.pages||{};l={...y};const E=await Lt(t,o);if(E.size){const V=JSON.parse(JSON.stringify(y[o],(v,B)=>{if(typeof B!="function")return B})),U=(v,B)=>{if(!(!v||!B))for(const D in v)typeof v[D]=="function"?B[D]=v[D]:typeof v[D]=="object"&&v[D]!==null&&!Array.isArray(v[D])&&typeof B[D]=="object"&&B[D]!==null&&U(v[D],B[D])};U(y[o],V),At(V,E),l[o]=V}}catch(y){console.error("[brender] Prefetch error:",y),l=t.pages}let u;if(f)try{u=await Pt(t)}catch(y){console.warn("[brender] SSR translation fetch failed:",y.message)}i!==void 0?globalThis.location=i:delete globalThis.location,n!==void 0?globalThis.window=n:delete globalThis.window;const{window:a,document:m}=nt(),_=m.body;a.location.pathname=c;const h=globalThis.document,g=globalThis.location;globalThis.document=m,globalThis.location=a.location;const{createDomqlElement:I}=await Et(),L=M(t.app||{}),R={...t.config||{}};t.polyglot&&!R.polyglot&&(R.polyglot=t.polyglot),t.fetch&&!R.fetch&&(R.fetch=t.fetch),t.router&&!R.router&&(R.router=t.router);for(const y of["useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDefaultConfig","useDocumentTheme"])t[y]!=null&&R[y]==null&&(R[y]=t[y]);const k=R.polyglot?{...R.polyglot}:void 0;u&&k&&(k.translations={...k.translations||{},...u});const O=M(t.state||{});(u||k)&&(O.root||(O.root={}),k&&(O.root.lang=O.root.lang||k.defaultLang||"en"),u&&(O.root.translations={...O.root.translations||{},...u})),qt();const C={state:O,...r?{state:{...O,...r}}:{},dependencies:M(t.dependencies||{}),components:M(t.components||{}),snippets:M(t.snippets||{}),pages:M(l||t.pages||{}),functions:{...t.functions||{},polyglot:vt,getActiveLang:lt,getLang:lt},methods:t.methods||{},designSystem:M(t.designSystem||{}),files:t.files||{},sharedLibraries:t.sharedLibraries||[],...R,...k?{polyglot:k}:{},document:m,window:a,parent:{node:_},initOptions:{},domqlOptions:{sourcemap:!1},...p||{}},F=await It();F&&(C.plugins=C.plugins||[],C.plugins.some(y=>y.name==="funcql")||C.plugins.push(F)),st();const A=await I(L,C),x=f?2e3:50;await new Promise(y=>setTimeout(y,x)),rt(_);const $=it(A),S=ut(A),w=ct(t,o,A,A?.state),j=[],T=m.head||m.querySelector("head");if(T)for(const y of T.querySelectorAll("style")){if(y.sheet&&y.sheet.cssRules)for(const E of y.sheet.cssRules)E.cssText&&j.push(E.cssText);if(!j.length){const E=y.textContent||"";E&&j.push(E)}}let P=dt(_.innerHTML);if(u){const y=k?.defaultLang||"en",E=u[y]||Object.values(u)[0]||{};P=P.replace(/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,(V,U)=>{const v=U.trim();return E[v]??V})}return h!==void 0?globalThis.document=h:delete globalThis.document,g!==void 0?globalThis.location=g:delete globalThis.location,{html:P,metadata:w,registry:$,brRegistry:S,element:A,emotionCSS:j,document:m,window:a,ssrTranslations:u,prefetchedPages:l}},pe=async(t,e={})=>{const{context:o={}}=e,{window:s,document:r}=nt(),p=r.body,{create:f}=await import("@symbo.ls/element"),c=await import("@symbo.ls/utils"),i={...Dt,...o.components||{}},n={...c,...o.utils||{},...o.functions||{}};st();let l;try{l=f(t,{node:p},"root",{context:{document:r,window:s,...o,components:i,utils:n}})}catch{}rt(p);const u=l?it(l):{};return{html:dt(p.innerHTML),registry:u,element:l}},dt=t=>t.replace(/(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,(e,o,s,r)=>{if(s.includes("&lt;")){const p=s.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&quot;/g,'"').replace(/&#39;/g,"'");return o+p+r}return e});let W=null;const Mt=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],mt=t=>{if(!t||typeof t!="object")return null;if(t.config&&typeof t.config=="object")return t.config;const e={};let o=!1;for(const s of Mt)Object.prototype.hasOwnProperty.call(t,s)&&(e[s]=t[s],o=!0);return o?e:t.settings||null},gt=async(t,e)=>{if(W)return W;try{const{existsSync:o,writeFileSync:s,unlinkSync:r}=await import("fs"),{tmpdir:p}=await import("os"),{randomBytes:f}=await import("crypto");try{p()}catch{return{}}const c=await import("esbuild"),i=JSON.stringify(t||{},at()),n=JSON.stringify(e||{},at()),l=tt(p(),`br_global_${f(6).toString("hex")}.mjs`),u=tt(p(),`br_global_${f(6).toString("hex")}_out.mjs`);s(l,`
1
+ import{resolve as m,join as Q,dirname as P}from"path";import{existsSync as y,unlinkSync as Ct,readFileSync as K,realpathSync as Tt}from"fs";import{resolvePackageEntry as Ot}from"./packageEntry.js";import{tmpdir as Lt}from"os";import{randomBytes as It}from"crypto";import{createRequire as tt}from"module";import{createEnv as st}from"./env.js";import{resetKeys as rt,assignKeys as it,mapKeysToElements as ct}from"./keys.js";import{extractMetadata as et,generateHeadHtml as At}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as Et}from"./shell.js";import{prefetchPageData as Pt,injectPrefetchedState as qt,fetchSSRTranslations as vt}from"./prefetch.js";let z=null;const Dt=async()=>{if(z)return z;try{return z=(await import("@symbo.ls/funcql")).funcqlPlugin,z}catch{return null}};import"linkedom";import{reset as Mt}from"@symbo.ls/css";const ot=(t,e)=>{if(!t||!e)return;if(t[e]!==void 0)return t[e];const o=e.split(".");let n=t;for(const r of o){if(n==null||typeof n!="object")return;n=n[r]}return n},Ft=function(t,e){if(!t)return"";const o=this?.context,n=o?.polyglot,r=e||n?.defaultLang||"en";if(n?.translations){const l=n.translations[r];if(l){const c=ot(l,t);if(c!==void 0)return c}}const u=this?.state?.root||o?.state?.root;if(u?.translations){const l=u.translations[r];if(l){const c=ot(l,t);if(c!==void 0)return c}}const p=n?.defaultLang||"en";if(p!==r&&n?.translations){const l=n.translations[p];if(l){const c=ot(l,t);if(c!==void 0)return c}}return t},lt=function(){const t=this?.context;return this?.state?.root?.lang||t?.polyglot?.defaultLang||"en"},F=(t,e=new WeakMap)=>{if(t===null||typeof t!="object")return t;if(e.has(t))return e.get(t);if(Array.isArray(t)){const n=[];e.set(t,n);for(const r of t)n.push(typeof r=="object"&&r!==null?F(r,e):r);return n}const o={};e.set(t,o);for(const n of Object.keys(t)){const r=t[n];o[n]=typeof r=="object"&&r!==null?F(r,e):r}return o},at=()=>{const t=new WeakSet;return(e,o)=>{if(typeof o!="function"){if(typeof o=="object"&&o!==null){if(t.has(o))return;t.add(o)}return o}}};let B=null;try{import.meta.url&&(B=tt(import.meta.url))}catch{}const ft=()=>{if(!import.meta.url||!B)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:c=>c};const t=Tt(new URL(".",import.meta.url).pathname),e=m(t,"../..");if(y(m(e,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:e};let n;try{const c=B.resolve("smbls/package.json");n=P(c)}catch{let c=t;for(;c!==P(c);){const s=m(c,"node_modules","smbls");if(y(m(s,"package.json"))){n=s;break}c=P(c)}}let r=B;if(n)try{r=tt(m(n,"package.json"))}catch{}let u,p=process.cwd();for(;p!==P(p);){if(y(m(p,"package.json"))){u=p;break}p=P(p)}let l=r;if(u)try{l=tt(m(u,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:n,brenderDir:t,projectRoot:u,_smblsRequire:r,_projectRequire:l}},H=(t,e)=>{const o=t.isMonorepo?[B]:[t._smblsRequire,t._projectRequire,B].filter(Boolean);for(const n of o)try{return n.resolve(e)}catch{}return null},he=(t,e,...o)=>{if(t.isMonorepo)return m(t.monorepoRoot,"packages",e,...o);const n=H(t,`${e}/package.json`);return n?m(P(n),...o):null},be=(t,e,...o)=>{if(t.isMonorepo)return m(t.monorepoRoot,"plugins",e,...o);const n=H(t,`@symbo.ls/${e}/package.json`);return n?m(P(n),...o):null},nt=(t,e,...o)=>{if(t.isMonorepo){for(const r of["packages","plugins"]){const u=m(t.monorepoRoot,r,e,...o);if(y(u))return u}return null}const n=H(t,`@symbo.ls/${e}/package.json`);return n?m(P(n),...o):null},Y=(t,e,...o)=>{if(t.isMonorepo)return m(t.monorepoRoot,"packages","domql","packages",e,...o);const n=H(t,`@symbo.ls/${e}/package.json`);return n?m(P(n),...o):null};let W=null;const ut="smbls/ssr",pt=async()=>{const t=await import("smbls/ssr");if(typeof t?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return t},Nt=async()=>{if(W)return W;const t=ft();if(!B)try{return W=await pt(),W}catch(l){throw new Error(`brender: ${ut} is not available in this bundled runtime (${l.message}). Bundle smbls \u2265 the release that adds the smbls/ssr export alongside @symbo.ls/brender.`)}let e;if(t.isMonorepo)e=m(t.monorepoRoot,"packages","smbls","src","createDomql.js");else{let l;try{return W=await pt(),W}catch(s){l=s}const c=t.smblsRoot&&m(t.smblsRoot,"src","createDomql.js");if(c&&y(c))e=c;else throw new Error(`brender: cannot load ${ut} (${l.message}). Server rendering needs smbls installed in this project, at a release that exports smbls/ssr`+(t.smblsRoot?` (found smbls at ${t.smblsRoot}).`:" (no smbls package found)."))}const o=await import("esbuild"),n=Q(Lt(),`br_createDomql_${It(6).toString("hex")}.mjs`),r=Ot,u={name:"workspace-resolve",setup(l){l.onResolve({filter:/^smbls/},c=>{const s=c.path.replace(/^smbls\/?/,""),i=t.isMonorepo?m(t.monorepoRoot,"packages","smbls"):t.smblsRoot;if(!i)return;if(!s){const g=r(i);return g?{path:g}:void 0}const a=m(i,s);if(y(a))return{path:a};if(y(a+".js"))return{path:a+".js"};const f=m(a,"index.js");if(y(f))return{path:f}}),l.onResolve({filter:/^domql$/},c=>{if(t.isMonorepo){const s=m(t.monorepoRoot,"packages","domql","src","index.js");if(y(s))return{path:s};const i=m(t.monorepoRoot,"packages","domql","index.js");if(y(i))return{path:i}}else try{const s=_require.resolve("domql/package.json"),i=r(P(s));if(i)return{path:i}}catch{}}),l.onResolve({filter:/^@symbo\.ls\//},c=>{const s=c.path.replace("@symbo.ls/","");if(s==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(t.isMonorepo){for(const a of["packages","plugins"]){const f=m(t.monorepoRoot,a,s,"src","index.js");if(y(f))return{path:f};const g=m(t.monorepoRoot,a,s,"index.js");if(y(g))return{path:g}}const i=m(t.monorepoRoot,"packages","default-config","blank","index.js");if(s==="default-config"&&y(i))return{path:i}}else{const i=nt(t,s,"src","index.js");if(i&&y(i))return{path:i};const a=nt(t,s,"index.js");if(a&&y(a))return{path:a};if(s==="default-config"){const f=nt(t,"default-config","blank","index.js");if(f&&y(f))return{path:f}}}}),l.onResolve({filter:/^@domql\//},c=>{const s=c.path.replace("@symbo.ls/","");if(t.isMonorepo){const i=m(t.monorepoRoot,"packages","domql","packages",s,"src","index.js");if(y(i))return{path:i};const a=m(t.monorepoRoot,"packages","domql","packages",s,"index.js");if(y(a))return{path:a}}else{const i=Y(t,s,"src","index.js");if(i&&y(i))return{path:i};const a=Y(t,s,"index.js");if(a&&y(a))return{path:a}}}),l.onResolve({filter:/^css-in-props/},c=>{let s;if(t.isMonorepo)s=m(t.monorepoRoot,"packages","css-in-props");else{const f=H(t,"css-in-props/package.json");f&&(s=P(f))}if(!s)return;const i=c.path.replace(/^css-in-props\/?/,"");if(i){const f=m(s,i),g=m(f,"index.js");if(y(g))return{path:g};if(y(f+".js"))return{path:f+".js"};if(y(f))return{path:f}}const a=r(s);if(a)return{path:a}}),l.onResolve({filter:/^@emotion\//},c=>{let s;if(t.isMonorepo)s=m(t.monorepoRoot,"node_modules",c.path);else{const i=H(t,`${c.path}/package.json`);if(!i)return;s=P(i)}if(y(s)){const i=m(s,"package.json");if(y(i))try{const a=JSON.parse(K(i,"utf8")),f=a.module||a.main||"dist/emotion-css.esm.js";return{path:m(s,f)}}catch{}return{path:s}}}),l.onResolve({filter:/\.json$/},c=>{if(c.resolveDir){const s=m(c.resolveDir,c.path);if(y(s))return{path:s}}}),l.onLoad({filter:/smbls\/.*options\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("options.js"))return;let s=K(c.path,"utf8");return s=s.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),s=s.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:s,loader:"js"}}),l.onLoad({filter:/smbls\/.*init\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("init.js"))return;let s=K(c.path,"utf8");return s=s.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:s,loader:"js"}}),l.onLoad({filter:/.*/,namespace:"brender-stub"},()=>({contents:"export const SyncComponent = {}; export const Inspect = {}; export const Notifications = {}; export const syncPlugin = () => ({}); export const notificationsPlugin = () => ({}); export const seedRawDesignSystem = () => {}; export const inspectPlugin = () => ({}); export default {}",loader:"js"})),l.onLoad({filter:/smbls\/src\/router\.js$/},async c=>{let s=K(c.path,"utf8");return s=s.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:s,loader:"js"}}),l.onLoad({filter:/fetchOnCreate\.js$/},async c=>{if(!c.path.includes("smbls/"))return;let s=K(c.path,"utf8");return s=s.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:s,loader:"js"}})}};await o.build({entryPoints:[e],bundle:!0,format:"esm",platform:"node",outfile:n,write:!0,logLevel:"warning",plugins:[u],nodePaths:t.isMonorepo?[m(t.monorepoRoot,"node_modules")]:[...t.smblsRoot?[m(t.smblsRoot,"node_modules")]:[],...t.projectRoot?[m(t.projectRoot,"node_modules")]:[],...t.smblsRoot?[m(t.smblsRoot,"..","..","node_modules")]:[]].filter(l=>y(l)),supported:{"import-attributes":!1},external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker","linkedom"]});const p=await import(`file://${n}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",n);else try{Ct(n)}catch{}return W=p,p},Bt={Box:{},Focusable:{},Block:{display:"block"},Inline:{display:"inline"},Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Link:{tag:"a",attr:{href:t=>t.href,target:t=>t.target,rel:t=>t.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:t=>{let e=t.src;return typeof e=="string"&&e.includes("{{")&&(e=t.call("replaceLiteralsWithObjectFields",e,t.state)),e},alt:t=>t.alt,loading:t=>t.loading}},Image:{extends:"Img"},Button:{tag:"button"},FocusableComponent:{tag:"button"},Form:{tag:"form"},Input:{tag:"input"},TextArea:{tag:"textarea"},Textarea:{tag:"textarea"},Select:{tag:"select"},Label:{tag:"label"},Iframe:{tag:"iframe"},Video:{tag:"video"},Audio:{tag:"audio"},Canvas:{tag:"canvas"},Span:{tag:"span"},P:{tag:"p"},H1:{tag:"h1"},H2:{tag:"h2"},H3:{tag:"h3"},H4:{tag:"h4"},H5:{tag:"h5"},H6:{tag:"h6"},Svg:{tag:"svg",attr:{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"}},Text:{tag:"span"}},mt=(t,e="")=>{if(!t||!t.__ref)return{};const o={},n=t.__ref.__brKey;if(n&&(o[e===""?"__root":e]=n),t.__ref.__children)for(const r of t.__ref.__children){const u=t[r];if(u&&u.__ref){const p=e===""?r:`${e}.${r}`;Object.assign(o,mt(u,p))}}return o},dt=async(t,e={})=>{const{route:o="/",pathname:n,state:r,context:u,prefetch:p=!1}=e,l=n||o,c=globalThis.location,s=globalThis.window;(!globalThis.location||globalThis.location.pathname!==l)&&(globalThis.location={pathname:l,href:l,search:"",hash:"",origin:""}),globalThis.window||(globalThis.window={location:globalThis.location});let i;if(p)try{const h=t.pages||{};i={...h};const O=await Pt(t,o);if(O.size){const V=JSON.parse(JSON.stringify(h[o],(v,N)=>{if(typeof N!="function")return N})),U=(v,N)=>{if(!(!v||!N))for(const D in v)typeof v[D]=="function"?N[D]=v[D]:typeof v[D]=="object"&&v[D]!==null&&!Array.isArray(v[D])&&typeof N[D]=="object"&&N[D]!==null&&U(v[D],N[D])};U(h[o],V),qt(V,O),i[o]=V}}catch(h){console.error("[brender] Prefetch error:",h),i=t.pages}let a;if(p)try{a=await vt(t)}catch(h){console.warn("[brender] SSR translation fetch failed:",h.message)}c!==void 0?globalThis.location=c:delete globalThis.location,s!==void 0?globalThis.window=s:delete globalThis.window;const{window:f,document:g}=st(),T=g.body;f.location.pathname=l;const d=globalThis.document,b=globalThis.location;globalThis.document=g,globalThis.location=f.location;const{createDomqlElement:q}=await Nt(),L=F(t.app||{}),S={...t.config||{}};t.polyglot&&!S.polyglot&&(S.polyglot=t.polyglot),t.fetch&&!S.fetch&&(S.fetch=t.fetch),t.router&&!S.router&&(S.router=t.router);for(const h of["useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDefaultConfig","useDocumentTheme"])t[h]!=null&&S[h]==null&&(S[h]=t[h]);const _=S.polyglot?{...S.polyglot}:void 0;a&&_&&(_.translations={..._.translations||{},...a});const j=F(t.state||{});(a||_)&&(j.root||(j.root={}),_&&(j.root.lang=j.root.lang||_.defaultLang||"en"),a&&(j.root.translations={...j.root.translations||{},...a})),Mt();const M={state:j,...r?{state:{...j,...r}}:{},dependencies:F(t.dependencies||{}),components:F(t.components||{}),snippets:F(t.snippets||{}),pages:F(i||t.pages||{}),functions:{...t.functions||{},polyglot:Ft,getActiveLang:lt,getLang:lt},methods:t.methods||{},designSystem:F(t.designSystem||{}),files:t.files||{},sharedLibraries:t.sharedLibraries||[],...S,..._?{polyglot:_}:{},document:g,window:f,parent:{node:T},initOptions:{},domqlOptions:{sourcemap:!1},sync:!1,inspect:!1,notifications:!1,...u||{}},k=await Dt();k&&(M.plugins=M.plugins||[],M.plugins.some(h=>h.name==="funcql")||M.plugins.push(k)),rt();const I=await q(L,M),E=p?2e3:50;await new Promise(h=>setTimeout(h,E)),it(T);const w=ct(I),C=mt(I),R=et(t,o,I,I?.state),x=[],$=g.head||g.querySelector("head");if($)for(const h of $.querySelectorAll("style")){if(h.sheet&&h.sheet.cssRules)for(const O of h.sheet.cssRules)O.cssText&&x.push(O.cssText);if(!x.length){const O=h.textContent||"";O&&x.push(O)}}let A=gt(T.innerHTML);if(a){const h=_?.defaultLang||"en",O=a[h]||Object.values(a)[0]||{};A=A.replace(/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,(V,U)=>{const v=U.trim();return O[v]??V})}return d!==void 0?globalThis.document=d:delete globalThis.document,b!==void 0?globalThis.location=b:delete globalThis.location,{html:A,metadata:R,registry:w,brRegistry:C,element:I,emotionCSS:x,document:g,window:f,ssrTranslations:a,prefetchedPages:i}},ye=async(t,e={})=>{const{context:o={}}=e,{window:n,document:r}=st(),u=r.body,{create:p}=await import("@symbo.ls/element"),l=await import("@symbo.ls/utils"),c={...Bt,...o.components||{}},s={...l,...o.utils||{},...o.functions||{}};rt();let i;try{i=p(t,{node:u},"root",{context:{document:r,window:n,...o,components:c,utils:s}})}catch{}it(u);const a=i?ct(i):{};return{html:gt(u.innerHTML),registry:a,element:i}},gt=t=>t.replace(/(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,(e,o,n,r)=>{if(n.includes("&lt;")){const u=n.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&quot;/g,'"').replace(/&#39;/g,"'");return o+u+r}return e});let J=null;const Wt=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],ht=t=>{if(!t||typeof t!="object")return null;if(t.config&&typeof t.config=="object")return t.config;const e={};let o=!1;for(const n of Wt)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n],o=!0);return o?e:t.settings||null},bt=(t,e,o)=>{const n=Object.entries(e||{}).map(([r,u])=>`${o} ${r}: ${u}`).join(`;
2
+ `);return n?`${o}${t} {
3
+ ${n};
4
+ ${o}}`:""},Jt=t=>Object.entries(t||{}).map(([e,o])=>{if(!e.startsWith("@"))return bt(e,o,"");const n=Object.entries(o||{}).map(([r,u])=>bt(r,u," ")).filter(Boolean).join(`
5
+ `);return n?`${e} {
6
+ ${n}
7
+ }`:""}).filter(Boolean).join(`
8
+
9
+ `),yt=async(t,e)=>{if(J)return J;try{const{existsSync:o,writeFileSync:n,unlinkSync:r}=await import("fs"),{tmpdir:u}=await import("os"),{randomBytes:p}=await import("crypto");try{u()}catch{return{}}const l=await import("esbuild"),c=JSON.stringify(t||{},at()),s=JSON.stringify(e||{},at()),i=Q(u(),`br_global_${p(6).toString("hex")}.mjs`),a=Q(u(),`br_global_${p(6).toString("hex")}_out.mjs`);n(i,`
2
10
  import { set, getActiveConfig, getFontFaceString } from '@symbo.ls/scratch'
11
+ // Namespace access for the skin builder: a scratch without it (version
12
+ // skew) gives an empty skin block instead of failing this whole bundle
13
+ // and, with it, every global rule.
14
+ import * as scratchNs from '@symbo.ls/scratch'
3
15
  import { DEFAULT_CONFIG } from '@symbo.ls/default-config'
4
16
 
5
- const ds = ${i}
6
- const cfg = ${n}
17
+ const ds = ${c}
18
+ const cfg = ${s}
7
19
 
8
20
  // Merge with defaults (same as initEmotion)
9
21
  const merged = {}
@@ -30,39 +42,46 @@ import{resolve as d,join as tt,dirname as q}from"path";import{existsSync as b,un
30
42
  const result = {
31
43
  CSS_VARS: conf.CSS_VARS || {},
32
44
  CSS_MEDIA_VARS: conf.CSS_MEDIA_VARS || {},
45
+ // Skin rules \u2014 the same builder smbls init() injects on the client
46
+ // (FW-SCRATCH-SKINS-DIMENSION-1).
47
+ CSS_SKIN_RULES: typeof scratchNs.buildSkinVarStyles === 'function'
48
+ ? scratchNs.buildSkinVarStyles(conf.cssSkinVars, conf.cssSkinFallback, ':root')
49
+ : {},
33
50
  reset: conf.reset || {},
34
51
  animation: conf.animation || {}
35
52
  }
36
53
  // Export as globalThis so we can read it
37
54
  globalThis.__BR_GLOBAL_CSS__ = result
38
55
  export default result
39
- `);const a=ft(),m={name:"workspace-resolve",setup(x){x.onResolve({filter:/^@symbo\.ls\//},$=>{const S=$.path.replace("@symbo.ls/","");if(a.isMonorepo){for(const j of["packages","plugins"]){const T=d(a.monorepoRoot,j,S,"src","index.js");if(o(T))return{path:T};const P=d(a.monorepoRoot,j,S,"index.js");if(o(P))return{path:P}}const w=d(a.monorepoRoot,"packages","default-config","blank","index.js");if(S==="default-config"&&o(w))return{path:w}}else{const w=H(a,S,"src","index.js");if(w&&o(w))return{path:w};const j=H(a,S,"index.js");if(j&&o(j))return{path:j};if(S==="default-config"){const T=H(a,"default-config","blank","index.js");if(T&&o(T))return{path:T}}}}),x.onResolve({filter:/^@domql\//},$=>{const S=$.path.replace("@symbo.ls/","");if(a.isMonorepo){const w=d(a.monorepoRoot,"packages","domql","packages",S,"src","index.js");if(o(w))return{path:w}}else{const w=Y(a,S,"src","index.js");if(w&&o(w))return{path:w};const j=Y(a,S,"index.js");if(j&&o(j))return{path:j}}})}};await c.build({entryPoints:[l],bundle:!0,format:"esm",platform:"node",outfile:u,write:!0,logLevel:"silent",plugins:[m],nodePaths:a.isMonorepo?[d(a.monorepoRoot,"node_modules")]:[...a.smblsRoot?[d(a.smblsRoot,"node_modules")]:[],...a.projectRoot?[d(a.projectRoot,"node_modules")]:[],...a.smblsRoot?[d(a.smblsRoot,"..","..","node_modules")]:[]].filter(x=>o(x)),external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker"]});const h=(await import(`file://${u}`)).default||{};try{r(l)}catch{}try{r(u)}catch{}const g=h.CSS_VARS||{},I=h.CSS_MEDIA_VARS||{},L=h.RESET||{},R=h.ANIMATION||{},k=Object.entries(g).map(([x,$])=>` ${x}: ${$}`).join(`;
40
- `);let O=k?`:root {
41
- ${k};
42
- }`:"";const C=Object.entries(I).map(([x,$])=>{const S=Object.entries($).map(([w,j])=>` ${w}: ${j}`).join(`;
43
- `);return S?x.startsWith("@media")?`${x} {
56
+ `);const f=ft(),g={name:"workspace-resolve",setup(w){w.onResolve({filter:/^@symbo\.ls\//},C=>{const R=C.path.replace("@symbo.ls/","");if(f.isMonorepo){for(const $ of["packages","plugins"]){const A=m(f.monorepoRoot,$,R,"src","index.js");if(o(A))return{path:A};const h=m(f.monorepoRoot,$,R,"index.js");if(o(h))return{path:h}}const x=m(f.monorepoRoot,"packages","default-config","blank","index.js");if(R==="default-config"&&o(x))return{path:x}}}),w.onResolve({filter:/^@domql\//},C=>{const R=C.path.replace("@symbo.ls/","");if(f.isMonorepo){const x=m(f.monorepoRoot,"packages","domql","packages",R,"src","index.js");if(o(x))return{path:x}}else{const x=Y(f,R,"src","index.js");if(x&&o(x))return{path:x};const $=Y(f,R,"index.js");if($&&o($))return{path:$}}})}};await l.build({entryPoints:[i],bundle:!0,format:"esm",platform:"node",outfile:a,write:!0,logLevel:"silent",plugins:[g],nodePaths:f.isMonorepo?[m(f.monorepoRoot,"node_modules")]:[...f.smblsRoot?[m(f.smblsRoot,"node_modules")]:[],...f.projectRoot?[m(f.projectRoot,"node_modules")]:[],...f.smblsRoot?[m(f.smblsRoot,"..","..","node_modules")]:[]].filter(w=>o(w)),external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker"]});const d=(await import(`file://${a}`)).default||{};try{r(i)}catch{}try{r(a)}catch{}const b=d.CSS_VARS||{},q=d.CSS_MEDIA_VARS||{},L=d.RESET||{},S=d.ANIMATION||{},_=Object.entries(b).map(([w,C])=>` ${w}: ${C}`).join(`;
57
+ `);let j=_?`:root {
58
+ ${_};
59
+ }`:"";const M=Object.entries(q).map(([w,C])=>{const R=Object.entries(C).map(([x,$])=>` ${x}: ${$}`).join(`;
60
+ `);return R?w.startsWith("@media")?`${w} {
44
61
  :root:not([data-theme]) {
45
- ${S};
62
+ ${R};
46
63
  }
47
- }`:`${x} {
48
- ${S};
64
+ }`:`${w} {
65
+ ${R};
49
66
  }`:""}).filter(Boolean).join(`
50
67
 
51
- `);C&&(O+=`
68
+ `);M&&(j+=`
69
+
70
+ `+M);const k=Jt(d.CSS_SKIN_RULES);k&&(j+=(j?`
52
71
 
53
- `+C);const F=wt(L),A=[];for(const x in R){const $=R[x];if(!$||typeof $!="object")continue;const S=Object.entries($).map(([w,j])=>{if(typeof j!="object")return"";const T=Object.entries(j).map(([P,y])=>`${J(P)}: ${y}`).join("; ");return` ${w} { ${T}; }`}).join(`
54
- `);A.push(`@keyframes ${x} {
55
- ${S}
56
- }`)}return W={rootRule:O,resetRules:F,fontFaceCSS:"",keyframeRules:A.join(`
57
- `)},W}catch(o){return console.warn("generateGlobalCSS failed:",o.message,o.stack),W={rootRule:"",resetRules:"",fontFaceCSS:"",keyframeRules:""},W}};let X=new Set;const de=()=>{W=null,X=new Set},me=()=>Array.from(X).join(`
58
- `),ge=(t,e)=>t.replace(/<style data-emotion="smbls">[\s\S]*?<\/style>/,e?`<style data-emotion="smbls">
72
+ `:"")+k);const I=kt(L),E=[];for(const w in S){const C=S[w];if(!C||typeof C!="object")continue;const R=Object.entries(C).map(([x,$])=>{if(typeof $!="object")return"";const A=Object.entries($).map(([h,O])=>`${G(h)}: ${O}`).join("; ");return` ${x} { ${A}; }`}).join(`
73
+ `);E.push(`@keyframes ${w} {
74
+ ${R}
75
+ }`)}return J={rootRule:j,resetRules:I,fontFaceCSS:"",keyframeRules:E.join(`
76
+ `)},J}catch(o){return console.warn("generateGlobalCSS failed:",o.message,o.stack),J={rootRule:"",resetRules:"",fontFaceCSS:"",keyframeRules:""},J}};let Z=new Set;const Se=()=>{J=null,Z=new Set},Re=()=>Array.from(Z).join(`
77
+ `),je=(t,e)=>t.replace(/<style data-emotion="smbls">[\s\S]*?<\/style>/,e?`<style data-emotion="smbls">
59
78
  ${e}
60
- </style>`:""),he=async(t,e={})=>{const{route:o="/",pathname:s}=e,r=await pt(t,{route:o,pathname:s,prefetch:!0});if(!r)return null;const p=t.designSystem||{},f=await gt(p,mt(t));let c=null,i=null;try{const n=r.element,l=n?.context?.polyglot||t.polyglot||t.config?.polyglot;if(i=n?.state?.root?.lang||l?.defaultLang||"en",r.prefetchedPages&&r.prefetchedPages[o]){const u=r.prefetchedPages[o],a=(m,_={})=>{if(!m||typeof m!="object")return _;if(m.state&&typeof m.state=="object")for(const[h,g]of Object.entries(m.state))g!=null&&typeof g!="function"&&(_[h]=g);for(const[h,g]of Object.entries(m))h==="state"||h==="props"||h==="attr"||h==="on"||h==="define"||h==="__ref"||h.startsWith("__")||g&&typeof g=="object"&&!Array.isArray(g)&&a(g,_);return _};c=a(u)}}catch{}return{html:r.html,css:r.emotionCSS?r.emotionCSS.join(`
61
- `):"",globalCSS:f,resetCss:f.resetRules||wt(p.reset),fontLinks:xt(p),metadata:r.metadata||ct(t,o),brKeyCount:r.registry?Object.keys(r.registry).length:0,brRegistry:r.brRegistry||{},ssrTranslations:r.ssrTranslations,prefetchedState:c,activeLang:i}},ye=async(t,e="/",o={})=>{const{lang:s,themeColor:r,isr:p,hydrate:f=!0,prefetch:c=!0}=o,i=s||t.state?.lang||t.app?.metadata?.lang||"en",n=await pt(t,{route:e,prefetch:c});if(!n)return null;const l={...n.metadata};r&&(l["theme-color"]=r);const u=Ot(l);if(n.emotionCSS&&n.emotionCSS.length)for(const C of n.emotionCSS)C&&X.add(C);const a=Array.from(X).join(`
62
- `),m=t.designSystem||{},_=await gt(m,mt(t)),h=xt(m),g=Object.keys(n.registry).length;let I="";if(p&&p.clientScript){const C=e==="/"?0:e.replace(/^\/|\/$/g,"").split("/").length,F=C>0?"../".repeat(C):"./";if(f){let A="";if(n.ssrTranslations){const S=t.polyglot||t.config?.polyglot,w=S?.storagePrefix||"",j=S?.storageLangKey||"",T=[];for(const P in n.ssrTranslations){const y=n.ssrTranslations[P];y&&typeof y=="object"&&T.push(`localStorage.setItem(${JSON.stringify(w+P)},${JSON.stringify(JSON.stringify(y))})`)}if(j){const P=S?.defaultLang||"en";T.push(`if(!localStorage.getItem(${JSON.stringify(j)}))localStorage.setItem(${JSON.stringify(j)},${JSON.stringify(P)})`)}T.length&&(A=`<script>try{${T.join(";")}}catch(e){}<\/script>
63
- `)}const x=n.brRegistry&&Object.keys(n.brRegistry).length?JSON.stringify(n.brRegistry):null,$=x?`<script>window.__BR_REGISTRY__=${x}<\/script>
64
- `:"";I=`${A}${$}<script>window.__BRENDER__=true<\/script>
65
- <script type="module" src="${F}${p.clientScript}"><\/script>`}else I=`<script type="module">
79
+ </style>`:""),we=async(t,e={})=>{const{route:o="/",pathname:n}=e,r=await dt(t,{route:o,pathname:n,prefetch:!0});if(!r)return null;const u=t.designSystem||{},p=await yt(u,ht(t));let l=null,c=null;try{const s=r.element,i=s?.context?.polyglot||t.polyglot||t.config?.polyglot;if(c=s?.state?.root?.lang||i?.defaultLang||"en",r.prefetchedPages&&r.prefetchedPages[o]){const a=r.prefetchedPages[o],f=(g,T={})=>{if(!g||typeof g!="object")return T;if(g.state&&typeof g.state=="object")for(const[d,b]of Object.entries(g.state))b!=null&&typeof b!="function"&&(T[d]=b);for(const[d,b]of Object.entries(g))d==="state"||d==="props"||d==="attr"||d==="on"||d==="define"||d==="__ref"||d.startsWith("__")||b&&typeof b=="object"&&!Array.isArray(b)&&f(b,T);return T};l=f(a)}}catch{}return{html:r.html,css:r.emotionCSS?r.emotionCSS.join(`
80
+ `):"",globalCSS:p,resetCss:p.resetRules||kt(u.reset),fontLinks:$t(u),metadata:r.metadata||et(t,o),brKeyCount:r.registry?Object.keys(r.registry).length:0,brRegistry:r.brRegistry||{},ssrTranslations:r.ssrTranslations,prefetchedState:l,activeLang:c}},xe=async(t,e="/",o={})=>{const{lang:n,themeColor:r,isr:u,hydrate:p=!0,prefetch:l=!0,shell:c}=o,s=n||t.state?.lang||t.app?.metadata?.lang||"en",i=await dt(t,{route:e,prefetch:l});if(!i)return null;const a={...i.metadata};if(r&&(a["theme-color"]=r),typeof c=="string"&&!t.name){const k="\0brender-undeclared-title\0";if(et({...t,name:k},e,i.element,i.element?.state).title===k)for(const E of["title","og:title","twitter:title"])a[E]===i.metadata.title&&delete a[E]}const f=At(a);if(i.emotionCSS&&i.emotionCSS.length)for(const k of i.emotionCSS)k&&Z.add(k);const g=Array.from(Z).join(`
81
+ `),T=t.designSystem||{},d=await yt(T,ht(t)),b=$t(T),q=Object.keys(i.registry).length;let L="";if(u&&u.clientScript){const k=Number.isInteger(o.depth)?o.depth:e==="/"?0:e.replace(/^\/|\/$/g,"").split("/").length,I=k>0?"../".repeat(k):"./";if(p){let E="";if(i.ssrTranslations){const R=t.polyglot||t.config?.polyglot,x=R?.storagePrefix||"",$=R?.storageLangKey||"",A=[];for(const h in i.ssrTranslations){const O=i.ssrTranslations[h];O&&typeof O=="object"&&A.push(`localStorage.setItem(${JSON.stringify(x+h)},${JSON.stringify(JSON.stringify(O))})`)}if($){const h=R?.defaultLang||"en";A.push(`if(!localStorage.getItem(${JSON.stringify($)}))localStorage.setItem(${JSON.stringify($)},${JSON.stringify(h)})`)}A.length&&(E=`<script>try{${A.join(";")}}catch(e){}<\/script>
82
+ `)}const w=i.brRegistry&&Object.keys(i.brRegistry).length?JSON.stringify(i.brRegistry):null,C=w?`<script>window.__BR_REGISTRY__=${w}<\/script>
83
+ `:"";L=`${E}${C}<script>window.__BRENDER__=true<\/script>
84
+ <script type="module" src="${I}${u.clientScript}"><\/script>`}else L=`<script type="module">
66
85
  {
67
86
  const brEls = document.querySelectorAll('body > :not(script):not(style)')
68
87
  const observer = new MutationObserver((mutations) => {
@@ -79,30 +98,37 @@ ${e}
79
98
  observer.observe(document.body, { childList: true })
80
99
  }
81
100
  <\/script>
82
- <script type="module" src="${F}${p.clientScript}"><\/script>`}const L={...t.config||{}};t.polyglot&&!L.polyglot&&(L.polyglot=t.polyglot);const R=L.polyglot;let k=u;if(R){const C=R.defaultLang||"en",A={...R.translations||{},...n.ssrTranslations||{}}[C]||{};k=u.replace(/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,(x,$)=>{const S=$.trim();return A[S]??x})}return{html:`<!DOCTYPE html>
83
- <html lang="${i}">
101
+ <script type="module" src="${I}${u.clientScript}"><\/script>`}const S={...t.config||{}};t.polyglot&&!S.polyglot&&(S.polyglot=t.polyglot);const _=S.polyglot;let j=f;if(_){const k=_.defaultLang||"en",E={..._.translations||{},...i.ssrTranslations||{}}[k]||{};j=f.replace(/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,(w,C)=>{const R=C.trim();return E[R]??w})}if(typeof c=="string"){const k=[d.fontFaceCSS?`<style>${d.fontFaceCSS}</style>`:"",`<style>
102
+ ${d.rootRule||""}
103
+ ${d.resetRules||""}
104
+ ${d.keyframeRules||""}
105
+ </style>`,g?`<style data-emotion="smbls">
106
+ ${g}
107
+ </style>`:""];return{html:Et(c,{headTags:j,headEnd:[b,...k].filter(Boolean).join(`
108
+ `),body:i.html,depth:Number.isInteger(o.depth)?o.depth:0}),route:e,brKeyCount:q,shell:!0}}return{html:`<!DOCTYPE html>
109
+ <html lang="${s}">
84
110
  <head>
85
- ${k}
86
- ${h}
87
- ${_.fontFaceCSS?`<style>${_.fontFaceCSS}</style>`:""}
111
+ ${j}
112
+ ${b}
113
+ ${d.fontFaceCSS?`<style>${d.fontFaceCSS}</style>`:""}
88
114
  <style>
89
- ${_.rootRule||""}
90
- ${_.resetRules||""}
91
- ${_.keyframeRules||""}
115
+ ${d.rootRule||""}
116
+ ${d.resetRules||""}
117
+ ${d.keyframeRules||""}
92
118
  </style>
93
- ${a?`<style data-emotion="smbls">
94
- ${a}
119
+ ${g?`<style data-emotion="smbls">
120
+ ${g}
95
121
  </style>`:""}
96
122
  </head>
97
123
  <body>
98
- ${n.html}
99
- ${I}
124
+ ${i.html}
125
+ ${L}
100
126
  </body>
101
- </html>`,route:e,brKeyCount:g}},Ft={U:-6,V:-5,W:-4,X:-3,Y:-2,Z:-1,A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8,J:9,K:10,L:11,M:12,N:13,O:14,P:15},ht=new Set(["padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingBlock","paddingInline","paddingBlockStart","paddingBlockEnd","paddingInlineStart","paddingInlineEnd","margin","marginTop","marginRight","marginBottom","marginLeft","marginBlock","marginInline","marginBlockStart","marginBlockEnd","marginInlineStart","marginInlineEnd","gap","rowGap","columnGap","top","right","bottom","left","width","height","minWidth","maxWidth","minHeight","maxHeight","flexBasis","fontSize","lineHeight","letterSpacing","borderWidth","borderRadius","outlineWidth","outlineOffset","inset","insetBlock","insetInline","boxSize","round"]),yt=(t,e)=>{if(!t||typeof t!="string"||!e)return null;const o=e.base||16,s=e.ratio||1.618,r=e.unit||"px",p=e.subSequence!==!1;if(t.includes(" "))return t.split(" ").map(g=>g==="-"||g===""?g:yt(g,e)||g).join(" ");if(/^(none|auto|inherit|initial|unset|0)$/i.test(t)||/\d+(px|em|rem|%|vh|vw|vmin|vmax|ch|ex|cm|mm|in|pt|pc|fr|s|ms)$/i.test(t)||/^(#|rgb|hsl|var\()/i.test(t))return null;const f=t.startsWith("-"),i=(f?t.slice(1):t).match(/^([A-Z])(\d)?$/i);if(!i)return null;const n=i[1].toUpperCase(),l=i[2]?parseInt(i[2]):0,u=Ft[n];if(u===void 0)return null;let a=o*Math.pow(s,u);if(l>0&&p){const h=o*Math.pow(s,u+1),I=(h-a)/s,L=h-I,R=a+I,k=(L+R)/2,O=~~h-~~a>16?[L,k,R]:[L,R];l<=O.length&&(a=O[l-1])}const m=Math.round(a*100)/100;return`${f?"-":""}${m}${r}`},Bt=new Set([...ht].map(t=>t.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()))),Q=(t,e,o)=>{if(typeof e!="string")return e;if(Nt.has(t)){const s=o?.color||{};if(s[e])return s[e]}if(ht.has(t)||Bt.has(t)){const s=o?.spacing||{},r=yt(e,s);if(r)return r}return e},Nt=new Set(["color","background","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor","fill","stroke"]),bt=new Set(["href","src","alt","title","id","name","type","value","placeholder","target","rel","loading","srcset","sizes","media","role","tabindex","for","action","method","enctype","autocomplete","autofocus","theme","__element","update","childrenAs","childExtends","childProps","children"]),J=t=>t.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),St=(t,e)=>{if(typeof e>"u"||e===null)return null;if(t==="flow"&&typeof e=="string"){let[o,s]=(e||"row").split(" ");return(e.startsWith("x")||e==="row")&&(o="row"),(e.startsWith("y")||e==="column")&&(o="column"),{display:"flex","flex-flow":(o||"")+" "+(s||"")}}if(t==="wrap")return{display:"flex","flex-wrap":e};if((t==="align"||t==="flexAlign")&&typeof e=="string"){const[o,s]=e.split(" "),r={display:"flex","align-items":o};return s&&(r["justify-content"]=s),r}if(t==="gridAlign"&&typeof e=="string"){const[o,s]=e.split(" "),r={display:"grid","align-items":o};return s&&(r["justify-content"]=s),r}if(t==="flexFlow"&&typeof e=="string"){let[o,s]=(e||"row").split(" ");return(e.startsWith("x")||e==="row")&&(o="row"),(e.startsWith("y")||e==="column")&&(o="column"),{display:"flex","flex-flow":(o||"")+" "+(s||"")}}if(t==="flexWrap")return{display:"flex","flex-wrap":e};if(t==="backgroundImage"&&typeof e=="string"&&!e.startsWith("url(")&&!e.startsWith("linear-gradient")&&!e.startsWith("radial-gradient")&&!e.startsWith("none"))return{"background-image":`url(${e})`};if(t==="round"||t==="borderRadius"&&e)return{"border-radius":typeof e=="number"?e+"px":e};if(t==="boxSize"&&typeof e=="string"){const[o,s]=e.split(" ");return{height:o,width:s||o}}if(t==="widthRange"&&typeof e=="string"){const[o,s]=e.split(" ");return{"min-width":o,"max-width":s||o}}if(t==="heightRange"&&typeof e=="string"){const[o,s]=e.split(" ");return{"min-height":o,"max-height":s||o}}return t==="column"?{"grid-column":e}:t==="columns"?{"grid-template-columns":e}:t==="templateColumns"?{"grid-template-columns":e}:t==="row"?{"grid-row":e}:t==="rows"?{"grid-template-rows":e}:t==="templateRows"?{"grid-template-rows":e}:t==="area"?{"grid-area":e}:t==="template"?{"grid-template":e}:t==="templateAreas"?{"grid-template-areas":e}:t==="autoColumns"?{"grid-auto-columns":e}:t==="autoRows"?{"grid-auto-rows":e}:t==="autoFlow"?{"grid-auto-flow":e}:t==="columnStart"?{"grid-column-start":e}:t==="rowStart"?{"grid-row-start":e}:null},jt=(t,e)=>{const o={};for(const s in t){const r=t[s],p=St(s,r);if(p){for(const f in p)o[f]=Q(f,p[f],e);continue}typeof r!="string"&&typeof r!="number"||(o[J(s)]=Q(s,r,e))}return o},Wt=(t,e,o)=>{const s={},r={},p={};for(const f in t){const c=t[f];if(f.charCodeAt(0)===64&&typeof c=="object"){const n=o?.[f.slice(1)];if(n){const l=jt(c,e);Object.keys(l).length&&(r[n]=l)}continue}if(f.charCodeAt(0)===58&&typeof c=="object"){const n=jt(c,e);Object.keys(n).length&&(p[f]=n);continue}if(typeof c!="string"&&typeof c!="number"||f.charCodeAt(0)>=65&&f.charCodeAt(0)<=90||bt.has(f))continue;const i=St(f,c);if(i){for(const n in i)s[n]=Q(n,i[n],e);continue}s[J(f)]=Q(f,c,e)}return{base:s,mediaRules:r,pseudoRules:p}},Jt=(t,{base:e,mediaRules:o,pseudoRules:s})=>{const r=[],p=Object.entries(e).map(([f,c])=>`${f}: ${c}`).join("; ");p&&r.push(`${t} { ${p}; }`);for(const[f,c]of Object.entries(s)){const i=Object.entries(c).map(([n,l])=>`${n}: ${l}`).join("; ");i&&r.push(`${t}${f} { ${i}; }`)}for(const[f,c]of Object.entries(o)){const i=Object.entries(c).map(([l,u])=>`${l}: ${u}`).join("; "),n=f.startsWith("@")?f:`@media ${f}`;i&&r.push(`${n} { ${t} { ${i}; } }`)}return r.join(`
102
- `)},Rt={Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Block:{display:"block"},Inline:{display:"inline"}},Gt=t=>{const e=t.__ref?.__extends;if(!e||!Array.isArray(e))return null;for(const o of e)if(Rt[o])return Rt[o];return null},Ht=t=>{let e;for(const o in t){if(typeof t[o]!="function"||bt.has(o)||o.charCodeAt(0)>=65&&o.charCodeAt(0)<=90||o.startsWith("on")||o.startsWith("__"))continue;e||(e={});let s;try{s=t[o](t,t.state||{})}catch{try{const r={root:{},...t.state||{}};s=t[o](t,r)}catch{}}s!=null&&s!==!1&&(e[o]=s)}return e||t},be=(t,e)=>{const o=e?.media||{},s=e?.animation||{},r=[],p=new Set,f=new Set,c=n=>{if(!n||!n.__ref)return;const l=Ht(n);if(l&&n.node){const u=n.node.getAttribute?.("class");if(u&&!p.has(u)){p.add(u);const a=Wt(l,e,o),m=Gt(n);if(m)for(const[g,I]of Object.entries(m)){const L=J(g);a.base[L]||(a.base[L]=I)}(Object.keys(a.base).length||Object.keys(a.mediaRules).length||Object.keys(a.pseudoRules).length)&&r.push(Jt("."+u.split(" ")[0],a));const h=l.animation||l.animationName;if(typeof h=="string"){const g=h.split(" ")[0];s[g]&&f.add(g)}}}if(n.__ref?.__children)for(const u of n.__ref.__children)n[u]?.__ref&&c(n[u])};c(t);const i=[];for(const n of f){const l=s[n],u=Object.entries(l).map(([a,m])=>{const _=Object.entries(m).map(([h,g])=>`${J(h)}: ${g}`).join("; ");return` ${a} { ${_}; }`}).join(`
103
- `);i.push(`@keyframes ${n} {
104
- ${u}
105
- }`)}return[...i,...r].join(`
106
- `)},wt=t=>{if(!t)return"";const e=[];for(const[o,s]of Object.entries(t)){if(!s||typeof s!="object")continue;const r=[],p=[];for(const[f,c]of Object.entries(s)){if(typeof c=="object"&&c!==null){if(f.startsWith("@media")||f.startsWith("@")){const i=Object.entries(c).filter(([,n])=>typeof n!="object").map(([n,l])=>`${J(n)}: ${l}`).join("; ");i&&p.push(`${f} { ${o} { ${i}; } }`)}continue}r.push(`${J(f)}: ${c}`)}r.length&&e.push(`${o} { ${r.join("; ")}; }`),e.push(...p)}return e.join(`
107
- `)},xt=t=>{if(!t)return"";const e=t.font_family||t.fontFamily||{},o=new Set;for(const r of Object.values(e)){if(typeof r!="string")continue;const p=r.match(/'([^']+)'/);p&&o.add(p[1])}return o.size?['<link rel="preconnect" href="https://fonts.googleapis.com">','<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',`<link href="https://fonts.googleapis.com/css2?${[...o].map(r=>`family=${r.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
108
- `):""};export{me as getAccumulatedEmotionCSS,pt as render,pe as renderElement,ye as renderPage,he as renderRoute,ge as replaceEmotionCSS,de as resetGlobalCSSCache};
127
+ </html>`,route:e,brKeyCount:q}},Gt={U:-6,V:-5,W:-4,X:-3,Y:-2,Z:-1,A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8,J:9,K:10,L:11,M:12,N:13,O:14,P:15},St=new Set(["padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingBlock","paddingInline","paddingBlockStart","paddingBlockEnd","paddingInlineStart","paddingInlineEnd","margin","marginTop","marginRight","marginBottom","marginLeft","marginBlock","marginInline","marginBlockStart","marginBlockEnd","marginInlineStart","marginInlineEnd","gap","rowGap","columnGap","top","right","bottom","left","width","height","minWidth","maxWidth","minHeight","maxHeight","flexBasis","fontSize","lineHeight","letterSpacing","borderWidth","borderRadius","outlineWidth","outlineOffset","inset","insetBlock","insetInline","boxSize","round"]),Rt=(t,e)=>{if(!t||typeof t!="string"||!e)return null;const o=e.base||16,n=e.ratio||1.618,r=e.unit||"px",u=e.subSequence!==!1;if(t.includes(" "))return t.split(" ").map(b=>b==="-"||b===""?b:Rt(b,e)||b).join(" ");if(/^(none|auto|inherit|initial|unset|0)$/i.test(t)||/\d+(px|em|rem|%|vh|vw|vmin|vmax|ch|ex|cm|mm|in|pt|pc|fr|s|ms)$/i.test(t)||/^(#|rgb|hsl|var\()/i.test(t))return null;const p=t.startsWith("-"),c=(p?t.slice(1):t).match(/^([A-Z])(\d)?$/i);if(!c)return null;const s=c[1].toUpperCase(),i=c[2]?parseInt(c[2]):0,a=Gt[s];if(a===void 0)return null;let f=o*Math.pow(n,a);if(i>0&&u){const d=o*Math.pow(n,a+1),q=(d-f)/n,L=d-q,S=f+q,_=(L+S)/2,j=~~d-~~f>16?[L,_,S]:[L,S];i<=j.length&&(f=j[i-1])}const g=Math.round(f*100)/100;return`${p?"-":""}${g}${r}`},Ht=new Set([...St].map(t=>t.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()))),X=(t,e,o)=>{if(typeof e!="string")return e;if(Vt.has(t)){const n=o?.color||{};if(n[e])return n[e]}if(St.has(t)||Ht.has(t)){const n=o?.spacing||{},r=Rt(e,n);if(r)return r}return e},Vt=new Set(["color","background","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor","fill","stroke"]),jt=new Set(["href","src","alt","title","id","name","type","value","placeholder","target","rel","loading","srcset","sizes","media","role","tabindex","for","action","method","enctype","autocomplete","autofocus","theme","__element","update","childrenAs","childExtends","childProps","children"]),G=t=>t.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),wt=(t,e)=>{if(typeof e>"u"||e===null)return null;if(t==="flow"&&typeof e=="string"){let[o,n]=(e||"row").split(" ");return(e.startsWith("x")||e==="row")&&(o="row"),(e.startsWith("y")||e==="column")&&(o="column"),{display:"flex","flex-flow":(o||"")+" "+(n||"")}}if(t==="wrap")return{display:"flex","flex-wrap":e};if((t==="align"||t==="flexAlign")&&typeof e=="string"){const[o,n]=e.split(" "),r={display:"flex","align-items":o};return n&&(r["justify-content"]=n),r}if(t==="gridAlign"&&typeof e=="string"){const[o,n]=e.split(" "),r={display:"grid","align-items":o};return n&&(r["justify-content"]=n),r}if(t==="flexFlow"&&typeof e=="string"){let[o,n]=(e||"row").split(" ");return(e.startsWith("x")||e==="row")&&(o="row"),(e.startsWith("y")||e==="column")&&(o="column"),{display:"flex","flex-flow":(o||"")+" "+(n||"")}}if(t==="flexWrap")return{display:"flex","flex-wrap":e};if(t==="backgroundImage"&&typeof e=="string"&&!e.startsWith("url(")&&!e.startsWith("linear-gradient")&&!e.startsWith("radial-gradient")&&!e.startsWith("none"))return{"background-image":`url(${e})`};if(t==="round"||t==="borderRadius"&&e)return{"border-radius":typeof e=="number"?e+"px":e};if(t==="boxSize"&&typeof e=="string"){const[o,n]=e.split(" ");return{height:o,width:n||o}}if(t==="widthRange"&&typeof e=="string"){const[o,n]=e.split(" ");return{"min-width":o,"max-width":n||o}}if(t==="heightRange"&&typeof e=="string"){const[o,n]=e.split(" ");return{"min-height":o,"max-height":n||o}}return t==="column"?{"grid-column":e}:t==="columns"?{"grid-template-columns":e}:t==="templateColumns"?{"grid-template-columns":e}:t==="row"?{"grid-row":e}:t==="rows"?{"grid-template-rows":e}:t==="templateRows"?{"grid-template-rows":e}:t==="area"?{"grid-area":e}:t==="template"?{"grid-template":e}:t==="templateAreas"?{"grid-template-areas":e}:t==="autoColumns"?{"grid-auto-columns":e}:t==="autoRows"?{"grid-auto-rows":e}:t==="autoFlow"?{"grid-auto-flow":e}:t==="columnStart"?{"grid-column-start":e}:t==="rowStart"?{"grid-row-start":e}:null},xt=(t,e)=>{const o={};for(const n in t){const r=t[n],u=wt(n,r);if(u){for(const p in u)o[p]=X(p,u[p],e);continue}typeof r!="string"&&typeof r!="number"||(o[G(n)]=X(n,r,e))}return o},Kt=(t,e,o)=>{const n={},r={},u={};for(const p in t){const l=t[p];if(p.charCodeAt(0)===64&&typeof l=="object"){const s=o?.[p.slice(1)];if(s){const i=xt(l,e);Object.keys(i).length&&(r[s]=i)}continue}if(p.charCodeAt(0)===58&&typeof l=="object"){const s=xt(l,e);Object.keys(s).length&&(u[p]=s);continue}if(typeof l!="string"&&typeof l!="number"||p.charCodeAt(0)>=65&&p.charCodeAt(0)<=90||jt.has(p))continue;const c=wt(p,l);if(c){for(const s in c)n[s]=X(s,c[s],e);continue}n[G(p)]=X(p,l,e)}return{base:n,mediaRules:r,pseudoRules:u}},Ut=(t,{base:e,mediaRules:o,pseudoRules:n})=>{const r=[],u=Object.entries(e).map(([p,l])=>`${p}: ${l}`).join("; ");u&&r.push(`${t} { ${u}; }`);for(const[p,l]of Object.entries(n)){const c=Object.entries(l).map(([s,i])=>`${s}: ${i}`).join("; ");c&&r.push(`${t}${p} { ${c}; }`)}for(const[p,l]of Object.entries(o)){const c=Object.entries(l).map(([i,a])=>`${i}: ${a}`).join("; "),s=p.startsWith("@")?p:`@media ${p}`;c&&r.push(`${s} { ${t} { ${c}; } }`)}return r.join(`
128
+ `)},_t={Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Block:{display:"block"},Inline:{display:"inline"}},zt=t=>{const e=t.__ref?.__extends;if(!e||!Array.isArray(e))return null;for(const o of e)if(_t[o])return _t[o];return null},Yt=t=>{let e;for(const o in t){if(typeof t[o]!="function"||jt.has(o)||o.charCodeAt(0)>=65&&o.charCodeAt(0)<=90||o.startsWith("on")||o.startsWith("__"))continue;e||(e={});let n;try{n=t[o](t,t.state||{})}catch{try{const r={root:{},...t.state||{}};n=t[o](t,r)}catch{}}n!=null&&n!==!1&&(e[o]=n)}return e||t},_e=(t,e)=>{const o=e?.media||{},n=e?.animation||{},r=[],u=new Set,p=new Set,l=s=>{if(!s||!s.__ref)return;const i=Yt(s);if(i&&s.node){const a=s.node.getAttribute?.("class");if(a&&!u.has(a)){u.add(a);const f=Kt(i,e,o),g=zt(s);if(g)for(const[b,q]of Object.entries(g)){const L=G(b);f.base[L]||(f.base[L]=q)}(Object.keys(f.base).length||Object.keys(f.mediaRules).length||Object.keys(f.pseudoRules).length)&&r.push(Ut("."+a.split(" ")[0],f));const d=i.animation||i.animationName;if(typeof d=="string"){const b=d.split(" ")[0];n[b]&&p.add(b)}}}if(s.__ref?.__children)for(const a of s.__ref.__children)s[a]?.__ref&&l(s[a])};l(t);const c=[];for(const s of p){const i=n[s],a=Object.entries(i).map(([f,g])=>{const T=Object.entries(g).map(([d,b])=>`${G(d)}: ${b}`).join("; ");return` ${f} { ${T}; }`}).join(`
129
+ `);c.push(`@keyframes ${s} {
130
+ ${a}
131
+ }`)}return[...c,...r].join(`
132
+ `)},kt=t=>{if(!t)return"";const e=[];for(const[o,n]of Object.entries(t)){if(!n||typeof n!="object")continue;const r=[],u=[];for(const[p,l]of Object.entries(n)){if(typeof l=="object"&&l!==null){if(p.startsWith("@media")||p.startsWith("@")){const c=Object.entries(l).filter(([,s])=>typeof s!="object").map(([s,i])=>`${G(s)}: ${i}`).join("; ");c&&u.push(`${p} { ${o} { ${c}; } }`)}continue}r.push(`${G(p)}: ${l}`)}r.length&&e.push(`${o} { ${r.join("; ")}; }`),e.push(...u)}return e.join(`
133
+ `)},$t=t=>{if(!t)return"";const e=t.font_family||t.fontFamily||{},o=new Set;for(const r of Object.values(e)){if(typeof r!="string")continue;const u=r.match(/'([^']+)'/);u&&o.add(u[1])}return o.size?['<link rel="preconnect" href="https://fonts.googleapis.com">','<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',`<link href="https://fonts.googleapis.com/css2?${[...o].map(r=>`family=${r.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
134
+ `):""};export{ut as SMBLS_SSR_SPECIFIER,Re as getAccumulatedEmotionCSS,dt as render,ye as renderElement,xe as renderPage,we as renderRoute,je as replaceEmotionCSS,Se as resetGlobalCSSCache,Jt as skinRulesToCSS};
@@ -0,0 +1,7 @@
1
+ const _=/<head(\s[^>]*)?>/i,A=/<body(\s[^>]*)?>/i,d=(e,n)=>{const s=new RegExp(`\\s${n}\\s*=\\s*("([^"]*)"|'([^']*)'|([^\\s>]+))`,"i").exec(e);return s?s[2]??s[3]??s[4]??"":null},O=e=>{const n=e.slice(0,12).toLowerCase();if(n.startsWith("<title"))return"title";if(n.startsWith("<meta")){if(d(e,"charset")!==null)return"charset";for(const s of["name","property","http-equiv","itemprop"]){const r=d(e,s);if(r!==null)return`${s}:${r.toLowerCase()}`}return null}if(n.startsWith("<link")){const s=(d(e,"rel")||"").toLowerCase();return s==="canonical"?"link:canonical":s==="icon"||s==="shortcut icon"?`link:${s}:${d(e,"href")||""}`:s==="alternate"&&d(e,"hreflang")!==null?`link:alternate:${(d(e,"hreflang")||"").toLowerCase()}`:null}return null},y=/<title[^>]*>[\s\S]*?<\/title\s*>|<meta\b[^>]*>|<link\b[^>]*>/gi,C=/<(script|style|noscript|template|textarea)\b[\s\S]*?<\/\1\s*>/gi,k=e=>[...e.matchAll(C)].map(n=>[n.index,n.index+n[0].length,n[0]]),E=(e,n,s=r=>r)=>{let r="",i=0;for(const[t,a,c]of k(e))r+=n(e.slice(i,t))+s(c),i=a;return r+n(e.slice(i))},f=(e,n,s=0)=>{const r=k(e),i=new RegExp(n.source,n.flags.includes("g")?n.flags:n.flags+"g");i.lastIndex=s;let t;for(;t=i.exec(e);){const a=t.index,c=r.find(([u,h])=>a>u&&a<h);if(!c)return t;i.lastIndex=c[1]}return null},L=e=>!!e&&!/^(?:[a-z][a-z0-9+.-]*:|\/|#|\?)/i.test(e),R=(e,n)=>e.replace(/(\s(?:src|href)\s*=\s*)(?:(["'])([^"']*)\2|([^\s"'>]+))/gi,(s,r,i,t,a)=>{const c=i?t:a;if(!L(c))return s;const u=i||"";return`${r}${u}${n}${c.replace(/^\.\//,"")}${u}`}),B=(e,n)=>{if(!n)return e;const s="../".repeat(n);return E(e,r=>r.replace(/<link\b[^>]*>/gi,i=>R(i,s)),r=>/^<script\b/i.test(r)?r.replace(/^<script\b[^>]*>/i,i=>R(i,s)):r)},D=(e,{headTags:n="",headEnd:s="",body:r="",depth:i=0}={})=>{if(typeof e!="string"||!e.trim())throw new Error("brender: the shell document is empty");let t=B(e,i);const a=new Set;for(const o of n.matchAll(y)){const l=O(o[0]);l&&a.add(l)}const c=o=>E(o,l=>l.replace(y,b=>a.has(O(b))?"":b)),u=n?`
2
+ ${n}`:"",h=s?`
3
+ ${s}
4
+ `:"",p=f(t,_),g=p&&f(t,/<\/head\s*>/i,p.index);if(p&&g){const o=p.index+p[0].length,l=g.index;t=t.slice(0,o)+u+c(t.slice(o,l))+h+t.slice(l)}else{t=c(t);const o=f(t,/<html(\s[^>]*)?>/i)||f(t,/<!doctype[^>]*>/i),l=o?o.index+o[0].length:0;t=t.slice(0,l)+u+h+t.slice(l)}const w=`
5
+ <script>window.__BRENDER__=true<\/script>
6
+ ${r}
7
+ `,x=f(t,A);if(x){const o=x.index+x[0].length;return t.slice(0,o)+w+t.slice(o)}const m=f(t,/<\/(?:body|html)\s*>/i),$=m?m.index:t.length;return t.slice(0,$)+w+t.slice($)};export{D as composeIntoShell,O as headTagKey};
package/env.js CHANGED
@@ -26,7 +26,9 @@ export const createEnv = (html = '<!DOCTYPE html><html><head></head><body></body
26
26
  }
27
27
  }
28
28
  if (!window.location) {
29
- window.location = { pathname: '/', search: '', hash: '', origin: 'http://localhost' }
29
+ // A complete Location shape (host/hostname/protocol/href too): framework
30
+ // modules read these at module load, before any route is set.
31
+ window.location = { pathname: '/', search: '', hash: '', origin: 'http://localhost', protocol: 'http:', host: 'localhost', hostname: 'localhost', port: '', href: 'http://localhost/' }
30
32
  }
31
33
  if (!window.URL) {
32
34
  window.URL = URL
package/index.js CHANGED
@@ -6,6 +6,7 @@ import { extractMetadata, generateHeadHtml } from './metadata.js'
6
6
  import { collectBrNodes, hydrate } from './hydrate.js'
7
7
  import { generateSitemap } from './sitemap.js'
8
8
  import { prefetchPageData, injectPrefetchedState } from './prefetch.js'
9
+ import { composeIntoShell } from './shell.js'
9
10
 
10
11
  export {
11
12
  createEnv,
@@ -27,7 +28,8 @@ export {
27
28
  hydrate,
28
29
  generateSitemap,
29
30
  prefetchPageData,
30
- injectPrefetchedState
31
+ injectPrefetchedState,
32
+ composeIntoShell
31
33
  }
32
34
 
33
35
  export default {
@@ -50,5 +52,6 @@ export default {
50
52
  hydrate,
51
53
  generateSitemap,
52
54
  prefetchPageData,
53
- injectPrefetchedState
55
+ injectPrefetchedState,
56
+ composeIntoShell
54
57
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/brender",
3
- "version": "3.14.660",
3
+ "version": "3.14.662",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
6
  "module": "./dist/esm/index.js",
@@ -46,15 +46,19 @@
46
46
  "prepublishOnly": "npm run build"
47
47
  },
48
48
  "dependencies": {
49
- "@symbo.ls/css": "^3.14.599",
50
- "@symbo.ls/default-config": "^3.14.0",
51
- "@symbo.ls/element": "^3.14.5",
52
- "@symbo.ls/helmet": "^3.14.599",
53
- "@symbo.ls/scratch": "^3.14.775",
54
- "@symbo.ls/utils": "^3.14.772",
49
+ "@symbo.ls/css": "^3.14.774",
50
+ "@symbo.ls/default-config": "^3.14.785",
51
+ "@symbo.ls/element": "^3.14.799",
52
+ "@symbo.ls/fetch": "^3.14.662",
53
+ "@symbo.ls/helmet": "^3.14.669",
54
+ "@symbo.ls/scratch": "^3.14.786",
55
+ "@symbo.ls/utils": "^3.14.784",
55
56
  "esbuild": "^0.28.1",
56
57
  "linkedom": "^0.16.8"
57
58
  },
59
+ "peerDependencies": {
60
+ "smbls": "^3.14.827"
61
+ },
58
62
  "optionalDependencies": {
59
63
  "@symbo.ls/funcql": "^3.14.0"
60
64
  },
package/prefetch.js CHANGED
@@ -106,32 +106,71 @@ const collectFetchDeclarations = (def, path = '') => {
106
106
  }
107
107
 
108
108
  /**
109
- * Create an SSR adapter from project config.
109
+ * Create an SSR adapter from project config — the SAME adapter the client's
110
+ * declarative `fetch` uses, resolved through @symbo.ls/fetch's public
111
+ * `resolveDb` (config.fetch / config.db: `{ adapter: 'rest', url, headers }`,
112
+ * or an adapter object with its own select/rpc).
110
113
  *
111
- * The Supabase SSR code path was removed — the SDK adapter is the only
112
- * backend transport now, and it has no server-side client here yet. Until
113
- * an SDK-backed SSR adapter exists, no built-in adapter resolves: callers
114
- * get null, skip prefetch, and the client-side fetch plugin owns data
115
- * loading after hydration.
114
+ * This used to be a stub that always returned null (xma.info report
115
+ * sub-problem 2): the Supabase SSR path had been removed, nothing replaced it,
116
+ * so server renders never had data or fetched translations.
117
+ *
118
+ * Not every adapter can run on the server: the platform's 'sdk' adapter is
119
+ * registered by the page runtime, which a server render does not have. For a
120
+ * name @symbo.ls/fetch cannot resolve right now (`hasAdapter`), this returns
121
+ * null at once — the page renders without prefetched data and the client's
122
+ * fetch loads it — instead of letting resolveDb wait for a registration that
123
+ * never comes.
116
124
  */
125
+ const BUILTIN_ADAPTER_NAMES = ['rest', 'local'] // @symbo.ls/fetch without hasAdapter()
126
+ const _adapterCache = new WeakMap()
127
+
117
128
  const createSSRAdapter = async (dbConfig) => {
118
129
  if (!dbConfig) return null
119
- return null
130
+ if (isObject(dbConfig) && (isFunction(dbConfig.select) || isFunction(dbConfig.rpc))) return dbConfig
131
+ const config = typeof dbConfig === 'string' ? { adapter: dbConfig } : dbConfig
132
+ if (!isObject(config) || typeof config.adapter !== 'string') return null
133
+ if (_adapterCache.has(config)) return _adapterCache.get(config)
134
+
135
+ const pending = (async () => {
136
+ let fetchPkg
137
+ try {
138
+ fetchPkg = await import('@symbo.ls/fetch')
139
+ } catch {
140
+ return null
141
+ }
142
+ const known = isFunction(fetchPkg.hasAdapter)
143
+ ? fetchPkg.hasAdapter(config.adapter)
144
+ : BUILTIN_ADAPTER_NAMES.includes(config.adapter)
145
+ if (!known) return null
146
+ try {
147
+ return await fetchPkg.resolveDb(config)
148
+ } catch (e) {
149
+ console.warn(`[brender] SSR adapter "${config.adapter}" unavailable: ${e.message}`)
150
+ return null
151
+ }
152
+ })()
153
+ _adapterCache.set(config, pending)
154
+ return pending
120
155
  }
121
156
 
157
+ export { createSSRAdapter }
158
+
122
159
  /**
123
160
  * Execute a single fetch config against the adapter.
124
161
  * Returns the fetched data, or null on error.
125
162
  */
126
163
  const executeSingle = async (adapter, config) => {
127
164
  try {
128
- const { method, from, params, transform, limit, offset, order, single } = config
165
+ const { method, from, params, transform, limit, offset, order, single, headers, baseUrl } = config
129
166
  let result
130
167
 
131
168
  if (method === 'rpc') {
132
- result = await adapter.rpc({ from, params })
169
+ if (!isFunction(adapter.rpc)) return null
170
+ result = await adapter.rpc({ from, params, headers, baseUrl })
133
171
  } else {
134
- result = await adapter.select({ from, select: config.select, params, limit, offset, order, single })
172
+ if (!isFunction(adapter.select)) return null
173
+ result = await adapter.select({ from, select: config.select, params, limit, offset, order, single, headers, baseUrl })
135
174
  }
136
175
 
137
176
  let data = result?.data ?? null
@@ -232,6 +271,7 @@ export const fetchSSRTranslations = async (data) => {
232
271
  const results = await Promise.allSettled(
233
272
  languages.map(async (lang) => {
234
273
  try {
274
+ if (!isFunction(adapter.rpc)) return
235
275
  const res = await adapter.rpc({
236
276
  from: rpcName,
237
277
  params: { p_lang: lang, p_cached_version: 0 }
package/render.js CHANGED
@@ -8,6 +8,7 @@ import { createEnv } from './env.js'
8
8
  import { resetKeys, assignKeys, mapKeysToElements } from './keys.js'
9
9
  import { extractMetadata, generateHeadHtml } from './metadata.js'
10
10
  import { hydrate } from './hydrate.js'
11
+ import { composeIntoShell } from './shell.js'
11
12
  import { prefetchPageData, injectPrefetchedState, fetchSSRTranslations } from './prefetch.js'
12
13
 
13
14
  // funcql plugin — enables evaluation of funcql schemas as property values
@@ -257,26 +258,56 @@ const resolveDomqlPackage = (ws, pkg, ...subpath) => {
257
258
  return null
258
259
  }
259
260
 
260
- // ── Bundled import of createDomqlElement ──────────────────────────────────────
261
- // The smbls source tree uses extensionless/directory imports that Node.js ESM
262
- // cannot resolve natively. We bundle createDomql.js with esbuild (once, cached)
263
- // so all bare/directory specifiers are resolved at bundle time.
261
+ // ── Loading createDomqlElement ────────────────────────────────────────────────
262
+ // Three sources, in this order:
263
+ //
264
+ // 1. The smbls MONOREPO (brender running from plugins/brender next to
265
+ // packages/smbls/src): esbuild-bundle the live SOURCE createDomql.js, so
266
+ // framework development renders what is on disk.
267
+ // 2. An INSTALLED smbls: its supported server-render entry, `smbls/ssr`
268
+ // (createDomqlElement + prepareContext, the same module instance as the
269
+ // `smbls` main entry). The published smbls ships bundles only — no src/,
270
+ // no dist/esm/src/ — so the old "bundle smbls's source" path failed every
271
+ // route of every npm install with "brender: cannot find createDomql.js"
272
+ // (xma.info report item 1). Rendering with the consumer's OWN smbls also
273
+ // keeps the server markup and the client that boots over it on one
274
+ // framework version; a createDomql prebuilt into brender's package would
275
+ // freeze whichever smbls brender was published against.
276
+ // 3. Bundled runtimes (Cloudflare Workers — no import.meta.url, no
277
+ // filesystem): the same `smbls/ssr` specifier, a string literal the
278
+ // worker's bundler resolves and inlines. render.js used to import
279
+ // `./dist/createDomql.bundled.mjs` here, a file nothing ever built, so
280
+ // the mermaid worker fell back to client render on every request
281
+ // (FW-BRENDER-PREBUNDLED-CREATEDOMQL-NEVER-BUILT-WORKER-SSR-FALLS-BACK-1).
282
+ //
283
+ // An installed smbls OLDER than the ssr entry that still carries
284
+ // src/createDomql.js (pre-54131b34d tarballs) keeps the source-bundle path.
264
285
  let _cachedCreateDomql = null
265
286
 
287
+ // Exported for the packaging lock in __tests__/ssrEntryPackaging.test.js —
288
+ // the specifier that test proves the packed smbls tarball serves.
289
+ export const SMBLS_SSR_SPECIFIER = 'smbls/ssr'
290
+
291
+ const importSmblsSsr = async () => {
292
+ // The literal (not the constant) is what a bundler can statically resolve.
293
+ const mod = await import('smbls/ssr')
294
+ if (typeof mod?.createDomqlElement !== 'function') {
295
+ throw new Error('smbls/ssr does not export createDomqlElement')
296
+ }
297
+ return mod
298
+ }
299
+
266
300
  const bundleCreateDomql = async () => {
267
301
  if (_cachedCreateDomql) return _cachedCreateDomql
268
302
 
269
303
  const ws = detectWorkspace()
270
304
 
271
- // In bundled environments (CF Workers), use the pre-bundled createDomql.
272
- // Generated by: node scripts/prebundle-createDomql.js (or during npm prepublish)
273
305
  if (!_brenderRequire) {
274
306
  try {
275
- const mod = await import('./dist/createDomql.bundled.mjs')
276
- _cachedCreateDomql = mod
277
- return mod
307
+ _cachedCreateDomql = await importSmblsSsr()
308
+ return _cachedCreateDomql
278
309
  } catch (err) {
279
- throw new Error(`brender: pre-bundled createDomql not available in bundled runtime: ${err.message}`)
310
+ throw new Error(`brender: ${SMBLS_SSR_SPECIFIER} is not available in this bundled runtime (${err.message}). Bundle smbls ≥ the release that adds the smbls/ssr export alongside @symbo.ls/brender.`)
280
311
  }
281
312
  }
282
313
 
@@ -284,15 +315,25 @@ const bundleCreateDomql = async () => {
284
315
  let entry
285
316
  if (ws.isMonorepo) {
286
317
  entry = resolve(ws.monorepoRoot, 'packages', 'smbls', 'src', 'createDomql.js')
287
- } else if (ws.smblsRoot) {
288
- // Prefer src/ (shipped in smbls package), fall back to dist
289
- const srcEntry = resolve(ws.smblsRoot, 'src', 'createDomql.js')
290
- const distEntry = resolve(ws.smblsRoot, 'dist', 'esm', 'src', 'createDomql.js')
291
- entry = existsSync(srcEntry) ? srcEntry : distEntry
292
- }
293
-
294
- if (!entry || !existsSync(entry)) {
295
- throw new Error(`brender: cannot find createDomql.js (isMonorepo=${ws.isMonorepo}, entry=${entry})`)
318
+ } else {
319
+ let ssrError
320
+ try {
321
+ _cachedCreateDomql = await importSmblsSsr()
322
+ return _cachedCreateDomql
323
+ } catch (err) {
324
+ ssrError = err
325
+ }
326
+ // Legacy: an smbls that predates the ssr entry but still ships its source.
327
+ const srcEntry = ws.smblsRoot && resolve(ws.smblsRoot, 'src', 'createDomql.js')
328
+ if (srcEntry && existsSync(srcEntry)) {
329
+ entry = srcEntry
330
+ } else {
331
+ throw new Error(
332
+ `brender: cannot load ${SMBLS_SSR_SPECIFIER} (${ssrError.message}). ` +
333
+ 'Server rendering needs smbls installed in this project, at a release that exports smbls/ssr' +
334
+ (ws.smblsRoot ? ` (found smbls at ${ws.smblsRoot}).` : ' (no smbls package found).')
335
+ )
336
+ }
296
337
  }
297
338
 
298
339
  const esbuild = await import('esbuild')
@@ -792,6 +833,15 @@ export const render = async (data, options = {}) => {
792
833
  // Disable sourcemap tracking in SSR — it causes stack overflows
793
834
  // when state contains large data arrays (articles, events, etc.)
794
835
  domqlOptions: { sourcemap: false },
836
+ // Editor/live-sync, inspector and toast plugins have no place in server
837
+ // markup. The source-bundle path used to stub @symbo.ls/sync to no-ops at
838
+ // bundle time; the installed `smbls/ssr` entry carries the real plugins,
839
+ // so they are switched off here instead — after `...config`, because a
840
+ // project config that enables them for the browser must not attach
841
+ // SyncComponent / overlays to the pre-rendered DOM.
842
+ sync: false,
843
+ inspect: false,
844
+ notifications: false,
795
845
  // Caller overrides
796
846
  ...(contextOverrides || {})
797
847
  }
@@ -980,6 +1030,28 @@ const pickProjectConfig = (data) => {
980
1030
  return data.settings || null
981
1031
  }
982
1032
 
1033
+ // Serialise scratch `buildSkinVarStyles` output — `{ selector: { var: value },
1034
+ // '@media …': { selector: { var: value } } }` — as CSS text
1035
+ // (FW-SCRATCH-SKINS-DIMENSION-1).
1036
+ const declarationBlock = (selector, vars, indent) => {
1037
+ const decls = Object.entries(vars || {})
1038
+ .map(([k, v]) => `${indent} ${k}: ${v}`)
1039
+ .join(';\n')
1040
+ return decls ? `${indent}${selector} {\n${decls};\n${indent}}` : ''
1041
+ }
1042
+
1043
+ export const skinRulesToCSS = (rules) => Object.entries(rules || {})
1044
+ .map(([key, body]) => {
1045
+ if (!key.startsWith('@')) return declarationBlock(key, body, '')
1046
+ const inner = Object.entries(body || {})
1047
+ .map(([selector, vars]) => declarationBlock(selector, vars, ' '))
1048
+ .filter(Boolean)
1049
+ .join('\n')
1050
+ return inner ? `${key} {\n${inner}\n}` : ''
1051
+ })
1052
+ .filter(Boolean)
1053
+ .join('\n\n')
1054
+
983
1055
  const generateGlobalCSS = async (ds, config) => {
984
1056
  if (_cachedGlobalCSS) return _cachedGlobalCSS
985
1057
 
@@ -1004,6 +1076,10 @@ const generateGlobalCSS = async (ds, config) => {
1004
1076
 
1005
1077
  writeFileSync(tmpEntry, `
1006
1078
  import { set, getActiveConfig, getFontFaceString } from '@symbo.ls/scratch'
1079
+ // Namespace access for the skin builder: a scratch without it (version
1080
+ // skew) gives an empty skin block instead of failing this whole bundle
1081
+ // and, with it, every global rule.
1082
+ import * as scratchNs from '@symbo.ls/scratch'
1007
1083
  import { DEFAULT_CONFIG } from '@symbo.ls/default-config'
1008
1084
 
1009
1085
  const ds = ${dsJson}
@@ -1034,6 +1110,11 @@ const generateGlobalCSS = async (ds, config) => {
1034
1110
  const result = {
1035
1111
  CSS_VARS: conf.CSS_VARS || {},
1036
1112
  CSS_MEDIA_VARS: conf.CSS_MEDIA_VARS || {},
1113
+ // Skin rules — the same builder smbls init() injects on the client
1114
+ // (FW-SCRATCH-SKINS-DIMENSION-1).
1115
+ CSS_SKIN_RULES: typeof scratchNs.buildSkinVarStyles === 'function'
1116
+ ? scratchNs.buildSkinVarStyles(conf.cssSkinVars, conf.cssSkinFallback, ':root')
1117
+ : {},
1037
1118
  reset: conf.reset || {},
1038
1119
  animation: conf.animation || {}
1039
1120
  }
@@ -1060,16 +1141,15 @@ const generateGlobalCSS = async (ds, config) => {
1060
1141
  }
1061
1142
  const blank = resolve(ws.monorepoRoot, 'packages', 'default-config', 'blank', 'index.js')
1062
1143
  if (pkg === 'default-config' && existsSync(blank)) return { path: blank }
1063
- } else {
1064
- const resolved = resolveSymbolsPackage(ws, pkg, 'src', 'index.js')
1065
- if (resolved && existsSync(resolved)) return { path: resolved }
1066
- const resolvedIdx = resolveSymbolsPackage(ws, pkg, 'index.js')
1067
- if (resolvedIdx && existsSync(resolvedIdx)) return { path: resolvedIdx }
1068
- if (pkg === 'default-config') {
1069
- const blank = resolveSymbolsPackage(ws, 'default-config', 'blank', 'index.js')
1070
- if (blank && existsSync(blank)) return { path: blank }
1071
- }
1072
1144
  }
1145
+ // An npm install: no override — esbuild resolves the package's
1146
+ // published `exports` (dist/esm). Forcing the root index.js here
1147
+ // broke every npm consumer: published @symbo.ls/scratch and
1148
+ // @symbo.ls/default-config ship a root index.js that re-exports
1149
+ // ./src/… and ./designSystem/…, which their tarballs do not
1150
+ // contain, so this bundle failed ("Could not resolve
1151
+ // ./src/index.js") and every page lost its :root variables, reset
1152
+ // and @keyframes (found with the xma.info report item 1 repro).
1073
1153
  })
1074
1154
  build.onResolve({ filter: /^@domql\// }, args => {
1075
1155
  const pkg = args.path.replace('@symbo.ls/', '')
@@ -1139,6 +1219,12 @@ const generateGlobalCSS = async (ds, config) => {
1139
1219
  .join('\n\n')
1140
1220
  if (themeVarRules) rootRule += '\n\n' + themeVarRules
1141
1221
 
1222
+ // ── Skin rules ([data-skin] selectors + the reduced-transparency block) ──
1223
+ // After the scheme blocks: on an equal specificity the skin wins, as it
1224
+ // does in the hydrated page (smbls init injects them in the same order).
1225
+ const skinRules = skinRulesToCSS(data.CSS_SKIN_RULES)
1226
+ if (skinRules) rootRule += (rootRule ? '\n\n' : '') + skinRules
1227
+
1142
1228
  // ── Reset styles ──
1143
1229
  const resetRules = generateResetCSS(reset)
1144
1230
 
@@ -1287,10 +1373,16 @@ export const renderRoute = async (data, options = {}) => {
1287
1373
  * @param {object} [options.isr] - ISR options with clientScript path
1288
1374
  * @param {boolean} [options.hydrate=true] - Use true hydration (attach to existing DOM) instead of full SPA re-render
1289
1375
  * @param {boolean} [options.prefetch=true] - Whether to prefetch data via DB adapter
1290
- * @returns {Promise<{ html: string, route: string, brKeyCount: number }>}
1376
+ * @param {string} [options.shell] - A built app document (e.g. dist/index.html)
1377
+ * to render INTO instead of emitting a standalone document (see shell.js).
1378
+ * The result then carries `shell: true`.
1379
+ * @param {number} [options.depth] - Directory depth of the output file: rebases
1380
+ * the shell's relative asset URLs (with `shell`, default 0) and the ISR
1381
+ * client script path (default: derived from the route).
1382
+ * @returns {Promise<{ html: string, route: string, brKeyCount: number, shell?: true }>}
1291
1383
  */
1292
1384
  export const renderPage = async (data, route = '/', options = {}) => {
1293
- const { lang, themeColor, isr, hydrate = true, prefetch = true } = options
1385
+ const { lang, themeColor, isr, hydrate = true, prefetch = true, shell } = options
1294
1386
 
1295
1387
  // Detect lang from project config, app metadata, or default
1296
1388
  const htmlLang = lang || data.state?.lang || data.app?.metadata?.lang || 'en'
@@ -1301,6 +1393,21 @@ export const renderPage = async (data, route = '/', options = {}) => {
1301
1393
 
1302
1394
  const metadata = { ...result.metadata }
1303
1395
  if (themeColor) metadata['theme-color'] = themeColor
1396
+ // Rendering into a built shell: a title the project never declared is
1397
+ // extractMetadata's fallback (`data.name || 'Symbols'`), and it must not
1398
+ // replace the title the shell's author wrote — the client keeps that one
1399
+ // too (helmet applies declared metadata only). Probed by handing
1400
+ // extractMetadata a name nothing else can produce; the element and state
1401
+ // go along so a function-valued title still counts as declared.
1402
+ if (typeof shell === 'string' && !data.name) {
1403
+ const probe = `\u0000brender-undeclared-title\u0000`
1404
+ const probed = extractMetadata({ ...data, name: probe }, route, result.element, result.element?.state)
1405
+ if (probed.title === probe) {
1406
+ for (const key of ['title', 'og:title', 'twitter:title']) {
1407
+ if (metadata[key] === result.metadata.title) delete metadata[key]
1408
+ }
1409
+ }
1410
+ }
1304
1411
  const headTags = generateHeadHtml(metadata)
1305
1412
 
1306
1413
  // Accumulate emotion CSS from each page render.
@@ -1326,8 +1433,12 @@ export const renderPage = async (data, route = '/', options = {}) => {
1326
1433
  // ISR: include client SPA bundle for hydration + data fetching
1327
1434
  let isrBody = ''
1328
1435
  if (isr && isr.clientScript) {
1329
- // Calculate relative path from route directory to root
1330
- const depth = route === '/' ? 0 : route.replace(/^\/|\/$/g, '').split('/').length
1436
+ // Calculate relative path from route directory to root — or take the
1437
+ // caller's: the file a route is written to decides it ('/*' → 404.html
1438
+ // sits at the root, not in a '*' directory).
1439
+ const depth = Number.isInteger(options.depth)
1440
+ ? options.depth
1441
+ : route === '/' ? 0 : route.replace(/^\/|\/$/g, '').split('/').length
1331
1442
  const prefix = depth > 0 ? '../'.repeat(depth) : './'
1332
1443
 
1333
1444
  if (hydrate) {
@@ -1409,6 +1520,25 @@ export const renderPage = async (data, route = '/', options = {}) => {
1409
1520
  })
1410
1521
  }
1411
1522
 
1523
+ // Build path: render INTO the app's own built document (shell.js) — the
1524
+ // standalone document below carries no app code unless `isr` adds a
1525
+ // client bundle, so writing it over a bundler's dist/index.html shipped
1526
+ // pages that never booted.
1527
+ if (typeof shell === 'string') {
1528
+ const styles = [
1529
+ globalCSS.fontFaceCSS ? `<style>${globalCSS.fontFaceCSS}</style>` : '',
1530
+ `<style>\n${globalCSS.rootRule || ''}\n${globalCSS.resetRules || ''}\n${globalCSS.keyframeRules || ''}\n</style>`,
1531
+ emotionCSS ? `<style data-emotion="smbls">\n${emotionCSS}\n</style>` : ''
1532
+ ]
1533
+ const html = composeIntoShell(shell, {
1534
+ headTags: resolvedHeadTags,
1535
+ headEnd: [fontLinks, ...styles].filter(Boolean).join('\n'),
1536
+ body: result.html,
1537
+ depth: Number.isInteger(options.depth) ? options.depth : 0
1538
+ })
1539
+ return { html, route, brKeyCount, shell: true }
1540
+ }
1541
+
1412
1542
  const html = `<!DOCTYPE html>
1413
1543
  <html lang="${htmlLang}">
1414
1544
  <head>
package/shell.js ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Compose a server render INTO an already-built app document (the "shell").
3
+ *
4
+ * `smbls build` with `"brender": true` pre-renders every static route after
5
+ * the bundler has written `dist/index.html`. That file is the only thing that
6
+ * boots the app — it carries the bundle's <script>/<link> tags (parcel, vite)
7
+ * or the inlined runtime and project (symbols-runner). Writing brender's
8
+ * standalone document over it (renderPage without `shell`) shipped pages with
9
+ * no app code at all: static markup that never became interactive. So the
10
+ * build path renders each route and puts the result into a copy of the shell
11
+ * instead:
12
+ *
13
+ * <head> route metadata first (each <title>/<meta>/canonical/icon the
14
+ * render produced replaces the shell's tag with the same identity —
15
+ * never a second <title>), then the shell's own head, then the
16
+ * render's font links and <style> blocks just before </head>.
17
+ * <body> `window.__BRENDER__=true` and the rendered markup right after
18
+ * <body>, BEFORE the shell's scripts. The client's createDomqlElement
19
+ * sees the flag, removes the server markup and its <style> blocks,
20
+ * and renders the app over the same body (packages/smbls
21
+ * createDomql.js fallbackRender) — no duplicated tree.
22
+ *
23
+ * Relative asset URLs (`src="./index.js"`, `href="style.css"`) on the shell's
24
+ * <script>/<link> tags are rebased by `depth` directories, so a route written
25
+ * to `docs/intro.html` or `about/index.html` still loads the bundle.
26
+ *
27
+ * Pure string work on purpose: the shell's inline scripts (symbols-runner
28
+ * inlines the whole runtime) must reach the output byte-for-byte, which a
29
+ * DOM parse + serialize round-trip does not guarantee.
30
+ */
31
+
32
+ const HEAD_OPEN = /<head(\s[^>]*)?>/i
33
+ const BODY_OPEN = /<body(\s[^>]*)?>/i
34
+
35
+ const attr = (tag, name) => {
36
+ const m = new RegExp(`\\s${name}\\s*=\\s*("([^"]*)"|'([^']*)'|([^\\s>]+))`, 'i').exec(tag)
37
+ return m ? (m[2] ?? m[3] ?? m[4] ?? '') : null
38
+ }
39
+
40
+ // The identity a head tag is deduplicated by — or null when the tag is not
41
+ // one the route's metadata owns (scripts, styles, stylesheets, preloads…).
42
+ export const headTagKey = (tag) => {
43
+ const lower = tag.slice(0, 12).toLowerCase()
44
+ if (lower.startsWith('<title')) return 'title'
45
+ if (lower.startsWith('<meta')) {
46
+ if (attr(tag, 'charset') !== null) return 'charset'
47
+ for (const a of ['name', 'property', 'http-equiv', 'itemprop']) {
48
+ const v = attr(tag, a)
49
+ if (v !== null) return `${a}:${v.toLowerCase()}`
50
+ }
51
+ return null
52
+ }
53
+ if (lower.startsWith('<link')) {
54
+ const rel = (attr(tag, 'rel') || '').toLowerCase()
55
+ if (rel === 'canonical') return 'link:canonical'
56
+ if (rel === 'icon' || rel === 'shortcut icon') return `link:${rel}:${attr(tag, 'href') || ''}`
57
+ if (rel === 'alternate' && attr(tag, 'hreflang') !== null) return `link:alternate:${(attr(tag, 'hreflang') || '').toLowerCase()}`
58
+ return null
59
+ }
60
+ return null
61
+ }
62
+
63
+ const HEAD_TAG = /<title[^>]*>[\s\S]*?<\/title\s*>|<meta\b[^>]*>|<link\b[^>]*>/gi
64
+
65
+ // Raw-text blocks: their content is never markup, so nothing below may match
66
+ // inside one. symbols-runner inlines the whole runtime, whose string literals
67
+ // contain `<link rel="icon" href="${href}"`, `<title>`, `<body>`…
68
+ const RAW_BLOCK = /<(script|style|noscript|template|textarea)\b[\s\S]*?<\/\1\s*>/gi
69
+
70
+ const rawRanges = (html) => [...html.matchAll(RAW_BLOCK)].map(m => [m.index, m.index + m[0].length, m[0]])
71
+
72
+ // Apply `fn` to the markup between raw blocks; `onRaw` (optional) to each
73
+ // raw block's text.
74
+ const mapOutsideRawBlocks = (html, fn, onRaw = (raw) => raw) => {
75
+ let out = ''
76
+ let last = 0
77
+ for (const [start, end, raw] of rawRanges(html)) {
78
+ out += fn(html.slice(last, start)) + onRaw(raw)
79
+ last = end
80
+ }
81
+ return out + fn(html.slice(last))
82
+ }
83
+
84
+ // First match of `re` at or after `from` that does not start inside a raw block.
85
+ const findOutside = (html, re, from = 0) => {
86
+ const ranges = rawRanges(html)
87
+ const g = new RegExp(re.source, re.flags.includes('g') ? re.flags : re.flags + 'g')
88
+ g.lastIndex = from
89
+ let m
90
+ while ((m = g.exec(html))) {
91
+ const at = m.index
92
+ const inside = ranges.find(([s, e]) => at > s && at < e)
93
+ if (!inside) return m
94
+ g.lastIndex = inside[1]
95
+ }
96
+ return null
97
+ }
98
+
99
+ const isRelativeUrl = (url) => !!url &&
100
+ !/^(?:[a-z][a-z0-9+.-]*:|\/|#|\?)/i.test(url)
101
+
102
+ // Quoted or unquoted (minifiers drop the quotes: `src=index.js`).
103
+ const rebaseTag = (tag, prefix) =>
104
+ tag.replace(/(\s(?:src|href)\s*=\s*)(?:(["'])([^"']*)\2|([^\s"'>]+))/gi, (whole, lead, q, quoted, bare) => {
105
+ const url = q ? quoted : bare
106
+ if (!isRelativeUrl(url)) return whole
107
+ const quote = q || ''
108
+ return `${lead}${quote}${prefix}${url.replace(/^\.\//, '')}${quote}`
109
+ })
110
+
111
+ // Rebase relative src/href on <script>/<link> tags by `depth` directories —
112
+ // the tags only: an inline script's TEXT is never touched.
113
+ const rebaseAssets = (html, depth) => {
114
+ if (!depth) return html
115
+ const prefix = '../'.repeat(depth)
116
+ return mapOutsideRawBlocks(
117
+ html,
118
+ (markup) => markup.replace(/<link\b[^>]*>/gi, (tag) => rebaseTag(tag, prefix)),
119
+ (raw) => /^<script\b/i.test(raw)
120
+ ? raw.replace(/^<script\b[^>]*>/i, (tag) => rebaseTag(tag, prefix))
121
+ : raw
122
+ )
123
+ }
124
+
125
+ /**
126
+ * @param {string} shell - the built app document (e.g. dist/index.html)
127
+ * @param {object} parts
128
+ * @param {string} [parts.headTags] - route metadata tags (generateHeadHtml)
129
+ * @param {string} [parts.headEnd] - font links + <style> blocks for </head>
130
+ * @param {string} [parts.body] - rendered body markup
131
+ * @param {number} [parts.depth=0] - directory depth of the output file
132
+ * @returns {string}
133
+ */
134
+ export const composeIntoShell = (shell, { headTags = '', headEnd = '', body = '', depth = 0 } = {}) => {
135
+ if (typeof shell !== 'string' || !shell.trim()) {
136
+ throw new Error('brender: the shell document is empty')
137
+ }
138
+ let html = rebaseAssets(shell, depth)
139
+
140
+ const owned = new Set()
141
+ for (const m of headTags.matchAll(HEAD_TAG)) {
142
+ const key = headTagKey(m[0])
143
+ if (key) owned.add(key)
144
+ }
145
+ const dropOwned = (markup) => mapOutsideRawBlocks(markup, (segment) =>
146
+ segment.replace(HEAD_TAG, (tag) => owned.has(headTagKey(tag)) ? '' : tag)
147
+ )
148
+ const headIn = (headTags ? `\n${headTags}` : '')
149
+ const headOut = (headEnd ? `\n${headEnd}\n` : '')
150
+
151
+ const headOpen = findOutside(html, HEAD_OPEN)
152
+ const headClose = headOpen && findOutside(html, /<\/head\s*>/i, headOpen.index)
153
+ if (headOpen && headClose) {
154
+ const start = headOpen.index + headOpen[0].length
155
+ const end = headClose.index
156
+ html = html.slice(0, start) + headIn + dropOwned(html.slice(start, end)) + headOut + html.slice(end)
157
+ } else {
158
+ // Optional <head>/<body> tags omitted — parcel's minifier (htmlnano)
159
+ // emits `<html lang=en><script type=importmap>…<meta charset=utf-8>
160
+ // <title>…<script type=module src=…>` with neither. Metadata and styles
161
+ // go right after <html> (or the doctype), where the parser opens the
162
+ // implied head; the shell's own metadata tags of the same identity are
163
+ // dropped wherever they sit.
164
+ html = dropOwned(html)
165
+ const htmlOpen = findOutside(html, /<html(\s[^>]*)?>/i) || findOutside(html, /<!doctype[^>]*>/i)
166
+ const at = htmlOpen ? htmlOpen.index + htmlOpen[0].length : 0
167
+ html = html.slice(0, at) + headIn + headOut + html.slice(at)
168
+ }
169
+
170
+ const flagged = `\n<script>window.__BRENDER__=true</script>\n${body}\n`
171
+ const bodyOpen = findOutside(html, BODY_OPEN)
172
+ if (bodyOpen) {
173
+ // Right after <body>: before every shell script, so a classic inline
174
+ // boot script (symbols-runner) already finds the flag and the markup.
175
+ const at = bodyOpen.index + bodyOpen[0].length
176
+ return html.slice(0, at) + flagged + html.slice(at)
177
+ }
178
+ // No <body> tag: the markup opens the implied body at the end of the
179
+ // document. Such shells load the app with module scripts (parcel, vite),
180
+ // which run after parsing — the flag and the markup are in place by then.
181
+ const htmlClose = findOutside(html, /<\/(?:body|html)\s*>/i)
182
+ const at = htmlClose ? htmlClose.index : html.length
183
+ return html.slice(0, at) + flagged + html.slice(at)
184
+ }