@webtypen/webframez-react 0.0.27 → 0.0.29
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 +4 -4
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/http.cjs +91 -20
- package/dist/http.js +91 -20
- package/dist/index.cjs +91 -20
- package/dist/index.js +91 -20
- package/dist/router.cjs +22 -16
- package/dist/router.js +22 -16
- package/dist/types.d.ts +10 -1
- package/dist/webframez-core.cjs +91 -20
- package/dist/webframez-core.js +91 -20
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -132,15 +132,15 @@ Route.renderReact("/app", {
|
|
|
132
132
|
|
|
133
133
|
## `Head()` Assets
|
|
134
134
|
|
|
135
|
-
Inside a page, layout, or error `Head()` method you can set `
|
|
136
|
-
That
|
|
137
|
-
|
|
135
|
+
Inside a page, layout, or error `Head()` method you can set `basename`.
|
|
136
|
+
That basename is applied to `favicon` and `links[].href`, and also updates the
|
|
137
|
+
router basename used by `Link`, `Redirect`, and client-side navigation.
|
|
138
138
|
|
|
139
139
|
```ts
|
|
140
140
|
export function Head() {
|
|
141
141
|
return {
|
|
142
142
|
title: "Dashboard",
|
|
143
|
-
|
|
143
|
+
basename: "/app",
|
|
144
144
|
favicon: "/favicon.ico",
|
|
145
145
|
links: [{ rel: "stylesheet", href: "/styles/dashboard.css" }],
|
|
146
146
|
};
|
package/dist/client.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var N=Object.create;var m=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var W=(e,t)=>{for(var n in t)m(e,n,{get:t[n],enumerable:!0})},v=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of z(t))!M.call(e,r)&&r!==n&&m(e,r,{get:()=>t[r],enumerable:!(o=U(t,r))||o.enumerable});return e};var D=(e,t,n)=>(n=e!=null?N(B(e)):{},v(t||!e||!e.__esModule?m(n,"default",{value:e,enumerable:!0}):n,e)),F=e=>v(m({},"__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"),l=require("react-server-dom-webpack/client");var G=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function u(e){let t=e?.trim();if(t)return t==="/"?"/":t.replace(/\/+$/,"")}function x(e,t){let n=e.trim(),o=u(t);return!n||!o||G.test(n)||o!=="/"&&(n===o||n.startsWith(`${o}/`))?n:o==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${o}${n}`:`${o}/${n}`}function E(e,t){if(!e)return;let n=u(e.basename)??u(t),o={...e,...n?{basename:n}:{}};return o.favicon&&(o.favicon=x(o.favicon,n)),o.links&&(o.links=o.links.map(r=>({...r,href:x(r.href,n)}))),o}var s=require("react/jsx-runtime"),Y={push:()=>{},replace:()=>{},refresh:()=>{}},p=typeof i.default.createContext=="function"?i.default.createContext(null):null,O="__WEBFRAMEZ_ROUTER__",Z="[data-webframez-head='true']";function q(){return typeof window>"u"?null:window[O]??null}function j(e){typeof window>"u"||(window[O]=e)}function S(){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("="),d=r>=0?o.slice(0,r).trim():o,c=r>=0?o.slice(r+1):"";d&&(e[d]=decodeURIComponent(c))}return e}function b(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 X(){return i.default.useMemo(()=>({all:()=>S(),get:e=>S()[e],set:(e,t,n)=>{typeof document>"u"||(document.cookie=b(e,t,n))},remove:(e,t)=>{typeof document>"u"||(document.cookie=b(e,"",{...t??{},maxAge:0}))}}),[])}function K(){let e=p?i.default.useContext(p):null;if(!e){let t=q();if(t)return t;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 k(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 I(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 P(e){if(typeof document>"u")return;let t=E(e)??e,n=u(t.basename);window.__RSC_BASENAME=n??"",document.title=t.title||"Webframez React";for(let o of document.head.querySelectorAll(Z))o.remove();t.description&&k({name:"description",content:t.description}),t.favicon&&I({rel:"icon",href:t.favicon});for(let o of t.meta??[])k(o);for(let o of t.links??[])I(o)}function J(e){let t=new TextEncoder;return new ReadableStream({start(n){n.enqueue(t.encode(e)),n.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,l.createFromReadableStream)(J(e)))}function ee(e){return Q()??(0,l.createFromFetch)(fetch(`${e}?path=${encodeURIComponent(window.location.pathname)}&search=${encodeURIComponent(window.location.search)}`,{headers:{Accept:"text/x-component"}}))}function te(e,t){return function(){let o=i.default.use(e),[r,d]=(0,i.useState)(o.model),[c,w]=(0,i.useState)(o.head),[T,h]=(0,i.useState)(!1),[$,H]=(0,i.useState)(!1);async function f(a,_="push"){h(!0);try{let g=await(0,l.createFromFetch)(fetch(`${t}?path=${encodeURIComponent(a.pathname)}&search=${encodeURIComponent(a.search)}`,{headers:{Accept:"text/x-component"}}));P(g.head),w(g.head),d(g.model);let y=`${a.pathname}${a.search}`;_==="replace"?history.replaceState(null,"",y):_==="push"&&history.pushState(null,"",y)}catch(A){console.error("[webframez-react] Failed to render route",A),d((0,s.jsx)("p",{children:"Failed to load route."}))}finally{h(!1)}}(0,i.useEffect)(()=>{P(c)},[c]),(0,i.useEffect)(()=>{H(!0);let a=()=>{f(new URL(window.location.href),"none")};return window.addEventListener("popstate",a),()=>{window.removeEventListener("popstate",a)}},[]);let R=i.default.useMemo(()=>({push:a=>{f(new URL(a,window.location.origin),"push")},replace:a=>{f(new URL(a,window.location.origin),"replace")},refresh:()=>{f(new URL(window.location.href),"none")}}),[]);j(R);let C=(0,s.jsxs)(s.Fragment,{children:[$?(0,s.jsx)(V,{active:T}):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 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",d=ee(r),c=te(d,r);return(0,L.hydrateRoot)(n,(0,s.jsx)(c,{}))}
|
package/dist/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import c,{useEffect as x,useState as
|
|
1
|
+
import c,{useEffect as x,useState as f}from"react";import{hydrateRoot as N}from"react-dom/client";import{createFromFetch as P,createFromReadableStream as U}from"react-server-dom-webpack/client";var H=/^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;function u(t){let o=t?.trim();if(o)return o==="/"?"/":o.replace(/\/+$/,"")}function y(t,o){let n=t.trim(),e=u(o);return!n||!e||H.test(n)||e!=="/"&&(n===e||n.startsWith(`${e}/`))?n:e==="/"?n.startsWith("/")?n:`/${n}`:n.startsWith("/")?`${e}${n}`:`${e}/${n}`}function v(t,o){if(!t)return;let n=u(t.basename)??u(o),e={...t,...n?{basename:n}:{}};return e.favicon&&(e.favicon=y(e.favicon,n)),e.links&&(e.links=e.links.map(r=>({...r,href:y(r.href,n)}))),e}import{Fragment as q,jsx as d,jsxs as j}from"react/jsx-runtime";var z={push:()=>{},replace:()=>{},refresh:()=>{}},m=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={},o=typeof document>"u"?"":document.cookie;if(!o||o.trim()==="")return t;for(let n of o.split(";")){let e=n.trim();if(!e)continue;let r=e.indexOf("="),a=r>=0?e.slice(0,r).trim():e,s=r>=0?e.slice(r+1):"";a&&(t[a]=decodeURIComponent(s))}return t}function S(t,o,n={}){let e=[`${t}=${encodeURIComponent(o)}`];return n.path&&e.push(`Path=${n.path}`),n.domain&&e.push(`Domain=${n.domain}`),typeof n.maxAge=="number"&&e.push(`Max-Age=${Math.floor(n.maxAge)}`),n.expires&&e.push(`Expires=${n.expires.toUTCString()}`),n.sameSite&&e.push(`SameSite=${n.sameSite}`),n.secure&&e.push("Secure"),e.join("; ")}function ee(){return c.useMemo(()=>({all:()=>E(),get:t=>E()[t],set:(t,o,n)=>{typeof document>"u"||(document.cookie=S(t,o,n))},remove:(t,o)=>{typeof document>"u"||(document.cookie=S(t,"",{...o??{},maxAge:0}))}}),[])}function te(){let t=m?c.useContext(m):null;if(!t){let o=M();if(o)return o;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 b(t){let o=document.createElement("meta");o.setAttribute("data-webframez-head","true");let n=Object.entries(t).filter(([,e])=>!!e);for(let[e,r]of n)o.setAttribute(e,String(r));document.head.appendChild(o)}function k(t){let o=document.createElement("link");o.setAttribute("data-webframez-head","true");let n=Object.entries(t).filter(([,e])=>!!e);for(let[e,r]of n)o.setAttribute(e,String(r));document.head.appendChild(o)}function I(t){if(typeof document>"u")return;let o=v(t)??t,n=u(o.basename);window.__RSC_BASENAME=n??"",document.title=o.title||"Webframez React";for(let e of document.head.querySelectorAll(B))e.remove();o.description&&b({name:"description",content:o.description}),o.favicon&&k({rel:"icon",href:o.favicon});for(let e of o.meta??[])b(e);for(let e of o.links??[])k(e)}function F(t){let o=new TextEncoder;return new ReadableStream({start(n){n.enqueue(o.encode(t)),n.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,U(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,o){return function(){let e=c.use(t),[r,a]=f(e.model),[s,g]=f(e.head),[O,w]=f(!1),[T,$]=f(!1);async function l(i,C="push"){w(!0);try{let p=await P(fetch(`${o}?path=${encodeURIComponent(i.pathname)}&search=${encodeURIComponent(i.search)}`,{headers:{Accept:"text/x-component"}}));I(p.head),g(p.head),a(p.model);let A=`${i.pathname}${i.search}`;C==="replace"?history.replaceState(null,"",A):C==="push"&&history.pushState(null,"",A)}catch(_){console.error("[webframez-react] Failed to render route",_),a(d("p",{children:"Failed to load route."}))}finally{w(!1)}}x(()=>{I(s)},[s]),x(()=>{$(!0);let i=()=>{l(new URL(window.location.href),"none")};return window.addEventListener("popstate",i),()=>{window.removeEventListener("popstate",i)}},[]);let h=c.useMemo(()=>({push:i=>{l(new URL(i,window.location.origin),"push")},replace:i=>{l(new URL(i,window.location.origin),"replace")},refresh:()=>{l(new URL(window.location.href),"none")}}),[]);W(h);let R=j(q,{children:[T?d(D,{active:O}):null,r??d("p",{style:{padding:24},children:"Loading..."})]});return m?d(m.Provider,{value:h,children:R}):R}}function ne(t={}){let o=t.rootId??"root",n=document.getElementById(o);if(!n)throw new Error(`Missing #${o} element`);let e=typeof window<"u"&&window.__RSC_ENDPOINT,r=t.rscEndpoint??e??"/rsc",a=Y(r),s=Z(a,r);return N(n,d(s,{}))}export{ne as mountWebframezClient,ee as useCookie,te as useRouter};
|
package/dist/http.cjs
CHANGED
|
@@ -152,7 +152,7 @@ var import_node_path2 = __toESM(require("node:path"), 1);
|
|
|
152
152
|
|
|
153
153
|
// src/head.ts
|
|
154
154
|
var ABSOLUTE_ASSET_URL_PATTERN = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;
|
|
155
|
-
function
|
|
155
|
+
function normalizeHeadBasename(value) {
|
|
156
156
|
const trimmed = value?.trim();
|
|
157
157
|
if (!trimmed) {
|
|
158
158
|
return void 0;
|
|
@@ -162,45 +162,45 @@ function normalizeAssetsBaseUrl(value) {
|
|
|
162
162
|
}
|
|
163
163
|
return trimmed.replace(/\/+$/, "");
|
|
164
164
|
}
|
|
165
|
-
function resolveHeadAssetUrl(assetUrl,
|
|
165
|
+
function resolveHeadAssetUrl(assetUrl, basename) {
|
|
166
166
|
const normalizedAssetUrl = assetUrl.trim();
|
|
167
|
-
const
|
|
168
|
-
if (!normalizedAssetUrl || !
|
|
167
|
+
const normalizedBasename = normalizeHeadBasename(basename);
|
|
168
|
+
if (!normalizedAssetUrl || !normalizedBasename) {
|
|
169
169
|
return normalizedAssetUrl;
|
|
170
170
|
}
|
|
171
171
|
if (ABSOLUTE_ASSET_URL_PATTERN.test(normalizedAssetUrl)) {
|
|
172
172
|
return normalizedAssetUrl;
|
|
173
173
|
}
|
|
174
|
-
if (
|
|
174
|
+
if (normalizedBasename !== "/" && (normalizedAssetUrl === normalizedBasename || normalizedAssetUrl.startsWith(`${normalizedBasename}/`))) {
|
|
175
175
|
return normalizedAssetUrl;
|
|
176
176
|
}
|
|
177
|
-
if (
|
|
177
|
+
if (normalizedBasename === "/") {
|
|
178
178
|
return normalizedAssetUrl.startsWith("/") ? normalizedAssetUrl : `/${normalizedAssetUrl}`;
|
|
179
179
|
}
|
|
180
180
|
if (normalizedAssetUrl.startsWith("/")) {
|
|
181
|
-
return `${
|
|
181
|
+
return `${normalizedBasename}${normalizedAssetUrl}`;
|
|
182
182
|
}
|
|
183
|
-
return `${
|
|
183
|
+
return `${normalizedBasename}/${normalizedAssetUrl}`;
|
|
184
184
|
}
|
|
185
|
-
function normalizeHeadConfig(head,
|
|
185
|
+
function normalizeHeadConfig(head, inheritedBasename) {
|
|
186
186
|
if (!head) {
|
|
187
187
|
return void 0;
|
|
188
188
|
}
|
|
189
|
-
const
|
|
189
|
+
const effectiveBasename = normalizeHeadBasename(head.basename) ?? normalizeHeadBasename(inheritedBasename);
|
|
190
190
|
const normalizedHead = {
|
|
191
191
|
...head,
|
|
192
|
-
...
|
|
192
|
+
...effectiveBasename ? { basename: effectiveBasename } : {}
|
|
193
193
|
};
|
|
194
194
|
if (normalizedHead.favicon) {
|
|
195
195
|
normalizedHead.favicon = resolveHeadAssetUrl(
|
|
196
196
|
normalizedHead.favicon,
|
|
197
|
-
|
|
197
|
+
effectiveBasename
|
|
198
198
|
);
|
|
199
199
|
}
|
|
200
200
|
if (normalizedHead.links) {
|
|
201
201
|
normalizedHead.links = normalizedHead.links.map((link) => ({
|
|
202
202
|
...link,
|
|
203
|
-
href: resolveHeadAssetUrl(link.href,
|
|
203
|
+
href: resolveHeadAssetUrl(link.href, effectiveBasename)
|
|
204
204
|
}));
|
|
205
205
|
}
|
|
206
206
|
return normalizedHead;
|
|
@@ -422,7 +422,7 @@ function mergeHead(...configs) {
|
|
|
422
422
|
links: []
|
|
423
423
|
};
|
|
424
424
|
for (const candidate of configs) {
|
|
425
|
-
const config = normalizeHeadConfig(candidate, merged.
|
|
425
|
+
const config = normalizeHeadConfig(candidate, merged.basename);
|
|
426
426
|
if (!config) {
|
|
427
427
|
continue;
|
|
428
428
|
}
|
|
@@ -432,8 +432,8 @@ function mergeHead(...configs) {
|
|
|
432
432
|
if (config.description) {
|
|
433
433
|
merged.description = config.description;
|
|
434
434
|
}
|
|
435
|
-
if (config.
|
|
436
|
-
merged.
|
|
435
|
+
if (config.basename) {
|
|
436
|
+
merged.basename = config.basename;
|
|
437
437
|
}
|
|
438
438
|
if (config.favicon) {
|
|
439
439
|
merged.favicon = config.favicon;
|
|
@@ -680,6 +680,12 @@ function createFileRouter(options) {
|
|
|
680
680
|
params: {},
|
|
681
681
|
searchParams: input.searchParams,
|
|
682
682
|
cookies: input.cookies ?? {},
|
|
683
|
+
request: input.request ?? {
|
|
684
|
+
host: null,
|
|
685
|
+
pathname,
|
|
686
|
+
originalPathname: pathname,
|
|
687
|
+
headers: {}
|
|
688
|
+
},
|
|
683
689
|
abort: (options2) => {
|
|
684
690
|
throw createAbort(options2);
|
|
685
691
|
}
|
|
@@ -907,6 +913,60 @@ function normalizeBasePath(basePath) {
|
|
|
907
913
|
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
908
914
|
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
909
915
|
}
|
|
916
|
+
function normalizeRequestHostValue(value) {
|
|
917
|
+
const trimmed = value.trim();
|
|
918
|
+
if (!trimmed) {
|
|
919
|
+
return null;
|
|
920
|
+
}
|
|
921
|
+
const firstValue = trimmed.split(",")[0]?.trim() || "";
|
|
922
|
+
if (!firstValue) {
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
925
|
+
if (firstValue.startsWith("[")) {
|
|
926
|
+
const closingIndex = firstValue.indexOf("]");
|
|
927
|
+
if (closingIndex > 0) {
|
|
928
|
+
return firstValue.slice(1, closingIndex).toLowerCase();
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return firstValue.replace(/:\d+$/, "").toLowerCase();
|
|
932
|
+
}
|
|
933
|
+
function getRequestHost(req) {
|
|
934
|
+
const candidates = [
|
|
935
|
+
req.headers["x-forwarded-host"],
|
|
936
|
+
req.headers["x-original-host"],
|
|
937
|
+
req.headers.host
|
|
938
|
+
];
|
|
939
|
+
for (const candidate of candidates) {
|
|
940
|
+
if (Array.isArray(candidate)) {
|
|
941
|
+
for (const singleValue of candidate) {
|
|
942
|
+
if (typeof singleValue !== "string") {
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
const normalized2 = normalizeRequestHostValue(singleValue);
|
|
946
|
+
if (normalized2) {
|
|
947
|
+
return normalized2;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
if (typeof candidate !== "string") {
|
|
953
|
+
continue;
|
|
954
|
+
}
|
|
955
|
+
const normalized = normalizeRequestHostValue(candidate);
|
|
956
|
+
if (normalized) {
|
|
957
|
+
return normalized;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
function createRouteRequestContext(req, pathname, originalPathname) {
|
|
963
|
+
return {
|
|
964
|
+
host: getRequestHost(req),
|
|
965
|
+
pathname,
|
|
966
|
+
originalPathname,
|
|
967
|
+
headers: req.headers
|
|
968
|
+
};
|
|
969
|
+
}
|
|
910
970
|
function stripBasePath(pathname, basePath) {
|
|
911
971
|
if (!basePath) {
|
|
912
972
|
return pathname;
|
|
@@ -1252,13 +1312,19 @@ function createNodeRequestHandler(options) {
|
|
|
1252
1312
|
}
|
|
1253
1313
|
if (url.pathname === rscPath) {
|
|
1254
1314
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1315
|
+
const requestContext = createRouteRequestContext(
|
|
1316
|
+
req,
|
|
1317
|
+
pathname,
|
|
1318
|
+
url.searchParams.get("path") || "/"
|
|
1319
|
+
);
|
|
1255
1320
|
const search = new URLSearchParams(url.searchParams.get("search") || "");
|
|
1256
1321
|
const resolved2 = await withRequestBasename(
|
|
1257
1322
|
basePath,
|
|
1258
1323
|
() => router.resolve({
|
|
1259
1324
|
pathname,
|
|
1260
1325
|
searchParams: parseSearchParams(search),
|
|
1261
|
-
cookies: requestCookies
|
|
1326
|
+
cookies: requestCookies,
|
|
1327
|
+
request: requestContext
|
|
1262
1328
|
})
|
|
1263
1329
|
);
|
|
1264
1330
|
const payload = {
|
|
@@ -1298,7 +1364,12 @@ function createNodeRequestHandler(options) {
|
|
|
1298
1364
|
() => router.resolve({
|
|
1299
1365
|
pathname: stripBasePath(url.pathname, basePath),
|
|
1300
1366
|
searchParams: parseSearchParams(url.searchParams),
|
|
1301
|
-
cookies: requestCookies
|
|
1367
|
+
cookies: requestCookies,
|
|
1368
|
+
request: createRouteRequestContext(
|
|
1369
|
+
req,
|
|
1370
|
+
stripBasePath(url.pathname, basePath),
|
|
1371
|
+
url.pathname
|
|
1372
|
+
)
|
|
1302
1373
|
})
|
|
1303
1374
|
);
|
|
1304
1375
|
const initialPayload = {
|
|
@@ -1342,7 +1413,7 @@ function createNodeRequestHandler(options) {
|
|
|
1342
1413
|
rscEndpoint: rscPath,
|
|
1343
1414
|
rootHtml: createInitialHtmlErrorMarkup("Initial HTML render failed."),
|
|
1344
1415
|
initialFlightData,
|
|
1345
|
-
basename: basePath,
|
|
1416
|
+
basename: resolved?.head?.basename ?? basePath,
|
|
1346
1417
|
liveReloadPath: liveReloadPath || void 0,
|
|
1347
1418
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1348
1419
|
})
|
|
@@ -1361,7 +1432,7 @@ function createNodeRequestHandler(options) {
|
|
|
1361
1432
|
rscEndpoint: rscPath,
|
|
1362
1433
|
rootHtml,
|
|
1363
1434
|
initialFlightData,
|
|
1364
|
-
basename: basePath,
|
|
1435
|
+
basename: resolved.head.basename ?? basePath,
|
|
1365
1436
|
liveReloadPath: liveReloadPath || void 0,
|
|
1366
1437
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1367
1438
|
})
|
package/dist/http.js
CHANGED
|
@@ -127,7 +127,7 @@ import path2 from "node:path";
|
|
|
127
127
|
|
|
128
128
|
// src/head.ts
|
|
129
129
|
var ABSOLUTE_ASSET_URL_PATTERN = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;
|
|
130
|
-
function
|
|
130
|
+
function normalizeHeadBasename(value) {
|
|
131
131
|
const trimmed = value?.trim();
|
|
132
132
|
if (!trimmed) {
|
|
133
133
|
return void 0;
|
|
@@ -137,45 +137,45 @@ function normalizeAssetsBaseUrl(value) {
|
|
|
137
137
|
}
|
|
138
138
|
return trimmed.replace(/\/+$/, "");
|
|
139
139
|
}
|
|
140
|
-
function resolveHeadAssetUrl(assetUrl,
|
|
140
|
+
function resolveHeadAssetUrl(assetUrl, basename) {
|
|
141
141
|
const normalizedAssetUrl = assetUrl.trim();
|
|
142
|
-
const
|
|
143
|
-
if (!normalizedAssetUrl || !
|
|
142
|
+
const normalizedBasename = normalizeHeadBasename(basename);
|
|
143
|
+
if (!normalizedAssetUrl || !normalizedBasename) {
|
|
144
144
|
return normalizedAssetUrl;
|
|
145
145
|
}
|
|
146
146
|
if (ABSOLUTE_ASSET_URL_PATTERN.test(normalizedAssetUrl)) {
|
|
147
147
|
return normalizedAssetUrl;
|
|
148
148
|
}
|
|
149
|
-
if (
|
|
149
|
+
if (normalizedBasename !== "/" && (normalizedAssetUrl === normalizedBasename || normalizedAssetUrl.startsWith(`${normalizedBasename}/`))) {
|
|
150
150
|
return normalizedAssetUrl;
|
|
151
151
|
}
|
|
152
|
-
if (
|
|
152
|
+
if (normalizedBasename === "/") {
|
|
153
153
|
return normalizedAssetUrl.startsWith("/") ? normalizedAssetUrl : `/${normalizedAssetUrl}`;
|
|
154
154
|
}
|
|
155
155
|
if (normalizedAssetUrl.startsWith("/")) {
|
|
156
|
-
return `${
|
|
156
|
+
return `${normalizedBasename}${normalizedAssetUrl}`;
|
|
157
157
|
}
|
|
158
|
-
return `${
|
|
158
|
+
return `${normalizedBasename}/${normalizedAssetUrl}`;
|
|
159
159
|
}
|
|
160
|
-
function normalizeHeadConfig(head,
|
|
160
|
+
function normalizeHeadConfig(head, inheritedBasename) {
|
|
161
161
|
if (!head) {
|
|
162
162
|
return void 0;
|
|
163
163
|
}
|
|
164
|
-
const
|
|
164
|
+
const effectiveBasename = normalizeHeadBasename(head.basename) ?? normalizeHeadBasename(inheritedBasename);
|
|
165
165
|
const normalizedHead = {
|
|
166
166
|
...head,
|
|
167
|
-
...
|
|
167
|
+
...effectiveBasename ? { basename: effectiveBasename } : {}
|
|
168
168
|
};
|
|
169
169
|
if (normalizedHead.favicon) {
|
|
170
170
|
normalizedHead.favicon = resolveHeadAssetUrl(
|
|
171
171
|
normalizedHead.favicon,
|
|
172
|
-
|
|
172
|
+
effectiveBasename
|
|
173
173
|
);
|
|
174
174
|
}
|
|
175
175
|
if (normalizedHead.links) {
|
|
176
176
|
normalizedHead.links = normalizedHead.links.map((link) => ({
|
|
177
177
|
...link,
|
|
178
|
-
href: resolveHeadAssetUrl(link.href,
|
|
178
|
+
href: resolveHeadAssetUrl(link.href, effectiveBasename)
|
|
179
179
|
}));
|
|
180
180
|
}
|
|
181
181
|
return normalizedHead;
|
|
@@ -397,7 +397,7 @@ function mergeHead(...configs) {
|
|
|
397
397
|
links: []
|
|
398
398
|
};
|
|
399
399
|
for (const candidate of configs) {
|
|
400
|
-
const config = normalizeHeadConfig(candidate, merged.
|
|
400
|
+
const config = normalizeHeadConfig(candidate, merged.basename);
|
|
401
401
|
if (!config) {
|
|
402
402
|
continue;
|
|
403
403
|
}
|
|
@@ -407,8 +407,8 @@ function mergeHead(...configs) {
|
|
|
407
407
|
if (config.description) {
|
|
408
408
|
merged.description = config.description;
|
|
409
409
|
}
|
|
410
|
-
if (config.
|
|
411
|
-
merged.
|
|
410
|
+
if (config.basename) {
|
|
411
|
+
merged.basename = config.basename;
|
|
412
412
|
}
|
|
413
413
|
if (config.favicon) {
|
|
414
414
|
merged.favicon = config.favicon;
|
|
@@ -655,6 +655,12 @@ function createFileRouter(options) {
|
|
|
655
655
|
params: {},
|
|
656
656
|
searchParams: input.searchParams,
|
|
657
657
|
cookies: input.cookies ?? {},
|
|
658
|
+
request: input.request ?? {
|
|
659
|
+
host: null,
|
|
660
|
+
pathname,
|
|
661
|
+
originalPathname: pathname,
|
|
662
|
+
headers: {}
|
|
663
|
+
},
|
|
658
664
|
abort: (options2) => {
|
|
659
665
|
throw createAbort(options2);
|
|
660
666
|
}
|
|
@@ -882,6 +888,60 @@ function normalizeBasePath(basePath) {
|
|
|
882
888
|
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
883
889
|
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
884
890
|
}
|
|
891
|
+
function normalizeRequestHostValue(value) {
|
|
892
|
+
const trimmed = value.trim();
|
|
893
|
+
if (!trimmed) {
|
|
894
|
+
return null;
|
|
895
|
+
}
|
|
896
|
+
const firstValue = trimmed.split(",")[0]?.trim() || "";
|
|
897
|
+
if (!firstValue) {
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
if (firstValue.startsWith("[")) {
|
|
901
|
+
const closingIndex = firstValue.indexOf("]");
|
|
902
|
+
if (closingIndex > 0) {
|
|
903
|
+
return firstValue.slice(1, closingIndex).toLowerCase();
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return firstValue.replace(/:\d+$/, "").toLowerCase();
|
|
907
|
+
}
|
|
908
|
+
function getRequestHost(req) {
|
|
909
|
+
const candidates = [
|
|
910
|
+
req.headers["x-forwarded-host"],
|
|
911
|
+
req.headers["x-original-host"],
|
|
912
|
+
req.headers.host
|
|
913
|
+
];
|
|
914
|
+
for (const candidate of candidates) {
|
|
915
|
+
if (Array.isArray(candidate)) {
|
|
916
|
+
for (const singleValue of candidate) {
|
|
917
|
+
if (typeof singleValue !== "string") {
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
const normalized2 = normalizeRequestHostValue(singleValue);
|
|
921
|
+
if (normalized2) {
|
|
922
|
+
return normalized2;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
if (typeof candidate !== "string") {
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
const normalized = normalizeRequestHostValue(candidate);
|
|
931
|
+
if (normalized) {
|
|
932
|
+
return normalized;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
function createRouteRequestContext(req, pathname, originalPathname) {
|
|
938
|
+
return {
|
|
939
|
+
host: getRequestHost(req),
|
|
940
|
+
pathname,
|
|
941
|
+
originalPathname,
|
|
942
|
+
headers: req.headers
|
|
943
|
+
};
|
|
944
|
+
}
|
|
885
945
|
function stripBasePath(pathname, basePath) {
|
|
886
946
|
if (!basePath) {
|
|
887
947
|
return pathname;
|
|
@@ -1227,13 +1287,19 @@ function createNodeRequestHandler(options) {
|
|
|
1227
1287
|
}
|
|
1228
1288
|
if (url.pathname === rscPath) {
|
|
1229
1289
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1290
|
+
const requestContext = createRouteRequestContext(
|
|
1291
|
+
req,
|
|
1292
|
+
pathname,
|
|
1293
|
+
url.searchParams.get("path") || "/"
|
|
1294
|
+
);
|
|
1230
1295
|
const search = new URLSearchParams(url.searchParams.get("search") || "");
|
|
1231
1296
|
const resolved2 = await withRequestBasename(
|
|
1232
1297
|
basePath,
|
|
1233
1298
|
() => router.resolve({
|
|
1234
1299
|
pathname,
|
|
1235
1300
|
searchParams: parseSearchParams(search),
|
|
1236
|
-
cookies: requestCookies
|
|
1301
|
+
cookies: requestCookies,
|
|
1302
|
+
request: requestContext
|
|
1237
1303
|
})
|
|
1238
1304
|
);
|
|
1239
1305
|
const payload = {
|
|
@@ -1273,7 +1339,12 @@ function createNodeRequestHandler(options) {
|
|
|
1273
1339
|
() => router.resolve({
|
|
1274
1340
|
pathname: stripBasePath(url.pathname, basePath),
|
|
1275
1341
|
searchParams: parseSearchParams(url.searchParams),
|
|
1276
|
-
cookies: requestCookies
|
|
1342
|
+
cookies: requestCookies,
|
|
1343
|
+
request: createRouteRequestContext(
|
|
1344
|
+
req,
|
|
1345
|
+
stripBasePath(url.pathname, basePath),
|
|
1346
|
+
url.pathname
|
|
1347
|
+
)
|
|
1277
1348
|
})
|
|
1278
1349
|
);
|
|
1279
1350
|
const initialPayload = {
|
|
@@ -1317,7 +1388,7 @@ function createNodeRequestHandler(options) {
|
|
|
1317
1388
|
rscEndpoint: rscPath,
|
|
1318
1389
|
rootHtml: createInitialHtmlErrorMarkup("Initial HTML render failed."),
|
|
1319
1390
|
initialFlightData,
|
|
1320
|
-
basename: basePath,
|
|
1391
|
+
basename: resolved?.head?.basename ?? basePath,
|
|
1321
1392
|
liveReloadPath: liveReloadPath || void 0,
|
|
1322
1393
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1323
1394
|
})
|
|
@@ -1336,7 +1407,7 @@ function createNodeRequestHandler(options) {
|
|
|
1336
1407
|
rscEndpoint: rscPath,
|
|
1337
1408
|
rootHtml,
|
|
1338
1409
|
initialFlightData,
|
|
1339
|
-
basename: basePath,
|
|
1410
|
+
basename: resolved.head.basename ?? basePath,
|
|
1340
1411
|
liveReloadPath: liveReloadPath || void 0,
|
|
1341
1412
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1342
1413
|
})
|