@real-router/core 0.54.5 → 0.54.6

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/esm/api.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{a as e,c as t,d as n,i as r,l as i,r as a,s as o}from"./Router-_BDnheMY.mjs";import{r as s,t as c}from"./internals-C59msvHY.mjs";import{i as l,n as u,r as d,t as f}from"./cloneRouter-DM59kihh.mjs";import{logger as p}from"@real-router/logger";function m(e,t,n){if(t){let n=t===e,r=t.startsWith(`${e}.`);if(n||r){let r=n?``:` (current: "${t}")`;return p.warn(`router.removeRoute`,`Cannot remove route "${e}" — it is currently active${r}. Navigate away first.`),!1}}return n&&p.warn(`router.removeRoute`,`Route "${e}" removed while navigation is in progress. This may cause unexpected behavior.`),!0}function h(e){return e?(p.error(`router.clearRoutes`,`Cannot clear routes while navigation is in progress. Wait for navigation to complete.`),!1):!0}function g(e,t,n=``){for(let r of e){let e=n?`${n}.${r.name}`:r.name;if(e===t)return r;if(r.children&&t.startsWith(`${e}.`))return g(r.children,t,e)}}function _(e,t,n,r){let i=t=>t===e||t.startsWith(`${e}.`);o(t.decoders,i),o(t.encoders,i),o(t.defaultParams,i),o(t.forwardMap,i),o(t.forwardFnMap,i),o(n,i),o(t.forwardMap,e=>i(t.forwardMap[e]));let[a,s]=r.getFactories();for(let e of Object.keys(s))i(e)&&r.clearCanActivate(e);for(let e of Object.keys(a))i(e)&&r.clearCanDeactivate(e)}function v(e,t,n,r){return t===null?(delete n.forwardMap[e],delete n.forwardFnMap[e]):typeof t==`string`?(delete n.forwardFnMap[e],n.forwardMap[e]=t):(delete n.forwardMap[e],n.forwardFnMap[e]=t),r(n)}function y(e,t,n,r){let i={name:e.name,path:e.path},a=n.forwardFnMap[t],o=n.forwardMap[t];a===void 0?o!==void 0&&(i.forwardTo=o):i.forwardTo=a,t in n.defaultParams&&(i.defaultParams=n.defaultParams[t]),t in n.decoders&&(i.decodeParams=n.decoders[t]),t in n.encoders&&(i.encodeParams=n.encoders[t]);let[s,c]=r;return t in c&&(i.canActivate=c[t]),t in s&&(i.canDeactivate=s[t]),e.children&&(i.children=e.children.map(e=>y(e,`${t}.${e.name}`,n,r))),i}function b(t,n,r){if(r){let e=g(t.definitions,r);e.children??=[];for(let t of n)e.children.push(i(t))}else for(let e of n)t.definitions.push(i(e));e(n,t.config,t.routeCustomFields,t.pendingCanActivate,t.pendingCanDeactivate,t.depsStore,r??``),t.treeOperations.commitTreeChanges(t)}function x(t,n,r,o,s){a(t),t.lifecycleNamespace.clearDefinitionGuards();for(let e of n)t.definitions.push(i(e));if(e(n,t.config,t.routeCustomFields,t.pendingCanActivate,t.pendingCanDeactivate,t.depsStore,``),t.treeOperations.commitTreeChanges(t),o!==void 0){let e=r.matchPath(o,r.getOptions());e?r.setState({...e,transition:s}):r.clearState()}}function S(e,n){return t(e.definitions,n)?(_(n,e.config,e.routeCustomFields,e.lifecycleNamespace),e.treeOperations.commitTreeChanges(e),!0):!1}function C(e,t,n){if(n.forwardTo!==void 0&&(e.resolvedForwardMap=v(t,n.forwardTo,e.config,e=>r(e))),n.defaultParams!==void 0&&(n.defaultParams===null?delete e.config.defaultParams[t]:e.config.defaultParams[t]=n.defaultParams),n.decodeParams!==void 0)if(n.decodeParams===null)delete e.config.decoders[t];else{let r=n.decodeParams;e.config.decoders[t]=e=>r(e)??e}if(n.encodeParams!==void 0)if(n.encodeParams===null)delete e.config.encoders[t];else{let r=n.encodeParams;e.config.encoders[t]=e=>r(e)??e}}function w(e,t){let n=e.matcher.getSegmentsByName(t);if(!n)return;let r=n.at(-1),i=e.treeOperations.nodeToDefinition(r),a=e.lifecycleNamespace.getFactories();return y(i,t,e.config,a)}function T(e){let t=s(e),r=t.routeGetStore(),i=c(`add`,(e,t)=>{b(r,e,t?.parent)},t.interceptors);return{add:(e,a)=>{l(t.isDisposed);let o=Array.isArray(e)?e:[e],s=a?.parent;n(o,t.validator),s!==void 0&&t.validator?.routes.validateParentOption(s,r.tree),t.validator?.routes.throwIfInternalRouteInArray(o,`addRoute`),t.validator?.routes.validateAddRouteArgs(o),t.validator?.routes.validateRoutes(o,r),i(o,s===void 0?void 0:{parent:s})},remove:e=>{l(t.isDisposed),t.validator?.routes.validateRemoveRouteArgs(e),t.validator?.routes.throwIfInternalRoute(e,`removeRoute`),m(e,t.getStateName(),t.isTransitioning())&&(S(r,e)||p.warn(`router.removeRoute`,`Route "${e}" not found. No changes made.`))},update:(e,n)=>{l(t.isDisposed),t.validator?.routes.validateUpdateRouteBasicArgs(e,n),t.validator?.routes.throwIfInternalRoute(e,`updateRoute`);let{forwardTo:i,defaultParams:a,decodeParams:o,encodeParams:s,canActivate:c,canDeactivate:u}=n;t.validator?.routes.validateUpdateRoutePropertyTypes(e,n),t.isTransitioning()&&p.error(`router.updateRoute`,`Updating route "${e}" while navigation is in progress. This may cause unexpected behavior.`),t.validator?.routes.validateUpdateRoute(e,n,r),C(r,e,{forwardTo:i,defaultParams:a,decodeParams:o,encodeParams:s}),c!==void 0&&(c===null?r.lifecycleNamespace.clearCanActivate(e):r.lifecycleNamespace.addCanActivate(e,c,!0)),u!==void 0&&(u===null?r.lifecycleNamespace.clearCanDeactivate(e):r.lifecycleNamespace.addCanDeactivate(e,u,!0))},clear:()=>{l(t.isDisposed),h(t.isTransitioning())&&(r.treeOperations.resetStore(r),r.lifecycleNamespace.clearAll(),t.clearState())},has:e=>(t.validator?.routes.validateRouteName(e,`hasRoute`),r.matcher.hasRoute(e)),get:e=>(t.validator?.routes.validateRouteName(e,`getRoute`),w(r,e)),replace:i=>{l(t.isDisposed);let a=Array.isArray(i)?i:[i];if(!h(t.isTransitioning()))return;n(a,t.validator),t.validator?.routes.throwIfInternalRouteInArray(a,`replaceRoutes`),t.validator?.routes.validateAddRouteArgs(a),t.validator?.routes.validateRoutes(a,r);let o=e.getState();x(r,a,t,o?.path,o?.transition)}}}function E(e,t,n,r){if(n===void 0)return!1;if(!Object.hasOwn(e.dependencies,t))r?.dependencies.validateDependencyCount(e,`setDependency`);else{let i=e.dependencies[t];i!==n&&!(Number.isNaN(i)&&Number.isNaN(n))&&r?.dependencies.warnOverwrite(t,`setDependency`)}return e.dependencies[t]=n,!0}function D(e,t,n){let r=[];for(let i in t)t[i]!==void 0&&(Object.hasOwn(e.dependencies,i)?r.push(i):n?.dependencies.validateDependencyCount(e,`setDependencies`),e.dependencies[i]=t[i]);r.length>0&&n?.dependencies.warnBatchOverwrite(r,`setDependencies`)}function O(e){let t=s(e);return{get:e=>{t.validator?.dependencies.validateDependencyName(e,`getDependency`);let n=t.dependenciesGetStore(),r=n.dependencies[e];return t.validator?.dependencies.validateDependencyExists(e,n),r},getAll:()=>({...t.dependenciesGetStore().dependencies}),set:(e,n)=>{l(t.isDisposed),t.validator?.dependencies.validateSetDependencyArgs(e,n,`setDependency`),E(t.dependenciesGetStore(),e,n,t.validator)},setAll:e=>{l(t.isDisposed);let n=t.dependenciesGetStore();t.validator?.dependencies.validateDependenciesObject(e,`setDependencies`),t.validator?.dependencies.validateDependencyLimit(n,n.limits),D(n,e,t.validator)},remove:e=>{l(t.isDisposed),t.validator?.dependencies.validateDependencyName(e,`removeDependency`);let n=t.dependenciesGetStore();Object.hasOwn(n.dependencies,e)||t.validator?.dependencies.warnRemoveNonExistent(e),delete n.dependencies[e]},reset:()=>{l(t.isDisposed);let e=t.dependenciesGetStore();e.dependencies=Object.create(null)},has:e=>(t.validator?.dependencies.validateDependencyName(e,`hasDependency`),Object.hasOwn(t.dependenciesGetStore().dependencies,e))}}export{f as cloneRouter,O as getDependenciesApi,u as getLifecycleApi,d as getPluginApi,T as getRoutesApi};
1
+ import{a as e,c as t,d as n,i as r,l as i,r as a,s as o}from"./Router-pwd8YBWr.mjs";import{r as s,t as c}from"./internals-C59msvHY.mjs";import{i as l,n as u,r as d,t as f}from"./cloneRouter-U8NeEoPX.mjs";import{logger as p}from"@real-router/logger";function m(e,t,n){if(t){let n=t===e,r=t.startsWith(`${e}.`);if(n||r){let r=n?``:` (current: "${t}")`;return p.warn(`router.removeRoute`,`Cannot remove route "${e}" — it is currently active${r}. Navigate away first.`),!1}}return n&&p.warn(`router.removeRoute`,`Route "${e}" removed while navigation is in progress. This may cause unexpected behavior.`),!0}function h(e){return e?(p.error(`router.clearRoutes`,`Cannot clear routes while navigation is in progress. Wait for navigation to complete.`),!1):!0}function g(e,t,n=``){for(let r of e){let e=n?`${n}.${r.name}`:r.name;if(e===t)return r;if(r.children&&t.startsWith(`${e}.`))return g(r.children,t,e)}}function _(e,t,n,r){let i=t=>t===e||t.startsWith(`${e}.`);o(t.decoders,i),o(t.encoders,i),o(t.defaultParams,i),o(t.forwardMap,i),o(t.forwardFnMap,i),o(n,i),o(t.forwardMap,e=>i(t.forwardMap[e]));let[a,s]=r.getFactories();for(let e of Object.keys(s))i(e)&&r.clearCanActivate(e);for(let e of Object.keys(a))i(e)&&r.clearCanDeactivate(e)}function v(e,t,n,r){return t===null?(delete n.forwardMap[e],delete n.forwardFnMap[e]):typeof t==`string`?(delete n.forwardFnMap[e],n.forwardMap[e]=t):(delete n.forwardMap[e],n.forwardFnMap[e]=t),r(n)}function y(e,t,n,r){let i={name:e.name,path:e.path},a=n.forwardFnMap[t],o=n.forwardMap[t];a===void 0?o!==void 0&&(i.forwardTo=o):i.forwardTo=a,t in n.defaultParams&&(i.defaultParams=n.defaultParams[t]),t in n.decoders&&(i.decodeParams=n.decoders[t]),t in n.encoders&&(i.encodeParams=n.encoders[t]);let[s,c]=r;return t in c&&(i.canActivate=c[t]),t in s&&(i.canDeactivate=s[t]),e.children&&(i.children=e.children.map(e=>y(e,`${t}.${e.name}`,n,r))),i}function b(t,n,r){if(r){let e=g(t.definitions,r);e.children??=[];for(let t of n)e.children.push(i(t))}else for(let e of n)t.definitions.push(i(e));e(n,t.config,t.routeCustomFields,t.pendingCanActivate,t.pendingCanDeactivate,t.depsStore,r??``),t.treeOperations.commitTreeChanges(t)}function x(t,n,r,o,s){a(t),t.lifecycleNamespace.clearDefinitionGuards();for(let e of n)t.definitions.push(i(e));if(e(n,t.config,t.routeCustomFields,t.pendingCanActivate,t.pendingCanDeactivate,t.depsStore,``),t.treeOperations.commitTreeChanges(t),o!==void 0){let e=r.matchPath(o,r.getOptions());e?r.setState({...e,transition:s}):r.clearState()}}function S(e,n){return t(e.definitions,n)?(_(n,e.config,e.routeCustomFields,e.lifecycleNamespace),e.treeOperations.commitTreeChanges(e),!0):!1}function C(e,t,n){if(n.forwardTo!==void 0&&(e.resolvedForwardMap=v(t,n.forwardTo,e.config,e=>r(e))),n.defaultParams!==void 0&&(n.defaultParams===null?delete e.config.defaultParams[t]:e.config.defaultParams[t]=n.defaultParams),n.decodeParams!==void 0)if(n.decodeParams===null)delete e.config.decoders[t];else{let r=n.decodeParams;e.config.decoders[t]=e=>r(e)??e}if(n.encodeParams!==void 0)if(n.encodeParams===null)delete e.config.encoders[t];else{let r=n.encodeParams;e.config.encoders[t]=e=>r(e)??e}}function w(e,t){let n=e.matcher.getSegmentsByName(t);if(!n)return;let r=n.at(-1),i=e.treeOperations.nodeToDefinition(r),a=e.lifecycleNamespace.getFactories();return y(i,t,e.config,a)}function T(e){let t=s(e),r=t.routeGetStore(),i=c(`add`,(e,t)=>{b(r,e,t?.parent)},t.interceptors);return{add:(e,a)=>{l(t.isDisposed);let o=Array.isArray(e)?e:[e],s=a?.parent;n(o,t.validator),s!==void 0&&t.validator?.routes.validateParentOption(s,r.tree),t.validator?.routes.throwIfInternalRouteInArray(o,`addRoute`),t.validator?.routes.validateAddRouteArgs(o),t.validator?.routes.validateRoutes(o,r),i(o,s===void 0?void 0:{parent:s})},remove:e=>{l(t.isDisposed),t.validator?.routes.validateRemoveRouteArgs(e),t.validator?.routes.throwIfInternalRoute(e,`removeRoute`),m(e,t.getStateName(),t.isTransitioning())&&(S(r,e)||p.warn(`router.removeRoute`,`Route "${e}" not found. No changes made.`))},update:(e,n)=>{l(t.isDisposed),t.validator?.routes.validateUpdateRouteBasicArgs(e,n),t.validator?.routes.throwIfInternalRoute(e,`updateRoute`);let{forwardTo:i,defaultParams:a,decodeParams:o,encodeParams:s,canActivate:c,canDeactivate:u}=n;t.validator?.routes.validateUpdateRoutePropertyTypes(e,n),t.isTransitioning()&&p.error(`router.updateRoute`,`Updating route "${e}" while navigation is in progress. This may cause unexpected behavior.`),t.validator?.routes.validateUpdateRoute(e,n,r),C(r,e,{forwardTo:i,defaultParams:a,decodeParams:o,encodeParams:s}),c!==void 0&&(c===null?r.lifecycleNamespace.clearCanActivate(e):r.lifecycleNamespace.addCanActivate(e,c,!0)),u!==void 0&&(u===null?r.lifecycleNamespace.clearCanDeactivate(e):r.lifecycleNamespace.addCanDeactivate(e,u,!0))},clear:()=>{l(t.isDisposed),h(t.isTransitioning())&&(r.treeOperations.resetStore(r),r.lifecycleNamespace.clearAll(),t.clearState())},has:e=>(t.validator?.routes.validateRouteName(e,`hasRoute`),r.matcher.hasRoute(e)),get:e=>(t.validator?.routes.validateRouteName(e,`getRoute`),w(r,e)),replace:i=>{l(t.isDisposed);let a=Array.isArray(i)?i:[i];if(!h(t.isTransitioning()))return;n(a,t.validator),t.validator?.routes.throwIfInternalRouteInArray(a,`replaceRoutes`),t.validator?.routes.validateAddRouteArgs(a),t.validator?.routes.validateRoutes(a,r);let o=e.getState();x(r,a,t,o?.path,o?.transition)}}}function E(e,t,n,r){if(n===void 0)return!1;if(!Object.hasOwn(e.dependencies,t))r?.dependencies.validateDependencyCount(e,`setDependency`);else{let i=e.dependencies[t];i!==n&&!(Number.isNaN(i)&&Number.isNaN(n))&&r?.dependencies.warnOverwrite(t,`setDependency`)}return e.dependencies[t]=n,!0}function D(e,t,n){let r=[];for(let i in t)t[i]!==void 0&&(Object.hasOwn(e.dependencies,i)?r.push(i):n?.dependencies.validateDependencyCount(e,`setDependencies`),e.dependencies[i]=t[i]);r.length>0&&n?.dependencies.warnBatchOverwrite(r,`setDependencies`)}function O(e){let t=s(e);return{get:e=>{t.validator?.dependencies.validateDependencyName(e,`getDependency`);let n=t.dependenciesGetStore(),r=n.dependencies[e];return t.validator?.dependencies.validateDependencyExists(e,n),r},getAll:()=>({...t.dependenciesGetStore().dependencies}),set:(e,n)=>{l(t.isDisposed),t.validator?.dependencies.validateSetDependencyArgs(e,n,`setDependency`),E(t.dependenciesGetStore(),e,n,t.validator)},setAll:e=>{l(t.isDisposed);let n=t.dependenciesGetStore();t.validator?.dependencies.validateDependenciesObject(e,`setDependencies`),t.validator?.dependencies.validateDependencyLimit(n,n.limits),D(n,e,t.validator)},remove:e=>{l(t.isDisposed),t.validator?.dependencies.validateDependencyName(e,`removeDependency`);let n=t.dependenciesGetStore();Object.hasOwn(n.dependencies,e)||t.validator?.dependencies.warnRemoveNonExistent(e),delete n.dependencies[e]},reset:()=>{l(t.isDisposed);let e=t.dependenciesGetStore();e.dependencies=Object.create(null)},has:e=>(t.validator?.dependencies.validateDependencyName(e,`hasDependency`),Object.hasOwn(t.dependenciesGetStore().dependencies,e))}}export{f as cloneRouter,O as getDependenciesApi,u as getLifecycleApi,d as getPluginApi,T as getRoutesApi};
2
2
  //# sourceMappingURL=api.mjs.map
@@ -1,2 +1,2 @@
1
- import{m as e,n as t,t as n,u as r}from"./Router-_BDnheMY.mjs";import{r as i}from"./internals-C59msvHY.mjs";function a(n){if(n())throw new t(e.ROUTER_DISPOSED)}const o=new WeakMap;function s(n){let r=o.get(n);if(r)return r;let s=i(n),c={makeState:(e,t,n,r)=>(s.validator?.state.validateMakeStateArgs(e,t,n),s.makeState(e,t,n,r?.params)),buildState:(e,t)=>{s.validator?.routes.validateStateBuilderArgs(e,t,`buildState`);let{name:n,params:r}=s.forwardState(e,t);return s.buildStateResolved(n,r)},forwardState:(e,t)=>(s.validator?.routes.validateStateBuilderArgs(e,t,`forwardState`),s.forwardState(e,t)),matchPath:e=>(s.validator?.routes.validateMatchPathArgs(e),s.matchPath(e,s.getOptions())),navigateToState:(e,t)=>(a(s.isDisposed),s.validator?.navigation.validateNavigateToStateArgs(e),t!==void 0&&s.validator?.navigation.validateNavigationOptions(t,`navigateToState`),s.navigateToState(e,t)),setRootPath:e=>{a(s.isDisposed),s.validator?.routes.validateSetRootPathArgs(e),s.setRootPath(e)},getRootPath:s.getRootPath,addEventListener:(e,t)=>(a(s.isDisposed),s.validator?.eventBus.validateListenerArgs(e,t),s.addEventListener(e,t)),buildNavigationState:(e,t={})=>{s.validator?.routes.validateStateBuilderArgs(e,t,`buildNavigationState`);let{name:n,params:r}=s.forwardState(e,t),i=s.buildStateResolved(n,r);if(i)return s.makeState(i.name,i.params,s.buildPath(i.name,i.params),i.meta)},getOptions:s.getOptions,getTree:s.getTree,addInterceptor:(e,t)=>{a(s.isDisposed),s.validator?.plugins.validateAddInterceptorArgs(e,t);let n=s.interceptors.get(e);return n||(n=[],s.interceptors.set(e,n)),n.push(t),()=>{let e=n.indexOf(t);e!==-1&&n.splice(e,1)}},getRouteConfig:e=>{let t=s.routeGetStore();if(t.matcher.hasRoute(e))return t.routeCustomFields[e]},extendRouter:r=>{a(s.isDisposed);let i=Object.keys(r);for(let r of i)if(r in n)throw new t(e.PLUGIN_CONFLICT,{message:`Cannot extend router: property "${r}" already exists`});for(let e of i)n[e]=r[e];let o={keys:i};s.routerExtensions.push(o);let c=!1;return()=>{if(c)return;c=!0;for(let e of o.keys)delete n[e];let e=s.routerExtensions.indexOf(o);e!==-1&&s.routerExtensions.splice(e,1)}},emitTransitionError:e=>{a(s.isDisposed),s.emitTransitionError(e)},claimContextNamespace:n=>{if(a(s.isDisposed),s.contextClaimRecords.has(n))throw new t(e.CONTEXT_NAMESPACE_ALREADY_CLAIMED,{message:`Cannot claim context namespace: "${n}" is already claimed by another plugin`});return s.contextClaimRecords.add(n),{write(e,t){e.context[n]=t},release(){s.contextClaimRecords.delete(n)}}}};return o.set(n,c),c}function c(e){let t=i(e),n=t.routeGetStore().lifecycleNamespace;return{addActivateGuard(e,r){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`addActivateGuard`),t.validator?.lifecycle.validateHandler(r,`addActivateGuard`);let i=n.getHandlerCount(`activate`);t.validator?.lifecycle.validateHandlerLimit(i,t.dependenciesGetStore().limits,`canActivate`),n.addCanActivate(e,r)},addDeactivateGuard(e,r){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`addDeactivateGuard`),t.validator?.lifecycle.validateHandler(r,`addDeactivateGuard`);let i=n.getHandlerCount(`deactivate`);t.validator?.lifecycle.validateHandlerLimit(i,t.dependenciesGetStore().limits,`canDeactivate`),n.addCanDeactivate(e,r)},removeActivateGuard(e){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`removeActivateGuard`),n.clearCanActivate(e)},removeDeactivateGuard(e){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`removeDeactivateGuard`),n.clearCanDeactivate(e)}}}function l(a,o){let s=i(a);if(s.isDisposed())throw new t(e.ROUTER_DISPOSED);s.validator?.dependencies.validateCloneArgs(o);let l=s.routeGetStore(),u=r(l.tree),d=l.config,f=l.resolvedForwardMap,p=l.routeCustomFields,m=s.cloneOptions(),h=s.cloneDependencies(),{definition:g,external:_}=l.lifecycleNamespace.getFactoriesByOrigin(),v=s.getPluginFactories(),y=new n(u,m,{...h,...o}),b=i(y).routeGetStore(),x=b.lifecycleNamespace,[S,C]=g,[w,T]=_;for(let[e,t]of Object.entries(S))x.addCanDeactivate(e,t,!0);for(let[e,t]of Object.entries(C))x.addCanActivate(e,t,!0);let E=c(y);for(let[e,t]of Object.entries(w))E.addDeactivateGuard(e,t);for(let[e,t]of Object.entries(T))E.addActivateGuard(e,t);return v.length>0&&y.usePlugin(...v),Object.assign(b.config.decoders,d.decoders),Object.assign(b.config.encoders,d.encoders),Object.assign(b.config.defaultParams,d.defaultParams),Object.assign(b.config.forwardMap,d.forwardMap),Object.assign(b.config.forwardFnMap,d.forwardFnMap),Object.assign(b.resolvedForwardMap,f),Object.assign(b.routeCustomFields,p),y}export{a as i,c as n,s as r,l as t};
2
- //# sourceMappingURL=cloneRouter-DM59kihh.mjs.map
1
+ import{m as e,n as t,t as n,u as r}from"./Router-pwd8YBWr.mjs";import{r as i}from"./internals-C59msvHY.mjs";function a(n){if(n())throw new t(e.ROUTER_DISPOSED)}const o=new WeakMap;function s(n){let r=o.get(n);if(r)return r;let s=i(n),c={makeState:(e,t,n,r)=>(s.validator?.state.validateMakeStateArgs(e,t,n),s.makeState(e,t,n,r?.params)),buildState:(e,t)=>{s.validator?.routes.validateStateBuilderArgs(e,t,`buildState`);let{name:n,params:r}=s.forwardState(e,t);return s.buildStateResolved(n,r)},forwardState:(e,t)=>(s.validator?.routes.validateStateBuilderArgs(e,t,`forwardState`),s.forwardState(e,t)),matchPath:e=>(s.validator?.routes.validateMatchPathArgs(e),s.matchPath(e,s.getOptions())),navigateToState:(e,t)=>(a(s.isDisposed),s.validator?.navigation.validateNavigateToStateArgs(e),t!==void 0&&s.validator?.navigation.validateNavigationOptions(t,`navigateToState`),s.navigateToState(e,t)),setRootPath:e=>{a(s.isDisposed),s.validator?.routes.validateSetRootPathArgs(e),s.setRootPath(e)},getRootPath:s.getRootPath,addEventListener:(e,t)=>(a(s.isDisposed),s.validator?.eventBus.validateListenerArgs(e,t),s.addEventListener(e,t)),buildNavigationState:(e,t={})=>{s.validator?.routes.validateStateBuilderArgs(e,t,`buildNavigationState`);let{name:n,params:r}=s.forwardState(e,t),i=s.buildStateResolved(n,r);if(i)return s.makeState(i.name,i.params,s.buildPath(i.name,i.params),i.meta)},getOptions:s.getOptions,getTree:s.getTree,addInterceptor:(e,t)=>{a(s.isDisposed),s.validator?.plugins.validateAddInterceptorArgs(e,t);let n=s.interceptors.get(e);return n||(n=[],s.interceptors.set(e,n)),n.push(t),()=>{let e=n.indexOf(t);e!==-1&&n.splice(e,1)}},getRouteConfig:e=>{let t=s.routeGetStore();if(t.matcher.hasRoute(e))return t.routeCustomFields[e]},extendRouter:r=>{a(s.isDisposed);let i=Object.keys(r);for(let r of i)if(r in n)throw new t(e.PLUGIN_CONFLICT,{message:`Cannot extend router: property "${r}" already exists`});for(let e of i)n[e]=r[e];let o={keys:i};s.routerExtensions.push(o);let c=!1;return()=>{if(c)return;c=!0;for(let e of o.keys)delete n[e];let e=s.routerExtensions.indexOf(o);e!==-1&&s.routerExtensions.splice(e,1)}},emitTransitionError:e=>{a(s.isDisposed),s.emitTransitionError(e)},claimContextNamespace:n=>{if(a(s.isDisposed),s.contextClaimRecords.has(n))throw new t(e.CONTEXT_NAMESPACE_ALREADY_CLAIMED,{message:`Cannot claim context namespace: "${n}" is already claimed by another plugin`});return s.contextClaimRecords.add(n),{write(e,t){e.context[n]=t},release(){s.contextClaimRecords.delete(n)}}}};return o.set(n,c),c}function c(e){let t=i(e),n=t.routeGetStore().lifecycleNamespace;return{addActivateGuard(e,r){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`addActivateGuard`),t.validator?.lifecycle.validateHandler(r,`addActivateGuard`);let i=n.getHandlerCount(`activate`);t.validator?.lifecycle.validateHandlerLimit(i,t.dependenciesGetStore().limits,`canActivate`),n.addCanActivate(e,r)},addDeactivateGuard(e,r){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`addDeactivateGuard`),t.validator?.lifecycle.validateHandler(r,`addDeactivateGuard`);let i=n.getHandlerCount(`deactivate`);t.validator?.lifecycle.validateHandlerLimit(i,t.dependenciesGetStore().limits,`canDeactivate`),n.addCanDeactivate(e,r)},removeActivateGuard(e){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`removeActivateGuard`),n.clearCanActivate(e)},removeDeactivateGuard(e){a(t.isDisposed),t.validator?.routes.validateRouteName(e,`removeDeactivateGuard`),n.clearCanDeactivate(e)}}}function l(a,o){let s=i(a);if(s.isDisposed())throw new t(e.ROUTER_DISPOSED);s.validator?.dependencies.validateCloneArgs(o);let l=s.routeGetStore(),u=r(l.tree),d=l.config,f=l.resolvedForwardMap,p=l.routeCustomFields,m=s.cloneOptions(),h=s.cloneDependencies(),{definition:g,external:_}=l.lifecycleNamespace.getFactoriesByOrigin(),v=s.getPluginFactories(),y=new n(u,m,{...h,...o}),b=i(y).routeGetStore(),x=b.lifecycleNamespace,[S,C]=g,[w,T]=_;for(let[e,t]of Object.entries(S))x.addCanDeactivate(e,t,!0);for(let[e,t]of Object.entries(C))x.addCanActivate(e,t,!0);let E=c(y);for(let[e,t]of Object.entries(w))E.addDeactivateGuard(e,t);for(let[e,t]of Object.entries(T))E.addActivateGuard(e,t);return v.length>0&&y.usePlugin(...v),Object.assign(b.config.decoders,d.decoders),Object.assign(b.config.encoders,d.encoders),Object.assign(b.config.defaultParams,d.defaultParams),Object.assign(b.config.forwardMap,d.forwardMap),Object.assign(b.config.forwardFnMap,d.forwardFnMap),Object.assign(b.resolvedForwardMap,f),Object.assign(b.routeCustomFields,p),y}export{a as i,c as n,s as r,l as t};
2
+ //# sourceMappingURL=cloneRouter-U8NeEoPX.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloneRouter-DM59kihh.mjs","names":["routeTreeToDefinitions","RouterClass"],"sources":["../../src/api/helpers.ts","../../src/api/getPluginApi.ts","../../src/api/getLifecycleApi.ts","../../src/api/cloneRouter.ts"],"sourcesContent":["// packages/core/src/api/helpers.ts\n\nimport { errorCodes } from \"../constants\";\nimport { RouterError } from \"../RouterError\";\n\nexport function throwIfDisposed(isDisposed: () => boolean): void {\n if (isDisposed()) {\n throw new RouterError(errorCodes.ROUTER_DISPOSED);\n }\n}\n","import { throwIfDisposed } from \"./helpers\";\nimport { errorCodes } from \"../constants\";\nimport { getInternals } from \"../internals\";\nimport { RouterError } from \"../RouterError\";\n\nimport type { PluginApi } from \"./types\";\nimport type {\n ContextNamespaceClaim,\n DefaultDependencies,\n Params,\n Router,\n State,\n} from \"@real-router/types\";\n\n// Cache the assembled PluginApi per router — mirrors getNavigator() (#525):\n// avoids re-allocating the closure-bag on each call (plugins call this once\n// at init, but tests + nested plugins poll it), and gives spy/stub helpers\n// a stable object identity to attach to (e.g. spying on\n// `getPluginApi(router).navigateToState` to inject errors in popstate\n// recovery tests).\nconst cache = new WeakMap<object, PluginApi>();\n\nexport function getPluginApi<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(router: Router<Dependencies>): PluginApi {\n const cached = cache.get(router);\n\n if (cached) {\n return cached;\n }\n\n const ctx = getInternals(router);\n const api: PluginApi = {\n makeState: (name, params, path, meta) => {\n ctx.validator?.state.validateMakeStateArgs(name, params, path);\n\n return ctx.makeState(\n name,\n params,\n path,\n meta?.params as\n | Record<string, Record<string, \"url\" | \"query\">>\n | undefined,\n );\n },\n buildState: (routeName, routeParams) => {\n ctx.validator?.routes.validateStateBuilderArgs(\n routeName,\n routeParams,\n \"buildState\",\n );\n\n const { name, params } = ctx.forwardState(routeName, routeParams);\n\n return ctx.buildStateResolved(name, params);\n },\n forwardState: <P extends Params = Params>(\n routeName: string,\n routeParams: P,\n ) => {\n ctx.validator?.routes.validateStateBuilderArgs(\n routeName,\n routeParams,\n \"forwardState\",\n );\n\n return ctx.forwardState(routeName, routeParams);\n },\n matchPath: (path) => {\n ctx.validator?.routes.validateMatchPathArgs(path);\n\n return ctx.matchPath(path, ctx.getOptions());\n },\n navigateToState: (state, options) => {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.navigation.validateNavigateToStateArgs(state);\n\n if (options !== undefined) {\n ctx.validator?.navigation.validateNavigationOptions(\n options,\n \"navigateToState\",\n );\n }\n\n return ctx.navigateToState(state, options);\n },\n setRootPath: (rootPath) => {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateSetRootPathArgs(rootPath);\n\n ctx.setRootPath(rootPath);\n },\n getRootPath: ctx.getRootPath,\n addEventListener: (eventName, cb) => {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.eventBus.validateListenerArgs(eventName, cb);\n\n return ctx.addEventListener(eventName, cb);\n },\n buildNavigationState: (name, params = {}) => {\n ctx.validator?.routes.validateStateBuilderArgs(\n name,\n params,\n \"buildNavigationState\",\n );\n\n const { name: resolvedName, params: resolvedParams } = ctx.forwardState(\n name,\n params,\n );\n const routeInfo = ctx.buildStateResolved(resolvedName, resolvedParams);\n\n if (!routeInfo) {\n return;\n }\n\n return ctx.makeState(\n routeInfo.name,\n routeInfo.params,\n ctx.buildPath(routeInfo.name, routeInfo.params),\n routeInfo.meta,\n );\n },\n getOptions: ctx.getOptions,\n getTree: ctx.getTree,\n addInterceptor: (method, fn) => {\n throwIfDisposed(ctx.isDisposed);\n ctx.validator?.plugins.validateAddInterceptorArgs(method, fn);\n let list = ctx.interceptors.get(method);\n\n if (!list) {\n list = [];\n ctx.interceptors.set(method, list);\n }\n\n list.push(fn);\n\n return () => {\n const index = list.indexOf(fn);\n\n if (index !== -1) {\n list.splice(index, 1);\n }\n };\n },\n getRouteConfig: (name) => {\n const store = ctx.routeGetStore();\n\n if (!store.matcher.hasRoute(name)) {\n return;\n }\n\n return store.routeCustomFields[name];\n },\n extendRouter: (extensions: Record<string, unknown>) => {\n throwIfDisposed(ctx.isDisposed);\n\n const keys = Object.keys(extensions);\n\n for (const key of keys) {\n if (key in router) {\n throw new RouterError(errorCodes.PLUGIN_CONFLICT, {\n message: `Cannot extend router: property \"${key}\" already exists`,\n });\n }\n }\n\n for (const key of keys) {\n (router as Record<string, unknown>)[key] = extensions[key];\n }\n\n const extensionRecord = { keys };\n\n ctx.routerExtensions.push(extensionRecord);\n\n let removed = false;\n\n return () => {\n if (removed) {\n return;\n }\n\n removed = true;\n\n for (const key of extensionRecord.keys) {\n delete (router as Record<string, unknown>)[key];\n }\n\n const idx = ctx.routerExtensions.indexOf(extensionRecord);\n\n if (idx !== -1) {\n ctx.routerExtensions.splice(idx, 1);\n }\n };\n },\n emitTransitionError: (error) => {\n throwIfDisposed(ctx.isDisposed);\n ctx.emitTransitionError(error);\n },\n claimContextNamespace: (namespace: string) => {\n throwIfDisposed(ctx.isDisposed);\n\n if (ctx.contextClaimRecords.has(namespace)) {\n throw new RouterError(errorCodes.CONTEXT_NAMESPACE_ALREADY_CLAIMED, {\n message: `Cannot claim context namespace: \"${namespace}\" is already claimed by another plugin`,\n });\n }\n\n ctx.contextClaimRecords.add(namespace);\n\n return {\n write(state: State, value: unknown) {\n state.context[namespace] = value;\n },\n release() {\n ctx.contextClaimRecords.delete(namespace);\n },\n } satisfies ContextNamespaceClaim;\n },\n };\n\n cache.set(router, api);\n\n return api;\n}\n","import { throwIfDisposed } from \"./helpers\";\nimport { getInternals } from \"../internals\";\n\nimport type { LifecycleApi } from \"./types\";\nimport type { DefaultDependencies, Router } from \"@real-router/types\";\n\nexport function getLifecycleApi<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(router: Router<Dependencies>): LifecycleApi<Dependencies> {\n const ctx = getInternals(router);\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring\n const lifecycleNamespace = ctx.routeGetStore().lifecycleNamespace!;\n\n return {\n addActivateGuard(name, handler) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"addActivateGuard\");\n ctx.validator?.lifecycle.validateHandler(handler, \"addActivateGuard\");\n\n const activateCount = lifecycleNamespace.getHandlerCount(\"activate\");\n\n ctx.validator?.lifecycle.validateHandlerLimit(\n activateCount,\n ctx.dependenciesGetStore().limits,\n \"canActivate\",\n );\n\n lifecycleNamespace.addCanActivate(name, handler);\n },\n\n addDeactivateGuard(name, handler) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"addDeactivateGuard\");\n ctx.validator?.lifecycle.validateHandler(handler, \"addDeactivateGuard\");\n\n const deactivateCount = lifecycleNamespace.getHandlerCount(\"deactivate\");\n\n ctx.validator?.lifecycle.validateHandlerLimit(\n deactivateCount,\n ctx.dependenciesGetStore().limits,\n \"canDeactivate\",\n );\n\n lifecycleNamespace.addCanDeactivate(name, handler);\n },\n\n removeActivateGuard(name) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"removeActivateGuard\");\n\n lifecycleNamespace.clearCanActivate(name);\n },\n\n removeDeactivateGuard(name) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"removeDeactivateGuard\");\n\n lifecycleNamespace.clearCanDeactivate(name);\n },\n };\n}\n","import { routeTreeToDefinitions } from \"route-tree\";\n\nimport { errorCodes } from \"../constants\";\nimport { getInternals } from \"../internals\";\nimport { Router as RouterClass } from \"../Router\";\nimport { RouterError } from \"../RouterError\";\nimport { getLifecycleApi } from \"./getLifecycleApi\";\n\nimport type { Route } from \"../types\";\nimport type { DefaultDependencies, Router } from \"@real-router/types\";\n\n/**\n * Build an independent router instance that shares the route tree, options,\n * lifecycle guards, and plugin factories of `router`. The primary use case\n * is **SSR multi-tenancy** — one base router per process, one clone per\n * request.\n *\n * @param router - Source router (must not be disposed).\n * @param dependencies - Optional per-clone overrides merged on top of the\n * base router's dependencies. Always **fresh per call** in the documented\n * SSR pattern: pass per-request state here, never store it in the base.\n *\n * @remarks\n *\n * **Dependency merge — shallow by design.** `base.dependencies` are spread\n * into the clone via `{ ...sourceDeps, ...dependencies }`. Top-level keys\n * are new objects, but **values are shared by reference**: a `Map`, `Set`,\n * class instance, function, or nested plain object stored in\n * `base.dependencies` is the **same instance** in every clone. Mutations\n * in one clone are visible in the base and in every sibling clone.\n *\n * This is intentional. `structuredClone` of dep values is **not** applied\n * because it would:\n * - strip class prototypes (`new DbClient()` → plain object, methods lost)\n * - reject functions and symbols (`DataCloneError`)\n * - fragment singleton pools (one connection pool per request — pool\n * semantics destroyed)\n * - reject circular references\n *\n * **SSR rule of thumb.** Place values in `base.dependencies` according to\n * their lifecycle:\n *\n * - **Singletons / shared services** → `base.dependencies`. Examples: DB\n * client, connection pool, logger, config, feature-flag client. Process-\n * wide pooling depends on sharing these by reference.\n * - **Per-request state** → the `dependencies` override parameter (or\n * `createRequestScope`'s `deps` argument). Examples: `currentUser`,\n * `traceId`, `sessionId`, `abortSignal`. The override is applied last,\n * so it wins over base keys; pass a fresh object per call.\n *\n * Cross-request data leaks are **only possible** when per-request mutable\n * state is incorrectly placed in `base.dependencies`. The override slot is\n * the safe channel.\n *\n * @example\n * ```typescript\n * // Server boot — singletons only\n * const base = createRouter(routes, options, {\n * db: new DbClient(dbUrl),\n * logger,\n * });\n *\n * // Per request — fresh override per call\n * const clone = cloneRouter(base, {\n * currentUser,\n * traceId,\n * });\n * // clone.deps.db === base.deps.db ✓ shared pool (intentional)\n * // clone.deps.currentUser ✓ unique per request\n * ```\n *\n * @see createRequestScope — `@real-router/core/utils` SSR helper that\n * wraps this function and injects `abortSignal` automatically.\n */\nexport function cloneRouter<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n router: Router<Dependencies>,\n dependencies?: Dependencies,\n): RouterClass<Dependencies> {\n const ctx = getInternals(router);\n\n if (ctx.isDisposed()) {\n throw new RouterError(errorCodes.ROUTER_DISPOSED);\n }\n\n ctx.validator?.dependencies.validateCloneArgs(dependencies);\n\n // Get source store directly\n const sourceStore = ctx.routeGetStore();\n const routes = routeTreeToDefinitions(sourceStore.tree);\n const routeConfig = sourceStore.config;\n const resolvedForwardMap = sourceStore.resolvedForwardMap;\n const routeCustomFields = sourceStore.routeCustomFields;\n\n const options = ctx.cloneOptions();\n const sourceDeps = ctx.cloneDependencies();\n // Origin-aware factory snapshot — definition guards are re-registered with\n // `isFromDefinition=true` on the clone so `replace()` can still strip them\n // via `clearDefinitionGuards()`. External guards take the public lifecycle\n // API path so they survive `replace()` symmetric with the base.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring\n const sourceLifecycleNamespace = sourceStore.lifecycleNamespace!;\n const { definition: definitionFactories, external: externalFactories } =\n sourceLifecycleNamespace.getFactoriesByOrigin();\n const pluginFactories = ctx.getPluginFactories();\n\n const mergedDeps = {\n ...sourceDeps,\n ...dependencies,\n } as Dependencies;\n\n const newRouter = new RouterClass<Dependencies>(\n routes as Route<Dependencies>[],\n options,\n mergedDeps,\n );\n\n const newCtx = getInternals(newRouter);\n const newStore = newCtx.routeGetStore();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring\n const newLifecycleNamespace = newStore.lifecycleNamespace!;\n\n const [definitionDeactivate, definitionActivate] = definitionFactories;\n const [externalDeactivate, externalActivate] = externalFactories;\n\n for (const [name, handler] of Object.entries(definitionDeactivate)) {\n newLifecycleNamespace.addCanDeactivate(name, handler, true);\n }\n\n for (const [name, handler] of Object.entries(definitionActivate)) {\n newLifecycleNamespace.addCanActivate(name, handler, true);\n }\n\n const lifecycle = getLifecycleApi(newRouter);\n\n for (const [name, handler] of Object.entries(externalDeactivate)) {\n lifecycle.addDeactivateGuard(name, handler);\n }\n\n for (const [name, handler] of Object.entries(externalActivate)) {\n lifecycle.addActivateGuard(name, handler);\n }\n\n if (pluginFactories.length > 0) {\n newRouter.usePlugin(...pluginFactories);\n }\n\n // Apply cloned config directly to new store\n Object.assign(newStore.config.decoders, routeConfig.decoders);\n Object.assign(newStore.config.encoders, routeConfig.encoders);\n Object.assign(newStore.config.defaultParams, routeConfig.defaultParams);\n Object.assign(newStore.config.forwardMap, routeConfig.forwardMap);\n Object.assign(newStore.config.forwardFnMap, routeConfig.forwardFnMap);\n Object.assign(newStore.resolvedForwardMap, resolvedForwardMap);\n Object.assign(newStore.routeCustomFields, routeCustomFields);\n\n return newRouter;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cloneRouter-U8NeEoPX.mjs","names":["routeTreeToDefinitions","RouterClass"],"sources":["../../src/api/helpers.ts","../../src/api/getPluginApi.ts","../../src/api/getLifecycleApi.ts","../../src/api/cloneRouter.ts"],"sourcesContent":["// packages/core/src/api/helpers.ts\n\nimport { errorCodes } from \"../constants\";\nimport { RouterError } from \"../RouterError\";\n\nexport function throwIfDisposed(isDisposed: () => boolean): void {\n if (isDisposed()) {\n throw new RouterError(errorCodes.ROUTER_DISPOSED);\n }\n}\n","import { throwIfDisposed } from \"./helpers\";\nimport { errorCodes } from \"../constants\";\nimport { getInternals } from \"../internals\";\nimport { RouterError } from \"../RouterError\";\n\nimport type { PluginApi } from \"./types\";\nimport type {\n ContextNamespaceClaim,\n DefaultDependencies,\n Params,\n Router,\n State,\n} from \"@real-router/types\";\n\n// Cache the assembled PluginApi per router — mirrors getNavigator() (#525):\n// avoids re-allocating the closure-bag on each call (plugins call this once\n// at init, but tests + nested plugins poll it), and gives spy/stub helpers\n// a stable object identity to attach to (e.g. spying on\n// `getPluginApi(router).navigateToState` to inject errors in popstate\n// recovery tests).\nconst cache = new WeakMap<object, PluginApi>();\n\nexport function getPluginApi<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(router: Router<Dependencies>): PluginApi {\n const cached = cache.get(router);\n\n if (cached) {\n return cached;\n }\n\n const ctx = getInternals(router);\n const api: PluginApi = {\n makeState: (name, params, path, meta) => {\n ctx.validator?.state.validateMakeStateArgs(name, params, path);\n\n return ctx.makeState(\n name,\n params,\n path,\n meta?.params as\n | Record<string, Record<string, \"url\" | \"query\">>\n | undefined,\n );\n },\n buildState: (routeName, routeParams) => {\n ctx.validator?.routes.validateStateBuilderArgs(\n routeName,\n routeParams,\n \"buildState\",\n );\n\n const { name, params } = ctx.forwardState(routeName, routeParams);\n\n return ctx.buildStateResolved(name, params);\n },\n forwardState: <P extends Params = Params>(\n routeName: string,\n routeParams: P,\n ) => {\n ctx.validator?.routes.validateStateBuilderArgs(\n routeName,\n routeParams,\n \"forwardState\",\n );\n\n return ctx.forwardState(routeName, routeParams);\n },\n matchPath: (path) => {\n ctx.validator?.routes.validateMatchPathArgs(path);\n\n return ctx.matchPath(path, ctx.getOptions());\n },\n navigateToState: (state, options) => {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.navigation.validateNavigateToStateArgs(state);\n\n if (options !== undefined) {\n ctx.validator?.navigation.validateNavigationOptions(\n options,\n \"navigateToState\",\n );\n }\n\n return ctx.navigateToState(state, options);\n },\n setRootPath: (rootPath) => {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateSetRootPathArgs(rootPath);\n\n ctx.setRootPath(rootPath);\n },\n getRootPath: ctx.getRootPath,\n addEventListener: (eventName, cb) => {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.eventBus.validateListenerArgs(eventName, cb);\n\n return ctx.addEventListener(eventName, cb);\n },\n buildNavigationState: (name, params = {}) => {\n ctx.validator?.routes.validateStateBuilderArgs(\n name,\n params,\n \"buildNavigationState\",\n );\n\n const { name: resolvedName, params: resolvedParams } = ctx.forwardState(\n name,\n params,\n );\n const routeInfo = ctx.buildStateResolved(resolvedName, resolvedParams);\n\n if (!routeInfo) {\n return;\n }\n\n return ctx.makeState(\n routeInfo.name,\n routeInfo.params,\n ctx.buildPath(routeInfo.name, routeInfo.params),\n routeInfo.meta,\n );\n },\n getOptions: ctx.getOptions,\n getTree: ctx.getTree,\n addInterceptor: (method, fn) => {\n throwIfDisposed(ctx.isDisposed);\n ctx.validator?.plugins.validateAddInterceptorArgs(method, fn);\n let list = ctx.interceptors.get(method);\n\n if (!list) {\n list = [];\n ctx.interceptors.set(method, list);\n }\n\n list.push(fn);\n\n return () => {\n const index = list.indexOf(fn);\n\n if (index !== -1) {\n list.splice(index, 1);\n }\n };\n },\n getRouteConfig: (name) => {\n const store = ctx.routeGetStore();\n\n if (!store.matcher.hasRoute(name)) {\n return;\n }\n\n return store.routeCustomFields[name];\n },\n extendRouter: (extensions: Record<string, unknown>) => {\n throwIfDisposed(ctx.isDisposed);\n\n const keys = Object.keys(extensions);\n\n for (const key of keys) {\n if (key in router) {\n throw new RouterError(errorCodes.PLUGIN_CONFLICT, {\n message: `Cannot extend router: property \"${key}\" already exists`,\n });\n }\n }\n\n for (const key of keys) {\n (router as Record<string, unknown>)[key] = extensions[key];\n }\n\n const extensionRecord = { keys };\n\n ctx.routerExtensions.push(extensionRecord);\n\n let removed = false;\n\n return () => {\n if (removed) {\n return;\n }\n\n removed = true;\n\n for (const key of extensionRecord.keys) {\n delete (router as Record<string, unknown>)[key];\n }\n\n const idx = ctx.routerExtensions.indexOf(extensionRecord);\n\n if (idx !== -1) {\n ctx.routerExtensions.splice(idx, 1);\n }\n };\n },\n emitTransitionError: (error) => {\n throwIfDisposed(ctx.isDisposed);\n ctx.emitTransitionError(error);\n },\n claimContextNamespace: (namespace: string) => {\n throwIfDisposed(ctx.isDisposed);\n\n if (ctx.contextClaimRecords.has(namespace)) {\n throw new RouterError(errorCodes.CONTEXT_NAMESPACE_ALREADY_CLAIMED, {\n message: `Cannot claim context namespace: \"${namespace}\" is already claimed by another plugin`,\n });\n }\n\n ctx.contextClaimRecords.add(namespace);\n\n return {\n write(state: State, value: unknown) {\n state.context[namespace] = value;\n },\n release() {\n ctx.contextClaimRecords.delete(namespace);\n },\n } satisfies ContextNamespaceClaim;\n },\n };\n\n cache.set(router, api);\n\n return api;\n}\n","import { throwIfDisposed } from \"./helpers\";\nimport { getInternals } from \"../internals\";\n\nimport type { LifecycleApi } from \"./types\";\nimport type { DefaultDependencies, Router } from \"@real-router/types\";\n\nexport function getLifecycleApi<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(router: Router<Dependencies>): LifecycleApi<Dependencies> {\n const ctx = getInternals(router);\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring\n const lifecycleNamespace = ctx.routeGetStore().lifecycleNamespace!;\n\n return {\n addActivateGuard(name, handler) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"addActivateGuard\");\n ctx.validator?.lifecycle.validateHandler(handler, \"addActivateGuard\");\n\n const activateCount = lifecycleNamespace.getHandlerCount(\"activate\");\n\n ctx.validator?.lifecycle.validateHandlerLimit(\n activateCount,\n ctx.dependenciesGetStore().limits,\n \"canActivate\",\n );\n\n lifecycleNamespace.addCanActivate(name, handler);\n },\n\n addDeactivateGuard(name, handler) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"addDeactivateGuard\");\n ctx.validator?.lifecycle.validateHandler(handler, \"addDeactivateGuard\");\n\n const deactivateCount = lifecycleNamespace.getHandlerCount(\"deactivate\");\n\n ctx.validator?.lifecycle.validateHandlerLimit(\n deactivateCount,\n ctx.dependenciesGetStore().limits,\n \"canDeactivate\",\n );\n\n lifecycleNamespace.addCanDeactivate(name, handler);\n },\n\n removeActivateGuard(name) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"removeActivateGuard\");\n\n lifecycleNamespace.clearCanActivate(name);\n },\n\n removeDeactivateGuard(name) {\n throwIfDisposed(ctx.isDisposed);\n\n ctx.validator?.routes.validateRouteName(name, \"removeDeactivateGuard\");\n\n lifecycleNamespace.clearCanDeactivate(name);\n },\n };\n}\n","import { routeTreeToDefinitions } from \"route-tree\";\n\nimport { errorCodes } from \"../constants\";\nimport { getInternals } from \"../internals\";\nimport { Router as RouterClass } from \"../Router\";\nimport { RouterError } from \"../RouterError\";\nimport { getLifecycleApi } from \"./getLifecycleApi\";\n\nimport type { Route } from \"../types\";\nimport type { DefaultDependencies, Router } from \"@real-router/types\";\n\n/**\n * Build an independent router instance that shares the route tree, options,\n * lifecycle guards, and plugin factories of `router`. The primary use case\n * is **SSR multi-tenancy** — one base router per process, one clone per\n * request.\n *\n * @param router - Source router (must not be disposed).\n * @param dependencies - Optional per-clone overrides merged on top of the\n * base router's dependencies. Always **fresh per call** in the documented\n * SSR pattern: pass per-request state here, never store it in the base.\n *\n * @remarks\n *\n * **Dependency merge — shallow by design.** `base.dependencies` are spread\n * into the clone via `{ ...sourceDeps, ...dependencies }`. Top-level keys\n * are new objects, but **values are shared by reference**: a `Map`, `Set`,\n * class instance, function, or nested plain object stored in\n * `base.dependencies` is the **same instance** in every clone. Mutations\n * in one clone are visible in the base and in every sibling clone.\n *\n * This is intentional. `structuredClone` of dep values is **not** applied\n * because it would:\n * - strip class prototypes (`new DbClient()` → plain object, methods lost)\n * - reject functions and symbols (`DataCloneError`)\n * - fragment singleton pools (one connection pool per request — pool\n * semantics destroyed)\n * - reject circular references\n *\n * **SSR rule of thumb.** Place values in `base.dependencies` according to\n * their lifecycle:\n *\n * - **Singletons / shared services** → `base.dependencies`. Examples: DB\n * client, connection pool, logger, config, feature-flag client. Process-\n * wide pooling depends on sharing these by reference.\n * - **Per-request state** → the `dependencies` override parameter (or\n * `createRequestScope`'s `deps` argument). Examples: `currentUser`,\n * `traceId`, `sessionId`, `abortSignal`. The override is applied last,\n * so it wins over base keys; pass a fresh object per call.\n *\n * Cross-request data leaks are **only possible** when per-request mutable\n * state is incorrectly placed in `base.dependencies`. The override slot is\n * the safe channel.\n *\n * @example\n * ```typescript\n * // Server boot — singletons only\n * const base = createRouter(routes, options, {\n * db: new DbClient(dbUrl),\n * logger,\n * });\n *\n * // Per request — fresh override per call\n * const clone = cloneRouter(base, {\n * currentUser,\n * traceId,\n * });\n * // clone.deps.db === base.deps.db ✓ shared pool (intentional)\n * // clone.deps.currentUser ✓ unique per request\n * ```\n *\n * @see createRequestScope — `@real-router/core/utils` SSR helper that\n * wraps this function and injects `abortSignal` automatically.\n */\nexport function cloneRouter<\n Dependencies extends DefaultDependencies = DefaultDependencies,\n>(\n router: Router<Dependencies>,\n dependencies?: Dependencies,\n): RouterClass<Dependencies> {\n const ctx = getInternals(router);\n\n if (ctx.isDisposed()) {\n throw new RouterError(errorCodes.ROUTER_DISPOSED);\n }\n\n ctx.validator?.dependencies.validateCloneArgs(dependencies);\n\n // Get source store directly\n const sourceStore = ctx.routeGetStore();\n const routes = routeTreeToDefinitions(sourceStore.tree);\n const routeConfig = sourceStore.config;\n const resolvedForwardMap = sourceStore.resolvedForwardMap;\n const routeCustomFields = sourceStore.routeCustomFields;\n\n const options = ctx.cloneOptions();\n const sourceDeps = ctx.cloneDependencies();\n // Origin-aware factory snapshot — definition guards are re-registered with\n // `isFromDefinition=true` on the clone so `replace()` can still strip them\n // via `clearDefinitionGuards()`. External guards take the public lifecycle\n // API path so they survive `replace()` symmetric with the base.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring\n const sourceLifecycleNamespace = sourceStore.lifecycleNamespace!;\n const { definition: definitionFactories, external: externalFactories } =\n sourceLifecycleNamespace.getFactoriesByOrigin();\n const pluginFactories = ctx.getPluginFactories();\n\n const mergedDeps = {\n ...sourceDeps,\n ...dependencies,\n } as Dependencies;\n\n const newRouter = new RouterClass<Dependencies>(\n routes as Route<Dependencies>[],\n options,\n mergedDeps,\n );\n\n const newCtx = getInternals(newRouter);\n const newStore = newCtx.routeGetStore();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring\n const newLifecycleNamespace = newStore.lifecycleNamespace!;\n\n const [definitionDeactivate, definitionActivate] = definitionFactories;\n const [externalDeactivate, externalActivate] = externalFactories;\n\n for (const [name, handler] of Object.entries(definitionDeactivate)) {\n newLifecycleNamespace.addCanDeactivate(name, handler, true);\n }\n\n for (const [name, handler] of Object.entries(definitionActivate)) {\n newLifecycleNamespace.addCanActivate(name, handler, true);\n }\n\n const lifecycle = getLifecycleApi(newRouter);\n\n for (const [name, handler] of Object.entries(externalDeactivate)) {\n lifecycle.addDeactivateGuard(name, handler);\n }\n\n for (const [name, handler] of Object.entries(externalActivate)) {\n lifecycle.addActivateGuard(name, handler);\n }\n\n if (pluginFactories.length > 0) {\n newRouter.usePlugin(...pluginFactories);\n }\n\n // Apply cloned config directly to new store\n Object.assign(newStore.config.decoders, routeConfig.decoders);\n Object.assign(newStore.config.encoders, routeConfig.encoders);\n Object.assign(newStore.config.defaultParams, routeConfig.defaultParams);\n Object.assign(newStore.config.forwardMap, routeConfig.forwardMap);\n Object.assign(newStore.config.forwardFnMap, routeConfig.forwardFnMap);\n Object.assign(newStore.resolvedForwardMap, resolvedForwardMap);\n Object.assign(newStore.routeCustomFields, routeCustomFields);\n\n return newRouter;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{f as e,h as t,m as n,n as r,o as i,p as a,t as o}from"./Router-_BDnheMY.mjs";const s=(e=[],t={},n={})=>new o(e,t,n),c=new WeakMap,l=e=>{let t=c.get(e);return t||(t=Object.freeze({navigate:e.navigate,getState:e.getState,isActiveRoute:e.isActiveRoute,canNavigateTo:e.canNavigateTo,subscribe:e.subscribe,subscribeLeave:e.subscribeLeave,isLeaveApproved:e.isLeaveApproved}),c.set(e,t)),t};export{o as Router,r as RouterError,e as UNKNOWN_ROUTE,a as constants,s as createRouter,n as errorCodes,t as events,l as getNavigator,i as resolveForwardChain};
1
+ import{f as e,h as t,m as n,n as r,o as i,p as a,t as o}from"./Router-pwd8YBWr.mjs";const s=(e=[],t={},n={})=>new o(e,t,n),c=new WeakMap,l=e=>{let t=c.get(e);return t||(t=Object.freeze({navigate:e.navigate,getState:e.getState,isActiveRoute:e.isActiveRoute,canNavigateTo:e.canNavigateTo,subscribe:e.subscribe,subscribeLeave:e.subscribeLeave,isLeaveApproved:e.isLeaveApproved}),c.set(e,t)),t};export{o as Router,r as RouterError,e as UNKNOWN_ROUTE,a as constants,s as createRouter,n as errorCodes,t as events,l as getNavigator,i as resolveForwardChain};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,2 +1,2 @@
1
- import{r as e}from"./internals-C59msvHY.mjs";import{r as t,t as n}from"./cloneRouter-DM59kihh.mjs";function r(e){return`signal`in e&&typeof e.signal==`object`&&e.signal!==void 0&&typeof e.signal.aborted==`boolean`}function i(e,t,i){let a,o;if(r(e))o=e.signal;else{let t=new AbortController,n=()=>{t.abort()};e.on(`close`,n),o=t.signal,a=()=>{e.removeListener?.(`close`,n)}}let s=n(t,{...i,abortSignal:o}),c=!1,l=()=>c?Promise.resolve():(c=!0,a?.(),s.dispose(),Promise.resolve());return{router:s,signal:o,dispose:l,[Symbol.asyncDispose]:l}}function a(e){let t=[];for(let n of e.children.values())n.children.size===0?t.push(n.fullName):t.push(...a(n));return t}async function o(e,n){let r=a(t(e).getTree()),i=[];for(let t of r){let r=n?.[t];if(r){let n=await r();for(let r of n)i.push(e.buildPath(t,r))}else i.push(e.buildPath(t,{}))}return i}async function s(t,n,r){let i=r?.deserialize??JSON.parse,a=typeof n==`string`?i(n):n,o=e(t),s=o.hydrationState;o.hydrationState=a;try{return await t.start(a.path)}finally{o.hydrationState=s}}function c(e,t){return((t?.serialize??JSON.stringify)(e)??`null`).replaceAll(`<`,String.raw`\u003c`).replaceAll(`>`,String.raw`\u003e`).replaceAll(`&`,String.raw`\u0026`)}function l(e,t){let n=t?.excludeContext,r=e.context;if(n?.length){let t={},i=e.context;for(let e of Object.keys(i))n.includes(e)||(t[e]=i[e]);r=t}let i={name:e.name,params:e.params,path:e.path,context:r};return t?.serialize?c(i,{serialize:t.serialize}):c(i)}export{i as createRequestScope,o as getStaticPaths,s as hydrateRouter,l as serializeRouterState,c as serializeState};
1
+ import{r as e}from"./internals-C59msvHY.mjs";import{r as t,t as n}from"./cloneRouter-U8NeEoPX.mjs";function r(e){return`signal`in e&&typeof e.signal==`object`&&e.signal!==void 0&&typeof e.signal.aborted==`boolean`}function i(e,t,i){let a,o;if(r(e))o=e.signal;else{let t=new AbortController,n=()=>{t.abort()};e.on(`close`,n),o=t.signal,a=()=>{e.removeListener?.(`close`,n)}}let s=n(t,{...i,abortSignal:o}),c=!1,l=()=>c?Promise.resolve():(c=!0,a?.(),s.dispose(),Promise.resolve());return{router:s,signal:o,dispose:l,[Symbol.asyncDispose]:l}}function a(e){let t=[];for(let n of e.children.values())n.children.size===0?t.push(n.fullName):t.push(...a(n));return t}async function o(e,n){let r=a(t(e).getTree()),i=[];for(let t of r){let r=n?.[t];if(r){let n=await r();for(let r of n)i.push(e.buildPath(t,r))}else i.push(e.buildPath(t,{}))}return i}async function s(t,n,r){let i=r?.deserialize??JSON.parse,a=typeof n==`string`?i(n):n,o=e(t),s=o.hydrationState;o.hydrationState=a;try{return await t.start(a.path)}finally{o.hydrationState=s}}function c(e,t){return((t?.serialize??JSON.stringify)(e)??`null`).replaceAll(`<`,String.raw`\u003c`).replaceAll(`>`,String.raw`\u003e`).replaceAll(`&`,String.raw`\u0026`)}function l(e,t){let n=t?.excludeContext,r=e.context;if(n?.length){let t={},i=e.context;for(let e of Object.keys(i))n.includes(e)||(t[e]=i[e]);r=t}let i={name:e.name,params:e.params,path:e.path,context:r};return t?.serialize?c(i,{serialize:t.serialize}):c(i)}export{i as createRequestScope,o as getStaticPaths,s as hydrateRouter,l as serializeRouterState,c as serializeState};
2
2
  //# sourceMappingURL=utils.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/core",
3
- "version": "0.54.5",
3
+ "version": "0.54.6",
4
4
  "type": "commonjs",
5
5
  "description": "A simple, powerful, view-agnostic, modular and extensible router",
6
6
  "main": "./dist/cjs/index.js",
@@ -87,13 +87,13 @@
87
87
  "homepage": "https://github.com/greydragon888/real-router",
88
88
  "sideEffects": false,
89
89
  "dependencies": {
90
+ "@real-router/fsm": "^0.4.0",
90
91
  "@real-router/logger": "^0.3.0",
91
- "@real-router/types": "^0.35.0",
92
- "@real-router/fsm": "^0.4.0"
92
+ "@real-router/types": "^0.35.0"
93
93
  },
94
94
  "devDependencies": {
95
- "event-emitter": "^0.1.2",
96
- "route-tree": "^0.3.4"
95
+ "route-tree": "^0.3.4",
96
+ "event-emitter": "^0.1.2"
97
97
  },
98
98
  "scripts": {
99
99
  "test": "vitest run functional/",
@@ -264,6 +264,19 @@ export class EventBusNamespace {
264
264
  return this.#currentToState;
265
265
  }
266
266
 
267
+ /**
268
+ * Plugin-author API for subscribing to internal router events.
269
+ *
270
+ * @remarks
271
+ *
272
+ * **Duplicate-registration semantics — strict (throws).** Passing the same
273
+ * callback reference twice for the same event throws
274
+ * `Error("Duplicate listener for ...")` from the underlying `EventEmitter`.
275
+ * This is loud-on-misuse by design: plugin code is expected to register
276
+ * each callback once. The contract differs from {@link subscribe} /
277
+ * {@link subscribeLeave}, which are end-user surfaces and silently accept
278
+ * duplicates.
279
+ */
267
280
  addEventListener<E extends EventName>(
268
281
  eventName: E,
269
282
  cb: Plugin[EventMethodMap[E]],
@@ -274,6 +287,22 @@ export class EventBusNamespace {
274
287
  );
275
288
  }
276
289
 
290
+ /**
291
+ * End-user / UI-binding API for subscribing to successful transitions.
292
+ *
293
+ * @remarks
294
+ *
295
+ * **Duplicate-registration semantics — independent.** Each call wraps
296
+ * `listener` in a fresh closure and registers it as a distinct internal
297
+ * slot. `router.subscribe(fn)` twice produces **two** active subscriptions;
298
+ * `fn` fires twice per `TRANSITION_SUCCESS`. The returned `Unsubscribe` is
299
+ * paired with its specific call — invoking it removes exactly that
300
+ * registration.
301
+ *
302
+ * This contract differs from {@link addEventListener} (plugin API, throws
303
+ * on duplicate). End-user code that wants idempotent registration must
304
+ * gate itself, e.g. `if (!unsub) unsub = router.subscribe(fn);`.
305
+ */
277
306
  subscribe(listener: SubscribeFn): Unsubscribe {
278
307
  return this.#emitter.on(
279
308
  events.TRANSITION_SUCCESS,
@@ -283,6 +312,31 @@ export class EventBusNamespace {
283
312
  );
284
313
  }
285
314
 
315
+ /**
316
+ * End-user / UI-binding API for subscribing to confirmed route departures
317
+ * (`LEAVE_APPROVED` phase). Async listeners block the activation phase.
318
+ *
319
+ * @remarks
320
+ *
321
+ * **Duplicate-registration semantics — independent (with internal quirk).**
322
+ * Each call pushes `listener` onto the internal array; `router.subscribeLeave(fn)`
323
+ * twice produces two array entries. `fn` fires **once** per leave when
324
+ * iteration snapshots the array (a snapshot is taken on entry to
325
+ * `awaitLeaveListeners`), but the function reference is invoked once per
326
+ * array slot — so in practice the wrapper fires twice through the same
327
+ * closure (no observable difference for stateless `fn`).
328
+ *
329
+ * The returned `Unsubscribe` removes the **first** array entry matching the
330
+ * function reference (`indexOf` semantic), not the most recently added one.
331
+ * Net effect of N subscribes + M unsubscribes is correct (N - M entries
332
+ * remain), but the specific physical entry that survives is reverse of the
333
+ * unsubscribe-call order. Irrelevant in practice — the function reference
334
+ * is the same; observable behaviour is identical regardless of which
335
+ * physical entry is removed.
336
+ *
337
+ * Contract differs from {@link addEventListener} (throws on duplicate).
338
+ * For idempotent registration, gate at the call site.
339
+ */
286
340
  subscribeLeave(listener: LeaveFn): Unsubscribe {
287
341
  this.#leaveListeners.push(listener);
288
342
 
@@ -308,16 +362,27 @@ export class EventBusNamespace {
308
362
  return undefined;
309
363
  }
310
364
 
311
- const leaveState: LeaveState = {
365
+ // Freeze the payload wrapper so listeners cannot mutate it (`payload.route`
366
+ // is already deep-frozen via the State immutability invariant; this closes
367
+ // the wrapper-mutation gap surfaced by audit `probe-05-payload-frozen`).
368
+ const leaveState: LeaveState = Object.freeze({
312
369
  route: fromState,
313
370
  nextRoute: toState,
314
371
  signal,
315
- };
372
+ });
316
373
 
317
374
  let promises: Promise<void>[] | undefined;
318
375
  let firstSyncError: unknown;
319
376
 
320
- for (const listener of this.#leaveListeners) {
377
+ // Snapshot before iteration — a listener that reentrantly calls
378
+ // `subscribeLeave(newFn)` or its own `unsubscribe()` must not affect the
379
+ // current emit cycle. Symmetric with the EventEmitter snapshot invariant
380
+ // (PR #666 / #659). Use `Array.from` rather than `[...array]` to keep the
381
+ // intent explicit (some lint rules treat spread-of-own-array as
382
+ // redundant and silently revert it).
383
+ const snapshot = [...this.#leaveListeners];
384
+
385
+ for (const listener of snapshot) {
321
386
  try {
322
387
  const result = listener(leaveState);
323
388