@symbo.ls/brender 3.14.665 → 3.14.666
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 +14 -0
- package/README.md +1 -1
- package/dist/esm/env.js +1 -1
- package/dist/esm/render.js +18 -18
- package/env.js +56 -35
- package/package.json +3 -3
- package/render.js +18 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @symbo.ls/brender
|
|
2
2
|
|
|
3
|
+
## 3.14.666
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Cross-tenant isolation for server renders, and the wider CLI production gate.
|
|
8
|
+
|
|
9
|
+
- fetch: a server render context (`isolateFetchCache`, set by brender) has its own query store — cache, requests in flight, invalidations and mounted queries — so two renders of different projects in one process never share rows, in sequence or at the same time; a server render binds no browser-only refetch (no focus / online listeners, no `refetchInterval` timer), so no request of one page lands in another page's seed and the process exits when the work is done.
|
|
10
|
+
- brender: renders that start together share one framework bundle; every render owns its `location`, Web Storage and `history`.
|
|
11
|
+
- cli: destructive platform writes (project delete, transfer, members, invites, library changes, version writes) print the target and need a typed "production" or `--yes` for production; `project create` is not gated.
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
- smbls@3.14.839
|
|
15
|
+
- @symbo.ls/fetch@3.14.666
|
|
16
|
+
|
|
3
17
|
## 3.14.665
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -159,7 +159,7 @@ Options:
|
|
|
159
159
|
|
|
160
160
|
**Diagnostics.** `result.diagnostics` names what a page was made without: `failedRequests` (`{ url, reason }`, origin and path only — a query can carry a key) and `rawLabelKeys` (label keys the page shows raw). `null` when another render overlapped this one in the same process. `smbls build` prints them; `smbls build --strict` fails on them.
|
|
161
161
|
|
|
162
|
-
**Every render is the same render.** Each render processes the design system on a config of its own, the way the page's single boot does (`context.isolateDesignSystem`), with its own `localStorage`/`sessionStorage`, so the tenth page of a build has the theme variables, language and labels of the first. Each render also
|
|
162
|
+
**Every render is the same render.** Each render processes the design system on a config of its own, the way the page's single boot does (`context.isolateDesignSystem`), with its own `localStorage`/`sessionStorage`, so the tenth page of a build has the theme variables, language and labels of the first. Each render also has a `@symbo.ls/fetch` query cache of its own (`context.isolateFetchCache`): a page makes every request its markup depends on itself, so its fetch seed carries every answer it shows, even when an earlier page of the build read the same key; and renders in one process — one after another or at once, of one project or of several — never share rows, requests in flight or invalidations. Its queries bind no window focus, reconnect or `refetchInterval` refetch: once its markup is taken, a render's queries leave no listener, no timer and no request behind. A process builds the framework bundle once, also when its first renders start together.
|
|
163
163
|
|
|
164
164
|
### The page the browser gets (the client's contract)
|
|
165
165
|
|
package/dist/esm/env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{parseHTML as
|
|
1
|
+
import{parseHTML as h}from"linkedom";const a=new WeakSet;class u{static[Symbol.hasInstance](t){return a.has(t)}}const b=o=>{let t=Object.getPrototypeOf(o.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(l){const r=l==null?"":String(l);let s=!1;for(const n of this.querySelectorAll("option")){const c=n.hasAttribute("value")?n.getAttribute("value"):n.textContent;!s&&c===r?(n.setAttribute("selected",""),s=!0):n.removeAttribute("selected")}}})},i=()=>{const o={};return{getItem:t=>o[t]??null,setItem:(t,e)=>{o[t]=String(e)},removeItem:t=>{delete o[t]},clear:()=>{for(const t in o)delete o[t]},get length(){return Object.keys(o).length},key:t=>Object.keys(o)[t]??null}},m=(o="<!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:i(),sessionStorage:i(),history:{pushState:()=>{},replaceState:()=>{},state:null}},{window:e,document:l}=h(o,t);return e.requestAnimationFrame||(e.requestAnimationFrame=r=>{const s=setTimeout(r,0);return s?.unref&&s.unref(),s}),e.cancelAnimationFrame||(e.cancelAnimationFrame=r=>clearTimeout(r)),e.URL||(e.URL=URL),e.scrollTo||(e.scrollTo=()=>{}),globalThis.localStorage=t.localStorage,globalThis.sessionStorage=t.sessionStorage,globalThis.history||(globalThis.history=t.history),b(l),e.MutationObserver||(e.MutationObserver=class{constructor(){}observe(){}disconnect(){}takeRecords(){return[]}}),globalThis.window=e,globalThis.document=l,globalThis.Node=e.Node||globalThis.Node,globalThis.Element=e.Element||globalThis.Element,globalThis.HTMLElement=e.HTMLElement||globalThis.HTMLElement,globalThis.MutationObserver=e.MutationObserver,a.add(e),e.constructor&&e.constructor!==Object?globalThis.Window=e.constructor:(typeof globalThis.Window!="function"||globalThis.Window===Object)&&(globalThis.Window=u),{window:e,document:l}};export{m as createEnv};
|
package/dist/esm/render.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import{resolve as m,join as Ce,dirname as x}from"path";import{existsSync as b,unlinkSync as De,readFileSync as W,realpathSync as Ie}from"fs";import{resolvePackageEntry as Oe}from"./packageEntry.js";import{tmpdir as Me}from"os";import{randomBytes as Pe}from"crypto";import{createRequire as oe}from"module";import{pathToFileURL as Fe}from"url";import{createEnv as ue}from"./env.js";import{resetKeys as de,assignKeys as me,mapKeysToElements as ge}from"./keys.js";import{extractMetadata as se,generateHeadHtml as Be}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as Ke}from"./shell.js";import{fetchSSRTranslations as Ne}from"./prefetch.js";import{createEarlySeedScript as Ge}from"@symbo.ls/fetch";import{headerEntries as He}from"@symbo.ls/fetch/rest";import{brenderRegistryBlock as Je,escapeRegExp as We,jsonForScript as Ue,polyglotFallbackLang as U}from"@symbo.ls/utils";let Z=null;const ze=async()=>{if(Z)return Z;try{return Z=(await import("@symbo.ls/funcql")).funcqlPlugin,Z}catch{return null}};import"linkedom";import{createEarlySeedBlock as Ye}from"@symbo.ls/fetch";import{reset as Ve}from"@symbo.ls/css";const Q=(e,t)=>{if(!e||!t)return;if(e[t]!==void 0)return e[t];const o=t.split(".");let s=e;for(const r of o){if(s==null||typeof s!="object")return;s=s[r]}return s},ne=(e,t)=>U(e?.lang,t),he=(e,t,o,s)=>{if(o?.translations){const n=o.translations[t];if(n){const a=Q(n,e);if(a!==void 0)return a}}if(s?.translations){const n=s.translations[t];if(n){const a=Q(n,e);if(a!==void 0)return a}}const r=U(void 0,o);if(r!==t&&o?.translations){const n=o.translations[r];if(n){const a=Q(n,e);if(a!==void 0)return a}}},Xe=function(e,t){if(!e)return"";const o=this?.context,s=o?.polyglot,r=this?.state?.root||o?.state?.root,n=he(e,t||ne(r,s),s,r);if(n!==void 0)return n;const a=ie(ce);return s&&a&&a.labelKeys.add(e),e},ye=function(){return ne(this?.state?.root,this?.context?.polyglot)},_=(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 s=[];t.set(e,s);for(const r of e)s.push(typeof r=="object"&&r!==null?_(r,t):r);return s}const o={};t.set(e,o);for(const s of Object.keys(e)){const r=e[s];o[s]=typeof r=="object"&&r!==null?_(r,t):r}return o};let $=null;try{import.meta.url&&($=oe(import.meta.url))}catch{}const Ze=()=>{if(!import.meta.url||!$)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:l=>l};const e=Ie(new URL(".",import.meta.url).pathname),t=m(e,"../..");if(b(m(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let s;try{const l=$.resolve("smbls/package.json");s=x(l)}catch{let l=e;for(;l!==x(l);){const y=m(l,"node_modules","smbls");if(b(m(y,"package.json"))){s=y;break}l=x(l)}}let r=$;if(s)try{r=oe(m(s,"package.json"))}catch{}let n,a=process.cwd();for(;a!==x(a);){if(b(m(a,"package.json"))){n=a;break}a=x(a)}let u=r;if(n)try{u=oe(m(n,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:s,brenderDir:e,projectRoot:n,_smblsRequire:r,_projectRequire:u}},P=(e,t)=>{const o=e.isMonorepo?[$]:[e._smblsRequire,e._projectRequire,$].filter(Boolean);for(const s of o)try{return s.resolve(t)}catch{}return null},Zt=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages",t,...o);const s=P(e,`${t}/package.json`);return s?m(x(s),...o):null},Qt=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"plugins",t,...o);const s=P(e,`@symbo.ls/${t}/package.json`);return s?m(x(s),...o):null},re=(e,t,...o)=>{if(e.isMonorepo){for(const r of["packages","plugins"]){const n=m(e.monorepoRoot,r,t,...o);if(b(n))return n}return null}const s=P(e,`@symbo.ls/${t}/package.json`);return s?m(x(s),...o):null},be=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages","domql","packages",t,...o);const s=P(e,`@symbo.ls/${t}/package.json`);return s?m(x(s),...o):null};let z=null;const Se="smbls/ssr",Qe=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},et=async()=>{if(z)return z;const e=Ze();let t;if($&&e.isMonorepo)t=m(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let f;try{return z=await Qe(),z}catch(c){f=c}if(!$)throw new Error(`brender: ${Se} 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 i=e.smblsRoot&&m(e.smblsRoot,"src","createDomql.js");if(i&&b(i))t=i;else throw new Error(`brender: cannot load ${Se} (${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"),s=Ce(Me(),`br_createDomql_${Pe(6).toString("hex")}.mjs`),r=Oe,n=e.isMonorepo?await import(Fe(m(e.monorepoRoot,"scripts","vite-workspace-source.mjs")).href):null,a=n?new Set(n.workspacePackageRoots().map(f=>n.workspacePackageAt(f).name)):null,u=/^(?:smbls(?:\/.*)?|domql|css-in-props(?:\/.*)?|@symbo\.ls\/[^/]+)$/,l={name:"workspace-resolve",setup(f){n&&(f.onResolve({filter:/^[^./]/},i=>{if(u.test(i.path))return;const c=i.path.split("/"),d=i.path.startsWith("@")?c.slice(0,2).join("/"):c[0];if(!a.has(d))return;const p=n.resolveWorkspaceSource(i.path,i.importer||t);return p?{path:p}:{errors:[{text:`"${i.path}" names no source file in the workspace`}]}}),f.onLoad({filter:/[\\/]dist[\\/]/},i=>n.isWorkspaceDist(i.path)?{errors:[{text:`${i.path} is a BUILD of a workspace package \u2014 the render bundles source`}]}:void 0)),f.onResolve({filter:/^smbls/},i=>{const c=i.path.replace(/^smbls\/?/,""),d=e.isMonorepo?m(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!d)return;if(!c){const g=r(d);return g?{path:g}:void 0}const p=m(d,c);if(b(p))return{path:p};if(b(p+".js"))return{path:p+".js"};const h=m(p,"index.js");if(b(h))return{path:h}}),f.onResolve({filter:/^domql$/},i=>{if(e.isMonorepo){const c=m(e.monorepoRoot,"packages","domql","src","index.js");if(b(c))return{path:c};const d=m(e.monorepoRoot,"packages","domql","index.js");if(b(d))return{path:d}}else try{const c=_require.resolve("domql/package.json"),d=r(x(c));if(d)return{path:d}}catch{}}),f.onResolve({filter:/^@symbo\.ls\//},i=>{const c=i.path.replace("@symbo.ls/","");if(c==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const p of["packages","plugins"]){const h=m(e.monorepoRoot,p,c,"src","index.js");if(b(h))return{path:h};const g=m(e.monorepoRoot,p,c,"index.js");if(b(g))return{path:g}}const d=m(e.monorepoRoot,"packages","default-config","blank","index.js");if(c==="default-config"&&b(d))return{path:d}}else{const d=re(e,c,"src","index.js");if(d&&b(d))return{path:d};const p=re(e,c,"index.js");if(p&&b(p))return{path:p};if(c==="default-config"){const h=re(e,"default-config","blank","index.js");if(h&&b(h))return{path:h}}}}),f.onResolve({filter:/^@domql\//},i=>{const c=i.path.replace("@symbo.ls/","");if(e.isMonorepo){const d=m(e.monorepoRoot,"packages","domql","packages",c,"src","index.js");if(b(d))return{path:d};const p=m(e.monorepoRoot,"packages","domql","packages",c,"index.js");if(b(p))return{path:p}}else{const d=be(e,c,"src","index.js");if(d&&b(d))return{path:d};const p=be(e,c,"index.js");if(p&&b(p))return{path:p}}}),f.onResolve({filter:/^css-in-props/},i=>{let c;if(e.isMonorepo)c=m(e.monorepoRoot,"packages","css-in-props");else{const h=P(e,"css-in-props/package.json");h&&(c=x(h))}if(!c)return;const d=i.path.replace(/^css-in-props\/?/,"");if(d){const h=m(c,d),g=m(h,"index.js");if(b(g))return{path:g};if(b(h+".js"))return{path:h+".js"};if(b(h))return{path:h}}const p=r(c);if(p)return{path:p}}),f.onResolve({filter:/^@emotion\//},i=>{let c;if(e.isMonorepo)c=m(e.monorepoRoot,"node_modules",i.path);else{const d=P(e,`${i.path}/package.json`);if(!d)return;c=x(d)}if(b(c)){const d=m(c,"package.json");if(b(d))try{const p=JSON.parse(W(d,"utf8")),h=p.module||p.main||"dist/emotion-css.esm.js";return{path:m(c,h)}}catch{}return{path:c}}}),f.onResolve({filter:/\.json$/},i=>{if(i.resolveDir){const c=m(i.resolveDir,i.path);if(b(c))return{path:c}}}),f.onLoad({filter:/smbls\/.*options\.js$/},async i=>{if(!i.path.includes("smbls/")||!i.path.endsWith("options.js"))return;let c=W(i.path,"utf8");return c=c.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),c=c.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:c,loader:"js"}}),f.onLoad({filter:/smbls\/.*init\.js$/},async i=>{if(!i.path.includes("smbls/")||!i.path.endsWith("init.js"))return;let c=W(i.path,"utf8");return c=c.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:c,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 i=>{let c=W(i.path,"utf8");return c=c.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:c,loader:"js"}}),f.onLoad({filter:/fetchOnCreate\.js$/},async i=>{if(!i.path.includes("smbls/"))return;let c=W(i.path,"utf8");return c=c.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:c,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:s,write:!0,logLevel:"warning",plugins:[l],nodePaths:e.isMonorepo?[m(e.monorepoRoot,"node_modules")]:[...e.smblsRoot?[m(e.smblsRoot,"node_modules")]:[],...e.projectRoot?[m(e.projectRoot,"node_modules")]:[],...e.smblsRoot?[m(e.smblsRoot,"..","..","node_modules")]:[]].filter(f=>b(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 y=await import(`file://${s}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",s);else try{De(s)}catch{}return z=y,y},tt={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"}},ot=(e,t)=>{const o={};return ke(e,(s,r)=>{if(!r.__brKey)return;const n=t(s);o[n===""?"__root":n]=r.__brKey}),o},ke=(e,t)=>{const o=s=>{const r=s&&s.__ref;if(r&&(t(s,r),r.__children))for(const n of r.__children)o(s[n])};o(e)},st=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let F=0;const Re=Symbol.for("brender.fetchTracked"),we=()=>F,nt=256*1024,rt=1024*1024,ct=new Set(["accept-language","accept"]),xe={renders:0,record:null},it=50,ce={renders:0,record:null},je=(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)}}},ie=e=>e.record&&!e.record.tainted?e.record:null,at=e=>{try{const t=new URL(e);return t.origin+t.pathname}catch{return String(e).split("?")[0]}},ae=(e,t,o)=>{!e||e.tainted||e.failures.length>=it||e.failures.push({url:at(t),reason:o})},ve=e=>e&&typeof e=="object"&&typeof e.url=="string"?e.url:String(e),lt=e=>{const[t,o]=e,s=t&&typeof t=="object"&&typeof t.url=="string",r=ve(t),n=String(o&&o.method||s&&t.method||"GET").toUpperCase(),a={},u=l=>{if(!l)return;const y=!Array.isArray(l)&&typeof l.entries!="function";for(const[f,i]of He(l))y&&i==null||(a[String(f).toLowerCase()]=String(i))};return s&&u(t.headers),o&&u(o.headers),{url:r,method:n,headers:a}},ft=(e,t,o,s)=>{if(!o||!o.ok||typeof o.clone!="function")return;const r=o.headers&&o.headers.get&&o.headers.get("content-type")||"";if(!/json|^text\//i.test(r))return;let n;try{n=o.clone()}catch{return}s(n.text().then(a=>{e.tainted||a.length>nt||e.bytes+a.length>rt||(e.bytes+=a.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:r,body:a}))},()=>{}))},pt=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[Re])return;const t=function(...o){F++;let s=!1;const r=()=>{s||(s=!0,F--)},n=i=>{F++,i.then(()=>{F--},()=>{F--})},a=ie(xe),u=ie(ce);let l=null;if(a)try{l=lt(o),(l.method!=="GET"||!/^https?:/i.test(l.url)||Object.keys(l.headers).some(i=>!ct.has(i)))&&(l=null)}catch{l=null}const y=()=>ve(o[0]);let f;try{f=e.apply(this,o)}catch(i){throw ae(u,y(),i&&i.message||"failed"),r(),i}return f&&typeof f.then=="function"?f.then(i=>{l&&ft(a,l,i,n),u&&i&&i.ok===!1&&ae(u,y(),"HTTP "+i.status),r()},i=>{ae(u,y(),i&&i.message||"network error"),r()}):r(),f};t[Re]=!0,globalThis.fetch=t},eo=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const s=Ue(e);return o?`<script>window.__BR_REGISTRY__=${s};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
|
|
2
|
-
`+Ge(t):""):`<script>window.__BR_REGISTRY__=${s}<\/script>`},_e=async(e,t={})=>{const{route:o="/",pathname:s,state:r,context:n,prefetch:
|
|
1
|
+
import{resolve as m,join as Ce,dirname as x}from"path";import{existsSync as b,unlinkSync as De,readFileSync as W,realpathSync as Ie}from"fs";import{resolvePackageEntry as Oe}from"./packageEntry.js";import{tmpdir as Me}from"os";import{randomBytes as Pe}from"crypto";import{createRequire as oe}from"module";import{pathToFileURL as Fe}from"url";import{createEnv as ue}from"./env.js";import{resetKeys as de,assignKeys as me,mapKeysToElements as ge}from"./keys.js";import{extractMetadata as se,generateHeadHtml as Be}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as Ke}from"./shell.js";import{fetchSSRTranslations as Ne}from"./prefetch.js";import{createEarlySeedScript as Ge}from"@symbo.ls/fetch";import{headerEntries as He}from"@symbo.ls/fetch/rest";import{brenderRegistryBlock as Je,escapeRegExp as We,jsonForScript as Ue,polyglotFallbackLang as U}from"@symbo.ls/utils";let X=null;const ze=async()=>{if(X)return X;try{return X=(await import("@symbo.ls/funcql")).funcqlPlugin,X}catch{return null}};import"linkedom";import{createEarlySeedBlock as Ye}from"@symbo.ls/fetch";import{reset as Ve}from"@symbo.ls/css";const Z=(e,t)=>{if(!e||!t)return;if(e[t]!==void 0)return e[t];const o=t.split(".");let s=e;for(const r of o){if(s==null||typeof s!="object")return;s=s[r]}return s},ne=(e,t)=>U(e?.lang,t),he=(e,t,o,s)=>{if(o?.translations){const n=o.translations[t];if(n){const l=Z(n,e);if(l!==void 0)return l}}if(s?.translations){const n=s.translations[t];if(n){const l=Z(n,e);if(l!==void 0)return l}}const r=U(void 0,o);if(r!==t&&o?.translations){const n=o.translations[r];if(n){const l=Z(n,e);if(l!==void 0)return l}}},Xe=function(e,t){if(!e)return"";const o=this?.context,s=o?.polyglot,r=this?.state?.root||o?.state?.root,n=he(e,t||ne(r,s),s,r);if(n!==void 0)return n;const l=ie(ce);return s&&l&&l.labelKeys.add(e),e},ye=function(){return ne(this?.state?.root,this?.context?.polyglot)},_=(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 s=[];t.set(e,s);for(const r of e)s.push(typeof r=="object"&&r!==null?_(r,t):r);return s}const o={};t.set(e,o);for(const s of Object.keys(e)){const r=e[s];o[s]=typeof r=="object"&&r!==null?_(r,t):r}return o};let $=null;try{import.meta.url&&($=oe(import.meta.url))}catch{}const Ze=()=>{if(!import.meta.url||!$)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:a=>a};const e=Ie(new URL(".",import.meta.url).pathname),t=m(e,"../..");if(b(m(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let s;try{const a=$.resolve("smbls/package.json");s=x(a)}catch{let a=e;for(;a!==x(a);){const y=m(a,"node_modules","smbls");if(b(m(y,"package.json"))){s=y;break}a=x(a)}}let r=$;if(s)try{r=oe(m(s,"package.json"))}catch{}let n,l=process.cwd();for(;l!==x(l);){if(b(m(l,"package.json"))){n=l;break}l=x(l)}let u=r;if(n)try{u=oe(m(n,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:s,brenderDir:e,projectRoot:n,_smblsRequire:r,_projectRequire:u}},P=(e,t)=>{const o=e.isMonorepo?[$]:[e._smblsRequire,e._projectRequire,$].filter(Boolean);for(const s of o)try{return s.resolve(t)}catch{}return null},Qt=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages",t,...o);const s=P(e,`${t}/package.json`);return s?m(x(s),...o):null},eo=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"plugins",t,...o);const s=P(e,`@symbo.ls/${t}/package.json`);return s?m(x(s),...o):null},re=(e,t,...o)=>{if(e.isMonorepo){for(const r of["packages","plugins"]){const n=m(e.monorepoRoot,r,t,...o);if(b(n))return n}return null}const s=P(e,`@symbo.ls/${t}/package.json`);return s?m(x(s),...o):null},be=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages","domql","packages",t,...o);const s=P(e,`@symbo.ls/${t}/package.json`);return s?m(x(s),...o):null};let Q=null;const Se="smbls/ssr",Qe=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},et=()=>(Q||(Q=tt().catch(e=>{throw Q=null,e})),Q),tt=async()=>{const e=Ze();let t;if($&&e.isMonorepo)t=m(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let f;try{return await Qe()}catch(c){f=c}if(!$)throw new Error(`brender: ${Se} 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 i=e.smblsRoot&&m(e.smblsRoot,"src","createDomql.js");if(i&&b(i))t=i;else throw new Error(`brender: cannot load ${Se} (${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"),s=Ce(Me(),`br_createDomql_${Pe(6).toString("hex")}.mjs`),r=Oe,n=e.isMonorepo?await import(Fe(m(e.monorepoRoot,"scripts","vite-workspace-source.mjs")).href):null,l=n?new Set(n.workspacePackageRoots().map(f=>n.workspacePackageAt(f).name)):null,u=/^(?:smbls(?:\/.*)?|domql|css-in-props(?:\/.*)?|@symbo\.ls\/[^/]+)$/,a={name:"workspace-resolve",setup(f){n&&(f.onResolve({filter:/^[^./]/},i=>{if(u.test(i.path))return;const c=i.path.split("/"),d=i.path.startsWith("@")?c.slice(0,2).join("/"):c[0];if(!l.has(d))return;const p=n.resolveWorkspaceSource(i.path,i.importer||t);return p?{path:p}:{errors:[{text:`"${i.path}" names no source file in the workspace`}]}}),f.onLoad({filter:/[\\/]dist[\\/]/},i=>n.isWorkspaceDist(i.path)?{errors:[{text:`${i.path} is a BUILD of a workspace package \u2014 the render bundles source`}]}:void 0)),f.onResolve({filter:/^smbls/},i=>{const c=i.path.replace(/^smbls\/?/,""),d=e.isMonorepo?m(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!d)return;if(!c){const g=r(d);return g?{path:g}:void 0}const p=m(d,c);if(b(p))return{path:p};if(b(p+".js"))return{path:p+".js"};const h=m(p,"index.js");if(b(h))return{path:h}}),f.onResolve({filter:/^domql$/},i=>{if(e.isMonorepo){const c=m(e.monorepoRoot,"packages","domql","src","index.js");if(b(c))return{path:c};const d=m(e.monorepoRoot,"packages","domql","index.js");if(b(d))return{path:d}}else try{const c=_require.resolve("domql/package.json"),d=r(x(c));if(d)return{path:d}}catch{}}),f.onResolve({filter:/^@symbo\.ls\//},i=>{const c=i.path.replace("@symbo.ls/","");if(c==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const p of["packages","plugins"]){const h=m(e.monorepoRoot,p,c,"src","index.js");if(b(h))return{path:h};const g=m(e.monorepoRoot,p,c,"index.js");if(b(g))return{path:g}}const d=m(e.monorepoRoot,"packages","default-config","blank","index.js");if(c==="default-config"&&b(d))return{path:d}}else{const d=re(e,c,"src","index.js");if(d&&b(d))return{path:d};const p=re(e,c,"index.js");if(p&&b(p))return{path:p};if(c==="default-config"){const h=re(e,"default-config","blank","index.js");if(h&&b(h))return{path:h}}}}),f.onResolve({filter:/^@domql\//},i=>{const c=i.path.replace("@symbo.ls/","");if(e.isMonorepo){const d=m(e.monorepoRoot,"packages","domql","packages",c,"src","index.js");if(b(d))return{path:d};const p=m(e.monorepoRoot,"packages","domql","packages",c,"index.js");if(b(p))return{path:p}}else{const d=be(e,c,"src","index.js");if(d&&b(d))return{path:d};const p=be(e,c,"index.js");if(p&&b(p))return{path:p}}}),f.onResolve({filter:/^css-in-props/},i=>{let c;if(e.isMonorepo)c=m(e.monorepoRoot,"packages","css-in-props");else{const h=P(e,"css-in-props/package.json");h&&(c=x(h))}if(!c)return;const d=i.path.replace(/^css-in-props\/?/,"");if(d){const h=m(c,d),g=m(h,"index.js");if(b(g))return{path:g};if(b(h+".js"))return{path:h+".js"};if(b(h))return{path:h}}const p=r(c);if(p)return{path:p}}),f.onResolve({filter:/^@emotion\//},i=>{let c;if(e.isMonorepo)c=m(e.monorepoRoot,"node_modules",i.path);else{const d=P(e,`${i.path}/package.json`);if(!d)return;c=x(d)}if(b(c)){const d=m(c,"package.json");if(b(d))try{const p=JSON.parse(W(d,"utf8")),h=p.module||p.main||"dist/emotion-css.esm.js";return{path:m(c,h)}}catch{}return{path:c}}}),f.onResolve({filter:/\.json$/},i=>{if(i.resolveDir){const c=m(i.resolveDir,i.path);if(b(c))return{path:c}}}),f.onLoad({filter:/smbls\/.*options\.js$/},async i=>{if(!i.path.includes("smbls/")||!i.path.endsWith("options.js"))return;let c=W(i.path,"utf8");return c=c.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),c=c.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:c,loader:"js"}}),f.onLoad({filter:/smbls\/.*init\.js$/},async i=>{if(!i.path.includes("smbls/")||!i.path.endsWith("init.js"))return;let c=W(i.path,"utf8");return c=c.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:c,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 i=>{let c=W(i.path,"utf8");return c=c.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:c,loader:"js"}}),f.onLoad({filter:/fetchOnCreate\.js$/},async i=>{if(!i.path.includes("smbls/"))return;let c=W(i.path,"utf8");return c=c.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:c,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:s,write:!0,logLevel:"warning",plugins:[a],nodePaths:e.isMonorepo?[m(e.monorepoRoot,"node_modules")]:[...e.smblsRoot?[m(e.smblsRoot,"node_modules")]:[],...e.projectRoot?[m(e.projectRoot,"node_modules")]:[],...e.smblsRoot?[m(e.smblsRoot,"..","..","node_modules")]:[]].filter(f=>b(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 y=await import(`file://${s}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",s);else try{De(s)}catch{}return y},ot={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"}},st=(e,t)=>{const o={};return ke(e,(s,r)=>{if(!r.__brKey)return;const n=t(s);o[n===""?"__root":n]=r.__brKey}),o},ke=(e,t)=>{const o=s=>{const r=s&&s.__ref;if(r&&(t(s,r),r.__children))for(const n of r.__children)o(s[n])};o(e)},nt=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let F=0;const Re=Symbol.for("brender.fetchTracked"),we=()=>F,rt=256*1024,ct=1024*1024,it=new Set(["accept-language","accept"]),xe={renders:0,record:null},lt=50,ce={renders:0,record:null},je=(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)}}},ie=e=>e.record&&!e.record.tainted?e.record:null,at=e=>{try{const t=new URL(e);return t.origin+t.pathname}catch{return String(e).split("?")[0]}},le=(e,t,o)=>{!e||e.tainted||e.failures.length>=lt||e.failures.push({url:at(t),reason:o})},ve=e=>e&&typeof e=="object"&&typeof e.url=="string"?e.url:String(e),ft=e=>{const[t,o]=e,s=t&&typeof t=="object"&&typeof t.url=="string",r=ve(t),n=String(o&&o.method||s&&t.method||"GET").toUpperCase(),l={},u=a=>{if(!a)return;const y=!Array.isArray(a)&&typeof a.entries!="function";for(const[f,i]of He(a))y&&i==null||(l[String(f).toLowerCase()]=String(i))};return s&&u(t.headers),o&&u(o.headers),{url:r,method:n,headers:l}},pt=(e,t,o,s)=>{if(!o||!o.ok||typeof o.clone!="function")return;const r=o.headers&&o.headers.get&&o.headers.get("content-type")||"";if(!/json|^text\//i.test(r))return;let n;try{n=o.clone()}catch{return}s(n.text().then(l=>{e.tainted||l.length>rt||e.bytes+l.length>ct||(e.bytes+=l.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:r,body:l}))},()=>{}))},ut=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[Re])return;const t=function(...o){F++;let s=!1;const r=()=>{s||(s=!0,F--)},n=i=>{F++,i.then(()=>{F--},()=>{F--})},l=ie(xe),u=ie(ce);let a=null;if(l)try{a=ft(o),(a.method!=="GET"||!/^https?:/i.test(a.url)||Object.keys(a.headers).some(i=>!it.has(i)))&&(a=null)}catch{a=null}const y=()=>ve(o[0]);let f;try{f=e.apply(this,o)}catch(i){throw le(u,y(),i&&i.message||"failed"),r(),i}return f&&typeof f.then=="function"?f.then(i=>{a&&pt(l,a,i,n),u&&i&&i.ok===!1&&le(u,y(),"HTTP "+i.status),r()},i=>{le(u,y(),i&&i.message||"network error"),r()}):r(),f};t[Re]=!0,globalThis.fetch=t},to=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const s=Ue(e);return o?`<script>window.__BR_REGISTRY__=${s};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
|
|
2
|
+
`+Ge(t):""):`<script>window.__BR_REGISTRY__=${s}<\/script>`},_e=async(e,t={})=>{const{route:o="/",pathname:s,state:r,context:n,prefetch:l=!1}=t,u=s||o;ut();const a=je(ce,()=>({failures:[],labelKeys:new Set,tainted:!1}));try{return await dt(e,{route:o,locationPath:u,stateOverrides:r,contextOverrides:n,prefetch:l},a.record)}finally{a.close()}},dt=async(e,{route:t,locationPath:o,stateOverrides:s,contextOverrides:r,prefetch:n},l)=>{let u;if(n)try{u=await Ne(e)}catch(c){console.warn("[brender] SSR translation fetch failed:",c.message)}const{window:a,document:y}=ue(),f=y.body;a.location.pathname=o;const i=[ee("document",y),ee("location",a.location),ee("localStorage",a.localStorage),ee("sessionStorage",a.sessionStorage)];try{const{createDomqlElement:c}=await et(),d=_(e.app||{}),p={...e.config||{}};e.polyglot&&!p.polyglot&&(p.polyglot=e.polyglot),e.fetch&&!p.fetch&&(p.fetch=e.fetch),e.router&&!p.router&&(p.router=e.router);for(const S of bt)e[S]!=null&&p[S]==null&&(p[S]=e[S]);const h=p.polyglot?{...p.polyglot}:void 0;u&&h&&(h.translations={...h.translations||{},...u});const g=_(e.state||{});(u||h)&&(g.root||(g.root={}),h&&(g.root.lang=U(g.root.lang,h)),u&&(g.root.translations={...g.root.translations||{},...u})),Ve();const q={};for(const S in e){if(nt.has(S))continue;const R=e[S];q[S]=R&&typeof R=="object"?_(R):R}const T={...q,state:g,...s?{state:{...g,...s}}:{},dependencies:_(e.dependencies||{}),components:_(e.components||{}),snippets:_(e.snippets||{}),pages:_(e.pages||{}),functions:{...e.functions||{},polyglot:Xe,getActiveLang:ye,getLang:ye},methods:e.methods||{},designSystem:_(e.designSystem||{}),files:e.files||{},sharedLibraries:e.sharedLibraries||[],...p,...h?{polyglot:h}:{},document:y,window:a,parent:{node:f},initOptions:{},domqlOptions:{sourcemap:!1},firstRender:!1,sync:!1,inspect:!1,notifications:!1,isolateDesignSystem:!0,isolateFetchCache:!0,...r||{}},B=await ze();B&&(T.plugins=T.plugins||[],T.plugins.some(S=>S.name==="funcql")||T.plugins.push(B)),de();const I=je(xe,()=>({entries:[],bytes:0,tainted:!1})),O=I.record;let j;try{j=await c(d,T);const S=Date.now(),R=n?2e3:50,L=M=>new Promise(J=>setTimeout(J,M));for(await L(Math.min(50,R));n&&we()>0&&Date.now()-S<R;)await L(10),we()===0&&await L(Math.max(0,Math.min(50,R-(Date.now()-S))))}finally{I.close()}const z=O&&!O.tainted?O.entries.slice():[];me(f);const Y=ge(j),{elementPath:A}=await import("@symbo.ls/element"),K=st(j,A),N=se(e,t,j,j?.state),v=[],C=y.head||y.querySelector("head");if(C)for(const S of C.querySelectorAll("style")){if(S.sheet&&S.sheet.cssRules)for(const R of S.sheet.cssRules)R.cssText&&v.push(R);if(!v.length){const R=S.textContent||"";R&&v.push({cssText:R})}}const D=v.map(S=>S.cssText),{globalCSS:V,classRules:pe}=wt(v);let k=Le(f.innerHTML);const w=j?.state?.root,E=ne(w,h),G=mt(u,w);G&&(k=Te(k,Ee(G,E,h)));const H=l&&!l.tainted?{failedRequests:l.failures.slice(),rawLabelKeys:yt(l.labelKeys,k,E,h,w)}:null;return{html:k,metadata:N,registry:Y,brRegistry:K,element:j,emotionCSS:D,globalCSS:V,classRules:pe,fetchSeed:z,document:y,window:a,ssrTranslations:G||void 0,activeLang:E,diagnostics:H}}finally{for(const c of i)c()}},ee=(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]})},ae=/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,fe=e=>e&&typeof e.parse=="function"?e.parse():e,mt=(e,t)=>{const o=fe(t?.translations),s={};for(const r of[e,o])if(!(!r||typeof r!="object"))for(const n in r){const l=fe(r[n]);l&&typeof l=="object"&&(s[n]={...s[n]||{},...l})}return Object.keys(s).length?s:null},Ee=(e,t,o)=>e[t]||e[U(void 0,o)]||Object.values(e)[0]||{},Te=(e,t)=>e.replace(ae,(o,s)=>Z(t,s.trim())??o),gt=/<script\b[^>]*\btype\s*=\s*["']?application\/json["']?[^>]*>[\s\S]*?<\/script\s*>/gi,ht=(e,t)=>new RegExp(`(?:^|[^\\w.-])${We(t)}(?![\\w-]|\\.\\w)`).test(e),yt=(e,t,o,s,r)=>{const n=new Set,l=t.replace(gt,"");for(const u of e)/\s/.test(u)||he(u,o,s,r)===void 0&&ht(l,u)&&n.add(u);for(const u of l.matchAll(ae))n.add(u[1].trim());return[...n]},oo=async(e,t={})=>{const{context:o={}}=t,{window:s,document:r}=ue(),n=r.body,{create:l}=await import("@symbo.ls/element"),u=await import("@symbo.ls/utils"),a={...ot,...o.components||{}},y={...u,...o.utils||{},...o.functions||{}};de();let f;try{f=l(e,{node:n},"root",{context:{document:r,window:s,...o,components:a,utils:y}})}catch{}me(n);const i=f?ge(f):{};return{html:Le(n.innerHTML),registry:i,element:f}},Le=e=>e.replace(/(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,(t,o,s,r)=>{if(s.includes("<")){const n=s.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&").replace(/"/g,'"').replace(/'/g,"'");return o+n+r}return t}),bt=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],St=/\.[A-Za-z_\\-]/,kt=e=>{if(typeof e!="string"||!e)return!1;const t=e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]");return!St.test(t)},Rt=/^\s*(:root|\[data-theme|\[data-skin)/,$e=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 kt(e.selectorText)?Rt.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 s=new Set(o.map($e));return s.has(null)||s.size!==1?s.has(null)?null:"reset":[...s][0]}return null},wt=e=>{const t={root:[],reset:[],keyframes:[]},o=[];for(const s of e||[]){const r=$e(s);r?t[r].push(s.cssText):s&&s.cssText&&o.push(s.cssText)}return{globalCSS:{rootRule:t.root.join(`
|
|
3
3
|
`),resetRules:t.reset.join(`
|
|
4
4
|
`),keyframeRules:t.keyframes.join(`
|
|
5
|
-
`),fontFaceCSS:""},classRules:o}};let te=new Set;const
|
|
6
|
-
`),
|
|
5
|
+
`),fontFaceCSS:""},classRules:o}};let te=new Set;const so=()=>{te=new Set},no=()=>Array.from(te).join(`
|
|
6
|
+
`),ro=(e,t)=>e.replace(/<style data-emotion="smbls">[\s\S]*?<\/style>/,t?`<style data-emotion="smbls">
|
|
7
7
|
${t}
|
|
8
|
-
</style>`:""),
|
|
9
|
-
`),classRules:n.classRules.slice(),globalCSS:u,resetCss:u.resetRules,fontLinks:
|
|
8
|
+
</style>`:""),co=async(e,t={})=>{const{route:o="/",pathname:s,prefetch:r=!0}=t,n=await _e(e,{route:o,pathname:s,prefetch:r});if(!n)return null;const l=e.designSystem||{},u=n.globalCSS;let a=null;try{const f=xt(n.element);Object.keys(f).length&&(a=f)}catch{}const y=n.activeLang;return{html:n.html,css:n.classRules.join(`
|
|
9
|
+
`),classRules:n.classRules.slice(),globalCSS:u,resetCss:u.resetRules,fontLinks:Ae(l),metadata:n.metadata||se(e,o),brKeyCount:n.registry?Object.keys(n.registry).length:0,brRegistry:n.brRegistry||{},fetchSeed:n.fetchSeed||[],ssrTranslations:n.ssrTranslations,prefetchedState:a,activeLang:y,diagnostics:n.diagnostics}},xt=e=>{const t={};return ke(e,o=>{const s=o.fetch;if(!(!s||typeof s!="object"||!o.state))for(const r of Array.isArray(s)?s:[s]){const n=r&&typeof r=="object"&&typeof r.as=="string"?r.as:null;if(!n)continue;const l=n.startsWith("~/"),u=l?n.slice(2):n,a=l?o.state.root:o.state,y=fe(a&&a[u]);u&&y!=null&&typeof y!="function"&&(t[u]=y)}}),t},io=async(e,t="/",o={})=>{const{lang:s,themeColor:r,isr:n,hydrate:l=!0,prefetch:u=!0,shell:a,adoptDom:y=!1,pathname:f,eagerImages:i=qe,preloadScripts:c=!0,nonce:d}=o,p=Tt(d),h=s||e.state?.lang||e.app?.metadata?.lang||"en",g=await _e(e,{route:t,pathname:f,prefetch:u});if(!g)return null;const q={...g.metadata};if(r&&(q["theme-color"]=r),typeof a=="string"&&!e.name){const k="\0brender-undeclared-title\0";if(se({...e,name:k},t,g.element,g.element?.state).title===k)for(const E of["title","og:title","twitter:title"])q[E]===g.metadata.title&&delete q[E]}const T=Be(q);for(const k of g.classRules)k&&te.add(k);const B=Array.from(te).join(`
|
|
10
10
|
`),I=g.globalCSS,O=`<style data-brender>
|
|
11
11
|
${I.rootRule||""}
|
|
12
12
|
${I.resetRules||""}
|
|
13
13
|
${I.keyframeRules||""}
|
|
14
14
|
</style>`,j=B?`<style data-emotion="smbls">
|
|
15
15
|
${B}
|
|
16
|
-
</style>`:"",
|
|
17
|
-
`)}const G=
|
|
16
|
+
</style>`:"",z=Ae(e.designSystem||{}),Y=Object.keys(g.registry).length,A=Et({brRegistry:g.brRegistry,fetchSeed:g.fetchSeed,adoptDom:y});let K="";if(n&&n.clientScript){const k=Number.isInteger(o.depth)?o.depth:t==="/"?0:t.replace(/^\/|\/$/g,"").split("/").length,w=k>0?"../".repeat(k):"./";if(l){let E="";if(g.ssrTranslations){const H=e.polyglot||e.config?.polyglot,S=H?.storagePrefix||"",R=H?.storageLangKey||"",L=[];for(const M in g.ssrTranslations){const J=g.ssrTranslations[M];J&&typeof J=="object"&&L.push(`localStorage.setItem(${JSON.stringify(S+M)},${JSON.stringify(JSON.stringify(J))})`)}if(R){const M=U(void 0,H);L.push(`if(!localStorage.getItem(${JSON.stringify(R)}))localStorage.setItem(${JSON.stringify(R)},${JSON.stringify(M)})`)}L.length&&(E=`<script${p}>try{${L.join(";")}}catch(e){}<\/script>
|
|
17
|
+
`)}const G=A.blocks?A.blocks+`
|
|
18
18
|
`:"";K=`${E}${G}<script type="module" src="${w}${n.clientScript}"${p}><\/script>`}else K=`<script type="module"${p}>
|
|
19
19
|
{
|
|
20
20
|
const brEls = document.querySelectorAll('body > :not(script):not(style)')
|
|
@@ -32,22 +32,22 @@ ${B}
|
|
|
32
32
|
observer.observe(document.body, { childList: true })
|
|
33
33
|
}
|
|
34
34
|
<\/script>
|
|
35
|
-
<script type="module" src="${w}${n.clientScript}"${p}><\/script>`}const N={...e.config||{}};e.polyglot&&!N.polyglot&&(N.polyglot=e.polyglot);const v=N.polyglot;let C=T;if(v){const k={...v.translations||{}};for(const w in g.ssrTranslations||{})k[w]={...k[w]||{},...g.ssrTranslations[w]};C=Te(T,Ee(k,g.activeLang,v))}const D=g.diagnostics;if(D)for(const k of C.matchAll(
|
|
36
|
-
${
|
|
37
|
-
`),body:
|
|
35
|
+
<script type="module" src="${w}${n.clientScript}"${p}><\/script>`}const N={...e.config||{}};e.polyglot&&!N.polyglot&&(N.polyglot=e.polyglot);const v=N.polyglot;let C=T;if(v){const k={...v.translations||{}};for(const w in g.ssrTranslations||{})k[w]={...k[w]||{},...g.ssrTranslations[w]};C=Te(T,Ee(k,g.activeLang,v))}const D=g.diagnostics;if(D)for(const k of C.matchAll(ae)){const w=k[1].trim();D.rawLabelKeys.includes(w)||D.rawLabelKeys.push(w)}const V=_t(g.html,i);return typeof a=="string"?{html:Ke(a,{headTags:`${C}
|
|
36
|
+
${A.meta}`,headEnd:[z,O,j].filter(Boolean).join(`
|
|
37
|
+
`),body:V,depth:Number.isInteger(o.depth)?o.depth:0,bootScripts:A.blocks,lang:s||(v?g.activeLang:void 0),preloadScripts:c}),route:t,brKeyCount:Y,shell:!0,diagnostics:D}:{html:`<!DOCTYPE html>
|
|
38
38
|
<html lang="${h}">
|
|
39
39
|
<head>
|
|
40
|
-
${C}${n&&n.clientScript&&
|
|
41
|
-
${
|
|
42
|
-
${
|
|
40
|
+
${C}${n&&n.clientScript&&l?`
|
|
41
|
+
${A.meta}`:""}
|
|
42
|
+
${z}
|
|
43
43
|
|
|
44
44
|
${O}
|
|
45
45
|
${j}
|
|
46
46
|
</head>
|
|
47
47
|
<body>
|
|
48
|
-
${
|
|
48
|
+
${V}
|
|
49
49
|
${K}
|
|
50
50
|
</body>
|
|
51
|
-
</html>`,route:t,brKeyCount:
|
|
52
|
-
`):""},
|
|
53
|
-
`)}},
|
|
51
|
+
</html>`,route:t,brKeyCount:Y,diagnostics:D}},qe=2,jt=/<img\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi,vt=/\sloading\s*=/i,_t=(e,t=qe)=>{if(t===!1||t==null||typeof e!="string")return e;const o=Math.max(0,Number(t)||0);let s=0;return e.replace(jt,r=>s++<o||vt.test(r)?r:r.replace(/^<img\b/i,'<img loading="lazy"'))},Ae=e=>{if(!e)return"";const t=e.font_family||e.fontFamily||{},o=new Set;for(const r of Object.values(t)){if(typeof r!="string")continue;const n=r.match(/'([^']+)'/);n&&o.add(n[1])}return o.size?['<link rel="preconnect" href="https://fonts.googleapis.com">','<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',`<link href="https://fonts.googleapis.com/css2?${[...o].map(r=>`family=${r.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
|
|
52
|
+
`):""},Et=({brRegistry:e,fetchSeed:t,adoptDom:o=!1}={})=>{const s=o&&e&&Object.keys(e).length?Je(e):"",r=Ye(t);return{meta:`<meta name="brender" content="${s?"hydrate":"replace"}">`,blocks:[s,r].filter(Boolean).join(`
|
|
53
|
+
`)}},Tt=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{qe as EAGER_IMAGES_DEFAULT,Se as SMBLS_SSR_SPECIFIER,to as adoptionScripts,no as getAccumulatedEmotionCSS,_t as markLazyImages,Et as prerenderParts,_e as render,oo as renderElement,io as renderPage,co as renderRoute,ro as replaceEmotionCSS,so as resetGlobalCSSCache,wt as splitCapturedCSS};
|
package/env.js
CHANGED
|
@@ -33,12 +33,58 @@ const patchSelectValue = (document) => {
|
|
|
33
33
|
})
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Web Storage for one environment.
|
|
37
|
+
const createStorage = () => {
|
|
38
|
+
const store = {}
|
|
39
|
+
return {
|
|
40
|
+
getItem: (k) => store[k] ?? null,
|
|
41
|
+
setItem: (k, v) => { store[k] = String(v) },
|
|
42
|
+
removeItem: (k) => { delete store[k] },
|
|
43
|
+
clear: () => { for (const k in store) delete store[k] },
|
|
44
|
+
get length () { return Object.keys(store).length },
|
|
45
|
+
key: (i) => Object.keys(store)[i] ?? null
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
36
49
|
/**
|
|
37
50
|
* Creates a virtual DOM environment for server-side rendering.
|
|
38
51
|
* Returns window and document that DOMQL can use as context.
|
|
39
52
|
*/
|
|
40
53
|
export const createEnv = (html = '<!DOCTYPE html><html><head></head><body></body></html>') => {
|
|
41
|
-
|
|
54
|
+
// Every environment owns its location, Web Storage and history.
|
|
55
|
+
// linkedom's window is a Proxy over globalThis itself: a property set on it
|
|
56
|
+
// is set on globalThis, and a property it does not know is read from
|
|
57
|
+
// globalThis — after the per-document globals parseHTML takes, which is
|
|
58
|
+
// where an environment's own objects have to live (`window.X` and
|
|
59
|
+
// `document.defaultView.X` read them first).
|
|
60
|
+
// - location was set on the window: that set globalThis.location, render()
|
|
61
|
+
// put it back after the render, and every later environment found it
|
|
62
|
+
// there and kept it — every render in a process shared one location and
|
|
63
|
+
// rewrote only its pathname. A render inherited the search and hash of
|
|
64
|
+
// the one before it, and renders that overlapped read each other's
|
|
65
|
+
// pathname: three of five overlapping renders of different routes
|
|
66
|
+
// rendered the home page.
|
|
67
|
+
// - Storage was set on the window too, so every environment's
|
|
68
|
+
// `window.localStorage` was the NEWEST environment's store: renders that
|
|
69
|
+
// overlapped read each other's persisted language and labels. (A new
|
|
70
|
+
// store per environment keeps renders one after another apart — polyglot
|
|
71
|
+
// keeps the language a page switched to and the labels it loaded there,
|
|
72
|
+
// and the next page of a build booted with them: xma.info report,
|
|
73
|
+
// brender build item 7.)
|
|
74
|
+
// - The history stub was set once on globalThis and shared by all.
|
|
75
|
+
// A complete Location shape (host/hostname/protocol/href too): framework
|
|
76
|
+
// modules read these at module load, before any route is set.
|
|
77
|
+
const own = {
|
|
78
|
+
location: { pathname: '/', search: '', hash: '', origin: 'http://localhost', protocol: 'http:', host: 'localhost', hostname: 'localhost', port: '', href: 'http://localhost/' },
|
|
79
|
+
localStorage: createStorage(),
|
|
80
|
+
sessionStorage: createStorage(),
|
|
81
|
+
history: {
|
|
82
|
+
pushState: () => {},
|
|
83
|
+
replaceState: () => {},
|
|
84
|
+
state: null
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const { window, document } = parseHTML(html, own)
|
|
42
88
|
|
|
43
89
|
// Stub APIs that DOMQL/smbls may call during rendering
|
|
44
90
|
if (!window.requestAnimationFrame) {
|
|
@@ -51,18 +97,6 @@ export const createEnv = (html = '<!DOCTYPE html><html><head></head><body></body
|
|
|
51
97
|
if (!window.cancelAnimationFrame) {
|
|
52
98
|
window.cancelAnimationFrame = (id) => clearTimeout(id)
|
|
53
99
|
}
|
|
54
|
-
if (!window.history) {
|
|
55
|
-
window.history = {
|
|
56
|
-
pushState: () => {},
|
|
57
|
-
replaceState: () => {},
|
|
58
|
-
state: null
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (!window.location) {
|
|
62
|
-
// A complete Location shape (host/hostname/protocol/href too): framework
|
|
63
|
-
// modules read these at module load, before any route is set.
|
|
64
|
-
window.location = { pathname: '/', search: '', hash: '', origin: 'http://localhost', protocol: 'http:', host: 'localhost', hostname: 'localhost', port: '', href: 'http://localhost/' }
|
|
65
|
-
}
|
|
66
100
|
if (!window.URL) {
|
|
67
101
|
window.URL = URL
|
|
68
102
|
}
|
|
@@ -70,28 +104,15 @@ export const createEnv = (html = '<!DOCTYPE html><html><head></head><body></body
|
|
|
70
104
|
window.scrollTo = () => {}
|
|
71
105
|
}
|
|
72
106
|
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
key: (i) => Object.keys(store)[i] ?? null
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// Every environment gets its own, empty storage. linkedom's window reads an
|
|
86
|
-
// unknown property through to globalThis, so `window.localStorage` found the
|
|
87
|
-
// FIRST environment's store (published on globalThis below) and every later
|
|
88
|
-
// render shared it: polyglot keeps the language a page switched to and the
|
|
89
|
-
// labels it loaded there, and the next page of a build booted with them
|
|
90
|
-
// (xma.info report, brender build item 7 — reset state between renders).
|
|
91
|
-
window.localStorage = createStorage()
|
|
92
|
-
window.sessionStorage = createStorage()
|
|
93
|
-
if (!globalThis.localStorage) globalThis.localStorage = window.localStorage
|
|
94
|
-
if (!globalThis.sessionStorage) globalThis.sessionStorage = window.sessionStorage
|
|
107
|
+
// The BARE globals stay what they were (the window's setter used to write
|
|
108
|
+
// them): `localStorage` / `sessionStorage` are the newest environment's
|
|
109
|
+
// stores, and `history` is the first environment's stub when the host has
|
|
110
|
+
// none. render() swaps the bare storage and location to the rendering
|
|
111
|
+
// environment's own for the length of a render; overlapping renders still
|
|
112
|
+
// share them (a render queue or per-render globals — an open decision).
|
|
113
|
+
globalThis.localStorage = own.localStorage
|
|
114
|
+
globalThis.sessionStorage = own.sessionStorage
|
|
115
|
+
if (!globalThis.history) globalThis.history = own.history
|
|
95
116
|
|
|
96
117
|
// linkedom's HTMLSelectElement has a `value` getter and NO setter: a
|
|
97
118
|
// `value` prop on a <select> threw "Cannot set property value … which has
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbo.ls/brender",
|
|
3
|
-
"version": "3.14.
|
|
3
|
+
"version": "3.14.666",
|
|
4
4
|
"license": "CC-BY-NC-4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@symbo.ls/css": "^3.14.779",
|
|
50
50
|
"@symbo.ls/default-config": "^3.14.787",
|
|
51
51
|
"@symbo.ls/element": "^3.14.805",
|
|
52
|
-
"@symbo.ls/fetch": "^3.14.
|
|
52
|
+
"@symbo.ls/fetch": "^3.14.666",
|
|
53
53
|
"@symbo.ls/helmet": "^3.14.670",
|
|
54
54
|
"@symbo.ls/scratch": "^3.14.789",
|
|
55
55
|
"@symbo.ls/utils": "^3.14.787",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"linkedom": "^0.16.8"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"smbls": "^3.14.
|
|
60
|
+
"smbls": "^3.14.839"
|
|
61
61
|
},
|
|
62
62
|
"optionalDependencies": {
|
|
63
63
|
"@symbo.ls/funcql": "^3.14.0"
|
package/render.js
CHANGED
|
@@ -288,6 +288,13 @@ const resolveDomqlPackage = (ws, pkg, ...subpath) => {
|
|
|
288
288
|
//
|
|
289
289
|
// An installed smbls OLDER than the ssr entry that still carries
|
|
290
290
|
// src/createDomql.js (pre-54131b34d tarballs) keeps the source-bundle path.
|
|
291
|
+
//
|
|
292
|
+
// Loaded once per process, and the load in progress is shared: it kept the
|
|
293
|
+
// loaded module, set when the load finished, so renders that started together
|
|
294
|
+
// before then loaded one each — two esbuild runs, and two framework instances
|
|
295
|
+
// in one process (two signal and CSS engines, two @symbo.ls/fetch copies with
|
|
296
|
+
// their own query caches); the renders after them got whichever finished
|
|
297
|
+
// last. A failed load is not kept: the next render tries again.
|
|
291
298
|
let _cachedCreateDomql = null
|
|
292
299
|
|
|
293
300
|
// Exported for the packaging lock in __tests__/ssrEntryPackaging.test.js —
|
|
@@ -303,9 +310,17 @@ const importSmblsSsr = async () => {
|
|
|
303
310
|
return mod
|
|
304
311
|
}
|
|
305
312
|
|
|
306
|
-
const bundleCreateDomql =
|
|
307
|
-
if (_cachedCreateDomql)
|
|
313
|
+
const bundleCreateDomql = () => {
|
|
314
|
+
if (!_cachedCreateDomql) {
|
|
315
|
+
_cachedCreateDomql = loadCreateDomql().catch((err) => {
|
|
316
|
+
_cachedCreateDomql = null
|
|
317
|
+
throw err
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
return _cachedCreateDomql
|
|
321
|
+
}
|
|
308
322
|
|
|
323
|
+
const loadCreateDomql = async () => {
|
|
309
324
|
const ws = detectWorkspace()
|
|
310
325
|
|
|
311
326
|
// Resolve entry point: the monorepo's source, else `smbls/ssr` (one import
|
|
@@ -316,8 +331,7 @@ const bundleCreateDomql = async () => {
|
|
|
316
331
|
} else {
|
|
317
332
|
let ssrError
|
|
318
333
|
try {
|
|
319
|
-
|
|
320
|
-
return _cachedCreateDomql
|
|
334
|
+
return await importSmblsSsr()
|
|
321
335
|
} catch (err) {
|
|
322
336
|
ssrError = err
|
|
323
337
|
}
|
|
@@ -594,7 +608,6 @@ const bundleCreateDomql = async () => {
|
|
|
594
608
|
console.log('[brender] Bundle saved:', outFile)
|
|
595
609
|
}
|
|
596
610
|
|
|
597
|
-
_cachedCreateDomql = mod
|
|
598
611
|
return mod
|
|
599
612
|
}
|
|
600
613
|
|