what-router 0.13.4 → 0.13.5

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/index.min.js CHANGED
@@ -1,4 +1,4 @@
1
- import{signal as R,effect as $,computed as b,batch as M,h as c,ErrorBoundary as X}from"what-core";function O(e){let n=e.replace(/\([\w-]+\)\//g,"").replace(/\[\.\.\.(\w+)\]/g,(i,u)=>`*:${u}`).replace(/\[(\w+)\]/g,":$1"),t=[],r=null,o=n.split("/").map(i=>i.startsWith("*:")?(r=i.slice(2),t.push(r),"(.+)"):i==="*"?(r="rest",t.push("rest"),"(.+)"):i.startsWith(":")?(t.push(i.slice(1)),"([^/]+)"):i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("/");return{regex:new RegExp(`^${o}$`),paramNames:t,catchAll:r}}var S=new Map,z=1e3;function H(e){let n=S.get(e);return n||(n=O(e),S.size>=z&&S.clear(),S.set(e,n)),n}function K(e,n){let t;try{t=decodeURIComponent(e)}catch{return null}let r=t.split(/[/\\]/);return!n&&r.length>1||r.includes("..")?null:t}function _(e,n){let t=n.filter(r=>r.path);t.sort((r,o)=>{let s=(r.path.match(/:/g)||[]).length+(r.path.includes("*")?100:0),i=(o.path.match(/:/g)||[]).length+(o.path.includes("*")?100:0);return s-i});for(let r of t){let{regex:o,paramNames:s,catchAll:i}=H(r.path),u=e.match(o);if(u){let p={},l=!1;if(s.forEach((a,d)=>{let m=K(u[d+1],a===i);if(m===null){l=!0;return}p[a]=m}),l)continue;return{route:r,params:p}}}return null}function A(e){let n=Object.create(null);if(!e)return n;let t=e.startsWith("?")?e.slice(1):e;for(let r of t.split("&")){let[o,s]=r.split("=");if(!o)continue;let i=decodeURIComponent(o),u=s?decodeURIComponent(s):"";Object.prototype.hasOwnProperty.call(n,i)?Array.isArray(n[i])?n[i].push(u):n[i]=[n[i],u]:n[i]=u}return n}var Q=new Set(["http:","https:","mailto:","tel:"]);function C(e){if(typeof e!="string")return!1;let t=e.trim().replace(/[\s\x00-\x1f]/g,"").toLowerCase();if(t.startsWith("javascript:")||t.startsWith("data:")||t.startsWith("vbscript:")||/^[/\\]{2}/.test(t))return!1;let r=t.match(/^([a-z][a-z0-9+.-]*:)/);return r?Q.has(r[1]):!t.includes("\\")}var h=R(typeof location<"u"?location.pathname+location.search+location.hash:"/"),G=R({}),F=R({}),y=R(!1),x=R(null),B=R(null),g={get url(){return h()},get path(){return h().split("?")[0].split("#")[0]},get params(){return G()},get query(){return F()},get hash(){let e=h().split("#")[1];return e?"#"+e:""},get isNavigating(){return y()},get error(){return B()}},q=[],P=[];function D(e,n){return e.push(n),()=>{let t=e.indexOf(n);t!==-1&&e.splice(t,1)}}function ue(e){return D(q,e)}function le(e){return D(P,e)}async function v(e,n={}){let{replace:t=!1,state:r=null,transition:o=!0,_fromPopstate:s=!1,_redirectChain:i=!1}=n;if(i||(w.length=0),!C(e)){typeof console<"u"&&console.warn("[what-router] Blocked navigation to unsafe URL:",e);return}if(typeof window<"u"&&e.startsWith("#")){let d=h().split("#")[0]+e;history.replaceState(r,"",d),h.set(d);let m=document.querySelector(e);m&&m.scrollIntoView({behavior:"smooth"});return}if(e===h()||y.peek())return;y.set(!0),x.set(e);let u=h();if(q.length){let l=!1;try{for(let a of q.slice())if(await a(e,u)===!1){l=!0;break}}catch(a){throw y.set(!1),x.set(null),a}if(l){y.set(!1),x.set(null),s&&typeof history<"u"&&history.pushState(null,"",u);return}}B.set(null);let p=()=>{s||(typeof window<"u"&&k.set(h(),{x:window.scrollX,y:window.scrollY}),t?history.replaceState(r,"",e):history.pushState(r,"",e)),h.set(e),y.set(!1),x.set(null)};if(o&&typeof document<"u"&&document.startViewTransition)try{let l=document.startViewTransition(p);l.ready&&typeof l.ready.catch=="function"&&l.ready.catch(()=>{}),await l.finished}catch{}else p();if(P.length)for(let l of P.slice())l(e,u)}var V=Symbol.for("what.router.redirect"),Y=Symbol.for("what.navigation.signal");function fe(e,n={}){if(!C(e)){let r=typeof e=="string"?e:Object.prototype.toString.call(e),o=new Error(`[what-router] redirect() refused an unsafe target: ${r}`);throw o.code="ERR_UNSAFE_REDIRECT",o.suggestion='redirect() accepts same-origin paths and http:, https:, mailto: or tel: URLs only. Protocol-relative ("//host"), backslash-smuggled and javascript:/data: targets are open-redirect vectors. Check a user-supplied target against an allowlist first.',o.codeExample=`// Bad - a user-controlled target can leave your origin:
1
+ import{signal as R,effect as G,computed as b,batch as M,h as c,ErrorBoundary as X}from"what-core";function U(e){let r=e.replace(/\([\w-]+\)\//g,"").replace(/\[\.\.\.(\w+)\]/g,(a,l)=>`*:${l}`).replace(/\[(\w+)\]/g,":$1"),t=[],n=null,o=r.split("/").map(a=>a.startsWith("*:")?(n=a.slice(2),t.push(n),"(.+)"):a==="*"?(n="rest",t.push("rest"),"(.+)"):a.startsWith(":")?(t.push(a.slice(1)),"([^/]+)"):a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("/");return{regex:new RegExp(`^${o}$`),paramNames:t,catchAll:n}}var E=new Map,z=1e3;function H(e){let r=E.get(e);return r||(r=U(e),E.size>=z&&E.clear(),E.set(e,r)),r}function K(e,r){let t;try{t=decodeURIComponent(e)}catch{return null}let n=t.split(/[/\\]/);return!r&&n.length>1||n.includes("..")?null:t}function _(e,r){let t=r.filter(n=>n.path);t.sort((n,o)=>{let i=(n.path.match(/:/g)||[]).length+(n.path.includes("*")?100:0),a=(o.path.match(/:/g)||[]).length+(o.path.includes("*")?100:0);return i-a});for(let n of t){let{regex:o,paramNames:i,catchAll:a}=H(n.path),l=e.match(o);if(l){let p={},u=!1;if(i.forEach((s,d)=>{let m=K(l[d+1],s===a);if(m===null){u=!0;return}p[s]=m}),u)continue;return{route:n,params:p}}}return null}function A(e){let r=Object.create(null);if(!e)return r;for(let[t,n]of new URLSearchParams(e))Object.prototype.hasOwnProperty.call(r,t)?Array.isArray(r[t])?r[t].push(n):r[t]=[r[t],n]:r[t]=n;return r}var Q=new Set(["http:","https:","mailto:","tel:"]);function k(e){if(typeof e!="string")return!1;let t=e.trim().replace(/[\s\x00-\x1f]/g,"").toLowerCase();if(t.startsWith("javascript:")||t.startsWith("data:")||t.startsWith("vbscript:")||/^[/\\]{2}/.test(t))return!1;let n=t.match(/^([a-z][a-z0-9+.-]*:)/);return n?Q.has(n[1]):!t.includes("\\")}var h=R(typeof location<"u"?location.pathname+location.search+location.hash:"/"),I=R({}),F=R({}),y=R(!1),x=R(null),B=R(null),g={get url(){return h()},get path(){return h().split("?")[0].split("#")[0]},get params(){return I()},get query(){return F()},get hash(){let e=h().split("#")[1];return e?"#"+e:""},get isNavigating(){return y()},get error(){return B()}},T=[],q=[];function D(e,r){return e.push(r),()=>{let t=e.indexOf(r);t!==-1&&e.splice(t,1)}}function ue(e){return D(T,e)}function le(e){return D(q,e)}async function v(e,r={}){let{replace:t=!1,state:n=null,transition:o=!0,_fromPopstate:i=!1,_redirectChain:a=!1}=r;if(a||(w.length=0),!k(e)){typeof console<"u"&&console.warn("[what-router] Blocked navigation to unsafe URL:",e);return}if(typeof window<"u"&&e.startsWith("#")){let d=h().split("#")[0]+e;history.replaceState(n,"",d),h.set(d);let m=document.querySelector(e);m&&m.scrollIntoView({behavior:"smooth"});return}if(e===h()||y.peek())return;y.set(!0),x.set(e);let l=h();if(T.length){let u=!1;try{for(let s of T.slice())if(await s(e,l)===!1){u=!0;break}}catch(s){throw y.set(!1),x.set(null),s}if(u){y.set(!1),x.set(null),i&&typeof history<"u"&&history.pushState(null,"",l);return}}B.set(null);let p=()=>{i||(typeof window<"u"&&C.set(h(),{x:window.scrollX,y:window.scrollY}),t?history.replaceState(n,"",e):history.pushState(n,"",e)),h.set(e),y.set(!1),x.set(null)};if(o&&typeof document<"u"&&document.startViewTransition)try{let u=document.startViewTransition(p);u.ready&&typeof u.ready.catch=="function"&&u.ready.catch(()=>{}),await u.finished}catch{}else p();if(q.length)for(let u of q.slice())u(e,l)}var V=Symbol.for("what.router.redirect"),Y=Symbol.for("what.navigation.signal");function fe(e,r={}){if(!k(e)){let n=typeof e=="string"?e:Object.prototype.toString.call(e),o=new Error(`[what-router] redirect() refused an unsafe target: ${n}`);throw o.code="ERR_UNSAFE_REDIRECT",o.suggestion='redirect() accepts same-origin paths and http:, https:, mailto: or tel: URLs only. Protocol-relative ("//host"), backslash-smuggled and javascript:/data: targets are open-redirect vectors. Check a user-supplied target against an allowlist first.',o.codeExample=`// Bad - a user-controlled target can leave your origin:
2
2
  redirect(query.next);
3
3
 
4
4
  // Good - allowlist the target first:
@@ -12,4 +12,4 @@ redirect(ALLOWED.has(query.next) ? query.next : '/');`,o}let t=new Error(`[what-
12
12
  function Private() {
13
13
  if (!user()) redirect('/login');
14
14
  return <Secret />;
15
- }`,t[V]=!0,t[Y]=()=>{L(e,n)},t.to=e,t.options=n,t}typeof window<"u"&&window.addEventListener("popstate",()=>{k.set(h(),{x:window.scrollX,y:window.scrollY});let e=location.pathname+location.search+location.hash;v(e,{replace:!0,_fromPopstate:!0,transition:!1}).then(()=>{let n=k.get(e);n&&requestAnimationFrame(()=>window.scrollTo(n.x,n.y))})});function J(e,n){let t=[];if(!e.path)return t;let r=e.path.split("/").filter(Boolean),o="";for(let s of r){o+="/"+s;let i=n.find(u=>u.layout&&u.path===o+"/_layout");i&&t.push(i.layout)}return e.layout&&t.push(e.layout),t}var w=[],Z=10;function I(e){return c("div",{class:"what-redirect-loop"},c("h1",null,"Redirect Loop"),c("p",null,e))}function L(e,n){if(x.peek()===e)return null;if(w.push(e),w.length>Z){let o=w.slice(-5).join(" \u2192 ");return w.length=0,console.error(`[what-router] Redirect loop detected: ${o}`),y.set(!1),x.set(null),I("Too many redirects. Check your middleware configuration.")}let t=new Set,r=!1;for(let o of w){if(t.has(o)){r=!0;break}t.add(o)}if(r){let o=w.join(" \u2192 ");return w.length=0,console.error(`[what-router] Redirect cycle detected: ${o}`),y.set(!1),x.set(null),I("Circular redirect detected. Check your middleware configuration.")}return v(e,{replace:!0,...n,_redirectChain:!0}),null}function ee(e,n,t){if(!e)return null;let r=e.split("?")[0].split("#")[0],o=_(r,n);return!o||o.route===t?null:o.route.loading||null}function te({routes:e,fallback:n,globalLayout:t}){let r=()=>{let s=h(),i=s.split("?")[0].split("#")[0],u=s.split("?")[1]?.split("#")[0]||"",p=y(),l=_(i,e);if(l){M(()=>{G.set(l.params),F.set(A(u))});let{route:a,params:d}=l,m=A(u);if(a.middleware&&a.middleware.length>0)for(let N of a.middleware){let T=N({path:i,params:d,query:m,route:a});if(T===!1)return n?c(n,{}):c("div",{class:"what-403"},c("h1",null,"403"),c("p",null,"Access denied"));if(typeof T=="string")return L(T)}let f,E=p?ee(x(),e,a):null;E?f=c(E,{}):a.loading&&p?f=c(a.loading,{}):f=c(a.component,{params:d,query:m,route:a}),a.error&&(f=c(X,{fallback:a.error},f));let j=J(a,e);for(let N of j.reverse())f=c(N,{params:d,query:m},f);return f}return n?c(n,{}):c("div",{class:"what-404"},c("h1",null,"404"),c("p",null,"Page not found"))},o=()=>{let s=null;try{return r()}catch(i){if(!i||!i[V])throw i;s=i}return L(s.to,s.options)};return t?c(t,{},o):o}function ne({href:e,class:n,className:t,children:r,replace:o,prefetch:s=!0,activeClass:i="active",exactActiveClass:u="exact-active",transition:p=!0,...l}){let a=C(e)?e:"about:blank";!C(e)&&typeof console<"u"&&console.warn("[what-router] Link blocked unsafe href:",e);let d=a.split("?")[0].split("#")[0];return c("a",{href:a,class:()=>{let f=g.path,E=d==="/"?f==="/":f===d||f.startsWith(d+"/");return[n||t,E&&i,f===d&&u].filter(Boolean).join(" ")||void 0},onclick:f=>{f.ctrlKey||f.metaKey||f.shiftKey||f.altKey||f.button!==0||(f.preventDefault(),v(a,{replace:o,transition:p}))},onmouseenter:s?()=>U(a):void 0,...l},...Array.isArray(r)?r:[r])}function de(e){return ne(e)}function pe(e){return Object.entries(e).map(([n,t])=>typeof t=="function"?{path:n,component:t}:{path:n,...t})}function re(e,n){let t=e.endsWith("/")?e.slice(0,-1):e,r=!n||n==="/"?"/":n.startsWith("/")?n:`/${n}`;return r==="/"?t||"/":t+r}function he(e,n,t={}){let{layout:r,loading:o,error:s}=t;return n.map(i=>({...i,path:re(e,i.path),layout:i.layout||r,loading:i.loading||o,error:i.error||s}))}function me(e,n,t={}){let{layout:r,middleware:o}=t;return n.map(s=>({...s,_group:e,layout:s.layout||r,middleware:[...s.middleware||[],...o||[]]}))}function ge({to:e}){return v(e,{replace:!0}),null}function ye(e,n){return t=>function(o){let s=e(o);return s instanceof Promise?c("div",{class:"what-guard-loading"},"Loading..."):s?c(t,o):typeof n=="string"?(v(n,{replace:!0}),null):c(n,o)}}function we(e,n={}){let{fallback:t="/login",loading:r=null}=n;return o=>function(i){let u=R("pending"),p=R(null),l=!1;return $(()=>(l=!1,Promise.resolve(e(i)).then(a=>{l||(p.set(a),u.set(a?"allowed":"denied"))}).catch(()=>{l||u.set("denied")}),()=>{l=!0})),()=>{let a=u();return a==="pending"?r?c(r,{}):null:a==="allowed"?c(o,i):typeof t=="string"?(v(t,{replace:!0}),null):c(t,i)}}}var W=new Set;function U(e){if(typeof document>"u"||W.has(e))return;W.add(e);let n=document.createElement("link");n.rel="prefetch",n.href=e,document.head.appendChild(n)}var k=new Map;function xe(){if(typeof window>"u")return;let e=!0;$(()=>{let n=g.url,t=k.get(n),r=g.hash,o=e;e=!1,requestAnimationFrame(()=>{r?oe(r)?.scrollIntoView():t?window.scrollTo(t.x,t.y):o||window.scrollTo(0,0)})})}function oe(e){try{return document.querySelector(e)}catch{return document.getElementById(e.slice(1))}}function Re(e){return{style:{viewTransitionName:e}}}function ve(e){typeof document>"u"||(document.documentElement.dataset.transition=e)}function be(){return{path:b(()=>g.path),params:b(()=>g.params),query:b(()=>g.query),hash:b(()=>g.hash),isNavigating:b(()=>g.isNavigating),navigate:v,prefetch:U}}function Ee(){return g.params}function Se(){return g.query}function _e(){return v}function Ae(e){U(e)}function Ce({children:e}){return e||null}function ke({routes:e,layout:n,fallback:t,error:r}){let o=e.map(s=>({path:s.path,component:s.component,layout:s.layout||void 0,loading:s.loading||void 0,error:s.error||r||void 0,_mode:s.mode||"client"}));return te({routes:o,globalLayout:n,fallback:t||ie})}function ie(){return c("div",{style:"text-align:center;padding:60px 20px"},c("h1",{style:"font-size:48px;margin-bottom:8px"},"404"),c("p",{style:"color:#64748b"},"Page not found"))}export{ke as FileRouter,ne as Link,de as NavLink,Ce as Outlet,ge as Redirect,te as Router,le as afterNavigate,we as asyncGuard,ue as beforeNavigate,O as compilePath,pe as defineRoutes,xe as enableScrollRestoration,ye as guard,C as isSafeUrl,_ as matchRoute,v as navigate,he as nestedRoutes,A as parseQuery,U as prefetch,Ae as prefetchRoute,fe as redirect,g as route,me as routeGroup,ve as setViewTransition,_e as useNavigate,Ee as useParams,be as useRoute,Se as useSearch,Re as viewTransitionName};
15
+ }`,t[V]=!0,t[Y]=()=>{L(e,r)},t.to=e,t.options=r,t}typeof window<"u"&&window.addEventListener("popstate",()=>{C.set(h(),{x:window.scrollX,y:window.scrollY});let e=location.pathname+location.search+location.hash;v(e,{replace:!0,_fromPopstate:!0,transition:!1}).then(()=>{let r=C.get(e);r&&requestAnimationFrame(()=>window.scrollTo(r.x,r.y))})});function J(e,r){let t=[];if(!e.path)return t;let n=e.path.split("/").filter(Boolean),o="";for(let i of n){o+="/"+i;let a=r.find(l=>l.layout&&l.path===o+"/_layout");a&&t.push(a.layout)}return e.layout&&t.push(e.layout),t}var w=[],Z=10;function $(e){return c("div",{class:"what-redirect-loop"},c("h1",null,"Redirect Loop"),c("p",null,e))}function L(e,r){if(x.peek()===e)return null;if(w.push(e),w.length>Z){let o=w.slice(-5).join(" \u2192 ");return w.length=0,console.error(`[what-router] Redirect loop detected: ${o}`),y.set(!1),x.set(null),$("Too many redirects. Check your middleware configuration.")}let t=new Set,n=!1;for(let o of w){if(t.has(o)){n=!0;break}t.add(o)}if(n){let o=w.join(" \u2192 ");return w.length=0,console.error(`[what-router] Redirect cycle detected: ${o}`),y.set(!1),x.set(null),$("Circular redirect detected. Check your middleware configuration.")}return v(e,{replace:!0,...r,_redirectChain:!0}),null}function ee(e,r,t){if(!e)return null;let n=e.split("?")[0].split("#")[0],o=_(n,r);return!o||o.route===t?null:o.route.loading||null}function te({routes:e,fallback:r,globalLayout:t}){let n=()=>{let i=h(),a=i.split("?")[0].split("#")[0],l=i.split("?")[1]?.split("#")[0]||"",p=y(),u=_(a,e);if(u){M(()=>{I.set(u.params),F.set(A(l))});let{route:s,params:d}=u,m=A(l);if(s.middleware&&s.middleware.length>0)for(let N of s.middleware){let P=N({path:a,params:d,query:m,route:s});if(P===!1)return r?c(r,{}):c("div",{class:"what-403"},c("h1",null,"403"),c("p",null,"Access denied"));if(typeof P=="string")return L(P)}let f,S=p?ee(x(),e,s):null;S?f=c(S,{}):s.loading&&p?f=c(s.loading,{}):f=c(s.component,{params:d,query:m,route:s}),s.error&&(f=c(X,{fallback:s.error},f));let O=J(s,e);for(let N of O.reverse())f=c(N,{params:d,query:m},f);return f}return r?c(r,{}):c("div",{class:"what-404"},c("h1",null,"404"),c("p",null,"Page not found"))},o=()=>{let i=null;try{return n()}catch(a){if(!a||!a[V])throw a;i=a}return L(i.to,i.options)};return t?c(t,{},o):o}function re({href:e,class:r,className:t,children:n,replace:o,prefetch:i=!0,activeClass:a="active",exactActiveClass:l="exact-active",transition:p=!0,...u}){let s=k(e)?e:"about:blank";!k(e)&&typeof console<"u"&&console.warn("[what-router] Link blocked unsafe href:",e);let d=s.split("?")[0].split("#")[0];return c("a",{href:s,class:()=>{let f=g.path,S=d==="/"?f==="/":f===d||f.startsWith(d+"/");return[r||t,S&&a,f===d&&l].filter(Boolean).join(" ")||void 0},onclick:f=>{f.ctrlKey||f.metaKey||f.shiftKey||f.altKey||f.button!==0||(f.preventDefault(),v(s,{replace:o,transition:p}))},onmouseenter:i?()=>j(s):void 0,...u},...Array.isArray(n)?n:[n])}function de(e){return re(e)}function pe(e){return Object.entries(e).map(([r,t])=>typeof t=="function"?{path:r,component:t}:{path:r,...t})}function ne(e,r){let t=e.endsWith("/")?e.slice(0,-1):e,n=!r||r==="/"?"/":r.startsWith("/")?r:`/${r}`;return n==="/"?t||"/":t+n}function he(e,r,t={}){let{layout:n,loading:o,error:i}=t;return r.map(a=>({...a,path:ne(e,a.path),layout:a.layout||n,loading:a.loading||o,error:a.error||i}))}function me(e,r,t={}){let{layout:n,middleware:o}=t;return r.map(i=>({...i,_group:e,layout:i.layout||n,middleware:[...i.middleware||[],...o||[]]}))}function ge({to:e}){return v(e,{replace:!0}),null}function ye(e,r){return t=>function(o){let i=e(o);return i instanceof Promise?c("div",{class:"what-guard-loading"},"Loading..."):i?c(t,o):typeof r=="string"?(v(r,{replace:!0}),null):c(r,o)}}function we(e,r={}){let{fallback:t="/login",loading:n=null}=r;return o=>function(a){let l=R("pending"),p=R(null),u=!1;return G(()=>(u=!1,Promise.resolve(e(a)).then(s=>{u||(p.set(s),l.set(s?"allowed":"denied"))}).catch(()=>{u||l.set("denied")}),()=>{u=!0})),()=>{let s=l();return s==="pending"?n?c(n,{}):null:s==="allowed"?c(o,a):typeof t=="string"?(v(t,{replace:!0}),null):c(t,a)}}}var W=new Set;function j(e){if(typeof document>"u"||W.has(e))return;W.add(e);let r=document.createElement("link");r.rel="prefetch",r.href=e,document.head.appendChild(r)}var C=new Map;function xe(){if(typeof window>"u")return;let e=!0;G(()=>{let r=g.url,t=C.get(r),n=g.hash,o=e;e=!1,requestAnimationFrame(()=>{n?oe(n)?.scrollIntoView():t?window.scrollTo(t.x,t.y):o||window.scrollTo(0,0)})})}function oe(e){try{return document.querySelector(e)}catch{return document.getElementById(e.slice(1))}}function Re(e){return{style:{viewTransitionName:e}}}function ve(e){typeof document>"u"||(document.documentElement.dataset.transition=e)}function be(){return{path:b(()=>g.path),params:b(()=>g.params),query:b(()=>g.query),hash:b(()=>g.hash),isNavigating:b(()=>g.isNavigating),navigate:v,prefetch:j}}function Se(){return g.params}function Ee(){return g.query}function _e(){return v}function Ae(e){j(e)}function ke({children:e}){return e||null}function Ce({routes:e,layout:r,fallback:t,error:n}){let o=e.map(i=>({path:i.path,component:i.component,layout:i.layout||void 0,loading:i.loading||void 0,error:i.error||n||void 0,_mode:i.mode||"client"}));return te({routes:o,globalLayout:r,fallback:t||ie})}function ie(){return c("div",{style:"text-align:center;padding:60px 20px"},c("h1",{style:"font-size:48px;margin-bottom:8px"},"404"),c("p",{style:"color:#64748b"},"Page not found"))}export{Ce as FileRouter,re as Link,de as NavLink,ke as Outlet,ge as Redirect,te as Router,le as afterNavigate,we as asyncGuard,ue as beforeNavigate,U as compilePath,pe as defineRoutes,xe as enableScrollRestoration,ye as guard,k as isSafeUrl,_ as matchRoute,v as navigate,he as nestedRoutes,A as parseQuery,j as prefetch,Ae as prefetchRoute,fe as redirect,g as route,me as routeGroup,ve as setViewTransition,_e as useNavigate,Se as useParams,be as useRoute,Ee as useSearch,Re as viewTransitionName};
package/dist/match.min.js CHANGED
@@ -1 +1 @@
1
- function h(n){let t=n.replace(/\([\w-]+\)\//g,"").replace(/\[\.\.\.(\w+)\]/g,(e,s)=>`*:${s}`).replace(/\[(\w+)\]/g,":$1"),c=[],r=null,o=t.split("/").map(e=>e.startsWith("*:")?(r=e.slice(2),c.push(r),"(.+)"):e==="*"?(r="rest",c.push("rest"),"(.+)"):e.startsWith(":")?(c.push(e.slice(1)),"([^/]+)"):e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("/");return{regex:new RegExp(`^${o}$`),paramNames:c,catchAll:r}}var a=new Map,m=1e3;function g(n){let t=a.get(n);return t||(t=h(n),a.size>=m&&a.clear(),a.set(n,t)),t}function x(n,t){let c;try{c=decodeURIComponent(n)}catch{return null}let r=c.split(/[/\\]/);return!t&&r.length>1||r.includes("..")?null:c}function y(n,t){let c=t.filter(r=>r.path);c.sort((r,o)=>{let l=(r.path.match(/:/g)||[]).length+(r.path.includes("*")?100:0),e=(o.path.match(/:/g)||[]).length+(o.path.includes("*")?100:0);return l-e});for(let r of c){let{regex:o,paramNames:l,catchAll:e}=g(r.path),s=n.match(o);if(s){let i={},u=!1;if(l.forEach((p,d)=>{let f=x(s[d+1],p===e);if(f===null){u=!0;return}i[p]=f}),u)continue;return{route:r,params:i}}}return null}function A(n){let t=Object.create(null);if(!n)return t;let c=n.startsWith("?")?n.slice(1):n;for(let r of c.split("&")){let[o,l]=r.split("=");if(!o)continue;let e=decodeURIComponent(o),s=l?decodeURIComponent(l):"";Object.prototype.hasOwnProperty.call(t,e)?Array.isArray(t[e])?t[e].push(s):t[e]=[t[e],s]:t[e]=s}return t}export{h as compilePath,y as matchRoute,A as parseQuery};
1
+ function d(c){let e=c.replace(/\([\w-]+\)\//g,"").replace(/\[\.\.\.(\w+)\]/g,(n,l)=>`*:${l}`).replace(/\[(\w+)\]/g,":$1"),r=[],t=null,o=e.split("/").map(n=>n.startsWith("*:")?(t=n.slice(2),r.push(t),"(.+)"):n==="*"?(t="rest",r.push("rest"),"(.+)"):n.startsWith(":")?(r.push(n.slice(1)),"([^/]+)"):n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("/");return{regex:new RegExp(`^${o}$`),paramNames:r,catchAll:t}}var s=new Map,m=1e3;function g(c){let e=s.get(c);return e||(e=d(c),s.size>=m&&s.clear(),s.set(c,e)),e}function x(c,e){let r;try{r=decodeURIComponent(c)}catch{return null}let t=r.split(/[/\\]/);return!e&&t.length>1||t.includes("..")?null:r}function w(c,e){let r=e.filter(t=>t.path);r.sort((t,o)=>{let a=(t.path.match(/:/g)||[]).length+(t.path.includes("*")?100:0),n=(o.path.match(/:/g)||[]).length+(o.path.includes("*")?100:0);return a-n});for(let t of r){let{regex:o,paramNames:a,catchAll:n}=g(t.path),l=c.match(o);if(l){let u={},i=!1;if(a.forEach((p,h)=>{let f=x(l[h+1],p===n);if(f===null){i=!0;return}u[p]=f}),i)continue;return{route:t,params:u}}}return null}function y(c){let e=Object.create(null);if(!c)return e;for(let[r,t]of new URLSearchParams(c))Object.prototype.hasOwnProperty.call(e,r)?Array.isArray(e[r])?e[r].push(t):e[r]=[e[r],t]:e[r]=t;return e}export{d as compilePath,w as matchRoute,y as parseQuery};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "what-router",
3
- "version": "0.13.4",
3
+ "version": "0.13.5",
4
4
  "description": "What Framework - File-based & programmatic router with View Transitions",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -35,7 +35,7 @@
35
35
  "license": "MIT",
36
36
  "dependencies": {},
37
37
  "peerDependencies": {
38
- "what-core": "^0.13.4"
38
+ "what-core": "^0.13.5"
39
39
  },
40
40
  "repository": {
41
41
  "type": "git",
package/src/index.js CHANGED
@@ -489,6 +489,7 @@ export function Router({ routes, fallback, globalLayout }) {
489
489
  // component runs after renderMatch has returned. Anything unbranded
490
490
  // propagates to the app's ErrorBoundary unchanged.
491
491
  const content = () => {
492
+ /** @type {any} */
492
493
  let sig = null;
493
494
  try {
494
495
  return renderMatch();
package/src/match.js CHANGED
@@ -15,6 +15,7 @@ export function compilePath(path) {
15
15
  .replace(/\[(\w+)\]/g, ':$1'); // File-based [param] to :param
16
16
 
17
17
  const paramNames = [];
18
+ /** @type {string | null} */
18
19
  let catchAll = null;
19
20
 
20
21
  const regexStr = normalized
@@ -112,12 +113,9 @@ export function matchRoute(path, routes) {
112
113
  export function parseQuery(search) {
113
114
  const params = Object.create(null);
114
115
  if (!search) return params;
115
- const qs = search.startsWith('?') ? search.slice(1) : search;
116
- for (const pair of qs.split('&')) {
117
- const [key, val] = pair.split('=');
118
- if (!key) continue;
119
- const decodedKey = decodeURIComponent(key);
120
- const decodedVal = val ? decodeURIComponent(val) : '';
116
+ // Match the platform's form-query decoding: '+' is a space, values may
117
+ // contain '=', and malformed escapes remain data rather than aborting SSR.
118
+ for (const [decodedKey, decodedVal] of new URLSearchParams(search)) {
121
119
  if (Object.prototype.hasOwnProperty.call(params, decodedKey)) {
122
120
  // Collect repeated keys into arrays
123
121
  if (Array.isArray(params[decodedKey])) {