@webtypen/webframez-react 0.0.24 → 0.0.27

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
@@ -14,7 +14,7 @@ React Server Components (RSC) extension for `@webtypen/webframez-core`.
14
14
 
15
15
  - Node.js `>= 20`
16
16
  - `@webtypen/webframez-core`
17
- - React Experimental (matching the package peer dependencies)
17
+ - React 19.x with matching `react-dom` and `react-server-dom-webpack`
18
18
 
19
19
  ## Installation
20
20
 
@@ -130,6 +130,25 @@ Route.renderReact("/app", {
130
130
  - Additional route options forwarded to `webframez-core`.
131
131
  - Typical use case: middleware.
132
132
 
133
+ ## `Head()` Assets
134
+
135
+ Inside a page, layout, or error `Head()` method you can set `assetsBaseUrl`.
136
+ That base URL is applied to `favicon` and `links[].href`, which is useful for CSS
137
+ files and other head assets served from a CDN or shared asset host.
138
+
139
+ ```ts
140
+ export function Head() {
141
+ return {
142
+ title: "Dashboard",
143
+ assetsBaseUrl: "https://cdn.example.com/app",
144
+ favicon: "/favicon.ico",
145
+ links: [{ rel: "stylesheet", href: "/styles/dashboard.css" }],
146
+ };
147
+ }
148
+ ```
149
+
150
+ Absolute URLs like `https://...` or `//...` stay unchanged.
151
+
133
152
  ## Recommended Project Structure
134
153
 
135
154
  ```txt
@@ -6,9 +6,14 @@ const frameworkDistDir = path.resolve(__dirname, "..", "dist");
6
6
  const clientEntry = process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY
7
7
  ? path.resolve(projectRoot, process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY)
8
8
  : path.resolve(projectRoot, "src/client.tsx");
9
+ const isWatchMode = process.argv.includes("--watch");
10
+ const mode =
11
+ process.env.NODE_ENV === "production" || (typeof process.env.NODE_ENV === "undefined" && !isWatchMode)
12
+ ? "production"
13
+ : "development";
9
14
 
10
15
  module.exports = {
11
- mode: process.env.NODE_ENV === "production" ? "production" : "development",
16
+ mode,
12
17
  entry: {
13
18
  client: clientEntry,
14
19
  },
@@ -38,6 +43,8 @@ module.exports = {
38
43
  optimization: {
39
44
  splitChunks: false,
40
45
  runtimeChunk: false,
46
+ moduleIds: "named",
47
+ chunkIds: "named",
41
48
  },
42
49
  plugins: [
43
50
  new ReactFlightWebpackPlugin({
package/dist/client.cjs CHANGED
@@ -1 +1 @@
1
- var T=Object.create;var f=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var $=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var H=(e,t)=>{for(var n in t)f(e,n,{get:t[n],enumerable:!0})},v=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of U(t))!M.call(e,i)&&i!==n&&f(e,i,{get:()=>t[i],enumerable:!(o=N(t,i))||o.enumerable});return e};var W=(e,t,n)=>(n=e!=null?T($(e)):{},v(t||!e||!e.__esModule?f(n,"default",{value:e,enumerable:!0}):n,e)),D=e=>v(f({},"__esModule",{value:!0}),e);var Q={};H(Q,{mountWebframezClient:()=>J,useCookie:()=>Y,useRouter:()=>q});module.exports=D(Q);var r=W(require("react"),1),S=require("react-dom/client"),u=require("react-server-dom-webpack/client"),s=require("react/jsx-runtime"),F={push:()=>{},replace:()=>{},refresh:()=>{}},p=typeof r.default.createContext=="function"?r.default.createContext(null):null,k="__WEBFRAMEZ_ROUTER__",B="[data-webframez-head='true']";function z(){return typeof window>"u"?null:window[k]??null}function G(e){typeof window>"u"||(window[k]=e)}function A(){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 i=o.indexOf("="),c=i>=0?o.slice(0,i).trim():o,d=i>=0?o.slice(i+1):"";c&&(e[c]=decodeURIComponent(d))}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 Y(){return r.default.useMemo(()=>({all:()=>A(),get:e=>A()[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 q(){let e=p?r.default.useContext(p):null;if(!e){let t=z();if(t)return t;if(typeof window>"u")return F;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function Z({active:e}){return(0,s.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 E(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,i]of n)t.setAttribute(o,String(i));document.head.appendChild(t)}function I(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,i]of n)t.setAttribute(o,String(i));document.head.appendChild(t)}function b(e){if(!(typeof document>"u")){document.title=e.title||"Webframez React";for(let t of document.head.querySelectorAll(B))t.remove();e.description&&E({name:"description",content:e.description}),e.favicon&&I({rel:"icon",href:e.favicon});for(let t of e.meta??[])E(t);for(let t of e.links??[])I(t)}}function j(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function X(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,(0,u.createFromReadableStream)(j(e)))}function K(e){return X()??(0,u.createFromFetch)(fetch(`${e}?path=${encodeURIComponent(window.location.pathname)}&search=${encodeURIComponent(window.location.search)}`,{headers:{Accept:"text/x-component"}}))}function V(e,t){return function(){let o=r.default.use(e),[i,c]=(0,r.useState)(o.model),[d,g]=(0,r.useState)(o.head),[P,w]=(0,r.useState)(!1),[L,O]=(0,r.useState)(!1);async function l(a,C="push"){w(!0);try{let m=await(0,u.createFromFetch)(fetch(`${t}?path=${encodeURIComponent(a.pathname)}&search=${encodeURIComponent(a.search)}`,{headers:{Accept:"text/x-component"}}));b(m.head),g(m.head),c(m.model);let _=`${a.pathname}${a.search}`;C==="replace"?history.replaceState(null,"",_):C==="push"&&history.pushState(null,"",_)}catch(y){console.error("[webframez-react] Failed to render route",y),c((0,s.jsx)("p",{children:"Failed to load route."}))}finally{w(!1)}}(0,r.useEffect)(()=>{b(d)},[d]),(0,r.useEffect)(()=>{O(!0);let a=()=>{l(new URL(window.location.href),"none")};return window.addEventListener("popstate",a),()=>{window.removeEventListener("popstate",a)}},[]);let R=r.default.useMemo(()=>({push:a=>{l(new URL(a,window.location.origin),"push")},replace:a=>{l(new URL(a,window.location.origin),"replace")},refresh:()=>{l(new URL(window.location.href),"none")}}),[]);G(R);let h=(0,s.jsxs)(s.Fragment,{children:[L?(0,s.jsx)(Z,{active:P}):null,i??(0,s.jsx)("p",{style:{padding:24},children:"Loading..."})]});return p?(0,s.jsx)(p.Provider,{value:R,children:h}):h}}function J(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,i=e.rscEndpoint??o??"/rsc",c=K(i),d=V(c,i);return(0,S.hydrateRoot)(n,(0,s.jsx)(d,{}))}
1
+ var H=Object.create;var f=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var W=(e,n)=>{for(var t in n)f(e,t,{get:n[t],enumerable:!0})},v=(e,n,t,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of z(n))!M.call(e,r)&&r!==t&&f(e,r,{get:()=>n[r],enumerable:!(o=N(n,r))||o.enumerable});return e};var D=(e,n,t)=>(t=e!=null?H(B(e)):{},v(n||!e||!e.__esModule?f(t,"default",{value:e,enumerable:!0}):t,e)),F=e=>v(f({},"__esModule",{value:!0}),e);var oe={};W(oe,{mountWebframezClient:()=>ne,useCookie:()=>X,useRouter:()=>K});module.exports=F(oe);var i=D(require("react"),1),L=require("react-dom/client"),u=require("react-server-dom-webpack/client");var G=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function g(e){let n=e?.trim();if(n)return n==="/"?"/":n.replace(/\/+$/,"")}function x(e,n){let t=e.trim(),o=g(n);return!t||!o||G.test(t)||o!=="/"&&(t===o||t.startsWith(`${o}/`))?t:o==="/"?t.startsWith("/")?t:`/${t}`:t.startsWith("/")?`${o}${t}`:`${o}/${t}`}function E(e,n){if(!e)return;let t=g(e.assetsBaseUrl)??g(n),o={...e,...t?{assetsBaseUrl:t}:{}};return o.favicon&&(o.favicon=x(o.favicon,t)),o.links&&(o.links=o.links.map(r=>({...r,href:x(r.href,t)}))),o}var s=require("react/jsx-runtime"),Y={push:()=>{},replace:()=>{},refresh:()=>{}},p=typeof i.default.createContext=="function"?i.default.createContext(null):null,U="__WEBFRAMEZ_ROUTER__",Z="[data-webframez-head='true']";function q(){return typeof window>"u"?null:window[U]??null}function j(e){typeof window>"u"||(window[U]=e)}function S(){let e={},n=typeof document>"u"?"":document.cookie;if(!n||n.trim()==="")return e;for(let t of n.split(";")){let o=t.trim();if(!o)continue;let r=o.indexOf("="),d=r>=0?o.slice(0,r).trim():o,c=r>=0?o.slice(r+1):"";d&&(e[d]=decodeURIComponent(c))}return e}function k(e,n,t={}){let o=[`${e}=${encodeURIComponent(n)}`];return t.path&&o.push(`Path=${t.path}`),t.domain&&o.push(`Domain=${t.domain}`),typeof t.maxAge=="number"&&o.push(`Max-Age=${Math.floor(t.maxAge)}`),t.expires&&o.push(`Expires=${t.expires.toUTCString()}`),t.sameSite&&o.push(`SameSite=${t.sameSite}`),t.secure&&o.push("Secure"),o.join("; ")}function X(){return i.default.useMemo(()=>({all:()=>S(),get:e=>S()[e],set:(e,n,t)=>{typeof document>"u"||(document.cookie=k(e,n,t))},remove:(e,n)=>{typeof document>"u"||(document.cookie=k(e,"",{...n??{},maxAge:0}))}}),[])}function K(){let e=p?i.default.useContext(p):null;if(!e){let n=q();if(n)return n;if(typeof window>"u")return Y;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function V({active:e}){return(0,s.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 I(e){let n=document.createElement("meta");n.setAttribute("data-webframez-head","true");let t=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of t)n.setAttribute(o,String(r));document.head.appendChild(n)}function b(e){let n=document.createElement("link");n.setAttribute("data-webframez-head","true");let t=Object.entries(e).filter(([,o])=>!!o);for(let[o,r]of t)n.setAttribute(o,String(r));document.head.appendChild(n)}function P(e){if(typeof document>"u")return;let n=E(e)??e;document.title=n.title||"Webframez React";for(let t of document.head.querySelectorAll(Z))t.remove();n.description&&I({name:"description",content:n.description}),n.favicon&&b({rel:"icon",href:n.favicon});for(let t of n.meta??[])I(t);for(let t of n.links??[])b(t)}function J(e){let n=new TextEncoder;return new ReadableStream({start(t){t.enqueue(n.encode(e)),t.close()}})}function Q(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,(0,u.createFromReadableStream)(J(e)))}function ee(e){return Q()??(0,u.createFromFetch)(fetch(`${e}?path=${encodeURIComponent(window.location.pathname)}&search=${encodeURIComponent(window.location.search)}`,{headers:{Accept:"text/x-component"}}))}function te(e,n){return function(){let o=i.default.use(e),[r,d]=(0,i.useState)(o.model),[c,h]=(0,i.useState)(o.head),[O,w]=(0,i.useState)(!1),[T,$]=(0,i.useState)(!1);async function l(a,A="push"){w(!0);try{let m=await(0,u.createFromFetch)(fetch(`${n}?path=${encodeURIComponent(a.pathname)}&search=${encodeURIComponent(a.search)}`,{headers:{Accept:"text/x-component"}}));P(m.head),h(m.head),d(m.model);let _=`${a.pathname}${a.search}`;A==="replace"?history.replaceState(null,"",_):A==="push"&&history.pushState(null,"",_)}catch(y){console.error("[webframez-react] Failed to render route",y),d((0,s.jsx)("p",{children:"Failed to load route."}))}finally{w(!1)}}(0,i.useEffect)(()=>{P(c)},[c]),(0,i.useEffect)(()=>{$(!0);let a=()=>{l(new URL(window.location.href),"none")};return window.addEventListener("popstate",a),()=>{window.removeEventListener("popstate",a)}},[]);let R=i.default.useMemo(()=>({push:a=>{l(new URL(a,window.location.origin),"push")},replace:a=>{l(new URL(a,window.location.origin),"replace")},refresh:()=>{l(new URL(window.location.href),"none")}}),[]);j(R);let C=(0,s.jsxs)(s.Fragment,{children:[T?(0,s.jsx)(V,{active:O}):null,r??(0,s.jsx)("p",{style:{padding:24},children:"Loading..."})]});return p?(0,s.jsx)(p.Provider,{value:R,children:C}):C}}function ne(e={}){let n=e.rootId??"root",t=document.getElementById(n);if(!t)throw new Error(`Missing #${n} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=e.rscEndpoint??o??"/rsc",d=ee(r),c=te(d,r);return(0,L.hydrateRoot)(t,(0,s.jsx)(c,{}))}
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- import d,{useEffect as _,useState as l}from"react";import{hydrateRoot as O}from"react-dom/client";import{createFromFetch as b,createFromReadableStream as T}from"react-server-dom-webpack/client";import{Fragment as z,jsx as c,jsxs as G}from"react/jsx-runtime";var N={push:()=>{},replace:()=>{},refresh:()=>{}},f=typeof d.createContext=="function"?d.createContext(null):null,S="__WEBFRAMEZ_ROUTER__",U="[data-webframez-head='true']";function $(){return typeof window>"u"?null:window[S]??null}function M(e){typeof window>"u"||(window[S]=e)}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 i=o.indexOf("="),a=i>=0?o.slice(0,i).trim():o,s=i>=0?o.slice(i+1):"";a&&(e[a]=decodeURIComponent(s))}return e}function A(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 j(){return d.useMemo(()=>({all:()=>v(),get:e=>v()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=A(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=A(e,"",{...t??{},maxAge:0}))}}),[])}function X(){let e=f?d.useContext(f):null;if(!e){let t=$();if(t)return t;if(typeof window>"u")return N;throw new Error("useRouter must be used inside mountWebframezClient()")}return e}function H({active:e}){return c("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 x(e){let t=document.createElement("meta");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,i]of n)t.setAttribute(o,String(i));document.head.appendChild(t)}function E(e){let t=document.createElement("link");t.setAttribute("data-webframez-head","true");let n=Object.entries(e).filter(([,o])=>!!o);for(let[o,i]of n)t.setAttribute(o,String(i));document.head.appendChild(t)}function I(e){if(!(typeof document>"u")){document.title=e.title||"Webframez React";for(let t of document.head.querySelectorAll(U))t.remove();e.description&&x({name:"description",content:e.description}),e.favicon&&E({rel:"icon",href:e.favicon});for(let t of e.meta??[])x(t);for(let t of e.links??[])E(t)}}function W(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.close()}})}function D(){if(typeof window>"u")return null;let e=window.__RSC_INITIAL_PAYLOAD;return typeof e!="string"||e===""?null:(delete window.__RSC_INITIAL_PAYLOAD,T(W(e)))}function F(e){return D()??b(fetch(`${e}?path=${encodeURIComponent(window.location.pathname)}&search=${encodeURIComponent(window.location.search)}`,{headers:{Accept:"text/x-component"}}))}function B(e,t){return function(){let o=d.use(e),[i,a]=l(o.model),[s,m]=l(o.head),[k,g]=l(!1),[P,L]=l(!1);async function u(r,h="push"){g(!0);try{let p=await b(fetch(`${t}?path=${encodeURIComponent(r.pathname)}&search=${encodeURIComponent(r.search)}`,{headers:{Accept:"text/x-component"}}));I(p.head),m(p.head),a(p.model);let y=`${r.pathname}${r.search}`;h==="replace"?history.replaceState(null,"",y):h==="push"&&history.pushState(null,"",y)}catch(C){console.error("[webframez-react] Failed to render route",C),a(c("p",{children:"Failed to load route."}))}finally{g(!1)}}_(()=>{I(s)},[s]),_(()=>{L(!0);let r=()=>{u(new URL(window.location.href),"none")};return window.addEventListener("popstate",r),()=>{window.removeEventListener("popstate",r)}},[]);let w=d.useMemo(()=>({push:r=>{u(new URL(r,window.location.origin),"push")},replace:r=>{u(new URL(r,window.location.origin),"replace")},refresh:()=>{u(new URL(window.location.href),"none")}}),[]);M(w);let R=G(z,{children:[P?c(H,{active:k}):null,i??c("p",{style:{padding:24},children:"Loading..."})]});return f?c(f.Provider,{value:w,children:R}):R}}function K(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,i=e.rscEndpoint??o??"/rsc",a=F(i),s=B(a,i);return O(n,c(s,{}))}export{K as mountWebframezClient,j as useCookie,X as useRouter};
1
+ import c,{useEffect as x,useState as l}from"react";import{hydrateRoot as H}from"react-dom/client";import{createFromFetch as P,createFromReadableStream as N}from"react-server-dom-webpack/client";var $=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function m(t){let n=t?.trim();if(n)return n==="/"?"/":n.replace(/\/+$/,"")}function _(t,n){let e=t.trim(),o=m(n);return!e||!o||$.test(e)||o!=="/"&&(e===o||e.startsWith(`${o}/`))?e:o==="/"?e.startsWith("/")?e:`/${e}`:e.startsWith("/")?`${o}${e}`:`${o}/${e}`}function v(t,n){if(!t)return;let e=m(t.assetsBaseUrl)??m(n),o={...t,...e?{assetsBaseUrl:e}:{}};return o.favicon&&(o.favicon=_(o.favicon,e)),o.links&&(o.links=o.links.map(r=>({...r,href:_(r.href,e)}))),o}import{Fragment as q,jsx as d,jsxs as j}from"react/jsx-runtime";var z={push:()=>{},replace:()=>{},refresh:()=>{}},f=typeof c.createContext=="function"?c.createContext(null):null,L="__WEBFRAMEZ_ROUTER__",B="[data-webframez-head='true']";function M(){return typeof window>"u"?null:window[L]??null}function W(t){typeof window>"u"||(window[L]=t)}function E(){let t={},n=typeof document>"u"?"":document.cookie;if(!n||n.trim()==="")return t;for(let e of n.split(";")){let o=e.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&&(t[a]=decodeURIComponent(s))}return t}function S(t,n,e={}){let o=[`${t}=${encodeURIComponent(n)}`];return e.path&&o.push(`Path=${e.path}`),e.domain&&o.push(`Domain=${e.domain}`),typeof e.maxAge=="number"&&o.push(`Max-Age=${Math.floor(e.maxAge)}`),e.expires&&o.push(`Expires=${e.expires.toUTCString()}`),e.sameSite&&o.push(`SameSite=${e.sameSite}`),e.secure&&o.push("Secure"),o.join("; ")}function ee(){return c.useMemo(()=>({all:()=>E(),get:t=>E()[t],set:(t,n,e)=>{typeof document>"u"||(document.cookie=S(t,n,e))},remove:(t,n)=>{typeof document>"u"||(document.cookie=S(t,"",{...n??{},maxAge:0}))}}),[])}function te(){let t=f?c.useContext(f):null;if(!t){let n=M();if(n)return n;if(typeof window>"u")return z;throw new Error("useRouter must be used inside mountWebframezClient()")}return t}function D({active:t}){return d("div",{style:{position:"fixed",top:0,left:0,width:"100%",height:3,zIndex:9999,transformOrigin:"left",transform:t?"scaleX(1)":"scaleX(0)",transition:"transform 180ms ease",background:"linear-gradient(90deg, #0ea5e9, #22c55e)"}})}function k(t){let n=document.createElement("meta");n.setAttribute("data-webframez-head","true");let e=Object.entries(t).filter(([,o])=>!!o);for(let[o,r]of e)n.setAttribute(o,String(r));document.head.appendChild(n)}function I(t){let n=document.createElement("link");n.setAttribute("data-webframez-head","true");let e=Object.entries(t).filter(([,o])=>!!o);for(let[o,r]of e)n.setAttribute(o,String(r));document.head.appendChild(n)}function b(t){if(typeof document>"u")return;let n=v(t)??t;document.title=n.title||"Webframez React";for(let e of document.head.querySelectorAll(B))e.remove();n.description&&k({name:"description",content:n.description}),n.favicon&&I({rel:"icon",href:n.favicon});for(let e of n.meta??[])k(e);for(let e of n.links??[])I(e)}function F(t){let n=new TextEncoder;return new ReadableStream({start(e){e.enqueue(n.encode(t)),e.close()}})}function G(){if(typeof window>"u")return null;let t=window.__RSC_INITIAL_PAYLOAD;return typeof t!="string"||t===""?null:(delete window.__RSC_INITIAL_PAYLOAD,N(F(t)))}function Y(t){return G()??P(fetch(`${t}?path=${encodeURIComponent(window.location.pathname)}&search=${encodeURIComponent(window.location.search)}`,{headers:{Accept:"text/x-component"}}))}function Z(t,n){return function(){let o=c.use(t),[r,a]=l(o.model),[s,g]=l(o.head),[U,h]=l(!1),[O,T]=l(!1);async function u(i,C="push"){h(!0);try{let p=await P(fetch(`${n}?path=${encodeURIComponent(i.pathname)}&search=${encodeURIComponent(i.search)}`,{headers:{Accept:"text/x-component"}}));b(p.head),g(p.head),a(p.model);let y=`${i.pathname}${i.search}`;C==="replace"?history.replaceState(null,"",y):C==="push"&&history.pushState(null,"",y)}catch(A){console.error("[webframez-react] Failed to render route",A),a(d("p",{children:"Failed to load route."}))}finally{h(!1)}}x(()=>{b(s)},[s]),x(()=>{T(!0);let i=()=>{u(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let w=c.useMemo(()=>({push:i=>{u(new URL(i,window.location.origin),"push")},replace:i=>{u(new URL(i,window.location.origin),"replace")},refresh:()=>{u(new URL(window.location.href),"none")}}),[]);W(w);let R=j(q,{children:[O?d(D,{active:U}):null,r??d("p",{style:{padding:24},children:"Loading..."})]});return f?d(f.Provider,{value:w,children:R}):R}}function ne(t={}){let n=t.rootId??"root",e=document.getElementById(n);if(!e)throw new Error(`Missing #${n} element`);let o=typeof window<"u"&&window.__RSC_ENDPOINT,r=t.rscEndpoint??o??"/rsc",a=Y(r),s=Z(a,r);return H(e,d(s,{}))}export{ne as mountWebframezClient,ee as useCookie,te as useRouter};
package/dist/http.cjs CHANGED
@@ -150,6 +150,62 @@ var import_node_fs = __toESM(require("node:fs"), 1);
150
150
  var import_node_module2 = __toESM(require("node:module"), 1);
151
151
  var import_node_path2 = __toESM(require("node:path"), 1);
152
152
 
153
+ // src/head.ts
154
+ var ABSOLUTE_ASSET_URL_PATTERN = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;
155
+ function normalizeAssetsBaseUrl(value) {
156
+ const trimmed = value?.trim();
157
+ if (!trimmed) {
158
+ return void 0;
159
+ }
160
+ if (trimmed === "/") {
161
+ return "/";
162
+ }
163
+ return trimmed.replace(/\/+$/, "");
164
+ }
165
+ function resolveHeadAssetUrl(assetUrl, assetsBaseUrl) {
166
+ const normalizedAssetUrl = assetUrl.trim();
167
+ const normalizedAssetsBaseUrl = normalizeAssetsBaseUrl(assetsBaseUrl);
168
+ if (!normalizedAssetUrl || !normalizedAssetsBaseUrl) {
169
+ return normalizedAssetUrl;
170
+ }
171
+ if (ABSOLUTE_ASSET_URL_PATTERN.test(normalizedAssetUrl)) {
172
+ return normalizedAssetUrl;
173
+ }
174
+ if (normalizedAssetsBaseUrl !== "/" && (normalizedAssetUrl === normalizedAssetsBaseUrl || normalizedAssetUrl.startsWith(`${normalizedAssetsBaseUrl}/`))) {
175
+ return normalizedAssetUrl;
176
+ }
177
+ if (normalizedAssetsBaseUrl === "/") {
178
+ return normalizedAssetUrl.startsWith("/") ? normalizedAssetUrl : `/${normalizedAssetUrl}`;
179
+ }
180
+ if (normalizedAssetUrl.startsWith("/")) {
181
+ return `${normalizedAssetsBaseUrl}${normalizedAssetUrl}`;
182
+ }
183
+ return `${normalizedAssetsBaseUrl}/${normalizedAssetUrl}`;
184
+ }
185
+ function normalizeHeadConfig(head, inheritedAssetsBaseUrl) {
186
+ if (!head) {
187
+ return void 0;
188
+ }
189
+ const effectiveAssetsBaseUrl = normalizeAssetsBaseUrl(head.assetsBaseUrl) ?? normalizeAssetsBaseUrl(inheritedAssetsBaseUrl);
190
+ const normalizedHead = {
191
+ ...head,
192
+ ...effectiveAssetsBaseUrl ? { assetsBaseUrl: effectiveAssetsBaseUrl } : {}
193
+ };
194
+ if (normalizedHead.favicon) {
195
+ normalizedHead.favicon = resolveHeadAssetUrl(
196
+ normalizedHead.favicon,
197
+ effectiveAssetsBaseUrl
198
+ );
199
+ }
200
+ if (normalizedHead.links) {
201
+ normalizedHead.links = normalizedHead.links.map((link) => ({
202
+ ...link,
203
+ href: resolveHeadAssetUrl(link.href, effectiveAssetsBaseUrl)
204
+ }));
205
+ }
206
+ return normalizedHead;
207
+ }
208
+
153
209
  // src/router-runtime.tsx
154
210
  var import_react = __toESM(require("react"), 1);
155
211
  var ROUTE_CHILDREN_TAG = "webframez-route-children";
@@ -365,7 +421,8 @@ function mergeHead(...configs) {
365
421
  meta: [],
366
422
  links: []
367
423
  };
368
- for (const config of configs) {
424
+ for (const candidate of configs) {
425
+ const config = normalizeHeadConfig(candidate, merged.assetsBaseUrl);
369
426
  if (!config) {
370
427
  continue;
371
428
  }
@@ -375,6 +432,9 @@ function mergeHead(...configs) {
375
432
  if (config.description) {
376
433
  merged.description = config.description;
377
434
  }
435
+ if (config.assetsBaseUrl) {
436
+ merged.assetsBaseUrl = config.assetsBaseUrl;
437
+ }
378
438
  if (config.favicon) {
379
439
  merged.favicon = config.favicon;
380
440
  }
@@ -388,22 +448,23 @@ function mergeHead(...configs) {
388
448
  return merged;
389
449
  }
390
450
  function renderHeadToString(head) {
451
+ const normalizedHead = normalizeHeadConfig(head) ?? head;
391
452
  const tags = [];
392
- if (head.description) {
453
+ if (normalizedHead.description) {
393
454
  tags.push(
394
- `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
455
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
395
456
  );
396
457
  }
397
- if (head.favicon) {
458
+ if (normalizedHead.favicon) {
398
459
  tags.push(
399
- `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
460
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
400
461
  );
401
462
  }
402
- for (const meta of head.meta ?? []) {
463
+ for (const meta of normalizedHead.meta ?? []) {
403
464
  const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
404
465
  tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
405
466
  }
406
- for (const link of head.links ?? []) {
467
+ for (const link of normalizedHead.links ?? []) {
407
468
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
408
469
  tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
409
470
  }
@@ -732,7 +793,21 @@ globalThis.__webpack_require__ = function __webframezNodeRequire(id) {
732
793
  }
733
794
 
734
795
  if (id.startsWith("./")) {
735
- return require(path.resolve(process.cwd(), id.slice(2)));
796
+ const relativeId = id.slice(2);
797
+ const candidates = [
798
+ path.resolve(process.cwd(), relativeId),
799
+ path.resolve(process.cwd(), "..", relativeId)
800
+ ];
801
+ for (const candidate of candidates) {
802
+ try {
803
+ return require(candidate);
804
+ } catch (error) {
805
+ const missingCandidate = error && error.code === "MODULE_NOT_FOUND" && typeof error.message === "string" && error.message.includes("'" + candidate + "'");
806
+ if (!missingCandidate) {
807
+ throw error;
808
+ }
809
+ }
810
+ }
736
811
  }
737
812
 
738
813
  return require(id);
@@ -1036,22 +1111,64 @@ function normalizeClientManifest(manifest, options) {
1036
1111
  }
1037
1112
  function createServerConsumerManifest(manifest) {
1038
1113
  const consumerManifest = {};
1114
+ const normalizeWorkerModuleId = (requestKey, rawModuleId) => {
1115
+ if (typeof rawModuleId === "string" && rawModuleId.trim() !== "") {
1116
+ return rawModuleId;
1117
+ }
1118
+ if (typeof rawModuleId !== "number" || !Number.isFinite(rawModuleId)) {
1119
+ return null;
1120
+ }
1121
+ if (!requestKey || requestKey.trim() === "") {
1122
+ return String(rawModuleId);
1123
+ }
1124
+ if (requestKey.startsWith("file://")) {
1125
+ try {
1126
+ return (0, import_node_url.fileURLToPath)(requestKey);
1127
+ } catch {
1128
+ return String(rawModuleId);
1129
+ }
1130
+ }
1131
+ if (requestKey.startsWith("/")) {
1132
+ return requestKey;
1133
+ }
1134
+ if (requestKey.startsWith("./")) {
1135
+ return requestKey;
1136
+ }
1137
+ if (requestKey.startsWith("node_modules/") || requestKey.startsWith("build/")) {
1138
+ return `./${requestKey}`;
1139
+ }
1140
+ return requestKey;
1141
+ };
1142
+ const addReference = (lookupKey, reference) => {
1143
+ if (!lookupKey || lookupKey.trim() === "") {
1144
+ return;
1145
+ }
1146
+ if (lookupKey in consumerManifest) {
1147
+ return;
1148
+ }
1149
+ consumerManifest[lookupKey] = {
1150
+ "*": reference
1151
+ };
1152
+ };
1039
1153
  for (const [key, value] of Object.entries(manifest)) {
1040
1154
  if (!value || typeof value !== "object") {
1041
1155
  continue;
1042
1156
  }
1043
1157
  const entry = value;
1044
- if (typeof entry.id !== "string" || entry.id.trim() === "") {
1158
+ const workerModuleId = normalizeWorkerModuleId(key, entry.id);
1159
+ if (!workerModuleId) {
1045
1160
  continue;
1046
1161
  }
1047
- consumerManifest[key] = {
1048
- "*": {
1049
- id: entry.id,
1050
- chunks: [],
1051
- name: entry.name ?? "*",
1052
- ...entry.async ? { async: entry.async } : {}
1053
- }
1162
+ const reference = {
1163
+ id: workerModuleId,
1164
+ chunks: Array.isArray(entry.chunks) ? entry.chunks : [],
1165
+ name: entry.name ?? "*",
1166
+ ...entry.async ? { async: entry.async } : {}
1054
1167
  };
1168
+ addReference(key, reference);
1169
+ if (typeof entry.id === "number" && Number.isFinite(entry.id)) {
1170
+ addReference(String(entry.id), reference);
1171
+ }
1055
1172
  }
1056
1173
  return consumerManifest;
1057
1174
  }
package/dist/http.js CHANGED
@@ -125,6 +125,62 @@ import fs from "node:fs";
125
125
  import Module from "node:module";
126
126
  import path2 from "node:path";
127
127
 
128
+ // src/head.ts
129
+ var ABSOLUTE_ASSET_URL_PATTERN = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;
130
+ function normalizeAssetsBaseUrl(value) {
131
+ const trimmed = value?.trim();
132
+ if (!trimmed) {
133
+ return void 0;
134
+ }
135
+ if (trimmed === "/") {
136
+ return "/";
137
+ }
138
+ return trimmed.replace(/\/+$/, "");
139
+ }
140
+ function resolveHeadAssetUrl(assetUrl, assetsBaseUrl) {
141
+ const normalizedAssetUrl = assetUrl.trim();
142
+ const normalizedAssetsBaseUrl = normalizeAssetsBaseUrl(assetsBaseUrl);
143
+ if (!normalizedAssetUrl || !normalizedAssetsBaseUrl) {
144
+ return normalizedAssetUrl;
145
+ }
146
+ if (ABSOLUTE_ASSET_URL_PATTERN.test(normalizedAssetUrl)) {
147
+ return normalizedAssetUrl;
148
+ }
149
+ if (normalizedAssetsBaseUrl !== "/" && (normalizedAssetUrl === normalizedAssetsBaseUrl || normalizedAssetUrl.startsWith(`${normalizedAssetsBaseUrl}/`))) {
150
+ return normalizedAssetUrl;
151
+ }
152
+ if (normalizedAssetsBaseUrl === "/") {
153
+ return normalizedAssetUrl.startsWith("/") ? normalizedAssetUrl : `/${normalizedAssetUrl}`;
154
+ }
155
+ if (normalizedAssetUrl.startsWith("/")) {
156
+ return `${normalizedAssetsBaseUrl}${normalizedAssetUrl}`;
157
+ }
158
+ return `${normalizedAssetsBaseUrl}/${normalizedAssetUrl}`;
159
+ }
160
+ function normalizeHeadConfig(head, inheritedAssetsBaseUrl) {
161
+ if (!head) {
162
+ return void 0;
163
+ }
164
+ const effectiveAssetsBaseUrl = normalizeAssetsBaseUrl(head.assetsBaseUrl) ?? normalizeAssetsBaseUrl(inheritedAssetsBaseUrl);
165
+ const normalizedHead = {
166
+ ...head,
167
+ ...effectiveAssetsBaseUrl ? { assetsBaseUrl: effectiveAssetsBaseUrl } : {}
168
+ };
169
+ if (normalizedHead.favicon) {
170
+ normalizedHead.favicon = resolveHeadAssetUrl(
171
+ normalizedHead.favicon,
172
+ effectiveAssetsBaseUrl
173
+ );
174
+ }
175
+ if (normalizedHead.links) {
176
+ normalizedHead.links = normalizedHead.links.map((link) => ({
177
+ ...link,
178
+ href: resolveHeadAssetUrl(link.href, effectiveAssetsBaseUrl)
179
+ }));
180
+ }
181
+ return normalizedHead;
182
+ }
183
+
128
184
  // src/router-runtime.tsx
129
185
  import React from "react";
130
186
  var ROUTE_CHILDREN_TAG = "webframez-route-children";
@@ -340,7 +396,8 @@ function mergeHead(...configs) {
340
396
  meta: [],
341
397
  links: []
342
398
  };
343
- for (const config of configs) {
399
+ for (const candidate of configs) {
400
+ const config = normalizeHeadConfig(candidate, merged.assetsBaseUrl);
344
401
  if (!config) {
345
402
  continue;
346
403
  }
@@ -350,6 +407,9 @@ function mergeHead(...configs) {
350
407
  if (config.description) {
351
408
  merged.description = config.description;
352
409
  }
410
+ if (config.assetsBaseUrl) {
411
+ merged.assetsBaseUrl = config.assetsBaseUrl;
412
+ }
353
413
  if (config.favicon) {
354
414
  merged.favicon = config.favicon;
355
415
  }
@@ -363,22 +423,23 @@ function mergeHead(...configs) {
363
423
  return merged;
364
424
  }
365
425
  function renderHeadToString(head) {
426
+ const normalizedHead = normalizeHeadConfig(head) ?? head;
366
427
  const tags = [];
367
- if (head.description) {
428
+ if (normalizedHead.description) {
368
429
  tags.push(
369
- `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
430
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
370
431
  );
371
432
  }
372
- if (head.favicon) {
433
+ if (normalizedHead.favicon) {
373
434
  tags.push(
374
- `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
435
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
375
436
  );
376
437
  }
377
- for (const meta of head.meta ?? []) {
438
+ for (const meta of normalizedHead.meta ?? []) {
378
439
  const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
379
440
  tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
380
441
  }
381
- for (const link of head.links ?? []) {
442
+ for (const link of normalizedHead.links ?? []) {
382
443
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
383
444
  tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
384
445
  }
@@ -707,7 +768,21 @@ globalThis.__webpack_require__ = function __webframezNodeRequire(id) {
707
768
  }
708
769
 
709
770
  if (id.startsWith("./")) {
710
- return require(path.resolve(process.cwd(), id.slice(2)));
771
+ const relativeId = id.slice(2);
772
+ const candidates = [
773
+ path.resolve(process.cwd(), relativeId),
774
+ path.resolve(process.cwd(), "..", relativeId)
775
+ ];
776
+ for (const candidate of candidates) {
777
+ try {
778
+ return require(candidate);
779
+ } catch (error) {
780
+ const missingCandidate = error && error.code === "MODULE_NOT_FOUND" && typeof error.message === "string" && error.message.includes("'" + candidate + "'");
781
+ if (!missingCandidate) {
782
+ throw error;
783
+ }
784
+ }
785
+ }
711
786
  }
712
787
 
713
788
  return require(id);
@@ -1011,22 +1086,64 @@ function normalizeClientManifest(manifest, options) {
1011
1086
  }
1012
1087
  function createServerConsumerManifest(manifest) {
1013
1088
  const consumerManifest = {};
1089
+ const normalizeWorkerModuleId = (requestKey, rawModuleId) => {
1090
+ if (typeof rawModuleId === "string" && rawModuleId.trim() !== "") {
1091
+ return rawModuleId;
1092
+ }
1093
+ if (typeof rawModuleId !== "number" || !Number.isFinite(rawModuleId)) {
1094
+ return null;
1095
+ }
1096
+ if (!requestKey || requestKey.trim() === "") {
1097
+ return String(rawModuleId);
1098
+ }
1099
+ if (requestKey.startsWith("file://")) {
1100
+ try {
1101
+ return fileURLToPath(requestKey);
1102
+ } catch {
1103
+ return String(rawModuleId);
1104
+ }
1105
+ }
1106
+ if (requestKey.startsWith("/")) {
1107
+ return requestKey;
1108
+ }
1109
+ if (requestKey.startsWith("./")) {
1110
+ return requestKey;
1111
+ }
1112
+ if (requestKey.startsWith("node_modules/") || requestKey.startsWith("build/")) {
1113
+ return `./${requestKey}`;
1114
+ }
1115
+ return requestKey;
1116
+ };
1117
+ const addReference = (lookupKey, reference) => {
1118
+ if (!lookupKey || lookupKey.trim() === "") {
1119
+ return;
1120
+ }
1121
+ if (lookupKey in consumerManifest) {
1122
+ return;
1123
+ }
1124
+ consumerManifest[lookupKey] = {
1125
+ "*": reference
1126
+ };
1127
+ };
1014
1128
  for (const [key, value] of Object.entries(manifest)) {
1015
1129
  if (!value || typeof value !== "object") {
1016
1130
  continue;
1017
1131
  }
1018
1132
  const entry = value;
1019
- if (typeof entry.id !== "string" || entry.id.trim() === "") {
1133
+ const workerModuleId = normalizeWorkerModuleId(key, entry.id);
1134
+ if (!workerModuleId) {
1020
1135
  continue;
1021
1136
  }
1022
- consumerManifest[key] = {
1023
- "*": {
1024
- id: entry.id,
1025
- chunks: [],
1026
- name: entry.name ?? "*",
1027
- ...entry.async ? { async: entry.async } : {}
1028
- }
1137
+ const reference = {
1138
+ id: workerModuleId,
1139
+ chunks: Array.isArray(entry.chunks) ? entry.chunks : [],
1140
+ name: entry.name ?? "*",
1141
+ ...entry.async ? { async: entry.async } : {}
1029
1142
  };
1143
+ addReference(key, reference);
1144
+ if (typeof entry.id === "number" && Number.isFinite(entry.id)) {
1145
+ addReference(String(entry.id), reference);
1146
+ }
1030
1147
  }
1031
1148
  return consumerManifest;
1032
1149
  }