@webtypen/webframez-react 0.0.48 → 0.0.50

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/README.md CHANGED
@@ -491,3 +491,64 @@ Watch mode for package development:
491
491
  ```bash
492
492
  npm run build:watch
493
493
  ```
494
+
495
+ ## Persistent navigation in consuming applications
496
+
497
+ Use the host router's Link component for URLs. Keep the Suite renderer mounted
498
+ across paths inside one authorized project; do not add `key={path}` or conditionally
499
+ unmount it while reloading project context. Revalidate/reset the context when the
500
+ project changes, and continue enforcing authorization on every server request.
501
+ Only the page content resets for a new screen. The renderer retains its layout and
502
+ prior page while a same-project request is pending, with stale interactions disabled.
503
+
504
+ For webframez-react, configure the DOM link adapter at the host boundary:
505
+
506
+ ```tsx
507
+ import React from "react";
508
+ import { Link } from "@webtypen/webframez-react/navigation";
509
+
510
+ const SuiteLink = React.forwardRef<HTMLAnchorElement,
511
+ React.AnchorHTMLAttributes<HTMLAnchorElement>
512
+ >(function SuiteLink({ href, ...props }, ref) {
513
+ return <Link {...props} ref={ref} to={href || "#"} basename="" />;
514
+ });
515
+
516
+ // Inside an already authorized project context; paths are fully qualified.
517
+ <NativeDesignProvider
518
+ key={projectId}
519
+ suite={{ endpoint: "/manager", navigation: {
520
+ pathname, linkComponent: SuiteLink,
521
+ onNavigate: to => router.push(to),
522
+ } }}
523
+ >
524
+ <WebframezSuiteRenderer />
525
+ </NativeDesignProvider>
526
+ ```
527
+
528
+ Screen definitions remain JSON-serializable: links use `to`/`path`; React Link
529
+ components belong in the consuming application's adapter, never in server schemas.
530
+ See `AGENTS.md` for the navigation invariants and regression-test requirements.
531
+
532
+
533
+ ## Core router basename
534
+
535
+ With the updated Core router, set `application.router.basename` in the Core
536
+ configuration. `initWebframezReact(Route).renderReact("/", options)` inherits it;
537
+ no duplicate `basePath`, `assetsPrefix`, `rscPath`, `clientScriptUrl`, or
538
+ `Head.basename` is needed. Nested render routes and `Route.group` prefixes are
539
+ included in the runtime mount while build target names and directories stay
540
+ stable. Explicit external asset URLs remain unchanged. Without Core, the Node
541
+ handler still supports `basePath` and explicit transport URLs.
542
+
543
+ For API calls, form actions, raw links and redirects in shared/client code:
544
+
545
+ ```ts
546
+ import { appPath, appRelativePath, getBasename } from "@webtypen/webframez-react/paths";
547
+ fetch(appPath("/api/items"));
548
+ ```
549
+
550
+ These browser-safe helpers bundle Core's URL logic and read the runtime mount;
551
+ no server dependencies are included. `Link` and `Redirect` inherit it
552
+ implicitly. Server requests use an async-local context, and HTML rendering and
553
+ client navigation receive the same basename through the Flight head and HTML
554
+ shell. External URLs and already-prefixed URLs are preserved.
@@ -1,9 +1,12 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
- const ReactFlightWebpackPlugin = require("react-server-dom-webpack/plugin");
3
+ const { createRequire } = require("node:module");
4
4
  const { fileURLToPath, pathToFileURL } = require("url");
5
5
 
6
6
  const projectRoot = process.cwd();
7
+ const projectRequire = createRequire(path.join(projectRoot, "package.json"));
8
+ const ReactFlightWebpackPlugin = projectRequire("react-server-dom-webpack/plugin");
9
+ const reactDomRequire = createRequire(projectRequire.resolve("react-dom/package.json"));
7
10
  const frameworkDistDir = path.resolve(__dirname, "..", "dist");
8
11
  const clientEntry = process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY
9
12
  ? path.resolve(projectRoot, process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY)
@@ -266,7 +269,8 @@ module.exports = {
266
269
  "react-dom": path.resolve(projectRoot, "node_modules", "react-dom"),
267
270
  "react/jsx-runtime": path.resolve(projectRoot, "node_modules", "react", "jsx-runtime.js"),
268
271
  "react/jsx-dev-runtime": path.resolve(projectRoot, "node_modules", "react", "jsx-dev-runtime.js"),
269
- scheduler: path.resolve(projectRoot, "node_modules", "scheduler"),
272
+ // Resolve React DOM's own scheduler, including pnpm's isolated layout.
273
+ scheduler: path.dirname(reactDomRequire.resolve("scheduler/package.json")),
270
274
  },
271
275
  },
272
276
  watchOptions: {
package/dist/client.cjs CHANGED
@@ -1 +1 @@
1
- var le=Object.create;var E=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var me=Object.getOwnPropertyNames;var pe=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var ge=(e,t)=>{for(var n in t)E(e,n,{get:t[n],enumerable:!0})},$=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of me(t))!Re.call(e,r)&&r!==n&&E(e,r,{get:()=>t[r],enumerable:!(o=fe(t,r))||o.enumerable});return e};var D=(e,t,n)=>(n=e!=null?le(pe(e)):{},$(t||!e||!e.__esModule?E(n,"default",{value:e,enumerable:!0}):n,e)),he=e=>$(E({},"__esModule",{value:!0}),e);var qe={};ge(qe,{mountWebframezClient:()=>Ge,useCookie:()=>Be,useRouter:()=>He});module.exports=he(qe);var c=D(require("react"),1),J=require("react-dom/client"),h=require("react-server-dom-webpack/client"),Q=require("@webtypen/webframez-react/route-slot");var we=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function l(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function W(e,t){let n=e.trim(),o=l(t);return!n||!o||we.test(n)||n.startsWith("/")||o!=="/"&&(n===o||n.startsWith(`${o}/`))?n:o==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${o}${n}`:`${o}/${n}`}function P(e,t){if(!e)return;let n=l(e.basename)??l(t),o=l(e.routeBasePath),r=l(e.transportBasePath),i={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return i.favicon&&(i.favicon=W(i.favicon,n)),i.links&&(i.links=i.links.map(s=>({...s,href:W(s.href,n)}))),i}var m=D(require("react"),1),q="webframez-route-children",K="__webframezRouteChildren",Y="WebframezRouteChildren",_e="__webframezRouteChildrenSlot",ye="WebframezRouteChildrenSlot",L=()=>m.default.createElement(q);L.displayName=Y;L[K]=!0;var Ce=L;function F(e){if(e===q||e===Ce)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[K]===!0||t.displayName===Y||t.name==="RouteChildren"}catch{return!1}}function j(e){if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[_e]===!0||t.displayName===ye||t.name==="RouteChildrenSlot"}catch{return!1}}function G(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function T(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let u=!1,w=e.map(p=>{let R=T(p,t);return R!==p&&(u=!0),R});return u?w:e}if(G(e)&&(F(e.type)||j(e.type)))return t;let n=m.default.isValidElement(e);if(!n&&!G(e))return e;if(n&&(F(e.type)||j(e.type)))return t;let o=e.props??{};if(!("children"in o))return e;let r=T(o.children,t);if(r===o.children)return e;if(n)return Array.isArray(r)?m.default.cloneElement(e,void 0,...r):m.default.cloneElement(e,void 0,r);let i=e,s={...i.props??{},children:r,...i.key!==void 0&&i.key!==null?{key:i.key}:{}};return m.default.createElement(i.type,s)}var d=require("react/jsx-runtime"),Ee={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},N=typeof c.default.createContext=="function"?c.default.createContext(null):null,ee="__WEBFRAMEZ_ROUTER__",Te="__WEBFRAMEZ_REACT_BUILD_ID",Ne="x-webframez-react-build",Ae="[data-webframez-head='true']";function Z(){if(typeof window>"u"||typeof document>"u")return;let e=()=>{window.scrollTo({top:0,left:0}),document.scrollingElement&&(document.scrollingElement.scrollTop=0),document.documentElement.scrollTop=0,document.body&&(document.body.scrollTop=0)};if(typeof window.requestAnimationFrame=="function"){window.requestAnimationFrame(e);return}window.setTimeout(e,0)}function x(e){return l(e)??""}function Se(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function te(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function Pe(){return x(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function ne(e){if(typeof window>"u")return e||"/";let t=x(window.__RSC_BASENAME),n=Pe(),o=Se(e||"/",t);return te(n,o)}function oe(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function Le(){if(typeof window>"u")return"";let e=window[Te];return typeof e=="string"?e:""}function ve(e){let t=Le();return!!t&&!!e&&t!==e}function v(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function Ie(){return typeof window>"u"?null:window[ee]??null}function xe(e){typeof window>"u"||(window[ee]=e)}function be(e){return!!e&&(typeof e=="object"||typeof e=="function")&&typeof e.then=="function"}function ke(e){return be(e)?c.default.use(e):e}function A(e){let t=ke(e);if(Array.isArray(t)){let r=!1,i=t.map(s=>{let u=A(s);return u!==s&&(r=!0),u});return r?i:t}if(!c.default.isValidElement(t))return t;let n=t.props;if(!("children"in n))return t;let o=A(n.children);return o===n.children?t:Array.isArray(o)?c.default.cloneElement(t,void 0,...o):c.default.cloneElement(t,void 0,o)}function V(){let e={},t=typeof document>"u"?"":document.cookie;if(!t||t.trim()==="")return e;for(let n of t.split(";")){let o=n.trim();if(!o)continue;let r=o.indexOf("="),i=r>=0?o.slice(0,r).trim():o,s=r>=0?o.slice(r+1):"";i&&(e[i]=decodeURIComponent(s))}return e}function X(e,t,n={}){let o=[`${e}=${encodeURIComponent(t)}`];return n.path&&o.push(`Path=${n.path}`),n.domain&&o.push(`Domain=${n.domain}`),typeof n.maxAge=="number"&&o.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&o.push(`Expires=${n.expires.toUTCString()}`),n.sameSite&&o.push(`SameSite=${n.sameSite}`),n.secure&&o.push("Secure"),o.join("; ")}function Be(){return c.default.useMemo(()=>({all:()=>V(),get:e=>V()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=X(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=X(e,"",{...t??{},maxAge:0}))}}),[])}function He(){let e=N?c.default.useContext(N):null;if(!e){let t=Ie();if(t)return t;if(typeof window>"u")return Ee;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Oe({active:e}){return(0,d.jsx)("div",{style:{position:"fixed",top:0,left:0,width:"100%",height:3,zIndex:9999,transformOrigin:"left",transform:e?"scaleX(1)":"scaleX(0)",transition:"transform 180ms ease",background:"linear-gradient(90deg, #0ea5e9, #22c55e)"}})}function Ue(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function Me(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function b(e,t){let n=Object.entries(t).filter(([o,r])=>o!=="data-webframez-head"&&!!r).map(([o,r])=>[o.toLowerCase(),String(r)]).sort(([o],[r])=>o.localeCompare(r));return`${e.toLowerCase()}:${n.map(([o,r])=>`${o}=${r}`).join(";")}`}function ze(e){let t={};for(let n of Array.from(e.attributes))t[n.name]=n.value;return b(e.tagName,t)}function $e(e){let t=[];e.description&&t.push({tagName:"meta",attrs:{name:"description",content:e.description}}),e.favicon&&t.push({tagName:"link",attrs:{rel:"icon",href:e.favicon}});for(let n of e.meta??[])t.push({tagName:"meta",attrs:n});for(let n of e.links??[])t.push({tagName:"link",attrs:n});return t}function I(e){if(typeof document>"u")return;let t=P(e)??e;re(t),document.body.className=t.bodyClassName||"",document.title=t.title||"Webframez React";let n=$e(t),o=new Set(n.map(i=>b(i.tagName,i.attrs))),r=new Set;for(let i of document.head.querySelectorAll(Ae)){let s=ze(i);if(o.has(s)&&!r.has(s)){r.add(s);continue}i.remove()}for(let i of n){let s=b(i.tagName,i.attrs);r.has(s)||(i.tagName==="meta"?Ue(i.attrs):Me(i.attrs),r.add(s))}}function re(e){if(typeof window>"u")return;let t=P(e)??e,n=l(t.basename),o=l(t.routeBasePath),r=l(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=te(r,"/rsc"))}function De(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function We(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,(0,h.createFromReadableStream)(De(e)))}function Fe(e){let t=oe(e),n=ne(window.location.pathname);return We()??(0,h.createFromFetch)(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function je(e,t){return function(){let o=c.default.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[i,s]=(0,c.useState)(o.model),[u,w]=(0,c.useState)(o.contextModel),[p,R]=(0,c.useState)(o.pageModel),[k,B]=(0,c.useState)(o.head),[ie,_]=(0,c.useState)(!1),[ae,se]=(0,c.useState)(!1),[ce,H]=(0,c.useState)(r);async function O(a){let C=oe(t),f=ne(a.pathname),g=await fetch(`${C}?path=${encodeURIComponent(f)}&search=${encodeURIComponent(a.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return ve(g.headers.get(Ne))?(v(a),await new Promise(()=>{})):await(0,h.createFromFetch)(Promise.resolve(g))}async function y(a,C="push"){_(!0);try{let f=await O(a);I(f.head),B(f.head),s(f.model),w(f.contextModel),R(f.pageModel),H(!1);let g=`${a.pathname}${a.search}${a.hash}`;C==="replace"?(history.replaceState(null,"",g),Z()):C==="push"&&(history.pushState(null,"",g),Z())}catch(f){console.error("[webframez-react] Failed to render route",f),v(a),s((0,d.jsx)("p",{children:"Failed to load route."}))}finally{_(!1)}}async function de(){_(!0);try{let a=await O(new URL(window.location.href));I(a.head),B(a.head),s(a.model),w(a.contextModel),R(a.pageModel),H(!1)}catch(a){console.error("[webframez-react] Failed to refresh route context",a),v(new URL(window.location.href))}finally{_(!1)}}(0,c.useEffect)(()=>{I(k)},[k]),(0,c.useEffect)(()=>{se(!0);let a=()=>{y(new URL(window.location.href),"none")};return window.addEventListener("popstate",a),()=>{window.removeEventListener("popstate",a)}},[]);let U=c.default.useMemo(()=>({push:a=>{y(new URL(a,window.location.origin),"push")},replace:a=>{y(new URL(a,window.location.origin),"replace")},refresh:()=>{y(new URL(window.location.href),"none")},refreshContext:()=>{de()}}),[]);xe(U);let M=A(u),S=A(p),ue=ce&&typeof p<"u"?M?(0,d.jsx)(Q.RouteChildrenSlotProvider,{page:S,children:T(M,S)}):S:i,z=(0,d.jsxs)(d.Fragment,{children:[ae?(0,d.jsx)(Oe,{active:ie}):null,ue??(0,d.jsx)("p",{style:{padding:24},children:"Loading..."})]});return N?(0,d.jsx)(N.Provider,{value:U,children:z}):z}}function Ge(e={}){let t=e.rootId??"root",n=document.getElementById(t);if(!n)throw new Error(`Missing #${t} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=e.rscEndpoint??o??"/rsc",i=Promise.resolve(Fe(r)).then(u=>(u?.head&&re(u.head),u)),s=je(i,r);return(0,J.hydrateRoot)(n,(0,d.jsx)(s,{}))}
1
+ var fe=Object.create;var E=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var ge=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var he=(e,t)=>{for(var n in t)E(e,n,{get:t[n],enumerable:!0})},D=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of pe(t))!Re.call(e,r)&&r!==n&&E(e,r,{get:()=>t[r],enumerable:!(o=me(t,r))||o.enumerable});return e};var W=(e,t,n)=>(n=e!=null?fe(ge(e)):{},D(t||!e||!e.__esModule?E(n,"default",{value:e,enumerable:!0}):n,e)),we=e=>D(E({},"__esModule",{value:!0}),e);var Ye={};he(Ye,{mountWebframezClient:()=>Ke,useCookie:()=>Be,useRouter:()=>Oe});module.exports=we(Ye);var c=W(require("react"),1),J=require("react-dom/client"),h=require("react-server-dom-webpack/client"),Q=require("@webtypen/webframez-react/route-slot");var _e=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function l(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function b(e,t){let n=e.trim(),o=l(t);return!n||!o||_e.test(n)||n.startsWith("/")||o!=="/"&&(n===o||n.startsWith(`${o}/`))?n:o==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${o}${n}`:`${o}/${n}`}function L(e,t){if(!e)return;let n=l(e.basename)??l(t),o=l(e.routeBasePath),r=l(e.transportBasePath),i={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return i.favicon&&(i.favicon=b(i.favicon,n)),i.links&&(i.links=i.links.map(a=>({...a,href:b(a.href,n)}))),i.scripts&&(i.scripts=i.scripts.map(a=>({...a,...a.src?{src:b(a.src,n)}:{}}))),i}var m=W(require("react"),1),q="webframez-route-children",K="__webframezRouteChildren",Y="WebframezRouteChildren",Ce="__webframezRouteChildrenSlot",ye="WebframezRouteChildrenSlot",x=()=>m.default.createElement(q);x.displayName=Y;x[K]=!0;var Ee=x;function F(e){if(e===q||e===Ee)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[K]===!0||t.displayName===Y||t.name==="RouteChildren"}catch{return!1}}function j(e){if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[Ce]===!0||t.displayName===ye||t.name==="RouteChildrenSlot"}catch{return!1}}function G(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function T(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let u=!1,w=e.map(p=>{let g=T(p,t);return g!==p&&(u=!0),g});return u?w:e}if(G(e)&&(F(e.type)||j(e.type)))return t;let n=m.default.isValidElement(e);if(!n&&!G(e))return e;if(n&&(F(e.type)||j(e.type)))return t;let o=e.props??{};if(!("children"in o))return e;let r=T(o.children,t);if(r===o.children)return e;if(n)return Array.isArray(r)?m.default.cloneElement(e,void 0,...r):m.default.cloneElement(e,void 0,r);let i=e,a={...i.props??{},children:r,...i.key!==void 0&&i.key!==null?{key:i.key}:{}};return m.default.createElement(i.type,a)}var d=require("react/jsx-runtime"),Te={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},N=typeof c.default.createContext=="function"?c.default.createContext(null):null,ee="__WEBFRAMEZ_ROUTER__",Ne="__WEBFRAMEZ_REACT_BUILD_ID",Ae="x-webframez-react-build",Se="[data-webframez-head='true']";function Z(){if(typeof window>"u"||typeof document>"u")return;let e=()=>{window.scrollTo({top:0,left:0}),document.scrollingElement&&(document.scrollingElement.scrollTop=0),document.documentElement.scrollTop=0,document.body&&(document.body.scrollTop=0)};if(typeof window.requestAnimationFrame=="function"){window.requestAnimationFrame(e);return}window.setTimeout(e,0)}function k(e){return l(e)??""}function Pe(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function te(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function be(){return k(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function ne(e){if(typeof window>"u")return e||"/";let t=k(window.__RSC_BASENAME),n=be(),o=Pe(e||"/",t);return te(n,o)}function oe(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function Le(){if(typeof window>"u")return"";let e=window[Ne];return typeof e=="string"?e:""}function xe(e){let t=Le();return!!t&&!!e&&t!==e}function v(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function ve(){return typeof window>"u"?null:window[ee]??null}function Ie(e){typeof window>"u"||(window[ee]=e)}function ke(e){return!!e&&(typeof e=="object"||typeof e=="function")&&typeof e.then=="function"}function He(e){return ke(e)?c.default.use(e):e}function A(e){let t=He(e);if(Array.isArray(t)){let r=!1,i=t.map(a=>{let u=A(a);return u!==a&&(r=!0),u});return r?i:t}if(!c.default.isValidElement(t))return t;let n=t.props;if(!("children"in n))return t;let o=A(n.children);return o===n.children?t:Array.isArray(o)?c.default.cloneElement(t,void 0,...o):c.default.cloneElement(t,void 0,o)}function V(){let e={},t=typeof document>"u"?"":document.cookie;if(!t||t.trim()==="")return e;for(let n of t.split(";")){let o=n.trim();if(!o)continue;let r=o.indexOf("="),i=r>=0?o.slice(0,r).trim():o,a=r>=0?o.slice(r+1):"";i&&(e[i]=decodeURIComponent(a))}return e}function X(e,t,n={}){let o=[`${e}=${encodeURIComponent(t)}`];return n.path&&o.push(`Path=${n.path}`),n.domain&&o.push(`Domain=${n.domain}`),typeof n.maxAge=="number"&&o.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&o.push(`Expires=${n.expires.toUTCString()}`),n.sameSite&&o.push(`SameSite=${n.sameSite}`),n.secure&&o.push("Secure"),o.join("; ")}function Be(){return c.default.useMemo(()=>({all:()=>V(),get:e=>V()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=X(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=X(e,"",{...t??{},maxAge:0}))}}),[])}function Oe(){let e=N?c.default.useContext(N):null;if(!e){let t=ve();if(t)return t;if(typeof window>"u")return Te;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Me({active:e}){return(0,d.jsx)("div",{style:{position:"fixed",top:0,left:0,width:"100%",height:3,zIndex:9999,transformOrigin:"left",transform:e?"scaleX(1)":"scaleX(0)",transition:"transform 180ms ease",background:"linear-gradient(90deg, #0ea5e9, #22c55e)"}})}function Ue(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function ze(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function $e(e){if(e.html){re(e.html);return}let t=document.createElement("script");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([o,r])=>o!=="content"&&o!=="html"&&r!==void 0&&r!==null&&r!==!1);for(let[o,r]of n)r===!0?t.setAttribute(o,""):t.setAttribute(o,String(r));e.content&&(t.textContent=e.content),document.head.appendChild(t)}function re(e){let t=document.createElement("template");t.innerHTML=e;for(let n of Array.from(t.content.childNodes))n.nodeType===Node.ELEMENT_NODE&&n.setAttribute("data-webframez-head","true"),document.head.appendChild(n)}function S(e,t){let n=Object.entries(t).filter(([o,r])=>o!=="data-webframez-head"&&!!r).map(([o,r])=>[o.toLowerCase(),String(r)]).sort(([o],[r])=>o.localeCompare(r));return`${e.toLowerCase()}:${n.map(([o,r])=>`${o}=${r}`).join(";")}`}function De(e){if(e.tagName.toLowerCase()==="script"&&e.textContent){let n={content:e.textContent};for(let o of Array.from(e.attributes))n[o.name]=o.value;return S(e.tagName,n)}let t={};for(let n of Array.from(e.attributes))t[n.name]=n.value;return S(e.tagName,t)}function We(e){let t=[];e.description&&t.push({tagName:"meta",attrs:{name:"description",content:e.description}}),e.favicon&&t.push({tagName:"link",attrs:{rel:"icon",href:e.favicon}});for(let n of e.meta??[])t.push({tagName:"meta",attrs:n});for(let n of e.links??[])t.push({tagName:"link",attrs:n});for(let n of e.scripts??[])t.push({tagName:"script",attrs:n});for(let n of e.html??[])typeof n=="string"&&n.trim()!==""&&t.push({tagName:"html",attrs:{html:n}});return t}function I(e){if(typeof document>"u")return;let t=L(e)??e;ie(t),document.body.className=t.bodyClassName||"",document.title=t.title||"Webframez React";let n=We(t),o=new Set(n.map(i=>S(i.tagName,i.attrs))),r=new Set;for(let i of document.head.querySelectorAll(Se)){let a=De(i);if(o.has(a)&&!r.has(a)){r.add(a);continue}i.remove()}for(let i of n){let a=S(i.tagName,i.attrs);r.has(a)||(i.tagName==="meta"?Ue(i.attrs):i.tagName==="link"?ze(i.attrs):i.tagName==="script"?$e(i.attrs):re(i.attrs.html),r.add(a))}}function ie(e){if(typeof window>"u")return;let t=L(e)??e,n=l(t.basename),o=l(t.routeBasePath),r=l(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=te(r,"/rsc"))}function Fe(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function je(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,(0,h.createFromReadableStream)(Fe(e)))}function Ge(e){let t=oe(e),n=ne(window.location.pathname);return je()??(0,h.createFromFetch)(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function qe(e,t){return function(){let o=c.default.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[i,a]=(0,c.useState)(o.model),[u,w]=(0,c.useState)(o.contextModel),[p,g]=(0,c.useState)(o.pageModel),[H,B]=(0,c.useState)(o.head),[ae,_]=(0,c.useState)(!1),[se,ce]=(0,c.useState)(!1),[de,O]=(0,c.useState)(r);async function M(s){let y=oe(t),f=ne(s.pathname),R=await fetch(`${y}?path=${encodeURIComponent(f)}&search=${encodeURIComponent(s.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return xe(R.headers.get(Ae))?(v(s),await new Promise(()=>{})):await(0,h.createFromFetch)(Promise.resolve(R))}async function C(s,y="push"){_(!0);try{let f=await M(s);I(f.head),B(f.head),a(f.model),w(f.contextModel),g(f.pageModel),O(!1);let R=`${s.pathname}${s.search}${s.hash}`;y==="replace"?(history.replaceState(null,"",R),Z()):y==="push"&&(history.pushState(null,"",R),Z())}catch(f){console.error("[webframez-react] Failed to render route",f),v(s),a((0,d.jsx)("p",{children:"Failed to load route."}))}finally{_(!1)}}async function ue(){_(!0);try{let s=await M(new URL(window.location.href));I(s.head),B(s.head),a(s.model),w(s.contextModel),g(s.pageModel),O(!1)}catch(s){console.error("[webframez-react] Failed to refresh route context",s),v(new URL(window.location.href))}finally{_(!1)}}(0,c.useEffect)(()=>{I(H)},[H]),(0,c.useEffect)(()=>{ce(!0);let s=()=>{C(new URL(window.location.href),"none")};return window.addEventListener("popstate",s),()=>{window.removeEventListener("popstate",s)}},[]);let U=c.default.useMemo(()=>({push:s=>{C(new URL(s,window.location.origin),"push")},replace:s=>{C(new URL(s,window.location.origin),"replace")},refresh:()=>{C(new URL(window.location.href),"none")},refreshContext:()=>{ue()}}),[]);Ie(U);let z=A(u),P=A(p),le=de&&typeof p<"u"?z?(0,d.jsx)(Q.RouteChildrenSlotProvider,{page:P,children:T(z,P)}):P:i,$=(0,d.jsxs)(d.Fragment,{children:[se?(0,d.jsx)(Me,{active:ae}):null,le??(0,d.jsx)("p",{style:{padding:24},children:"Loading..."})]});return N?(0,d.jsx)(N.Provider,{value:U,children:$}):$}}function Ke(e={}){let t=e.rootId??"root",n=document.getElementById(t);if(!n)throw new Error(`Missing #${t} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=e.rscEndpoint??o??"/rsc",i=Promise.resolve(Ge(r)).then(u=>(u?.head&&ie(u.head),u)),a=qe(i,r);return(0,J.hydrateRoot)(n,(0,d.jsx)(a,{}))}
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- import u,{useEffect as q,useState as f}from"react";import{hydrateRoot as fe}from"react-dom/client";import{createFromFetch as V,createFromReadableStream as me}from"react-server-dom-webpack/client";import{RouteChildrenSlotProvider as pe}from"@webtypen/webframez-react/route-slot";var ce=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function d(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function z(e,t){let n=e.trim(),o=d(t);return!n||!o||ce.test(n)||n.startsWith("/")||o!=="/"&&(n===o||n.startsWith(`${o}/`))?n:o==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${o}${n}`:`${o}/${n}`}function S(e,t){if(!e)return;let n=d(e.basename)??d(t),o=d(e.routeBasePath),r=d(e.transportBasePath),i={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return i.favicon&&(i.favicon=z(i.favicon,n)),i.links&&(i.links=i.links.map(s=>({...s,href:z(s.href,n)}))),i}import h from"react";var F="webframez-route-children",j="__webframezRouteChildren",G="WebframezRouteChildren",de="__webframezRouteChildrenSlot",ue="WebframezRouteChildrenSlot",P=()=>h.createElement(F);P.displayName=G;P[j]=!0;var le=P;function $(e){if(e===F||e===le)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[j]===!0||t.displayName===G||t.name==="RouteChildren"}catch{return!1}}function D(e){if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[de]===!0||t.displayName===ue||t.name==="RouteChildrenSlot"}catch{return!1}}function W(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function E(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let c=!1,w=e.map(p=>{let R=E(p,t);return R!==p&&(c=!0),R});return c?w:e}if(W(e)&&($(e.type)||D(e.type)))return t;let n=h.isValidElement(e);if(!n&&!W(e))return e;if(n&&($(e.type)||D(e.type)))return t;let o=e.props??{};if(!("children"in o))return e;let r=E(o.children,t);if(r===o.children)return e;if(n)return Array.isArray(r)?h.cloneElement(e,void 0,...r):h.cloneElement(e,void 0,r);let i=e,s={...i.props??{},children:r,...i.key!==void 0&&i.key!==null?{key:i.key}:{}};return h.createElement(i.type,s)}import{Fragment as Oe,jsx as m,jsxs as Ue}from"react/jsx-runtime";var Re={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},T=typeof u.createContext=="function"?u.createContext(null):null,X="__WEBFRAMEZ_ROUTER__",ge="__WEBFRAMEZ_REACT_BUILD_ID",he="x-webframez-react-build",we="[data-webframez-head='true']";function K(){if(typeof window>"u"||typeof document>"u")return;let e=()=>{window.scrollTo({top:0,left:0}),document.scrollingElement&&(document.scrollingElement.scrollTop=0),document.documentElement.scrollTop=0,document.body&&(document.body.scrollTop=0)};if(typeof window.requestAnimationFrame=="function"){window.requestAnimationFrame(e);return}window.setTimeout(e,0)}function I(e){return d(e)??""}function _e(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function J(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function ye(){return I(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function Q(e){if(typeof window>"u")return e||"/";let t=I(window.__RSC_BASENAME),n=ye(),o=_e(e||"/",t);return J(n,o)}function ee(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function Ce(){if(typeof window>"u")return"";let e=window[ge];return typeof e=="string"?e:""}function Ee(e){let t=Ce();return!!t&&!!e&&t!==e}function L(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function Te(){return typeof window>"u"?null:window[X]??null}function Ne(e){typeof window>"u"||(window[X]=e)}function Ae(e){return!!e&&(typeof e=="object"||typeof e=="function")&&typeof e.then=="function"}function Se(e){return Ae(e)?u.use(e):e}function N(e){let t=Se(e);if(Array.isArray(t)){let r=!1,i=t.map(s=>{let c=N(s);return c!==s&&(r=!0),c});return r?i:t}if(!u.isValidElement(t))return t;let n=t.props;if(!("children"in n))return t;let o=N(n.children);return o===n.children?t:Array.isArray(o)?u.cloneElement(t,void 0,...o):u.cloneElement(t,void 0,o)}function Y(){let e={},t=typeof document>"u"?"":document.cookie;if(!t||t.trim()==="")return e;for(let n of t.split(";")){let o=n.trim();if(!o)continue;let r=o.indexOf("="),i=r>=0?o.slice(0,r).trim():o,s=r>=0?o.slice(r+1):"";i&&(e[i]=decodeURIComponent(s))}return e}function Z(e,t,n={}){let o=[`${e}=${encodeURIComponent(t)}`];return n.path&&o.push(`Path=${n.path}`),n.domain&&o.push(`Domain=${n.domain}`),typeof n.maxAge=="number"&&o.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&o.push(`Expires=${n.expires.toUTCString()}`),n.sameSite&&o.push(`SameSite=${n.sameSite}`),n.secure&&o.push("Secure"),o.join("; ")}function Ye(){return u.useMemo(()=>({all:()=>Y(),get:e=>Y()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=Z(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=Z(e,"",{...t??{},maxAge:0}))}}),[])}function Ze(){let e=T?u.useContext(T):null;if(!e){let t=Te();if(t)return t;if(typeof window>"u")return Re;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Pe({active:e}){return m("div",{style:{position:"fixed",top:0,left:0,width:"100%",height:3,zIndex:9999,transformOrigin:"left",transform:e?"scaleX(1)":"scaleX(0)",transition:"transform 180ms ease",background:"linear-gradient(90deg, #0ea5e9, #22c55e)"}})}function Le(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function ve(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function x(e,t){let n=Object.entries(t).filter(([o,r])=>o!=="data-webframez-head"&&!!r).map(([o,r])=>[o.toLowerCase(),String(r)]).sort(([o],[r])=>o.localeCompare(r));return`${e.toLowerCase()}:${n.map(([o,r])=>`${o}=${r}`).join(";")}`}function Ie(e){let t={};for(let n of Array.from(e.attributes))t[n.name]=n.value;return x(e.tagName,t)}function xe(e){let t=[];e.description&&t.push({tagName:"meta",attrs:{name:"description",content:e.description}}),e.favicon&&t.push({tagName:"link",attrs:{rel:"icon",href:e.favicon}});for(let n of e.meta??[])t.push({tagName:"meta",attrs:n});for(let n of e.links??[])t.push({tagName:"link",attrs:n});return t}function v(e){if(typeof document>"u")return;let t=S(e)??e;te(t),document.body.className=t.bodyClassName||"",document.title=t.title||"Webframez React";let n=xe(t),o=new Set(n.map(i=>x(i.tagName,i.attrs))),r=new Set;for(let i of document.head.querySelectorAll(we)){let s=Ie(i);if(o.has(s)&&!r.has(s)){r.add(s);continue}i.remove()}for(let i of n){let s=x(i.tagName,i.attrs);r.has(s)||(i.tagName==="meta"?Le(i.attrs):ve(i.attrs),r.add(s))}}function te(e){if(typeof window>"u")return;let t=S(e)??e,n=d(t.basename),o=d(t.routeBasePath),r=d(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=J(r,"/rsc"))}function be(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function ke(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,me(be(e)))}function Be(e){let t=ee(e),n=Q(window.location.pathname);return ke()??V(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function He(e,t){return function(){let o=u.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[i,s]=f(o.model),[c,w]=f(o.contextModel),[p,R]=f(o.pageModel),[b,k]=f(o.head),[ne,_]=f(!1),[oe,re]=f(!1),[ie,B]=f(r);async function H(a){let C=ee(t),l=Q(a.pathname),g=await fetch(`${C}?path=${encodeURIComponent(l)}&search=${encodeURIComponent(a.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return Ee(g.headers.get(he))?(L(a),await new Promise(()=>{})):await V(Promise.resolve(g))}async function y(a,C="push"){_(!0);try{let l=await H(a);v(l.head),k(l.head),s(l.model),w(l.contextModel),R(l.pageModel),B(!1);let g=`${a.pathname}${a.search}${a.hash}`;C==="replace"?(history.replaceState(null,"",g),K()):C==="push"&&(history.pushState(null,"",g),K())}catch(l){console.error("[webframez-react] Failed to render route",l),L(a),s(m("p",{children:"Failed to load route."}))}finally{_(!1)}}async function ae(){_(!0);try{let a=await H(new URL(window.location.href));v(a.head),k(a.head),s(a.model),w(a.contextModel),R(a.pageModel),B(!1)}catch(a){console.error("[webframez-react] Failed to refresh route context",a),L(new URL(window.location.href))}finally{_(!1)}}q(()=>{v(b)},[b]),q(()=>{re(!0);let a=()=>{y(new URL(window.location.href),"none")};return window.addEventListener("popstate",a),()=>{window.removeEventListener("popstate",a)}},[]);let O=u.useMemo(()=>({push:a=>{y(new URL(a,window.location.origin),"push")},replace:a=>{y(new URL(a,window.location.origin),"replace")},refresh:()=>{y(new URL(window.location.href),"none")},refreshContext:()=>{ae()}}),[]);Ne(O);let U=N(c),A=N(p),se=ie&&typeof p<"u"?U?m(pe,{page:A,children:E(U,A)}):A:i,M=Ue(Oe,{children:[oe?m(Pe,{active:ne}):null,se??m("p",{style:{padding:24},children:"Loading..."})]});return T?m(T.Provider,{value:O,children:M}):M}}function Ve(e={}){let t=e.rootId??"root",n=document.getElementById(t);if(!n)throw new Error(`Missing #${t} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=e.rscEndpoint??o??"/rsc",i=Promise.resolve(Be(r)).then(c=>(c?.head&&te(c.head),c)),s=He(i,r);return fe(n,m(s,{}))}export{Ve as mountWebframezClient,Ye as useCookie,Ze as useRouter};
1
+ import u,{useEffect as q,useState as f}from"react";import{hydrateRoot as me}from"react-dom/client";import{createFromFetch as V,createFromReadableStream as pe}from"react-server-dom-webpack/client";import{RouteChildrenSlotProvider as ge}from"@webtypen/webframez-react/route-slot";var de=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function d(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function P(e,t){let n=e.trim(),o=d(t);return!n||!o||de.test(n)||n.startsWith("/")||o!=="/"&&(n===o||n.startsWith(`${o}/`))?n:o==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${o}${n}`:`${o}/${n}`}function b(e,t){if(!e)return;let n=d(e.basename)??d(t),o=d(e.routeBasePath),r=d(e.transportBasePath),i={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return i.favicon&&(i.favicon=P(i.favicon,n)),i.links&&(i.links=i.links.map(a=>({...a,href:P(a.href,n)}))),i.scripts&&(i.scripts=i.scripts.map(a=>({...a,...a.src?{src:P(a.src,n)}:{}}))),i}import h from"react";var F="webframez-route-children",j="__webframezRouteChildren",G="WebframezRouteChildren",ue="__webframezRouteChildrenSlot",le="WebframezRouteChildrenSlot",L=()=>h.createElement(F);L.displayName=G;L[j]=!0;var fe=L;function $(e){if(e===F||e===fe)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[j]===!0||t.displayName===G||t.name==="RouteChildren"}catch{return!1}}function D(e){if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[ue]===!0||t.displayName===le||t.name==="RouteChildrenSlot"}catch{return!1}}function W(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function E(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let c=!1,w=e.map(p=>{let g=E(p,t);return g!==p&&(c=!0),g});return c?w:e}if(W(e)&&($(e.type)||D(e.type)))return t;let n=h.isValidElement(e);if(!n&&!W(e))return e;if(n&&($(e.type)||D(e.type)))return t;let o=e.props??{};if(!("children"in o))return e;let r=E(o.children,t);if(r===o.children)return e;if(n)return Array.isArray(r)?h.cloneElement(e,void 0,...r):h.cloneElement(e,void 0,r);let i=e,a={...i.props??{},children:r,...i.key!==void 0&&i.key!==null?{key:i.key}:{}};return h.createElement(i.type,a)}import{Fragment as Ue,jsx as m,jsxs as ze}from"react/jsx-runtime";var Re={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},T=typeof u.createContext=="function"?u.createContext(null):null,X="__WEBFRAMEZ_ROUTER__",he="__WEBFRAMEZ_REACT_BUILD_ID",we="x-webframez-react-build",_e="[data-webframez-head='true']";function K(){if(typeof window>"u"||typeof document>"u")return;let e=()=>{window.scrollTo({top:0,left:0}),document.scrollingElement&&(document.scrollingElement.scrollTop=0),document.documentElement.scrollTop=0,document.body&&(document.body.scrollTop=0)};if(typeof window.requestAnimationFrame=="function"){window.requestAnimationFrame(e);return}window.setTimeout(e,0)}function I(e){return d(e)??""}function Ce(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function J(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function ye(){return I(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function Q(e){if(typeof window>"u")return e||"/";let t=I(window.__RSC_BASENAME),n=ye(),o=Ce(e||"/",t);return J(n,o)}function ee(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function Ee(){if(typeof window>"u")return"";let e=window[he];return typeof e=="string"?e:""}function Te(e){let t=Ee();return!!t&&!!e&&t!==e}function x(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function Ne(){return typeof window>"u"?null:window[X]??null}function Ae(e){typeof window>"u"||(window[X]=e)}function Se(e){return!!e&&(typeof e=="object"||typeof e=="function")&&typeof e.then=="function"}function Pe(e){return Se(e)?u.use(e):e}function N(e){let t=Pe(e);if(Array.isArray(t)){let r=!1,i=t.map(a=>{let c=N(a);return c!==a&&(r=!0),c});return r?i:t}if(!u.isValidElement(t))return t;let n=t.props;if(!("children"in n))return t;let o=N(n.children);return o===n.children?t:Array.isArray(o)?u.cloneElement(t,void 0,...o):u.cloneElement(t,void 0,o)}function Y(){let e={},t=typeof document>"u"?"":document.cookie;if(!t||t.trim()==="")return e;for(let n of t.split(";")){let o=n.trim();if(!o)continue;let r=o.indexOf("="),i=r>=0?o.slice(0,r).trim():o,a=r>=0?o.slice(r+1):"";i&&(e[i]=decodeURIComponent(a))}return e}function Z(e,t,n={}){let o=[`${e}=${encodeURIComponent(t)}`];return n.path&&o.push(`Path=${n.path}`),n.domain&&o.push(`Domain=${n.domain}`),typeof n.maxAge=="number"&&o.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&o.push(`Expires=${n.expires.toUTCString()}`),n.sameSite&&o.push(`SameSite=${n.sameSite}`),n.secure&&o.push("Secure"),o.join("; ")}function Ve(){return u.useMemo(()=>({all:()=>Y(),get:e=>Y()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=Z(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=Z(e,"",{...t??{},maxAge:0}))}}),[])}function Xe(){let e=T?u.useContext(T):null;if(!e){let t=Ne();if(t)return t;if(typeof window>"u")return Re;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function be({active:e}){return m("div",{style:{position:"fixed",top:0,left:0,width:"100%",height:3,zIndex:9999,transformOrigin:"left",transform:e?"scaleX(1)":"scaleX(0)",transition:"transform 180ms ease",background:"linear-gradient(90deg, #0ea5e9, #22c55e)"}})}function Le(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function xe(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of n)t.setAttribute(o,String(r));document.head.appendChild(t)}function ve(e){if(e.html){te(e.html);return}let t=document.createElement("script");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([o,r])=>o!=="content"&&o!=="html"&&r!==void 0&&r!==null&&r!==!1);for(let[o,r]of n)r===!0?t.setAttribute(o,""):t.setAttribute(o,String(r));e.content&&(t.textContent=e.content),document.head.appendChild(t)}function te(e){let t=document.createElement("template");t.innerHTML=e;for(let n of Array.from(t.content.childNodes))n.nodeType===Node.ELEMENT_NODE&&n.setAttribute("data-webframez-head","true"),document.head.appendChild(n)}function A(e,t){let n=Object.entries(t).filter(([o,r])=>o!=="data-webframez-head"&&!!r).map(([o,r])=>[o.toLowerCase(),String(r)]).sort(([o],[r])=>o.localeCompare(r));return`${e.toLowerCase()}:${n.map(([o,r])=>`${o}=${r}`).join(";")}`}function Ie(e){if(e.tagName.toLowerCase()==="script"&&e.textContent){let n={content:e.textContent};for(let o of Array.from(e.attributes))n[o.name]=o.value;return A(e.tagName,n)}let t={};for(let n of Array.from(e.attributes))t[n.name]=n.value;return A(e.tagName,t)}function ke(e){let t=[];e.description&&t.push({tagName:"meta",attrs:{name:"description",content:e.description}}),e.favicon&&t.push({tagName:"link",attrs:{rel:"icon",href:e.favicon}});for(let n of e.meta??[])t.push({tagName:"meta",attrs:n});for(let n of e.links??[])t.push({tagName:"link",attrs:n});for(let n of e.scripts??[])t.push({tagName:"script",attrs:n});for(let n of e.html??[])typeof n=="string"&&n.trim()!==""&&t.push({tagName:"html",attrs:{html:n}});return t}function v(e){if(typeof document>"u")return;let t=b(e)??e;ne(t),document.body.className=t.bodyClassName||"",document.title=t.title||"Webframez React";let n=ke(t),o=new Set(n.map(i=>A(i.tagName,i.attrs))),r=new Set;for(let i of document.head.querySelectorAll(_e)){let a=Ie(i);if(o.has(a)&&!r.has(a)){r.add(a);continue}i.remove()}for(let i of n){let a=A(i.tagName,i.attrs);r.has(a)||(i.tagName==="meta"?Le(i.attrs):i.tagName==="link"?xe(i.attrs):i.tagName==="script"?ve(i.attrs):te(i.attrs.html),r.add(a))}}function ne(e){if(typeof window>"u")return;let t=b(e)??e,n=d(t.basename),o=d(t.routeBasePath),r=d(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=J(r,"/rsc"))}function He(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function Be(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,pe(He(e)))}function Oe(e){let t=ee(e),n=Q(window.location.pathname);return Be()??V(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function Me(e,t){return function(){let o=u.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[i,a]=f(o.model),[c,w]=f(o.contextModel),[p,g]=f(o.pageModel),[k,H]=f(o.head),[oe,_]=f(!1),[re,ie]=f(!1),[ae,B]=f(r);async function O(s){let y=ee(t),l=Q(s.pathname),R=await fetch(`${y}?path=${encodeURIComponent(l)}&search=${encodeURIComponent(s.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return Te(R.headers.get(we))?(x(s),await new Promise(()=>{})):await V(Promise.resolve(R))}async function C(s,y="push"){_(!0);try{let l=await O(s);v(l.head),H(l.head),a(l.model),w(l.contextModel),g(l.pageModel),B(!1);let R=`${s.pathname}${s.search}${s.hash}`;y==="replace"?(history.replaceState(null,"",R),K()):y==="push"&&(history.pushState(null,"",R),K())}catch(l){console.error("[webframez-react] Failed to render route",l),x(s),a(m("p",{children:"Failed to load route."}))}finally{_(!1)}}async function se(){_(!0);try{let s=await O(new URL(window.location.href));v(s.head),H(s.head),a(s.model),w(s.contextModel),g(s.pageModel),B(!1)}catch(s){console.error("[webframez-react] Failed to refresh route context",s),x(new URL(window.location.href))}finally{_(!1)}}q(()=>{v(k)},[k]),q(()=>{ie(!0);let s=()=>{C(new URL(window.location.href),"none")};return window.addEventListener("popstate",s),()=>{window.removeEventListener("popstate",s)}},[]);let M=u.useMemo(()=>({push:s=>{C(new URL(s,window.location.origin),"push")},replace:s=>{C(new URL(s,window.location.origin),"replace")},refresh:()=>{C(new URL(window.location.href),"none")},refreshContext:()=>{se()}}),[]);Ae(M);let U=N(c),S=N(p),ce=ae&&typeof p<"u"?U?m(ge,{page:S,children:E(U,S)}):S:i,z=ze(Ue,{children:[re?m(be,{active:oe}):null,ce??m("p",{style:{padding:24},children:"Loading..."})]});return T?m(T.Provider,{value:M,children:z}):z}}function Je(e={}){let t=e.rootId??"root",n=document.getElementById(t);if(!n)throw new Error(`Missing #${t} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=e.rscEndpoint??o??"/rsc",i=Promise.resolve(Oe(r)).then(c=>(c?.head&&ne(c.head),c)),a=Me(i,r);return me(n,m(a,{}))}export{Je as mountWebframezClient,Ve as useCookie,Xe as useRouter};
package/dist/http.cjs CHANGED
@@ -29,9 +29,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // src/http.ts
30
30
  var http_exports = {};
31
31
  __export(http_exports, {
32
- createNodeRequestHandler: () => createNodeRequestHandler
32
+ createNodeRequestHandler: () => createNodeRequestHandler,
33
+ disposeReactHtmlRenderer: () => disposeReactHtmlRenderer,
34
+ renderReactToHtml: () => renderReactToHtml
33
35
  });
34
36
  module.exports = __toCommonJS(http_exports);
37
+ var import_node_async_hooks = require("node:async_hooks");
35
38
  var import_node_fs2 = __toESM(require("node:fs"), 1);
36
39
  var import_node_path3 = __toESM(require("node:path"), 1);
37
40
  var import_node_url = require("node:url");
@@ -55,6 +58,8 @@ function createHTMLShell(options = {}) {
55
58
  buildId = "",
56
59
  headTags = "",
57
60
  bodyClassName = "",
61
+ bodyStartHtml = "",
62
+ bodyEndHtml = "",
58
63
  rootHtml = "",
59
64
  initialFlightData = "",
60
65
  basename = "",
@@ -104,7 +109,9 @@ function createHTMLShell(options = {}) {
104
109
  ${headTags}
105
110
  </head>
106
111
  <body${bodyClassName ? ` class="${bodyClassName.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}"` : ""}>
112
+ ${bodyStartHtml}
107
113
  <div id="root">${rootHtml}</div>
114
+ ${bodyEndHtml}
108
115
  <script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
109
116
  <script>window.__RSC_BASENAME = "${basename}";</script>
110
117
  <script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
@@ -219,6 +226,12 @@ function normalizeHeadConfig(head, inheritedBasename) {
219
226
  href: resolveHeadAssetUrl(link.href, effectiveBasename)
220
227
  }));
221
228
  }
229
+ if (normalizedHead.scripts) {
230
+ normalizedHead.scripts = normalizedHead.scripts.map((script) => ({
231
+ ...script,
232
+ ...script.src ? { src: resolveHeadAssetUrl(script.src, effectiveBasename) } : {}
233
+ }));
234
+ }
222
235
  return normalizedHead;
223
236
  }
224
237
 
@@ -331,8 +344,7 @@ var FORCED_PACKAGE_REQUESTS = [
331
344
  "react-server-dom-webpack",
332
345
  "react-server-dom-webpack/server",
333
346
  "react-server-dom-webpack/client",
334
- "react-server-dom-webpack/client.node",
335
- "scheduler"
347
+ "react-server-dom-webpack/client.node"
336
348
  ];
337
349
  var forcedPackageResolutionInstalled = false;
338
350
  function normalizePathname(pathname) {
@@ -471,7 +483,9 @@ function matchRoute(entry, pathname) {
471
483
  function mergeHead(...configs) {
472
484
  const merged = {
473
485
  meta: [],
474
- links: []
486
+ links: [],
487
+ scripts: [],
488
+ html: []
475
489
  };
476
490
  for (const candidate of configs) {
477
491
  const config = normalizeHeadConfig(candidate, merged.basename);
@@ -506,9 +520,28 @@ function mergeHead(...configs) {
506
520
  if (config.links) {
507
521
  merged.links?.push(...config.links);
508
522
  }
523
+ if (config.scripts) {
524
+ merged.scripts?.push(...config.scripts);
525
+ }
526
+ if (config.html) {
527
+ merged.html?.push(...Array.isArray(config.html) ? config.html : [config.html]);
528
+ }
529
+ if (config.bodyStartHtml) {
530
+ merged.bodyStartHtml = [merged.bodyStartHtml, config.bodyStartHtml].filter(Boolean).join("\n");
531
+ }
532
+ if (config.bodyEndHtml) {
533
+ merged.bodyEndHtml = [merged.bodyEndHtml, config.bodyEndHtml].filter(Boolean).join("\n");
534
+ }
509
535
  }
510
536
  return merged;
511
537
  }
538
+ function renderGenericAttributes(entry, excluded = []) {
539
+ return Object.entries(entry).filter(
540
+ ([key, value]) => !excluded.includes(key) && value !== void 0 && value !== null && value !== false
541
+ ).map(
542
+ ([key, value]) => value === true ? key : `${key}="${escapeHtml(String(value))}"`
543
+ ).join(" ");
544
+ }
512
545
  function renderHeadToString(head) {
513
546
  const normalizedHead = normalizeHeadConfig(head) ?? head;
514
547
  const tags = [];
@@ -530,6 +563,23 @@ function renderHeadToString(head) {
530
563
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
531
564
  tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
532
565
  }
566
+ for (const script of normalizedHead.scripts ?? []) {
567
+ if (script.html) {
568
+ tags.push(script.html);
569
+ continue;
570
+ }
571
+ const attrs = renderGenericAttributes(script, [
572
+ "content",
573
+ "html"
574
+ ]);
575
+ const content = script.content ? String(script.content) : "";
576
+ tags.push(`<script ${createManagedAttributes()} ${attrs}>${content}</script>`);
577
+ }
578
+ for (const html of normalizedHead.html ?? []) {
579
+ if (typeof html === "string" && html.trim() !== "") {
580
+ tags.push(html);
581
+ }
582
+ }
533
583
  return tags.join("\n");
534
584
  }
535
585
  function clearModuleCache(modulePath, rootDir, visited = /* @__PURE__ */ new Set()) {
@@ -615,6 +665,7 @@ function isRouteAbort(value) {
615
665
  function createFileRouter(options) {
616
666
  installForcedPackageResolution();
617
667
  const pagesDir = options.pagesDir;
668
+ const onData = options.onData;
618
669
  const layoutPath = import_node_path2.default.join(pagesDir, "layout.js");
619
670
  const errorPath = import_node_path2.default.join(pagesDir, "errors.js");
620
671
  const middlewaresPath = import_node_path2.default.join(pagesDir, "middlewares.js");
@@ -779,10 +830,16 @@ function createFileRouter(options) {
779
830
  data: mergeRouteData(middlewareContext.data, pageData)
780
831
  };
781
832
  activeContext = pageContext;
782
- const pageNode = await pageModule.default(pageContext);
783
- const layoutHead = layoutModule ? await resolveHead(layoutModule, pageContext) : void 0;
784
- const pageHead = await resolveHead(pageModule, pageContext);
785
- const layoutNode = layoutModule ? await layoutModule.default(pageContext) : null;
833
+ const onDataResult = typeof onData === "function" ? await onData(pageContext) : void 0;
834
+ const eventContext = {
835
+ ...pageContext,
836
+ data: mergeRouteData(pageContext.data, onDataResult)
837
+ };
838
+ activeContext = eventContext;
839
+ const pageNode = await pageModule.default(eventContext);
840
+ const layoutHead = layoutModule ? await resolveHead(layoutModule, eventContext) : void 0;
841
+ const pageHead = await resolveHead(pageModule, eventContext);
842
+ const layoutNode = layoutModule ? await layoutModule.default(eventContext) : null;
786
843
  const model = layoutNode ? injectRouteChildren(layoutNode, pageNode) : pageNode;
787
844
  const contextModel = layoutNode ? injectRouteChildren(layoutNode, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RouteChildren, {})) : void 0;
788
845
  return {
@@ -791,7 +848,7 @@ function createFileRouter(options) {
791
848
  contextModel,
792
849
  pageModel: pageNode,
793
850
  head: mergeHead(layoutHead, pageHead),
794
- context: pageContext
851
+ context: eventContext
795
852
  };
796
853
  } catch (error) {
797
854
  if (isRouteAbort(error)) {
@@ -938,6 +995,7 @@ const rootParent = {
938
995
  path: process.cwd(),
939
996
  paths: Module._nodeModulePaths(process.cwd()),
940
997
  };
998
+ // Transitive dependencies (e.g. scheduler) must resolve from their importer.
941
999
  const forcedPackageRequests = [
942
1000
  "@webtypen/webframez-core",
943
1001
  "@webtypen/webframez-react",
@@ -952,7 +1010,6 @@ const forcedPackageRequests = [
952
1010
  "react-server-dom-webpack/server",
953
1011
  "react-server-dom-webpack/client",
954
1012
  "react-server-dom-webpack/client.node",
955
- "scheduler"
956
1013
  ];
957
1014
 
958
1015
  function shouldForcePackageResolution(request) {
@@ -1144,13 +1201,17 @@ async function renderHtmlFromFlightData(flightData, moduleMap) {
1144
1201
  ? payload.head.basename
1145
1202
  : "";
1146
1203
 
1147
- const previousBasename = globalThis.__RSC_BASENAME;
1148
- globalThis.__RSC_BASENAME = basename;
1149
- try {
1150
- return await renderHtml(model);
1151
- } finally {
1152
- globalThis.__RSC_BASENAME = previousBasename;
1153
- }
1204
+ const routingContext = globalThis.__WEBFRAMEZ_ROUTING_CONTEXT__ ??=
1205
+ new (require("node:async_hooks").AsyncLocalStorage)();
1206
+ return routingContext.run(basename, async () => {
1207
+ const previousBasename = globalThis.__RSC_BASENAME;
1208
+ globalThis.__RSC_BASENAME = basename;
1209
+ try {
1210
+ return await renderHtml(model);
1211
+ } finally {
1212
+ globalThis.__RSC_BASENAME = previousBasename;
1213
+ }
1214
+ });
1154
1215
  }
1155
1216
 
1156
1217
  process.on("message", async (message) => {
@@ -1386,24 +1447,10 @@ ${stderrBuffer.trim()}` : "";
1386
1447
  }
1387
1448
  };
1388
1449
  }
1450
+ var routingRuntime = globalThis;
1451
+ var basenameContext = routingRuntime.__WEBFRAMEZ_ROUTING_CONTEXT__ ??= new import_node_async_hooks.AsyncLocalStorage();
1389
1452
  function withRequestBasename(basename, fn) {
1390
- const target = globalThis;
1391
- const previous = target.__RSC_BASENAME;
1392
- target.__RSC_BASENAME = basename;
1393
- const finish = () => {
1394
- target.__RSC_BASENAME = previous;
1395
- };
1396
- try {
1397
- const result = fn();
1398
- if (result && typeof result.then === "function") {
1399
- return result.finally(finish);
1400
- }
1401
- finish();
1402
- return result;
1403
- } catch (error) {
1404
- finish();
1405
- throw error;
1406
- }
1453
+ return basenameContext.run(basename, fn);
1407
1454
  }
1408
1455
  function parseCookies(rawCookieHeader) {
1409
1456
  const raw = Array.isArray(rawCookieHeader) ? rawCookieHeader.join("; ") : rawCookieHeader ?? "";
@@ -1438,12 +1485,27 @@ function normalizeClientManifest(manifest, options) {
1438
1485
  }
1439
1486
  };
1440
1487
  for (const [key, value] of Object.entries(manifest)) {
1488
+ const hashIndex = key.indexOf("#");
1489
+ const moduleKey = hashIndex < 0 ? key : key.slice(0, hashIndex);
1490
+ const exportSuffix = hashIndex < 0 ? "" : key.slice(hashIndex);
1491
+ if (!import_node_path3.default.isAbsolute(moduleKey) && !moduleKey.includes(":") && !moduleKey.startsWith("file://")) {
1492
+ const runtimePath = import_node_path3.default.resolve(options.cwd, moduleKey);
1493
+ const allowedRoots = [options.distRootDir, ...candidateNodeModulesDirs];
1494
+ const insideArtifact = allowedRoots.some((root) => {
1495
+ const relative = import_node_path3.default.relative(import_node_path3.default.resolve(root), runtimePath);
1496
+ return relative !== "" && relative !== ".." && !relative.startsWith(`..${import_node_path3.default.sep}`) && !import_node_path3.default.isAbsolute(relative);
1497
+ });
1498
+ if (insideArtifact) {
1499
+ addAlias(`${runtimePath}${exportSuffix}`, value);
1500
+ addAlias(`${(0, import_node_url.pathToFileURL)(runtimePath).href}${exportSuffix}`, value);
1501
+ }
1502
+ }
1441
1503
  if (!key.startsWith("file://")) {
1442
1504
  continue;
1443
1505
  }
1444
1506
  let absolutePath = "";
1445
1507
  try {
1446
- absolutePath = (0, import_node_url.fileURLToPath)(key);
1508
+ absolutePath = (0, import_node_url.fileURLToPath)(moduleKey);
1447
1509
  } catch {
1448
1510
  continue;
1449
1511
  }
@@ -1454,13 +1516,13 @@ function normalizeClientManifest(manifest, options) {
1454
1516
  }
1455
1517
  const relativeModulePath = absolutePath.slice(markerIndex + marker.length);
1456
1518
  const relativeModulePathPosix = relativeModulePath.split(import_node_path3.default.sep).join("/");
1457
- addAlias(`./node_modules/${relativeModulePathPosix}`, value);
1458
- addAlias(`node_modules/${relativeModulePathPosix}`, value);
1459
- addAlias(absolutePath, value);
1519
+ addAlias(`./node_modules/${relativeModulePathPosix}${exportSuffix}`, value);
1520
+ addAlias(`node_modules/${relativeModulePathPosix}${exportSuffix}`, value);
1521
+ addAlias(`${absolutePath}${exportSuffix}`, value);
1460
1522
  for (const nodeModulesDir of candidateNodeModulesDirs) {
1461
1523
  const aliasPath = import_node_path3.default.join(nodeModulesDir, relativeModulePath);
1462
- addAlias(aliasPath, value);
1463
- addAlias((0, import_node_url.pathToFileURL)(aliasPath).href, value);
1524
+ addAlias(`${aliasPath}${exportSuffix}`, value);
1525
+ addAlias(`${(0, import_node_url.pathToFileURL)(aliasPath).href}${exportSuffix}`, value);
1464
1526
  }
1465
1527
  }
1466
1528
  return normalized;
@@ -1605,16 +1667,16 @@ function createNodeRequestHandler(options) {
1605
1667
  const manifestPath = import_node_path3.default.resolve(
1606
1668
  options.manifestPath ?? import_node_path3.default.join(distRootDir, "react-client-manifest.json")
1607
1669
  );
1608
- const assetsPrefix = options.assetsPrefix ?? "/assets/";
1609
- const rscPath = options.rscPath ?? "/rsc";
1610
- const clientScriptUrl = options.clientScriptUrl ?? "/assets/client.js";
1611
1670
  const basePath = normalizeBasePath(options.basePath);
1671
+ const assetsPrefix = options.assetsPrefix ?? `${basePath}/assets/`;
1672
+ const rscPath = options.rscPath ?? `${basePath}/rsc`;
1673
+ const clientScriptUrl = options.clientScriptUrl ?? `${basePath}/assets/client.js`;
1612
1674
  const nodeEnv = process.env.NODE_ENV || "";
1613
1675
  const runningInWatchMode = Array.isArray(process.execArgv) && process.execArgv.includes("--watch");
1614
1676
  const liveReloadEnabled = options.liveReloadPath !== false && (nodeEnv === "development" || runningInWatchMode);
1615
1677
  const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
1616
1678
  const liveReloadClients = /* @__PURE__ */ new Set();
1617
- const router = createFileRouter({ pagesDir });
1679
+ const router = createFileRouter({ pagesDir, onData: options.onData });
1618
1680
  const getManifestState = createManifestLoader({
1619
1681
  distRootDir,
1620
1682
  manifestPath,
@@ -1627,7 +1689,7 @@ function createNodeRequestHandler(options) {
1627
1689
  process.once("exit", disposeInitialHtmlWorker);
1628
1690
  process.once("SIGINT", disposeInitialHtmlWorker);
1629
1691
  process.once("SIGTERM", disposeInitialHtmlWorker);
1630
- return async function handleRequest(req, res) {
1692
+ const handleRequest = async (req, res) => {
1631
1693
  if (!req.url) {
1632
1694
  res.statusCode = 400;
1633
1695
  res.end("Bad request");
@@ -1691,6 +1753,7 @@ function createNodeRequestHandler(options) {
1691
1753
  request: requestContext
1692
1754
  })
1693
1755
  );
1756
+ resolved2.head = { ...resolved2.head, basename: resolved2.head.basename ?? basePath };
1694
1757
  attachResolvedContextToCoreRequest(req, resolved2.context);
1695
1758
  const payload = {
1696
1759
  model: resolved2.model,
@@ -1766,6 +1829,7 @@ function createNodeRequestHandler(options) {
1766
1829
  )
1767
1830
  })
1768
1831
  );
1832
+ resolved.head = { ...resolved.head, basename: resolved.head.basename ?? basePath };
1769
1833
  attachResolvedContextToCoreRequest(req, resolved.context);
1770
1834
  const initialPayload = {
1771
1835
  model: resolved.model,
@@ -1838,6 +1902,8 @@ function createNodeRequestHandler(options) {
1838
1902
  initialFlightData,
1839
1903
  basename: shellBasename,
1840
1904
  routeBasePath: shellRouteBasePath,
1905
+ bodyStartHtml: resolved.head.bodyStartHtml || "",
1906
+ bodyEndHtml: resolved.head.bodyEndHtml || "",
1841
1907
  liveReloadPath: liveReloadPath || void 0,
1842
1908
  liveReloadServerId: liveReloadPath ? devServerId : void 0
1843
1909
  }),
@@ -1849,8 +1915,30 @@ function createNodeRequestHandler(options) {
1849
1915
  }
1850
1916
  );
1851
1917
  };
1918
+ return (req, res) => withRequestBasename(basePath, () => handleRequest(req, res));
1919
+ }
1920
+ var standaloneHtmlWorker;
1921
+ async function renderReactToHtml(element) {
1922
+ if (!standaloneHtmlWorker) {
1923
+ standaloneHtmlWorker = createInitialHtmlWorker(process.cwd());
1924
+ process.once("exit", disposeReactHtmlRenderer);
1925
+ }
1926
+ const flightData = await renderRSCToString({ model: element }, {
1927
+ moduleMap: {},
1928
+ onError: (error) => {
1929
+ console.error("[webframez-react] HTML render failed", error);
1930
+ }
1931
+ });
1932
+ return standaloneHtmlWorker.renderFromFlightData({ flightData, moduleMap: {} });
1933
+ }
1934
+ function disposeReactHtmlRenderer() {
1935
+ process.removeListener("exit", disposeReactHtmlRenderer);
1936
+ standaloneHtmlWorker?.dispose();
1937
+ standaloneHtmlWorker = void 0;
1852
1938
  }
1853
1939
  // Annotate the CommonJS export names for ESM import in node:
1854
1940
  0 && (module.exports = {
1855
- createNodeRequestHandler
1941
+ createNodeRequestHandler,
1942
+ disposeReactHtmlRenderer,
1943
+ renderReactToHtml
1856
1944
  });
package/dist/http.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { RouteDataHook } from "./types";
2
3
 
3
4
  export type WebframezReactRoutePath = `/${string}` | "/";
4
5
  export type WebframezReactAssetsPrefix = `${WebframezReactRoutePath}/` | "/";
@@ -20,8 +21,12 @@ export interface CreateNodeHandlerRoutingOptions {
20
21
  export interface CreateNodeHandlerOptions
21
22
  extends CreateNodeHandlerPathsOptions,
22
23
  CreateNodeHandlerRoutingOptions {
24
+ onData?: RouteDataHook;
23
25
  }
24
26
 
25
27
  export function createNodeRequestHandler(
26
28
  options: CreateNodeHandlerOptions
27
29
  ): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
30
+
31
+ export function renderReactToHtml(element: unknown): Promise<string>;
32
+ export function disposeReactHtmlRenderer(): void;