@webtypen/webframez-react 0.0.36 → 0.0.38

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/dist/client.cjs CHANGED
@@ -1 +1 @@
1
- var se=Object.create;var y=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var ue=Object.getPrototypeOf,le=Object.prototype.hasOwnProperty;var fe=(e,t)=>{for(var n in t)y(e,n,{get:t[n],enumerable:!0})},L=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of de(t))!le.call(e,r)&&r!==n&&y(e,r,{get:()=>t[r],enumerable:!(o=ce(t,r))||o.enumerable});return e};var H=(e,t,n)=>(n=e!=null?se(ue(e)):{},L(t||!e||!e.__esModule?y(n,"default",{value:e,enumerable:!0}):n,e)),pe=e=>L(y({},"__esModule",{value:!0}),e);var be={};fe(be,{mountWebframezClient:()=>ve,useCookie:()=>Ee,useRouter:()=>Ae});module.exports=pe(be);var s=H(require("react"),1),Z=require("react-dom/client"),R=require("react-server-dom-webpack/client"),K=require("@webtypen/webframez-react/route-slot");var me=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function u(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function U(e,t){let n=e.trim(),o=u(t);return!n||!o||me.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=u(e.basename)??u(t),o=u(e.routeBasePath),r=u(e.transportBasePath),a={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return a.favicon&&(a.favicon=U(a.favicon,n)),a.links&&(a.links=a.links.map(c=>({...c,href:U(c.href,n)}))),a}var m=H(require("react"),1),$="webframez-route-children",W="__webframezRouteChildren",D="WebframezRouteChildren",N=()=>m.default.createElement($);N.displayName=D;N[W]=!0;var Re=N;function z(e){if(e===$||e===Re)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[W]===!0||t.displayName===D||t.name==="RouteChildren"}catch{return!1}}function M(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 l=!1,g=e.map(p=>{let w=E(p,t);return w!==p&&(l=!0),w});return l?g:e}if(M(e)&&z(e.type))return t;let n=m.default.isValidElement(e);if(!n&&!M(e))return e;if(n&&z(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)?m.default.cloneElement(e,void 0,...r):m.default.cloneElement(e,void 0,r);let a=e,c={...a.props??{},children:r,...a.key!==void 0&&a.key!==null?{key:a.key}:{}};return m.default.createElement(a.type,c)}var d=require("react/jsx-runtime"),ge={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},A=typeof s.default.createContext=="function"?s.default.createContext(null):null,V="__WEBFRAMEZ_ROUTER__",we="[data-webframez-head='true']";function F(){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 v(e){return u(e)??""}function he(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function X(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function _e(){return v(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function J(e){if(typeof window>"u")return e||"/";let t=v(window.__RSC_BASENAME),n=_e(),o=he(e||"/",t);return X(n,o)}function Q(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function Ce(){return typeof window>"u"?null:window[V]??null}function ye(e){typeof window>"u"||(window[V]=e)}function j(){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("="),a=r>=0?o.slice(0,r).trim():o,c=r>=0?o.slice(r+1):"";a&&(e[a]=decodeURIComponent(c))}return e}function q(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 Ee(){return s.default.useMemo(()=>({all:()=>j(),get:e=>j()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=q(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=q(e,"",{...t??{},maxAge:0}))}}),[])}function Ae(){let e=A?s.default.useContext(A):null;if(!e){let t=Ce();if(t)return t;if(typeof window>"u")return ge;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Te({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 G(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 Y(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){if(typeof document>"u")return;let t=S(e)??e;ee(t),document.title=t.title||"Webframez React";for(let n of document.head.querySelectorAll(we))n.remove();t.description&&G({name:"description",content:t.description}),t.favicon&&Y({rel:"icon",href:t.favicon});for(let n of t.meta??[])G(n);for(let n of t.links??[])Y(n)}function ee(e){if(typeof window>"u")return;let t=S(e)??e,n=u(t.basename),o=u(t.routeBasePath),r=u(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=X(r,"/rsc"))}function Pe(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function Se(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,(0,R.createFromReadableStream)(Pe(e)))}function Ne(e){let t=Q(e),n=J(window.location.pathname);return Se()??(0,R.createFromFetch)(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function xe(e,t){return function(){let o=s.default.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[a,c]=(0,s.useState)(o.model),[l,g]=(0,s.useState)(o.contextModel),[p,w]=(0,s.useState)(o.pageModel),[b,I]=(0,s.useState)(o.head),[te,h]=(0,s.useState)(!1),[ne,oe]=(0,s.useState)(!1),[re,T]=(0,s.useState)(r);async function O(i){let C=Q(t),f=J(i.pathname);return await(0,R.createFromFetch)(fetch(`${C}?path=${encodeURIComponent(f)}&search=${encodeURIComponent(i.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}async function _(i,C="push"){h(!0);try{let f=await O(i);x(f.head),I(f.head),c(f.model),g(f.contextModel),w(f.pageModel),T(!0);let P=`${i.pathname}${i.search}`;C==="replace"?(history.replaceState(null,"",P),F()):C==="push"&&(history.pushState(null,"",P),F())}catch(f){console.error("[webframez-react] Failed to render route",f),c((0,d.jsx)("p",{children:"Failed to load route."}))}finally{h(!1)}}async function ie(){h(!0);try{let i=await O(new URL(window.location.href));if(x(i.head),I(i.head),Object.prototype.hasOwnProperty.call(i,"contextModel")){g(i.contextModel),T(!0);return}c(i.model),T(!1)}catch(i){console.error("[webframez-react] Failed to refresh route context",i)}finally{h(!1)}}(0,s.useEffect)(()=>{x(b)},[b]),(0,s.useEffect)(()=>{oe(!0);let i=()=>{_(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let k=s.default.useMemo(()=>({push:i=>{_(new URL(i,window.location.origin),"push")},replace:i=>{_(new URL(i,window.location.origin),"replace")},refresh:()=>{_(new URL(window.location.href),"none")},refreshContext:()=>{ie()}}),[]);ye(k);let ae=re&&typeof p<"u"?l?(0,d.jsx)(K.RouteChildrenSlotProvider,{page:p,children:E(l,p)}):p:a,B=(0,d.jsxs)(d.Fragment,{children:[ne?(0,d.jsx)(Te,{active:te}):null,ae??(0,d.jsx)("p",{style:{padding:24},children:"Loading..."})]});return A?(0,d.jsx)(A.Provider,{value:k,children:B}):B}}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",a=Promise.resolve(Ne(r)).then(l=>(l?.head&&ee(l.head),l)),c=xe(a,r);return(0,Z.hydrateRoot)(n,(0,d.jsx)(c,{}))}
1
+ var ce=Object.create;var E=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var le=Object.getPrototypeOf,fe=Object.prototype.hasOwnProperty;var pe=(e,t)=>{for(var n in t)E(e,n,{get:t[n],enumerable:!0})},U=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ue(t))!fe.call(e,r)&&r!==n&&E(e,r,{get:()=>t[r],enumerable:!(o=de(t,r))||o.enumerable});return e};var H=(e,t,n)=>(n=e!=null?ce(le(e)):{},U(t||!e||!e.__esModule?E(n,"default",{value:e,enumerable:!0}):n,e)),me=e=>U(E({},"__esModule",{value:!0}),e);var ke={};pe(ke,{mountWebframezClient:()=>Oe,useCookie:()=>Ne,useRouter:()=>ve});module.exports=me(ke);var s=H(require("react"),1),K=require("react-dom/client"),w=require("react-server-dom-webpack/client"),V=require("@webtypen/webframez-react/route-slot");var Re=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function u(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function z(e,t){let n=e.trim(),o=u(t);return!n||!o||Re.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=u(e.basename)??u(t),o=u(e.routeBasePath),r=u(e.transportBasePath),a={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return a.favicon&&(a.favicon=z(a.favicon,n)),a.links&&(a.links=a.links.map(c=>({...c,href:z(c.href,n)}))),a}var m=H(require("react"),1),D="webframez-route-children",W="__webframezRouteChildren",F="WebframezRouteChildren",N=()=>m.default.createElement(D);N.displayName=F;N[W]=!0;var we=N;function M(e){if(e===D||e===we)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[W]===!0||t.displayName===F||t.name==="RouteChildren"}catch{return!1}}function $(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function A(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let l=!1,_=e.map(p=>{let h=A(p,t);return h!==p&&(l=!0),h});return l?_:e}if($(e)&&M(e.type))return t;let n=m.default.isValidElement(e);if(!n&&!$(e))return e;if(n&&M(e.type))return t;let o=e.props??{};if(!("children"in o))return e;let r=A(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 a=e,c={...a.props??{},children:r,...a.key!==void 0&&a.key!==null?{key:a.key}:{}};return m.default.createElement(a.type,c)}var d=require("react/jsx-runtime"),_e={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},T=typeof s.default.createContext=="function"?s.default.createContext(null):null,X="__WEBFRAMEZ_ROUTER__",he="__WEBFRAMEZ_REACT_BUILD_ID",ge="x-webframez-react-build",Ce="[data-webframez-head='true']";function j(){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 u(e)??""}function ye(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 Ee(){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=Ee(),o=ye(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 Ae(){if(typeof window>"u")return"";let e=window[he];return typeof e=="string"?e:""}function Te(e){let t=Ae();return!!t&&!!e&&t!==e}function v(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function Pe(){return typeof window>"u"?null:window[X]??null}function Se(e){typeof window>"u"||(window[X]=e)}function G(){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("="),a=r>=0?o.slice(0,r).trim():o,c=r>=0?o.slice(r+1):"";a&&(e[a]=decodeURIComponent(c))}return e}function q(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 Ne(){return s.default.useMemo(()=>({all:()=>G(),get:e=>G()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=q(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=q(e,"",{...t??{},maxAge:0}))}}),[])}function ve(){let e=T?s.default.useContext(T):null;if(!e){let t=Pe();if(t)return t;if(typeof window>"u")return _e;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function xe({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 Y(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 Z(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){if(typeof document>"u")return;let t=S(e)??e;te(t),document.title=t.title||"Webframez React";for(let n of document.head.querySelectorAll(Ce))n.remove();t.description&&Y({name:"description",content:t.description}),t.favicon&&Z({rel:"icon",href:t.favicon});for(let n of t.meta??[])Y(n);for(let n of t.links??[])Z(n)}function te(e){if(typeof window>"u")return;let t=S(e)??e,n=u(t.basename),o=u(t.routeBasePath),r=u(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=J(r,"/rsc"))}function Ie(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,(0,w.createFromReadableStream)(Ie(e)))}function Le(e){let t=ee(e),n=Q(window.location.pathname);return Be()??(0,w.createFromFetch)(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function be(e,t){return function(){let o=s.default.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[a,c]=(0,s.useState)(o.model),[l,_]=(0,s.useState)(o.contextModel),[p,h]=(0,s.useState)(o.pageModel),[B,L]=(0,s.useState)(o.head),[ne,g]=(0,s.useState)(!1),[oe,re]=(0,s.useState)(!1),[ie,P]=(0,s.useState)(r);async function b(i){let y=ee(t),f=Q(i.pathname),R=await fetch(`${y}?path=${encodeURIComponent(f)}&search=${encodeURIComponent(i.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return Te(R.headers.get(ge))?(v(i),await new Promise(()=>{})):await(0,w.createFromFetch)(Promise.resolve(R))}async function C(i,y="push"){g(!0);try{let f=await b(i);x(f.head),L(f.head),c(f.model),_(f.contextModel),h(f.pageModel),P(!0);let R=`${i.pathname}${i.search}${i.hash}`;y==="replace"?(history.replaceState(null,"",R),j()):y==="push"&&(history.pushState(null,"",R),j())}catch(f){console.error("[webframez-react] Failed to render route",f),v(i),c((0,d.jsx)("p",{children:"Failed to load route."}))}finally{g(!1)}}async function ae(){g(!0);try{let i=await b(new URL(window.location.href));if(x(i.head),L(i.head),Object.prototype.hasOwnProperty.call(i,"contextModel")){_(i.contextModel),P(!0);return}c(i.model),P(!1)}catch(i){console.error("[webframez-react] Failed to refresh route context",i),v(new URL(window.location.href))}finally{g(!1)}}(0,s.useEffect)(()=>{x(B)},[B]),(0,s.useEffect)(()=>{re(!0);let i=()=>{C(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let O=s.default.useMemo(()=>({push:i=>{C(new URL(i,window.location.origin),"push")},replace:i=>{C(new URL(i,window.location.origin),"replace")},refresh:()=>{C(new URL(window.location.href),"none")},refreshContext:()=>{ae()}}),[]);Se(O);let se=ie&&typeof p<"u"?l?(0,d.jsx)(V.RouteChildrenSlotProvider,{page:p,children:A(l,p)}):p:a,k=(0,d.jsxs)(d.Fragment,{children:[oe?(0,d.jsx)(xe,{active:ne}):null,se??(0,d.jsx)("p",{style:{padding:24},children:"Loading..."})]});return T?(0,d.jsx)(T.Provider,{value:O,children:k}):k}}function Oe(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",a=Promise.resolve(Le(r)).then(l=>(l?.head&&te(l.head),l)),c=be(a,r);return(0,K.hydrateRoot)(n,(0,d.jsx)(c,{}))}
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- import m,{useEffect as $,useState as f}from"react";import{hydrateRoot as ae}from"react-dom/client";import{createFromFetch as G,createFromReadableStream as se}from"react-server-dom-webpack/client";import{RouteChildrenSlotProvider as ce}from"@webtypen/webframez-react/route-slot";var re=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function c(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function B(e,t){let n=e.trim(),o=c(t);return!n||!o||re.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=c(e.basename)??c(t),o=c(e.routeBasePath),r=c(e.transportBasePath),a={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return a.favicon&&(a.favicon=B(a.favicon,n)),a.links&&(a.links=a.links.map(s=>({...s,href:B(s.href,n)}))),a}import R from"react";var U="webframez-route-children",z="__webframezRouteChildren",M="WebframezRouteChildren",S=()=>R.createElement(U);S.displayName=M;S[z]=!0;var ie=S;function L(e){if(e===U||e===ie)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[z]===!0||t.displayName===M||t.name==="RouteChildren"}catch{return!1}}function H(e){if(!e||typeof e!="object")return!1;try{return"type"in e&&"props"in e}catch{return!1}}function y(e,t){if(e==null||typeof e=="boolean")return e;if(Array.isArray(e)){let d=!1,g=e.map(l=>{let w=y(l,t);return w!==l&&(d=!0),w});return d?g:e}if(H(e)&&L(e.type))return t;let n=R.isValidElement(e);if(!n&&!H(e))return e;if(n&&L(e.type))return t;let o=e.props??{};if(!("children"in o))return e;let r=y(o.children,t);if(r===o.children)return e;if(n)return Array.isArray(r)?R.cloneElement(e,void 0,...r):R.cloneElement(e,void 0,r);let a=e,s={...a.props??{},children:r,...a.key!==void 0&&a.key!==null?{key:a.key}:{}};return R.createElement(a.type,s)}import{Fragment as Ce,jsx as p,jsxs as ye}from"react/jsx-runtime";var de={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},E=typeof m.createContext=="function"?m.createContext(null):null,Y="__WEBFRAMEZ_ROUTER__",ue="[data-webframez-head='true']";function W(){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 c(e)??""}function le(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function Z(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function fe(){return x(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function K(e){if(typeof window>"u")return e||"/";let t=x(window.__RSC_BASENAME),n=fe(),o=le(e||"/",t);return Z(n,o)}function V(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function pe(){return typeof window>"u"?null:window[Y]??null}function me(e){typeof window>"u"||(window[Y]=e)}function D(){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("="),a=r>=0?o.slice(0,r).trim():o,s=r>=0?o.slice(r+1):"";a&&(e[a]=decodeURIComponent(s))}return e}function F(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 Ie(){return m.useMemo(()=>({all:()=>D(),get:e=>D()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=F(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=F(e,"",{...t??{},maxAge:0}))}}),[])}function Oe(){let e=E?m.useContext(E):null;if(!e){let t=pe();if(t)return t;if(typeof window>"u")return de;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Re({active:e}){return p("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 j(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 q(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 N(e){if(typeof document>"u")return;let t=P(e)??e;X(t),document.title=t.title||"Webframez React";for(let n of document.head.querySelectorAll(ue))n.remove();t.description&&j({name:"description",content:t.description}),t.favicon&&q({rel:"icon",href:t.favicon});for(let n of t.meta??[])j(n);for(let n of t.links??[])q(n)}function X(e){if(typeof window>"u")return;let t=P(e)??e,n=c(t.basename),o=c(t.routeBasePath),r=c(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=Z(r,"/rsc"))}function ge(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,se(ge(e)))}function he(e){let t=V(e),n=K(window.location.pathname);return we()??G(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function _e(e,t){return function(){let o=m.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[a,s]=f(o.model),[d,g]=f(o.contextModel),[l,w]=f(o.pageModel),[v,b]=f(o.head),[J,h]=f(!1),[Q,ee]=f(!1),[te,A]=f(r);async function I(i){let C=V(t),u=K(i.pathname);return await G(fetch(`${C}?path=${encodeURIComponent(u)}&search=${encodeURIComponent(i.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}async function _(i,C="push"){h(!0);try{let u=await I(i);N(u.head),b(u.head),s(u.model),g(u.contextModel),w(u.pageModel),A(!0);let T=`${i.pathname}${i.search}`;C==="replace"?(history.replaceState(null,"",T),W()):C==="push"&&(history.pushState(null,"",T),W())}catch(u){console.error("[webframez-react] Failed to render route",u),s(p("p",{children:"Failed to load route."}))}finally{h(!1)}}async function ne(){h(!0);try{let i=await I(new URL(window.location.href));if(N(i.head),b(i.head),Object.prototype.hasOwnProperty.call(i,"contextModel")){g(i.contextModel),A(!0);return}s(i.model),A(!1)}catch(i){console.error("[webframez-react] Failed to refresh route context",i)}finally{h(!1)}}$(()=>{N(v)},[v]),$(()=>{ee(!0);let i=()=>{_(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let O=m.useMemo(()=>({push:i=>{_(new URL(i,window.location.origin),"push")},replace:i=>{_(new URL(i,window.location.origin),"replace")},refresh:()=>{_(new URL(window.location.href),"none")},refreshContext:()=>{ne()}}),[]);me(O);let oe=te&&typeof l<"u"?d?p(ce,{page:l,children:y(d,l)}):l:a,k=ye(Ce,{children:[Q?p(Re,{active:J}):null,oe??p("p",{style:{padding:24},children:"Loading..."})]});return E?p(E.Provider,{value:O,children:k}):k}}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",a=Promise.resolve(he(r)).then(d=>(d?.head&&X(d.head),d)),s=_e(a,r);return ae(n,p(s,{}))}export{ke as mountWebframezClient,Ie as useCookie,Oe as useRouter};
1
+ import m,{useEffect as D,useState as f}from"react";import{hydrateRoot as se}from"react-dom/client";import{createFromFetch as Y,createFromReadableStream as ce}from"react-server-dom-webpack/client";import{RouteChildrenSlotProvider as de}from"@webtypen/webframez-react/route-slot";var ie=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function c(e){if(typeof e!="string")return;let t=e.trim();return!t||t==="/"?"":t.replace(/\/+$/,"")}function k(e,t){let n=e.trim(),o=c(t);return!n||!o||ie.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=c(e.basename)??c(t),o=c(e.routeBasePath),r=c(e.transportBasePath),a={...e,...n!==void 0?{basename:n}:{},...o!==void 0?{routeBasePath:o}:{},...r!==void 0?{transportBasePath:r}:{}};return a.favicon&&(a.favicon=k(a.favicon,n)),a.links&&(a.links=a.links.map(s=>({...s,href:k(s.href,n)}))),a}import w from"react";var z="webframez-route-children",M="__webframezRouteChildren",$="WebframezRouteChildren",S=()=>w.createElement(z);S.displayName=$;S[M]=!0;var ae=S;function U(e){if(e===z||e===ae)return!0;if(!e||typeof e!="function"&&typeof e!="object")return!1;try{let t=e;return t[M]===!0||t.displayName===$||t.name==="RouteChildren"}catch{return!1}}function H(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 d=!1,_=e.map(l=>{let h=E(l,t);return h!==l&&(d=!0),h});return d?_:e}if(H(e)&&U(e.type))return t;let n=w.isValidElement(e);if(!n&&!H(e))return e;if(n&&U(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)?w.cloneElement(e,void 0,...r):w.cloneElement(e,void 0,r);let a=e,s={...a.props??{},children:r,...a.key!==void 0&&a.key!==null?{key:a.key}:{}};return w.createElement(a.type,s)}import{Fragment as Pe,jsx as p,jsxs as Se}from"react/jsx-runtime";var ue={push:()=>{},replace:()=>{},refresh:()=>{},refreshContext:()=>{}},A=typeof m.createContext=="function"?m.createContext(null):null,Z="__WEBFRAMEZ_ROUTER__",le="__WEBFRAMEZ_REACT_BUILD_ID",fe="x-webframez-react-build",pe="[data-webframez-head='true']";function W(){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 c(e)??""}function me(e,t){return t?e===t?"/":e.startsWith(`${t}/`)?e.slice(t.length)||"/":e||"/":e||"/"}function K(e,t){let n=!t||t==="/"?"/":t.startsWith("/")?t:`/${t}`;return e?n==="/"?e:`${e}${n}`:n}function Re(){return x(typeof window>"u"?globalThis.__RSC_ROUTE_BASE_PATH:window.__RSC_ROUTE_BASE_PATH)}function V(e){if(typeof window>"u")return e||"/";let t=x(window.__RSC_BASENAME),n=Re(),o=me(e||"/",t);return K(n,o)}function X(e){if(typeof window>"u")return e;let t=window.__RSC_ENDPOINT;return typeof t=="string"&&t.trim()!==""?t:e}function we(){if(typeof window>"u")return"";let e=window[le];return typeof e=="string"?e:""}function _e(e){let t=we();return!!t&&!!e&&t!==e}function N(e){typeof window>"u"||window.location.assign(`${e.pathname}${e.search}${e.hash}`)}function he(){return typeof window>"u"?null:window[Z]??null}function ge(e){typeof window>"u"||(window[Z]=e)}function F(){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("="),a=r>=0?o.slice(0,r).trim():o,s=r>=0?o.slice(r+1):"";a&&(e[a]=decodeURIComponent(s))}return e}function j(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 He(){return m.useMemo(()=>({all:()=>F(),get:e=>F()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=j(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=j(e,"",{...t??{},maxAge:0}))}}),[])}function ze(){let e=A?m.useContext(A):null;if(!e){let t=he();if(t)return t;if(typeof window>"u")return ue;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Ce({active:e}){return p("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 G(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 q(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 v(e){if(typeof document>"u")return;let t=P(e)??e;J(t),document.title=t.title||"Webframez React";for(let n of document.head.querySelectorAll(pe))n.remove();t.description&&G({name:"description",content:t.description}),t.favicon&&q({rel:"icon",href:t.favicon});for(let n of t.meta??[])G(n);for(let n of t.links??[])q(n)}function J(e){if(typeof window>"u")return;let t=P(e)??e,n=c(t.basename),o=c(t.routeBasePath),r=c(t.transportBasePath);window.__RSC_BASENAME=n??"",window.__RSC_ROUTE_BASE_PATH=o??"",r!==void 0&&(window.__RSC_ENDPOINT=K(r,"/rsc"))}function ye(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function Ee(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,ce(ye(e)))}function Ae(e){let t=X(e),n=V(window.location.pathname);return Ee()??Y(fetch(`${t}?path=${encodeURIComponent(n)}&search=${encodeURIComponent(window.location.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}}))}function Te(e,t){return function(){let o=m.use(e),r=typeof o.contextModel<"u"&&typeof o.pageModel<"u",[a,s]=f(o.model),[d,_]=f(o.contextModel),[l,h]=f(o.pageModel),[I,B]=f(o.head),[Q,g]=f(!1),[ee,te]=f(!1),[ne,T]=f(r);async function L(i){let y=X(t),u=V(i.pathname),R=await fetch(`${y}?path=${encodeURIComponent(u)}&search=${encodeURIComponent(i.search)}`,{cache:"no-store",credentials:"same-origin",headers:{Accept:"text/x-component"}});return _e(R.headers.get(fe))?(N(i),await new Promise(()=>{})):await Y(Promise.resolve(R))}async function C(i,y="push"){g(!0);try{let u=await L(i);v(u.head),B(u.head),s(u.model),_(u.contextModel),h(u.pageModel),T(!0);let R=`${i.pathname}${i.search}${i.hash}`;y==="replace"?(history.replaceState(null,"",R),W()):y==="push"&&(history.pushState(null,"",R),W())}catch(u){console.error("[webframez-react] Failed to render route",u),N(i),s(p("p",{children:"Failed to load route."}))}finally{g(!1)}}async function oe(){g(!0);try{let i=await L(new URL(window.location.href));if(v(i.head),B(i.head),Object.prototype.hasOwnProperty.call(i,"contextModel")){_(i.contextModel),T(!0);return}s(i.model),T(!1)}catch(i){console.error("[webframez-react] Failed to refresh route context",i),N(new URL(window.location.href))}finally{g(!1)}}D(()=>{v(I)},[I]),D(()=>{te(!0);let i=()=>{C(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let b=m.useMemo(()=>({push:i=>{C(new URL(i,window.location.origin),"push")},replace:i=>{C(new URL(i,window.location.origin),"replace")},refresh:()=>{C(new URL(window.location.href),"none")},refreshContext:()=>{oe()}}),[]);ge(b);let re=ne&&typeof l<"u"?d?p(de,{page:l,children:E(d,l)}):l:a,O=Se(Pe,{children:[ee?p(Ce,{active:Q}):null,re??p("p",{style:{padding:24},children:"Loading..."})]});return A?p(A.Provider,{value:b,children:O}):O}}function Me(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",a=Promise.resolve(Ae(r)).then(d=>(d?.head&&J(d.head),d)),s=Te(a,r);return se(n,p(s,{}))}export{Me as mountWebframezClient,He as useCookie,ze as useRouter};
package/dist/http.cjs CHANGED
@@ -52,6 +52,7 @@ function createHTMLShell(options = {}) {
52
52
  title = "RSC App",
53
53
  rscEndpoint = "/rsc",
54
54
  clientScriptUrl = "/client.js",
55
+ buildId = "",
55
56
  headTags = "",
56
57
  rootHtml = "",
57
58
  initialFlightData = "",
@@ -106,6 +107,7 @@ function createHTMLShell(options = {}) {
106
107
  <script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
107
108
  <script>window.__RSC_BASENAME = "${basename}";</script>
108
109
  <script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
110
+ <script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
109
111
  <script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
110
112
  <script type="module" src="${clientScriptUrl}"></script>
111
113
  ${liveReloadScript}
@@ -801,6 +803,15 @@ function createClientAssetVersion(distRootDir) {
801
803
  return "";
802
804
  }
803
805
  }
806
+ function createBuildId(distRootDir, manifestPath) {
807
+ const clientVersion = createClientAssetVersion(distRootDir);
808
+ try {
809
+ const stat = import_node_fs2.default.statSync(manifestPath);
810
+ return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
811
+ } catch {
812
+ return clientVersion;
813
+ }
814
+ }
804
815
  function appendAssetVersion(url, version) {
805
816
  if (!version) {
806
817
  return url;
@@ -1494,6 +1505,30 @@ function createServerConsumerManifest(manifest) {
1494
1505
  }
1495
1506
  return consumerManifest;
1496
1507
  }
1508
+ function createManifestLoader(options) {
1509
+ let cache = null;
1510
+ return () => {
1511
+ const stat = import_node_fs2.default.statSync(options.manifestPath);
1512
+ const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
1513
+ if (cache && cache.cacheKey === cacheKey) {
1514
+ return cache;
1515
+ }
1516
+ const moduleMap = normalizeClientManifest(
1517
+ JSON.parse(import_node_fs2.default.readFileSync(options.manifestPath, "utf-8")),
1518
+ {
1519
+ distRootDir: options.distRootDir,
1520
+ cwd: options.cwd
1521
+ }
1522
+ );
1523
+ cache = {
1524
+ cacheKey,
1525
+ buildId: createBuildId(options.distRootDir, options.manifestPath),
1526
+ moduleMap,
1527
+ serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
1528
+ };
1529
+ return cache;
1530
+ };
1531
+ }
1497
1532
  function createNodeRequestHandler(options) {
1498
1533
  const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1499
1534
  const distRootDir = import_node_path3.default.resolve(options.distRootDir);
@@ -1511,14 +1546,11 @@ function createNodeRequestHandler(options) {
1511
1546
  const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
1512
1547
  const liveReloadClients = /* @__PURE__ */ new Set();
1513
1548
  const router = createFileRouter({ pagesDir });
1514
- const moduleMap = normalizeClientManifest(
1515
- JSON.parse(import_node_fs2.default.readFileSync(manifestPath, "utf-8")),
1516
- {
1517
- distRootDir,
1518
- cwd: process.cwd()
1519
- }
1520
- );
1521
- const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
1549
+ const getManifestState = createManifestLoader({
1550
+ distRootDir,
1551
+ manifestPath,
1552
+ cwd: process.cwd()
1553
+ });
1522
1554
  const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
1523
1555
  const disposeInitialHtmlWorker = () => {
1524
1556
  initialHtmlWorker.dispose();
@@ -1573,6 +1605,7 @@ function createNodeRequestHandler(options) {
1573
1605
  return;
1574
1606
  }
1575
1607
  if (url.pathname === rscPath) {
1608
+ const manifestState2 = getManifestState();
1576
1609
  const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
1577
1610
  const requestContext = createRouteRequestContext(
1578
1611
  req,
@@ -1595,8 +1628,9 @@ function createNodeRequestHandler(options) {
1595
1628
  pageModel: resolved2.pageModel,
1596
1629
  head: resolved2.head
1597
1630
  };
1631
+ res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
1598
1632
  sendRSC(res, payload, {
1599
- moduleMap,
1633
+ moduleMap: manifestState2.moduleMap,
1600
1634
  statusCode: resolved2.statusCode
1601
1635
  });
1602
1636
  return;
@@ -1666,8 +1700,9 @@ function createNodeRequestHandler(options) {
1666
1700
  model: resolved.model,
1667
1701
  head: resolved.head
1668
1702
  };
1703
+ const manifestState = getManifestState();
1669
1704
  const initialFlightData = await renderRSCToString(initialPayload, {
1670
- moduleMap
1705
+ moduleMap: manifestState.moduleMap
1671
1706
  });
1672
1707
  const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
1673
1708
  const shellClientScriptUrl = appendAssetVersion(
@@ -1684,7 +1719,7 @@ function createNodeRequestHandler(options) {
1684
1719
  try {
1685
1720
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1686
1721
  flightData: initialFlightData,
1687
- moduleMap: serverConsumerModuleMap
1722
+ moduleMap: manifestState.serverConsumerModuleMap
1688
1723
  });
1689
1724
  } catch (error) {
1690
1725
  console.error("[webframez-react] Failed to render initial HTML", error);
@@ -1692,7 +1727,7 @@ function createNodeRequestHandler(options) {
1692
1727
  initialHtmlWorker.dispose();
1693
1728
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1694
1729
  flightData: initialFlightData,
1695
- moduleMap: serverConsumerModuleMap
1730
+ moduleMap: manifestState.serverConsumerModuleMap
1696
1731
  });
1697
1732
  } catch (retryError) {
1698
1733
  console.error("[webframez-react] Retry for initial HTML failed", retryError);
@@ -1700,7 +1735,7 @@ function createNodeRequestHandler(options) {
1700
1735
  initialHtmlWorker.dispose();
1701
1736
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1702
1737
  flightData: initialFlightData,
1703
- moduleMap: serverConsumerModuleMap
1738
+ moduleMap: manifestState.serverConsumerModuleMap
1704
1739
  });
1705
1740
  } catch (flightRenderError) {
1706
1741
  console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
@@ -1725,6 +1760,7 @@ function createNodeRequestHandler(options) {
1725
1760
  title: resolved.head.title || "Webframez React",
1726
1761
  headTags: renderHeadToString(resolved.head),
1727
1762
  clientScriptUrl: shellClientScriptUrl,
1763
+ buildId: manifestState.buildId,
1728
1764
  rscEndpoint: shellRscEndpoint,
1729
1765
  rootHtml,
1730
1766
  initialFlightData,
package/dist/http.js CHANGED
@@ -32,6 +32,7 @@ function createHTMLShell(options = {}) {
32
32
  title = "RSC App",
33
33
  rscEndpoint = "/rsc",
34
34
  clientScriptUrl = "/client.js",
35
+ buildId = "",
35
36
  headTags = "",
36
37
  rootHtml = "",
37
38
  initialFlightData = "",
@@ -86,6 +87,7 @@ function createHTMLShell(options = {}) {
86
87
  <script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
87
88
  <script>window.__RSC_BASENAME = "${basename}";</script>
88
89
  <script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
90
+ <script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
89
91
  <script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
90
92
  <script type="module" src="${clientScriptUrl}"></script>
91
93
  ${liveReloadScript}
@@ -781,6 +783,15 @@ function createClientAssetVersion(distRootDir) {
781
783
  return "";
782
784
  }
783
785
  }
786
+ function createBuildId(distRootDir, manifestPath) {
787
+ const clientVersion = createClientAssetVersion(distRootDir);
788
+ try {
789
+ const stat = fs2.statSync(manifestPath);
790
+ return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
791
+ } catch {
792
+ return clientVersion;
793
+ }
794
+ }
784
795
  function appendAssetVersion(url, version) {
785
796
  if (!version) {
786
797
  return url;
@@ -1474,6 +1485,30 @@ function createServerConsumerManifest(manifest) {
1474
1485
  }
1475
1486
  return consumerManifest;
1476
1487
  }
1488
+ function createManifestLoader(options) {
1489
+ let cache = null;
1490
+ return () => {
1491
+ const stat = fs2.statSync(options.manifestPath);
1492
+ const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
1493
+ if (cache && cache.cacheKey === cacheKey) {
1494
+ return cache;
1495
+ }
1496
+ const moduleMap = normalizeClientManifest(
1497
+ JSON.parse(fs2.readFileSync(options.manifestPath, "utf-8")),
1498
+ {
1499
+ distRootDir: options.distRootDir,
1500
+ cwd: options.cwd
1501
+ }
1502
+ );
1503
+ cache = {
1504
+ cacheKey,
1505
+ buildId: createBuildId(options.distRootDir, options.manifestPath),
1506
+ moduleMap,
1507
+ serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
1508
+ };
1509
+ return cache;
1510
+ };
1511
+ }
1477
1512
  function createNodeRequestHandler(options) {
1478
1513
  const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1479
1514
  const distRootDir = path3.resolve(options.distRootDir);
@@ -1491,14 +1526,11 @@ function createNodeRequestHandler(options) {
1491
1526
  const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
1492
1527
  const liveReloadClients = /* @__PURE__ */ new Set();
1493
1528
  const router = createFileRouter({ pagesDir });
1494
- const moduleMap = normalizeClientManifest(
1495
- JSON.parse(fs2.readFileSync(manifestPath, "utf-8")),
1496
- {
1497
- distRootDir,
1498
- cwd: process.cwd()
1499
- }
1500
- );
1501
- const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
1529
+ const getManifestState = createManifestLoader({
1530
+ distRootDir,
1531
+ manifestPath,
1532
+ cwd: process.cwd()
1533
+ });
1502
1534
  const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
1503
1535
  const disposeInitialHtmlWorker = () => {
1504
1536
  initialHtmlWorker.dispose();
@@ -1553,6 +1585,7 @@ function createNodeRequestHandler(options) {
1553
1585
  return;
1554
1586
  }
1555
1587
  if (url.pathname === rscPath) {
1588
+ const manifestState2 = getManifestState();
1556
1589
  const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
1557
1590
  const requestContext = createRouteRequestContext(
1558
1591
  req,
@@ -1575,8 +1608,9 @@ function createNodeRequestHandler(options) {
1575
1608
  pageModel: resolved2.pageModel,
1576
1609
  head: resolved2.head
1577
1610
  };
1611
+ res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
1578
1612
  sendRSC(res, payload, {
1579
- moduleMap,
1613
+ moduleMap: manifestState2.moduleMap,
1580
1614
  statusCode: resolved2.statusCode
1581
1615
  });
1582
1616
  return;
@@ -1646,8 +1680,9 @@ function createNodeRequestHandler(options) {
1646
1680
  model: resolved.model,
1647
1681
  head: resolved.head
1648
1682
  };
1683
+ const manifestState = getManifestState();
1649
1684
  const initialFlightData = await renderRSCToString(initialPayload, {
1650
- moduleMap
1685
+ moduleMap: manifestState.moduleMap
1651
1686
  });
1652
1687
  const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
1653
1688
  const shellClientScriptUrl = appendAssetVersion(
@@ -1664,7 +1699,7 @@ function createNodeRequestHandler(options) {
1664
1699
  try {
1665
1700
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1666
1701
  flightData: initialFlightData,
1667
- moduleMap: serverConsumerModuleMap
1702
+ moduleMap: manifestState.serverConsumerModuleMap
1668
1703
  });
1669
1704
  } catch (error) {
1670
1705
  console.error("[webframez-react] Failed to render initial HTML", error);
@@ -1672,7 +1707,7 @@ function createNodeRequestHandler(options) {
1672
1707
  initialHtmlWorker.dispose();
1673
1708
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1674
1709
  flightData: initialFlightData,
1675
- moduleMap: serverConsumerModuleMap
1710
+ moduleMap: manifestState.serverConsumerModuleMap
1676
1711
  });
1677
1712
  } catch (retryError) {
1678
1713
  console.error("[webframez-react] Retry for initial HTML failed", retryError);
@@ -1680,7 +1715,7 @@ function createNodeRequestHandler(options) {
1680
1715
  initialHtmlWorker.dispose();
1681
1716
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1682
1717
  flightData: initialFlightData,
1683
- moduleMap: serverConsumerModuleMap
1718
+ moduleMap: manifestState.serverConsumerModuleMap
1684
1719
  });
1685
1720
  } catch (flightRenderError) {
1686
1721
  console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
@@ -1705,6 +1740,7 @@ function createNodeRequestHandler(options) {
1705
1740
  title: resolved.head.title || "Webframez React",
1706
1741
  headTags: renderHeadToString(resolved.head),
1707
1742
  clientScriptUrl: shellClientScriptUrl,
1743
+ buildId: manifestState.buildId,
1708
1744
  rscEndpoint: shellRscEndpoint,
1709
1745
  rootHtml,
1710
1746
  initialFlightData,
package/dist/index.cjs CHANGED
@@ -59,6 +59,7 @@ function createHTMLShell(options = {}) {
59
59
  title = "RSC App",
60
60
  rscEndpoint = "/rsc",
61
61
  clientScriptUrl = "/client.js",
62
+ buildId = "",
62
63
  headTags = "",
63
64
  rootHtml = "",
64
65
  initialFlightData = "",
@@ -113,6 +114,7 @@ function createHTMLShell(options = {}) {
113
114
  <script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
114
115
  <script>window.__RSC_BASENAME = "${basename}";</script>
115
116
  <script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
117
+ <script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
116
118
  <script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
117
119
  <script type="module" src="${clientScriptUrl}"></script>
118
120
  ${liveReloadScript}
@@ -841,6 +843,15 @@ function createClientAssetVersion(distRootDir) {
841
843
  return "";
842
844
  }
843
845
  }
846
+ function createBuildId(distRootDir, manifestPath) {
847
+ const clientVersion = createClientAssetVersion(distRootDir);
848
+ try {
849
+ const stat = import_node_fs2.default.statSync(manifestPath);
850
+ return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
851
+ } catch {
852
+ return clientVersion;
853
+ }
854
+ }
844
855
  function appendAssetVersion(url, version) {
845
856
  if (!version) {
846
857
  return url;
@@ -1534,6 +1545,30 @@ function createServerConsumerManifest(manifest) {
1534
1545
  }
1535
1546
  return consumerManifest;
1536
1547
  }
1548
+ function createManifestLoader(options) {
1549
+ let cache = null;
1550
+ return () => {
1551
+ const stat = import_node_fs2.default.statSync(options.manifestPath);
1552
+ const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
1553
+ if (cache && cache.cacheKey === cacheKey) {
1554
+ return cache;
1555
+ }
1556
+ const moduleMap = normalizeClientManifest(
1557
+ JSON.parse(import_node_fs2.default.readFileSync(options.manifestPath, "utf-8")),
1558
+ {
1559
+ distRootDir: options.distRootDir,
1560
+ cwd: options.cwd
1561
+ }
1562
+ );
1563
+ cache = {
1564
+ cacheKey,
1565
+ buildId: createBuildId(options.distRootDir, options.manifestPath),
1566
+ moduleMap,
1567
+ serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
1568
+ };
1569
+ return cache;
1570
+ };
1571
+ }
1537
1572
  function createNodeRequestHandler(options) {
1538
1573
  const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1539
1574
  const distRootDir = import_node_path3.default.resolve(options.distRootDir);
@@ -1551,14 +1586,11 @@ function createNodeRequestHandler(options) {
1551
1586
  const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
1552
1587
  const liveReloadClients = /* @__PURE__ */ new Set();
1553
1588
  const router = createFileRouter({ pagesDir });
1554
- const moduleMap = normalizeClientManifest(
1555
- JSON.parse(import_node_fs2.default.readFileSync(manifestPath, "utf-8")),
1556
- {
1557
- distRootDir,
1558
- cwd: process.cwd()
1559
- }
1560
- );
1561
- const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
1589
+ const getManifestState = createManifestLoader({
1590
+ distRootDir,
1591
+ manifestPath,
1592
+ cwd: process.cwd()
1593
+ });
1562
1594
  const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
1563
1595
  const disposeInitialHtmlWorker = () => {
1564
1596
  initialHtmlWorker.dispose();
@@ -1613,6 +1645,7 @@ function createNodeRequestHandler(options) {
1613
1645
  return;
1614
1646
  }
1615
1647
  if (url.pathname === rscPath) {
1648
+ const manifestState2 = getManifestState();
1616
1649
  const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
1617
1650
  const requestContext = createRouteRequestContext(
1618
1651
  req,
@@ -1635,8 +1668,9 @@ function createNodeRequestHandler(options) {
1635
1668
  pageModel: resolved2.pageModel,
1636
1669
  head: resolved2.head
1637
1670
  };
1671
+ res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
1638
1672
  sendRSC(res, payload, {
1639
- moduleMap,
1673
+ moduleMap: manifestState2.moduleMap,
1640
1674
  statusCode: resolved2.statusCode
1641
1675
  });
1642
1676
  return;
@@ -1706,8 +1740,9 @@ function createNodeRequestHandler(options) {
1706
1740
  model: resolved.model,
1707
1741
  head: resolved.head
1708
1742
  };
1743
+ const manifestState = getManifestState();
1709
1744
  const initialFlightData = await renderRSCToString(initialPayload, {
1710
- moduleMap
1745
+ moduleMap: manifestState.moduleMap
1711
1746
  });
1712
1747
  const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
1713
1748
  const shellClientScriptUrl = appendAssetVersion(
@@ -1724,7 +1759,7 @@ function createNodeRequestHandler(options) {
1724
1759
  try {
1725
1760
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1726
1761
  flightData: initialFlightData,
1727
- moduleMap: serverConsumerModuleMap
1762
+ moduleMap: manifestState.serverConsumerModuleMap
1728
1763
  });
1729
1764
  } catch (error) {
1730
1765
  console.error("[webframez-react] Failed to render initial HTML", error);
@@ -1732,7 +1767,7 @@ function createNodeRequestHandler(options) {
1732
1767
  initialHtmlWorker.dispose();
1733
1768
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1734
1769
  flightData: initialFlightData,
1735
- moduleMap: serverConsumerModuleMap
1770
+ moduleMap: manifestState.serverConsumerModuleMap
1736
1771
  });
1737
1772
  } catch (retryError) {
1738
1773
  console.error("[webframez-react] Retry for initial HTML failed", retryError);
@@ -1740,7 +1775,7 @@ function createNodeRequestHandler(options) {
1740
1775
  initialHtmlWorker.dispose();
1741
1776
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1742
1777
  flightData: initialFlightData,
1743
- moduleMap: serverConsumerModuleMap
1778
+ moduleMap: manifestState.serverConsumerModuleMap
1744
1779
  });
1745
1780
  } catch (flightRenderError) {
1746
1781
  console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
@@ -1765,6 +1800,7 @@ function createNodeRequestHandler(options) {
1765
1800
  title: resolved.head.title || "Webframez React",
1766
1801
  headTags: renderHeadToString(resolved.head),
1767
1802
  clientScriptUrl: shellClientScriptUrl,
1803
+ buildId: manifestState.buildId,
1768
1804
  rscEndpoint: shellRscEndpoint,
1769
1805
  rootHtml,
1770
1806
  initialFlightData,
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ function createHTMLShell(options = {}) {
20
20
  title = "RSC App",
21
21
  rscEndpoint = "/rsc",
22
22
  clientScriptUrl = "/client.js",
23
+ buildId = "",
23
24
  headTags = "",
24
25
  rootHtml = "",
25
26
  initialFlightData = "",
@@ -74,6 +75,7 @@ function createHTMLShell(options = {}) {
74
75
  <script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
75
76
  <script>window.__RSC_BASENAME = "${basename}";</script>
76
77
  <script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
78
+ <script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
77
79
  <script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
78
80
  <script type="module" src="${clientScriptUrl}"></script>
79
81
  ${liveReloadScript}
@@ -807,6 +809,15 @@ function createClientAssetVersion(distRootDir) {
807
809
  return "";
808
810
  }
809
811
  }
812
+ function createBuildId(distRootDir, manifestPath) {
813
+ const clientVersion = createClientAssetVersion(distRootDir);
814
+ try {
815
+ const stat = fs2.statSync(manifestPath);
816
+ return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
817
+ } catch {
818
+ return clientVersion;
819
+ }
820
+ }
810
821
  function appendAssetVersion(url, version) {
811
822
  if (!version) {
812
823
  return url;
@@ -1500,6 +1511,30 @@ function createServerConsumerManifest(manifest) {
1500
1511
  }
1501
1512
  return consumerManifest;
1502
1513
  }
1514
+ function createManifestLoader(options) {
1515
+ let cache = null;
1516
+ return () => {
1517
+ const stat = fs2.statSync(options.manifestPath);
1518
+ const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
1519
+ if (cache && cache.cacheKey === cacheKey) {
1520
+ return cache;
1521
+ }
1522
+ const moduleMap = normalizeClientManifest(
1523
+ JSON.parse(fs2.readFileSync(options.manifestPath, "utf-8")),
1524
+ {
1525
+ distRootDir: options.distRootDir,
1526
+ cwd: options.cwd
1527
+ }
1528
+ );
1529
+ cache = {
1530
+ cacheKey,
1531
+ buildId: createBuildId(options.distRootDir, options.manifestPath),
1532
+ moduleMap,
1533
+ serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
1534
+ };
1535
+ return cache;
1536
+ };
1537
+ }
1503
1538
  function createNodeRequestHandler(options) {
1504
1539
  const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1505
1540
  const distRootDir = path3.resolve(options.distRootDir);
@@ -1517,14 +1552,11 @@ function createNodeRequestHandler(options) {
1517
1552
  const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
1518
1553
  const liveReloadClients = /* @__PURE__ */ new Set();
1519
1554
  const router = createFileRouter({ pagesDir });
1520
- const moduleMap = normalizeClientManifest(
1521
- JSON.parse(fs2.readFileSync(manifestPath, "utf-8")),
1522
- {
1523
- distRootDir,
1524
- cwd: process.cwd()
1525
- }
1526
- );
1527
- const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
1555
+ const getManifestState = createManifestLoader({
1556
+ distRootDir,
1557
+ manifestPath,
1558
+ cwd: process.cwd()
1559
+ });
1528
1560
  const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
1529
1561
  const disposeInitialHtmlWorker = () => {
1530
1562
  initialHtmlWorker.dispose();
@@ -1579,6 +1611,7 @@ function createNodeRequestHandler(options) {
1579
1611
  return;
1580
1612
  }
1581
1613
  if (url.pathname === rscPath) {
1614
+ const manifestState2 = getManifestState();
1582
1615
  const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
1583
1616
  const requestContext = createRouteRequestContext(
1584
1617
  req,
@@ -1601,8 +1634,9 @@ function createNodeRequestHandler(options) {
1601
1634
  pageModel: resolved2.pageModel,
1602
1635
  head: resolved2.head
1603
1636
  };
1637
+ res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
1604
1638
  sendRSC(res, payload, {
1605
- moduleMap,
1639
+ moduleMap: manifestState2.moduleMap,
1606
1640
  statusCode: resolved2.statusCode
1607
1641
  });
1608
1642
  return;
@@ -1672,8 +1706,9 @@ function createNodeRequestHandler(options) {
1672
1706
  model: resolved.model,
1673
1707
  head: resolved.head
1674
1708
  };
1709
+ const manifestState = getManifestState();
1675
1710
  const initialFlightData = await renderRSCToString(initialPayload, {
1676
- moduleMap
1711
+ moduleMap: manifestState.moduleMap
1677
1712
  });
1678
1713
  const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
1679
1714
  const shellClientScriptUrl = appendAssetVersion(
@@ -1690,7 +1725,7 @@ function createNodeRequestHandler(options) {
1690
1725
  try {
1691
1726
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1692
1727
  flightData: initialFlightData,
1693
- moduleMap: serverConsumerModuleMap
1728
+ moduleMap: manifestState.serverConsumerModuleMap
1694
1729
  });
1695
1730
  } catch (error) {
1696
1731
  console.error("[webframez-react] Failed to render initial HTML", error);
@@ -1698,7 +1733,7 @@ function createNodeRequestHandler(options) {
1698
1733
  initialHtmlWorker.dispose();
1699
1734
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1700
1735
  flightData: initialFlightData,
1701
- moduleMap: serverConsumerModuleMap
1736
+ moduleMap: manifestState.serverConsumerModuleMap
1702
1737
  });
1703
1738
  } catch (retryError) {
1704
1739
  console.error("[webframez-react] Retry for initial HTML failed", retryError);
@@ -1706,7 +1741,7 @@ function createNodeRequestHandler(options) {
1706
1741
  initialHtmlWorker.dispose();
1707
1742
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1708
1743
  flightData: initialFlightData,
1709
- moduleMap: serverConsumerModuleMap
1744
+ moduleMap: manifestState.serverConsumerModuleMap
1710
1745
  });
1711
1746
  } catch (flightRenderError) {
1712
1747
  console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
@@ -1731,6 +1766,7 @@ function createNodeRequestHandler(options) {
1731
1766
  title: resolved.head.title || "Webframez React",
1732
1767
  headTags: renderHeadToString(resolved.head),
1733
1768
  clientScriptUrl: shellClientScriptUrl,
1769
+ buildId: manifestState.buildId,
1734
1770
  rscEndpoint: shellRscEndpoint,
1735
1771
  rootHtml,
1736
1772
  initialFlightData,
@@ -56,6 +56,25 @@ function normalizeBase(base) {
56
56
  function isExternal(href) {
57
57
  return /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(href) || href.startsWith("//");
58
58
  }
59
+ function navigateWithClientRouter(href, mode = "push") {
60
+ const router = getClientRouter();
61
+ if (router) {
62
+ router[mode](href);
63
+ return;
64
+ }
65
+ window.setTimeout(() => {
66
+ const nextRouter = getClientRouter();
67
+ if (nextRouter) {
68
+ nextRouter[mode](href);
69
+ return;
70
+ }
71
+ if (mode === "replace") {
72
+ window.location.replace(href);
73
+ } else {
74
+ window.location.assign(href);
75
+ }
76
+ }, 0);
77
+ }
59
78
  function resolveHref(to, basename) {
60
79
  if (!to || to.trim() === "") {
61
80
  return "/";
@@ -100,12 +119,8 @@ function Link({ to, basename, onClick, ...rest }) {
100
119
  if (isExternal(resolvedHref)) {
101
120
  return;
102
121
  }
103
- const router = getClientRouter();
104
- if (!router) {
105
- return;
106
- }
107
122
  event.preventDefault();
108
- router.push(resolvedHref);
123
+ navigateWithClientRouter(resolvedHref);
109
124
  }
110
125
  }
111
126
  );
@@ -124,20 +139,7 @@ function Redirect({ to, basename, replace = true }) {
124
139
  }
125
140
  return;
126
141
  }
127
- const router = getClientRouter();
128
- if (router) {
129
- if (replace) {
130
- router.replace(resolvedHref);
131
- } else {
132
- router.push(resolvedHref);
133
- }
134
- return;
135
- }
136
- if (replace) {
137
- window.location.replace(resolvedHref);
138
- } else {
139
- window.location.assign(resolvedHref);
140
- }
142
+ navigateWithClientRouter(resolvedHref, replace ? "replace" : "push");
141
143
  }, 0);
142
144
  }
143
145
  }
@@ -33,6 +33,25 @@ function normalizeBase(base) {
33
33
  function isExternal(href) {
34
34
  return /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(href) || href.startsWith("//");
35
35
  }
36
+ function navigateWithClientRouter(href, mode = "push") {
37
+ const router = getClientRouter();
38
+ if (router) {
39
+ router[mode](href);
40
+ return;
41
+ }
42
+ window.setTimeout(() => {
43
+ const nextRouter = getClientRouter();
44
+ if (nextRouter) {
45
+ nextRouter[mode](href);
46
+ return;
47
+ }
48
+ if (mode === "replace") {
49
+ window.location.replace(href);
50
+ } else {
51
+ window.location.assign(href);
52
+ }
53
+ }, 0);
54
+ }
36
55
  function resolveHref(to, basename) {
37
56
  if (!to || to.trim() === "") {
38
57
  return "/";
@@ -77,12 +96,8 @@ function Link({ to, basename, onClick, ...rest }) {
77
96
  if (isExternal(resolvedHref)) {
78
97
  return;
79
98
  }
80
- const router = getClientRouter();
81
- if (!router) {
82
- return;
83
- }
84
99
  event.preventDefault();
85
- router.push(resolvedHref);
100
+ navigateWithClientRouter(resolvedHref);
86
101
  }
87
102
  }
88
103
  );
@@ -101,20 +116,7 @@ function Redirect({ to, basename, replace = true }) {
101
116
  }
102
117
  return;
103
118
  }
104
- const router = getClientRouter();
105
- if (router) {
106
- if (replace) {
107
- router.replace(resolvedHref);
108
- } else {
109
- router.push(resolvedHref);
110
- }
111
- return;
112
- }
113
- if (replace) {
114
- window.location.replace(resolvedHref);
115
- } else {
116
- window.location.assign(resolvedHref);
117
- }
119
+ navigateWithClientRouter(resolvedHref, replace ? "replace" : "push");
118
120
  }, 0);
119
121
  }
120
122
  }
package/dist/types.d.ts CHANGED
@@ -111,6 +111,7 @@ export type CreateHtmlShellOptions = {
111
111
  title?: string;
112
112
  rscEndpoint?: string;
113
113
  clientScriptUrl?: string;
114
+ buildId?: string;
114
115
  headTags?: string;
115
116
  rootHtml?: string;
116
117
  initialFlightData?: string;
@@ -59,6 +59,7 @@ function createHTMLShell(options = {}) {
59
59
  title = "RSC App",
60
60
  rscEndpoint = "/rsc",
61
61
  clientScriptUrl = "/client.js",
62
+ buildId = "",
62
63
  headTags = "",
63
64
  rootHtml = "",
64
65
  initialFlightData = "",
@@ -113,6 +114,7 @@ function createHTMLShell(options = {}) {
113
114
  <script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
114
115
  <script>window.__RSC_BASENAME = "${basename}";</script>
115
116
  <script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
117
+ <script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
116
118
  <script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
117
119
  <script type="module" src="${clientScriptUrl}"></script>
118
120
  ${liveReloadScript}
@@ -808,6 +810,15 @@ function createClientAssetVersion(distRootDir) {
808
810
  return "";
809
811
  }
810
812
  }
813
+ function createBuildId(distRootDir, manifestPath) {
814
+ const clientVersion = createClientAssetVersion(distRootDir);
815
+ try {
816
+ const stat = import_node_fs2.default.statSync(manifestPath);
817
+ return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
818
+ } catch {
819
+ return clientVersion;
820
+ }
821
+ }
811
822
  function appendAssetVersion(url, version) {
812
823
  if (!version) {
813
824
  return url;
@@ -1501,6 +1512,30 @@ function createServerConsumerManifest(manifest) {
1501
1512
  }
1502
1513
  return consumerManifest;
1503
1514
  }
1515
+ function createManifestLoader(options) {
1516
+ let cache = null;
1517
+ return () => {
1518
+ const stat = import_node_fs2.default.statSync(options.manifestPath);
1519
+ const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
1520
+ if (cache && cache.cacheKey === cacheKey) {
1521
+ return cache;
1522
+ }
1523
+ const moduleMap = normalizeClientManifest(
1524
+ JSON.parse(import_node_fs2.default.readFileSync(options.manifestPath, "utf-8")),
1525
+ {
1526
+ distRootDir: options.distRootDir,
1527
+ cwd: options.cwd
1528
+ }
1529
+ );
1530
+ cache = {
1531
+ cacheKey,
1532
+ buildId: createBuildId(options.distRootDir, options.manifestPath),
1533
+ moduleMap,
1534
+ serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
1535
+ };
1536
+ return cache;
1537
+ };
1538
+ }
1504
1539
  function createNodeRequestHandler(options) {
1505
1540
  const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1506
1541
  const distRootDir = import_node_path3.default.resolve(options.distRootDir);
@@ -1518,14 +1553,11 @@ function createNodeRequestHandler(options) {
1518
1553
  const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
1519
1554
  const liveReloadClients = /* @__PURE__ */ new Set();
1520
1555
  const router = createFileRouter({ pagesDir });
1521
- const moduleMap = normalizeClientManifest(
1522
- JSON.parse(import_node_fs2.default.readFileSync(manifestPath, "utf-8")),
1523
- {
1524
- distRootDir,
1525
- cwd: process.cwd()
1526
- }
1527
- );
1528
- const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
1556
+ const getManifestState = createManifestLoader({
1557
+ distRootDir,
1558
+ manifestPath,
1559
+ cwd: process.cwd()
1560
+ });
1529
1561
  const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
1530
1562
  const disposeInitialHtmlWorker = () => {
1531
1563
  initialHtmlWorker.dispose();
@@ -1580,6 +1612,7 @@ function createNodeRequestHandler(options) {
1580
1612
  return;
1581
1613
  }
1582
1614
  if (url.pathname === rscPath) {
1615
+ const manifestState2 = getManifestState();
1583
1616
  const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
1584
1617
  const requestContext = createRouteRequestContext(
1585
1618
  req,
@@ -1602,8 +1635,9 @@ function createNodeRequestHandler(options) {
1602
1635
  pageModel: resolved2.pageModel,
1603
1636
  head: resolved2.head
1604
1637
  };
1638
+ res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
1605
1639
  sendRSC(res, payload, {
1606
- moduleMap,
1640
+ moduleMap: manifestState2.moduleMap,
1607
1641
  statusCode: resolved2.statusCode
1608
1642
  });
1609
1643
  return;
@@ -1673,8 +1707,9 @@ function createNodeRequestHandler(options) {
1673
1707
  model: resolved.model,
1674
1708
  head: resolved.head
1675
1709
  };
1710
+ const manifestState = getManifestState();
1676
1711
  const initialFlightData = await renderRSCToString(initialPayload, {
1677
- moduleMap
1712
+ moduleMap: manifestState.moduleMap
1678
1713
  });
1679
1714
  const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
1680
1715
  const shellClientScriptUrl = appendAssetVersion(
@@ -1691,7 +1726,7 @@ function createNodeRequestHandler(options) {
1691
1726
  try {
1692
1727
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1693
1728
  flightData: initialFlightData,
1694
- moduleMap: serverConsumerModuleMap
1729
+ moduleMap: manifestState.serverConsumerModuleMap
1695
1730
  });
1696
1731
  } catch (error) {
1697
1732
  console.error("[webframez-react] Failed to render initial HTML", error);
@@ -1699,7 +1734,7 @@ function createNodeRequestHandler(options) {
1699
1734
  initialHtmlWorker.dispose();
1700
1735
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1701
1736
  flightData: initialFlightData,
1702
- moduleMap: serverConsumerModuleMap
1737
+ moduleMap: manifestState.serverConsumerModuleMap
1703
1738
  });
1704
1739
  } catch (retryError) {
1705
1740
  console.error("[webframez-react] Retry for initial HTML failed", retryError);
@@ -1707,7 +1742,7 @@ function createNodeRequestHandler(options) {
1707
1742
  initialHtmlWorker.dispose();
1708
1743
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1709
1744
  flightData: initialFlightData,
1710
- moduleMap: serverConsumerModuleMap
1745
+ moduleMap: manifestState.serverConsumerModuleMap
1711
1746
  });
1712
1747
  } catch (flightRenderError) {
1713
1748
  console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
@@ -1732,6 +1767,7 @@ function createNodeRequestHandler(options) {
1732
1767
  title: resolved.head.title || "Webframez React",
1733
1768
  headTags: renderHeadToString(resolved.head),
1734
1769
  clientScriptUrl: shellClientScriptUrl,
1770
+ buildId: manifestState.buildId,
1735
1771
  rscEndpoint: shellRscEndpoint,
1736
1772
  rootHtml,
1737
1773
  initialFlightData,
@@ -35,6 +35,7 @@ function createHTMLShell(options = {}) {
35
35
  title = "RSC App",
36
36
  rscEndpoint = "/rsc",
37
37
  clientScriptUrl = "/client.js",
38
+ buildId = "",
38
39
  headTags = "",
39
40
  rootHtml = "",
40
41
  initialFlightData = "",
@@ -89,6 +90,7 @@ function createHTMLShell(options = {}) {
89
90
  <script>window.__RSC_ENDPOINT = "${rscEndpoint}";</script>
90
91
  <script>window.__RSC_BASENAME = "${basename}";</script>
91
92
  <script>window.__RSC_ROUTE_BASE_PATH = "${routeBasePath}";</script>
93
+ <script>window.__WEBFRAMEZ_REACT_BUILD_ID = "${buildId}";</script>
92
94
  <script>window.__RSC_INITIAL_PAYLOAD = ${escapedInitialFlightData};</script>
93
95
  <script type="module" src="${clientScriptUrl}"></script>
94
96
  ${liveReloadScript}
@@ -784,6 +786,15 @@ function createClientAssetVersion(distRootDir) {
784
786
  return "";
785
787
  }
786
788
  }
789
+ function createBuildId(distRootDir, manifestPath) {
790
+ const clientVersion = createClientAssetVersion(distRootDir);
791
+ try {
792
+ const stat = fs2.statSync(manifestPath);
793
+ return `${clientVersion}:${Math.floor(stat.mtimeMs)}-${stat.size}`;
794
+ } catch {
795
+ return clientVersion;
796
+ }
797
+ }
787
798
  function appendAssetVersion(url, version) {
788
799
  if (!version) {
789
800
  return url;
@@ -1477,6 +1488,30 @@ function createServerConsumerManifest(manifest) {
1477
1488
  }
1478
1489
  return consumerManifest;
1479
1490
  }
1491
+ function createManifestLoader(options) {
1492
+ let cache = null;
1493
+ return () => {
1494
+ const stat = fs2.statSync(options.manifestPath);
1495
+ const cacheKey = `${Math.floor(stat.mtimeMs)}-${stat.size}`;
1496
+ if (cache && cache.cacheKey === cacheKey) {
1497
+ return cache;
1498
+ }
1499
+ const moduleMap = normalizeClientManifest(
1500
+ JSON.parse(fs2.readFileSync(options.manifestPath, "utf-8")),
1501
+ {
1502
+ distRootDir: options.distRootDir,
1503
+ cwd: options.cwd
1504
+ }
1505
+ );
1506
+ cache = {
1507
+ cacheKey,
1508
+ buildId: createBuildId(options.distRootDir, options.manifestPath),
1509
+ moduleMap,
1510
+ serverConsumerModuleMap: createServerConsumerManifest(moduleMap)
1511
+ };
1512
+ return cache;
1513
+ };
1514
+ }
1480
1515
  function createNodeRequestHandler(options) {
1481
1516
  const devServerId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
1482
1517
  const distRootDir = path3.resolve(options.distRootDir);
@@ -1494,14 +1529,11 @@ function createNodeRequestHandler(options) {
1494
1529
  const liveReloadPath = !liveReloadEnabled ? "" : options.liveReloadPath ?? `${basePath || ""}/__webframez_live_reload`;
1495
1530
  const liveReloadClients = /* @__PURE__ */ new Set();
1496
1531
  const router = createFileRouter({ pagesDir });
1497
- const moduleMap = normalizeClientManifest(
1498
- JSON.parse(fs2.readFileSync(manifestPath, "utf-8")),
1499
- {
1500
- distRootDir,
1501
- cwd: process.cwd()
1502
- }
1503
- );
1504
- const serverConsumerModuleMap = createServerConsumerManifest(moduleMap);
1532
+ const getManifestState = createManifestLoader({
1533
+ distRootDir,
1534
+ manifestPath,
1535
+ cwd: process.cwd()
1536
+ });
1505
1537
  const initialHtmlWorker = createInitialHtmlWorker(pagesDir);
1506
1538
  const disposeInitialHtmlWorker = () => {
1507
1539
  initialHtmlWorker.dispose();
@@ -1556,6 +1588,7 @@ function createNodeRequestHandler(options) {
1556
1588
  return;
1557
1589
  }
1558
1590
  if (url.pathname === rscPath) {
1591
+ const manifestState2 = getManifestState();
1559
1592
  const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
1560
1593
  const requestContext = createRouteRequestContext(
1561
1594
  req,
@@ -1578,8 +1611,9 @@ function createNodeRequestHandler(options) {
1578
1611
  pageModel: resolved2.pageModel,
1579
1612
  head: resolved2.head
1580
1613
  };
1614
+ res.setHeader("X-Webframez-React-Build", manifestState2.buildId);
1581
1615
  sendRSC(res, payload, {
1582
- moduleMap,
1616
+ moduleMap: manifestState2.moduleMap,
1583
1617
  statusCode: resolved2.statusCode
1584
1618
  });
1585
1619
  return;
@@ -1649,8 +1683,9 @@ function createNodeRequestHandler(options) {
1649
1683
  model: resolved.model,
1650
1684
  head: resolved.head
1651
1685
  };
1686
+ const manifestState = getManifestState();
1652
1687
  const initialFlightData = await renderRSCToString(initialPayload, {
1653
- moduleMap
1688
+ moduleMap: manifestState.moduleMap
1654
1689
  });
1655
1690
  const transportBasePath = normalizeRuntimeBasePath(resolved.head.transportBasePath) ?? normalizeRuntimeBasePath(basePath) ?? "";
1656
1691
  const shellClientScriptUrl = appendAssetVersion(
@@ -1667,7 +1702,7 @@ function createNodeRequestHandler(options) {
1667
1702
  try {
1668
1703
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1669
1704
  flightData: initialFlightData,
1670
- moduleMap: serverConsumerModuleMap
1705
+ moduleMap: manifestState.serverConsumerModuleMap
1671
1706
  });
1672
1707
  } catch (error) {
1673
1708
  console.error("[webframez-react] Failed to render initial HTML", error);
@@ -1675,7 +1710,7 @@ function createNodeRequestHandler(options) {
1675
1710
  initialHtmlWorker.dispose();
1676
1711
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1677
1712
  flightData: initialFlightData,
1678
- moduleMap: serverConsumerModuleMap
1713
+ moduleMap: manifestState.serverConsumerModuleMap
1679
1714
  });
1680
1715
  } catch (retryError) {
1681
1716
  console.error("[webframez-react] Retry for initial HTML failed", retryError);
@@ -1683,7 +1718,7 @@ function createNodeRequestHandler(options) {
1683
1718
  initialHtmlWorker.dispose();
1684
1719
  rootHtml = await initialHtmlWorker.renderFromFlightData({
1685
1720
  flightData: initialFlightData,
1686
- moduleMap: serverConsumerModuleMap
1721
+ moduleMap: manifestState.serverConsumerModuleMap
1687
1722
  });
1688
1723
  } catch (flightRenderError) {
1689
1724
  console.error("[webframez-react] Flight-to-HTML render failed", flightRenderError);
@@ -1708,6 +1743,7 @@ function createNodeRequestHandler(options) {
1708
1743
  title: resolved.head.title || "Webframez React",
1709
1744
  headTags: renderHeadToString(resolved.head),
1710
1745
  clientScriptUrl: shellClientScriptUrl,
1746
+ buildId: manifestState.buildId,
1711
1747
  rscEndpoint: shellRscEndpoint,
1712
1748
  rootHtml,
1713
1749
  initialFlightData,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webtypen/webframez-react",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "description": "TypeScript React RSC addition for @webtypen/webframez-core",
5
5
  "homepage": "https://webtypen.de/",
6
6
  "author": {