@symbo.ls/brender 3.14.677 → 3.14.678

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,38 @@
1
1
  # @symbo.ls/brender
2
2
 
3
+ ## 3.14.678
4
+
5
+ ### Patch Changes
6
+
7
+ - 9e31e2f: The faces sheet `<style data-smbls-faces>` carries `data-smbls-faces-version` (sha256 of the sheet's rules, 12 hex: equal rules give an equal version) and `data-smbls-faces-files` (per `@font-face`, in rule order, the first `url()` of its `src`; `-` for a rule with no file). The helpers (`facesSheetTag`, `facesSheetMarks`, `markFacesSheet`, `faceFileOf`) are exported from the root and from the new light subpath `@symbo.ls/brender/faces`. `smbls build` / `smbls brender` mark each page again after its `file:` URLs are mapped into the output, so the version follows the shipped files. No sheet file is written.
8
+
9
+ The built-page script defines `window.__smblsFacesReady`: a promise for the faces the page draws (`document.fonts.load` per family, weight and style). It resolves with the loaded `FontFace` objects, at the time limit (the hold cap, else 3000 ms) with the ones loaded so far, and at once with `[]` when the page has no faces. It never rejects. A property that already exists is kept.
10
+
11
+ `brender.app: { start: 'afterFirstView', after: 'faces' | '<window property>' | [ … ] }`: the app's files also wait for the page's faces promise and/or project promises (a property set later is watched; a rejection counts as in; the first input and `wait` still start the app). Without `after` the start is unchanged; `after` with an eager start is an error.
12
+
13
+ A failed AVIF `<source>` (the one whose `srcset` names the image's `currentSrc`) is taken out of its `<picture>` once, on the image's error or when it failed before the script ran; the browser then picks the WebP or the `<img>` src. No loop; an image still loading is untouched.
14
+
15
+ The built-page script stays hand-written ES5: 2,115 → 4,084 B raw, 760 → 1,363 B Brotli.
16
+
17
+ - 2522f1c: A server render keeps the rules a browser keeps that linkedom's CSS parser cannot read: `@container` (the breakpoints of `breakpointsFrom: 'container'`), `@layer`, `@scope`, `@starting-style`, and an `@media` / `@supports` that holds one. They were dropped, so the page's classes went into the markup without their rules and a phone's first frame showed the desktop layout.
18
+
19
+ `smbls publish --ssr` honours a page's `prerender: false` and symbols.json `brender.exclude`, as `smbls build` and `smbls brender` do: an opted-out page costs no render and no budget, and the publish report lists it.
20
+
21
+ Page code that throws after its render (a timer, an animation frame, a rejected promise) is reported once per message and never ends the publish; each server window has its own timers.
22
+
23
+ - Updated dependencies [2522f1c]
24
+ - Updated dependencies [2522f1c]
25
+ - Updated dependencies [f718247]
26
+ - Updated dependencies [c21bff7]
27
+ - Updated dependencies [c62254b]
28
+ - Updated dependencies [77a4634]
29
+ - Updated dependencies [0d684b1]
30
+ - @symbo.ls/fetch@3.14.674
31
+ - smbls@3.14.860
32
+ - @symbo.ls/utils@3.14.854
33
+ - @symbo.ls/helmet@3.14.673
34
+ - @symbo.ls/scratch@3.14.796
35
+
3
36
  ## 3.14.677
4
37
 
5
38
  ### Patch Changes
package/README.md CHANGED
@@ -198,6 +198,16 @@ No inline script — a strict Content-Security-Policy (`script-src 'self'`, no `
198
198
  | `<script type="application/json" data-fetch-seed>[…]</script>` | after the markup | The anonymous GET answers the render got (`@symbo.ls/fetch`), adopted by the client request that sends exactly the same request |
199
199
  | `<meta name="brender-stamp" content="<stamp>" data-time="<ms>">` | `<head>`, after the mark | The build the page comes from: `stamp` (the `stamp` option, else the render time as an ISO string) and the render time in ms. App code reads it as `el.context.prerender` (`{ stamp, time }`) |
200
200
  | `<link rel="expect" href="#smbls-whole" blocking="render">` + `<template id="smbls-whole">` | after the charset declaration; after the markup | `paint: { whole: true }` only: the first paint waits for the whole markup |
201
+ | `<style data-smbls-faces data-smbls-faces-version="…" data-smbls-faces-files="…">` | `<head>`, ahead of the page's styles | Every `@font-face` rule of the page, in one sheet, with two marks for a host (below). Only when the page has faces |
202
+
203
+ **The faces sheet and its marks.** A host that serves a returning reader the faces it keeps by address, and the rest inline, reads two marks on the sheet; brender writes no other faces file:
204
+
205
+ | Mark | Value |
206
+ |------|-------|
207
+ | `data-smbls-faces-version` | A content hash of the sheet's rules (12 hex characters): equal rules in the same order give the same version on every page and every render; any change to a rule (a file, a range, a `font-display`), a rule more or less, or another order gives a new one. |
208
+ | `data-smbls-faces-files` | Per `@font-face` rule, in rule order, its file address: the first `url()` of its `src` — a `local()` before it is skipped, a later `url()` (another format) is not listed — as the rule names it. `-` for a rule that names no file (only `local()`, or a `data:` URL). Space-separated; a space in an address is written `%20`. |
209
+
210
+ The marks describe the faces by address. `smbls build` marks each page again after its `file:` URLs point into the build output, so the version follows the files the page ships (every page of a build carries the same one when the font URLs are site-root or absolute; a relative URL differs by the page's directory, and so does the version). Its `brender.faces.inline` step moves files into the sheet as `data:` URLs and keeps both marks as they were: an inlined face still names its file. A tool that changes the addresses in a page itself calls `markFacesSheet(html)` (exported): it writes both marks again from the rules the sheet holds, leaves the sheet's text and its other attributes as they are, and returns a page without a faces sheet unchanged. `facesSheetMarks(rules)` returns `{ version, files }` for a sheet's text or its rules (`null` without a `@font-face`).
201
211
 
202
212
  The runtime also reads what pages from brender up to 3.14.664 carry — the inline `window.__BRENDER__` flag, `window.__BR_REGISTRY__`, `window.__BRENDER_HYDRATE__` — and, when a policy blocked that flag, takes a `data-br` element directly in the mount node for the mark. An smbls runtime older than this format does not know the `<meta>`: keep `smbls` and `@symbo.ls/brender` at the same release.
203
213
 
package/dist/esm/env.js CHANGED
@@ -1 +1 @@
1
- import{parseHTML as f}from"linkedom";const p=new WeakSet;class y{static[Symbol.hasInstance](e){return p.has(e)}}const m=o=>{let e=Object.getPrototypeOf(o.createElement("select")),t;for(;e&&!(t=Object.getOwnPropertyDescriptor(e,"value"));)e=Object.getPrototypeOf(e);!e||!t||!t.get||t.set||Object.defineProperty(e,"value",{configurable:!0,enumerable:t.enumerable,get:t.get,set(l){const s=l==null?"":String(l);let n=!1;for(const i of this.querySelectorAll("option")){const r=i.hasAttribute("value")?i.getAttribute("value"):i.textContent;!n&&r===s?(i.setAttribute("selected",""),n=!0):i.removeAttribute("selected")}}})},h=Symbol.for("@symbo.ls/brender:styleMap"),b=o=>typeof o=="string"&&o.charCodeAt(0)===45&&o.charCodeAt(1)===45,d=o=>{let e=Object.getPrototypeOf(o.createElement("div").style);for(;e&&!Object.prototype.hasOwnProperty.call(e,"setProperty");)e=Object.getPrototypeOf(e);if(!e||Object.prototype.hasOwnProperty.call(e,h))return;const{setProperty:t,removeProperty:l,getPropertyValue:s}=e;if(typeof t!="function"||typeof l!="function"||typeof s!="function")return;Object.defineProperty(e,h,{configurable:!0,get(){return this}});const n=(r,a)=>{let c="";for(;a.has(c);)c+=" ";l.call(r,c)},i=(r,a,c)=>{const u=r[h];n(r,u),c==null?u.delete(a):u.set(a,c),n(r,u)};Object.defineProperties(e,{setProperty:{configurable:!0,writable:!0,value:function(r,a){if(!b(r))return t.apply(this,arguments);i(this,r,a)}},removeProperty:{configurable:!0,writable:!0,value:function(r){if(!b(r))return l.apply(this,arguments);i(this,r,null)}},getPropertyValue:{configurable:!0,writable:!0,value:function(r){return b(r)?(s.call(this,r),this[h].get(r)):s.apply(this,arguments)}}})},g=()=>{const o={};return{getItem:e=>o[e]??null,setItem:(e,t)=>{o[e]=String(t)},removeItem:e=>{delete o[e]},clear:()=>{for(const e in o)delete o[e]},get length(){return Object.keys(o).length},key:e=>Object.keys(o)[e]??null}},T=(o="<!DOCTYPE html><html><head></head><body></body></html>")=>{const e={location:{pathname:"/",search:"",hash:"",origin:"http://localhost",protocol:"http:",host:"localhost",hostname:"localhost",port:"",href:"http://localhost/"},localStorage:g(),sessionStorage:g(),history:{pushState:()=>{},replaceState:()=>{},state:null}},{window:t,document:l}=f(o,e);return t.requestAnimationFrame||(t.requestAnimationFrame=s=>{const n=setTimeout(s,0);return n?.unref&&n.unref(),n}),t.cancelAnimationFrame||(t.cancelAnimationFrame=s=>clearTimeout(s)),t.URL||(t.URL=URL),t.scrollTo||(t.scrollTo=()=>{}),globalThis.localStorage=e.localStorage,globalThis.sessionStorage=e.sessionStorage,globalThis.history||(globalThis.history=e.history),m(l),d(l),t.MutationObserver||(t.MutationObserver=class{constructor(){}observe(){}disconnect(){}takeRecords(){return[]}}),globalThis.window=t,globalThis.document=l,globalThis.Node=t.Node||globalThis.Node,globalThis.Element=t.Element||globalThis.Element,globalThis.HTMLElement=t.HTMLElement||globalThis.HTMLElement,globalThis.MutationObserver=t.MutationObserver,p.add(t),t.constructor&&t.constructor!==Object?globalThis.Window=t.constructor:(typeof globalThis.Window!="function"||globalThis.Window===Object)&&(globalThis.Window=y),{window:t,document:l}};export{T as createEnv};
1
+ import{parseHTML as A}from"linkedom";const S=new WeakSet;class M{static[Symbol.hasInstance](t){return S.has(t)}}const C=r=>{let t=Object.getPrototypeOf(r.createElement("select")),e;for(;t&&!(e=Object.getOwnPropertyDescriptor(t,"value"));)t=Object.getPrototypeOf(t);!t||!e||!e.get||e.set||Object.defineProperty(t,"value",{configurable:!0,enumerable:e.enumerable,get:e.get,set(o){const s=o==null?"":String(o);let i=!1;for(const l of this.querySelectorAll("option")){const n=l.hasAttribute("value")?l.getAttribute("value"):l.textContent;!i&&n===s?(l.setAttribute("selected",""),i=!0):l.removeAttribute("selected")}}})},d=Symbol.for("@symbo.ls/brender:styleMap"),w=r=>typeof r=="string"&&r.charCodeAt(0)===45&&r.charCodeAt(1)===45,U=r=>{let t=Object.getPrototypeOf(r.createElement("div").style);for(;t&&!Object.prototype.hasOwnProperty.call(t,"setProperty");)t=Object.getPrototypeOf(t);if(!t||Object.prototype.hasOwnProperty.call(t,d))return;const{setProperty:e,removeProperty:o,getPropertyValue:s}=t;if(typeof e!="function"||typeof o!="function"||typeof s!="function")return;Object.defineProperty(t,d,{configurable:!0,get(){return this}});const i=(n,c)=>{let u="";for(;c.has(u);)u+=" ";o.call(n,u)},l=(n,c,u)=>{const a=n[d];i(n,a),u==null?a.delete(c):a.set(c,u),i(n,a)};Object.defineProperties(t,{setProperty:{configurable:!0,writable:!0,value:function(n,c){if(!w(n))return e.apply(this,arguments);l(this,n,c)}},removeProperty:{configurable:!0,writable:!0,value:function(n){if(!w(n))return o.apply(this,arguments);l(this,n,null)}},getPropertyValue:{configurable:!0,writable:!0,value:function(n){return w(n)?(s.call(this,n),this[d].get(n)):s.apply(this,arguments)}}})},T=Symbol.for("@symbo.ls/brender:groupRules"),W=/^@(container|layer|scope|starting-style|media|supports)(?![\w-])/i,_=/^@layer\s+[-\w.]+(?:\s*,\s*[-\w.]+)*\s*;?$/i,I={media:4,supports:12},O=r=>{const t=[];let e=0,o=0,s=null;const i=l=>{const n=r.slice(o,l).trim();n&&t.push(n),o=l};for(let l=0;l<r.length;l++){const n=r[l];if(s){n==="\\"?l++:n===s&&(s=null);continue}if(n==="\\"){l++;continue}if(n==="/"&&r[l+1]==="*"){const c=r.indexOf("*/",l+2);if(c===-1)return null;e===0&&!r.slice(o,l).trim()&&(o=c+2),l=c+1;continue}if(n==='"'||n==="'")s=n;else if(n==="{")e++;else if(n==="}"){if(e===0)return null;--e===0&&i(l+1)}else n===";"&&e===0&&i(l+1)}return s||e?null:(i(r.length),t)};class R{constructor(t,e,o){this.keyword=t,this.condition=e,this.cssRules=o,this.parentRule=null,this.parentStyleSheet=null;for(const s of o)s.parentRule=this}get type(){return I[this.keyword]||0}get conditionText(){return this.condition}get name(){return this.keyword==="layer"?this.condition:void 0}get cssText(){let t="";for(const e of this.cssRules)t+=e.cssText;return`@${this.keyword}${this.condition?" "+this.condition:""} {${t}}`}}class ${constructor(t){this.nameList=t,this.parentRule=null,this.parentStyleSheet=null}get type(){return 0}get cssText(){return`@layer ${this.nameList.join(", ")};`}}const N=(r,t)=>{const e={cssRules:[]};let o=null;try{if(t.call(e,r,0),e.cssRules[0])return e.cssRules[0]}catch(i){o=i}const s=P(String(r).trim(),t);if(s)return s;throw o||new SyntaxError(`Failed to parse the rule '${r}'`)},P=(r,t)=>{if(_.test(r))return new $(r.replace(/^@layer\s+/i,"").replace(/\s*;$/,"").split(/\s*,\s*/));const e=W.exec(r);if(!e)return null;const o=O(r);if(!o||o.length!==1||!r.endsWith("}"))return null;const s=q(r);if(s===-1)return null;const i=O(r.slice(s+1,-1));if(!i)return null;const l=[];for(const n of i)try{l.push(N(n,t))}catch{return null}return new R(e[1].toLowerCase(),r.slice(e[0].length,s).trim(),l)},q=r=>{let t=null;for(let e=0;e<r.length;e++){const o=r[e];if(t){o==="\\"?e++:o===t&&(t=null);continue}if(o==="\\"){e++;continue}if(o==="/"&&r[e+1]==="*"){const s=r.indexOf("*/",e+2);if(s===-1)return-1;e=s+1;continue}if(o==='"'||o==="'")t=o;else if(o==="{")return e}return-1},E=(r,t)=>{if(r.parentStyleSheet=t,r instanceof R)for(const e of r.cssRules)E(e,t)},F=r=>{const t=r.createElement("style");let e;try{e=t.sheet}catch{return}let o=e&&Object.getPrototypeOf(e);for(;o&&!Object.prototype.hasOwnProperty.call(o,"insertRule");)o=Object.getPrototypeOf(o);if(!o||Object.prototype.hasOwnProperty.call(o,T))return;const s=o.insertRule;if(typeof s!="function")return;const i=e.constructor;Object.defineProperty(o,T,{configurable:!0,value:!0}),Object.defineProperty(o,"insertRule",{configurable:!0,writable:!0,value:function(p,h){try{return s.apply(this,arguments)}catch(b){const f=String(p),g=P(f.trim(),s);if(!g)throw b;const y=h===void 0?0:Number(h);if(!(y>=0&&y<=this.cssRules.length))throw new RangeError("INDEX_SIZE_ERR");return E(g,this),this.cssRules.splice(y,0,g),y}}});let l=Object.getPrototypeOf(t),n;for(;l&&!(n=Object.getOwnPropertyDescriptor(l,"sheet"));)l=Object.getPrototypeOf(l);if(!l||!n||typeof n.get!="function"||typeof i!="function")return;const c=n.get,u=new WeakMap;Object.defineProperty(l,"sheet",{configurable:!0,enumerable:n.enumerable,get(){try{return c.call(this)}catch(a){const p=this.textContent,h=u.get(this);if(h&&h.text===p)return h.sheet;const b=O(p);if(!b)throw a;const f=new i;for(const g of b)try{f.insertRule(g,f.cssRules.length)}catch{}return u.set(this,{text:p,sheet:f}),f}}})},m=new Set,j=r=>{const t=r&&r.message||String(r);m.has(t)||(m.size>=200&&m.clear(),m.add(t),console.warn(`[brender] page code threw in a timer; reported as a browser reports it, the render goes on (once per message): ${t}`))},v=r=>function(...t){try{const e=r.apply(this,t);return e&&typeof e.then=="function"&&e.then(null,j),e}catch(e){j(e)}},L=r=>(t,...e)=>globalThis[r](typeof t=="function"?v(t):t,...e),k=()=>{const r={};return{getItem:t=>r[t]??null,setItem:(t,e)=>{r[t]=String(e)},removeItem:t=>{delete r[t]},clear:()=>{for(const t in r)delete r[t]},get length(){return Object.keys(r).length},key:t=>Object.keys(r)[t]??null}},G=(r="<!DOCTYPE html><html><head></head><body></body></html>")=>{const t={location:{pathname:"/",search:"",hash:"",origin:"http://localhost",protocol:"http:",host:"localhost",hostname:"localhost",port:"",href:"http://localhost/"},localStorage:k(),sessionStorage:k(),history:{pushState:()=>{},replaceState:()=>{},state:null},setTimeout:L("setTimeout"),setInterval:L("setInterval")},{window:e,document:o}=A(r,t);return e.requestAnimationFrame||(e.requestAnimationFrame=s=>{const i=setTimeout(typeof s=="function"?v(s):s,0);return i?.unref&&i.unref(),i}),e.cancelAnimationFrame||(e.cancelAnimationFrame=s=>clearTimeout(s)),e.URL||(e.URL=URL),e.scrollTo||(e.scrollTo=()=>{}),globalThis.localStorage=t.localStorage,globalThis.sessionStorage=t.sessionStorage,globalThis.history||(globalThis.history=t.history),C(o),U(o),F(o),e.MutationObserver||(e.MutationObserver=class{constructor(){}observe(){}disconnect(){}takeRecords(){return[]}}),globalThis.window=e,globalThis.document=o,globalThis.Node=e.Node||globalThis.Node,globalThis.Element=e.Element||globalThis.Element,globalThis.HTMLElement=e.HTMLElement||globalThis.HTMLElement,globalThis.MutationObserver=e.MutationObserver,S.add(e),e.constructor&&e.constructor!==Object?globalThis.Window=e.constructor:(typeof globalThis.Window!="function"||globalThis.Window===Object)&&(globalThis.Window=M),{window:e,document:o}};export{G as createEnv};
@@ -0,0 +1,5 @@
1
+ import{createHash as S}from"crypto";import{stylesheetRules as x}from"./pageWeight.js";const u="data-smbls-faces",h="data-smbls-faces-version",A="data-smbls-faces-files",F="-",y=/^@font-face\b/i,T=t=>typeof t=="string"&&y.test(t.trim()),E=t=>{const e={},s=t.indexOf("{");if(s===-1)return e;let o=s+1,n=null,i=0;const c=r=>{const l=t.slice(o,r),a=l.indexOf(":");if(a!==-1){const f=l.slice(0,a).trim().toLowerCase();f&&!(f in e)&&(e[f]=l.slice(a+1).trim())}o=r+1};for(let r=o;r<t.length;r++){const l=t[r];if(n){l==="\\"?r++:l===n&&(n=null);continue}if(l==="\\"){r++;continue}if(l==='"'||l==="'")n=l;else if(l==="(")i++;else if(l===")")i=Math.max(0,i-1);else{if(i)continue;if(l===";")c(r);else if(l==="}"){c(r);break}}}return e},_=t=>{const e=parseInt(t,16);return e>0&&e<=1114111&&!(e>=55296&&e<=57343)?String.fromCodePoint(e):"\uFFFD"},$=t=>{const e=t.trim(),s=e[0];return((s==='"'||s==="'")&&e.length>1&&e[e.length-1]===s?e.slice(1,-1):e).replace(/\\(?:([0-9a-fA-F]{1,6})\s?|([\s\S]))/g,(n,i,c)=>i?_(i):c).trim()},b=t=>{if(typeof t!="string")return null;let e=null;for(let s=0;s<t.length;s++){const o=t[s];if(e){o==="\\"?s++:o===e&&(e=null);continue}if(o==='"'||o==="'"){e=o;continue}if(!/^url\(/i.test(t.slice(s,s+4))||/[\w-]/.test(t[s-1]||""))continue;let n=s+4;for(;n<t.length&&/\s/.test(t[n]);)n++;let i;if(t[n]==='"'||t[n]==="'"){for(i=n+1;i<t.length&&t[i]!==t[n];)i+=t[i]==="\\"?2:1;i++}else i=t.indexOf(")",n),i===-1&&(i=t.length);const c=$(t.slice(n,i));return c&&!/^data:/i.test(c)?c:null}return null},R=t=>t?t.replace(/\s/g,e=>"%"+e.charCodeAt(0).toString(16).toUpperCase().padStart(2,"0")):F,p=t=>{const e=typeof t=="string"?x(t):Array.isArray(t)?t:null;if(!e)return null;const s=e.map(n=>String(n).trim()).filter(Boolean),o=s.filter(T);return o.length?{version:S("sha256").update(s.join(`
2
+ `)).digest("hex").slice(0,12),files:o.map(n=>R(b(E(n).src)))}:null},g=t=>String(t).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),d=t=>t?` ${h}="${g(t.version)}" ${A}="${g(t.files.join(" "))}"`:"",I=t=>!Array.isArray(t)||!t.length?"":`<style ${u}${d(p(t))}>
3
+ ${t.join(`
4
+ `)}
5
+ </style>`,C=/<script\b[\s\S]*?<\/script\s*>|<style\b([^>]*)>([\s\S]*?)(<\/style\s*>)/gi,m=/(^|\s)data-smbls-faces(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?(?=[\s/]|$)/i,O=/\s(?:data-smbls-faces-version|data-smbls-faces-files)(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?/gi,j=t=>{if(typeof t!="string"||!t.includes(u))return t;let e=!1;return t.replace(C,(s,o,n,i)=>{if(e||o===void 0||!m.test(o))return s;e=!0;const c=p(n);if(!c)return s;const r=o.replace(O,""),l=m.exec(r),a=l.index+l[0].length;return`<style${r.slice(0,a)}${d(c)}${r.slice(a)}>${n}${i}`})};export{A as FACES_FILES_ATTR,u as FACES_SHEET_ATTR,h as FACES_VERSION_ATTR,F as NO_FACE_FILE,b as faceFileOf,p as facesSheetMarks,I as facesSheetTag,j as markFacesSheet};
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 l,renderElement as p,renderRoute as i,renderPage as s,resetGlobalCSSCache as d,getAccumulatedEmotionCSS as n,replaceEmotionCSS as c,adoptionScripts as f,prerenderParts as S,buildStamp as g}from"./render.js";import{extractMetadata as u,generateHeadHtml as P}from"./metadata.js";import{collectBrNodes as h,hydrate as y}from"./hydrate.js";import{generateSitemap as C}from"./sitemap.js";import{prefetchPageData as E,injectPrefetchedState as R}from"./prefetch.js";import{composeIntoShell as b}from"./shell.js";import{trimSpriteToPage as x,classRulesForPage as A,markupClasses as K,trimVariablesToPage as T,stylesheetRules as j}from"./pageWeight.js";var V={createEnv:e,resetKeys:r,assignKeys:t,mapKeysToElements:o,loadProject:a,loadAndRenderAll:m,render:l,renderElement:p,renderRoute:i,renderPage:s,resetGlobalCSSCache:d,getAccumulatedEmotionCSS:n,replaceEmotionCSS:c,extractMetadata:u,generateHeadHtml:P,collectBrNodes:h,hydrate:y,generateSitemap:C,prefetchPageData:E,injectPrefetchedState:R,composeIntoShell:b,adoptionScripts:f,prerenderParts:S,buildStamp:g,trimSpriteToPage:x,classRulesForPage:A,markupClasses:K,trimVariablesToPage:T,stylesheetRules:j};export{f as adoptionScripts,t as assignKeys,g as buildStamp,A as classRulesForPage,h as collectBrNodes,b as composeIntoShell,e as createEnv,V as default,u as extractMetadata,P as generateHeadHtml,C as generateSitemap,n as getAccumulatedEmotionCSS,y as hydrate,R as injectPrefetchedState,m as loadAndRenderAll,a as loadProject,o as mapKeysToElements,K as markupClasses,E as prefetchPageData,S as prerenderParts,l as render,p as renderElement,s as renderPage,i as renderRoute,c as replaceEmotionCSS,d as resetGlobalCSSCache,r as resetKeys,j as stylesheetRules,x as trimSpriteToPage,T as trimVariablesToPage};
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 s,renderElement as p,renderRoute as i,renderPage as l,resetGlobalCSSCache as d,getAccumulatedEmotionCSS as n,replaceEmotionCSS as c,adoptionScripts as f,prerenderParts as S,buildStamp as g}from"./render.js";import{extractMetadata as h,generateHeadHtml as u}from"./metadata.js";import{collectBrNodes as P,hydrate as y}from"./hydrate.js";import{generateSitemap as C}from"./sitemap.js";import{prefetchPageData as E,injectPrefetchedState as R}from"./prefetch.js";import{composeIntoShell as b}from"./shell.js";import{trimSpriteToPage as k,classRulesForPage as x,markupClasses as A,trimVariablesToPage as K,stylesheetRules as T}from"./pageWeight.js";import{markFacesSheet as j,facesSheetMarks as F}from"./faces.js";var z={createEnv:e,resetKeys:r,assignKeys:t,mapKeysToElements:o,loadProject:a,loadAndRenderAll:m,render:s,renderElement:p,renderRoute:i,renderPage:l,resetGlobalCSSCache:d,getAccumulatedEmotionCSS:n,replaceEmotionCSS:c,extractMetadata:h,generateHeadHtml:u,collectBrNodes:P,hydrate:y,generateSitemap:C,prefetchPageData:E,injectPrefetchedState:R,composeIntoShell:b,adoptionScripts:f,prerenderParts:S,buildStamp:g,trimSpriteToPage:k,classRulesForPage:x,markupClasses:A,trimVariablesToPage:K,stylesheetRules:T,markFacesSheet:j,facesSheetMarks:F};export{f as adoptionScripts,t as assignKeys,g as buildStamp,x as classRulesForPage,P as collectBrNodes,b as composeIntoShell,e as createEnv,z as default,h as extractMetadata,F as facesSheetMarks,u as generateHeadHtml,C as generateSitemap,n as getAccumulatedEmotionCSS,y as hydrate,R as injectPrefetchedState,m as loadAndRenderAll,a as loadProject,o as mapKeysToElements,j as markFacesSheet,A as markupClasses,E as prefetchPageData,S as prerenderParts,s as render,p as renderElement,l as renderPage,i as renderRoute,c as replaceEmotionCSS,d as resetGlobalCSSCache,r as resetKeys,T as stylesheetRules,k as trimSpriteToPage,K as trimVariablesToPage};
@@ -1,23 +1,20 @@
1
- import{resolve as d,join as tt,dirname as j}from"path";import{existsSync as S,unlinkSync as ot,readFileSync as Y,realpathSync as nt}from"fs";import{resolvePackageEntry as st}from"./packageEntry.js";import{tmpdir as rt}from"os";import{randomBytes as ct}from"crypto";import{createRequire as ge}from"module";import{pathToFileURL as it}from"url";import{createEnv as je}from"./env.js";import{resetKeys as Te,assignKeys as ve,mapKeysToElements as Le}from"./keys.js";import{extractMetadata as he,generateHeadHtml as lt}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as at}from"./shell.js";import{trimSpriteToPage as ft,classRulesForPage as pt,markupClasses as ut,trimVariablesToPage as mt}from"./pageWeight.js";import{fetchSSRTranslations as dt}from"./prefetch.js";import{createEarlySeedScript as gt}from"@symbo.ls/fetch";import{headerEntries as ht}from"@symbo.ls/fetch/rest";import{brenderStampMeta as yt,brenderLazyMeta as $e,escapeRegExp as bt,jsonForScript as St,libraryPackageSpecs as Rt,polyglotFallbackLang as ye,polyglotLangStorageKey as wt,polyglotAddressLang as kt,polyglotStartupScript as xt}from"@symbo.ls/utils";import{brenderRegistryBlock as _t,brenderRegistryTreeBlock as Et}from"@symbo.ls/utils/server";import*as jt from"@symbo.ls/utils/server";let ce=null;const Tt=async()=>{if(ce)return ce;try{return ce=(await import("@symbo.ls/funcql")).funcqlPlugin,ce}catch{return null}};import"linkedom";import{createEarlySeedBlock as vt,fetchRunsOf as Lt}from"@symbo.ls/fetch";import{reset as $t}from"@symbo.ls/css";const ie=(e,t)=>{if(!e||!t)return;if(e[t]!==void 0)return e[t];const o=t.split(".");let n=e;for(const s of o){if(n==null||typeof n!="object")return;n=n[s]}return n},le=(e,t)=>ye(e?.lang,t),At=e=>{const t=jt.revivePolyglotDefaultLang;if(typeof t!="function"||!e||typeof e!="object")return e;const o=e.polyglot?t(e.polyglot):e.polyglot,n=e.config&&e.config.polyglot,s=n&&t(n);if(o===e.polyglot&&s===n)return e;const r={...e};return o!==e.polyglot&&(r.polyglot=o),s!==n&&(r.config={...e.config,polyglot:s}),r},Ae=(e,t,o,n)=>{if(o?.translations){const r=o.translations[t];if(r){const i=ie(r,e);if(i!==void 0)return i}}if(n?.translations){const r=n.translations[t];if(r){const i=ie(r,e);if(i!==void 0)return i}}const s=ye(void 0,o);if(s!==t&&o?.translations){const r=o.translations[s];if(r){const i=ie(r,e);if(i!==void 0)return i}}},Dt=function(e,t){if(!e)return"";const o=this?.context,n=o?.polyglot,s=this?.state?.root||o?.state?.root,r=Ae(e,t||le(s,n),n,s);if(r!==void 0)return r;const i=we(Re);return n&&i&&i.labelKeys.add(e),e},De=function(){return le(this?.state?.root,this?.context?.polyglot)},L=(e,t=new WeakMap)=>{if(e===null||typeof e!="object")return e;if(t.has(e))return t.get(e);if(Array.isArray(e)){const n=[];t.set(e,n);for(const s of e)n.push(typeof s=="object"&&s!==null?L(s,t):s);return n}const o={};t.set(e,o);for(const n of Object.keys(e)){const s=e[n];o[n]=typeof s=="object"&&s!==null?L(s,t):s}return o};let q=null;try{import.meta.url&&(q=ge(import.meta.url))}catch{}const Ct=()=>{if(!import.meta.url||!q)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:a=>a};const e=nt(new URL(".",import.meta.url).pathname),t=d(e,"../..");if(S(d(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let n;try{const a=q.resolve("smbls/package.json");n=j(a)}catch{let a=e;for(;a!==j(a);){const g=d(a,"node_modules","smbls");if(S(d(g,"package.json"))){n=g;break}a=j(a)}}let s=q;if(n)try{s=ge(d(n,"package.json"))}catch{}let r,i=process.cwd();for(;i!==j(i);){if(S(d(i,"package.json"))){r=i;break}i=j(i)}let u=s;if(r)try{u=ge(d(r,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:n,brenderDir:e,projectRoot:r,_smblsRequire:s,_projectRequire:u}},H=(e,t)=>{const o=e.isMonorepo?[q]:[e._smblsRequire,e._projectRequire,q].filter(Boolean);for(const n of o)try{return n.resolve(t)}catch{}return null},en=(e,t,...o)=>{if(e.isMonorepo)return d(e.monorepoRoot,"packages",t,...o);const n=H(e,`${t}/package.json`);return n?d(j(n),...o):null},tn=(e,t,...o)=>{if(e.isMonorepo)return d(e.monorepoRoot,"plugins",t,...o);const n=H(e,`@symbo.ls/${t}/package.json`);return n?d(j(n),...o):null},be=(e,t,...o)=>{if(e.isMonorepo){for(const s of["packages","plugins"]){const r=d(e.monorepoRoot,s,t,...o);if(S(r))return r}return null}const n=H(e,`@symbo.ls/${t}/package.json`);return n?d(j(n),...o):null},Ce=(e,t,...o)=>{if(e.isMonorepo)return d(e.monorepoRoot,"packages","domql","packages",t,...o);const n=H(e,`@symbo.ls/${t}/package.json`);return n?d(j(n),...o):null};let ae=null;const Me="smbls/ssr",Mt=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},Oe=()=>(ae||(ae=Ot().catch(e=>{throw ae=null,e})),ae),Ot=async()=>{const e=Ct();let t;if(q&&e.isMonorepo)t=d(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let f;try{return await Mt()}catch(l){f=l}if(!q)throw new Error(`brender: ${Me} is not available in this bundled runtime (${f.message}). Bundle smbls \u2265 the release that adds the smbls/ssr export alongside @symbo.ls/brender.`);const c=e.smblsRoot&&d(e.smblsRoot,"src","createDomql.js");if(c&&S(c))t=c;else throw new Error(`brender: cannot load ${Me} (${f.message}). Server rendering needs smbls installed in this project, at a release that exports smbls/ssr`+(e.smblsRoot?` (found smbls at ${e.smblsRoot}).`:" (no smbls package found)."))}const o=await import("esbuild"),n=tt(rt(),`br_createDomql_${ct(6).toString("hex")}.mjs`),s=st,r=e.isMonorepo?await import(it(d(e.monorepoRoot,"scripts","vite-workspace-source.mjs")).href):null,i=r?new Set(r.workspacePackageRoots().map(f=>r.workspacePackageAt(f).name)):null,u=/^(?:smbls(?:\/.*)?|domql|css-in-props(?:\/.*)?|@symbo\.ls\/[^/]+)$/,a={name:"workspace-resolve",setup(f){r&&(f.onResolve({filter:/^[^./]/},c=>{if(u.test(c.path))return;const l=c.path.split("/"),p=c.path.startsWith("@")?l.slice(0,2).join("/"):l[0];if(!i.has(p))return;const h=r.resolveWorkspaceSource(c.path,c.importer||t);return h?{path:h}:{errors:[{text:`"${c.path}" names no source file in the workspace`}]}}),f.onLoad({filter:/[\\/]dist[\\/]/},c=>r.isWorkspaceDist(c.path)?{errors:[{text:`${c.path} is a BUILD of a workspace package \u2014 the render bundles source`}]}:void 0)),f.onResolve({filter:/^smbls/},c=>{const l=c.path.replace(/^smbls\/?/,""),p=e.isMonorepo?d(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!p)return;if(!l){const k=s(p);return k?{path:k}:void 0}const h=d(p,l);if(S(h))return{path:h};if(S(h+".js"))return{path:h+".js"};const R=d(h,"index.js");if(S(R))return{path:R}}),f.onResolve({filter:/^domql$/},c=>{if(e.isMonorepo){const l=d(e.monorepoRoot,"packages","domql","src","index.js");if(S(l))return{path:l};const p=d(e.monorepoRoot,"packages","domql","index.js");if(S(p))return{path:p}}else try{const l=_require.resolve("domql/package.json"),p=s(j(l));if(p)return{path:p}}catch{}}),f.onResolve({filter:/^@symbo\.ls\//},c=>{const l=c.path.replace("@symbo.ls/","");if(l==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const h of["packages","plugins"]){const R=d(e.monorepoRoot,h,l,"src","index.js");if(S(R))return{path:R};const k=d(e.monorepoRoot,h,l,"index.js");if(S(k))return{path:k}}const p=d(e.monorepoRoot,"packages","default-config","blank","index.js");if(l==="default-config"&&S(p))return{path:p}}else{const p=be(e,l,"src","index.js");if(p&&S(p))return{path:p};const h=be(e,l,"index.js");if(h&&S(h))return{path:h};if(l==="default-config"){const R=be(e,"default-config","blank","index.js");if(R&&S(R))return{path:R}}}}),f.onResolve({filter:/^@domql\//},c=>{const l=c.path.replace("@symbo.ls/","");if(e.isMonorepo){const p=d(e.monorepoRoot,"packages","domql","packages",l,"src","index.js");if(S(p))return{path:p};const h=d(e.monorepoRoot,"packages","domql","packages",l,"index.js");if(S(h))return{path:h}}else{const p=Ce(e,l,"src","index.js");if(p&&S(p))return{path:p};const h=Ce(e,l,"index.js");if(h&&S(h))return{path:h}}}),f.onResolve({filter:/^css-in-props/},c=>{let l;if(e.isMonorepo)l=d(e.monorepoRoot,"packages","css-in-props");else{const R=H(e,"css-in-props/package.json");R&&(l=j(R))}if(!l)return;const p=c.path.replace(/^css-in-props\/?/,"");if(p){const R=d(l,p),k=d(R,"index.js");if(S(k))return{path:k};if(S(R+".js"))return{path:R+".js"};if(S(R))return{path:R}}const h=s(l);if(h)return{path:h}}),f.onResolve({filter:/^@emotion\//},c=>{let l;if(e.isMonorepo)l=d(e.monorepoRoot,"node_modules",c.path);else{const p=H(e,`${c.path}/package.json`);if(!p)return;l=j(p)}if(S(l)){const p=d(l,"package.json");if(S(p))try{const h=JSON.parse(Y(p,"utf8")),R=h.module||h.main||"dist/emotion-css.esm.js";return{path:d(l,R)}}catch{}return{path:l}}}),f.onResolve({filter:/\.json$/},c=>{if(c.resolveDir){const l=d(c.resolveDir,c.path);if(S(l))return{path:l}}}),f.onLoad({filter:/smbls\/.*options\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("options.js"))return;let l=Y(c.path,"utf8");return l=l.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),l=l.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:l,loader:"js"}}),f.onLoad({filter:/smbls\/.*init\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("init.js"))return;let l=Y(c.path,"utf8");return l=l.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:l,loader:"js"}}),f.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"})),f.onLoad({filter:/smbls\/src\/router\.js$/},async c=>{let l=Y(c.path,"utf8");return l=l.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:l,loader:"js"}}),f.onLoad({filter:/fetchOnCreate\.js$/},async c=>{if(!c.path.includes("smbls/"))return;let l=Y(c.path,"utf8");return l=l.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:l,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:n,write:!0,logLevel:"warning",plugins:[a],nodePaths:e.isMonorepo?[d(e.monorepoRoot,"node_modules")]:[...e.smblsRoot?[d(e.smblsRoot,"node_modules")]:[],...e.projectRoot?[d(e.projectRoot,"node_modules")]:[],...e.smblsRoot?[d(e.smblsRoot,"..","..","node_modules")]:[]].filter(f=>S(f)),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 g=await import(`file://${n}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",n);else try{ot(n)}catch{}return g},qt={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:e=>e.href,target:e=>e.target,rel:e=>e.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:e=>{let t=e.src;return typeof t=="string"&&t.includes("{{")&&(t=e.call("replaceLiteralsWithObjectFields",t,e.state)),t},alt:e=>e.alt,loading:e=>e.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"}},Pt=(e,t)=>{const o={};return qe(e,(n,s)=>{if(!s.__brKey)return;const r=t(n);o[r===""?"__root":r]=s.__brKey}),o},qe=(e,t)=>{const o=n=>{const s=n&&n.__ref;if(s&&(t(n,s),s.__children))for(const r of s.__children)o(n[r])};o(e)},It=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let z=0;const Pe=Symbol.for("brender.fetchTracked"),Se=()=>z,Ft=256*1024,Gt=1024*1024,Bt=new Set(["accept-language","accept"]),Ie={renders:0,record:null},Kt=50,Re={renders:0,record:null},Fe=(e,t)=>{e.renders++,e.renders===1?e.record=t():e.record&&(e.record.tainted=!0);const o=e.record;return{record:o,close:()=>{e.renders--,e.record===o&&(e.record=null)}}},we=e=>e.record&&!e.record.tainted?e.record:null,Nt=e=>{try{const t=new URL(e);return t.origin+t.pathname}catch{return String(e).split("?")[0]}},ke=(e,t,o)=>{!e||e.tainted||e.failures.length>=Kt||e.failures.push({url:Nt(t),reason:o})},Ge=e=>e&&typeof e=="object"&&typeof e.url=="string"?e.url:String(e),Ht=e=>{const[t,o]=e,n=t&&typeof t=="object"&&typeof t.url=="string",s=Ge(t),r=String(o&&o.method||n&&t.method||"GET").toUpperCase(),i={},u=a=>{if(!a)return;const g=!Array.isArray(a)&&typeof a.entries!="function";for(const[f,c]of ht(a))g&&c==null||(i[String(f).toLowerCase()]=String(c))};return n&&u(t.headers),o&&u(o.headers),{url:s,method:r,headers:i}},zt=(e,t,o,n)=>{if(!o||!o.ok||typeof o.clone!="function")return;const s=o.headers&&o.headers.get&&o.headers.get("content-type")||"";if(!/json|^text\//i.test(s))return;let r;try{r=o.clone()}catch{return}n(r.text().then(i=>{e.tainted||i.length>Ft||e.bytes+i.length>Gt||(e.bytes+=i.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:s,body:i}))},()=>{}))},Wt=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[Pe])return;const t=function(...o){z++;let n=!1;const s=()=>{n||(n=!0,z--)},r=c=>{z++,c.then(()=>{z--},()=>{z--})},i=we(Ie),u=we(Re);let a=null;if(i)try{a=Ht(o),(a.method!=="GET"||!/^https?:/i.test(a.url)||Object.keys(a.headers).some(c=>!Bt.has(c)))&&(a=null)}catch{a=null}const g=()=>Ge(o[0]);let f;try{f=e.apply(this,o)}catch(c){throw ke(u,g(),c&&c.message||"failed"),s(),c}return f&&typeof f.then=="function"?f.then(c=>{a&&zt(i,a,c,r),u&&c&&c.ok===!1&&ke(u,g(),"HTTP "+c.status),s()},c=>{ke(u,g(),c&&c.message||"network error"),s()}):s(),f};t[Pe]=!0,globalThis.fetch=t},on=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const n=St(e);return o?`<script>window.__BR_REGISTRY__=${n};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
2
- `+gt(t):""):`<script>window.__BR_REGISTRY__=${n}<\/script>`},Ut=e=>{const t=globalThis.__SMBLS_PKGS__,o=new Set(t&&typeof t=="object"?Object.getOwnPropertyNames(t):[]);return()=>{const n=globalThis.__SMBLS_PKGS__;if(!n||typeof n!="object")return;let s;try{s=Rt(e())}catch{return}for(const[r]of s)!o.has(r)&&Object.prototype.hasOwnProperty.call(n,r)&&Reflect.deleteProperty(n,r)}},Vt=3e4,Jt=2147483647;let Be=Promise.resolve();const Ke=()=>{},Yt=e=>{const t=Be.then(e);return Be=t.then(Ke,Ke),t},Xt=e=>{if(e===void 0)return Vt;if(e===0||e===!1||e===1/0)return 0;if(typeof e!="number"||!(e>0))throw new TypeError(`brender: options.timeout is a number of milliseconds, or 0 / false for no limit \u2014 not ${JSON.stringify(e)}`);return Math.min(e,Jt)},Qt=(e,t)=>{const o=e.route||"/",n=e.pathname||o,s=n===o?o:`${n} (route ${o})`,r=new Error(`brender: the render of ${s} did not finish within ${t} ms and was abandoned, so the renders after it can run (options.timeout)`);return r.code="BRENDER_RENDER_TIMEOUT",r.route=o,r.pathname=n,r.timeout=t,r},Zt=e=>{e.closed=!0;for(const t of e.undo.splice(0))t()},eo=e=>{let t=!1;return()=>{t||(t=!0,e())}},Ne=(e,t={})=>{let o;try{o=Xt(t.timeout)}catch(n){return Promise.reject(n)}return Yt(()=>to(e,t,o))},to=async(e,t,o)=>{await Oe();const n={closed:!1,undo:[]},s=oo(e,t,n);if(!o)return s;let r;const i=new Promise((u,a)=>{r=setTimeout(()=>{Zt(n),a(Qt(t,o))},o)});try{return await Promise.race([s,i])}finally{clearTimeout(r)}},oo=async(e,t,o)=>{const{route:n="/",pathname:s,state:r,context:i,prefetch:u=!1,lazyGroups:a}=t,g=s||n;Wt();const f=Fe(Re,()=>({failures:[],labelKeys:new Set,tainted:!1}));try{return await no(At(e),{route:n,locationPath:g,stateOverrides:r,contextOverrides:i,prefetch:u,lazyGroups:a},f.record,o)}finally{f.close()}},no=async(e,{route:t,locationPath:o,stateOverrides:n,contextOverrides:s,prefetch:r,lazyGroups:i},u,a)=>{const g=()=>{if(a.closed)throw new Error("brender: this render was abandoned at its timeout")};let f;if(r){try{f=await dt(e)}catch(k){a.closed||console.warn("[brender] SSR translation fetch failed:",k.message)}g()}const{window:c,document:l}=je(),p=l.body;c.location.pathname=o;let h=null;const R=[fe("document",l),fe("location",c.location),fe("localStorage",c.localStorage),fe("sessionStorage",c.sessionStorage),Ut(()=>h&&h.sharedLibraries)].map(eo);a.undo.push(...R);try{const{createDomqlElement:k,PRERENDER_REGISTRY_FORMATS:X}=await Oe();g();const me=L(e.app||{}),_={...e.config||{}};e.polyglot&&!_.polyglot&&(_.polyglot=e.polyglot),e.fetch&&!_.fetch&&(_.fetch=e.fetch),e.router&&!_.router&&(_.router=e.router);for(const m of fo)e[m]!=null&&_[m]==null&&(_[m]=e[m]);const E=_.polyglot?{..._.polyglot,prefetch:!1}:void 0,Q=kt(o,E);Q&&c.localStorage.setItem(wt(E),Q),f&&E&&(E.translations={...E.translations||{},...f});const Z=L(e.state||{});$t();const P={};for(const m in e){if(It.has(m))continue;const b=e[m];P[m]=b&&typeof b=="object"?L(b):b}const x={...P,state:Z,...n?{state:{...Z,...n}}:{},dependencies:L(e.dependencies||{}),components:L(e.components||{}),snippets:L(e.snippets||{}),pages:L(e.pages||{}),functions:{...e.functions||{},polyglot:Dt,getActiveLang:De,getLang:De},methods:e.methods||{},designSystem:L(e.designSystem||{}),files:e.files||{},sharedLibraries:e.sharedLibraries||[],..._,...E?{polyglot:E}:{},document:l,window:c,parent:{node:p},initOptions:{},domqlOptions:{sourcemap:!1},firstRender:!1,sync:!1,inspect:!1,notifications:!1,afterFirstView:null,isolateDesignSystem:!0,isolateFetchCache:!0,captureDesignSystem:!0,...so(i),...s||{},ssr:!0};h=x;const ee=await Tt();g(),ee&&(x.plugins=x.plugins||[],x.plugins.some(m=>m.name==="funcql")||x.plugins.push(ee)),Te();const B=Fe(Ie,()=>({entries:[],bytes:0,tainted:!1})),y=B.record;let w;try{if(w=await k(me,x),g(),x.lazyFirstView){const D=(w&&w.context||x).__firstNavigation;if(D&&typeof D.then=="function"){try{await D}catch{}g()}}const m=Date.now(),b=r?2e3:50,T=D=>new Promise(re=>setTimeout(re,D));for(await T(Math.min(50,b));r&&!a.closed&&Se()>0&&Date.now()-m<b;)await T(10),Se()===0&&await T(Math.max(0,Math.min(50,b-(Date.now()-m))));if(g(),r&&await ro(w,E)){g();const D=Date.now();for(await T(Math.min(50,b));!a.closed&&Se()>0&&Date.now()-D<b;)await T(10);g()}}finally{B.close()}const W=y&&!y.tainted&&!(_.fetch&&_.fetch.seed===!1)?y.entries.slice():[];ve(p);const $=Le(w),{elementPath:K}=await import("@symbo.ls/element");g();const U=Pt(w,K),te=W.length?Lt(w&&w.context||x,K):{},V=w?.context?.routerOptions?.contentElementKey||"content",I=w&&w[V],C=I&&typeof I=="object"&&I.__ref?I:void 0,Ee=he(e,t,w,w?.state,C),M=[],J=l.head||l.querySelector("head");if(J)for(const m of J.querySelectorAll("style")){if(m.sheet&&m.sheet.cssRules)for(const b of m.sheet.cssRules)b.cssText&&M.push(b);if(!M.length){const b=m.textContent||"";b&&M.push({cssText:b})}}const oe=M.map(m=>m.cssText),{globalCSS:ne,classRules:de}=yo(M);let v=We(p.innerHTML);const F=w?.state?.root,G=le(F,E),O=co(f,F);O&&(v=ze(v,He(O,G,E)));const N=u&&!u.tainted?{failedRequests:u.failures.slice(),rawLabelKeys:ao(u.labelKeys,v,G,E,F)}:null,A=(w&&w.context||x).__lazyFirstViews,se=A&&typeof A.forEach=="function"?[...A]:[];return{html:v,metadata:Ee,registry:$,brRegistry:U,element:w,emotionCSS:oe,lazyGroups:se,globalCSS:ne,classRules:de,fetchSeed:W,fetchRuns:te,document:l,window:c,ssrTranslations:O||void 0,activeLang:G,diagnostics:N,preparedDesignSystem:x.preparedDesignSystem||null,registryFormats:Array.isArray(X)?X.slice():["paths"]}}finally{for(const k of R)k()}},so=e=>{if(e==="load"||e===!0)return{lazyFirstView:!0};if(Array.isArray(e)){const t=e.filter(o=>typeof o=="string"&&o);return t.length?{lazyFirstView:t}:{}}return{}},fe=(e,t)=>{const o=Object.getOwnPropertyDescriptor(globalThis,e);return o&&!o.configurable?!o.writable&&!o.set?()=>{}:(globalThis[e]=t,()=>{}):(Object.defineProperty(globalThis,e,{value:t,writable:!0,configurable:!0,enumerable:!0}),()=>{o?Object.defineProperty(globalThis,e,o):delete globalThis[e]})},ro=async(e,t)=>{if(!t||!t.fetch||!e||typeof e.call!="function")return!1;const o=e.state&&e.state.root;if(!o)return!1;const n=le(o,t),s=o.translations&&o.translations[n];if(s&&typeof s=="object"&&Object.keys(s).length||t.translations&&t.translations[n])return!1;try{await e.call("loadTranslations",n,{inFlight:!0})}catch{}return!0},xe=/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,_e=e=>e&&typeof e.parse=="function"?e.parse():e,co=(e,t)=>{const o=_e(t?.translations),n={};for(const s of[e,o])if(!(!s||typeof s!="object"))for(const r in s){const i=_e(s[r]);i&&typeof i=="object"&&(n[r]={...n[r]||{},...i})}return Object.keys(n).length?n:null},He=(e,t,o)=>e[t]||e[ye(void 0,o)]||Object.values(e)[0]||{},ze=(e,t)=>e.replace(xe,(o,n)=>ie(t,n.trim())??o),io=/<script\b[^>]*\btype\s*=\s*["']?application\/json["']?[^>]*>[\s\S]*?<\/script\s*>/gi,lo=(e,t)=>new RegExp(`(?:^|[^\\w.-])${bt(t)}(?![\\w-]|\\.\\w)`).test(e),ao=(e,t,o,n,s)=>{const r=new Set,i=t.replace(io,"");for(const u of e)/\s/.test(u)||Ae(u,o,n,s)===void 0&&lo(i,u)&&r.add(u);for(const u of i.matchAll(xe))r.add(u[1].trim());return[...r]},nn=async(e,t={})=>{const{context:o={}}=t,{window:n,document:s}=je(),r=s.body,{create:i}=await import("@symbo.ls/element"),u=await import("@symbo.ls/utils"),a={...qt,...o.components||{}},g={...u,...o.utils||{},...o.functions||{}};Te();let f;try{f=i(e,{node:r},"root",{context:{document:s,window:n,...o,components:a,utils:g,ssr:!0}})}catch{}ve(r);const c=f?Le(f):{};return{html:We(r.innerHTML),registry:c,element:f}},We=e=>e.replace(/(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,(t,o,n,s)=>{if(n.includes("&lt;")){const r=n.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&quot;/g,'"').replace(/&#39;/g,"'");return o+r+s}return t}),fo=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],po=new Set(["auto","system"]),Ue=e=>{if(!e||typeof e!="object")return null;const t=e.config&&typeof e.config=="object"?e.config:{};if((t.themeRoot!=null?t.themeRoot:e.themeRoot)!=null)return null;const n=t.globalTheme!=null?t.globalTheme:e.globalTheme;if(typeof n!="string")return null;const s=n.trim();return!s||po.has(s)?null:s},uo=e=>String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),mo=/\.[A-Za-z_\\-]/,go=e=>{if(typeof e!="string"||!e)return!1;const t=e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]");return!mo.test(t)},ho=/^\s*(:root|\[data-theme|\[data-skin)/,Ve=e=>{const t=e&&e.cssText;if(typeof t!="string")return null;if(/^@(-webkit-)?keyframes\b/.test(t))return"keyframes";if(t.startsWith("@font-face"))return null;if(typeof e.selectorText=="string")return go(e.selectorText)?ho.test(e.selectorText)?"root":"reset":null;const o=e.cssRules&&Array.from(e.cssRules);if(o&&o.length&&/^@(media|supports|container)\b/.test(t)){const n=new Set(o.map(Ve));return n.has(null)||n.size!==1?n.has(null)?null:"reset":[...n][0]}return null},Je=e=>typeof e=="string"&&/^\s*@font-face\b/i.test(e),yo=e=>{const t={root:[],reset:[],keyframes:[]},o=[];for(const n of e||[]){const s=Ve(n);s?t[s].push(n.cssText):n&&n.cssText&&o.push(n.cssText)}return{globalCSS:{rootRule:t.root.join(`
1
+ import{resolve as d,join as tt,dirname as j}from"path";import{existsSync as S,unlinkSync as ot,readFileSync as J,realpathSync as nt}from"fs";import{resolvePackageEntry as st}from"./packageEntry.js";import{tmpdir as rt}from"os";import{randomBytes as ct}from"crypto";import{createRequire as ge}from"module";import{pathToFileURL as it}from"url";import{createEnv as je}from"./env.js";import{resetKeys as Te,assignKeys as ve,mapKeysToElements as Le}from"./keys.js";import{extractMetadata as he,generateHeadHtml as lt}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as at}from"./shell.js";import{trimSpriteToPage as ft,classRulesForPage as pt,markupClasses as ut,trimVariablesToPage as mt}from"./pageWeight.js";import{facesSheetTag as dt}from"./faces.js";import{fetchSSRTranslations as gt}from"./prefetch.js";import{createEarlySeedScript as ht}from"@symbo.ls/fetch";import{headerEntries as yt}from"@symbo.ls/fetch/rest";import{brenderStampMeta as bt,brenderLazyMeta as Ae,escapeRegExp as St,jsonForScript as Rt,libraryPackageSpecs as wt,polyglotFallbackLang as ye,polyglotLangStorageKey as kt,polyglotAddressLang as xt,polyglotStartupScript as _t}from"@symbo.ls/utils";import{brenderRegistryBlock as Et,brenderRegistryTreeBlock as jt}from"@symbo.ls/utils/server";import*as Tt from"@symbo.ls/utils/server";let ce=null;const vt=async()=>{if(ce)return ce;try{return ce=(await import("@symbo.ls/funcql")).funcqlPlugin,ce}catch{return null}};import"linkedom";import{createEarlySeedBlock as Lt,fetchRunsOf as At}from"@symbo.ls/fetch";import{reset as $t}from"@symbo.ls/css";const ie=(e,t)=>{if(!e||!t)return;if(e[t]!==void 0)return e[t];const o=t.split(".");let n=e;for(const s of o){if(n==null||typeof n!="object")return;n=n[s]}return n},le=(e,t)=>ye(e?.lang,t),Dt=e=>{const t=Tt.revivePolyglotDefaultLang;if(typeof t!="function"||!e||typeof e!="object")return e;const o=e.polyglot?t(e.polyglot):e.polyglot,n=e.config&&e.config.polyglot,s=n&&t(n);if(o===e.polyglot&&s===n)return e;const r={...e};return o!==e.polyglot&&(r.polyglot=o),s!==n&&(r.config={...e.config,polyglot:s}),r},$e=(e,t,o,n)=>{if(o?.translations){const r=o.translations[t];if(r){const i=ie(r,e);if(i!==void 0)return i}}if(n?.translations){const r=n.translations[t];if(r){const i=ie(r,e);if(i!==void 0)return i}}const s=ye(void 0,o);if(s!==t&&o?.translations){const r=o.translations[s];if(r){const i=ie(r,e);if(i!==void 0)return i}}},Ct=function(e,t){if(!e)return"";const o=this?.context,n=o?.polyglot,s=this?.state?.root||o?.state?.root,r=$e(e,t||le(s,n),n,s);if(r!==void 0)return r;const i=we(Re);return n&&i&&i.labelKeys.add(e),e},De=function(){return le(this?.state?.root,this?.context?.polyglot)},L=(e,t=new WeakMap)=>{if(e===null||typeof e!="object")return e;if(t.has(e))return t.get(e);if(Array.isArray(e)){const n=[];t.set(e,n);for(const s of e)n.push(typeof s=="object"&&s!==null?L(s,t):s);return n}const o={};t.set(e,o);for(const n of Object.keys(e)){const s=e[n];o[n]=typeof s=="object"&&s!==null?L(s,t):s}return o};let q=null;try{import.meta.url&&(q=ge(import.meta.url))}catch{}const Mt=()=>{if(!import.meta.url||!q)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:a=>a};const e=nt(new URL(".",import.meta.url).pathname),t=d(e,"../..");if(S(d(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let n;try{const a=q.resolve("smbls/package.json");n=j(a)}catch{let a=e;for(;a!==j(a);){const g=d(a,"node_modules","smbls");if(S(d(g,"package.json"))){n=g;break}a=j(a)}}let s=q;if(n)try{s=ge(d(n,"package.json"))}catch{}let r,i=process.cwd();for(;i!==j(i);){if(S(d(i,"package.json"))){r=i;break}i=j(i)}let u=s;if(r)try{u=ge(d(r,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:n,brenderDir:e,projectRoot:r,_smblsRequire:s,_projectRequire:u}},H=(e,t)=>{const o=e.isMonorepo?[q]:[e._smblsRequire,e._projectRequire,q].filter(Boolean);for(const n of o)try{return n.resolve(t)}catch{}return null},on=(e,t,...o)=>{if(e.isMonorepo)return d(e.monorepoRoot,"packages",t,...o);const n=H(e,`${t}/package.json`);return n?d(j(n),...o):null},nn=(e,t,...o)=>{if(e.isMonorepo)return d(e.monorepoRoot,"plugins",t,...o);const n=H(e,`@symbo.ls/${t}/package.json`);return n?d(j(n),...o):null},be=(e,t,...o)=>{if(e.isMonorepo){for(const s of["packages","plugins"]){const r=d(e.monorepoRoot,s,t,...o);if(S(r))return r}return null}const n=H(e,`@symbo.ls/${t}/package.json`);return n?d(j(n),...o):null},Ce=(e,t,...o)=>{if(e.isMonorepo)return d(e.monorepoRoot,"packages","domql","packages",t,...o);const n=H(e,`@symbo.ls/${t}/package.json`);return n?d(j(n),...o):null};let ae=null;const Me="smbls/ssr",Ot=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},Oe=()=>(ae||(ae=qt().catch(e=>{throw ae=null,e})),ae),qt=async()=>{const e=Mt();let t;if(q&&e.isMonorepo)t=d(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let f;try{return await Ot()}catch(l){f=l}if(!q)throw new Error(`brender: ${Me} is not available in this bundled runtime (${f.message}). Bundle smbls \u2265 the release that adds the smbls/ssr export alongside @symbo.ls/brender.`);const c=e.smblsRoot&&d(e.smblsRoot,"src","createDomql.js");if(c&&S(c))t=c;else throw new Error(`brender: cannot load ${Me} (${f.message}). Server rendering needs smbls installed in this project, at a release that exports smbls/ssr`+(e.smblsRoot?` (found smbls at ${e.smblsRoot}).`:" (no smbls package found)."))}const o=await import("esbuild"),n=tt(rt(),`br_createDomql_${ct(6).toString("hex")}.mjs`),s=st,r=e.isMonorepo?await import(it(d(e.monorepoRoot,"scripts","vite-workspace-source.mjs")).href):null,i=r?new Set(r.workspacePackageRoots().map(f=>r.workspacePackageAt(f).name)):null,u=/^(?:smbls(?:\/.*)?|domql|css-in-props(?:\/.*)?|@symbo\.ls\/[^/]+)$/,a={name:"workspace-resolve",setup(f){r&&(f.onResolve({filter:/^[^./]/},c=>{if(u.test(c.path))return;const l=c.path.split("/"),p=c.path.startsWith("@")?l.slice(0,2).join("/"):l[0];if(!i.has(p))return;const h=r.resolveWorkspaceSource(c.path,c.importer||t);return h?{path:h}:{errors:[{text:`"${c.path}" names no source file in the workspace`}]}}),f.onLoad({filter:/[\\/]dist[\\/]/},c=>r.isWorkspaceDist(c.path)?{errors:[{text:`${c.path} is a BUILD of a workspace package \u2014 the render bundles source`}]}:void 0)),f.onResolve({filter:/^smbls/},c=>{const l=c.path.replace(/^smbls\/?/,""),p=e.isMonorepo?d(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!p)return;if(!l){const k=s(p);return k?{path:k}:void 0}const h=d(p,l);if(S(h))return{path:h};if(S(h+".js"))return{path:h+".js"};const R=d(h,"index.js");if(S(R))return{path:R}}),f.onResolve({filter:/^domql$/},c=>{if(e.isMonorepo){const l=d(e.monorepoRoot,"packages","domql","src","index.js");if(S(l))return{path:l};const p=d(e.monorepoRoot,"packages","domql","index.js");if(S(p))return{path:p}}else try{const l=_require.resolve("domql/package.json"),p=s(j(l));if(p)return{path:p}}catch{}}),f.onResolve({filter:/^@symbo\.ls\//},c=>{const l=c.path.replace("@symbo.ls/","");if(l==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const h of["packages","plugins"]){const R=d(e.monorepoRoot,h,l,"src","index.js");if(S(R))return{path:R};const k=d(e.monorepoRoot,h,l,"index.js");if(S(k))return{path:k}}const p=d(e.monorepoRoot,"packages","default-config","blank","index.js");if(l==="default-config"&&S(p))return{path:p}}else{const p=be(e,l,"src","index.js");if(p&&S(p))return{path:p};const h=be(e,l,"index.js");if(h&&S(h))return{path:h};if(l==="default-config"){const R=be(e,"default-config","blank","index.js");if(R&&S(R))return{path:R}}}}),f.onResolve({filter:/^@domql\//},c=>{const l=c.path.replace("@symbo.ls/","");if(e.isMonorepo){const p=d(e.monorepoRoot,"packages","domql","packages",l,"src","index.js");if(S(p))return{path:p};const h=d(e.monorepoRoot,"packages","domql","packages",l,"index.js");if(S(h))return{path:h}}else{const p=Ce(e,l,"src","index.js");if(p&&S(p))return{path:p};const h=Ce(e,l,"index.js");if(h&&S(h))return{path:h}}}),f.onResolve({filter:/^css-in-props/},c=>{let l;if(e.isMonorepo)l=d(e.monorepoRoot,"packages","css-in-props");else{const R=H(e,"css-in-props/package.json");R&&(l=j(R))}if(!l)return;const p=c.path.replace(/^css-in-props\/?/,"");if(p){const R=d(l,p),k=d(R,"index.js");if(S(k))return{path:k};if(S(R+".js"))return{path:R+".js"};if(S(R))return{path:R}}const h=s(l);if(h)return{path:h}}),f.onResolve({filter:/^@emotion\//},c=>{let l;if(e.isMonorepo)l=d(e.monorepoRoot,"node_modules",c.path);else{const p=H(e,`${c.path}/package.json`);if(!p)return;l=j(p)}if(S(l)){const p=d(l,"package.json");if(S(p))try{const h=JSON.parse(J(p,"utf8")),R=h.module||h.main||"dist/emotion-css.esm.js";return{path:d(l,R)}}catch{}return{path:l}}}),f.onResolve({filter:/\.json$/},c=>{if(c.resolveDir){const l=d(c.resolveDir,c.path);if(S(l))return{path:l}}}),f.onLoad({filter:/smbls\/.*options\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("options.js"))return;let l=J(c.path,"utf8");return l=l.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),l=l.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:l,loader:"js"}}),f.onLoad({filter:/smbls\/.*init\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("init.js"))return;let l=J(c.path,"utf8");return l=l.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:l,loader:"js"}}),f.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"})),f.onLoad({filter:/smbls\/src\/router\.js$/},async c=>{let l=J(c.path,"utf8");return l=l.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:l,loader:"js"}}),f.onLoad({filter:/fetchOnCreate\.js$/},async c=>{if(!c.path.includes("smbls/"))return;let l=J(c.path,"utf8");return l=l.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:l,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:n,write:!0,logLevel:"warning",plugins:[a],nodePaths:e.isMonorepo?[d(e.monorepoRoot,"node_modules")]:[...e.smblsRoot?[d(e.smblsRoot,"node_modules")]:[],...e.projectRoot?[d(e.projectRoot,"node_modules")]:[],...e.smblsRoot?[d(e.smblsRoot,"..","..","node_modules")]:[]].filter(f=>S(f)),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 g=await import(`file://${n}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",n);else try{ot(n)}catch{}return g},Pt={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:e=>e.href,target:e=>e.target,rel:e=>e.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:e=>{let t=e.src;return typeof t=="string"&&t.includes("{{")&&(t=e.call("replaceLiteralsWithObjectFields",t,e.state)),t},alt:e=>e.alt,loading:e=>e.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"}},It=(e,t)=>{const o={};return qe(e,(n,s)=>{if(!s.__brKey)return;const r=t(n);o[r===""?"__root":r]=s.__brKey}),o},qe=(e,t)=>{const o=n=>{const s=n&&n.__ref;if(s&&(t(n,s),s.__children))for(const r of s.__children)o(n[r])};o(e)},Ft=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let z=0;const Pe=Symbol.for("brender.fetchTracked"),Se=()=>z,Gt=256*1024,Bt=1024*1024,Kt=new Set(["accept-language","accept"]),Ie={renders:0,record:null},Nt=50,Re={renders:0,record:null},Fe=(e,t)=>{e.renders++,e.renders===1?e.record=t():e.record&&(e.record.tainted=!0);const o=e.record;return{record:o,close:()=>{e.renders--,e.record===o&&(e.record=null)}}},we=e=>e.record&&!e.record.tainted?e.record:null,Ht=e=>{try{const t=new URL(e);return t.origin+t.pathname}catch{return String(e).split("?")[0]}},ke=(e,t,o)=>{!e||e.tainted||e.failures.length>=Nt||e.failures.push({url:Ht(t),reason:o})},Ge=e=>e&&typeof e=="object"&&typeof e.url=="string"?e.url:String(e),zt=e=>{const[t,o]=e,n=t&&typeof t=="object"&&typeof t.url=="string",s=Ge(t),r=String(o&&o.method||n&&t.method||"GET").toUpperCase(),i={},u=a=>{if(!a)return;const g=!Array.isArray(a)&&typeof a.entries!="function";for(const[f,c]of yt(a))g&&c==null||(i[String(f).toLowerCase()]=String(c))};return n&&u(t.headers),o&&u(o.headers),{url:s,method:r,headers:i}},Wt=(e,t,o,n)=>{if(!o||!o.ok||typeof o.clone!="function")return;const s=o.headers&&o.headers.get&&o.headers.get("content-type")||"";if(!/json|^text\//i.test(s))return;let r;try{r=o.clone()}catch{return}n(r.text().then(i=>{e.tainted||i.length>Gt||e.bytes+i.length>Bt||(e.bytes+=i.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:s,body:i}))},()=>{}))},Ut=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[Pe])return;const t=function(...o){z++;let n=!1;const s=()=>{n||(n=!0,z--)},r=c=>{z++,c.then(()=>{z--},()=>{z--})},i=we(Ie),u=we(Re);let a=null;if(i)try{a=zt(o),(a.method!=="GET"||!/^https?:/i.test(a.url)||Object.keys(a.headers).some(c=>!Kt.has(c)))&&(a=null)}catch{a=null}const g=()=>Ge(o[0]);let f;try{f=e.apply(this,o)}catch(c){throw ke(u,g(),c&&c.message||"failed"),s(),c}return f&&typeof f.then=="function"?f.then(c=>{a&&Wt(i,a,c,r),u&&c&&c.ok===!1&&ke(u,g(),"HTTP "+c.status),s()},c=>{ke(u,g(),c&&c.message||"network error"),s()}):s(),f};t[Pe]=!0,globalThis.fetch=t},sn=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const n=Rt(e);return o?`<script>window.__BR_REGISTRY__=${n};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
2
+ `+ht(t):""):`<script>window.__BR_REGISTRY__=${n}<\/script>`},Vt=e=>{const t=globalThis.__SMBLS_PKGS__,o=new Set(t&&typeof t=="object"?Object.getOwnPropertyNames(t):[]);return()=>{const n=globalThis.__SMBLS_PKGS__;if(!n||typeof n!="object")return;let s;try{s=wt(e())}catch{return}for(const[r]of s)!o.has(r)&&Object.prototype.hasOwnProperty.call(n,r)&&Reflect.deleteProperty(n,r)}},Jt=3e4,Yt=2147483647;let Be=Promise.resolve();const Ke=()=>{},Xt=e=>{const t=Be.then(e);return Be=t.then(Ke,Ke),t},Qt=e=>{if(e===void 0)return Jt;if(e===0||e===!1||e===1/0)return 0;if(typeof e!="number"||!(e>0))throw new TypeError(`brender: options.timeout is a number of milliseconds, or 0 / false for no limit \u2014 not ${JSON.stringify(e)}`);return Math.min(e,Yt)},Zt=(e,t)=>{const o=e.route||"/",n=e.pathname||o,s=n===o?o:`${n} (route ${o})`,r=new Error(`brender: the render of ${s} did not finish within ${t} ms and was abandoned, so the renders after it can run (options.timeout)`);return r.code="BRENDER_RENDER_TIMEOUT",r.route=o,r.pathname=n,r.timeout=t,r},eo=e=>{e.closed=!0;for(const t of e.undo.splice(0))t()},to=e=>{let t=!1;return()=>{t||(t=!0,e())}},Ne=(e,t={})=>{let o;try{o=Qt(t.timeout)}catch(n){return Promise.reject(n)}return Xt(()=>oo(e,t,o))},oo=async(e,t,o)=>{await Oe();const n={closed:!1,undo:[]},s=no(e,t,n);if(!o)return s;let r;const i=new Promise((u,a)=>{r=setTimeout(()=>{eo(n),a(Zt(t,o))},o)});try{return await Promise.race([s,i])}finally{clearTimeout(r)}},no=async(e,t,o)=>{const{route:n="/",pathname:s,state:r,context:i,prefetch:u=!1,lazyGroups:a}=t,g=s||n;Ut();const f=Fe(Re,()=>({failures:[],labelKeys:new Set,tainted:!1}));try{return await so(Dt(e),{route:n,locationPath:g,stateOverrides:r,contextOverrides:i,prefetch:u,lazyGroups:a},f.record,o)}finally{f.close()}},so=async(e,{route:t,locationPath:o,stateOverrides:n,contextOverrides:s,prefetch:r,lazyGroups:i},u,a)=>{const g=()=>{if(a.closed)throw new Error("brender: this render was abandoned at its timeout")};let f;if(r){try{f=await gt(e)}catch(k){a.closed||console.warn("[brender] SSR translation fetch failed:",k.message)}g()}const{window:c,document:l}=je(),p=l.body;c.location.pathname=o;let h=null;const R=[fe("document",l),fe("location",c.location),fe("localStorage",c.localStorage),fe("sessionStorage",c.sessionStorage),Vt(()=>h&&h.sharedLibraries)].map(to);a.undo.push(...R);try{const{createDomqlElement:k,PRERENDER_REGISTRY_FORMATS:Y}=await Oe();g();const me=L(e.app||{}),_={...e.config||{}};e.polyglot&&!_.polyglot&&(_.polyglot=e.polyglot),e.fetch&&!_.fetch&&(_.fetch=e.fetch),e.router&&!_.router&&(_.router=e.router);for(const m of po)e[m]!=null&&_[m]==null&&(_[m]=e[m]);const E=_.polyglot?{..._.polyglot,prefetch:!1}:void 0,X=xt(o,E);X&&c.localStorage.setItem(kt(E),X),f&&E&&(E.translations={...E.translations||{},...f});const Q=L(e.state||{});$t();const P={};for(const m in e){if(Ft.has(m))continue;const b=e[m];P[m]=b&&typeof b=="object"?L(b):b}const x={...P,state:Q,...n?{state:{...Q,...n}}:{},dependencies:L(e.dependencies||{}),components:L(e.components||{}),snippets:L(e.snippets||{}),pages:L(e.pages||{}),functions:{...e.functions||{},polyglot:Ct,getActiveLang:De,getLang:De},methods:e.methods||{},designSystem:L(e.designSystem||{}),files:e.files||{},sharedLibraries:e.sharedLibraries||[],..._,...E?{polyglot:E}:{},document:l,window:c,parent:{node:p},initOptions:{},domqlOptions:{sourcemap:!1},firstRender:!1,sync:!1,inspect:!1,notifications:!1,afterFirstView:null,isolateDesignSystem:!0,isolateFetchCache:!0,captureDesignSystem:!0,...ro(i),...s||{},ssr:!0};h=x;const Z=await vt();g(),Z&&(x.plugins=x.plugins||[],x.plugins.some(m=>m.name==="funcql")||x.plugins.push(Z)),Te();const B=Fe(Ie,()=>({entries:[],bytes:0,tainted:!1})),y=B.record;let w;try{if(w=await k(me,x),g(),x.lazyFirstView){const D=(w&&w.context||x).__firstNavigation;if(D&&typeof D.then=="function"){try{await D}catch{}g()}}const m=Date.now(),b=r?2e3:50,T=D=>new Promise(re=>setTimeout(re,D));for(await T(Math.min(50,b));r&&!a.closed&&Se()>0&&Date.now()-m<b;)await T(10),Se()===0&&await T(Math.max(0,Math.min(50,b-(Date.now()-m))));if(g(),r&&await co(w,E)){g();const D=Date.now();for(await T(Math.min(50,b));!a.closed&&Se()>0&&Date.now()-D<b;)await T(10);g()}}finally{B.close()}const W=y&&!y.tainted&&!(_.fetch&&_.fetch.seed===!1)?y.entries.slice():[];ve(p);const A=Le(w),{elementPath:K}=await import("@symbo.ls/element");g();const ee=It(w,K),te=W.length?At(w&&w.context||x,K):{},U=w?.context?.routerOptions?.contentElementKey||"content",I=w&&w[U],C=I&&typeof I=="object"&&I.__ref?I:void 0,Ee=he(e,t,w,w?.state,C),M=[],V=l.head||l.querySelector("head");if(V)for(const m of V.querySelectorAll("style")){if(m.sheet&&m.sheet.cssRules)for(const b of m.sheet.cssRules)b.cssText&&M.push(b);if(!M.length){const b=m.textContent||"";b&&M.push({cssText:b})}}const oe=M.map(m=>m.cssText),{globalCSS:ne,classRules:de}=bo(M);let v=We(p.innerHTML);const F=w?.state?.root,G=le(F,E),O=io(f,F);O&&(v=ze(v,He(O,G,E)));const N=u&&!u.tainted?{failedRequests:u.failures.slice(),rawLabelKeys:fo(u.labelKeys,v,G,E,F)}:null,$=(w&&w.context||x).__lazyFirstViews,se=$&&typeof $.forEach=="function"?[...$]:[];return{html:v,metadata:Ee,registry:A,brRegistry:ee,element:w,emotionCSS:oe,lazyGroups:se,globalCSS:ne,classRules:de,fetchSeed:W,fetchRuns:te,document:l,window:c,ssrTranslations:O||void 0,activeLang:G,diagnostics:N,preparedDesignSystem:x.preparedDesignSystem||null,registryFormats:Array.isArray(Y)?Y.slice():["paths"]}}finally{for(const k of R)k()}},ro=e=>{if(e==="load"||e===!0)return{lazyFirstView:!0};if(Array.isArray(e)){const t=e.filter(o=>typeof o=="string"&&o);return t.length?{lazyFirstView:t}:{}}return{}},fe=(e,t)=>{const o=Object.getOwnPropertyDescriptor(globalThis,e);return o&&!o.configurable?!o.writable&&!o.set?()=>{}:(globalThis[e]=t,()=>{}):(Object.defineProperty(globalThis,e,{value:t,writable:!0,configurable:!0,enumerable:!0}),()=>{o?Object.defineProperty(globalThis,e,o):delete globalThis[e]})},co=async(e,t)=>{if(!t||!t.fetch||!e||typeof e.call!="function")return!1;const o=e.state&&e.state.root;if(!o)return!1;const n=le(o,t),s=o.translations&&o.translations[n];if(s&&typeof s=="object"&&Object.keys(s).length||t.translations&&t.translations[n])return!1;try{await e.call("loadTranslations",n,{inFlight:!0})}catch{}return!0},xe=/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,_e=e=>e&&typeof e.parse=="function"?e.parse():e,io=(e,t)=>{const o=_e(t?.translations),n={};for(const s of[e,o])if(!(!s||typeof s!="object"))for(const r in s){const i=_e(s[r]);i&&typeof i=="object"&&(n[r]={...n[r]||{},...i})}return Object.keys(n).length?n:null},He=(e,t,o)=>e[t]||e[ye(void 0,o)]||Object.values(e)[0]||{},ze=(e,t)=>e.replace(xe,(o,n)=>ie(t,n.trim())??o),lo=/<script\b[^>]*\btype\s*=\s*["']?application\/json["']?[^>]*>[\s\S]*?<\/script\s*>/gi,ao=(e,t)=>new RegExp(`(?:^|[^\\w.-])${St(t)}(?![\\w-]|\\.\\w)`).test(e),fo=(e,t,o,n,s)=>{const r=new Set,i=t.replace(lo,"");for(const u of e)/\s/.test(u)||$e(u,o,n,s)===void 0&&ao(i,u)&&r.add(u);for(const u of i.matchAll(xe))r.add(u[1].trim());return[...r]},rn=async(e,t={})=>{const{context:o={}}=t,{window:n,document:s}=je(),r=s.body,{create:i}=await import("@symbo.ls/element"),u=await import("@symbo.ls/utils"),a={...Pt,...o.components||{}},g={...u,...o.utils||{},...o.functions||{}};Te();let f;try{f=i(e,{node:r},"root",{context:{document:s,window:n,...o,components:a,utils:g,ssr:!0}})}catch{}ve(r);const c=f?Le(f):{};return{html:We(r.innerHTML),registry:c,element:f}},We=e=>e.replace(/(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,(t,o,n,s)=>{if(n.includes("&lt;")){const r=n.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").replace(/&quot;/g,'"').replace(/&#39;/g,"'");return o+r+s}return t}),po=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],uo=new Set(["auto","system"]),Ue=e=>{if(!e||typeof e!="object")return null;const t=e.config&&typeof e.config=="object"?e.config:{};if((t.themeRoot!=null?t.themeRoot:e.themeRoot)!=null)return null;const n=t.globalTheme!=null?t.globalTheme:e.globalTheme;if(typeof n!="string")return null;const s=n.trim();return!s||uo.has(s)?null:s},mo=e=>String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),go=/\.[A-Za-z_\\-]/,ho=e=>{if(typeof e!="string"||!e)return!1;const t=e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]");return!go.test(t)},yo=/^\s*(:root|\[data-theme|\[data-skin)/,Ve=e=>{const t=e&&e.cssText;if(typeof t!="string")return null;if(/^@(-webkit-)?keyframes\b/.test(t))return"keyframes";if(t.startsWith("@font-face"))return null;if(typeof e.selectorText=="string")return ho(e.selectorText)?yo.test(e.selectorText)?"root":"reset":null;const o=e.cssRules&&Array.from(e.cssRules);if(o&&o.length&&/^@(media|supports|container)\b/.test(t)){const n=new Set(o.map(Ve));return n.has(null)||n.size!==1?n.has(null)?null:"reset":[...n][0]}return null},Je=e=>typeof e=="string"&&/^\s*@font-face\b/i.test(e),bo=e=>{const t={root:[],reset:[],keyframes:[]},o=[];for(const n of e||[]){const s=Ve(n);s?t[s].push(n.cssText):n&&n.cssText&&o.push(n.cssText)}return{globalCSS:{rootRule:t.root.join(`
3
3
  `),resetRules:t.reset.join(`
4
4
  `),keyframeRules:t.keyframes.join(`
5
- `),fontFaceCSS:""},classRules:o}};let pe=new Set;const sn=()=>{pe=new Set},rn=()=>Array.from(pe).join(`
6
- `),cn=(e,t)=>e.replace(/<style data-emotion="smbls">[\s\S]*?<\/style>/,t?`<style data-emotion="smbls">
5
+ `),fontFaceCSS:""},classRules:o}};let pe=new Set;const cn=()=>{pe=new Set},ln=()=>Array.from(pe).join(`
6
+ `),an=(e,t)=>e.replace(/<style data-emotion="smbls">[\s\S]*?<\/style>/,t?`<style data-emotion="smbls">
7
7
  ${t}
8
- </style>`:""),ln=async(e,t={})=>{const{route:o="/",pathname:n,prefetch:s=!0,timeout:r}=t,i=await Ne(e,{route:o,pathname:n,prefetch:s,timeout:r});if(!i)return null;const u=e.designSystem||{},a=i.globalCSS;let g=null;try{const c=bo(i.element);Object.keys(c).length&&(g=c)}catch{}const f=i.activeLang;return{html:i.html,css:i.classRules.join(`
9
- `),classRules:i.classRules.slice(),globalCSS:a,resetCss:a.resetRules,fontLinks:et(u),metadata:i.metadata||he(e,o),brKeyCount:i.registry?Object.keys(i.registry).length:0,brRegistry:i.brRegistry||{},fetchSeed:i.fetchSeed||[],fetchRuns:i.fetchRuns||{},ssrTranslations:i.ssrTranslations,prefetchedState:g,activeLang:f,theme:Ue(e),diagnostics:i.diagnostics,preparedDesignSystem:i.preparedDesignSystem||null}},bo=e=>{const t={};return qe(e,o=>{const n=o.fetch;if(!(!n||typeof n!="object"||!o.state))for(const s of Array.isArray(n)?n:[n]){const r=s&&typeof s=="object"&&typeof s.as=="string"?s.as:null;if(!r)continue;const i=r.startsWith("~/"),u=i?r.slice(2):r,a=i?o.state.root:o.state,g=_e(a&&a[u]);u&&g!=null&&typeof g!="function"&&(t[u]=g)}}),t},an=async(e,t="/",o={})=>{const{lang:n,themeColor:s,isr:r,hydrate:i=!0,prefetch:u=!0,shell:a,adoptDom:g=!1,pathname:f,eagerImages:c=Ze,preloadScripts:l=!0,nonce:p,timeout:h,stamp:R,time:k,spriteIcons:X="all",cssClasses:me="all",cssVariables:_="all",registryFormat:E="paths",lazyGroups:Q,paint:Z}=o,P=So(Z),x=To(p),ee=n||e.state?.lang||e.app?.metadata?.lang||"en",B=Ue(e),y=await Ne(e,{route:t,pathname:f,prefetch:u,timeout:h,lazyGroups:Q});if(!y)return null;const w={...y.metadata};if(s&&(w["theme-color"]=s),typeof a=="string"&&!e.name){const m="\0brender-undeclared-title\0";if(he({...e,name:m},t,y.element,y.element?.state).title===m)for(const T of["title","og:title","twitter:title"])w[T]===y.metadata.title&&delete w[T]}const W=lt(w);for(const m of y.classRules)m&&pe.add(m);let $=_o(y.html,c);X==="page"&&($=ft($,typeof a=="string"?a:"").html);const K=Array.from(pe),U=K.filter(Je),te=U.length?K.filter(m=>!Je(m)):K,V=me==="page"?pt(te,ut($,typeof a=="string"?a:"")).join(`
8
+ </style>`:""),fn=async(e,t={})=>{const{route:o="/",pathname:n,prefetch:s=!0,timeout:r}=t,i=await Ne(e,{route:o,pathname:n,prefetch:s,timeout:r});if(!i)return null;const u=e.designSystem||{},a=i.globalCSS;let g=null;try{const c=So(i.element);Object.keys(c).length&&(g=c)}catch{}const f=i.activeLang;return{html:i.html,css:i.classRules.join(`
9
+ `),classRules:i.classRules.slice(),globalCSS:a,resetCss:a.resetRules,fontLinks:et(u),metadata:i.metadata||he(e,o),brKeyCount:i.registry?Object.keys(i.registry).length:0,brRegistry:i.brRegistry||{},fetchSeed:i.fetchSeed||[],fetchRuns:i.fetchRuns||{},ssrTranslations:i.ssrTranslations,prefetchedState:g,activeLang:f,theme:Ue(e),diagnostics:i.diagnostics,preparedDesignSystem:i.preparedDesignSystem||null}},So=e=>{const t={};return qe(e,o=>{const n=o.fetch;if(!(!n||typeof n!="object"||!o.state))for(const s of Array.isArray(n)?n:[n]){const r=s&&typeof s=="object"&&typeof s.as=="string"?s.as:null;if(!r)continue;const i=r.startsWith("~/"),u=i?r.slice(2):r,a=i?o.state.root:o.state,g=_e(a&&a[u]);u&&g!=null&&typeof g!="function"&&(t[u]=g)}}),t},pn=async(e,t="/",o={})=>{const{lang:n,themeColor:s,isr:r,hydrate:i=!0,prefetch:u=!0,shell:a,adoptDom:g=!1,pathname:f,eagerImages:c=Ze,preloadScripts:l=!0,nonce:p,timeout:h,stamp:R,time:k,spriteIcons:Y="all",cssClasses:me="all",cssVariables:_="all",registryFormat:E="paths",lazyGroups:X,paint:Q}=o,P=Ro(Q),x=vo(p),Z=n||e.state?.lang||e.app?.metadata?.lang||"en",B=Ue(e),y=await Ne(e,{route:t,pathname:f,prefetch:u,timeout:h,lazyGroups:X});if(!y)return null;const w={...y.metadata};if(s&&(w["theme-color"]=s),typeof a=="string"&&!e.name){const m="\0brender-undeclared-title\0";if(he({...e,name:m},t,y.element,y.element?.state).title===m)for(const T of["title","og:title","twitter:title"])w[T]===y.metadata.title&&delete w[T]}const W=lt(w);for(const m of y.classRules)m&&pe.add(m);let A=Eo(y.html,c);Y==="page"&&(A=ft(A,typeof a=="string"?a:"").html);const K=Array.from(pe),ee=K.filter(Je),te=ee.length?K.filter(m=>!Je(m)):K,U=me==="page"?pt(te,ut(A,typeof a=="string"?a:"")).join(`
10
10
  `):te.join(`
11
- `),I=U.length?`<style data-smbls-faces>
12
- ${U.join(`
13
- `)}
14
- </style>`:"",C=y.globalCSS,M=`<style data-brender>
15
- ${(_==="page"?mt(C.rootRule||"",C.resetRules,C.keyframeRules,V,$,typeof a=="string"?a:"").css:C.rootRule)||""}
11
+ `),I=dt(ee),C=y.globalCSS,M=`<style data-brender>
12
+ ${(_==="page"?mt(C.rootRule||"",C.resetRules,C.keyframeRules,U,A,typeof a=="string"?a:"").css:C.rootRule)||""}
16
13
  ${C.resetRules||""}
17
14
  ${C.keyframeRules||""}
18
- </style>`,J=V?`<style data-emotion="smbls">
19
- ${V}
20
- </style>`:"",oe=et(e.designSystem||{}),ne=Object.keys(y.registry).length,de=E==="tree"||E==="auto"&&(y.registryFormats||[]).includes("tree"),v=Eo({brRegistry:y.brRegistry,fetchSeed:y.fetchSeed,fetchRuns:y.fetchRuns,adoptDom:g,stamp:R,time:k,registryFormat:de?"tree":"paths",lazyGroups:y.lazyGroups});let F="";if(r&&r.clientScript){const m=Number.isInteger(o.depth)?o.depth:t==="/"?0:t.replace(/^\/|\/$/g,"").split("/").length,b=m>0?"../".repeat(m):"./";if(i){const T=xt({polyglot:e.polyglot||e.config?.polyglot,translations:y.ssrTranslations,lang:y.activeLang,pathname:f||t,attrs:x}),D=T?T+`
15
+ </style>`,V=U?`<style data-emotion="smbls">
16
+ ${U}
17
+ </style>`:"",oe=et(e.designSystem||{}),ne=Object.keys(y.registry).length,de=E==="tree"||E==="auto"&&(y.registryFormats||[]).includes("tree"),v=jo({brRegistry:y.brRegistry,fetchSeed:y.fetchSeed,fetchRuns:y.fetchRuns,adoptDom:g,stamp:R,time:k,registryFormat:de?"tree":"paths",lazyGroups:y.lazyGroups});let F="";if(r&&r.clientScript){const m=Number.isInteger(o.depth)?o.depth:t==="/"?0:t.replace(/^\/|\/$/g,"").split("/").length,b=m>0?"../".repeat(m):"./";if(i){const T=_t({polyglot:e.polyglot||e.config?.polyglot,translations:y.ssrTranslations,lang:y.activeLang,pathname:f||t,attrs:x}),D=T?T+`
21
18
  `:"",re=v.blocks?v.blocks+`
22
19
  `:"";F=`${D}${re}<script type="module" src="${b}${r.clientScript}"${x}><\/script>`}else F=`<script type="module"${x}>
23
20
  {
@@ -36,29 +33,29 @@ ${V}
36
33
  observer.observe(document.body, { childList: true })
37
34
  }
38
35
  <\/script>
39
- <script type="module" src="${b}${r.clientScript}"${x}><\/script>`}const G={...e.config||{}};e.polyglot&&!G.polyglot&&(G.polyglot=e.polyglot);const O=G.polyglot;let N=W;if(O){const m={...O.translations||{}};for(const b in y.ssrTranslations||{})m[b]={...m[b]||{},...y.ssrTranslations[b]};N=ze(W,He(m,y.activeLang,O))}const A=y.diagnostics;if(A)for(const m of N.matchAll(xe)){const b=m[1].trim();A.rawLabelKeys.includes(b)||A.rawLabelKeys.push(b)}if(typeof a=="string"){const m=at(a,{headTags:`${N}
40
- ${v.meta}`,headEnd:[oe,I,M,J].filter(Boolean).join(`
41
- `),body:P?$+`
42
- `+Xe:$,depth:Number.isInteger(o.depth)?o.depth:0,bootScripts:v.blocks,lang:n||(O?y.activeLang:void 0),theme:B,preloadScripts:l});return{html:P?Qe(m):m,route:t,brKeyCount:ne,shell:!0,diagnostics:A,preparedDesignSystem:y.preparedDesignSystem||null,lazyGroups:y.lazyGroups||[]}}const se=`<!DOCTYPE html>
43
- <html lang="${ee}"${B?` data-theme="${uo(B)}"`:""}>
36
+ <script type="module" src="${b}${r.clientScript}"${x}><\/script>`}const G={...e.config||{}};e.polyglot&&!G.polyglot&&(G.polyglot=e.polyglot);const O=G.polyglot;let N=W;if(O){const m={...O.translations||{}};for(const b in y.ssrTranslations||{})m[b]={...m[b]||{},...y.ssrTranslations[b]};N=ze(W,He(m,y.activeLang,O))}const $=y.diagnostics;if($)for(const m of N.matchAll(xe)){const b=m[1].trim();$.rawLabelKeys.includes(b)||$.rawLabelKeys.push(b)}if(typeof a=="string"){const m=at(a,{headTags:`${N}
37
+ ${v.meta}`,headEnd:[oe,I,M,V].filter(Boolean).join(`
38
+ `),body:P?A+`
39
+ `+Xe:A,depth:Number.isInteger(o.depth)?o.depth:0,bootScripts:v.blocks,lang:n||(O?y.activeLang:void 0),theme:B,preloadScripts:l});return{html:P?Qe(m):m,route:t,brKeyCount:ne,shell:!0,diagnostics:$,preparedDesignSystem:y.preparedDesignSystem||null,lazyGroups:y.lazyGroups||[]}}const se=`<!DOCTYPE html>
40
+ <html lang="${Z}"${B?` data-theme="${mo(B)}"`:""}>
44
41
  <head>
45
42
  ${N}${r&&r.clientScript&&i?`
46
43
  ${v.meta}`:""}
47
44
  ${oe}
48
45
  ${I}
49
46
  ${M}
50
- ${J}
47
+ ${V}
51
48
  </head>
52
49
  <body>
53
- ${$}${P?`
50
+ ${A}${P?`
54
51
  ${Xe}`:""}
55
52
  ${F}
56
53
  </body>
57
- </html>`;return{html:P?Qe(se):se,route:t,brKeyCount:ne,diagnostics:A,preparedDesignSystem:y.preparedDesignSystem||null,lazyGroups:y.lazyGroups||[]}},Ye="smbls-whole",Xe=`<template id="${Ye}"></template>`,ue=`<link rel="expect" href="#${Ye}" blocking="render">`,So=e=>!!(e&&typeof e=="object"&&e.whole===!0),Ro=/<meta\b[^>]*\bcharset\s*=[^>]*>/i,wo=[/<head\b[^>]*>/i,/<html\b[^>]*>/i,/^\s*<!doctype\b[^>]*>/i],Qe=e=>{if(typeof e!="string"||e.includes(ue))return e;const t=Ro.exec(e.slice(0,1024));if(t){const o=t.index+t[0].length;return e.slice(0,o)+`
58
- `+ue+e.slice(o)}for(const o of wo){const n=o.exec(e);if(n)return e.slice(0,n.index+n[0].length)+`
54
+ </html>`;return{html:P?Qe(se):se,route:t,brKeyCount:ne,diagnostics:$,preparedDesignSystem:y.preparedDesignSystem||null,lazyGroups:y.lazyGroups||[]}},Ye="smbls-whole",Xe=`<template id="${Ye}"></template>`,ue=`<link rel="expect" href="#${Ye}" blocking="render">`,Ro=e=>!!(e&&typeof e=="object"&&e.whole===!0),wo=/<meta\b[^>]*\bcharset\s*=[^>]*>/i,ko=[/<head\b[^>]*>/i,/<html\b[^>]*>/i,/^\s*<!doctype\b[^>]*>/i],Qe=e=>{if(typeof e!="string"||e.includes(ue))return e;const t=wo.exec(e.slice(0,1024));if(t){const o=t.index+t[0].length;return e.slice(0,o)+`
55
+ `+ue+e.slice(o)}for(const o of ko){const n=o.exec(e);if(n)return e.slice(0,n.index+n[0].length)+`
59
56
  `+ue+e.slice(n.index+n[0].length)}return ue+`
60
- `+e},Ze=2,ko=/<img\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi,xo=/\sloading\s*=/i,_o=(e,t=Ze)=>{if(t===!1||t==null||typeof e!="string")return e;const o=Math.max(0,Number(t)||0);let n=0;return e.replace(ko,s=>n++<o||xo.test(s)?s:s.replace(/^<img\b/i,'<img loading="lazy"'))},et=e=>{if(!e)return"";const t=e.font_family||e.fontFamily||{},o=new Set;for(const s of Object.values(t)){if(typeof s!="string")continue;const r=s.match(/'([^']+)'/);r&&o.add(r[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(s=>`family=${s.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
61
- `):""},Eo=({brRegistry:e,fetchSeed:t,fetchRuns:o,adoptDom:n=!1,stamp:s,time:r,registryFormat:i="paths",lazyGroups:u}={})=>{const g=n&&e&&Object.keys(e).length?i==="tree"&&Et(e)||_t(e):"",f=vt(t,o);return{meta:`<meta name="brender" content="${g?"hydrate":"replace"}">
62
- `+yt(jo(s,r))+($e(u)?`
63
- `+$e(u):""),blocks:[g,f].filter(Boolean).join(`
64
- `)}},jo=(e,t)=>{const o=typeof t=="number"&&isFinite(t)?Math.round(t):Date.now();return{stamp:e!=null&&e!==""?String(e):new Date(o).toISOString(),time:o}},To=e=>{if(e==null||e==="")return"";const t=String(e);if(!/^[A-Za-z0-9+/=_-]+$/.test(t))throw new Error("brender: a nonce is base64 or base64url text");return` nonce="${t}"`};export{Ze as EAGER_IMAGES_DEFAULT,Me as SMBLS_SSR_SPECIFIER,Ye as WHOLE_MARKER_ID,on as adoptionScripts,jo as buildStamp,Ue as fixedThemeOf,rn as getAccumulatedEmotionCSS,_o as markLazyImages,So as paintsWhole,Eo as prerenderParts,Ne as render,nn as renderElement,an as renderPage,ln as renderRoute,cn as replaceEmotionCSS,sn as resetGlobalCSSCache,yo as splitCapturedCSS,Qe as withWholePaint};
57
+ `+e},Ze=2,xo=/<img\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi,_o=/\sloading\s*=/i,Eo=(e,t=Ze)=>{if(t===!1||t==null||typeof e!="string")return e;const o=Math.max(0,Number(t)||0);let n=0;return e.replace(xo,s=>n++<o||_o.test(s)?s:s.replace(/^<img\b/i,'<img loading="lazy"'))},et=e=>{if(!e)return"";const t=e.font_family||e.fontFamily||{},o=new Set;for(const s of Object.values(t)){if(typeof s!="string")continue;const r=s.match(/'([^']+)'/);r&&o.add(r[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(s=>`family=${s.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
58
+ `):""},jo=({brRegistry:e,fetchSeed:t,fetchRuns:o,adoptDom:n=!1,stamp:s,time:r,registryFormat:i="paths",lazyGroups:u}={})=>{const g=n&&e&&Object.keys(e).length?i==="tree"&&jt(e)||Et(e):"",f=Lt(t,o);return{meta:`<meta name="brender" content="${g?"hydrate":"replace"}">
59
+ `+bt(To(s,r))+(Ae(u)?`
60
+ `+Ae(u):""),blocks:[g,f].filter(Boolean).join(`
61
+ `)}},To=(e,t)=>{const o=typeof t=="number"&&isFinite(t)?Math.round(t):Date.now();return{stamp:e!=null&&e!==""?String(e):new Date(o).toISOString(),time:o}},vo=e=>{if(e==null||e==="")return"";const t=String(e);if(!/^[A-Za-z0-9+/=_-]+$/.test(t))throw new Error("brender: a nonce is base64 or base64url text");return` nonce="${t}"`};export{Ze as EAGER_IMAGES_DEFAULT,Me as SMBLS_SSR_SPECIFIER,Ye as WHOLE_MARKER_ID,sn as adoptionScripts,To as buildStamp,Ue as fixedThemeOf,ln as getAccumulatedEmotionCSS,Eo as markLazyImages,Ro as paintsWhole,jo as prerenderParts,Ne as render,rn as renderElement,pn as renderPage,fn as renderRoute,an as replaceEmotionCSS,cn as resetGlobalCSSCache,bo as splitCapturedCSS,Qe as withWholePaint};
package/env.js CHANGED
@@ -101,6 +101,284 @@ const patchCustomPropertyNames = (document) => {
101
101
  })
102
102
  }
103
103
 
104
+ // ── Rules a browser keeps that linkedom's CSS parser cannot read ───────────
105
+ // linkedom gives every <style> a sheet from `cssom` 0.5: `style.sheet` parses
106
+ // the style's text, `sheet.insertRule` parses one rule. That parser knows
107
+ // @media, @supports, @font-face, @keyframes, @import, @document and @host and
108
+ // nothing newer: a rule that holds a container query threw ("Unexpected }").
109
+ // Under a `breakpointsFrom` ancestor the atomic engine writes every breakpoint
110
+ // as one (`@container breakpoints (max-width: 1024px){._cX{display:none}}`,
111
+ // @symbo.ls/element resolveMediaCssKey) and counts a throw as an invalid rule:
112
+ // the server page carried the class with no rule. On the merged landing
113
+ // (`Page` declares `breakpointsFrom: 'container'`) 153 of the 343 `_c`
114
+ // classes of `/` had none, and a phone's first frame showed the desktop header
115
+ // until the client replaced it (W7-FIXA). Reading the sheet of a <style> whose
116
+ // TEXT held such a rule threw too, and the render failed with it.
117
+ // Kept now, as a browser keeps them: a block rule whose at-keyword cssom does
118
+ // not know (@container, @layer, @scope, @starting-style), or an @media /
119
+ // @supports that holds one, is read as a grouping rule — its condition, its
120
+ // rules and its text — and a `@layer a, b;` statement as a statement. A rule
121
+ // a browser refuses still throws: text after the one rule (a stray `}`, a
122
+ // second rule), or a rule inside the block that cannot be read either. Every
123
+ // rule cssom reads is cssom's own, as before.
124
+ const GROUP_RULES = Symbol.for('@symbo.ls/brender:groupRules')
125
+ const GROUP_AT_RULE = /^@(container|layer|scope|starting-style|media|supports)(?![\w-])/i
126
+ const LAYER_STATEMENT = /^@layer\s+[-\w.]+(?:\s*,\s*[-\w.]+)*\s*;?$/i
127
+ // The CSSRule type a browser reports; a rule kind newer than the type
128
+ // constants reports 0.
129
+ const GROUP_RULE_TYPES = { media: 4, supports: 12 }
130
+
131
+ // The top-level rules of a CSS text, each as its own text; null when the text
132
+ // is not whole (an unclosed block, string or comment, a stray `}`). A comment
133
+ // between rules belongs to none of them.
134
+ const topLevelRules = (css) => {
135
+ const rules = []
136
+ let depth = 0
137
+ let start = 0
138
+ let quote = null
139
+ const take = (end) => {
140
+ const rule = css.slice(start, end).trim()
141
+ if (rule) rules.push(rule)
142
+ start = end
143
+ }
144
+ for (let i = 0; i < css.length; i++) {
145
+ const ch = css[i]
146
+ if (quote) {
147
+ if (ch === '\\') i++
148
+ else if (ch === quote) quote = null
149
+ continue
150
+ }
151
+ if (ch === '\\') {
152
+ i++
153
+ continue
154
+ }
155
+ if (ch === '/' && css[i + 1] === '*') {
156
+ const close = css.indexOf('*/', i + 2)
157
+ if (close === -1) return null
158
+ if (depth === 0 && !css.slice(start, i).trim()) start = close + 2
159
+ i = close + 1
160
+ continue
161
+ }
162
+ if (ch === '"' || ch === "'") quote = ch
163
+ else if (ch === '{') depth++
164
+ else if (ch === '}') {
165
+ if (depth === 0) return null
166
+ if (--depth === 0) take(i + 1)
167
+ } else if (ch === ';' && depth === 0) take(i + 1)
168
+ }
169
+ if (quote || depth) return null
170
+ take(css.length)
171
+ return rules
172
+ }
173
+
174
+ // A grouping rule cssom cannot read, the way a browser reads it.
175
+ class ServerGroupingRule {
176
+ constructor (keyword, condition, rules) {
177
+ this.keyword = keyword
178
+ this.condition = condition
179
+ this.cssRules = rules
180
+ this.parentRule = null
181
+ this.parentStyleSheet = null
182
+ for (const rule of rules) rule.parentRule = this
183
+ }
184
+
185
+ get type () { return GROUP_RULE_TYPES[this.keyword] || 0 }
186
+ get conditionText () { return this.condition }
187
+ get name () { return this.keyword === 'layer' ? this.condition : undefined }
188
+ get cssText () {
189
+ // the way cssom writes an @media rule: `@media <condition> {<rules>}`
190
+ let inner = ''
191
+ for (const rule of this.cssRules) inner += rule.cssText
192
+ return `@${this.keyword}${this.condition ? ' ' + this.condition : ''} {${inner}}`
193
+ }
194
+ }
195
+
196
+ // A `@layer a, b;` statement.
197
+ class ServerLayerStatementRule {
198
+ constructor (names) {
199
+ this.nameList = names
200
+ this.parentRule = null
201
+ this.parentStyleSheet = null
202
+ }
203
+
204
+ get type () { return 0 }
205
+ get cssText () { return `@layer ${this.nameList.join(', ')};` }
206
+ }
207
+
208
+ // One rule's text as a rule: cssom's reading of it, else the grouping rule
209
+ // (or @layer statement) a browser reads; else the error cssom threw.
210
+ // `cssomInsertRule` is cssom's own CSSStyleSheet#insertRule, run on a holder.
211
+ const readRule = (text, cssomInsertRule) => {
212
+ const holder = { cssRules: [] }
213
+ let error = null
214
+ try {
215
+ cssomInsertRule.call(holder, text, 0)
216
+ if (holder.cssRules[0]) return holder.cssRules[0]
217
+ } catch (e) {
218
+ error = e
219
+ }
220
+ const rule = groupingRuleOf(String(text).trim(), cssomInsertRule)
221
+ if (rule) return rule
222
+ throw error || new SyntaxError(`Failed to parse the rule '${text}'`)
223
+ }
224
+
225
+ const groupingRuleOf = (text, cssomInsertRule) => {
226
+ if (LAYER_STATEMENT.test(text)) {
227
+ return new ServerLayerStatementRule(text.replace(/^@layer\s+/i, '').replace(/\s*;$/, '').split(/\s*,\s*/))
228
+ }
229
+ const at = GROUP_AT_RULE.exec(text)
230
+ if (!at) return null
231
+ // exactly one block rule: `<prelude>{<rules>}` and nothing after it
232
+ const whole = topLevelRules(text)
233
+ if (!whole || whole.length !== 1 || !text.endsWith('}')) return null
234
+ const open = blockStart(text)
235
+ if (open === -1) return null
236
+ const inner = topLevelRules(text.slice(open + 1, -1))
237
+ if (!inner) return null
238
+ const rules = []
239
+ for (const ruleText of inner) {
240
+ try {
241
+ rules.push(readRule(ruleText, cssomInsertRule))
242
+ } catch (e) {
243
+ return null
244
+ }
245
+ }
246
+ return new ServerGroupingRule(at[1].toLowerCase(), text.slice(at[0].length, open).trim(), rules)
247
+ }
248
+
249
+ // Where a rule's block opens: its first `{` outside strings and comments.
250
+ const blockStart = (text) => {
251
+ let quote = null
252
+ for (let i = 0; i < text.length; i++) {
253
+ const ch = text[i]
254
+ if (quote) {
255
+ if (ch === '\\') i++
256
+ else if (ch === quote) quote = null
257
+ continue
258
+ }
259
+ if (ch === '\\') {
260
+ i++
261
+ continue
262
+ }
263
+ if (ch === '/' && text[i + 1] === '*') {
264
+ const close = text.indexOf('*/', i + 2)
265
+ if (close === -1) return -1
266
+ i = close + 1
267
+ continue
268
+ }
269
+ if (ch === '"' || ch === "'") quote = ch
270
+ else if (ch === '{') return i
271
+ }
272
+ return -1
273
+ }
274
+
275
+ const adopt = (rule, sheet) => {
276
+ rule.parentStyleSheet = sheet
277
+ if (rule instanceof ServerGroupingRule) for (const inner of rule.cssRules) adopt(inner, sheet)
278
+ }
279
+
280
+ // Patch linkedom's sheets once per process (the prototypes are cssom's and
281
+ // linkedom's, shared by every document): insertRule keeps a rule cssom cannot
282
+ // read and a browser keeps; `style.sheet` of a text holding one reads that
283
+ // text rule by rule, as a browser does, dropping only a rule it cannot read.
284
+ const patchStyleSheetRules = (document) => {
285
+ const style = document.createElement('style')
286
+ let sheet
287
+ try { sheet = style.sheet } catch (e) { return }
288
+ let sheetProto = sheet && Object.getPrototypeOf(sheet)
289
+ while (sheetProto && !Object.prototype.hasOwnProperty.call(sheetProto, 'insertRule')) sheetProto = Object.getPrototypeOf(sheetProto)
290
+ if (!sheetProto || Object.prototype.hasOwnProperty.call(sheetProto, GROUP_RULES)) return
291
+ const cssomInsertRule = sheetProto.insertRule
292
+ if (typeof cssomInsertRule !== 'function') return
293
+ const SheetConstructor = sheet.constructor
294
+ Object.defineProperty(sheetProto, GROUP_RULES, { configurable: true, value: true })
295
+ Object.defineProperty(sheetProto, 'insertRule', {
296
+ configurable: true,
297
+ writable: true,
298
+ value: function insertRule (rule, index) {
299
+ try {
300
+ return cssomInsertRule.apply(this, arguments)
301
+ } catch (error) {
302
+ const text = String(rule)
303
+ const kept = groupingRuleOf(text.trim(), cssomInsertRule)
304
+ if (!kept) throw error
305
+ const at = index === undefined ? 0 : Number(index)
306
+ if (!(at >= 0 && at <= this.cssRules.length)) throw new RangeError('INDEX_SIZE_ERR')
307
+ adopt(kept, this)
308
+ this.cssRules.splice(at, 0, kept)
309
+ return at
310
+ }
311
+ }
312
+ })
313
+
314
+ let styleProto = Object.getPrototypeOf(style)
315
+ let desc
316
+ while (styleProto && !(desc = Object.getOwnPropertyDescriptor(styleProto, 'sheet'))) styleProto = Object.getPrototypeOf(styleProto)
317
+ if (!styleProto || !desc || typeof desc.get !== 'function' || typeof SheetConstructor !== 'function') return
318
+ const readSheet = desc.get
319
+ // the sheet read from a style's text, while the text holds
320
+ const textSheets = new WeakMap()
321
+ Object.defineProperty(styleProto, 'sheet', {
322
+ configurable: true,
323
+ enumerable: desc.enumerable,
324
+ get () {
325
+ try {
326
+ return readSheet.call(this)
327
+ } catch (error) {
328
+ const text = this.textContent
329
+ const known = textSheets.get(this)
330
+ if (known && known.text === text) return known.sheet
331
+ const rules = topLevelRules(text)
332
+ if (!rules) throw error
333
+ const read = new SheetConstructor()
334
+ for (const rule of rules) {
335
+ try { read.insertRule(rule, read.cssRules.length) } catch (e) { /* a browser drops a rule it cannot read */ }
336
+ }
337
+ textSheets.set(this, { text, sheet: read })
338
+ return read
339
+ }
340
+ }
341
+ })
342
+ }
343
+
344
+ // ── A page timer that throws ends nothing ──────────────────────────────────
345
+ // In a browser, a timer callback that throws (or whose promise rejects) is a
346
+ // line in the console, and the page goes on. In Node it is an uncaught
347
+ // exception (an unhandled rejection), and a host that runs renders ends the
348
+ // process on one: the smbls CLI's handler exits 1. W7-FIXA (fly/landing-fly
349
+ // 1.5.0, a dry run that rendered every static route): `/ask` (fly/core
350
+ // askReveal / askStay) scheduled `win.setTimeout(...)` callbacks that call
351
+ // `win.getComputedStyle`, which the server window does not have; they fired
352
+ // during the next four renders, and `smbls publish` stopped in its
353
+ // pre-render, before it published. The window's own timers (setTimeout,
354
+ // setInterval, the requestAnimationFrame shim) now run their callback inside
355
+ // a try and report what it throws, once per message. What stays: page code
356
+ // that calls the BARE `setTimeout` gets Node's own, and a timer a render
357
+ // left behind still fires during a later render (render.js "One render at a
358
+ // time").
359
+ const reportedTimerErrors = new Set()
360
+ const reportTimerError = (err) => {
361
+ const message = (err && err.message) || String(err)
362
+ if (reportedTimerErrors.has(message)) return
363
+ if (reportedTimerErrors.size >= 200) reportedTimerErrors.clear()
364
+ reportedTimerErrors.add(message)
365
+ console.warn(`[brender] page code threw in a timer; reported as a browser reports it, the render goes on (once per message): ${message}`)
366
+ }
367
+ const containedCallback = (fn) => function (...args) {
368
+ try {
369
+ const out = fn.apply(this, args)
370
+ if (out && typeof out.then === 'function') out.then(null, reportTimerError)
371
+ return out
372
+ } catch (err) {
373
+ reportTimerError(err)
374
+ }
375
+ }
376
+ // The process's timer, read when the page calls it (as the window read it
377
+ // before: a host's fake timers still apply). Node refuses a callback that is
378
+ // not a function; so does this.
379
+ const pageTimer = (name) => (fn, ...rest) =>
380
+ globalThis[name](typeof fn === 'function' ? containedCallback(fn) : fn, ...rest)
381
+
104
382
  // Web Storage for one environment.
105
383
  const createStorage = () => {
106
384
  const store = {}
@@ -150,14 +428,19 @@ export const createEnv = (html = '<!DOCTYPE html><html><head></head><body></body
150
428
  pushState: () => {},
151
429
  replaceState: () => {},
152
430
  state: null
153
- }
431
+ },
432
+ // the page's timers: a callback that throws is reported, never the end of
433
+ // the process (see "A page timer that throws ends nothing"); the bare
434
+ // globals stay Node's
435
+ setTimeout: pageTimer('setTimeout'),
436
+ setInterval: pageTimer('setInterval')
154
437
  }
155
438
  const { window, document } = parseHTML(html, own)
156
439
 
157
440
  // Stub APIs that DOMQL/smbls may call during rendering
158
441
  if (!window.requestAnimationFrame) {
159
442
  window.requestAnimationFrame = (fn) => {
160
- const id = setTimeout(fn, 0)
443
+ const id = setTimeout(typeof fn === 'function' ? containedCallback(fn) : fn, 0)
161
444
  if (id?.unref) id.unref()
162
445
  return id
163
446
  }
@@ -202,6 +485,12 @@ export const createEnv = (html = '<!DOCTYPE html><html><head></head><body></body
202
485
  // as before.
203
486
  patchCustomPropertyNames(document)
204
487
 
488
+ // linkedom's sheets parse with `cssom` 0.5, which cannot read a container
489
+ // query: every breakpoint under a `breakpointsFrom` ancestor lost its rule
490
+ // (W7-FIXA: 153 of the 343 `_c` classes of the merged landing's `/`). A rule
491
+ // a browser keeps is kept (see patchStyleSheetRules).
492
+ patchStyleSheetRules(document)
493
+
205
494
  // Stub MutationObserver for SSR (not provided by linkedom)
206
495
  if (!window.MutationObserver) {
207
496
  window.MutationObserver = class MutationObserver {
package/faces.js ADDED
@@ -0,0 +1,193 @@
1
+ // ── The page's font faces: one sheet, marked for a host ─────────────────────
2
+ // renderPage writes every @font-face rule of the page into ONE
3
+ // `<style data-smbls-faces>` ahead of the server's styles (render.js,
4
+ // facesStyle). XMA r12, ask 2 (mirc #430, decided in #440/#441): a host
5
+ // that serves a returning reader the faces it already keeps by address, and
6
+ // the rest inline, needs to tell kept faces from new ones and to warm the
7
+ // files. So the sheet carries two marks:
8
+ //
9
+ // data-smbls-faces-version a content hash of the sheet's rules — equal
10
+ // rules (same text, same order) give the same
11
+ // version, any change to a rule a new one
12
+ // data-smbls-faces-files per @font-face rule, in rule order, its file
13
+ // address: the first url() of its `src` (a
14
+ // `local()` source before it is skipped), as the
15
+ // rule names it; `-` for a rule that names no
16
+ // file (no url(), or a data: url); a space in an
17
+ // address is written %20
18
+ //
19
+ // The marks describe the faces BY ADDRESS. `smbls build` marks each page
20
+ // again after its file: URLs point into the build output (the version then
21
+ // follows the files the page names, and every page of a build carries the
22
+ // same one when the font URLs are site-root or absolute); its
23
+ // `brender.faces.inline` step moves files into the sheet as data: URLs and
24
+ // keeps both marks as they are, so an inlined face still names its file.
25
+ // No sheet file is written: the host builds a by-address sheet from the list.
26
+ import { createHash } from 'crypto'
27
+ import { stylesheetRules } from './pageWeight.js'
28
+
29
+ export const FACES_SHEET_ATTR = 'data-smbls-faces'
30
+ export const FACES_VERSION_ATTR = 'data-smbls-faces-version'
31
+ export const FACES_FILES_ATTR = 'data-smbls-faces-files'
32
+ // The list entry of a rule that names no file.
33
+ export const NO_FACE_FILE = '-'
34
+
35
+ const FACE_RULE_START = /^@font-face\b/i
36
+ const isFaceRule = (rule) => typeof rule === 'string' && FACE_RULE_START.test(rule.trim())
37
+
38
+ // The declarations of one rule's block, name (lowercase) → value, read past
39
+ // strings and parentheses: a `;` inside `url(data:…;base64,…)` or a quoted
40
+ // url does not end a declaration.
41
+ const declarationsOf = (rule) => {
42
+ const out = {}
43
+ const open = rule.indexOf('{')
44
+ if (open === -1) return out
45
+ let start = open + 1
46
+ let quote = null
47
+ let parens = 0
48
+ const take = (end) => {
49
+ const text = rule.slice(start, end)
50
+ const colon = text.indexOf(':')
51
+ if (colon !== -1) {
52
+ const name = text.slice(0, colon).trim().toLowerCase()
53
+ if (name && !(name in out)) out[name] = text.slice(colon + 1).trim()
54
+ }
55
+ start = end + 1
56
+ }
57
+ for (let i = start; i < rule.length; i++) {
58
+ const ch = rule[i]
59
+ if (quote) {
60
+ if (ch === '\\') i++
61
+ else if (ch === quote) quote = null
62
+ continue
63
+ }
64
+ if (ch === '\\') { i++; continue }
65
+ if (ch === '"' || ch === "'") quote = ch
66
+ else if (ch === '(') parens++
67
+ else if (ch === ')') parens = Math.max(0, parens - 1)
68
+ else if (parens) continue
69
+ else if (ch === ';') take(i)
70
+ else if (ch === '}') { take(i); break }
71
+ }
72
+ return out
73
+ }
74
+
75
+ // A code point from a CSS hex escape (an invalid one is U+FFFD).
76
+ const codePoint = (hex) => {
77
+ const n = parseInt(hex, 16)
78
+ return n > 0 && n <= 0x10FFFF && !(n >= 0xD800 && n <= 0xDFFF) ? String.fromCodePoint(n) : '�'
79
+ }
80
+
81
+ // The text of a url() argument: quotes off, CSS escapes resolved.
82
+ const urlText = (text) => {
83
+ const t = text.trim()
84
+ const q = t[0]
85
+ const body = (q === '"' || q === "'") && t.length > 1 && t[t.length - 1] === q ? t.slice(1, -1) : t
86
+ return body.replace(/\\(?:([0-9a-fA-F]{1,6})\s?|([\s\S]))/g, (m, hex, ch) => hex ? codePoint(hex) : ch).trim()
87
+ }
88
+
89
+ /**
90
+ * The file address a `src` value names: its first `url()` (a `local()`
91
+ * before it is skipped). null when it names none, or only a data: url.
92
+ * @param {string} src - the value of a `@font-face` rule's `src`
93
+ * @returns {string|null}
94
+ */
95
+ export const faceFileOf = (src) => {
96
+ if (typeof src !== 'string') return null
97
+ let quote = null
98
+ for (let i = 0; i < src.length; i++) {
99
+ const ch = src[i]
100
+ if (quote) {
101
+ if (ch === '\\') i++
102
+ else if (ch === quote) quote = null
103
+ continue
104
+ }
105
+ if (ch === '"' || ch === "'") { quote = ch; continue }
106
+ if (!/^url\(/i.test(src.slice(i, i + 4)) || /[\w-]/.test(src[i - 1] || '')) continue
107
+ // the argument: a quoted string, or the raw text up to the `)`
108
+ let j = i + 4
109
+ while (j < src.length && /\s/.test(src[j])) j++
110
+ let end
111
+ if (src[j] === '"' || src[j] === "'") {
112
+ end = j + 1
113
+ while (end < src.length && src[end] !== src[j]) end += src[end] === '\\' ? 2 : 1
114
+ end++
115
+ } else {
116
+ end = src.indexOf(')', j)
117
+ if (end === -1) end = src.length
118
+ }
119
+ const value = urlText(src.slice(j, end))
120
+ return value && !/^data:/i.test(value) ? value : null
121
+ }
122
+ return null
123
+ }
124
+
125
+ // A whitespace character in an address, percent-encoded: the list is
126
+ // space-separated.
127
+ const listEntry = (file) => file
128
+ ? file.replace(/\s/g, (c) => '%' + c.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'))
129
+ : NO_FACE_FILE
130
+
131
+ /**
132
+ * The marks of a faces sheet, from its rules.
133
+ * @param {string|string[]} rules - the sheet's text, or its rules in order
134
+ * @returns {{ version: string, files: string[] }|null} null for a sheet with
135
+ * no @font-face rule, or a text that cannot be read whole
136
+ */
137
+ export const facesSheetMarks = (rules) => {
138
+ const list = typeof rules === 'string' ? stylesheetRules(rules) : Array.isArray(rules) ? rules : null
139
+ if (!list) return null
140
+ const all = list.map((rule) => String(rule).trim()).filter(Boolean)
141
+ const faces = all.filter(isFaceRule)
142
+ if (!faces.length) return null
143
+ return {
144
+ version: createHash('sha256').update(all.join('\n')).digest('hex').slice(0, 12),
145
+ files: faces.map((rule) => listEntry(faceFileOf(declarationsOf(rule).src)))
146
+ }
147
+ }
148
+
149
+ const escapeAttr = (value) => String(value).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;')
150
+
151
+ const marksText = (marks) => marks
152
+ ? ` ${FACES_VERSION_ATTR}="${escapeAttr(marks.version)}" ${FACES_FILES_ATTR}="${escapeAttr(marks.files.join(' '))}"`
153
+ : ''
154
+
155
+ /**
156
+ * The page's `<style data-smbls-faces>` for its @font-face rules, marked.
157
+ * @param {string[]} rules - the rules, in order
158
+ * @returns {string} '' for no rule
159
+ */
160
+ export const facesSheetTag = (rules) => {
161
+ if (!Array.isArray(rules) || !rules.length) return ''
162
+ return `<style ${FACES_SHEET_ATTR}${marksText(facesSheetMarks(rules))}>\n${rules.join('\n')}\n</style>`
163
+ }
164
+
165
+ // A <style> element, or a <script> one (skipped: its text is code, not markup).
166
+ const STYLE_OR_SCRIPT = /<script\b[\s\S]*?<\/script\s*>|<style\b([^>]*)>([\s\S]*?)(<\/style\s*>)/gi
167
+ const SHEET_ATTR = /(^|\s)data-smbls-faces(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?(?=[\s/]|$)/i
168
+ const OLD_MARK = /\s(?:data-smbls-faces-version|data-smbls-faces-files)(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?/gi
169
+
170
+ /**
171
+ * Mark a page's faces sheet again from the rules it holds now — after a
172
+ * step changed the addresses its rules name (`smbls build` maps file: URLs
173
+ * into the build output). The sheet's text and its other attributes stay as
174
+ * they are; the two marks are written again after `data-smbls-faces`. A page
175
+ * without a faces sheet, or with one whose text cannot be read whole, comes
176
+ * back as it was.
177
+ * @param {string} html
178
+ * @returns {string}
179
+ */
180
+ export const markFacesSheet = (html) => {
181
+ if (typeof html !== 'string' || !html.includes(FACES_SHEET_ATTR)) return html
182
+ let done = false
183
+ return html.replace(STYLE_OR_SCRIPT, (whole, attrs, css, close) => {
184
+ if (done || attrs === undefined || !SHEET_ATTR.test(attrs)) return whole
185
+ done = true
186
+ const marks = facesSheetMarks(css)
187
+ if (!marks) return whole
188
+ const rest = attrs.replace(OLD_MARK, '')
189
+ const at = SHEET_ATTR.exec(rest)
190
+ const end = at.index + at[0].length
191
+ return `<style${rest.slice(0, end)}${marksText(marks)}${rest.slice(end)}>${css}${close}`
192
+ })
193
+ }
package/index.js CHANGED
@@ -12,6 +12,10 @@ import { composeIntoShell } from './shell.js'
12
12
  // or trims a stored page as it serves it (stylesheetRules reads a stored
13
13
  // stylesheet text back into the rules classRulesForPage takes).
14
14
  import { trimSpriteToPage, classRulesForPage, markupClasses, trimVariablesToPage, stylesheetRules } from './pageWeight.js'
15
+ // The faces sheet's marks (XMA r12): a caller that changes the addresses a
16
+ // page's faces name (`smbls build` maps file: URLs into its output) marks the
17
+ // sheet again.
18
+ import { markFacesSheet, facesSheetMarks } from './faces.js'
15
19
 
16
20
  export {
17
21
  createEnv,
@@ -42,7 +46,9 @@ export {
42
46
  classRulesForPage,
43
47
  markupClasses,
44
48
  trimVariablesToPage,
45
- stylesheetRules
49
+ stylesheetRules,
50
+ markFacesSheet,
51
+ facesSheetMarks
46
52
  }
47
53
 
48
54
  export default {
@@ -74,5 +80,7 @@ export default {
74
80
  classRulesForPage,
75
81
  markupClasses,
76
82
  trimVariablesToPage,
77
- stylesheetRules
83
+ stylesheetRules,
84
+ markFacesSheet,
85
+ facesSheetMarks
78
86
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/brender",
3
- "version": "3.14.677",
3
+ "version": "3.14.678",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
6
  "module": "./dist/esm/index.js",
@@ -25,6 +25,11 @@
25
25
  "development": "./load.js",
26
26
  "import": "./dist/esm/load.js",
27
27
  "default": "./dist/esm/load.js"
28
+ },
29
+ "./faces": {
30
+ "development": "./faces.js",
31
+ "import": "./dist/esm/faces.js",
32
+ "default": "./dist/esm/faces.js"
28
33
  }
29
34
  },
30
35
  "source": "index.js",
@@ -49,15 +54,15 @@
49
54
  "@symbo.ls/css": "^3.14.782",
50
55
  "@symbo.ls/default-config": "^3.14.789",
51
56
  "@symbo.ls/element": "^3.14.818",
52
- "@symbo.ls/fetch": "^3.14.673",
53
- "@symbo.ls/helmet": "^3.14.672",
54
- "@symbo.ls/scratch": "^3.14.795",
55
- "@symbo.ls/utils": "^3.14.853",
57
+ "@symbo.ls/fetch": "^3.14.674",
58
+ "@symbo.ls/helmet": "^3.14.673",
59
+ "@symbo.ls/scratch": "^3.14.796",
60
+ "@symbo.ls/utils": "^3.14.854",
56
61
  "esbuild": "^0.28.1",
57
62
  "linkedom": "^0.16.8"
58
63
  },
59
64
  "peerDependencies": {
60
- "smbls": "^3.14.859"
65
+ "smbls": "^3.14.860"
61
66
  },
62
67
  "optionalDependencies": {
63
68
  "@symbo.ls/funcql": "^3.14.0"
package/render.js CHANGED
@@ -11,6 +11,7 @@ import { extractMetadata, generateHeadHtml } from './metadata.js'
11
11
  import { hydrate } from './hydrate.js'
12
12
  import { composeIntoShell } from './shell.js'
13
13
  import { trimSpriteToPage, classRulesForPage, markupClasses, trimVariablesToPage } from './pageWeight.js'
14
+ import { facesSheetTag } from './faces.js'
14
15
  import { fetchSSRTranslations } from './prefetch.js'
15
16
  import { createEarlySeedScript } from '@symbo.ls/fetch'
16
17
  import { headerEntries } from '@symbo.ls/fetch/rest'
@@ -2114,7 +2115,10 @@ export const renderPage = async (data, route = '/', options = {}) => {
2114
2115
  const emotionCSS = cssClasses === 'page'
2115
2116
  ? classRulesForPage(classRules, markupClasses(bodyHtml, typeof shell === 'string' ? shell : '')).join('\n')
2116
2117
  : classRules.join('\n')
2117
- const facesStyle = faceRules.length ? `<style data-smbls-faces>\n${faceRules.join('\n')}\n</style>` : ''
2118
+ // Marked for a host (faces.js): `data-smbls-faces-version` (a hash of the
2119
+ // rules) and `data-smbls-faces-files` (each rule's file address, in rule
2120
+ // order) — XMA r12, ask 2.
2121
+ const facesStyle = facesSheetTag(faceRules)
2118
2122
 
2119
2123
  // Global CSS (variables, reset, keyframes): this render's own init output.
2120
2124
  // The style tags, built once for both documents below.