@vielzeug/wayfinder 3.0.0 → 26.10.0
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/_dev.cjs +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +1 -6
- package/dist/_dev.js.map +1 -1
- package/dist/_navigation.cjs +1 -1
- package/dist/_navigation.cjs.map +1 -1
- package/dist/_navigation.js +1 -20
- package/dist/_navigation.js.map +1 -1
- package/dist/compile.cjs +1 -1
- package/dist/compile.cjs.map +1 -1
- package/dist/compile.js +1 -46
- package/dist/compile.js.map +1 -1
- package/dist/context.cjs +1 -1
- package/dist/context.cjs.map +1 -1
- package/dist/context.js +1 -59
- package/dist/context.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +4 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -17
- package/dist/errors.js.map +1 -1
- package/dist/guards.cjs +1 -1
- package/dist/guards.cjs.map +1 -1
- package/dist/guards.js +1 -9
- package/dist/guards.js.map +1 -1
- package/dist/history.cjs +1 -1
- package/dist/history.cjs.map +1 -1
- package/dist/history.d.ts +11 -0
- package/dist/history.d.ts.map +1 -1
- package/dist/history.js +1 -67
- package/dist/history.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -5
- package/dist/middleware.cjs +1 -1
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.js +1 -9
- package/dist/middleware.js.map +1 -1
- package/dist/path.cjs +1 -1
- package/dist/path.cjs.map +1 -1
- package/dist/path.js +1 -132
- package/dist/path.js.map +1 -1
- package/dist/phase-mirror.cjs +2 -0
- package/dist/phase-mirror.cjs.map +1 -0
- package/dist/phase-mirror.d.ts +51 -0
- package/dist/phase-mirror.d.ts.map +1 -0
- package/dist/phase-mirror.js +2 -0
- package/dist/phase-mirror.js.map +1 -0
- package/dist/route-signals.cjs +2 -0
- package/dist/route-signals.cjs.map +1 -0
- package/dist/route-signals.d.ts +23 -0
- package/dist/route-signals.d.ts.map +1 -0
- package/dist/route-signals.js +2 -0
- package/dist/route-signals.js.map +1 -0
- package/dist/router.cjs +1 -1
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.ts +7 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +1 -475
- package/dist/router.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/wayfinder.cjs +1 -1
- package/dist/wayfinder.cjs.map +1 -1
- package/dist/wayfinder.iife.js +1 -1
- package/dist/wayfinder.iife.js.map +1 -1
- package/dist/wayfinder.js +1 -1
- package/dist/wayfinder.js.map +1 -1
- package/package.json +8 -5
package/dist/router.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./history.cjs"),n=require("./_navigation.cjs"),r=require("./path.cjs"),i=require("./compile.cjs"),a=require("./context.cjs"),o=require("./guards.cjs");function s(t,n){let r=n.get(t);if(r)return r;let i=[...n.keys()].join(`, `);throw new e.WayfinderRouteError(i?`Unknown route name: ${t}. Available routes: ${i}`:`Unknown route name: ${t}`)}function c(e,t,n=`/`){if(`path`in e)return e.path;let i=s(e.name,t),a=r.buildUrl(n,i.path,e.params,e.query);return e.hash?`${a}#${e.hash}`:a}var l=Symbol(`wayfinder.routerError`);function u(e,t){return{[l]:!0,context:t,error:e}}function d(e){return typeof e==`object`&&!!e&&l in e}function f(e){throw d(e)?e.error:e}var p=class{#e;#t;#n;#r;#i;#a;#o;#s;#c;#l=new Set;#u=n.createNavigationCoordinator();#d;#f=!1;#p=new AbortController;#m=`/`;#h=new Set;#g=new Map;#_=new Map;#v;#y;ready;constructor(e){let n=i.compileRoutes(e);if(this.#e=r.normalizePath(e.base??`/`),this.#t=e.middleware??[],this.#n=e.coerceSearch,this.#r=e.history??t.createBrowserHistory(),this.#o=e.onError,this.#s=e.scroll,this.#c=e.viewTransition??!1,this.#i=n.records,this.#a=n.routesByName,this.#d=a.createRouteState({location:{hash:``,historyState:null,pathname:`/`,query:{}},matches:[],status:`idle`}),e.notFound){let t=e.notFound,n={dataFn:t.data,name:`__notFound__`};this.#v={branchDefs:[n],leaf:n,matcher:{paramNames:[],pattern:/(?:)/,prefixPattern:/(?:)/},ownMiddleware:t.middleware??[],path:`/*`}}else this.#v=null;this.#y=this.#x();let{hash:o,pathname:s,search:c}=this.#r.location;this.#m=`${s}${c}${o}`;let l=this.#u.begin(),u=this.#A(l,r.readLocation(this.#e,this.#r),(e,t)=>{if(!l.isCurrent())return;let n=this.#F(e);t&&this.#r.replace(n,e.historyState),this.#m=n},void 0,0,!1).then(()=>void 0);this.ready=u.catch(f),this.ready.catch(()=>{}),this.#w(u,{source:`initial-navigation`}),this.beforeLeave=this.beforeLeave.bind(this),this.createViewRegistry=this.createViewRegistry.bind(this),this.dispose=this.dispose.bind(this),this.getSnapshot=this.getSnapshot.bind(this),this.isActive=this.isActive.bind(this),this.load=this.load.bind(this),this.match=this.match.bind(this),this.navigate=this.navigate.bind(this),this.preload=this.preload.bind(this),this.subscribe=this.subscribe.bind(this),this.url=this.url.bind(this),this.waitFor=this.waitFor.bind(this)}getSnapshot(){return this.#d}createViewRegistry(e,t){return{resolve:n=>{let r=n.matches.at(-1)?.name;return r===`__notFound__`?t?.notFound:r?e[r]:void 0}}}subscribe(e){return this.#b(),this.#h.add(e),()=>{this.#h.delete(e)}}navigate(e,t){let n=c(typeof e==`string`?{path:e}:e,this.#a);return this.#L(n,t)}url(e,t,n){let i=s(e,this.#a);return r.buildUrl(this.#e,i.path,t,n)}isActive(e,t={}){let n=s(e,this.#a),i=this.#d.location.pathname;return t.exact??!1?r.matchRouteFor(i,[n]).record!=null:r.matchesPrefix(i,n)}match(e){let t=r.stripBase(r.normalizePath(e),this.#e),{params:n,record:i}=r.matchRouteFor(t,this.#i);if(!i||i.redirect)return null;let o=a.buildMatchBranch(i.branchDefs,n,t,i.branchDefs.map(()=>void 0));return o.length?o:null}async load(e,t){let n=await this.#D(e);if(n.type!==`matched`)return null;let{location:r,params:i,record:o,resolvedQuery:s}=n,c=o.branchDefs,l=c.some(e=>e.dataFn!=null),u=c.map(()=>void 0),d,f=`idle`;if(l){let e=t?.signal??new AbortController().signal,n=a.buildMatchBranch(c,i,r.pathname,u),o=a.createRouteContext(r,s,i,n,()=>Promise.resolve());try{u=await this.#E(c,o,e)}catch(e){d=e,f=`error`}}return a.createRouteState({error:d,location:r,matches:a.buildMatchBranch(c,i,r.pathname,u),status:f})}async preload(e){this.#b();let t=this.#N(c(e,this.#a,this.#e)),n=this.#_.get(t);if(n)return n;let r=this.load(t,{signal:this.#p.signal}).then(e=>{if(this.#f)throw this.#p.signal.reason;if(e?.status===`error`)throw e.error;if(e){let t=this.#F(e.location);this.#g.size>=20&&this.#g.delete(this.#g.keys().next().value),this.#g.set(t,e.matches.map(e=>e.data))}return e}).catch(e=>{throw this.#o&&this.#C(e,{source:`preload`}),e}).finally(()=>{this.#_.delete(t)});return this.#_.set(t,r),r}waitFor(e){return this.#b(),new Promise((t,n)=>{let r=t=>t.status===`idle`&&t.matches.some(t=>t.name===e);if(this.#d.status===`error`){n(this.#d.error);return}if(r(this.#d)){t(this.#d);return}let i=this.subscribe(e=>{r(e)?(i(),t(e)):e.status===`error`&&(i(),n(e.error))});this.#p.signal.addEventListener(`abort`,()=>{i(),n(this.#p.signal.reason)},{once:!0})})}beforeLeave(e,t){this.#b();let n={handler:e,routes:t?.routes};return this.#l.add(n),()=>{this.#l.delete(n)}}get disposalSignal(){return this.#p.signal}get disposed(){return this.#f}dispose(){this.#f||(this.#f=!0,this.#l.clear(),this.#h.clear(),this.#g.clear(),this.#_.clear(),this.#u.invalidate(new e.WayfinderDisposedError),this.#y(),this.#p.abort(new e.WayfinderDisposedError))}[Symbol.dispose](){this.dispose()}#b(){if(this.#f)throw new e.WayfinderDisposedError}#x(){return this.#r.onPopstate(()=>{let{hash:e,pathname:t,search:n}=this.#r.location,r=`${t}${n}${e}`,i=this.#m;r!==i&&this.#w(this.#S(r,i),{source:`history-listener`})})}async#S(e,t){let n=this.#u.begin(),i=this.#d.matches.map(e=>e.name),a=this.#I(e),s=await o.runLeaveBlockers(this.#l,i,a);if(!n.isCurrent())return;if(!s){this.#r.replace(t,this.#d.location.historyState);return}let c=await this.#A(n,r.readLocation(this.#e,this.#r),(e,t)=>{if(!n.isCurrent())return;let r=this.#F(e);t&&this.#r.replace(r,e.historyState),this.#m=r},void 0,0,!1);n.isCurrent()&&!c&&this.#r.replace(t,this.#d.location.historyState)}#C(e,t){a.reportError(e,t,this.#o)}#w(e,t){e.catch(e=>{d(e)?this.#C(e.error,e.context):this.#C(e,t)})}#T(){this.#h.forEach(e=>{e(this.#d)})}async#E(e,t,n){return Promise.all(e.map(async e=>{if(!e.dataFn)return;let r=e.dataFn;try{return await r({...t,signal:n})}catch(r){if(e.onError)return e.onError(r,{...t,signal:n});throw r}}))}async#D(t){let n=t;for(let e=0;e<5;e+=1){let e=new URL(n,`http://localhost`),t={hash:e.hash.replace(/^#/,``),historyState:null,pathname:r.stripBase(e.pathname,this.#e),query:r.parseQuery(e.search)},i=await this.#O(t);if(i.type!==`redirect`)return i;n=this.#N(i.redirectTo)}throw new e.WayfinderRedirectLoopError}async#O(e){let{params:t,record:n}=r.matchRouteFor(e.pathname,this.#i);if(!n)return{location:e,params:t,type:`unmatched`};if(n.redirect)return{location:e,params:t,redirectTo:c(n.redirect,this.#a,this.#e),type:`redirect`};let i=e.query,o=n.coerceSearch??this.#n;if(o)try{i=o(e.query)}catch(t){this.#C(t,{source:`coerce-search`}),i=e.query}return{branch:a.buildMatchBranch(n.branchDefs,t,e.pathname,n.branchDefs.map(()=>void 0)),location:e,params:t,record:n,resolvedQuery:i,type:`matched`}}async#k(e,t,n,r,i,o,s){if(!o())return;let c=e.branchDefs,l=c.some(e=>e.dataFn!=null),u=c.map(()=>void 0);if(l){let e=this.#F(n),l=this.#_.get(e);if(l&&(await l.catch(()=>void 0),!o()))return;let d=this.#g.get(e);if(d)this.#g.delete(e),u=d;else{this.#d=a.createRouteState({location:n,matches:a.buildMatchBranch(c,r,n.pathname,u),status:`loading`}),this.#T();try{u=await this.#E(c,t,i)}catch(e){if(!o())return;throw this.#d=a.createRouteState({error:e,location:n,matches:a.buildMatchBranch(c,r,n.pathname,u),status:`error`}),s?.(e),e}}}o()&&(this.#d=a.createRouteState({location:n,matches:a.buildMatchBranch(c,r,n.pathname,u),status:`idle`}))}async#A(t,n,r,i,o=0,s=!1){let c=this.#d,l=()=>t.isCurrent()&&!this.#f,f=await this.#O(n);if(!l())return!1;if(f.type===`redirect`){if(o>=5)throw new e.WayfinderRedirectLoopError;return this.#A(t,this.#P(f.redirectTo,n.historyState),r,i,o+1,!0)}if(f.type===`unmatched`){if(this.#v){let e=[this.#v.leaf],o=a.buildMatchBranch(e,{},n.pathname,[void 0]),f=!1,p,m=!1,h=!1,g=n.query;if(this.#n)try{g=this.#n(n.query)}catch(e){this.#C(e,{source:`coerce-search`})}let _=async()=>{if(!l())return;let e=a.createRouteContext(n,g,{},o,(e,t)=>this.navigate(e,t));h=await a.executeMiddlewarePipeline(e,[...this.#t,...this.#v.ownMiddleware],async()=>{l()&&(f=!0,r(n,s),l()&&await this.#k(this.#v,e,n,{},t.signal,l,e=>{p=e,m=!0}))},e=>d(e)||m&&e===p?e:u(e,{routeName:`__notFound__`,source:`middleware`}))};try{await this.#j(_,i)}catch(e){throw m&&e===p?u(e,{routeName:`__notFound__`,source:`data-loader`}):e}finally{l()&&f&&(this.#T(),this.#M(this.#d,c))}return h&&f}return!l()||(r(f.location,s),!l())?!1:(this.#d=a.createRouteState({location:f.location,matches:[],status:`idle`}),this.#T(),this.#M(this.#d,c),!0)}let{branch:p,location:m,params:h,record:g,resolvedQuery:_}=f,v=!1,y,b=!1,x=!1,S=async()=>{if(!l())return;let e=a.createRouteContext(m,_,h,p,(e,t)=>this.navigate(e,t));x=await a.executeMiddlewarePipeline(e,[...this.#t,...g.ownMiddleware],async()=>{l()&&(v=!0,r(m,s),l()&&await this.#k(g,e,m,h,t.signal,l,e=>{y=e,b=!0}))},e=>d(e)||b&&e===y?e:u(e,{routeName:g.leaf.name,source:`middleware`}))};try{await this.#j(S,i)}catch(e){throw b&&e===y?u(e,{routeName:g.leaf.name,source:`data-loader`}):e}finally{l()&&v&&(this.#T(),this.#M(this.#d,c))}return x&&v}async#j(e,t){if((t??this.#c)&&typeof document<`u`){let t=document.startViewTransition;if(t){await t.call(document,e).finished;return}}await e()}#M(e,t){if(!this.#s||typeof window>`u`)return;let n=this.#s(e,t);if(n!==`preserve`){if(n===`top`){window.scrollTo(0,0);return}window.scrollTo(n.x,n.y)}}#N(e){let t=new URL(e,`http://localhost`),n=r.stripBase(t.pathname,this.#e);return`${r.joinPaths(this.#e,n)}${t.search}${t.hash}`}#P(e,t){let n=new URL(this.#N(e),`http://localhost`);return{hash:n.hash.replace(/^#/,``),historyState:t,pathname:r.stripBase(n.pathname,this.#e),query:r.parseQuery(n.search)}}#F(e){let t=new URLSearchParams;for(let[n,r]of Object.entries(e.query))Array.isArray(r)?r.forEach(e=>{t.append(n,e)}):t.set(n,r);let n=t.toString(),i=e.hash?`#${e.hash}`:``;return`${r.joinPaths(this.#e,e.pathname)}${n?`?${n}`:``}${i}`}#I(e){let t=new URL(e,`http://localhost`),n=r.stripBase(t.pathname,this.#e),{params:i,record:a}=r.matchRouteFor(n,this.#i);return{name:a?.leaf.name,params:i,pathname:n,query:r.parseQuery(t.search)}}async#L(e,t={}){this.#b();let n=this.#N(e);if(!t.force&&n===this.#m)return;let r=this.#u.begin(),i=this.#d.matches.map(e=>e.name),a=await o.runLeaveBlockers(this.#l,i,this.#I(n));if(r.isCurrent()&&a)try{await this.#A(r,this.#P(n,t.state),(e,t)=>{if(!r.isCurrent())return;let n=this.#F(e);t?this.#r.replace(n,e.historyState):this.#r.push(n,e.historyState),this.#m=n},t.viewTransition,0,t.replace??!1)}catch(e){throw d(e)?e.error:e}}};function m(e){return new p(e)}exports.createRouter=m;
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./path.cjs"),n=require("./history.cjs"),r=require("./_navigation.cjs"),i=require("./compile.cjs"),a=require("./context.cjs"),o=require("./guards.cjs");function getRouteByName(t,n){let r=n.get(t);if(r)return r;let i=[...n.keys()].join(`, `);throw new e.WayfinderRouteError(i?`Unknown route name: ${t}. Available routes: ${i}`:`Unknown route name: ${t}`)}function resolveTarget(e,n,r=`/`){if(`path`in e)return e.path;let i=getRouteByName(e.name,n),a=t.buildUrl(r,i.path,e.params,e.query);return e.hash?`${a}#${e.hash}`:a}var s=Symbol(`wayfinder.routerError`);function carryError(e,t){return{[s]:!0,context:t,error:e}}function isRouterErrorCarrier(e){return typeof e==`object`&&!!e&&s in e}function unwrapCarrier(e){throw isRouterErrorCarrier(e)?e.error:e}var Router=class{#e;#t;#n;#r;#i;#a;#o;#s;#c;#l=new Set;#u=r.createNavigationCoordinator();#d;#f=!1;#p=new AbortController;#m=`/`;#h=new Set;#g=new Map;#_=new Map;#v;#y;ready;constructor(e){let r=i.compileRoutes(e);if(this.#e=t.normalizePath(e.base??`/`),this.#t=e.middleware??[],this.#n=e.coerceSearch,this.#r=e.history??n.createBrowserHistory(),this.#o=e.onError,this.#s=e.scroll,this.#c=e.viewTransition??!1,this.#i=r.records,this.#a=r.routesByName,this.#d=a.createRouteState({location:{hash:``,historyState:null,pathname:`/`,query:{}},matches:[],status:`idle`}),e.notFound){let t=e.notFound,n={dataFn:t.data,name:`__notFound__`};this.#v={branchDefs:[n],leaf:n,matcher:{paramNames:[],pattern:/(?:)/,prefixPattern:/(?:)/},ownMiddleware:t.middleware??[],path:`/*`}}else this.#v=null;this.#y=this.#x();let{hash:o,pathname:s,search:c}=this.#r.location;this.#m=`${s}${c}${o}`;let l=this.#u.begin(),u=this.#A(l,t.readLocation(this.#e,this.#r),(e,t)=>{if(!l.isCurrent())return;let n=this.#F(e);t&&this.#r.replace(n,e.historyState),this.#m=n},void 0,0,!1).then(()=>void 0);this.ready=u.catch(unwrapCarrier),this.ready.catch(()=>{}),this.#w(u,{source:`initial-navigation`}),this.beforeLeave=this.beforeLeave.bind(this),this.createViewRegistry=this.createViewRegistry.bind(this),this.dispose=this.dispose.bind(this),this.getSnapshot=this.getSnapshot.bind(this),this.isActive=this.isActive.bind(this),this.load=this.load.bind(this),this.match=this.match.bind(this),this.navigate=this.navigate.bind(this),this.preload=this.preload.bind(this),this.subscribe=this.subscribe.bind(this),this.url=this.url.bind(this),this.waitFor=this.waitFor.bind(this)}getSnapshot(){return this.#d}createViewRegistry(e,t){return{resolve:n=>{let r=n.matches.at(-1)?.name;return r===`__notFound__`?t?.notFound:r?e[r]:void 0}}}subscribe(e){return this.#b(),this.#h.add(e),()=>{this.#h.delete(e)}}navigate(e,t){let n=resolveTarget(typeof e==`string`?{path:e}:e,this.#a);return this.#L(n,t)}url(e,n,r){let i=getRouteByName(e,this.#a);return t.buildUrl(this.#e,i.path,n,r)}href(e,n,r){let i=getRouteByName(e,this.#a),a=t.buildUrl(this.#e,i.path,n,r);return this.#r.href?.(a)??a}isActive(e,n={}){let r=getRouteByName(e,this.#a),i=this.#d.location.pathname;return n.exact??!1?t.matchRouteFor(i,[r]).record!=null:t.matchesPrefix(i,r)}match(e){let n=t.stripBase(t.normalizePath(e),this.#e),{params:r,record:i}=t.matchRouteFor(n,this.#i);if(!i||i.redirect)return null;let o=a.buildMatchBranch(i.branchDefs,r,n,i.branchDefs.map(()=>void 0));return o.length?o:null}async load(e,t){let n=await this.#D(e);if(n.type!==`matched`)return null;let{location:r,params:i,record:o,resolvedQuery:s}=n,c=o.branchDefs,l=c.some(e=>e.dataFn!=null),u=c.map(()=>void 0),d,f=`idle`;if(l){let e=t?.signal??new AbortController().signal,n=a.buildMatchBranch(c,i,r.pathname,u),o=a.createRouteContext(r,s,i,n,()=>Promise.resolve());try{u=await this.#E(c,o,e)}catch(e){d=e,f=`error`}}return a.createRouteState({error:d,location:r,matches:a.buildMatchBranch(c,i,r.pathname,u),status:f})}async preload(e){this.#b();let t=this.#N(resolveTarget(e,this.#a,this.#e)),n=this.#_.get(t);if(n)return n;let r=this.load(t,{signal:this.#p.signal}).then(e=>{if(this.#f)throw this.#p.signal.reason;if(e?.status===`error`)throw e.error;if(e){let t=this.#F(e.location);this.#g.size>=20&&this.#g.delete(this.#g.keys().next().value),this.#g.set(t,e.matches.map(e=>e.data))}return e}).catch(e=>{throw this.#o&&this.#C(e,{source:`preload`}),e}).finally(()=>{this.#_.delete(t)});return this.#_.set(t,r),r}waitFor(e){return this.#b(),new Promise((t,n)=>{let matchesName=t=>t.status===`idle`&&t.matches.some(t=>t.name===e);if(this.#d.status===`error`){n(this.#d.error);return}if(matchesName(this.#d)){t(this.#d);return}let r=this.subscribe(e=>{matchesName(e)?(r(),t(e)):e.status===`error`&&(r(),n(e.error))});this.#p.signal.addEventListener(`abort`,()=>{r(),n(this.#p.signal.reason)},{once:!0})})}beforeLeave(e,t){this.#b();let n={handler:e,routes:t?.routes};return this.#l.add(n),()=>{this.#l.delete(n)}}get disposalSignal(){return this.#p.signal}get disposed(){return this.#f}dispose(){this.#f||(this.#f=!0,this.#l.clear(),this.#h.clear(),this.#g.clear(),this.#_.clear(),this.#u.invalidate(new e.WayfinderDisposedError),this.#y(),this.#p.abort(new e.WayfinderDisposedError))}[Symbol.dispose](){this.dispose()}#b(){if(this.#f)throw new e.WayfinderDisposedError}#x(){return this.#r.onPopstate(()=>{let{hash:e,pathname:t,search:n}=this.#r.location,r=`${t}${n}${e}`,i=this.#m;r!==i&&this.#w(this.#S(r,i),{source:`history-listener`})})}async#S(e,n){let r=this.#u.begin(),i=this.#d.matches.map(e=>e.name),a=this.#I(e),s=await o.runLeaveBlockers(this.#l,i,a);if(!r.isCurrent())return;if(!s){this.#r.replace(n,this.#d.location.historyState);return}let c=await this.#A(r,t.readLocation(this.#e,this.#r),(e,t)=>{if(!r.isCurrent())return;let n=this.#F(e);t&&this.#r.replace(n,e.historyState),this.#m=n},void 0,0,!1);r.isCurrent()&&!c&&this.#r.replace(n,this.#d.location.historyState)}#C(e,t){a.reportError(e,t,this.#o)}#w(e,t){e.catch(e=>{isRouterErrorCarrier(e)?this.#C(e.error,e.context):this.#C(e,t)})}#T(){for(let e of[...this.#h])try{e(this.#d)}catch(e){queueMicrotask(()=>{throw e})}}async#E(e,t,n){return Promise.all(e.map(async e=>{if(!e.dataFn)return;let r=e.dataFn;try{return await r({...t,signal:n})}catch(r){if(e.onError)return e.onError(r,{...t,signal:n});throw r}}))}async#D(n){let r=n;for(let e=0;e<5;e+=1){let e=new URL(r,`http://localhost`),n={hash:e.hash.replace(/^#/,``),historyState:null,pathname:t.stripBase(e.pathname,this.#e),query:t.parseQuery(e.search)},i=await this.#O(n);if(i.type!==`redirect`)return i;r=this.#N(i.redirectTo)}throw new e.WayfinderRedirectLoopError}async#O(e){let{params:n,record:r}=t.matchRouteFor(e.pathname,this.#i);if(!r)return{location:e,params:n,type:`unmatched`};if(r.redirect)return{location:e,params:n,redirectTo:resolveTarget(r.redirect,this.#a,this.#e),type:`redirect`};let i=e.query,o=r.coerceSearch??this.#n;if(o)try{i=o(e.query)}catch(t){this.#C(t,{source:`coerce-search`}),i=e.query}return{branch:a.buildMatchBranch(r.branchDefs,n,e.pathname,r.branchDefs.map(()=>void 0)),location:e,params:n,record:r,resolvedQuery:i,type:`matched`}}async#k(e,t,n,r,i,o,s){if(!o())return;let c=e.branchDefs,l=c.some(e=>e.dataFn!=null),u=c.map(()=>void 0);if(l){let e=this.#F(n),l=this.#_.get(e);if(l&&(await l.catch(()=>void 0),!o()))return;let d=this.#g.get(e);if(d)this.#g.delete(e),u=d;else{this.#d=a.createRouteState({location:n,matches:a.buildMatchBranch(c,r,n.pathname,u),status:`loading`}),this.#T();try{u=await this.#E(c,t,i)}catch(e){if(!o())return;throw this.#d=a.createRouteState({error:e,location:n,matches:a.buildMatchBranch(c,r,n.pathname,u),status:`error`}),s?.(e),e}}}o()&&(this.#d=a.createRouteState({location:n,matches:a.buildMatchBranch(c,r,n.pathname,u),status:`idle`}))}async#A(t,n,r,i,o=0,s=!1){let c=this.#d,isCurrent=()=>t.isCurrent()&&!this.#f,l=await this.#O(n);if(!isCurrent())return!1;if(l.type===`redirect`){if(o>=5)throw new e.WayfinderRedirectLoopError;return this.#A(t,this.#P(l.redirectTo,n.historyState),r,i,o+1,!0)}if(l.type===`unmatched`){if(this.#v){let e=[this.#v.leaf],o=a.buildMatchBranch(e,{},n.pathname,[void 0]),l=!1,u,d=!1,f=!1,p=n.query,m=!1;if(this.#n)try{p=this.#n(n.query)}catch(e){this.#C(e,{source:`coerce-search`})}let run=async()=>{if(!isCurrent())return;let e=a.createRouteContext(n,p,{},o,(e,t)=>this.navigate(e,t));f=await a.executeMiddlewarePipeline(e,[...this.#t,...this.#v.ownMiddleware],async()=>{isCurrent()&&(l=!0,r(n,s),isCurrent()&&(await this.#k(this.#v,e,n,{},t.signal,isCurrent,e=>{u=e,d=!0}),isCurrent()&&(m=!0,this.#T(),this.#M(this.#d,c))))},e=>isRouterErrorCarrier(e)||d&&e===u?e:carryError(e,{routeName:`__notFound__`,source:`middleware`}))};try{await this.#j(run,i)}catch(e){throw d&&e===u?carryError(e,{routeName:`__notFound__`,source:`data-loader`}):e}finally{isCurrent()&&l&&!m&&(this.#T(),this.#M(this.#d,c))}return f&&l}return!isCurrent()||(r(l.location,s),!isCurrent())?!1:(this.#d=a.createRouteState({location:l.location,matches:[],status:`idle`}),this.#T(),this.#M(this.#d,c),!0)}let{branch:u,location:d,params:f,record:p,resolvedQuery:m}=l,h=!1,g,_=!1,v=!1,y=!1,run=async()=>{if(!isCurrent())return;let e=a.createRouteContext(d,m,f,u,(e,t)=>this.navigate(e,t));v=await a.executeMiddlewarePipeline(e,[...this.#t,...p.ownMiddleware],async()=>{isCurrent()&&(h=!0,r(d,s),isCurrent()&&(await this.#k(p,e,d,f,t.signal,isCurrent,e=>{g=e,_=!0}),isCurrent()&&(y=!0,this.#T(),this.#M(this.#d,c))))},e=>isRouterErrorCarrier(e)||_&&e===g?e:carryError(e,{routeName:p.leaf.name,source:`middleware`}))};try{await this.#j(run,i)}catch(e){throw _&&e===g?carryError(e,{routeName:p.leaf.name,source:`data-loader`}):e}finally{isCurrent()&&h&&!y&&(this.#T(),this.#M(this.#d,c))}return v&&h}async#j(e,t){if((t??this.#c)&&typeof document<`u`){let t=document.startViewTransition;if(t){await t.call(document,e).finished;return}}await e()}#M(e,t){if(!this.#s||typeof window>`u`)return;let n=this.#s(e,t);if(n!==`preserve`){if(n===`top`){window.scrollTo(0,0);return}window.scrollTo(n.x,n.y)}}#N(e){let n=new URL(e,`http://localhost`),r=t.stripBase(n.pathname,this.#e);return`${t.joinPaths(this.#e,r)}${n.search}${n.hash}`}#P(e,n){let r=new URL(this.#N(e),`http://localhost`);return{hash:r.hash.replace(/^#/,``),historyState:n,pathname:t.stripBase(r.pathname,this.#e),query:t.parseQuery(r.search)}}#F(e){let n=new URLSearchParams;for(let[t,r]of Object.entries(e.query))Array.isArray(r)?r.forEach(e=>{n.append(t,e)}):n.set(t,r);let r=n.toString(),i=e.hash?`#${e.hash}`:``;return`${t.joinPaths(this.#e,e.pathname)}${r?`?${r}`:``}${i}`}#I(e){let n=new URL(e,`http://localhost`),r=t.stripBase(n.pathname,this.#e),{params:i,record:a}=t.matchRouteFor(r,this.#i);return{name:a?.leaf.name,params:i,pathname:r,query:t.parseQuery(n.search)}}async#L(e,t={}){this.#b();let n=this.#N(e);if(!t.force&&n===this.#m)return;let r=this.#u.begin(),i=this.#d.matches.map(e=>e.name),a=await o.runLeaveBlockers(this.#l,i,this.#I(n));if(r.isCurrent()&&a)try{await this.#A(r,this.#P(n,t.state),(e,t)=>{if(!r.isCurrent())return;let n=this.#F(e);t?this.#r.replace(n,e.historyState):this.#r.push(n,e.historyState),this.#m=n},t.viewTransition,0,t.replace??!1)}catch(e){throw isRouterErrorCarrier(e)?e.error:e}}};function createRouter(e){return new Router(e)}exports.createRouter=createRouter;
|
|
2
2
|
//# sourceMappingURL=router.cjs.map
|
package/dist/router.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs","names":[],"sources":["../src/router.ts"],"sourcesContent":["import { createNavigationCoordinator, type NavigationAttempt } from './_navigation';\nimport { compileRoutes } from './compile';\nimport {\n buildMatchBranch,\n createRouteContext,\n createRouteState,\n executeMiddlewarePipeline,\n reportError,\n} from './context';\nimport { WayfinderDisposedError, WayfinderRedirectLoopError, WayfinderRouteError } from './errors';\nimport { type RegisteredBlocker, runLeaveBlockers } from './guards';\nimport { createBrowserHistory } from './history';\nimport {\n buildUrl,\n joinPaths,\n matchesPrefix,\n matchRouteFor,\n normalizePath,\n parseQuery,\n readLocation,\n stripBase,\n} from './path';\nimport type {\n BeforeLeaveBlocker,\n BeforeLeaveOptions,\n CoerceSearchFn,\n DataContext,\n DataFn,\n HistoryDriver,\n IsActiveOptions,\n Middleware,\n NamedNavigationTarget,\n NavigateOptions,\n NavigationDestination,\n PathParams,\n RawNavigationTarget,\n ResolvedQueryParams,\n RouteBranchDef,\n RouteContext,\n RouteLocation,\n RouteMatchBranch,\n RouteName,\n RouteParams,\n RoutePathByName,\n RouteRecord,\n RouterErrorContext,\n RouterOptions,\n RouteState,\n RouteTable,\n RouteViewMap,\n RouteViewName,\n RouteViewRegistry,\n Unsubscribe,\n} from './types';\n\n// ─── Module-level helpers ────────────────────────────────────────────────────\n\nfunction getRouteByName(name: string, routesByName: ReadonlyMap<string, RouteRecord>): RouteRecord {\n const route = routesByName.get(name);\n\n if (route) return route;\n\n const available = [...routesByName.keys()].join(', ');\n\n throw new WayfinderRouteError(\n available ? `Unknown route name: ${name}. Available routes: ${available}` : `Unknown route name: ${name}`,\n );\n}\n\nfunction resolveTarget(\n target: { path: string } | { hash?: string; name: string; params?: RouteParams; query?: ResolvedQueryParams },\n routesByName: ReadonlyMap<string, RouteRecord>,\n base = '/',\n): string {\n if ('path' in target) return target.path;\n\n const route = getRouteByName(target.name, routesByName);\n const path = buildUrl(base, route.path, target.params, target.query);\n\n return target.hash ? `${path}#${target.hash}` : path;\n}\n\n// ─── Internal error carrier ──────────────────────────────────────────────────\n//\n// Carries error context alongside the original error without mutating the thrown\n// object. The carrier is unwrapped before reaching external callers so error\n// identity and `cause` chains are preserved.\n\nconst ROUTER_ERROR = Symbol('wayfinder.routerError');\n\ntype RouterErrorCarrier = {\n [ROUTER_ERROR]: true;\n readonly error: unknown;\n readonly context: RouterErrorContext;\n};\n\nfunction carryError(error: unknown, context: RouterErrorContext): RouterErrorCarrier {\n return { [ROUTER_ERROR]: true, context, error };\n}\n\nfunction isRouterErrorCarrier(value: unknown): value is RouterErrorCarrier {\n return value !== null && typeof value === 'object' && ROUTER_ERROR in (value as Record<symbol, unknown>);\n}\n\nfunction unwrapCarrier(value: unknown): never {\n if (isRouterErrorCarrier(value)) throw value.error;\n\n throw value;\n}\n\n// ─── Internal types ───────────────────────────────────────────────────────────\n\ntype NavigationDecision =\n | {\n branch: RouteMatchBranch;\n location: RouteLocation;\n params: RouteParams;\n record: RouteRecord;\n resolvedQuery: ResolvedQueryParams;\n type: 'matched';\n }\n | { location: RouteLocation; params: RouteParams; type: 'unmatched' }\n | { location: RouteLocation; params: RouteParams; redirectTo: string; type: 'redirect' };\n\n// ─── Router class ─────────────────────────────────────────────────────────────\n\nclass Router<TRoutes extends RouteTable> {\n readonly #base: string;\n readonly #globalMiddleware: readonly Middleware[];\n readonly #globalCoerceSearch?: CoerceSearchFn;\n readonly #history: HistoryDriver;\n readonly #records: readonly RouteRecord[];\n readonly #routesByName: ReadonlyMap<string, RouteRecord>;\n readonly #onError?: RouterOptions<TRoutes>['onError'];\n readonly #scroll?: RouterOptions<TRoutes>['scroll'];\n readonly #useViewTransition: boolean;\n\n // Mutable navigation state\n readonly #beforeLeaveBlockers = new Set<RegisteredBlocker>();\n readonly #navigation = createNavigationCoordinator();\n #currentState: RouteState;\n #disposed = false;\n readonly #disposeController = new AbortController();\n #lastHref = '/';\n readonly #listeners = new Set<(state: RouteState) => void>();\n readonly #preloaded = new Map<string, unknown[]>();\n readonly #preloads = new Map<string, Promise<RouteState | null>>();\n // Compiled notFound fallback record\n readonly #notFoundRecord: RouteRecord | null;\n\n readonly #unlistenHistory: () => void;\n\n /** Resolves when the constructor-triggered navigation has settled; rejects if it fails. */\n readonly ready: Promise<void>;\n\n constructor(options: RouterOptions<TRoutes>) {\n const compiled = compileRoutes(options);\n\n this.#base = normalizePath(options.base ?? '/');\n this.#globalMiddleware = (options.middleware ?? []) as unknown as Middleware[];\n this.#globalCoerceSearch = options.coerceSearch;\n this.#history = options.history ?? createBrowserHistory();\n this.#onError = options.onError;\n this.#scroll = options.scroll;\n this.#useViewTransition = options.viewTransition ?? false;\n this.#records = compiled.records as unknown as readonly RouteRecord[];\n this.#routesByName = compiled.routesByName as unknown as ReadonlyMap<string, RouteRecord>;\n this.#currentState = createRouteState({\n location: { hash: '', historyState: null, pathname: '/', query: {} },\n matches: [] as RouteMatchBranch,\n status: 'idle',\n });\n\n // Build a synthetic RouteRecord for the notFound fallback.\n if (options.notFound) {\n const nf = options.notFound;\n const leafDef: RouteBranchDef = {\n dataFn: nf.data,\n name: '__notFound__',\n };\n\n this.#notFoundRecord = {\n branchDefs: [leafDef],\n leaf: leafDef,\n matcher: { paramNames: [], pattern: /(?:)/, prefixPattern: /(?:)/ },\n ownMiddleware: (nf.middleware ?? []) as unknown as Middleware[],\n path: '/*',\n };\n } else {\n this.#notFoundRecord = null;\n }\n\n this.#unlistenHistory = this.#registerHistoryListener();\n\n const { hash, pathname, search } = this.#history.location;\n\n this.#lastHref = `${pathname}${search}${hash}`;\n\n const attempt = this.#navigation.begin();\n\n const navigationPromise = this.#handleRoute(\n attempt,\n readLocation(this.#base, this.#history),\n (location, replace) => {\n if (!attempt.isCurrent()) return;\n\n const href = this.#hrefForLocation(location);\n\n if (replace) this.#history.replace(href, location.historyState);\n\n this.#lastHref = href;\n },\n undefined,\n 0,\n false,\n ).then(() => undefined);\n\n // ready rejects with the original error (carrier unwrapped) for external consumers.\n this.ready = navigationPromise.catch(unwrapCarrier);\n // Attach a silent handler so an unawaited ready promise doesn't trigger\n // an unhandled-rejection warning. External consumers can still await ready\n // and receive the rejection — each .catch() subscriber fires independently.\n this.ready.catch(() => {});\n // #runInBackground receives the raw promise so it can extract carrier context for onError.\n this.#runInBackground(navigationPromise, { source: 'initial-navigation' });\n\n // Router actions are intentionally bound once so they remain safe when destructured.\n this.beforeLeave = this.beforeLeave.bind(this);\n this.createViewRegistry = this.createViewRegistry.bind(this);\n this.dispose = this.dispose.bind(this);\n this.getSnapshot = this.getSnapshot.bind(this);\n this.isActive = this.isActive.bind(this);\n this.load = this.load.bind(this);\n this.match = this.match.bind(this);\n this.navigate = this.navigate.bind(this);\n this.preload = this.preload.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.url = this.url.bind(this);\n this.waitFor = this.waitFor.bind(this);\n }\n\n // ─── Public state ─────────────────────────────────────────────────────────\n\n /**\n * Returns the current immutable router state snapshot.\n *\n * Compatible with React's `useSyncExternalStore`:\n * ```ts\n * const state = useSyncExternalStore(\n * (cb) => router.subscribe(cb),\n * () => router.getSnapshot()\n * );\n * ```\n */\n getSnapshot(): RouteState {\n return this.#currentState;\n }\n\n createViewRegistry<const TViews extends RouteViewMap<TRoutes>, TNotFound = never>(\n views: TViews & Record<Exclude<keyof TViews, RouteViewName<TRoutes>>, never>,\n options?: { notFound?: TNotFound },\n ): RouteViewRegistry<TViews[keyof TViews] | TNotFound> {\n return {\n resolve: (state) => {\n const name = state.matches.at(-1)?.name;\n\n if (name === '__notFound__') return options?.notFound;\n\n return name ? (views[name as keyof TViews] as TViews[keyof TViews]) : undefined;\n },\n };\n }\n\n // ─── Subscription ─────────────────────────────────────────────────────────\n\n /**\n * Subscribe to state changes. The listener is called on each subsequent state change;\n * use `getSnapshot()` to read the current value immediately.\n */\n subscribe(listener: (state: RouteState) => void): Unsubscribe {\n this.#assertNotDisposed();\n this.#listeners.add(listener);\n\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n // ─── Navigation ───────────────────────────────────────────────────────────\n\n /**\n * Navigate using a named route target or a raw path target.\n *\n * If a data loader throws after terminal execution begins, history has already committed\n * the destination and the returned Promise rejects with the loader error.\n */\n navigate(\n target: NamedNavigationTarget<TRoutes> | RawNavigationTarget | string,\n options?: NavigateOptions,\n ): Promise<void> {\n const normalized = typeof target === 'string' ? { path: target } : target;\n const destination = resolveTarget(normalized, this.#routesByName);\n\n return this.#navigateToPath(destination, options);\n }\n\n // ─── URL helpers ──────────────────────────────────────────────────────────\n\n /** Build a URL for a named route, including optional params and query string. */\n url<Name extends RouteName<TRoutes>>(\n name: Name,\n params?: PathParams<RoutePathByName<TRoutes, Name>>,\n query?: ResolvedQueryParams,\n ): string {\n const route = getRouteByName(name, this.#routesByName);\n\n return buildUrl(this.#base, route.path, params, query);\n }\n\n /** Returns true when the current location matches the named route by prefix (default) or exactly. */\n isActive<Name extends RouteName<TRoutes>>(name: Name, options: IsActiveOptions = {}): boolean {\n const route = getRouteByName(name, this.#routesByName);\n const pathname = this.#currentState.location.pathname;\n const exact = options.exact ?? false;\n\n return exact ? matchRouteFor(pathname, [route]).record != null : matchesPrefix(pathname, route);\n }\n\n /** Match a pathname to a route branch without running middleware or data loaders. Returns null for redirects or no match. */\n match(pathname: string): RouteMatchBranch | null {\n const normalizedPathname = stripBase(normalizePath(pathname), this.#base);\n const { params, record } = matchRouteFor(normalizedPathname, this.#records);\n\n if (!record || record.redirect) return null;\n\n const branch = buildMatchBranch(\n record.branchDefs,\n params,\n normalizedPathname,\n record.branchDefs.map(() => undefined),\n );\n\n return branch.length ? branch : null;\n }\n\n /**\n * Load a URL into a route state including data loader results, without modifying\n * router state or history. Follows declarative redirects but does not cache results.\n * Middleware is not executed — use `navigate()` when middleware side effects are needed.\n */\n async load(url: string, options?: { signal?: AbortSignal }): Promise<RouteState | null> {\n const prepared = await this.#resolveUrl(url);\n\n if (prepared.type !== 'matched') return null;\n\n const { location, params, record, resolvedQuery } = prepared;\n const defs = record.branchDefs;\n const hasData = defs.some((d) => d.dataFn != null);\n let dataResults: unknown[] = defs.map(() => undefined);\n let error: unknown;\n let status: 'error' | 'idle' = 'idle';\n\n if (hasData) {\n const effectiveSignal = options?.signal ?? new AbortController().signal;\n const branch = buildMatchBranch(defs, params, location.pathname, dataResults);\n const context = createRouteContext<TRoutes>(location, resolvedQuery, params, branch, () => Promise.resolve());\n\n try {\n dataResults = await this.#loadData(defs, context, effectiveSignal);\n } catch (e) {\n error = e;\n status = 'error';\n }\n }\n\n return createRouteState({\n error,\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status,\n });\n }\n\n async preload(target: NamedNavigationTarget<TRoutes>): Promise<RouteState | null> {\n this.#assertNotDisposed();\n\n const destination = this.#resolveDestination(resolveTarget(target, this.#routesByName, this.#base));\n const existing = this.#preloads.get(destination);\n\n if (existing) return existing;\n\n const work = this.load(destination, { signal: this.#disposeController.signal })\n .then((state) => {\n if (this.#disposed) throw this.#disposeController.signal.reason;\n\n if (state?.status === 'error') throw state.error;\n\n if (state) {\n const key = this.#hrefForLocation(state.location);\n\n if (this.#preloaded.size >= 20) this.#preloaded.delete(this.#preloaded.keys().next().value!);\n\n this.#preloaded.set(\n key,\n state.matches.map((match) => match.data),\n );\n }\n\n return state;\n })\n .catch((error) => {\n if (this.#onError) this.#reportError(error, { source: 'preload' });\n\n throw error;\n })\n .finally(() => {\n this.#preloads.delete(destination);\n });\n\n this.#preloads.set(destination, work);\n\n return work;\n }\n\n /**\n * Returns a Promise that resolves the next time the router reaches `status: 'idle'`\n * and the active matches include a route named `name`.\n *\n * - Resolves immediately if the router is already `idle` at `name`.\n * - Rejects immediately if the router is already in `status: 'error'`.\n * - If the router is currently `idle` at a **different** route and no navigation is in\n * flight, this promise will not resolve until a future navigation lands on `name`.\n * Typical use-case is awaiting a navigation you just triggered:\n * `router.navigate(target); await router.waitFor('routeName')`.\n * @throws {WayfinderDisposedError} if the router is disposed while the promise is pending,\n * or if called after the router has already been disposed.\n */\n waitFor(name: RouteName<TRoutes>): Promise<RouteState> {\n this.#assertNotDisposed();\n\n return new Promise((resolve, reject) => {\n const matchesName = (state: RouteState): boolean =>\n state.status === 'idle' && state.matches.some((m) => m.name === name);\n\n if (this.#currentState.status === 'error') {\n reject(this.#currentState.error);\n\n return;\n }\n\n if (matchesName(this.#currentState)) {\n resolve(this.#currentState);\n\n return;\n }\n\n const unsub = this.subscribe((state) => {\n if (matchesName(state)) {\n unsub();\n resolve(state);\n } else if (state.status === 'error') {\n unsub();\n reject(state.error);\n }\n });\n\n this.#disposeController.signal.addEventListener(\n 'abort',\n () => {\n unsub();\n reject(this.#disposeController.signal.reason);\n },\n { once: true },\n );\n });\n }\n\n // ─── Navigation guards ────────────────────────────────────────────────────\n\n /**\n * Register a leave guard. Called before user-triggered navigation attempts.\n * Return `false` to cancel; `true` to allow.\n * Returns a function that removes the guard.\n *\n * Use `options.routes` to scope the guard to specific routes (fires only when navigating\n * away from a route whose name appears in the array, checked against any node in the active branch).\n */\n beforeLeave(blocker: BeforeLeaveBlocker, options?: BeforeLeaveOptions<TRoutes>): Unsubscribe {\n this.#assertNotDisposed();\n\n const entry: RegisteredBlocker = {\n handler: blocker,\n routes: options?.routes as string[] | undefined,\n };\n\n this.#beforeLeaveBlockers.add(entry);\n\n return () => {\n this.#beforeLeaveBlockers.delete(entry);\n };\n }\n\n // ─── Lifecycle ────────────────────────────────────────────────────────────\n\n get disposalSignal(): AbortSignal {\n return this.#disposeController.signal;\n }\n\n get disposed(): boolean {\n return this.#disposed;\n }\n\n /** Dispose event listeners and prevent further router interaction. Idempotent. */\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n this.#beforeLeaveBlockers.clear();\n this.#listeners.clear();\n this.#preloaded.clear();\n this.#preloads.clear();\n this.#navigation.invalidate(new WayfinderDisposedError());\n this.#unlistenHistory();\n // Abort the disposal signal last — waitFor() listeners clean themselves up via this signal.\n this.#disposeController.abort(new WayfinderDisposedError());\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n // ─── Private: assertions ──────────────────────────────────────────────────\n\n #assertNotDisposed(): void {\n if (this.#disposed) throw new WayfinderDisposedError();\n }\n\n // ─── Private: history listener ────────────────────────────────────────────\n\n #registerHistoryListener(): () => void {\n return this.#history.onPopstate(() => {\n const { hash, pathname, search } = this.#history.location;\n const newHref = `${pathname}${search}${hash}`;\n const previousHref = this.#lastHref;\n\n if (newHref === previousHref) return;\n\n this.#runInBackground(this.#handleHistoryNavigation(newHref, previousHref), { source: 'history-listener' });\n });\n }\n\n async #handleHistoryNavigation(newHref: string, previousHref: string): Promise<void> {\n const attempt = this.#navigation.begin();\n const activeMatchNames = this.#currentState.matches.map((m) => m.name);\n const destination = this.#navigationDestination(newHref);\n const allowed = await runLeaveBlockers(this.#beforeLeaveBlockers, activeMatchNames, destination);\n\n if (!attempt.isCurrent()) return;\n\n if (!allowed) {\n this.#history.replace(previousHref, this.#currentState.location.historyState);\n\n return;\n }\n\n const terminalRan = await this.#handleRoute(\n attempt,\n readLocation(this.#base, this.#history),\n (location, replace) => {\n if (!attempt.isCurrent()) return;\n\n const href = this.#hrefForLocation(location);\n\n if (replace) this.#history.replace(href, location.historyState);\n\n this.#lastHref = href;\n },\n undefined,\n 0,\n false,\n );\n\n if (attempt.isCurrent() && !terminalRan) {\n this.#history.replace(previousHref, this.#currentState.location.historyState);\n }\n }\n\n // ─── Private: error handling ──────────────────────────────────────────────\n\n #reportError(error: unknown, context: RouterErrorContext): void {\n reportError(error, context, this.#onError);\n }\n\n #runInBackground(promise: Promise<void>, context: RouterErrorContext): void {\n void promise.catch((value) => {\n if (isRouterErrorCarrier(value)) {\n this.#reportError(value.error, value.context);\n } else {\n this.#reportError(value, context);\n }\n });\n }\n\n // ─── Private: listener notification ──────────────────────────────────────\n\n #notifyListeners(): void {\n this.#listeners.forEach((listener) => {\n listener(this.#currentState);\n });\n }\n\n // ─── Private: data loaders ────────────────────────────────────────────────\n\n /**\n * Run all data loaders and return their results. Per-def `onError` boundaries are applied.\n */\n async #loadData(\n defs: readonly RouteBranchDef[],\n context: RouteContext<RouteParams, TRoutes>,\n signal: AbortSignal,\n ): Promise<unknown[]> {\n return Promise.all(\n defs.map(async (def) => {\n if (!def.dataFn) return undefined;\n\n const dataFn = def.dataFn as unknown as DataFn<RouteParams, TRoutes>;\n\n try {\n return await dataFn({ ...context, signal } as DataContext<RouteParams, TRoutes>);\n } catch (err) {\n if (def.onError) return def.onError(err, { ...context, signal } as unknown as DataContext);\n\n throw err;\n }\n }),\n );\n }\n\n // ─── Private: URL resolution ──────────────────────────────────────────────\n\n /** Parse a URL, call #prepareRoute, and follow declarative redirects up to 5 hops. */\n async #resolveUrl(url: string): Promise<NavigationDecision> {\n let destination = url;\n\n for (let i = 0; i < 5; i += 1) {\n const parsed = new URL(destination, 'http://localhost');\n const location: RouteLocation = {\n hash: parsed.hash.replace(/^#/, ''),\n historyState: null,\n pathname: stripBase(parsed.pathname, this.#base),\n query: parseQuery(parsed.search),\n };\n\n const prepared = await this.#prepareRoute(location);\n\n if (prepared.type !== 'redirect') return prepared;\n\n destination = this.#resolveDestination(prepared.redirectTo);\n }\n\n throw new WayfinderRedirectLoopError();\n }\n\n // ─── Private: route preparation ───────────────────────────────────────────\n\n async #prepareRoute(location: RouteLocation): Promise<NavigationDecision> {\n const { params, record } = matchRouteFor(location.pathname, this.#records);\n\n if (!record) {\n return { location, params, type: 'unmatched' };\n }\n\n if (record.redirect) {\n return {\n location,\n params,\n redirectTo: resolveTarget(record.redirect, this.#routesByName, this.#base),\n type: 'redirect',\n };\n }\n\n let resolvedQuery: ResolvedQueryParams = location.query;\n\n const coerce: CoerceSearchFn | undefined = record.coerceSearch ?? this.#globalCoerceSearch;\n\n if (coerce) {\n try {\n resolvedQuery = coerce(location.query);\n } catch (err) {\n this.#reportError(err, { source: 'coerce-search' });\n resolvedQuery = location.query;\n }\n }\n\n return {\n branch: buildMatchBranch(\n record.branchDefs,\n params,\n location.pathname,\n record.branchDefs.map(() => undefined),\n ),\n location,\n params,\n record,\n resolvedQuery,\n type: 'matched',\n };\n }\n\n // ─── Private: terminal (data only) ────────────────────────────────────────\n\n async #runTerminal(\n record: RouteRecord,\n context: RouteContext<RouteParams, TRoutes>,\n location: RouteLocation,\n params: RouteParams,\n signal: AbortSignal,\n isCurrent: () => boolean,\n onDataError?: (error: unknown) => void,\n ): Promise<void> {\n if (!isCurrent()) return;\n\n const defs = record.branchDefs;\n const hasData = defs.some((d) => d.dataFn != null);\n let dataResults: unknown[] = defs.map(() => undefined);\n\n if (hasData) {\n const preloadKey = this.#hrefForLocation(location);\n const preloading = this.#preloads.get(preloadKey);\n\n if (preloading) {\n await preloading.catch(() => undefined);\n\n if (!isCurrent()) return;\n }\n\n const cached = this.#preloaded.get(preloadKey);\n\n if (cached) {\n this.#preloaded.delete(preloadKey);\n dataResults = cached;\n } else {\n this.#currentState = createRouteState({\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status: 'loading',\n });\n this.#notifyListeners();\n\n try {\n dataResults = await this.#loadData(defs, context, signal);\n } catch (error) {\n if (!isCurrent()) return;\n\n this.#currentState = createRouteState({\n error,\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status: 'error',\n });\n onDataError?.(error);\n throw error;\n }\n }\n }\n\n if (!isCurrent()) return;\n\n this.#currentState = createRouteState({\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status: 'idle',\n });\n }\n\n // ─── Private: main navigation orchestrator ────────────────────────────────\n\n /**\n * Declarative redirects reuse the active attempt and replace the final history entry.\n * Middleware redirects call `ctx.navigate()`, which starts a new attempt.\n */\n async #handleRoute(\n attempt: NavigationAttempt,\n currentLocation: RouteLocation,\n commit: (location: RouteLocation, replace: boolean) => void,\n useTransition?: boolean,\n depth = 0,\n replace = false,\n ): Promise<boolean> {\n const previousState = this.#currentState;\n const isCurrent = (): boolean => attempt.isCurrent() && !this.#disposed;\n const prepared = await this.#prepareRoute(currentLocation);\n\n if (!isCurrent()) return false;\n\n if (prepared.type === 'redirect') {\n if (depth >= 5) throw new WayfinderRedirectLoopError();\n\n return this.#handleRoute(\n attempt,\n this.#locationFromPath(prepared.redirectTo, currentLocation.historyState),\n commit,\n useTransition,\n depth + 1,\n true,\n );\n }\n\n if (prepared.type === 'unmatched') {\n // Fall back to notFound record when defined.\n if (this.#notFoundRecord) {\n const nfDefs = [this.#notFoundRecord.leaf];\n const nfBranch = buildMatchBranch(nfDefs, {}, currentLocation.pathname, [undefined]);\n let committed = false;\n let dataError: unknown;\n let hasDataError = false;\n let terminalRan = false;\n\n // Apply global coerceSearch to the unmatched location so notFound handlers\n // receive typed query params, consistent with matched-route behaviour.\n let nfResolvedQuery: ResolvedQueryParams = currentLocation.query;\n\n if (this.#globalCoerceSearch) {\n try {\n nfResolvedQuery = this.#globalCoerceSearch(currentLocation.query);\n } catch (err) {\n this.#reportError(err, { source: 'coerce-search' });\n }\n }\n\n const run = async (): Promise<void> => {\n if (!isCurrent()) return;\n\n const context = createRouteContext<TRoutes>(\n currentLocation,\n nfResolvedQuery,\n {},\n nfBranch,\n (target, options) => this.navigate(target, options),\n );\n\n terminalRan = await executeMiddlewarePipeline(\n context,\n [...this.#globalMiddleware, ...this.#notFoundRecord!.ownMiddleware] as unknown as Middleware<TRoutes>[],\n async () => {\n if (!isCurrent()) return;\n\n committed = true;\n commit(currentLocation, replace);\n\n if (!isCurrent()) return;\n\n await this.#runTerminal(\n this.#notFoundRecord!,\n context,\n currentLocation,\n {},\n attempt.signal,\n isCurrent,\n (error) => {\n dataError = error;\n hasDataError = true;\n },\n );\n },\n (error) =>\n isRouterErrorCarrier(error) || (hasDataError && error === dataError)\n ? error\n : carryError(error, { routeName: '__notFound__', source: 'middleware' }),\n );\n };\n\n try {\n await this.#runWithTransition(run, useTransition);\n } catch (error) {\n if (hasDataError && error === dataError) {\n throw carryError(error, { routeName: '__notFound__', source: 'data-loader' });\n }\n\n throw error;\n } finally {\n if (isCurrent() && committed) {\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n }\n }\n\n return terminalRan && committed;\n }\n\n if (!isCurrent()) return false;\n\n commit(prepared.location, replace);\n\n if (!isCurrent()) return false;\n\n this.#currentState = createRouteState({\n location: prepared.location,\n matches: [] as RouteMatchBranch,\n status: 'idle',\n });\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n\n return true;\n }\n\n const { branch, location, params, record, resolvedQuery } = prepared;\n let committed = false;\n let dataError: unknown;\n let hasDataError = false;\n let terminalRan = false;\n\n const run = async (): Promise<void> => {\n if (!isCurrent()) return;\n\n const context = createRouteContext<TRoutes>(location, resolvedQuery, params, branch, (target, options) =>\n this.navigate(target, options),\n );\n\n terminalRan = await executeMiddlewarePipeline(\n context,\n [...this.#globalMiddleware, ...record.ownMiddleware] as unknown as Middleware<TRoutes>[],\n async () => {\n if (!isCurrent()) return;\n\n committed = true;\n commit(location, replace);\n\n if (!isCurrent()) return;\n\n await this.#runTerminal(record, context, location, params, attempt.signal, isCurrent, (error) => {\n dataError = error;\n hasDataError = true;\n });\n },\n (error) =>\n isRouterErrorCarrier(error) || (hasDataError && error === dataError)\n ? error\n : carryError(error, { routeName: record.leaf.name, source: 'middleware' }),\n );\n };\n\n try {\n await this.#runWithTransition(run, useTransition);\n } catch (error) {\n if (hasDataError && error === dataError) {\n throw carryError(error, { routeName: record.leaf.name, source: 'data-loader' });\n }\n\n throw error;\n } finally {\n if (isCurrent() && committed) {\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n }\n }\n\n return terminalRan && committed;\n }\n\n async #runWithTransition(run: () => Promise<void>, useTransition?: boolean): Promise<void> {\n if ((useTransition ?? this.#useViewTransition) && typeof document !== 'undefined') {\n const startViewTransition = (\n document as Document & {\n startViewTransition?: (callback: () => void | Promise<void>) => { finished: Promise<void> };\n }\n ).startViewTransition;\n\n if (startViewTransition) {\n await startViewTransition.call(document, run).finished;\n\n return;\n }\n }\n\n await run();\n }\n\n #applyScroll(to: RouteState, from: RouteState): void {\n if (!this.#scroll || typeof window === 'undefined') return;\n\n const decision = this.#scroll(to, from);\n\n if (decision === 'preserve') return;\n\n if (decision === 'top') {\n window.scrollTo(0, 0);\n\n return;\n }\n\n window.scrollTo(decision.x, decision.y);\n }\n\n // ─── Private: destination resolution ─────────────────────────────────────\n\n #resolveDestination(path: string): string {\n const parsed = new URL(path, 'http://localhost');\n const normalizedPath = stripBase(parsed.pathname, this.#base);\n\n return `${joinPaths(this.#base, normalizedPath)}${parsed.search}${parsed.hash}`;\n }\n\n #locationFromPath(path: string, historyState: unknown): RouteLocation {\n const parsed = new URL(this.#resolveDestination(path), 'http://localhost');\n\n return {\n hash: parsed.hash.replace(/^#/, ''),\n historyState,\n pathname: stripBase(parsed.pathname, this.#base),\n query: parseQuery(parsed.search),\n };\n }\n\n #hrefForLocation(location: RouteLocation): string {\n const search = new URLSearchParams();\n\n for (const [key, value] of Object.entries(location.query)) {\n if (Array.isArray(value))\n value.forEach((item) => {\n search.append(key, item);\n });\n else search.set(key, value);\n }\n\n const query = search.toString();\n const hash = location.hash ? `#${location.hash}` : '';\n\n return `${joinPaths(this.#base, location.pathname)}${query ? `?${query}` : ''}${hash}`;\n }\n\n #navigationDestination(href: string): NavigationDestination {\n const parsed = new URL(href, 'http://localhost');\n const pathname = stripBase(parsed.pathname, this.#base);\n const { params, record } = matchRouteFor(pathname, this.#records);\n\n return {\n name: record?.leaf.name,\n params,\n pathname,\n query: parseQuery(parsed.search),\n };\n }\n\n /** User-initiated navigation. History changes only after middleware reaches the terminal stage. */\n async #navigateToPath(path: string, options: NavigateOptions = {}): Promise<void> {\n this.#assertNotDisposed();\n\n const destination = this.#resolveDestination(path);\n\n if (!options.force && destination === this.#lastHref) return;\n\n const attempt = this.#navigation.begin();\n const activeMatchNames = this.#currentState.matches.map((match) => match.name);\n const allowed = await runLeaveBlockers(\n this.#beforeLeaveBlockers,\n activeMatchNames,\n this.#navigationDestination(destination),\n );\n\n if (!attempt.isCurrent() || !allowed) return;\n\n try {\n await this.#handleRoute(\n attempt,\n this.#locationFromPath(destination, options.state),\n (location, replace) => {\n if (!attempt.isCurrent()) return;\n\n const href = this.#hrefForLocation(location);\n\n if (replace) this.#history.replace(href, location.historyState);\n else this.#history.push(href, location.historyState);\n\n this.#lastHref = href;\n },\n options.viewTransition,\n 0,\n options.replace ?? false,\n );\n } catch (value) {\n throw isRouterErrorCarrier(value) ? value.error : value;\n }\n }\n}\n\n// ─── Public factory ───────────────────────────────────────────────────────────\n\n/**\n * Create a new router instance from a route table.\n *\n * @example\n * const router = createRouter({\n * routes: {\n * home: { path: '/' },\n * userDetail: { path: '/users/:id', data: fetchUser },\n * },\n * });\n */\nexport function createRouter<const TRoutes extends RouteTable>(options: RouterOptions<TRoutes>): Router<TRoutes> {\n return new Router(options);\n}\n\n// Export the Router type (not the constructor value) for type annotations.\nexport type { Router };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs","names":[],"sources":["../src/router.ts"],"sourcesContent":["import { createNavigationCoordinator, type NavigationAttempt } from './_navigation';\nimport { compileRoutes } from './compile';\nimport {\n buildMatchBranch,\n createRouteContext,\n createRouteState,\n executeMiddlewarePipeline,\n reportError,\n} from './context';\nimport { WayfinderDisposedError, WayfinderRedirectLoopError, WayfinderRouteError } from './errors';\nimport { type RegisteredBlocker, runLeaveBlockers } from './guards';\nimport { createBrowserHistory } from './history';\nimport {\n buildUrl,\n joinPaths,\n matchesPrefix,\n matchRouteFor,\n normalizePath,\n parseQuery,\n readLocation,\n stripBase,\n} from './path';\nimport type {\n BeforeLeaveBlocker,\n BeforeLeaveOptions,\n CoerceSearchFn,\n DataContext,\n DataFn,\n HistoryDriver,\n IsActiveOptions,\n Middleware,\n NamedNavigationTarget,\n NavigateOptions,\n NavigationDestination,\n PathParams,\n RawNavigationTarget,\n ResolvedQueryParams,\n RouteBranchDef,\n RouteContext,\n RouteLocation,\n RouteMatchBranch,\n RouteName,\n RouteParams,\n RoutePathByName,\n RouteRecord,\n RouterErrorContext,\n RouterOptions,\n RouteState,\n RouteTable,\n RouteViewMap,\n RouteViewName,\n RouteViewRegistry,\n Unsubscribe,\n} from './types';\n\n// ─── Module-level helpers ────────────────────────────────────────────────────\n\nfunction getRouteByName(name: string, routesByName: ReadonlyMap<string, RouteRecord>): RouteRecord {\n const route = routesByName.get(name);\n\n if (route) return route;\n\n const available = [...routesByName.keys()].join(', ');\n\n throw new WayfinderRouteError(\n available ? `Unknown route name: ${name}. Available routes: ${available}` : `Unknown route name: ${name}`,\n );\n}\n\nfunction resolveTarget(\n target: { path: string } | { hash?: string; name: string; params?: RouteParams; query?: ResolvedQueryParams },\n routesByName: ReadonlyMap<string, RouteRecord>,\n base = '/',\n): string {\n if ('path' in target) return target.path;\n\n const route = getRouteByName(target.name, routesByName);\n const path = buildUrl(base, route.path, target.params, target.query);\n\n return target.hash ? `${path}#${target.hash}` : path;\n}\n\n// ─── Internal error carrier ──────────────────────────────────────────────────\n//\n// Carries error context alongside the original error without mutating the thrown\n// object. The carrier is unwrapped before reaching external callers so error\n// identity and `cause` chains are preserved.\n\nconst ROUTER_ERROR = Symbol('wayfinder.routerError');\n\ntype RouterErrorCarrier = {\n [ROUTER_ERROR]: true;\n readonly error: unknown;\n readonly context: RouterErrorContext;\n};\n\nfunction carryError(error: unknown, context: RouterErrorContext): RouterErrorCarrier {\n return { [ROUTER_ERROR]: true, context, error };\n}\n\nfunction isRouterErrorCarrier(value: unknown): value is RouterErrorCarrier {\n return value !== null && typeof value === 'object' && ROUTER_ERROR in (value as Record<symbol, unknown>);\n}\n\nfunction unwrapCarrier(value: unknown): never {\n if (isRouterErrorCarrier(value)) throw value.error;\n\n throw value;\n}\n\n// ─── Internal types ───────────────────────────────────────────────────────────\n\ntype NavigationDecision =\n | {\n branch: RouteMatchBranch;\n location: RouteLocation;\n params: RouteParams;\n record: RouteRecord;\n resolvedQuery: ResolvedQueryParams;\n type: 'matched';\n }\n | { location: RouteLocation; params: RouteParams; type: 'unmatched' }\n | { location: RouteLocation; params: RouteParams; redirectTo: string; type: 'redirect' };\n\n// ─── Router class ─────────────────────────────────────────────────────────────\n\nclass Router<TRoutes extends RouteTable = RouteTable> {\n readonly #base: string;\n readonly #globalMiddleware: readonly Middleware[];\n readonly #globalCoerceSearch?: CoerceSearchFn;\n readonly #history: HistoryDriver;\n readonly #records: readonly RouteRecord[];\n readonly #routesByName: ReadonlyMap<string, RouteRecord>;\n readonly #onError?: RouterOptions<TRoutes>['onError'];\n readonly #scroll?: RouterOptions<TRoutes>['scroll'];\n readonly #useViewTransition: boolean;\n\n // Mutable navigation state\n readonly #beforeLeaveBlockers = new Set<RegisteredBlocker>();\n readonly #navigation = createNavigationCoordinator();\n #currentState: RouteState;\n #disposed = false;\n readonly #disposeController = new AbortController();\n #lastHref = '/';\n readonly #listeners = new Set<(state: RouteState) => void>();\n readonly #preloaded = new Map<string, unknown[]>();\n readonly #preloads = new Map<string, Promise<RouteState | null>>();\n // Compiled notFound fallback record\n readonly #notFoundRecord: RouteRecord | null;\n\n readonly #unlistenHistory: () => void;\n\n /** Resolves when the constructor-triggered navigation has settled; rejects if it fails. */\n readonly ready: Promise<void>;\n\n constructor(options: RouterOptions<TRoutes>) {\n const compiled = compileRoutes(options);\n\n this.#base = normalizePath(options.base ?? '/');\n this.#globalMiddleware = (options.middleware ?? []) as unknown as Middleware[];\n this.#globalCoerceSearch = options.coerceSearch;\n this.#history = options.history ?? createBrowserHistory();\n this.#onError = options.onError;\n this.#scroll = options.scroll;\n this.#useViewTransition = options.viewTransition ?? false;\n this.#records = compiled.records as unknown as readonly RouteRecord[];\n this.#routesByName = compiled.routesByName as unknown as ReadonlyMap<string, RouteRecord>;\n this.#currentState = createRouteState({\n location: { hash: '', historyState: null, pathname: '/', query: {} },\n matches: [] as RouteMatchBranch,\n status: 'idle',\n });\n\n // Build a synthetic RouteRecord for the notFound fallback.\n if (options.notFound) {\n const nf = options.notFound;\n const leafDef: RouteBranchDef = {\n dataFn: nf.data,\n name: '__notFound__',\n };\n\n this.#notFoundRecord = {\n branchDefs: [leafDef],\n leaf: leafDef,\n matcher: { paramNames: [], pattern: /(?:)/, prefixPattern: /(?:)/ },\n ownMiddleware: (nf.middleware ?? []) as unknown as Middleware[],\n path: '/*',\n };\n } else {\n this.#notFoundRecord = null;\n }\n\n this.#unlistenHistory = this.#registerHistoryListener();\n\n const { hash, pathname, search } = this.#history.location;\n\n this.#lastHref = `${pathname}${search}${hash}`;\n\n const attempt = this.#navigation.begin();\n\n const navigationPromise = this.#handleRoute(\n attempt,\n readLocation(this.#base, this.#history),\n (location, replace) => {\n if (!attempt.isCurrent()) return;\n\n const href = this.#hrefForLocation(location);\n\n if (replace) this.#history.replace(href, location.historyState);\n\n this.#lastHref = href;\n },\n undefined,\n 0,\n false,\n ).then(() => undefined);\n\n // ready rejects with the original error (carrier unwrapped) for external consumers.\n this.ready = navigationPromise.catch(unwrapCarrier);\n // Attach a silent handler so an unawaited ready promise doesn't trigger\n // an unhandled-rejection warning. External consumers can still await ready\n // and receive the rejection — each .catch() subscriber fires independently.\n this.ready.catch(() => {});\n // #runInBackground receives the raw promise so it can extract carrier context for onError.\n this.#runInBackground(navigationPromise, { source: 'initial-navigation' });\n\n // Router actions are intentionally bound once so they remain safe when destructured.\n this.beforeLeave = this.beforeLeave.bind(this);\n this.createViewRegistry = this.createViewRegistry.bind(this);\n this.dispose = this.dispose.bind(this);\n this.getSnapshot = this.getSnapshot.bind(this);\n this.isActive = this.isActive.bind(this);\n this.load = this.load.bind(this);\n this.match = this.match.bind(this);\n this.navigate = this.navigate.bind(this);\n this.preload = this.preload.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.url = this.url.bind(this);\n this.waitFor = this.waitFor.bind(this);\n }\n\n // ─── Public state ─────────────────────────────────────────────────────────\n\n /**\n * Returns the current immutable router state snapshot.\n *\n * Compatible with React's `useSyncExternalStore`:\n * ```ts\n * const state = useSyncExternalStore(\n * (cb) => router.subscribe(cb),\n * () => router.getSnapshot()\n * );\n * ```\n */\n getSnapshot(): RouteState {\n return this.#currentState;\n }\n\n createViewRegistry<const TViews extends RouteViewMap<TRoutes>, TNotFound = never>(\n views: TViews & Record<Exclude<keyof TViews, RouteViewName<TRoutes>>, never>,\n options?: { notFound?: TNotFound },\n ): RouteViewRegistry<TViews[keyof TViews] | TNotFound> {\n return {\n resolve: (state) => {\n const name = state.matches.at(-1)?.name;\n\n if (name === '__notFound__') return options?.notFound;\n\n return name ? (views[name as keyof TViews] as TViews[keyof TViews]) : undefined;\n },\n };\n }\n\n // ─── Subscription ─────────────────────────────────────────────────────────\n\n /**\n * Subscribe to state changes. The listener is called on each subsequent state change;\n * use `getSnapshot()` to read the current value immediately.\n */\n subscribe(listener: (state: RouteState) => void): Unsubscribe {\n this.#assertNotDisposed();\n this.#listeners.add(listener);\n\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n // ─── Navigation ───────────────────────────────────────────────────────────\n\n /**\n * Navigate using a named route target or a raw path target.\n *\n * If a data loader throws after terminal execution begins, history has already committed\n * the destination and the returned Promise rejects with the loader error.\n */\n navigate(\n target: NamedNavigationTarget<TRoutes> | RawNavigationTarget | string,\n options?: NavigateOptions,\n ): Promise<void> {\n const normalized = typeof target === 'string' ? { path: target } : target;\n const destination = resolveTarget(normalized, this.#routesByName);\n\n return this.#navigateToPath(destination, options);\n }\n\n // ─── URL helpers ──────────────────────────────────────────────────────────\n\n /** Build a URL for a named route, including optional params and query string. */\n url<Name extends RouteName<TRoutes>>(\n name: Name,\n params?: PathParams<RoutePathByName<TRoutes, Name>>,\n query?: ResolvedQueryParams,\n ): string {\n const route = getRouteByName(name, this.#routesByName);\n\n return buildUrl(this.#base, route.path, params, query);\n }\n\n /**\n * Build an anchor-ready href for a named route — the address-bar form for the configured\n * history driver. `url()` returns the router-internal path; under `createHashHistory`\n * the same route lives behind `#`, and `href()` returns that form for `<a>` elements.\n */\n href<Name extends RouteName<TRoutes>>(\n name: Name,\n params?: PathParams<RoutePathByName<TRoutes, Name>>,\n query?: ResolvedQueryParams,\n ): string {\n const route = getRouteByName(name, this.#routesByName);\n const url = buildUrl(this.#base, route.path, params, query);\n\n return this.#history.href?.(url) ?? url;\n }\n\n /** Returns true when the current location matches the named route by prefix (default) or exactly. */\n isActive<Name extends RouteName<TRoutes>>(name: Name, options: IsActiveOptions = {}): boolean {\n const route = getRouteByName(name, this.#routesByName);\n const pathname = this.#currentState.location.pathname;\n const exact = options.exact ?? false;\n\n return exact ? matchRouteFor(pathname, [route]).record != null : matchesPrefix(pathname, route);\n }\n\n /** Match a pathname to a route branch without running middleware or data loaders. Returns null for redirects or no match. */\n match(pathname: string): RouteMatchBranch | null {\n const normalizedPathname = stripBase(normalizePath(pathname), this.#base);\n const { params, record } = matchRouteFor(normalizedPathname, this.#records);\n\n if (!record || record.redirect) return null;\n\n const branch = buildMatchBranch(\n record.branchDefs,\n params,\n normalizedPathname,\n record.branchDefs.map(() => undefined),\n );\n\n return branch.length ? branch : null;\n }\n\n /**\n * Load a URL into a route state including data loader results, without modifying\n * router state or history. Follows declarative redirects but does not cache results.\n * Middleware is not executed — use `navigate()` when middleware side effects are needed.\n */\n async load(url: string, options?: { signal?: AbortSignal }): Promise<RouteState | null> {\n const prepared = await this.#resolveUrl(url);\n\n if (prepared.type !== 'matched') return null;\n\n const { location, params, record, resolvedQuery } = prepared;\n const defs = record.branchDefs;\n const hasData = defs.some((d) => d.dataFn != null);\n let dataResults: unknown[] = defs.map(() => undefined);\n let error: unknown;\n let status: 'error' | 'idle' = 'idle';\n\n if (hasData) {\n const effectiveSignal = options?.signal ?? new AbortController().signal;\n const branch = buildMatchBranch(defs, params, location.pathname, dataResults);\n const context = createRouteContext<TRoutes>(location, resolvedQuery, params, branch, () => Promise.resolve());\n\n try {\n dataResults = await this.#loadData(defs, context, effectiveSignal);\n } catch (e) {\n error = e;\n status = 'error';\n }\n }\n\n return createRouteState({\n error,\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status,\n });\n }\n\n async preload(target: NamedNavigationTarget<TRoutes>): Promise<RouteState | null> {\n this.#assertNotDisposed();\n\n const destination = this.#resolveDestination(resolveTarget(target, this.#routesByName, this.#base));\n const existing = this.#preloads.get(destination);\n\n if (existing) return existing;\n\n const work = this.load(destination, { signal: this.#disposeController.signal })\n .then((state) => {\n if (this.#disposed) throw this.#disposeController.signal.reason;\n\n if (state?.status === 'error') throw state.error;\n\n if (state) {\n const key = this.#hrefForLocation(state.location);\n\n if (this.#preloaded.size >= 20) this.#preloaded.delete(this.#preloaded.keys().next().value!);\n\n this.#preloaded.set(\n key,\n state.matches.map((match) => match.data),\n );\n }\n\n return state;\n })\n .catch((error) => {\n if (this.#onError) this.#reportError(error, { source: 'preload' });\n\n throw error;\n })\n .finally(() => {\n this.#preloads.delete(destination);\n });\n\n this.#preloads.set(destination, work);\n\n return work;\n }\n\n /**\n * Returns a Promise that resolves the next time the router reaches `status: 'idle'`\n * and the active matches include a route named `name`.\n *\n * - Resolves immediately if the router is already `idle` at `name`.\n * - Rejects immediately if the router is already in `status: 'error'`.\n * - If the router is currently `idle` at a **different** route and no navigation is in\n * flight, this promise will not resolve until a future navigation lands on `name`.\n * Typical use-case is awaiting a navigation you just triggered:\n * `router.navigate(target); await router.waitFor('routeName')`.\n * @throws {WayfinderDisposedError} if the router is disposed while the promise is pending,\n * or if called after the router has already been disposed.\n */\n waitFor(name: RouteName<TRoutes>): Promise<RouteState> {\n this.#assertNotDisposed();\n\n return new Promise((resolve, reject) => {\n const matchesName = (state: RouteState): boolean =>\n state.status === 'idle' && state.matches.some((m) => m.name === name);\n\n if (this.#currentState.status === 'error') {\n reject(this.#currentState.error);\n\n return;\n }\n\n if (matchesName(this.#currentState)) {\n resolve(this.#currentState);\n\n return;\n }\n\n const unsub = this.subscribe((state) => {\n if (matchesName(state)) {\n unsub();\n resolve(state);\n } else if (state.status === 'error') {\n unsub();\n reject(state.error);\n }\n });\n\n this.#disposeController.signal.addEventListener(\n 'abort',\n () => {\n unsub();\n reject(this.#disposeController.signal.reason);\n },\n { once: true },\n );\n });\n }\n\n // ─── Navigation guards ────────────────────────────────────────────────────\n\n /**\n * Register a leave guard. Called before user-triggered navigation attempts.\n * Return `false` to cancel; `true` to allow.\n * Returns a function that removes the guard.\n *\n * Use `options.routes` to scope the guard to specific routes (fires only when navigating\n * away from a route whose name appears in the array, checked against any node in the active branch).\n */\n beforeLeave(blocker: BeforeLeaveBlocker, options?: BeforeLeaveOptions<TRoutes>): Unsubscribe {\n this.#assertNotDisposed();\n\n const entry: RegisteredBlocker = {\n handler: blocker,\n routes: options?.routes as string[] | undefined,\n };\n\n this.#beforeLeaveBlockers.add(entry);\n\n return () => {\n this.#beforeLeaveBlockers.delete(entry);\n };\n }\n\n // ─── Lifecycle ────────────────────────────────────────────────────────────\n\n get disposalSignal(): AbortSignal {\n return this.#disposeController.signal;\n }\n\n get disposed(): boolean {\n return this.#disposed;\n }\n\n /** Dispose event listeners and prevent further router interaction. Idempotent. */\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n this.#beforeLeaveBlockers.clear();\n this.#listeners.clear();\n this.#preloaded.clear();\n this.#preloads.clear();\n this.#navigation.invalidate(new WayfinderDisposedError());\n this.#unlistenHistory();\n // Abort the disposal signal last — waitFor() listeners clean themselves up via this signal.\n this.#disposeController.abort(new WayfinderDisposedError());\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n\n // ─── Private: assertions ──────────────────────────────────────────────────\n\n #assertNotDisposed(): void {\n if (this.#disposed) throw new WayfinderDisposedError();\n }\n\n // ─── Private: history listener ────────────────────────────────────────────\n\n #registerHistoryListener(): () => void {\n return this.#history.onPopstate(() => {\n const { hash, pathname, search } = this.#history.location;\n const newHref = `${pathname}${search}${hash}`;\n const previousHref = this.#lastHref;\n\n if (newHref === previousHref) return;\n\n this.#runInBackground(this.#handleHistoryNavigation(newHref, previousHref), { source: 'history-listener' });\n });\n }\n\n async #handleHistoryNavigation(newHref: string, previousHref: string): Promise<void> {\n const attempt = this.#navigation.begin();\n const activeMatchNames = this.#currentState.matches.map((m) => m.name);\n const destination = this.#navigationDestination(newHref);\n const allowed = await runLeaveBlockers(this.#beforeLeaveBlockers, activeMatchNames, destination);\n\n if (!attempt.isCurrent()) return;\n\n if (!allowed) {\n this.#history.replace(previousHref, this.#currentState.location.historyState);\n\n return;\n }\n\n const terminalRan = await this.#handleRoute(\n attempt,\n readLocation(this.#base, this.#history),\n (location, replace) => {\n if (!attempt.isCurrent()) return;\n\n const href = this.#hrefForLocation(location);\n\n if (replace) this.#history.replace(href, location.historyState);\n\n this.#lastHref = href;\n },\n undefined,\n 0,\n false,\n );\n\n if (attempt.isCurrent() && !terminalRan) {\n this.#history.replace(previousHref, this.#currentState.location.historyState);\n }\n }\n\n // ─── Private: error handling ──────────────────────────────────────────────\n\n #reportError(error: unknown, context: RouterErrorContext): void {\n reportError(error, context, this.#onError);\n }\n\n #runInBackground(promise: Promise<void>, context: RouterErrorContext): void {\n void promise.catch((value) => {\n if (isRouterErrorCarrier(value)) {\n this.#reportError(value.error, value.context);\n } else {\n this.#reportError(value, context);\n }\n });\n }\n\n // ─── Private: listener notification ──────────────────────────────────────\n\n #notifyListeners(): void {\n for (const listener of [...this.#listeners]) {\n try {\n listener(this.#currentState);\n } catch (error) {\n // A throwing subscriber must not abort the rest of the notify pass or\n // corrupt navigation state; surface it as an unhandled error instead.\n queueMicrotask(() => {\n throw error;\n });\n }\n }\n }\n\n // ─── Private: data loaders ────────────────────────────────────────────────\n\n /**\n * Run all data loaders and return their results. Per-def `onError` boundaries are applied.\n */\n async #loadData(\n defs: readonly RouteBranchDef[],\n context: RouteContext<RouteParams, TRoutes>,\n signal: AbortSignal,\n ): Promise<unknown[]> {\n return Promise.all(\n defs.map(async (def) => {\n if (!def.dataFn) return undefined;\n\n const dataFn = def.dataFn as unknown as DataFn<RouteParams, TRoutes>;\n\n try {\n return await dataFn({ ...context, signal } as DataContext<RouteParams, TRoutes>);\n } catch (err) {\n if (def.onError) return def.onError(err, { ...context, signal } as unknown as DataContext);\n\n throw err;\n }\n }),\n );\n }\n\n // ─── Private: URL resolution ──────────────────────────────────────────────\n\n /** Parse a URL, call #prepareRoute, and follow declarative redirects up to 5 hops. */\n async #resolveUrl(url: string): Promise<NavigationDecision> {\n let destination = url;\n\n for (let i = 0; i < 5; i += 1) {\n const parsed = new URL(destination, 'http://localhost');\n const location: RouteLocation = {\n hash: parsed.hash.replace(/^#/, ''),\n historyState: null,\n pathname: stripBase(parsed.pathname, this.#base),\n query: parseQuery(parsed.search),\n };\n\n const prepared = await this.#prepareRoute(location);\n\n if (prepared.type !== 'redirect') return prepared;\n\n destination = this.#resolveDestination(prepared.redirectTo);\n }\n\n throw new WayfinderRedirectLoopError();\n }\n\n // ─── Private: route preparation ───────────────────────────────────────────\n\n async #prepareRoute(location: RouteLocation): Promise<NavigationDecision> {\n const { params, record } = matchRouteFor(location.pathname, this.#records);\n\n if (!record) {\n return { location, params, type: 'unmatched' };\n }\n\n if (record.redirect) {\n return {\n location,\n params,\n redirectTo: resolveTarget(record.redirect, this.#routesByName, this.#base),\n type: 'redirect',\n };\n }\n\n let resolvedQuery: ResolvedQueryParams = location.query;\n\n const coerce: CoerceSearchFn | undefined = record.coerceSearch ?? this.#globalCoerceSearch;\n\n if (coerce) {\n try {\n resolvedQuery = coerce(location.query);\n } catch (err) {\n this.#reportError(err, { source: 'coerce-search' });\n resolvedQuery = location.query;\n }\n }\n\n return {\n branch: buildMatchBranch(\n record.branchDefs,\n params,\n location.pathname,\n record.branchDefs.map(() => undefined),\n ),\n location,\n params,\n record,\n resolvedQuery,\n type: 'matched',\n };\n }\n\n // ─── Private: terminal (data only) ────────────────────────────────────────\n\n async #runTerminal(\n record: RouteRecord,\n context: RouteContext<RouteParams, TRoutes>,\n location: RouteLocation,\n params: RouteParams,\n signal: AbortSignal,\n isCurrent: () => boolean,\n onDataError?: (error: unknown) => void,\n ): Promise<void> {\n if (!isCurrent()) return;\n\n const defs = record.branchDefs;\n const hasData = defs.some((d) => d.dataFn != null);\n let dataResults: unknown[] = defs.map(() => undefined);\n\n if (hasData) {\n const preloadKey = this.#hrefForLocation(location);\n const preloading = this.#preloads.get(preloadKey);\n\n if (preloading) {\n await preloading.catch(() => undefined);\n\n if (!isCurrent()) return;\n }\n\n const cached = this.#preloaded.get(preloadKey);\n\n if (cached) {\n this.#preloaded.delete(preloadKey);\n dataResults = cached;\n } else {\n this.#currentState = createRouteState({\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status: 'loading',\n });\n this.#notifyListeners();\n\n try {\n dataResults = await this.#loadData(defs, context, signal);\n } catch (error) {\n if (!isCurrent()) return;\n\n this.#currentState = createRouteState({\n error,\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status: 'error',\n });\n onDataError?.(error);\n throw error;\n }\n }\n }\n\n if (!isCurrent()) return;\n\n this.#currentState = createRouteState({\n location,\n matches: buildMatchBranch(defs, params, location.pathname, dataResults),\n status: 'idle',\n });\n }\n\n // ─── Private: main navigation orchestrator ────────────────────────────────\n\n /**\n * Declarative redirects reuse the active attempt and replace the final history entry.\n * Middleware redirects call `ctx.navigate()`, which starts a new attempt.\n */\n async #handleRoute(\n attempt: NavigationAttempt,\n currentLocation: RouteLocation,\n commit: (location: RouteLocation, replace: boolean) => void,\n useTransition?: boolean,\n depth = 0,\n replace = false,\n ): Promise<boolean> {\n const previousState = this.#currentState;\n const isCurrent = (): boolean => attempt.isCurrent() && !this.#disposed;\n const prepared = await this.#prepareRoute(currentLocation);\n\n if (!isCurrent()) return false;\n\n if (prepared.type === 'redirect') {\n if (depth >= 5) throw new WayfinderRedirectLoopError();\n\n return this.#handleRoute(\n attempt,\n this.#locationFromPath(prepared.redirectTo, currentLocation.historyState),\n commit,\n useTransition,\n depth + 1,\n true,\n );\n }\n\n if (prepared.type === 'unmatched') {\n // Fall back to notFound record when defined.\n if (this.#notFoundRecord) {\n const nfDefs = [this.#notFoundRecord.leaf];\n const nfBranch = buildMatchBranch(nfDefs, {}, currentLocation.pathname, [undefined]);\n let committed = false;\n let dataError: unknown;\n let hasDataError = false;\n let terminalRan = false;\n\n // Apply global coerceSearch to the unmatched location so notFound handlers\n // receive typed query params, consistent with matched-route behaviour.\n let nfResolvedQuery: ResolvedQueryParams = currentLocation.query;\n let notified = false;\n\n if (this.#globalCoerceSearch) {\n try {\n nfResolvedQuery = this.#globalCoerceSearch(currentLocation.query);\n } catch (err) {\n this.#reportError(err, { source: 'coerce-search' });\n }\n }\n\n const run = async (): Promise<void> => {\n if (!isCurrent()) return;\n\n const context = createRouteContext<TRoutes>(\n currentLocation,\n nfResolvedQuery,\n {},\n nfBranch,\n (target, options) => this.navigate(target, options),\n );\n\n terminalRan = await executeMiddlewarePipeline(\n context,\n [...this.#globalMiddleware, ...this.#notFoundRecord!.ownMiddleware] as unknown as Middleware<TRoutes>[],\n async () => {\n if (!isCurrent()) return;\n\n committed = true;\n commit(currentLocation, replace);\n\n if (!isCurrent()) return;\n\n await this.#runTerminal(\n this.#notFoundRecord!,\n context,\n currentLocation,\n {},\n attempt.signal,\n isCurrent,\n (error) => {\n dataError = error;\n hasDataError = true;\n },\n );\n\n if (!isCurrent()) return;\n\n // Swap and scroll while the view transition is still open: the new view renders\n // and the scroll resets before the new-state capture, so neither change lands\n // as an uncovered jump after the animation ends.\n notified = true;\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n },\n (error) =>\n isRouterErrorCarrier(error) || (hasDataError && error === dataError)\n ? error\n : carryError(error, { routeName: '__notFound__', source: 'middleware' }),\n );\n };\n\n try {\n await this.#runWithTransition(run, useTransition);\n } catch (error) {\n if (hasDataError && error === dataError) {\n throw carryError(error, { routeName: '__notFound__', source: 'data-loader' });\n }\n\n throw error;\n } finally {\n // Abort and error paths skip the in-run swap above; they still settle here.\n if (isCurrent() && committed && !notified) {\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n }\n }\n\n return terminalRan && committed;\n }\n\n if (!isCurrent()) return false;\n\n commit(prepared.location, replace);\n\n if (!isCurrent()) return false;\n\n this.#currentState = createRouteState({\n location: prepared.location,\n matches: [] as RouteMatchBranch,\n status: 'idle',\n });\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n\n return true;\n }\n\n const { branch, location, params, record, resolvedQuery } = prepared;\n let committed = false;\n let dataError: unknown;\n let hasDataError = false;\n let terminalRan = false;\n let notified = false;\n\n const run = async (): Promise<void> => {\n if (!isCurrent()) return;\n\n const context = createRouteContext<TRoutes>(location, resolvedQuery, params, branch, (target, options) =>\n this.navigate(target, options),\n );\n\n terminalRan = await executeMiddlewarePipeline(\n context,\n [...this.#globalMiddleware, ...record.ownMiddleware] as unknown as Middleware<TRoutes>[],\n async () => {\n if (!isCurrent()) return;\n\n committed = true;\n commit(location, replace);\n\n if (!isCurrent()) return;\n\n await this.#runTerminal(record, context, location, params, attempt.signal, isCurrent, (error) => {\n dataError = error;\n hasDataError = true;\n });\n\n if (!isCurrent()) return;\n\n // Swap and scroll while the view transition is still open: the new view renders\n // and the scroll resets before the new-state capture, so neither change lands\n // as an uncovered jump after the animation ends.\n notified = true;\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n },\n (error) =>\n isRouterErrorCarrier(error) || (hasDataError && error === dataError)\n ? error\n : carryError(error, { routeName: record.leaf.name, source: 'middleware' }),\n );\n };\n\n try {\n await this.#runWithTransition(run, useTransition);\n } catch (error) {\n if (hasDataError && error === dataError) {\n throw carryError(error, { routeName: record.leaf.name, source: 'data-loader' });\n }\n\n throw error;\n } finally {\n // Abort and error paths skip the in-run swap above; they still settle here.\n if (isCurrent() && committed && !notified) {\n this.#notifyListeners();\n this.#applyScroll(this.#currentState, previousState);\n }\n }\n\n return terminalRan && committed;\n }\n\n async #runWithTransition(run: () => Promise<void>, useTransition?: boolean): Promise<void> {\n if ((useTransition ?? this.#useViewTransition) && typeof document !== 'undefined') {\n const startViewTransition = (\n document as Document & {\n startViewTransition?: (callback: () => void | Promise<void>) => { finished: Promise<void> };\n }\n ).startViewTransition;\n\n if (startViewTransition) {\n await startViewTransition.call(document, run).finished;\n\n return;\n }\n }\n\n await run();\n }\n\n #applyScroll(to: RouteState, from: RouteState): void {\n if (!this.#scroll || typeof window === 'undefined') return;\n\n const decision = this.#scroll(to, from);\n\n if (decision === 'preserve') return;\n\n if (decision === 'top') {\n window.scrollTo(0, 0);\n\n return;\n }\n\n window.scrollTo(decision.x, decision.y);\n }\n\n // ─── Private: destination resolution ─────────────────────────────────────\n\n #resolveDestination(path: string): string {\n const parsed = new URL(path, 'http://localhost');\n const normalizedPath = stripBase(parsed.pathname, this.#base);\n\n return `${joinPaths(this.#base, normalizedPath)}${parsed.search}${parsed.hash}`;\n }\n\n #locationFromPath(path: string, historyState: unknown): RouteLocation {\n const parsed = new URL(this.#resolveDestination(path), 'http://localhost');\n\n return {\n hash: parsed.hash.replace(/^#/, ''),\n historyState,\n pathname: stripBase(parsed.pathname, this.#base),\n query: parseQuery(parsed.search),\n };\n }\n\n #hrefForLocation(location: RouteLocation): string {\n const search = new URLSearchParams();\n\n for (const [key, value] of Object.entries(location.query)) {\n if (Array.isArray(value))\n value.forEach((item) => {\n search.append(key, item);\n });\n else search.set(key, value);\n }\n\n const query = search.toString();\n const hash = location.hash ? `#${location.hash}` : '';\n\n return `${joinPaths(this.#base, location.pathname)}${query ? `?${query}` : ''}${hash}`;\n }\n\n #navigationDestination(href: string): NavigationDestination {\n const parsed = new URL(href, 'http://localhost');\n const pathname = stripBase(parsed.pathname, this.#base);\n const { params, record } = matchRouteFor(pathname, this.#records);\n\n return {\n name: record?.leaf.name,\n params,\n pathname,\n query: parseQuery(parsed.search),\n };\n }\n\n /** User-initiated navigation. History changes only after middleware reaches the terminal stage. */\n async #navigateToPath(path: string, options: NavigateOptions = {}): Promise<void> {\n this.#assertNotDisposed();\n\n const destination = this.#resolveDestination(path);\n\n if (!options.force && destination === this.#lastHref) return;\n\n const attempt = this.#navigation.begin();\n const activeMatchNames = this.#currentState.matches.map((match) => match.name);\n const allowed = await runLeaveBlockers(\n this.#beforeLeaveBlockers,\n activeMatchNames,\n this.#navigationDestination(destination),\n );\n\n if (!attempt.isCurrent() || !allowed) return;\n\n try {\n await this.#handleRoute(\n attempt,\n this.#locationFromPath(destination, options.state),\n (location, replace) => {\n if (!attempt.isCurrent()) return;\n\n const href = this.#hrefForLocation(location);\n\n if (replace) this.#history.replace(href, location.historyState);\n else this.#history.push(href, location.historyState);\n\n this.#lastHref = href;\n },\n options.viewTransition,\n 0,\n options.replace ?? false,\n );\n } catch (value) {\n throw isRouterErrorCarrier(value) ? value.error : value;\n }\n }\n}\n\n// ─── Public factory ───────────────────────────────────────────────────────────\n\n/**\n * Create a new router instance from a route table.\n *\n * @example\n * const router = createRouter({\n * routes: {\n * home: { path: '/' },\n * userDetail: { path: '/users/:id', data: fetchUser },\n * },\n * });\n */\nexport function createRouter<const TRoutes extends RouteTable>(options: RouterOptions<TRoutes>): Router<TRoutes> {\n return new Router(options);\n}\n\n// Export the Router type (not the constructor value) for type annotations.\nexport type { Router };\n"],"mappings":"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"}
|
package/dist/router.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BeforeLeaveBlocker, BeforeLeaveOptions, IsActiveOptions, NamedNavigationTarget, NavigateOptions, PathParams, RawNavigationTarget, ResolvedQueryParams, RouteMatchBranch, RouteName, RoutePathByName, RouterOptions, RouteState, RouteTable, RouteViewMap, RouteViewName, RouteViewRegistry, Unsubscribe } from './types';
|
|
2
|
-
declare class Router<TRoutes extends RouteTable> {
|
|
2
|
+
declare class Router<TRoutes extends RouteTable = RouteTable> {
|
|
3
3
|
#private;
|
|
4
4
|
/** Resolves when the constructor-triggered navigation has settled; rejects if it fails. */
|
|
5
5
|
readonly ready: Promise<void>;
|
|
@@ -33,6 +33,12 @@ declare class Router<TRoutes extends RouteTable> {
|
|
|
33
33
|
navigate(target: NamedNavigationTarget<TRoutes> | RawNavigationTarget | string, options?: NavigateOptions): Promise<void>;
|
|
34
34
|
/** Build a URL for a named route, including optional params and query string. */
|
|
35
35
|
url<Name extends RouteName<TRoutes>>(name: Name, params?: PathParams<RoutePathByName<TRoutes, Name>>, query?: ResolvedQueryParams): string;
|
|
36
|
+
/**
|
|
37
|
+
* Build an anchor-ready href for a named route — the address-bar form for the configured
|
|
38
|
+
* history driver. `url()` returns the router-internal path; under `createHashHistory`
|
|
39
|
+
* the same route lives behind `#`, and `href()` returns that form for `<a>` elements.
|
|
40
|
+
*/
|
|
41
|
+
href<Name extends RouteName<TRoutes>>(name: Name, params?: PathParams<RoutePathByName<TRoutes, Name>>, query?: ResolvedQueryParams): string;
|
|
36
42
|
/** Returns true when the current location matches the named route by prefix (default) or exactly. */
|
|
37
43
|
isActive<Name extends RouteName<TRoutes>>(name: Name, options?: IsActiveOptions): boolean;
|
|
38
44
|
/** Match a pathname to a route branch without running middleware or data loaders. Returns null for redirects or no match. */
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAKlB,eAAe,EAEf,qBAAqB,EACrB,eAAe,EAEf,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EAInB,gBAAgB,EAChB,SAAS,EAET,eAAe,EAGf,aAAa,EACb,UAAU,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,WAAW,EACZ,MAAM,SAAS,CAAC;AAyEjB,cAAM,MAAM,CAAC,OAAO,SAAS,UAAU;;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|