@symbo.ls/brender 3.14.674 → 3.14.676

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,69 @@
1
1
  # @symbo.ls/brender
2
2
 
3
+ ## 3.14.676
4
+
5
+ ### Patch Changes
6
+
7
+ - abeeed0: Built-page options for `smbls build` (XMA questions 1–4 and ask C; all opt-in, a build without them writes the same pages): `brender.onProblem: 'skip'` leaves out only a page with a failed request or a raw label key (its address falls to `200.html`), `'fail'` = `strict`; `brender.report` writes a versioned JSON report of every page (status, failed requests, raw label keys, inline faces, ms); `brender.paint: { whole: true }` holds the first paint until the markup is in (`<link rel="expect" blocking="render">` + a marker, no script; `renderPage({ paint })` in brender); `brender.faces: { inline, wait }` writes a page's own faces inline and keeps it unseen until they are in (CSS hold with its own cap); `brender.app: 'afterFirstView'` holds the app's scripts and preloads until the first view is in, the first input, or 3 s; `brender.beforeWrite(html, page)` gives the project each page before its file is written (`page.afterMarkup`). The page's script ships as a file (`smbls-built.<hash>.js`, no inline script), or with `brender.pageScript: 'inline'` inline with one constant CSP hash (logged and in the report). `brender.paths` may be a function, and `brender.module` names a build-only module for the function-valued settings. Fix: `brender.stamp` (and the new settings) in config.js are found also when a `brender.context` module spreads config.js into the context. Fix: the `fetch.early` script tag goes right after `<meta charset>` (it went ahead of it on a page without `<head>`), else first in `<head>`.
8
+ - 908c4e3: A server render no longer puts a `root: { lang, translations }` key into the state it hands smbls. That key never reached the state (smbls merges state with `mergeStateData`, which keeps the store's `parent` / `root` slots out) and made every `smbls build` with brender print `[smbls/state] the declared state key "root" … was NOT copied`. The language and the loaded labels come from where the render already reads them (polyglot's start language, `polyglot.translations`); the pages are the same.
9
+ - df41d88: `prefetchPageData` reads `on` as `@symbo.ls/fetch` does: a list that names `'create'` (`on: ['create', 'stateChange']`) or an empty list is prefetched; a list without `'create'` is not. Before, every config whose `on` was not the string `'create'` was skipped.
10
+ - a529b80: Note for code that reads the page's fetch seed (`script[type="application/json"][data-fetch-seed]`): since brender 3.14.675 the seed list ends with one more item, `{"r":{…}}` — which of its queries each element ran in the render — after the query items (`{"k":…,"b":…}`). A reader must skip an item it does not know (one without `k`), as `@symbo.ls/fetch` does.
11
+ - f8d78c4: A lazy route can be built ahead as its group's real page (XMA question 6).
12
+ symbols.json `brender.lazyGroups: 'load' | ['group', …]` makes the build's
13
+ first navigation load the group and render the route as the group's page
14
+ (the group's `when` is asked at build time; false builds the placeholder).
15
+ The page names the groups it was built with (`<meta name="brender-lazy">`)
16
+ and `smbls build` preloads each group's chunk (`<link rel="modulepreload">`
17
+ after the page's own preloads, found through the chunk's source map;
18
+ `build.modulePreload: "strict"` fails the build without one). In the browser
19
+ the boot reads the tag into the new `context.lazyFirstView` (router): the
20
+ first navigation loads those groups and renders their pages, so the takeover
21
+ adopts the built page instead of mounting the placeholder over it. Public
22
+ pages can move out of the main bundle and still arrive built.
23
+
24
+ The default build (no `brender.lazyGroups`) is fixed the same way: a route
25
+ whose group loaded during the render (a context that declares `lazy`, e.g.
26
+ through `brender.context`) already showed the group's page, but the page
27
+ named no group, so the browser mounted the placeholder over it (1 adoption
28
+ miss; on a slow run the built page was removed and rendered again). The
29
+ router now records a first navigation that showed the placeholder and then
30
+ the group's page; the page names that group and preloads its chunk. The
31
+ built content does not change.
32
+
33
+ - b11e6c6: `polyglot.defaultLang` may be a function `(polyglot) => code`, called each time the default is asked (utils `polyglotDefaultLang`; every reader of the default goes through `polyglotFallbackLang`). The `fetch.early` pre-boot script carries its source and calls it before it decides. The language the pre-boot `startLang(ctx)` hook chose for a page load is recorded by the script (utils `polyglotEarlyStartLang`) and is the start language in every `addressLang` mode: under `'strict'` an unprefixed page started in the static default and asked for its labels a second time. A visitor's own stored choice still never wins under `'strict'`; an admin whose hook returns `null` keeps its own rule.
34
+ - d33cb15: `polyglot.prefetch: true` (or `'idle'`): once the page has loaded and the browser is idle (2 s at most), once per app, each other language's labels load through `loadTranslations` (stored, so a first switch applies them at once) and the font faces their letters need load in the body's font. Skipped for a reader who saves data. brender switches it off for its server renders.
35
+ - 8ddfa44: `polyglot.defaultLang` given as function TEXT (frank JSON — what the runner's `smbls start` page, mermaid's head and a brender render handed the stored payload read) gives the function's answer: `<html lang>` was `en` for `defaultLang: () => 'ka'`. The server readers revive the config before they ask: new `@symbo.ls/utils/server` `revivePolyglotDefaultLang(polyglot, { evaluate })` (deepDestringifyFunctions, the global eval — as the browser revives it), used by brender's render and mermaid's page; the runner, whose utils floor predates that export, revives with the index's `deepDestringifyFunctions`. The shared helpers (`polyglotDefaultLang`, `polyglotFallbackLang`, `polyglotStartupScript`) compile nothing — every browser bundle carries them and the browser never holds the text — so no browser bundle grows. Where nothing may be compiled from text (an EvalError: a Cloudflare Worker, a CSP without `unsafe-eval`) or the caller passes `{ evaluate: false }` (mermaid passes its `canEval`, the `evalAvailable` seam), the text stays and counts as none, as before, and nothing throws.
36
+ - 6ecdb94: `afterFirstView` create option (config.js / context.js / `create(App, { afterFirstView })`): `(app, state, context)` runs once per app, a task after the first view is in — after `create()` rendered it or adopted the pre-rendered page, after the first navigation settled — the moment fetch.early's `afterFirstView` hook has. An app no longer polls `window.__BRENDER_HYDRATION__` to learn that a built page was taken over. A hook that throws or rejects is reported, never rethrown. brender switches it off for its server renders.
37
+ - a529b80: Server render and page replace (W7): `el.context.ssr` is true while a component renders in a server render, so app code can tell it runs there. smbls replaces a pre-rendered page in short tasks and swaps it in at once; an adoption that throws falls back to the one-task replace. brender exports its page-weight trims (text between sprite symbols no longer stops the sprite trim) and `stylesheetRules`, which turns a stored stylesheet text back into its rules. `smbls build`: each pre-rendered route carries its own icons after its content (Fix B), and the cli reads brender's page trims as optional exports, so an older brender still builds.
38
+ - Updated dependencies [3aa9e6a]
39
+ - Updated dependencies [8797734]
40
+ - Updated dependencies [b0240a2]
41
+ - Updated dependencies [e8eaf28]
42
+ - Updated dependencies [f8d78c4]
43
+ - Updated dependencies [b11e6c6]
44
+ - Updated dependencies [8ddfa44]
45
+ - Updated dependencies [6ecdb94]
46
+ - Updated dependencies [a529b80]
47
+ - Updated dependencies [d42696c]
48
+ - @symbo.ls/utils@3.14.853
49
+ - smbls@3.14.859
50
+ - @symbo.ls/fetch@3.14.673
51
+ - @symbo.ls/element@3.14.818
52
+ - @symbo.ls/helmet@3.14.672
53
+
54
+ ## 3.14.675
55
+
56
+ ### Patch Changes
57
+
58
+ - 7b3795b: A part of a pre-built page whose query runs after its create (on a state change, once its `enabled` turns true) is taken over as the page shows it. The render records which of its queries each element ran (`fetchRunsOf`), the page carries that record in its seed block, and the element takes those queries' recorded answers at its init — no loading look between the takeover and its data, no request. An element that never ran a query never takes another element's answer. `elementPath` moves to `@symbo.ls/utils` (still exported by `@symbo.ls/element`).
59
+ - Updated dependencies [7b3795b]
60
+ - Updated dependencies [8700d85]
61
+ - Updated dependencies [9184c58]
62
+ - @symbo.ls/fetch@3.14.671
63
+ - @symbo.ls/utils@3.14.852
64
+ - @symbo.ls/element@3.14.817
65
+ - smbls@3.14.857
66
+
3
67
  ## 3.14.674
4
68
 
5
69
  ### Patch Changes
package/README.md CHANGED
@@ -40,7 +40,7 @@ In the browser, when the app JS loads (`smbls` `src/prerender.js`):
40
40
  3. With a registry (an adoption page): the app's normal `create()` runs, but each element takes the server's node at its path — its attributes and text are written again by the client, its element children are adopted the same way. A node of another tag is not adopted (that element gets a fresh one)
41
41
  4. The adoption stays open until the first view has settled: the first route rendered (also behind a guard that waits), and no `@symbo.ls/fetch` request in flight — so a list that renders with its first data adopts the server's rows. Meanwhile the server nodes still waiting for their element stay on screen, where they were. It closes at the latest after 3 s (`hydrate: { timeout }` in the project's config), or at the visitor's first click or key press; then whatever no element adopted goes, with the server's `<style>` tags
42
42
  5. Without a registry (a replace page, or `hydrate: false` in the project's config): the server's markup and styles go and the app renders fresh
43
- 6. Either way the recorded data answers (`data-fetch-seed`, below) are adopted by the requests that ask for them, so the client does not ask again for what the server had, and `el.context.prerendered` is `true` — a gate that hides the app until its data is in can let the server's first view count as ready
43
+ 6. Either way the recorded data answers (`data-fetch-seed`, below) are adopted by the requests that ask for them, so the client does not ask again for what the server had, and `el.context.prerendered` is `true`. An element whose query the render ran — at its create, or later (a state change, an `enabled` that turned true) — takes that query's recorded answer at its init, so it is taken over with the server's data and never shows its loading look in between; a gate that reads that data (a part busy until its rows are in) needs no special case for the takeover
44
44
 
45
45
  ```
46
46
  Browser DOM (static) DOMQL Tree (no nodes) After hydrate()
@@ -161,6 +161,8 @@ Options:
161
161
  | `time` | now | The build time in ms, written as its `data-time`. A build passes one `stamp` and `time` to every page |
162
162
  | `nonce` | — | Content-Security-Policy nonce for the inline scripts the `isr` document still has (the label seed, the legacy swap script) — a page rendered into a shell has none |
163
163
  | `themeColor` | | See render.js. |
164
+ | `lazyGroups` | — | A lazy route (`@symbo.ls/router` "Lazy Routes") built as its group's REAL page, not its placeholder: `'load'` for every group, or an array of group names. The render's first navigation loads the group, then renders the route; the group's `when` is asked as in the browser, and a `when` that says false (or a load that fails) builds the placeholder. Unset, the render does not wait for a group: the route shows the group's page when the group loaded during the render (its loader settled in time — a context that declares `lazy`), else its placeholder. Either way the page names the groups whose page it shows (`<meta name="brender-lazy">`, `result.lazyGroups`); the browser's first navigation loads them before it adopts the page. `smbls build` reads it from symbols.json `brender.lazyGroups` and preloads each group's chunk on those pages. |
165
+ | `paint` | — | `{ whole: true }`: the first paint waits until the page's markup is in — `<link rel="expect" href="#smbls-whole" blocking="render">` right after the charset declaration, and an empty `<template id="smbls-whole">` right after the markup (before the data blocks and the app's scripts). No script; the browser also stops the wait when it finishes parsing a document without the element. `smbls build` passes it with `symbols.json` `brender.paint` |
164
166
 
165
167
  **Data and labels.** A page's declarative `fetch` runs during the render, through the fetch plugin, with the real element: its `transform(data, el, state)`, and `children` re-run on the answer. The render waits for the requests it starts. Labels: a table/RPC `polyglot.fetch` (`{ rpc }`) is fetched before the render, for every language; a FUNCTION `polyglot.fetch` is the project's own loader and runs inside the render, called by the polyglot plugin with the root element. Labels resolve in the page's language — the root state's `lang` (a router guard that reads `/en/…` sets it), else `polyglot.defaultLang`.
166
168
 
@@ -170,6 +172,20 @@ Options:
170
172
 
171
173
  **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.
172
174
 
175
+ **App code knows it runs on the server.** Every render sets `el.context.ssr` to `true` (`render`, `renderRoute`, `renderPage`, `renderElement`); no payload key and no `context` override turns it off. The server document lays nothing out and observes nothing: no `getComputedStyle`, no `ResizeObserver` or `IntersectionObserver`, no scroll. Code that measures, observes or plays an entrance renders the final state there — test `el.context.ssr === true` before it hides anything (an entrance that sets `opacity: 0` and waits for an observer stores a blank block in the page). A browser has no `ssr` key; a client that boots over a pre-rendered page has `el.context.prerendered === true` instead (step 6 above).
176
+
177
+ ### Page-weight trims (`pageWeight.js`)
178
+
179
+ `renderPage` options `spriteIcons: 'page'`, `cssClasses: 'page'` and `cssVariables: 'page'` keep only what the page paints before the client boots: the icons its markup uses, the atomic rules of its classes, the CSS variables its CSS and markup read (each defaults to `'all'`; `smbls build` turns the first two on). The client adds the rest as it boots. The four trims behind them are exported for a tool that weighs a page of its own — the CLI's publish pre-render (`@symbo.ls/cli` `helpers/ssrCache.js`) stores each route's own icons with them — with `stylesheetRules`, which reads a stored stylesheet text back into the rules `classRulesForPage` takes (the platform's renderer trims a stored route's CSS with them as it serves the route):
180
+
181
+ | Export | Returns |
182
+ |--------|---------|
183
+ | `trimSpriteToPage(html, context?)` | `{ html, kept, dropped }`: `html` with its `<svg id="svgSprite">` holding only the symbols the rest of `html` (and `context`) references, and the symbols those reference. Text and comments between the symbols stay in place and never stop the trim (a library icon whose value is not an `<svg>` leaves a stray `<>` there); a sprite that holds an element other than a symbol is left whole (`kept: 0, dropped: 0`). |
184
+ | `markupClasses(...texts)` | a `Set` of the class names in the texts' `class` attributes |
185
+ | `classRulesForPage(rules, classes)` | the rules (cssText) that name one of `classes`, and every rule that names no class (an `@font-face`), in their order |
186
+ | `trimVariablesToPage(rootCss, ...readers)` | `{ css, kept, dropped }`: `rootCss` with only the custom properties the readers read through `var(--…)`, and the ones those read |
187
+ | `stylesheetRules(css)` | the rules of a stylesheet text, each as its own cssText, in order — whatever the layout (one rule per line, as a stored pre-render keeps them, or several per line); strings, comments, escapes and parentheses are skipped, a comment between rules is dropped. `null` for a text it cannot read whole (an unclosed block, string, comment or parenthesis): keep that text as it is. Never pass a string to `classRulesForPage` — it reads it a character at a time |
188
+
173
189
  ### The page the browser gets (the client's contract)
174
190
 
175
191
  No inline script — a strict Content-Security-Policy (`script-src 'self'`, no `'unsafe-inline'`) blocks inline scripts, never `<meta>` tags or JSON data blocks:
@@ -181,6 +197,7 @@ No inline script — a strict Content-Security-Policy (`script-src 'self'`, no `
181
197
  | `<script type="application/json" data-brender="registry">{…}</script>` | after the markup | Element path → `data-br` key (`__root` for the app's root); adoption pages only |
182
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 |
183
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
+ | `<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 |
184
201
 
185
202
  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.
186
203
 
@@ -304,6 +321,7 @@ With brender on (the default), `smbls build` pre-renders every static route INTO
304
321
  - Every `file:` URL in a page (a `new URL('…', import.meta.url)` asset) is mapped to the file the bundler emitted from the same source (found by content), or copied into the output under a content hash. A `file:` URL that names no project file fails the build.
305
322
  - A page made with failed data or label requests, or with raw label keys, is reported; `smbls build --strict` (or `brender.strict`) fails the build on it.
306
323
  - Every page carries the data of the build time until the next build, and says which build that is: one stamp per build (`<meta name="brender-stamp">`). `brender.stamp` in `symbols.json` (a string or a number), else `brender.stamp` in the project's `config.js` — a value, or a function `({ time, data }) => stamp` run once per build (it may be async: the data's own version, such as the time of its latest change) — else the build time. A stamp function that throws fails the build. How a page learns that its data moved on: `@symbo.ls/fetch`, "A pre-built page shows the data of its build".
324
+ - Opt-in, per page: `brender.onProblem` (`'skip'` leaves out only a page with a failed request or a raw label key), `brender.report` (a JSON report of every page), `brender.paths` as a function, `brender.paint: { whole: true }`, `brender.faces: { inline, wait }` (faces inline, the page unseen until they are in), `brender.app: 'afterFirstView'` (the app's files after the first view) and `brender.beforeWrite(html, page)`; functions live in a build-only `brender.module`. See the CLI README, "Built-page options".
307
325
 
308
326
  #### Routes without their own page: 200.html
309
327
 
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 m,loadAndRenderAll as a}from"./load.js";import{render as p,renderElement as d,renderRoute as n,renderPage as i,resetGlobalCSSCache as l,getAccumulatedEmotionCSS as c,replaceEmotionCSS as f,adoptionScripts as s,prerenderParts as S,buildStamp as g}from"./render.js";import{extractMetadata as h,generateHeadHtml as u}from"./metadata.js";import{collectBrNodes as E,hydrate as P}from"./hydrate.js";import{generateSitemap as y}from"./sitemap.js";import{prefetchPageData as C,injectPrefetchedState as x}from"./prefetch.js";import{composeIntoShell as A}from"./shell.js";var I={createEnv:e,resetKeys:r,assignKeys:t,mapKeysToElements:o,loadProject:m,loadAndRenderAll:a,render:p,renderElement:d,renderRoute:n,renderPage:i,resetGlobalCSSCache:l,getAccumulatedEmotionCSS:c,replaceEmotionCSS:f,extractMetadata:h,generateHeadHtml:u,collectBrNodes:E,hydrate:P,generateSitemap:y,prefetchPageData:C,injectPrefetchedState:x,composeIntoShell:A,adoptionScripts:s,prerenderParts:S,buildStamp:g};export{s as adoptionScripts,t as assignKeys,g as buildStamp,E as collectBrNodes,A as composeIntoShell,e as createEnv,I as default,h as extractMetadata,u as generateHeadHtml,y as generateSitemap,c as getAccumulatedEmotionCSS,P as hydrate,x as injectPrefetchedState,a as loadAndRenderAll,m as loadProject,o as mapKeysToElements,C as prefetchPageData,S as prerenderParts,p as render,d as renderElement,i as renderPage,n as renderRoute,f as replaceEmotionCSS,l as resetGlobalCSSCache,r as resetKeys};
1
+ import{createEnv as e}from"./env.js";import{resetKeys as r,assignKeys as t,mapKeysToElements as o}from"./keys.js";import{loadProject as 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 +1 @@
1
- const E=/<svg\b[^>]*\sid="svgSprite"[^>]*>/,x=/\s*<symbol\b[^>]*>[\s\S]*?<\/symbol>/y,m=/\s*<\/svg>/y,O=/^\s*<symbol\b[^>]*?\sid="([^"]+)"/,y=/#([^\s"'()<>&,;#]+)/g,w=(e,c)=>{if(typeof e!="string"||!e)return c;y.lastIndex=0;let t;for(;t=y.exec(e);)c.add(t[1]);return c},q=(e,c="")=>{const t={html:e,kept:0,dropped:0};if(typeof e!="string")return t;const s=E.exec(e);if(!s)return t;const n=s.index;let o=n+s[0].length;const r=[];for(;;){x.lastIndex=o;const f=x.exec(e);if(!f)break;const p=O.exec(f[0]);r.push({text:f[0],id:p?p[1]:null}),o=x.lastIndex}if(m.lastIndex=o,!m.exec(e))return t;const g=m.lastIndex,i=e.slice(0,n)+e.slice(g),u=w(c,w(i,new Set)),a=new Set,h=new Map;for(const f of r)f.id&&h.set(f.id,f);const S=[...u];for(;S.length;){const f=S.pop(),p=h.get(f);if(!(!p||a.has(p))){a.add(p);for(const k of w(p.text,new Set))h.has(k)&&S.push(k)}}const d=r.filter(f=>!f.id||a.has(f));if(d.length===r.length)return{html:e,kept:d.length,dropped:0};const v=s[0]+d.map(f=>f.text).join("")+e.slice(o,g);return{html:e.slice(0,n)+v+e.slice(g),kept:d.length,dropped:r.length-d.length}},M=e=>e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]"),T=/\.(-?(?:[_A-Za-z -￿]|\\.)(?:[\w -￿-]|\\.)*)/g,P=e=>e.replace(/\\(?:([0-9a-fA-F]{1,6})\s?|(.))/g,(c,t,s)=>t?String.fromCodePoint(parseInt(t,16)):s),L=e=>{const c=[];let t=0,s=null;for(let n=0;n<e.length;n++){const o=e[n];if(s){o==="\\"?n++:o===s&&(s=null);continue}o==='"'||o==="'"?s=o:o==="{"?(c.push(e.slice(t,n).trim()),t=n+1):(o==="}"||o===";")&&(t=n+1)}return c},C=e=>{const c=[];for(const t of L(String(e||""))){if(!t||t[0]==="@")continue;T.lastIndex=0;const s=M(t);let n;for(;n=T.exec(s);)c.push(P(n[1]))}return c},A=/\sclass\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/gi,F=(...e)=>{const c=new Set;for(const t of e){if(typeof t!="string"||!t)continue;A.lastIndex=0;let s;for(;s=A.exec(t);){const n=s[1]??s[2]??s[3]??"";for(const o of n.split(/\s+/))o&&c.add(o.replace(/&amp;/g,"&"))}}return c},N=(e,c)=>{const t=[];for(const s of e||[]){if(!s)continue;const n=C(s);(!n.length||n.some(o=>c.has(o)))&&t.push(s)}return t},b=/var\(\s*(--[\w-]+)/g,_=/^\s*(--[\w-]+)\s*:([\s\S]*)$/,I=(e,c)=>{if(typeof e!="string"||!e)return c;b.lastIndex=0;let t;for(;t=b.exec(e);)c.add(t[1]);return c},R=(e,c)=>{let t="",s=0,n=null,o=0;for(let r=0;r<e.length;r++){const l=e[r];if(n){l==="\\"?r++:l===n&&(n=null);continue}if(l==='"'||l==="'")n=l;else if(l==="(")o++;else if(l===")")o=Math.max(0,o-1);else{if(o)continue;l==="{"?(t+=e.slice(s,r+1),s=r+1):l===";"?(t+=c(e.slice(s,r),";"),s=r+1):l==="}"&&(t+=c(e.slice(s,r),"")+"}",s=r+1)}}return t+e.slice(s)},B=(e,...c)=>{if(typeof e!="string"||!e)return{css:e,kept:0,dropped:0};const t=new Map,s=new Set;R(e,i=>{const u=_.exec(i);if(u){const a=t.get(u[1])||[];a.push(u[2]),t.set(u[1],a)}else I(i,s);return""});for(const i of c)I(i,s);const n=new Set,o=[...s];for(;o.length;){const i=o.pop();if(!(n.has(i)||!t.has(i))){n.add(i);for(const u of t.get(i))for(const a of I(u,new Set))o.push(a)}}let r=0,l=0;return{css:R(e,(i,u)=>{const a=_.exec(i);return!a||n.has(a[1])?(a&&r++,i+u):(l++,"")}),kept:r,dropped:l}};export{N as classRulesForPage,F as markupClasses,C as ruleClasses,q as trimSpriteToPage,B as trimVariablesToPage};
1
+ const N=/<svg\b[^>]*\sid="svgSprite"[^>]*>/,m=/\s*<symbol\b[^>]*>[\s\S]*?<\/symbol>/y,w=/\s*<\/svg>/y,C=/^\s*<symbol\b[^>]*?\sid="([^"]+)"/,k=/<symbol\b|<\/svg>/g,q=/<\/?[A-Za-z]/,F=/<!--[\s\S]*?-->/g,E=/#([^\s"'()<>&,;#]+)/g,y=(e,l)=>{if(typeof e!="string"||!e)return l;E.lastIndex=0;let t;for(;t=E.exec(e);)l.add(t[1]);return l},K=(e,l="")=>{const t={html:e,kept:0,dropped:0};if(typeof e!="string")return t;const n=N.exec(e);if(!n)return t;const o=n.index;let s=o+n[0].length;const c=[],i=[];for(;;){m.lastIndex=s;const u=m.exec(e);if(u){const A=C.exec(u[0]),b={text:u[0],id:A?A[1]:null};c.push(b),i.push(b),s=m.lastIndex;continue}if(w.lastIndex=s,w.exec(e))break;k.lastIndex=s;const d=k.exec(e);if(!d)return t;const g=e.slice(s,d.index);if(q.test(g.replace(F,"")))return t;i.push(g),s=d.index}const r=w.lastIndex,f=e.slice(0,o)+e.slice(r),p=y(l,y(f,new Set)),a=new Set,x=new Map;for(const u of c)u.id&&x.set(u.id,u);const S=[...p];for(;S.length;){const u=S.pop(),d=x.get(u);if(!(!d||a.has(d))){a.add(d);for(const g of y(d.text,new Set))x.has(g)&&S.push(g)}}const T=u=>!u.id||a.has(u),h=c.filter(T);if(h.length===c.length)return{html:e,kept:h.length,dropped:0};const P=i.map(u=>typeof u=="string"?u:T(u)?u.text:"").join(""),L=n[0]+P+e.slice(s,r);return{html:e.slice(0,o)+L+e.slice(r),kept:h.length,dropped:c.length-h.length}},z=e=>e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]"),_=/\.(-?(?:[_A-Za-z -￿]|\\.)(?:[\w -￿-]|\\.)*)/g,B=e=>e.replace(/\\(?:([0-9a-fA-F]{1,6})\s?|(.))/g,(l,t,n)=>t?String.fromCodePoint(parseInt(t,16)):n),D=e=>{const l=[];let t=0,n=null;for(let o=0;o<e.length;o++){const s=e[o];if(n){s==="\\"?o++:s===n&&(n=null);continue}s==='"'||s==="'"?n=s:s==="{"?(l.push(e.slice(t,o).trim()),t=o+1):(s==="}"||s===";")&&(t=o+1)}return l},G=e=>{const l=[];for(const t of D(String(e||""))){if(!t||t[0]==="@")continue;_.lastIndex=0;const n=z(t);let o;for(;o=_.exec(n);)l.push(B(o[1]))}return l},R=/\sclass\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/gi,V=(...e)=>{const l=new Set;for(const t of e){if(typeof t!="string"||!t)continue;R.lastIndex=0;let n;for(;n=R.exec(t);){const o=n[1]??n[2]??n[3]??"";for(const s of o.split(/\s+/))s&&l.add(s.replace(/&amp;/g,"&"))}}return l},Y=(e,l)=>{const t=[];for(const n of e||[]){if(!n)continue;const o=G(n);(!o.length||o.some(s=>l.has(s)))&&t.push(n)}return t},Z=e=>{if(typeof e!="string")return null;const l=[];let t=0,n=0,o=0,s=null;const c=i=>{const r=e.slice(t,i).trim();r&&l.push(r),t=i};for(let i=0;i<e.length;i++){const r=e[i];if(s){r==="\\"?i++:r===s&&(s=null);continue}if(r==="\\"){i++;continue}if(r==="/"&&e[i+1]==="*"){const f=e.indexOf("*/",i+2);if(f===-1)return null;!n&&!o&&!e.slice(t,i).trim()&&(t=f+2),i=f+1;continue}if(r==='"'||r==="'")s=r;else if(r==="(")o++;else if(r===")"){if(!o)return null;o--}else{if(o)continue;if(r==="{")n++;else if(r==="}"){if(!n)return null;--n||c(i+1)}else r===";"&&!n&&c(i+1)}}return s||n||o?null:(c(e.length),l)},M=/var\(\s*(--[\w-]+)/g,O=/^\s*(--[\w-]+)\s*:([\s\S]*)$/,I=(e,l)=>{if(typeof e!="string"||!e)return l;M.lastIndex=0;let t;for(;t=M.exec(e);)l.add(t[1]);return l},v=(e,l)=>{let t="",n=0,o=null,s=0;for(let c=0;c<e.length;c++){const i=e[c];if(o){i==="\\"?c++:i===o&&(o=null);continue}if(i==='"'||i==="'")o=i;else if(i==="(")s++;else if(i===")")s=Math.max(0,s-1);else{if(s)continue;i==="{"?(t+=e.slice(n,c+1),n=c+1):i===";"?(t+=l(e.slice(n,c),";"),n=c+1):i==="}"&&(t+=l(e.slice(n,c),"")+"}",n=c+1)}}return t+e.slice(n)},j=(e,...l)=>{if(typeof e!="string"||!e)return{css:e,kept:0,dropped:0};const t=new Map,n=new Set;v(e,f=>{const p=O.exec(f);if(p){const a=t.get(p[1])||[];a.push(p[2]),t.set(p[1],a)}else I(f,n);return""});for(const f of l)I(f,n);const o=new Set,s=[...n];for(;s.length;){const f=s.pop();if(!(o.has(f)||!t.has(f))){o.add(f);for(const p of t.get(f))for(const a of I(p,new Set))s.push(a)}}let c=0,i=0;return{css:v(e,(f,p)=>{const a=O.exec(f);return!a||o.has(a[1])?(a&&c++,f+p):(i++,"")}),kept:c,dropped:i}};export{Y as classRulesForPage,V as markupClasses,G as ruleClasses,Z as stylesheetRules,K as trimSpriteToPage,j as trimVariablesToPage};
@@ -1 +1 @@
1
- const l=t=>typeof t=="function",S=t=>Array.isArray(t),g=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),_=(t,r)=>{if(t){if(l(t))try{return t({state:r||{},call:()=>{},__ref:{}},r||{})}catch{return}return t}},j=(t,r)=>{if(!t)return null;if(typeof t=="string")return{from:t,method:"select"};const n=l(t)?null:{...t};return!n||(n.method||(n.method="select"),l(n.params)&&(n.params=_(n.params,r)),n.method==="insert"||n.method==="update"||n.method==="upsert"||n.method==="delete")||n.on&&n.on!=="create"?null:n},b=(t,r="")=>{if(!t||typeof t!="object")return[];if(l(t))return[];const n=[],s=t.state||{};if(t.fetch){const e=S(t.fetch)?t.fetch:[t.fetch];for(const c of e){const a=j(c,s);a&&n.push({config:a,stateKey:a.as,path:r,elementState:s})}}for(const e in t)e==="fetch"||e==="state"||e==="props"||e==="attr"||e==="on"||e==="define"||e==="childExtends"||e==="childProps"||e==="childrenAs"||e.charAt(0)>="A"&&e.charAt(0)<="Z"&&g(t[e])&&n.push(...b(t[e],r?`${r}.${e}`:e));return n},M=["rest","local"],w=new WeakMap,A=async t=>{if(!t)return null;if(g(t)&&(l(t.select)||l(t.rpc)))return t;const r=typeof t=="string"?{adapter:t}:t;if(!g(r)||typeof r.adapter!="string")return null;if(w.has(r))return w.get(r);const n=(async()=>{let s;try{s=await import("@symbo.ls/fetch")}catch{return null}if(!(l(s.hasAdapter)?s.hasAdapter(r.adapter):M.includes(r.adapter)))return null;try{return await s.resolveDb(r)}catch(c){return console.warn(`[brender] SSR adapter "${r.adapter}" unavailable: ${c.message}`),null}})();return w.set(r,n),n},k=async(t,r)=>{try{const{method:n,from:s,params:e,transform:c,limit:a,offset:u,order:h,single:f,headers:d,baseUrl:p}=r;let o;if(n==="rpc"){if(!l(t.rpc))return null;o=await t.rpc({from:s,params:e,headers:d,baseUrl:p})}else{if(!l(t.select))return null;o=await t.select({from:s,select:r.select,params:e,limit:a,offset:u,order:h,single:f,headers:d,baseUrl:p})}let i=o?.data??null;if(o?.error)return null;if(i&&c&&l(c))try{i=c(i)}catch{}return i}catch{return null}},P=async(t,r="/",n={})=>{const e=(t.pages||{})[r];if(!e)return new Map;const c=t.config||t.settings||{},a=c.fetch||t.fetch||c.db||t.db;if(!a)return new Map;const u=await A(a);if(!u)return new Map;const h=b(e);if(!h.length)return new Map;const f=new Map,d=await Promise.allSettled(h.map(async({config:p,stateKey:o,path:i})=>{const y=await k(u,p);if(y!==null){const m=f.get(i)||{};o?m[o]=y:g(y)&&Object.assign(m,y),f.set(i,m)}}));return f},x=async t=>{const r=t.config||{},n=r.polyglot||t.polyglot;if(!n?.fetch||typeof n.fetch=="function")return null;const s=r.fetch||t.fetch||r.db||t.db;if(!s)return null;const e=await A(s);if(!e)return null;const c=n.fetch,a=c.rpc||c.from||"get_translations_if_changed",u=(await import("@symbo.ls/utils")).polyglotLanguages(n,!1),h=u.length?u:[n.defaultLang||"en"],f={},d=await Promise.allSettled(h.map(async p=>{try{if(!l(e.rpc))return;const o=await e.rpc({from:a,params:{p_lang:p,p_cached_version:0}});if(o.error||!o.data)return;const i=o.data;i.translations&&(f[p]=i.translations)}catch(o){console.warn("[brender] SSR translation fetch failed:",o.message)}}));return Object.keys(f).length?f:null},D=(t,r)=>{if(!(!r||!r.size))for(const[n,s]of r){let e=t;if(n){const c=n.split(".");for(const a of c){if(!e||typeof e!="object")break;e=e[a]}}e&&typeof e=="object"&&((!e.state||typeof e.state!="object")&&(e.state={}),Object.assign(e.state,s))}};export{A as createSSRAdapter,x as fetchSSRTranslations,D as injectPrefetchedState,P as prefetchPageData};
1
+ const l=t=>typeof t=="function",A=t=>Array.isArray(t),y=t=>t!==null&&typeof t=="object"&&!Array.isArray(t),_=(t,n)=>{if(t){if(l(t))try{return t({state:n||{},call:()=>{},__ref:{}},n||{})}catch{return}return t}},j=t=>A(t)?t.length===0||t.includes("create")||!t.some(n=>typeof n=="string"&&n):!t||t==="create",k=(t,n)=>{if(!t)return null;if(typeof t=="string")return{from:t,method:"select"};const r=l(t)?null:{...t};return!r||(r.method||(r.method="select"),l(r.params)&&(r.params=_(r.params,n)),r.method==="insert"||r.method==="update"||r.method==="upsert"||r.method==="delete")||!j(r.on)?null:r},S=(t,n="")=>{if(!t||typeof t!="object")return[];if(l(t))return[];const r=[],s=t.state||{};if(t.fetch){const e=A(t.fetch)?t.fetch:[t.fetch];for(const c of e){const o=k(c,s);o&&r.push({config:o,stateKey:o.as,path:n,elementState:s})}}for(const e in t)e==="fetch"||e==="state"||e==="props"||e==="attr"||e==="on"||e==="define"||e==="childExtends"||e==="childProps"||e==="childrenAs"||e.charAt(0)>="A"&&e.charAt(0)<="Z"&&y(t[e])&&r.push(...S(t[e],n?`${n}.${e}`:e));return r},M=["rest","local"],w=new WeakMap,b=async t=>{if(!t)return null;if(y(t)&&(l(t.select)||l(t.rpc)))return t;const n=typeof t=="string"?{adapter:t}:t;if(!y(n)||typeof n.adapter!="string")return null;if(w.has(n))return w.get(n);const r=(async()=>{let s;try{s=await import("@symbo.ls/fetch")}catch{return null}if(!(l(s.hasAdapter)?s.hasAdapter(n.adapter):M.includes(n.adapter)))return null;try{return await s.resolveDb(n)}catch(c){return console.warn(`[brender] SSR adapter "${n.adapter}" unavailable: ${c.message}`),null}})();return w.set(n,r),r},P=async(t,n)=>{try{const{method:r,from:s,params:e,transform:c,limit:o,offset:f,order:u,single:p,headers:h,baseUrl:g}=n;let i;if(r==="rpc"){if(!l(t.rpc))return null;i=await t.rpc({from:s,params:e,headers:h,baseUrl:g})}else{if(!l(t.select))return null;i=await t.select({from:s,select:n.select,params:e,limit:o,offset:f,order:u,single:p,headers:h,baseUrl:g})}let a=i?.data??null;if(i?.error)return null;if(a&&c&&l(c))try{a=c(a)}catch{}return a}catch{return null}},x=async(t,n="/",r={})=>{const e=(t.pages||{})[n];if(!e)return new Map;const c=t.config||t.settings||{},o=c.fetch||t.fetch||c.db||t.db;if(!o)return new Map;const f=await b(o);if(!f)return new Map;const u=S(e);if(!u.length)return new Map;const p=new Map,h=await Promise.allSettled(u.map(async({config:g,stateKey:i,path:a})=>{const d=await P(f,g);if(d!==null){const m=p.get(a)||{};i?m[i]=d:y(d)&&Object.assign(m,d),p.set(a,m)}}));return p},D=async t=>{const n=t.config||{},r=n.polyglot||t.polyglot;if(!r?.fetch||typeof r.fetch=="function")return null;const s=n.fetch||t.fetch||n.db||t.db;if(!s)return null;const e=await b(s);if(!e)return null;const c=r.fetch,o=c.rpc||c.from||"get_translations_if_changed",f=await import("@symbo.ls/utils"),u=f.polyglotLanguages(r,!1),p=u.length?u:[f.polyglotFallbackLang(void 0,r)],h={},g=await Promise.allSettled(p.map(async i=>{try{if(!l(e.rpc))return;const a=await e.rpc({from:o,params:{p_lang:i,p_cached_version:0}});if(a.error||!a.data)return;const d=a.data;d.translations&&(h[i]=d.translations)}catch(a){console.warn("[brender] SSR translation fetch failed:",a.message)}}));return Object.keys(h).length?h:null},E=(t,n)=>{if(!(!n||!n.size))for(const[r,s]of n){let e=t;if(r){const c=r.split(".");for(const o of c){if(!e||typeof e!="object")break;e=e[o]}}e&&typeof e=="object"&&((!e.state||typeof e.state!="object")&&(e.state={}),Object.assign(e.state,s))}};export{b as createSSRAdapter,D as fetchSSRTranslations,E as injectPrefetchedState,x as prefetchPageData};
@@ -1,25 +1,25 @@
1
- import{resolve as m,join as Je,dirname as E}from"path";import{existsSync as b,unlinkSync as Ye,readFileSync as z,realpathSync as ze}from"fs";import{resolvePackageEntry as Ve}from"./packageEntry.js";import{tmpdir as Xe}from"os";import{randomBytes as Qe}from"crypto";import{createRequire as pe}from"module";import{pathToFileURL as Ze}from"url";import{createEnv as ke}from"./env.js";import{resetKeys as we,assignKeys as _e,mapKeysToElements as je}from"./keys.js";import{extractMetadata as ue,generateHeadHtml as et}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as tt}from"./shell.js";import{trimSpriteToPage as ot,classRulesForPage as nt,markupClasses as st,trimVariablesToPage as rt}from"./pageWeight.js";import{fetchSSRTranslations as ct}from"./prefetch.js";import{createEarlySeedScript as at}from"@symbo.ls/fetch";import{headerEntries as it}from"@symbo.ls/fetch/rest";import{brenderStampMeta as lt,escapeRegExp as ft,jsonForScript as pt,libraryPackageSpecs as ut,polyglotFallbackLang as te,polyglotLangStorageKey as mt,polyglotAddressLang as dt,polyglotStartupScript as gt}from"@symbo.ls/utils";import{brenderRegistryBlock as ht,brenderRegistryTreeBlock as yt}from"@symbo.ls/utils/server";let oe=null;const bt=async()=>{if(oe)return oe;try{return oe=(await import("@symbo.ls/funcql")).funcqlPlugin,oe}catch{return null}};import"linkedom";import{createEarlySeedBlock as St}from"@symbo.ls/fetch";import{reset as Rt}from"@symbo.ls/css";const ne=(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},se=(e,t)=>te(e?.lang,t),xe=(e,t,o,n)=>{if(o?.translations){const r=o.translations[t];if(r){const a=ne(r,e);if(a!==void 0)return a}}if(n?.translations){const r=n.translations[t];if(r){const a=ne(r,e);if(a!==void 0)return a}}const s=te(void 0,o);if(s!==t&&o?.translations){const r=o.translations[s];if(r){const a=ne(r,e);if(a!==void 0)return a}}},kt=function(e,t){if(!e)return"";const o=this?.context,n=o?.polyglot,s=this?.state?.root||o?.state?.root,r=xe(e,t||se(s,n),n,s);if(r!==void 0)return r;const a=he(ge);return n&&a&&a.labelKeys.add(e),e},Te=function(){return se(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 n=[];t.set(e,n);for(const s of e)n.push(typeof s=="object"&&s!==null?$(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?$(s,t):s}return o};let O=null;try{import.meta.url&&(O=pe(import.meta.url))}catch{}const wt=()=>{if(!import.meta.url||!O)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:l=>l};const e=ze(new URL(".",import.meta.url).pathname),t=m(e,"../..");if(b(m(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let n;try{const l=O.resolve("smbls/package.json");n=E(l)}catch{let l=e;for(;l!==E(l);){const h=m(l,"node_modules","smbls");if(b(m(h,"package.json"))){n=h;break}l=E(l)}}let s=O;if(n)try{s=pe(m(n,"package.json"))}catch{}let r,a=process.cwd();for(;a!==E(a);){if(b(m(a,"package.json"))){r=a;break}a=E(a)}let p=s;if(r)try{p=pe(m(r,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:n,brenderDir:e,projectRoot:r,_smblsRequire:s,_projectRequire:p}},G=(e,t)=>{const o=e.isMonorepo?[O]:[e._smblsRequire,e._projectRequire,O].filter(Boolean);for(const n of o)try{return n.resolve(t)}catch{}return null},Fo=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages",t,...o);const n=G(e,`${t}/package.json`);return n?m(E(n),...o):null},Bo=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"plugins",t,...o);const n=G(e,`@symbo.ls/${t}/package.json`);return n?m(E(n),...o):null},me=(e,t,...o)=>{if(e.isMonorepo){for(const s of["packages","plugins"]){const r=m(e.monorepoRoot,s,t,...o);if(b(r))return r}return null}const n=G(e,`@symbo.ls/${t}/package.json`);return n?m(E(n),...o):null},Ee=(e,t,...o)=>{if(e.isMonorepo)return m(e.monorepoRoot,"packages","domql","packages",t,...o);const n=G(e,`@symbo.ls/${t}/package.json`);return n?m(E(n),...o):null};let re=null;const ve="smbls/ssr",_t=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},Le=()=>(re||(re=jt().catch(e=>{throw re=null,e})),re),jt=async()=>{const e=wt();let t;if(O&&e.isMonorepo)t=m(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let f;try{return await _t()}catch(i){f=i}if(!O)throw new Error(`brender: ${ve} 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&&m(e.smblsRoot,"src","createDomql.js");if(c&&b(c))t=c;else throw new Error(`brender: cannot load ${ve} (${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=Je(Xe(),`br_createDomql_${Qe(6).toString("hex")}.mjs`),s=Ve,r=e.isMonorepo?await import(Ze(m(e.monorepoRoot,"scripts","vite-workspace-source.mjs")).href):null,a=r?new Set(r.workspacePackageRoots().map(f=>r.workspacePackageAt(f).name)):null,p=/^(?:smbls(?:\/.*)?|domql|css-in-props(?:\/.*)?|@symbo\.ls\/[^/]+)$/,l={name:"workspace-resolve",setup(f){r&&(f.onResolve({filter:/^[^./]/},c=>{if(p.test(c.path))return;const i=c.path.split("/"),u=c.path.startsWith("@")?i.slice(0,2).join("/"):i[0];if(!a.has(u))return;const g=r.resolveWorkspaceSource(c.path,c.importer||t);return g?{path:g}:{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 i=c.path.replace(/^smbls\/?/,""),u=e.isMonorepo?m(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!u)return;if(!i){const x=s(u);return x?{path:x}:void 0}const g=m(u,i);if(b(g))return{path:g};if(b(g+".js"))return{path:g+".js"};const y=m(g,"index.js");if(b(y))return{path:y}}),f.onResolve({filter:/^domql$/},c=>{if(e.isMonorepo){const i=m(e.monorepoRoot,"packages","domql","src","index.js");if(b(i))return{path:i};const u=m(e.monorepoRoot,"packages","domql","index.js");if(b(u))return{path:u}}else try{const i=_require.resolve("domql/package.json"),u=s(E(i));if(u)return{path:u}}catch{}}),f.onResolve({filter:/^@symbo\.ls\//},c=>{const i=c.path.replace("@symbo.ls/","");if(i==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const g of["packages","plugins"]){const y=m(e.monorepoRoot,g,i,"src","index.js");if(b(y))return{path:y};const x=m(e.monorepoRoot,g,i,"index.js");if(b(x))return{path:x}}const u=m(e.monorepoRoot,"packages","default-config","blank","index.js");if(i==="default-config"&&b(u))return{path:u}}else{const u=me(e,i,"src","index.js");if(u&&b(u))return{path:u};const g=me(e,i,"index.js");if(g&&b(g))return{path:g};if(i==="default-config"){const y=me(e,"default-config","blank","index.js");if(y&&b(y))return{path:y}}}}),f.onResolve({filter:/^@domql\//},c=>{const i=c.path.replace("@symbo.ls/","");if(e.isMonorepo){const u=m(e.monorepoRoot,"packages","domql","packages",i,"src","index.js");if(b(u))return{path:u};const g=m(e.monorepoRoot,"packages","domql","packages",i,"index.js");if(b(g))return{path:g}}else{const u=Ee(e,i,"src","index.js");if(u&&b(u))return{path:u};const g=Ee(e,i,"index.js");if(g&&b(g))return{path:g}}}),f.onResolve({filter:/^css-in-props/},c=>{let i;if(e.isMonorepo)i=m(e.monorepoRoot,"packages","css-in-props");else{const y=G(e,"css-in-props/package.json");y&&(i=E(y))}if(!i)return;const u=c.path.replace(/^css-in-props\/?/,"");if(u){const y=m(i,u),x=m(y,"index.js");if(b(x))return{path:x};if(b(y+".js"))return{path:y+".js"};if(b(y))return{path:y}}const g=s(i);if(g)return{path:g}}),f.onResolve({filter:/^@emotion\//},c=>{let i;if(e.isMonorepo)i=m(e.monorepoRoot,"node_modules",c.path);else{const u=G(e,`${c.path}/package.json`);if(!u)return;i=E(u)}if(b(i)){const u=m(i,"package.json");if(b(u))try{const g=JSON.parse(z(u,"utf8")),y=g.module||g.main||"dist/emotion-css.esm.js";return{path:m(i,y)}}catch{}return{path:i}}}),f.onResolve({filter:/\.json$/},c=>{if(c.resolveDir){const i=m(c.resolveDir,c.path);if(b(i))return{path:i}}}),f.onLoad({filter:/smbls\/.*options\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("options.js"))return;let i=z(c.path,"utf8");return i=i.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),i=i.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:i,loader:"js"}}),f.onLoad({filter:/smbls\/.*init\.js$/},async c=>{if(!c.path.includes("smbls/")||!c.path.endsWith("init.js"))return;let i=z(c.path,"utf8");return i=i.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:i,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 i=z(c.path,"utf8");return i=i.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:i,loader:"js"}}),f.onLoad({filter:/fetchOnCreate\.js$/},async c=>{if(!c.path.includes("smbls/"))return;let i=z(c.path,"utf8");return i=i.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:i,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:n,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 h=await import(`file://${n}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",n);else try{Ye(n)}catch{}return h},xt={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"}},Tt=(e,t)=>{const o={};return $e(e,(n,s)=>{if(!s.__brKey)return;const r=t(n);o[r===""?"__root":r]=s.__brKey}),o},$e=(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)},Et=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let N=0;const De=Symbol.for("brender.fetchTracked"),de=()=>N,vt=256*1024,Lt=1024*1024,$t=new Set(["accept-language","accept"]),Ae={renders:0,record:null},Dt=50,ge={renders:0,record:null},Ce=(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)}}},he=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]}},ye=(e,t,o)=>{!e||e.tainted||e.failures.length>=Dt||e.failures.push({url:At(t),reason:o})},qe=e=>e&&typeof e=="object"&&typeof e.url=="string"?e.url:String(e),Ct=e=>{const[t,o]=e,n=t&&typeof t=="object"&&typeof t.url=="string",s=qe(t),r=String(o&&o.method||n&&t.method||"GET").toUpperCase(),a={},p=l=>{if(!l)return;const h=!Array.isArray(l)&&typeof l.entries!="function";for(const[f,c]of it(l))h&&c==null||(a[String(f).toLowerCase()]=String(c))};return n&&p(t.headers),o&&p(o.headers),{url:s,method:r,headers:a}},qt=(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(a=>{e.tainted||a.length>vt||e.bytes+a.length>Lt||(e.bytes+=a.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:s,body:a}))},()=>{}))},Mt=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[De])return;const t=function(...o){N++;let n=!1;const s=()=>{n||(n=!0,N--)},r=c=>{N++,c.then(()=>{N--},()=>{N--})},a=he(Ae),p=he(ge);let l=null;if(a)try{l=Ct(o),(l.method!=="GET"||!/^https?:/i.test(l.url)||Object.keys(l.headers).some(c=>!$t.has(c)))&&(l=null)}catch{l=null}const h=()=>qe(o[0]);let f;try{f=e.apply(this,o)}catch(c){throw ye(p,h(),c&&c.message||"failed"),s(),c}return f&&typeof f.then=="function"?f.then(c=>{l&&qt(a,l,c,r),p&&c&&c.ok===!1&&ye(p,h(),"HTTP "+c.status),s()},c=>{ye(p,h(),c&&c.message||"network error"),s()}):s(),f};t[De]=!0,globalThis.fetch=t},Ko=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const n=pt(e);return o?`<script>window.__BR_REGISTRY__=${n};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
2
- `+at(t):""):`<script>window.__BR_REGISTRY__=${n}<\/script>`},Ot=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=ut(e())}catch{return}for(const[r]of s)!o.has(r)&&Object.prototype.hasOwnProperty.call(n,r)&&Reflect.deleteProperty(n,r)}},Pt=3e4,It=2147483647;let Me=Promise.resolve();const Oe=()=>{},Ft=e=>{const t=Me.then(e);return Me=t.then(Oe,Oe),t},Bt=e=>{if(e===void 0)return Pt;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,It)},Kt=(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},Gt=e=>{e.closed=!0;for(const t of e.undo.splice(0))t()},Nt=e=>{let t=!1;return()=>{t||(t=!0,e())}},Pe=(e,t={})=>{let o;try{o=Bt(t.timeout)}catch(n){return Promise.reject(n)}return Ft(()=>Ht(e,t,o))},Ht=async(e,t,o)=>{await Le();const n={closed:!1,undo:[]},s=Ut(e,t,n);if(!o)return s;let r;const a=new Promise((p,l)=>{r=setTimeout(()=>{Gt(n),l(Kt(t,o))},o)});try{return await Promise.race([s,a])}finally{clearTimeout(r)}},Ut=async(e,t,o)=>{const{route:n="/",pathname:s,state:r,context:a,prefetch:p=!1}=t,l=s||n;Mt();const h=Ce(ge,()=>({failures:[],labelKeys:new Set,tainted:!1}));try{return await Wt(e,{route:n,locationPath:l,stateOverrides:r,contextOverrides:a,prefetch:p},h.record,o)}finally{h.close()}},Wt=async(e,{route:t,locationPath:o,stateOverrides:n,contextOverrides:s,prefetch:r},a,p)=>{const l=()=>{if(p.closed)throw new Error("brender: this render was abandoned at its timeout")};let h;if(r){try{h=await ct(e)}catch(y){p.closed||console.warn("[brender] SSR translation fetch failed:",y.message)}l()}const{window:f,document:c}=ke(),i=c.body;f.location.pathname=o;let u=null;const g=[ce("document",c),ce("location",f.location),ce("localStorage",f.localStorage),ce("sessionStorage",f.sessionStorage),Ot(()=>u&&u.sharedLibraries)].map(Nt);p.undo.push(...g);try{const{createDomqlElement:y,PRERENDER_REGISTRY_FORMATS:x}=await Le();l();const ie=$(e.app||{}),j={...e.config||{}};e.polyglot&&!j.polyglot&&(j.polyglot=e.polyglot),e.fetch&&!j.fetch&&(j.fetch=e.fetch),e.router&&!j.router&&(j.router=e.router);for(const R of Qt)e[R]!=null&&j[R]==null&&(j[R]=e[R]);const w=j.polyglot?{...j.polyglot}:void 0,H=dt(o,w);H&&f.localStorage.setItem(mt(w),H),h&&w&&(w.translations={...w.translations||{},...h});const T=$(e.state||{});(h||w)&&(T.root||(T.root={}),w&&(T.root.lang=te(T.root.lang,w)),h&&(T.root.translations={...T.root.translations||{},...h})),Rt();const V={};for(const R in e){if(Et.has(R))continue;const d=e[R];V[R]=d&&typeof d=="object"?$(d):d}const v={...V,state:T,...n?{state:{...T,...n}}:{},dependencies:$(e.dependencies||{}),components:$(e.components||{}),snippets:$(e.snippets||{}),pages:$(e.pages||{}),functions:{...e.functions||{},polyglot:kt,getActiveLang:Te,getLang:Te},methods:e.methods||{},designSystem:$(e.designSystem||{}),files:e.files||{},sharedLibraries:e.sharedLibraries||[],...j,...w?{polyglot:w}:{},document:c,window:f,parent:{node:i},initOptions:{},domqlOptions:{sourcemap:!1},firstRender:!1,sync:!1,inspect:!1,notifications:!1,isolateDesignSystem:!0,isolateFetchCache:!0,captureDesignSystem:!0,...s||{}};u=v;const S=await bt();l(),S&&(v.plugins=v.plugins||[],v.plugins.some(R=>R.name==="funcql")||v.plugins.push(S)),we();const P=Ce(Ae,()=>({entries:[],bytes:0,tainted:!1})),K=P.record;let k;try{k=await y(ie,v),l();const R=Date.now(),d=r?2e3:50,_=D=>new Promise(fe=>setTimeout(fe,D));for(await _(Math.min(50,d));r&&!p.closed&&de()>0&&Date.now()-R<d;)await _(10),de()===0&&await _(Math.max(0,Math.min(50,d-(Date.now()-R))));if(l(),r&&await Jt(k,w)){l();const D=Date.now();for(await _(Math.min(50,d));!p.closed&&de()>0&&Date.now()-D<d;)await _(10);l()}}finally{P.close()}const U=K&&!K.tainted&&!(j.fetch&&j.fetch.seed===!1)?K.entries.slice():[];_e(i);const W=je(k),{elementPath:X}=await import("@symbo.ls/element");l();const J=Tt(k,X),Q=k?.context?.routerOptions?.contentElementKey||"content",L=k&&k[Q],Re=L&&typeof L=="object"&&L.__ref?L:void 0,Z=ue(e,t,k,k?.state,Re),A=[],Y=c.head||c.querySelector("head");if(Y)for(const R of Y.querySelectorAll("style")){if(R.sheet&&R.sheet.cssRules)for(const d of R.sheet.cssRules)d.cssText&&A.push(d);if(!A.length){const d=R.textContent||"";d&&A.push({cssText:d})}}const ee=A.map(R=>R.cssText),{globalCSS:le,classRules:I}=so(A);let C=Be(i.innerHTML);const F=k?.state?.root,q=se(F,w),M=Yt(h,F);M&&(C=Fe(C,Ie(M,q,w)));const B=a&&!a.tainted?{failedRequests:a.failures.slice(),rawLabelKeys:Xt(a.labelKeys,C,q,w,F)}:null;return{html:C,metadata:Z,registry:W,brRegistry:J,element:k,emotionCSS:ee,globalCSS:le,classRules:I,fetchSeed:U,document:c,window:f,ssrTranslations:M||void 0,activeLang:q,diagnostics:B,preparedDesignSystem:v.preparedDesignSystem||null,registryFormats:Array.isArray(x)?x.slice():["paths"]}}finally{for(const y of g)y()}},ce=(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]})},Jt=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=se(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},be=/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,Se=e=>e&&typeof e.parse=="function"?e.parse():e,Yt=(e,t)=>{const o=Se(t?.translations),n={};for(const s of[e,o])if(!(!s||typeof s!="object"))for(const r in s){const a=Se(s[r]);a&&typeof a=="object"&&(n[r]={...n[r]||{},...a})}return Object.keys(n).length?n:null},Ie=(e,t,o)=>e[t]||e[te(void 0,o)]||Object.values(e)[0]||{},Fe=(e,t)=>e.replace(be,(o,n)=>ne(t,n.trim())??o),zt=/<script\b[^>]*\btype\s*=\s*["']?application\/json["']?[^>]*>[\s\S]*?<\/script\s*>/gi,Vt=(e,t)=>new RegExp(`(?:^|[^\\w.-])${ft(t)}(?![\\w-]|\\.\\w)`).test(e),Xt=(e,t,o,n,s)=>{const r=new Set,a=t.replace(zt,"");for(const p of e)/\s/.test(p)||xe(p,o,n,s)===void 0&&Vt(a,p)&&r.add(p);for(const p of a.matchAll(be))r.add(p[1].trim());return[...r]},Go=async(e,t={})=>{const{context:o={}}=t,{window:n,document:s}=ke(),r=s.body,{create:a}=await import("@symbo.ls/element"),p=await import("@symbo.ls/utils"),l={...xt,...o.components||{}},h={...p,...o.utils||{},...o.functions||{}};we();let f;try{f=a(e,{node:r},"root",{context:{document:s,window:n,...o,components:l,utils:h}})}catch{}_e(r);const c=f?je(f):{};return{html:Be(r.innerHTML),registry:c,element:f}},Be=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}),Qt=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],Zt=new Set(["auto","system"]),Ke=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||Zt.has(s)?null:s},eo=e=>String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;"),to=/\.[A-Za-z_\\-]/,oo=e=>{if(typeof e!="string"||!e)return!1;const t=e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]");return!to.test(t)},no=/^\s*(:root|\[data-theme|\[data-skin)/,Ge=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 oo(e.selectorText)?no.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(Ge));return n.has(null)||n.size!==1?n.has(null)?null:"reset":[...n][0]}return null},Ne=e=>typeof e=="string"&&/^\s*@font-face\b/i.test(e),so=e=>{const t={root:[],reset:[],keyframes:[]},o=[];for(const n of e||[]){const s=Ge(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 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(`
3
3
  `),resetRules:t.reset.join(`
4
4
  `),keyframeRules:t.keyframes.join(`
5
- `),fontFaceCSS:""},classRules:o}};let ae=new Set;const No=()=>{ae=new Set},Ho=()=>Array.from(ae).join(`
6
- `),Uo=(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 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">
7
7
  ${t}
8
- </style>`:""),Wo=async(e,t={})=>{const{route:o="/",pathname:n,prefetch:s=!0,timeout:r}=t,a=await Pe(e,{route:o,pathname:n,prefetch:s,timeout:r});if(!a)return null;const p=e.designSystem||{},l=a.globalCSS;let h=null;try{const c=ro(a.element);Object.keys(c).length&&(h=c)}catch{}const f=a.activeLang;return{html:a.html,css:a.classRules.join(`
9
- `),classRules:a.classRules.slice(),globalCSS:l,resetCss:l.resetRules,fontLinks:Ue(p),metadata:a.metadata||ue(e,o),brKeyCount:a.registry?Object.keys(a.registry).length:0,brRegistry:a.brRegistry||{},fetchSeed:a.fetchSeed||[],ssrTranslations:a.ssrTranslations,prefetchedState:h,activeLang:f,theme:Ke(e),diagnostics:a.diagnostics,preparedDesignSystem:a.preparedDesignSystem||null}},ro=e=>{const t={};return $e(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 a=r.startsWith("~/"),p=a?r.slice(2):r,l=a?o.state.root:o.state,h=Se(l&&l[p]);p&&h!=null&&typeof h!="function"&&(t[p]=h)}}),t},Jo=async(e,t="/",o={})=>{const{lang:n,themeColor:s,isr:r,hydrate:a=!0,prefetch:p=!0,shell:l,adoptDom:h=!1,pathname:f,eagerImages:c=He,preloadScripts:i=!0,nonce:u,timeout:g,stamp:y,time:x,spriteIcons:ie="all",cssClasses:j="all",cssVariables:w="all",registryFormat:H="paths"}=o,T=po(u),V=n||e.state?.lang||e.app?.metadata?.lang||"en",v=Ke(e),S=await Pe(e,{route:t,pathname:f,prefetch:p,timeout:g});if(!S)return null;const P={...S.metadata};if(s&&(P["theme-color"]=s),typeof l=="string"&&!e.name){const d="\0brender-undeclared-title\0";if(ue({...e,name:d},t,S.element,S.element?.state).title===d)for(const D of["title","og:title","twitter:title"])P[D]===S.metadata.title&&delete P[D]}const K=et(P);for(const d of S.classRules)d&&ae.add(d);let k=io(S.html,c);ie==="page"&&(k=ot(k,typeof l=="string"?l:"").html);const U=Array.from(ae),W=U.filter(Ne),X=W.length?U.filter(d=>!Ne(d)):U,J=j==="page"?nt(X,st(k,typeof l=="string"?l:"")).join(`
10
- `):X.join(`
11
- `),Q=W.length?`<style data-smbls-faces>
12
- ${W.join(`
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(`
10
+ `):te.join(`
11
+ `),I=U.length?`<style data-smbls-faces>
12
+ ${U.join(`
13
13
  `)}
14
- </style>`:"",L=S.globalCSS,Z=`<style data-brender>
15
- ${(w==="page"?rt(L.rootRule||"",L.resetRules,L.keyframeRules,J,k,typeof l=="string"?l:"").css:L.rootRule)||""}
16
- ${L.resetRules||""}
17
- ${L.keyframeRules||""}
18
- </style>`,A=J?`<style data-emotion="smbls">
19
- ${J}
20
- </style>`:"",Y=Ue(e.designSystem||{}),ee=Object.keys(S.registry).length,le=H==="tree"||H==="auto"&&(S.registryFormats||[]).includes("tree"),I=lo({brRegistry:S.brRegistry,fetchSeed:S.fetchSeed,adoptDom:h,stamp:y,time:x,registryFormat:le?"tree":"paths"});let C="";if(r&&r.clientScript){const d=Number.isInteger(o.depth)?o.depth:t==="/"?0:t.replace(/^\/|\/$/g,"").split("/").length,_=d>0?"../".repeat(d):"./";if(a){const D=gt({polyglot:e.polyglot||e.config?.polyglot,translations:S.ssrTranslations,lang:S.activeLang,pathname:f||t,attrs:T}),fe=D?D+`
21
- `:"",We=I.blocks?I.blocks+`
22
- `:"";C=`${fe}${We}<script type="module" src="${_}${r.clientScript}"${T}><\/script>`}else C=`<script type="module"${T}>
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)||""}
16
+ ${C.resetRules||""}
17
+ ${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+`
21
+ `:"",re=v.blocks?v.blocks+`
22
+ `:"";F=`${D}${re}<script type="module" src="${b}${r.clientScript}"${x}><\/script>`}else F=`<script type="module"${x}>
23
23
  {
24
24
  const brEls = document.querySelectorAll('body > :not(script):not(style)')
25
25
  const observer = new MutationObserver((mutations) => {
@@ -36,23 +36,29 @@ ${J}
36
36
  observer.observe(document.body, { childList: true })
37
37
  }
38
38
  <\/script>
39
- <script type="module" src="${_}${r.clientScript}"${T}><\/script>`}const F={...e.config||{}};e.polyglot&&!F.polyglot&&(F.polyglot=e.polyglot);const q=F.polyglot;let M=K;if(q){const d={...q.translations||{}};for(const _ in S.ssrTranslations||{})d[_]={...d[_]||{},...S.ssrTranslations[_]};M=Fe(K,Ie(d,S.activeLang,q))}const B=S.diagnostics;if(B)for(const d of M.matchAll(be)){const _=d[1].trim();B.rawLabelKeys.includes(_)||B.rawLabelKeys.push(_)}return typeof l=="string"?{html:tt(l,{headTags:`${M}
40
- ${I.meta}`,headEnd:[Y,Q,Z,A].filter(Boolean).join(`
41
- `),body:k,depth:Number.isInteger(o.depth)?o.depth:0,bootScripts:I.blocks,lang:n||(q?S.activeLang:void 0),theme:v,preloadScripts:i}),route:t,brKeyCount:ee,shell:!0,diagnostics:B,preparedDesignSystem:S.preparedDesignSystem||null}:{html:`<!DOCTYPE html>
42
- <html lang="${V}"${v?` data-theme="${eo(v)}"`:""}>
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)}"`:""}>
43
44
  <head>
44
- ${M}${r&&r.clientScript&&a?`
45
- ${I.meta}`:""}
46
- ${Y}
47
- ${Q}
48
- ${Z}
49
- ${A}
45
+ ${N}${r&&r.clientScript&&i?`
46
+ ${v.meta}`:""}
47
+ ${oe}
48
+ ${I}
49
+ ${M}
50
+ ${J}
50
51
  </head>
51
52
  <body>
52
- ${k}
53
- ${C}
53
+ ${$}${P?`
54
+ ${Xe}`:""}
55
+ ${F}
54
56
  </body>
55
- </html>`,route:t,brKeyCount:ee,diagnostics:B,preparedDesignSystem:S.preparedDesignSystem||null}},He=2,co=/<img\b(?:[^>"']|"[^"]*"|'[^']*')*>/gi,ao=/\sloading\s*=/i,io=(e,t=He)=>{if(t===!1||t==null||typeof e!="string")return e;const o=Math.max(0,Number(t)||0);let n=0;return e.replace(co,s=>n++<o||ao.test(s)?s:s.replace(/^<img\b/i,'<img loading="lazy"'))},Ue=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(`
56
- `):""},lo=({brRegistry:e,fetchSeed:t,adoptDom:o=!1,stamp:n,time:s,registryFormat:r="paths"}={})=>{const p=o&&e&&Object.keys(e).length?r==="tree"&&yt(e)||ht(e):"",l=St(t);return{meta:`<meta name="brender" content="${p?"hydrate":"replace"}">
57
- `+lt(fo(n,s)),blocks:[p,l].filter(Boolean).join(`
58
- `)}},fo=(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}},po=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{He as EAGER_IMAGES_DEFAULT,ve as SMBLS_SSR_SPECIFIER,Ko as adoptionScripts,fo as buildStamp,Ke as fixedThemeOf,Ho as getAccumulatedEmotionCSS,io as markLazyImages,lo as prerenderParts,Pe as render,Go as renderElement,Jo as renderPage,Wo as renderRoute,Uo as replaceEmotionCSS,No as resetGlobalCSSCache,so as splitCapturedCSS};
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)+`
59
+ `+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};
package/index.js CHANGED
@@ -7,6 +7,11 @@ import { collectBrNodes, hydrate } from './hydrate.js'
7
7
  import { generateSitemap } from './sitemap.js'
8
8
  import { prefetchPageData, injectPrefetchedState } from './prefetch.js'
9
9
  import { composeIntoShell } from './shell.js'
10
+ // The page-weight trims (XMA round 8), public for a caller that stores pages
11
+ // itself — @symbo.ls/cli's publish-time pre-render (helpers/ssrCache.js) —
12
+ // or trims a stored page as it serves it (stylesheetRules reads a stored
13
+ // stylesheet text back into the rules classRulesForPage takes).
14
+ import { trimSpriteToPage, classRulesForPage, markupClasses, trimVariablesToPage, stylesheetRules } from './pageWeight.js'
10
15
 
11
16
  export {
12
17
  createEnv,
@@ -32,7 +37,12 @@ export {
32
37
  composeIntoShell,
33
38
  adoptionScripts,
34
39
  prerenderParts,
35
- buildStamp
40
+ buildStamp,
41
+ trimSpriteToPage,
42
+ classRulesForPage,
43
+ markupClasses,
44
+ trimVariablesToPage,
45
+ stylesheetRules
36
46
  }
37
47
 
38
48
  export default {
@@ -59,5 +69,10 @@ export default {
59
69
  composeIntoShell,
60
70
  adoptionScripts,
61
71
  prerenderParts,
62
- buildStamp
72
+ buildStamp,
73
+ trimSpriteToPage,
74
+ classRulesForPage,
75
+ markupClasses,
76
+ trimVariablesToPage,
77
+ stylesheetRules
63
78
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/brender",
3
- "version": "3.14.674",
3
+ "version": "3.14.676",
4
4
  "license": "CC-BY-NC-4.0",
5
5
  "type": "module",
6
6
  "module": "./dist/esm/index.js",
@@ -48,16 +48,16 @@
48
48
  "dependencies": {
49
49
  "@symbo.ls/css": "^3.14.782",
50
50
  "@symbo.ls/default-config": "^3.14.789",
51
- "@symbo.ls/element": "^3.14.813",
52
- "@symbo.ls/fetch": "^3.14.669",
53
- "@symbo.ls/helmet": "^3.14.671",
51
+ "@symbo.ls/element": "^3.14.818",
52
+ "@symbo.ls/fetch": "^3.14.673",
53
+ "@symbo.ls/helmet": "^3.14.672",
54
54
  "@symbo.ls/scratch": "^3.14.795",
55
- "@symbo.ls/utils": "^3.14.851",
55
+ "@symbo.ls/utils": "^3.14.853",
56
56
  "esbuild": "^0.28.1",
57
57
  "linkedom": "^0.16.8"
58
58
  },
59
59
  "peerDependencies": {
60
- "smbls": "^3.14.856"
60
+ "smbls": "^3.14.859"
61
61
  },
62
62
  "optionalDependencies": {
63
63
  "@symbo.ls/funcql": "^3.14.0"
package/pageWeight.js CHANGED
@@ -25,6 +25,12 @@ const SPRITE_OPEN = /<svg\b[^>]*\sid="svgSprite"[^>]*>/
25
25
  const SYMBOL_AT = /\s*<symbol\b[^>]*>[\s\S]*?<\/symbol>/y
26
26
  const SPRITE_CLOSE_AT = /\s*<\/svg>/y
27
27
  const SYMBOL_ID = /^\s*<symbol\b[^>]*?\sid="([^"]+)"/
28
+ // Where the next symbol, or the sprite's end, starts.
29
+ const NEXT_PART = /<symbol\b|<\/svg>/g
30
+ // An element tag (a comment aside) — the sign of a sprite holding more than
31
+ // symbols and text, which the trim leaves alone.
32
+ const ELEMENT_TAG = /<\/?[A-Za-z]/
33
+ const COMMENT = /<!--[\s\S]*?-->/g
28
34
  // A fragment reference — `href="#x"`, `xlink:href="#x"`, `url(#x)` — or any
29
35
  // `#token`: a hex colour that happens to spell an icon's name keeps it, which
30
36
  // is the safe direction.
@@ -43,8 +49,11 @@ const fragmentsIn = (text, into) => {
43
49
  * symbols those reference). The client's design-system init adds every other
44
50
  * icon of the design system to the same sprite before the app is created, so
45
51
  * an icon the page shows later (after a click, on new data) is there when it
46
- * renders. Returns `html` unchanged when it has no sprite or the sprite holds
47
- * anything but symbols.
52
+ * renders. Text between the symbols (a library icon whose value is not an
53
+ * <svg> leaves it there — system/brand's stray `<>`) and comments are kept as
54
+ * they are and never end the walk: it stopped there, and system/landing's
55
+ * pages kept all 710 symbols (W7 B0). Returns `html` unchanged when it has no
56
+ * sprite or the sprite holds an element other than a symbol.
48
57
  * @param {string} html - the page's body markup
49
58
  * @param {string} [context] - other markup of the same document (the shell)
50
59
  * @returns {{ html: string, kept: number, dropped: number }}
@@ -57,18 +66,30 @@ export const trimSpriteToPage = (html, context = '') => {
57
66
  const start = open.index
58
67
  let at = start + open[0].length
59
68
  const symbols = []
69
+ // The sprite's content in order: each symbol, and the text between them.
70
+ const parts = []
60
71
  for (;;) {
61
72
  SYMBOL_AT.lastIndex = at
62
73
  const m = SYMBOL_AT.exec(html)
63
- if (!m) break
64
- const id = SYMBOL_ID.exec(m[0])
65
- symbols.push({ text: m[0], id: id ? id[1] : null })
66
- at = SYMBOL_AT.lastIndex
74
+ if (m) {
75
+ const id = SYMBOL_ID.exec(m[0])
76
+ const symbol = { text: m[0], id: id ? id[1] : null }
77
+ symbols.push(symbol)
78
+ parts.push(symbol)
79
+ at = SYMBOL_AT.lastIndex
80
+ continue
81
+ }
82
+ SPRITE_CLOSE_AT.lastIndex = at
83
+ if (SPRITE_CLOSE_AT.exec(html)) break
84
+ NEXT_PART.lastIndex = at
85
+ const next = NEXT_PART.exec(html)
86
+ // No end, or an element other than a symbol inside the sprite: left alone.
87
+ if (!next) return none
88
+ const text = html.slice(at, next.index)
89
+ if (ELEMENT_TAG.test(text.replace(COMMENT, ''))) return none
90
+ parts.push(text)
91
+ at = next.index
67
92
  }
68
- SPRITE_CLOSE_AT.lastIndex = at
69
- const close = SPRITE_CLOSE_AT.exec(html)
70
- // Something other than a symbol inside the sprite: left alone.
71
- if (!close) return none
72
93
  const end = SPRITE_CLOSE_AT.lastIndex
73
94
 
74
95
  const outside = html.slice(0, start) + html.slice(end)
@@ -87,9 +108,11 @@ export const trimSpriteToPage = (html, context = '') => {
87
108
  }
88
109
  // An anonymous symbol is kept: nothing can name it, but nothing proves it
89
110
  // unused either.
90
- const kept = symbols.filter((s) => !s.id || keep.has(s))
111
+ const isKept = (s) => !s.id || keep.has(s)
112
+ const kept = symbols.filter(isKept)
91
113
  if (kept.length === symbols.length) return { html, kept: kept.length, dropped: 0 }
92
- const sprite = open[0] + kept.map((s) => s.text).join('') + html.slice(at, end)
114
+ const content = parts.map((part) => typeof part === 'string' ? part : isKept(part) ? part.text : '').join('')
115
+ const sprite = open[0] + content + html.slice(at, end)
93
116
  return { html: html.slice(0, start) + sprite + html.slice(end), kept: kept.length, dropped: symbols.length - kept.length }
94
117
  }
95
118
 
@@ -185,6 +208,69 @@ export const classRulesForPage = (rules, classes) => {
185
208
  return out
186
209
  }
187
210
 
211
+ /**
212
+ * The rules of a stylesheet text, each as its own cssText — what
213
+ * classRulesForPage takes (a string there would be read a character at a
214
+ * time). A stored pre-render keeps a version's atomic rules as one text
215
+ * (@symbo.ls/cli helpers/ssrCache.js `__styles.css`, one rule per line), and
216
+ * the platform trims it to each route as it serves the route. Any layout
217
+ * reads alike, a rule over several lines or several rules on one line:
218
+ * strings, comments, escapes and parentheses are skipped, a comment between
219
+ * rules is dropped, and a statement at-rule (`@import …;`) is a rule of its
220
+ * own.
221
+ * @param {string} css
222
+ * @returns {string[]|null} the rules, in order; null for a text it cannot
223
+ * read whole (an unclosed block, string, comment or parenthesis, a stray
224
+ * `}` or `)`), so the caller keeps that text as it is
225
+ */
226
+ export const stylesheetRules = (css) => {
227
+ if (typeof css !== 'string') return null
228
+ const rules = []
229
+ let start = 0
230
+ let depth = 0
231
+ let parens = 0
232
+ let quote = null
233
+ const take = (end) => {
234
+ const rule = css.slice(start, end).trim()
235
+ if (rule) rules.push(rule)
236
+ start = end
237
+ }
238
+ for (let i = 0; i < css.length; i++) {
239
+ const ch = css[i]
240
+ if (quote) {
241
+ if (ch === '\\') i++
242
+ else if (ch === quote) quote = null
243
+ continue
244
+ }
245
+ if (ch === '\\') {
246
+ i++
247
+ continue
248
+ }
249
+ if (ch === '/' && css[i + 1] === '*') {
250
+ const close = css.indexOf('*/', i + 2)
251
+ if (close === -1) return null
252
+ // Between rules the comment is dropped; inside a rule it stays.
253
+ if (!depth && !parens && !css.slice(start, i).trim()) start = close + 2
254
+ i = close + 1
255
+ continue
256
+ }
257
+ if (ch === '"' || ch === "'") quote = ch
258
+ else if (ch === '(') parens++
259
+ else if (ch === ')') {
260
+ if (!parens) return null
261
+ parens--
262
+ } else if (parens) continue
263
+ else if (ch === '{') depth++
264
+ else if (ch === '}') {
265
+ if (!depth) return null
266
+ if (!--depth) take(i + 1)
267
+ } else if (ch === ';' && !depth) take(i + 1)
268
+ }
269
+ if (quote || depth || parens) return null
270
+ take(css.length)
271
+ return rules
272
+ }
273
+
188
274
  // ── The CSS variables (E7) ──────────────────────────────────────────────────
189
275
 
190
276
  const VAR_REF = /var\(\s*(--[\w-]+)/g
package/prefetch.js CHANGED
@@ -36,6 +36,14 @@ const resolveParams = (params, mockState) => {
36
36
  return params
37
37
  }
38
38
 
39
+ // Does a config run on create? `on` as @symbo.ls/fetch reads it: no value or
40
+ // an empty list is 'create'; a string is that trigger; a list runs on every
41
+ // trigger it names (`on: ['create', 'stateChange']` loads on create too).
42
+ const runsOnCreate = (on) => {
43
+ if (isArray(on)) return on.length === 0 || on.includes('create') || !on.some((t) => typeof t === 'string' && t)
44
+ return !on || on === 'create'
45
+ }
46
+
39
47
  /**
40
48
  * Normalize a single fetch declaration to a standard config object.
41
49
  */
@@ -58,7 +66,7 @@ const normalizeFetchConfig = (cfg, elementState) => {
58
66
  const isMutation = resolved.method === 'insert' || resolved.method === 'update' ||
59
67
  resolved.method === 'upsert' || resolved.method === 'delete'
60
68
  if (isMutation) return null
61
- if (resolved.on && resolved.on !== 'create') return null
69
+ if (!runsOnCreate(resolved.on)) return null
62
70
 
63
71
  return resolved
64
72
  }
@@ -270,8 +278,10 @@ export const fetchSSRTranslations = async (data) => {
270
278
  const fetchConfig = polyglot.fetch
271
279
  const rpcName = fetchConfig.rpc || fetchConfig.from || 'get_translations_if_changed'
272
280
  // `languages` may be a function (utils polyglotLanguages); none: the default
273
- const listed = (await import('@symbo.ls/utils')).polyglotLanguages(polyglot, false)
274
- const languages = listed.length ? listed : [polyglot.defaultLang || 'en']
281
+ const utils = await import('@symbo.ls/utils')
282
+ const listed = utils.polyglotLanguages(polyglot, false)
283
+ // `defaultLang` may be a function too (utils polyglotDefaultLang)
284
+ const languages = listed.length ? listed : [utils.polyglotFallbackLang(undefined, polyglot)]
275
285
 
276
286
  const translations = {}
277
287
 
package/render.js CHANGED
@@ -14,8 +14,12 @@ import { trimSpriteToPage, classRulesForPage, markupClasses, trimVariablesToPage
14
14
  import { fetchSSRTranslations } from './prefetch.js'
15
15
  import { createEarlySeedScript } from '@symbo.ls/fetch'
16
16
  import { headerEntries } from '@symbo.ls/fetch/rest'
17
- import { brenderStampMeta, escapeRegExp, jsonForScript, libraryPackageSpecs, polyglotFallbackLang, polyglotLangStorageKey, polyglotAddressLang, polyglotStartupScript } from '@symbo.ls/utils'
17
+ import { brenderStampMeta, brenderLazyMeta, escapeRegExp, jsonForScript, libraryPackageSpecs, polyglotFallbackLang, polyglotLangStorageKey, polyglotAddressLang, polyglotStartupScript } from '@symbo.ls/utils'
18
18
  import { brenderRegistryBlock, brenderRegistryTreeBlock } from '@symbo.ls/utils/server'
19
+ // Namespace import, read at call time: revivePolyglotDefaultLang is newer
20
+ // than this package's utils floor (a named import of a missing export fails
21
+ // the module at link time).
22
+ import * as utilsServer from '@symbo.ls/utils/server'
19
23
 
20
24
  // funcql plugin — enables evaluation of funcql schemas as property values
21
25
  // during SSR. Async-imported to avoid polluting non-funcql codepaths.
@@ -31,7 +35,7 @@ const getFuncqlPlugin = async () => {
31
35
  }
32
36
  }
33
37
  import { parseHTML } from 'linkedom'
34
- import { createEarlySeedBlock } from '@symbo.ls/fetch'
38
+ import { createEarlySeedBlock, fetchRunsOf } from '@symbo.ls/fetch'
35
39
  import { css, injectGlobal, reset as resetCss } from '@symbo.ls/css'
36
40
 
37
41
  // Lightweight SSR polyglot functions — resolve translations from context
@@ -56,6 +60,27 @@ const ssrResolve = (map, key) => {
56
60
  // SSR/hydrate text mismatches.
57
61
  const activeLangOf = (root, poly) => polyglotFallbackLang(root?.lang, poly)
58
62
 
63
+ // The payload as a server may hold it (frank JSON — mermaid's live render,
64
+ // any caller that does not revive it first): `polyglot.defaultLang` as a
65
+ // function's source TEXT. Revived once per render, before anything asks —
66
+ // the start language (smbls prepareState), activeLangOf, the labels, the
67
+ // prefetch — so the render is in the language the page starts in
68
+ // (@symbo.ls/utils/server revivePolyglotDefaultLang; text that cannot be
69
+ // compiled here stays text and counts as none, as before). The shared
70
+ // language helpers compile no text: they ride in every browser bundle.
71
+ const withRevivedDefaultLang = (data) => {
72
+ const revive = utilsServer.revivePolyglotDefaultLang
73
+ if (typeof revive !== 'function' || !data || typeof data !== 'object') return data
74
+ const top = data.polyglot ? revive(data.polyglot) : data.polyglot
75
+ const stored = data.config && data.config.polyglot
76
+ const inConfig = stored ? revive(stored) : stored
77
+ if (top === data.polyglot && inConfig === stored) return data
78
+ const out = { ...data }
79
+ if (top !== data.polyglot) out.polyglot = top
80
+ if (inConfig !== stored) out.config = { ...data.config, polyglot: inConfig }
81
+ return out
82
+ }
83
+
59
84
  // One label lookup, the order the client's translate() reads: static
60
85
  // translations, then the labels loaded into the root state, then the
61
86
  // default language's static ones. `undefined` when no table has the key.
@@ -1119,7 +1144,7 @@ const renderInTurn = async (data, options, timeout) => {
1119
1144
  }
1120
1145
 
1121
1146
  const renderOnce = async (data, options, turn) => {
1122
- const { route = '/', pathname, state: stateOverrides, context: contextOverrides, prefetch = false } = options
1147
+ const { route = '/', pathname, state: stateOverrides, context: contextOverrides, prefetch = false, lazyGroups } = options
1123
1148
  // pathname is the actual URL path (e.g. /podcast/abc-123), route is the page pattern (e.g. /podcast/:id)
1124
1149
  const locationPath = pathname || route
1125
1150
 
@@ -1127,13 +1152,13 @@ const renderOnce = async (data, options, turn) => {
1127
1152
  trackFetches()
1128
1153
  const diag = openRenderRecord(DIAG, () => ({ failures: [], labelKeys: new Set(), tainted: false }))
1129
1154
  try {
1130
- return await renderWithDiagnostics(data, { route, locationPath, stateOverrides, contextOverrides, prefetch }, diag.record, turn)
1155
+ return await renderWithDiagnostics(withRevivedDefaultLang(data), { route, locationPath, stateOverrides, contextOverrides, prefetch, lazyGroups }, diag.record, turn)
1131
1156
  } finally {
1132
1157
  diag.close()
1133
1158
  }
1134
1159
  }
1135
1160
 
1136
- const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides, contextOverrides, prefetch }, diag, turn) => {
1161
+ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides, contextOverrides, prefetch, lazyGroups }, diag, turn) => {
1137
1162
  // After every wait: a render abandoned at its timeout stops here (see
1138
1163
  // "One render at a time").
1139
1164
  const live = () => {
@@ -1217,7 +1242,9 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1217
1242
  }
1218
1243
 
1219
1244
  // Inject SSR translations into polyglot config and root state
1220
- const polyglotConfig = config.polyglot ? { ...config.polyglot } : undefined
1245
+ // `prefetch` (warm the other languages at idle) is for a visitor's
1246
+ // browser: a render loads its page's language only.
1247
+ const polyglotConfig = config.polyglot ? { ...config.polyglot, prefetch: false } : undefined
1221
1248
 
1222
1249
  // The address's language in this render's storage before the app starts,
1223
1250
  // as the browser has it (see "The address's language").
@@ -1231,20 +1258,14 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1231
1258
  }
1232
1259
  }
1233
1260
 
1261
+ // The project's state as declared. No `root` key of the render's own: the
1262
+ // language comes from polyglot's start language (smbls prepareState) and
1263
+ // the loaded labels are in `polyglotConfig.translations` (above). A
1264
+ // `root: { lang, translations }` written here never reached the state —
1265
+ // smbls merges state with mergeStateData, which keeps the store's
1266
+ // bookkeeping slots out — and made every build print the
1267
+ // `[smbls/state] … "root"` warning (XMA 3.14.857 audit, c7).
1234
1268
  const baseState = structuredCloneDeep(data.state || {})
1235
- // Ensure root state has lang and translations for polyglot resolution
1236
- if (ssrTranslations || polyglotConfig) {
1237
- if (!baseState.root) baseState.root = {}
1238
- if (polyglotConfig) {
1239
- baseState.root.lang = polyglotFallbackLang(baseState.root.lang, polyglotConfig)
1240
- }
1241
- if (ssrTranslations) {
1242
- baseState.root.translations = {
1243
- ...(baseState.root.translations || {}),
1244
- ...ssrTranslations
1245
- }
1246
- }
1247
- }
1248
1269
 
1249
1270
  // Reset the atomic CSS engine for this render pass
1250
1271
  resetCss()
@@ -1309,6 +1330,9 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1309
1330
  sync: false,
1310
1331
  inspect: false,
1311
1332
  notifications: false,
1333
+ // The app's `afterFirstView` (smbls create option) is for the visitor's
1334
+ // first view — an analytics beacon, a page view — never for a build.
1335
+ afterFirstView: null,
1312
1336
  // Every server render processes the design system the way the page's
1313
1337
  // own single boot does, on a config of its own — the first render of a
1314
1338
  // process used to share the global config and every later one took the
@@ -1328,8 +1352,22 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1328
1352
  // render returns it as `preparedDesignSystem`, and `smbls build` writes
1329
1353
  // it into one file each page preloads).
1330
1354
  captureDesignSystem: true,
1355
+ // `lazyGroups` (XMA question 6): a lazy route renders as its group's
1356
+ // real page, not its placeholder — @symbo.ls/router lazy.js "The first
1357
+ // view" (see lazyFirstViewOf).
1358
+ ...lazyFirstViewOf(lazyGroups),
1331
1359
  // Caller overrides
1332
- ...(contextOverrides || {})
1360
+ ...(contextOverrides || {}),
1361
+ // For app code: this code runs inside a server render. The server
1362
+ // document lays nothing out and observes nothing (no getComputedStyle,
1363
+ // no ResizeObserver / IntersectionObserver): an entrance motion that
1364
+ // hides an element until it scrolls into view stored the hidden state in
1365
+ // the page (W7 B0, system/landing: 34 blocks at `opacity: 0` on `/`).
1366
+ // App code reads `el.context.ssr === true` and renders the final state.
1367
+ // A browser has no such key; a client boot over a pre-rendered page has
1368
+ // `el.context.prerendered` (smbls prerender.js). Last, so no payload key
1369
+ // and no caller override makes a server render look like a browser.
1370
+ ssr: true
1333
1371
  }
1334
1372
  renderContext = ctx
1335
1373
 
@@ -1353,6 +1391,16 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1353
1391
  try {
1354
1392
  element = await createDomqlElement(app, ctx)
1355
1393
  live()
1394
+ // `lazyGroups`: the first navigation awaits its group before it renders
1395
+ // the route (@symbo.ls/router lazy.js "The first view") — the page is
1396
+ // in once that navigation is. Bounded by the render's own time limit.
1397
+ if (ctx.lazyFirstView) {
1398
+ const navigation = ((element && element.context) || ctx).__firstNavigation
1399
+ if (navigation && typeof navigation.then === 'function') {
1400
+ try { await navigation } catch (err) { /* the router reports its own errors */ }
1401
+ live()
1402
+ }
1403
+ }
1356
1404
 
1357
1405
  // Allow async operations (fetch callbacks, state updates, re-renders) to flush.
1358
1406
  // DOMQL's fetch plugin fires on element creation and updates state
@@ -1408,6 +1456,11 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1408
1456
  const { elementPath } = await import('@symbo.ls/element')
1409
1457
  live()
1410
1458
  const brRegistry = buildPathRegistry(element, elementPath)
1459
+ // Which queries each element ran (@symbo.ls/fetch fetchRunsOf), named by
1460
+ // the same paths: the page carries it beside the recorded answers, so a
1461
+ // part whose query ran after its create starts from that query's answer
1462
+ // when the browser takes it over (fetch "Queries the build ran later").
1463
+ const fetchRuns = fetchSeed.length ? fetchRunsOf((element && element.context) || ctx, elementPath) : {}
1411
1464
 
1412
1465
  // Extract metadata for the rendered route
1413
1466
  // Pass the rendered element and its state so function-valued metadata
@@ -1464,7 +1517,13 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1464
1517
  }
1465
1518
  : null
1466
1519
 
1467
- return { html, metadata, registry, brRegistry, element, emotionCSS, globalCSS, classRules, fetchSeed, document, window, ssrTranslations: labels || undefined, activeLang, diagnostics, preparedDesignSystem: ctx.preparedDesignSystem || null,
1520
+ // The lazy groups whose page this render's first view shows — awaited
1521
+ // (`lazyGroups`) or loaded during the render — as the router records them:
1522
+ // the page names them and `smbls build` preloads their chunks.
1523
+ const firstViews = ((element && element.context) || ctx).__lazyFirstViews
1524
+ const lazyGroupsShown = firstViews && typeof firstViews.forEach === 'function' ? [...firstViews] : []
1525
+
1526
+ return { html, metadata, registry, brRegistry, element, emotionCSS, lazyGroups: lazyGroupsShown, globalCSS, classRules, fetchSeed, fetchRuns, document, window, ssrTranslations: labels || undefined, activeLang, diagnostics, preparedDesignSystem: ctx.preparedDesignSystem || null,
1468
1527
  // the registry encodings the client of this smbls reads (smbls
1469
1528
  // prerender.js PRERENDER_REGISTRY_FORMATS); an older smbls reads paths
1470
1529
  registryFormats: Array.isArray(PRERENDER_REGISTRY_FORMATS) ? PRERENDER_REGISTRY_FORMATS.slice() : ['paths'] }
@@ -1473,6 +1532,25 @@ const renderWithDiagnostics = async (data, { route, locationPath, stateOverrides
1473
1532
  }
1474
1533
  }
1475
1534
 
1535
+ // ── Lazy routes built as their pages (XMA question 6) ──────────────────────
1536
+ // `lazyGroups: 'load'` — every lazy group a pre-rendered route names is
1537
+ // loaded in the render and the route renders as the group's page; an array
1538
+ // of group names does that for those groups only. Unset: the render does not
1539
+ // wait for a group — the route shows its group's page when the group loaded
1540
+ // during the render (its loader settled in time: a context that declares
1541
+ // `lazy`, `brender.context`), else its placeholder. The group's `when` is
1542
+ // asked as in the browser: false builds the placeholder. Either way a page
1543
+ // names the groups whose page it shows (`<meta name="brender-lazy">`), and
1544
+ // the browser's first navigation loads them before it adopts the page.
1545
+ const lazyFirstViewOf = (lazyGroups) => {
1546
+ if (lazyGroups === 'load' || lazyGroups === true) return { lazyFirstView: true }
1547
+ if (Array.isArray(lazyGroups)) {
1548
+ const names = lazyGroups.filter((g) => typeof g === 'string' && g)
1549
+ return names.length ? { lazyFirstView: names } : {}
1550
+ }
1551
+ return {}
1552
+ }
1553
+
1476
1554
  // Put `value` on globalThis[name] for a render and hand back what puts the
1477
1555
  // old property back, descriptor and all. Never reads the old value — a host
1478
1556
  // global can be a lazy accessor that warns or throws when read.
@@ -1616,7 +1694,8 @@ export const renderElement = async (elementDef, options = {}) => {
1616
1694
  let element
1617
1695
  try {
1618
1696
  element = create(elementDef, { node: body }, 'root', {
1619
- context: { document, window, ...context, components, utils }
1697
+ // `ssr: true` — a server render, as in render() above
1698
+ context: { document, window, ...context, components, utils, ssr: true }
1620
1699
  })
1621
1700
  } catch (err) {
1622
1701
  // Lifecycle events (onRender, onDone, etc.) may throw in SSR
@@ -1856,6 +1935,8 @@ export const renderRoute = async (data, options = {}) => {
1856
1935
  brRegistry: result.brRegistry || {},
1857
1936
  // anonymous GET answers this render got (see `SEED`) — for adoptionScripts
1858
1937
  fetchSeed: result.fetchSeed || [],
1938
+ // which queries each element ran (fetchRunsOf) — beside the seed
1939
+ fetchRuns: result.fetchRuns || {},
1859
1940
  ssrTranslations: result.ssrTranslations,
1860
1941
  prefetchedState,
1861
1942
  activeLang,
@@ -1952,10 +2033,13 @@ const collectFetchedState = (element) => {
1952
2033
  * `adoptDom`: the element-path registry as paths, as a tree (the same data
1953
2034
  * in a third of the bytes — @symbo.ls/utils/server encodeBrenderRegistry), or the
1954
2035
  * tree when the smbls the page renders with reads it
2036
+ * @param {{ whole?: boolean }} [options.paint] - `{ whole: true }`: the first
2037
+ * paint waits until the page's markup is in (see withWholePaint)
1955
2038
  * @returns {Promise<{ html: string, route: string, brKeyCount: number, shell?: true }>}
1956
2039
  */
1957
2040
  export const renderPage = async (data, route = '/', options = {}) => {
1958
- const { lang, themeColor, isr, hydrate = true, prefetch = true, shell, adoptDom = false, pathname, eagerImages = EAGER_IMAGES_DEFAULT, preloadScripts = true, nonce, timeout, stamp, time, spriteIcons = 'all', cssClasses = 'all', cssVariables = 'all', registryFormat = 'paths' } = options
2041
+ const { lang, themeColor, isr, hydrate = true, prefetch = true, shell, adoptDom = false, pathname, eagerImages = EAGER_IMAGES_DEFAULT, preloadScripts = true, nonce, timeout, stamp, time, spriteIcons = 'all', cssClasses = 'all', cssVariables = 'all', registryFormat = 'paths', lazyGroups, paint } = options
2042
+ const whole = paintsWhole(paint)
1959
2043
  const nonceAttr = nonceAttribute(nonce)
1960
2044
 
1961
2045
  // Detect lang from project config, app metadata, or default
@@ -1969,7 +2053,7 @@ export const renderPage = async (data, route = '/', options = {}) => {
1969
2053
  // canonical/og:url built from it read it. Without it a route was rendered
1970
2054
  // at its own pattern: the `/*` page wrote a `/*` canonical into 404.html
1971
2055
  // (xma.info report, brender build item 7).
1972
- const result = await render(data, { route, pathname, prefetch, timeout })
2056
+ const result = await render(data, { route, pathname, prefetch, timeout, lazyGroups })
1973
2057
  if (!result) return null
1974
2058
 
1975
2059
  const metadata = { ...result.metadata }
@@ -2056,7 +2140,7 @@ export const renderPage = async (data, route = '/', options = {}) => {
2056
2140
  // `registryFormat: 'auto'` — the tree when the smbls this page renders
2057
2141
  // with (the page's own client) reads it, else paths (XMA round 8, E13).
2058
2142
  const treeRegistry = registryFormat === 'tree' || (registryFormat === 'auto' && (result.registryFormats || []).includes('tree'))
2059
- const prerender = prerenderParts({ brRegistry: result.brRegistry, fetchSeed: result.fetchSeed, adoptDom, stamp, time, registryFormat: treeRegistry ? 'tree' : 'paths' })
2143
+ const prerender = prerenderParts({ brRegistry: result.brRegistry, fetchSeed: result.fetchSeed, fetchRuns: result.fetchRuns, adoptDom, stamp, time, registryFormat: treeRegistry ? 'tree' : 'paths', lazyGroups: result.lazyGroups })
2060
2144
 
2061
2145
  // ISR: include client SPA bundle for hydration + data fetching
2062
2146
  let isrBody = ''
@@ -2152,7 +2236,7 @@ export const renderPage = async (data, route = '/', options = {}) => {
2152
2236
  const html = composeIntoShell(shell, {
2153
2237
  headTags: `${resolvedHeadTags}\n${prerender.meta}`,
2154
2238
  headEnd: [fontLinks, facesStyle, brenderStyle, emotionStyle].filter(Boolean).join('\n'),
2155
- body: bodyHtml,
2239
+ body: whole ? bodyHtml + '\n' + WHOLE_MARKER : bodyHtml,
2156
2240
  depth: Number.isInteger(options.depth) ? options.depth : 0,
2157
2241
  bootScripts: prerender.blocks,
2158
2242
  // The page's language on <html>, as the client's polyglot sets it at
@@ -2162,7 +2246,7 @@ export const renderPage = async (data, route = '/', options = {}) => {
2162
2246
  theme: htmlTheme,
2163
2247
  preloadScripts
2164
2248
  })
2165
- return { html, route, brKeyCount, shell: true, diagnostics, preparedDesignSystem: result.preparedDesignSystem || null }
2249
+ return { html: whole ? withWholePaint(html) : html, route, brKeyCount, shell: true, diagnostics, preparedDesignSystem: result.preparedDesignSystem || null, lazyGroups: result.lazyGroups || [] }
2166
2250
  }
2167
2251
 
2168
2252
  // The line after the font links holds the page's @font-face rules in a
@@ -2177,12 +2261,49 @@ ${brenderStyle}
2177
2261
  ${emotionStyle}
2178
2262
  </head>
2179
2263
  <body>
2180
- ${bodyHtml}
2264
+ ${bodyHtml}${whole ? `\n${WHOLE_MARKER}` : ''}
2181
2265
  ${isrBody}
2182
2266
  </body>
2183
2267
  </html>`
2184
2268
 
2185
- return { html, route, brKeyCount, diagnostics, preparedDesignSystem: result.preparedDesignSystem || null }
2269
+ return { html: whole ? withWholePaint(html) : html, route, brKeyCount, diagnostics, preparedDesignSystem: result.preparedDesignSystem || null, lazyGroups: result.lazyGroups || [] }
2270
+ }
2271
+
2272
+ // ── The first paint waits for the whole markup (`paint: { whole: true }`) ───
2273
+ // A long page built ahead arrives in parts on a slow connection, and the
2274
+ // browser paints what it has parsed so far: the header and a part of the
2275
+ // first view, then the rest, which moves the parts below it in. With
2276
+ // `paint.whole` the page holds its first paint until its markup is in: a
2277
+ // `<link rel="expect" href="#smbls-whole" blocking="render">` right after the
2278
+ // charset declaration names an empty `<template id="smbls-whole">` that
2279
+ // follows the markup (before the page's data blocks and the app's scripts).
2280
+ // No script: a strict Content-Security-Policy does not block it. A browser
2281
+ // stops the hold when the element is parsed, and when the parser finishes
2282
+ // the document without one (HTML "expect" links: "unblock rendering" at the
2283
+ // end of parsing), so a page never stays blank. A browser without
2284
+ // `rel=expect` (Firefox, Safari in 2026) paints as before.
2285
+ export const WHOLE_MARKER_ID = 'smbls-whole'
2286
+ const WHOLE_MARKER = `<template id="${WHOLE_MARKER_ID}"></template>`
2287
+ const WHOLE_LINK = `<link rel="expect" href="#${WHOLE_MARKER_ID}" blocking="render">`
2288
+ // `paint: { whole: true }` (symbols.json / config.js `brender.paint`).
2289
+ export const paintsWhole = (paint) => !!(paint && typeof paint === 'object' && paint.whole === true)
2290
+ // The link after the charset declaration (a parser reads the charset in the
2291
+ // first 1024 bytes, so nothing goes ahead of it), else after the head's
2292
+ // opener, the html's, or the doctype.
2293
+ const CHARSET_META = /<meta\b[^>]*\bcharset\s*=[^>]*>/i
2294
+ const PAINT_OPENERS = [/<head\b[^>]*>/i, /<html\b[^>]*>/i, /^\s*<!doctype\b[^>]*>/i]
2295
+ export const withWholePaint = (html) => {
2296
+ if (typeof html !== 'string' || html.includes(WHOLE_LINK)) return html
2297
+ const charset = CHARSET_META.exec(html.slice(0, 1024))
2298
+ if (charset) {
2299
+ const end = charset.index + charset[0].length
2300
+ return html.slice(0, end) + '\n' + WHOLE_LINK + html.slice(end)
2301
+ }
2302
+ for (const opener of PAINT_OPENERS) {
2303
+ const m = opener.exec(html)
2304
+ if (m) return html.slice(0, m.index + m[0].length) + '\n' + WHOLE_LINK + html.slice(m.index + m[0].length)
2305
+ }
2306
+ return WHOLE_LINK + '\n' + html
2186
2307
  }
2187
2308
 
2188
2309
  // ── Images below the fold ───────────────────────────────────────────────────
@@ -2260,14 +2381,18 @@ const generateFontLinks = (ds) => {
2260
2381
  // `registryFormat: 'tree'` writes the registry as a tree (@symbo.ls/utils
2261
2382
  // encodeBrenderRegistry, XMA round 8, E13) — the same data, a third of the
2262
2383
  // bytes — in its own block; a registry that cannot be one stays paths.
2263
- export const prerenderParts = ({ brRegistry, fetchSeed, adoptDom = false, stamp, time, registryFormat = 'paths' } = {}) => {
2384
+ // `fetchRuns` — which queries each element ran (@symbo.ls/fetch
2385
+ // fetchRunsOf), carried in the seed block with the answers.
2386
+ export const prerenderParts = ({ brRegistry, fetchSeed, fetchRuns, adoptDom = false, stamp, time, registryFormat = 'paths', lazyGroups } = {}) => {
2264
2387
  const has = adoptDom && brRegistry && Object.keys(brRegistry).length
2265
2388
  const registry = has
2266
2389
  ? (registryFormat === 'tree' && brenderRegistryTreeBlock(brRegistry)) || brenderRegistryBlock(brRegistry)
2267
2390
  : ''
2268
- const seed = createEarlySeedBlock(fetchSeed)
2391
+ const seed = createEarlySeedBlock(fetchSeed, fetchRuns)
2269
2392
  return {
2270
- meta: `<meta name="brender" content="${registry ? 'hydrate' : 'replace'}">\n` + brenderStampMeta(buildStamp(stamp, time)),
2393
+ // `lazyGroups`: the groups whose pages the page was built with
2394
+ // (@symbo.ls/utils brenderLazyMeta) — none, no tag
2395
+ meta: `<meta name="brender" content="${registry ? 'hydrate' : 'replace'}">\n` + brenderStampMeta(buildStamp(stamp, time)) + (brenderLazyMeta(lazyGroups) ? '\n' + brenderLazyMeta(lazyGroups) : ''),
2271
2396
  blocks: [registry, seed].filter(Boolean).join('\n')
2272
2397
  }
2273
2398
  }