vue-router-citadel 0.2.0 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
6
6
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.1] - 2026-03-09
11
+
12
+ ### Fixed
13
+
14
+ - Resolved 38 ESLint `@typescript-eslint/no-non-null-assertion` warnings in
15
+ `src/navigationOutposts.ts` and `__tests__/devtools-inspector.test.ts`
16
+
8
17
  ## [0.2.0] - 2026-03-01
9
18
 
10
19
  ### Added
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var devtoolsApi=require('@vue/devtools-api');var Yt=Object.defineProperty;var h=(t,o)=>()=>(t&&(o=t(t=0)),o);var Xt=(t,o)=>{for(var e in o)Yt(t,e,{get:o[e],enumerable:true});};exports.NavigationHooks=void 0;exports.NavigationOutpostVerdicts=void 0;exports.NavigationOutpostScopes=void 0;exports.DebugPoints=void 0;var G=h(()=>{exports.NavigationHooks={BEFORE_EACH:"beforeEach",BEFORE_RESOLVE:"beforeResolve",AFTER_EACH:"afterEach"},exports.NavigationOutpostVerdicts={ALLOW:"allow",BLOCK:"block"},exports.NavigationOutpostScopes={GLOBAL:"global",ROUTE:"route"},exports.DebugPoints={NAVIGATION_START:"navigation-start",OUTPOST_ENTER:"outpost-enter",OUTPOST_BLOCK:"outpost-block",OUTPOST_TIMEOUT:"outpost-timeout",ERROR_CATCH:"error-catch",DEVTOOLS_INIT:"devtools-init",DEVTOOLS_INSPECT:"devtools-inspect"};});var H,x,P,k=h(()=>{H=typeof undefined<"u"?!!undefined.DEV:globalThis.process?.env?.NODE_ENV!=="production",x="[\u{1F3F0} NavigationCitadel]",P=100;});exports.createDefaultLogger=void 0;exports.createDefaultDebugHandler=void 0;var E,$=h(()=>{k();exports.createDefaultLogger=()=>({info:(...t)=>console.info(`\u{1F535} ${x}`,...t),warn:(...t)=>console.log(`\u{1F7E1} ${x}`,...t),error:(...t)=>console.error(`\u{1F534} ${x}`,...t),debug:(...t)=>console.log(`\u{1F7E3} ${x} [DEBUG]`,...t)}),exports.createDefaultDebugHandler=()=>()=>{debugger},E=(t,o,e,n)=>{o&&(e.debug(t),n?.(t));};});var tt,F,Nt,Rt,w,Lt,bt,Et,Tt,yt,St,ot,_t,z,M,Ct,Dt,et,nt,K=h(()=>{G();tt="navigation.citadel",F="Navigation Citadel",Nt="castle",Rt="https://kassaila.github.io/vue-router-citadel/logo_devtools.svg",w=tt+".inspector",Lt="citadel-root",bt="citadel-"+exports.NavigationOutpostScopes.GLOBAL,Et="citadel-"+exports.NavigationOutpostScopes.ROUTE,Tt="citadel-route-assignments",yt="citadel-current-route",St=16777215,ot=4372867,_t=3900150,z=9133302,M=16096779,Ct=15485081,Dt=1357990,et="vue-router-citadel:settings:",nt="logLevel";});var _,Zt,qt,Y,ht,It,xt,At,Qt,to,oo,eo,no,ao,io,ro,Gt,at,Pt=h(()=>{G();k();$();K();_=(t,o)=>({label:t,textColor:St,backgroundColor:o}),Zt=t=>t===exports.NavigationOutpostScopes.GLOBAL?z:M,qt=(t,o,e,n,a)=>(e.lazy&&a.push(_("lazy",Ct)),{id:`${t}-${n}-${o}`,label:o,tags:a}),Y=(t,o,e,n,a)=>{let s=[];for(let i of t){let u=o.get(i);u&&s.push(qt(n,i,u,e,a(u)));}return s},ht=t=>{let o=t.hooks??[exports.NavigationHooks.BEFORE_EACH],e=t.priority??P;return [_(`priority: ${e}`,ot),_(o.length===1?o[0]:`${o.length} hooks`,_t)]},It=t=>o=>{let e=o.priority??P;return [_(t,Zt(t)),_(`priority: ${e}`,ot)]},xt=t=>t.name?String(t.name):t.path,At=(t,o)=>{if(!t.name&&!t.path)return t.meta.outposts??[];try{return (t.name?o.resolve({name:t.name}):o.resolve(t.path)).matched.flatMap(n=>n.meta?.outposts??[])}catch{return t.meta.outposts??[]}},Qt=t=>{let o=[];for(let e of t.getRoutes()){let n=At(e,t);if(n.length===0)continue;let a=e.meta.outposts??[],s=n.filter(u=>!a.includes(u)).length,i=[_(`${n.length} outpost${n.length===1?"":"s"}`,M)];s>0&&i.push(_(`${s} inherited`,z)),o.push({id:`route-assignment-${xt(e)}`,label:xt(e),tags:i});}return {id:Tt,label:`Route Assignments (${o.length})`,children:o}},to=(t,o)=>{let e=o.currentRoute.value,n=Y(t.globalSorted,t.global,exports.NavigationOutpostScopes.GLOBAL,"current-route-outpost",It(exports.NavigationOutpostScopes.GLOBAL)),a=new Set(e.matched.flatMap(u=>u.meta?.outposts??[])),s=Y(t.routeSorted.filter(u=>a.has(u)),t.route,exports.NavigationOutpostScopes.ROUTE,"current-route-outpost",It(exports.NavigationOutpostScopes.ROUTE)),i=[...n,...s];return {id:yt,label:`Current Route: ${e.path} (${i.length})`,tags:[_("active",Dt)],children:i}},oo=(t,o)=>{let e=Y(t.globalSorted,t.global,exports.NavigationOutpostScopes.GLOBAL,"outpost",ht),n=Y(t.routeSorted,t.route,exports.NavigationOutpostScopes.ROUTE,"outpost",ht),a=[{id:Lt,label:"Outposts",children:[{id:bt,label:`Global (${e.length})`,tags:[_(exports.NavigationOutpostScopes.GLOBAL,z)],children:e},{id:Et,label:`Route (${n.length})`,tags:[_(exports.NavigationOutpostScopes.ROUTE,M)],children:n}]}];return o&&(a.push(Qt(o)),a.push(to(t,o))),a},eo=(t,o,e)=>({"Outpost Details":[{key:"name",value:t},{key:"scope",value:o},{key:"priority",value:e.priority??P},{key:"hooks",value:e.hooks??[exports.NavigationHooks.BEFORE_EACH]},{key:"timeout",value:e.timeout??"none (uses default)"},{key:"lazy",value:e.lazy}]}),no=/^route-assignment-(.+)$/,ao=new RegExp(`^(?:outpost|current-route-outpost)-(${exports.NavigationOutpostScopes.GLOBAL}|${exports.NavigationOutpostScopes.ROUTE})-(.+)$`),io=(t,o)=>{let e=At(t,o),n=t.meta.outposts??[],a=e.filter(s=>!n.includes(s));return {"Route Details":[{key:"name",value:t.name?String(t.name):"unnamed"},{key:"path",value:t.path},{key:"outposts (own)",value:n},...a.length>0?[{key:"outposts (inherited)",value:a}]:[],{key:"outposts (resolved)",value:e}]}},ro=(t,o,e)=>{let n=t.match(ao);if(n){let[,a,s]=n,u=(a===exports.NavigationOutpostScopes.GLOBAL?o.global:o.route).get(s);return u?eo(s,a,u):null}if(e){let a=t.match(no);if(a){let s=a[1],i=e.getRoutes().find(u=>u.name?String(u.name)===s:u.path===s);return i?io(i,e):null}}return null},Gt=(t,o,e,n,a=false,s)=>{t.addInspector({id:w,label:F,icon:Nt}),t.on.getInspectorTree(i=>{i.inspectorId===w&&(i.rootNodes=oo(o,e));}),t.on.getInspectorState(i=>{if(i.inspectorId!==w)return;let u=ro(i.nodeId,o,e);u&&(i.state=u);}),e.afterEach(()=>{at(t);}),E(exports.DebugPoints.DEVTOOLS_INSPECT,a,n,s);},at=t=>{t.sendInspectorTree(w),t.sendInspectorState(w);};});var N,kt=h(()=>{N={OFF:"off",LOG:"log",DEBUG:"debug"};});var so,uo,po,it,lo,wt,Ht,$t,Bt=h(()=>{kt();K();so=()=>{if(typeof window>"u"||!window.localStorage)return null;try{let t=localStorage.getItem(et+nt);return t===null?null:t===N.OFF||t===N.LOG||t===N.DEBUG?t:null}catch{return null}},uo=t=>{if(!(typeof window>"u"||!window.localStorage))try{localStorage.setItem(et+nt,t);}catch{}},po=(t,o,e)=>o?N.DEBUG:t??e?N.LOG:N.OFF,it=t=>{switch(t){case N.OFF:return {log:false,debug:false};case N.LOG:return {log:true,debug:false};case N.DEBUG:return {log:true,debug:true}}},lo=t=>t.debug?N.DEBUG:t.log?N.LOG:N.OFF,wt=(t,o,e)=>{let n=so();if(n!==null)return it(n);let a=po(t,o,e);return it(a)},Ht=(t,o)=>{let e=it(o);t.log=e.log,t.debug=e.debug,uo(o);},$t=t=>({logLevel:{label:"Log level",type:"choice",defaultValue:lo(t),options:[{label:"Off",value:N.OFF},{label:"Log",value:N.LOG},{label:"Log + Debug",value:N.DEBUG}],component:"button-group"}});});var Ut={};Xt(Ut,{clearDevtoolsApi:()=>fo,notifyDevtoolsRefresh:()=>Oo,setupDevtools:()=>co});var X,co,Oo,fo,Vt=h(()=>{k();K();Pt();Bt();X=null,co=(t,o,e,n,a,s,i,u)=>{let c=wt(s,i,H);a.log=c.log,a.debug=c.debug,devtoolsApi.setupDevToolsPlugin({id:tt,label:F,logo:Rt,packageName:"vue-router-citadel",homepage:"https://kassaila.github.io/vue-router-citadel",enableEarlyProxy:true,app:t,settings:$t(a)},g=>{X=g,g.on.setPluginSettings(v=>{v.key==="logLevel"&&Ht(a,v.newValue);}),Gt(g,o,e,n,a.debug,u);});},Oo=()=>{X&&at(X);},fo=()=>{X=null;};});G();$();G();k();$();var lt=()=>({global:new Map,route:new Map,globalSorted:[],routeSorted:[]}),gt=(t,o,e)=>{let n=t[o],a=`${o}Sorted`;t[a]=Array.from(n.keys()).sort((s,i)=>{let u=n.get(s)?.priority??e,c=n.get(i)?.priority??e;return u-c});},ct=(t,o,e,n,a)=>{t[o].has(e.name)&&a.warn(`${o} outpost "${e.name}" already exists, replacing...`),t[o].set(e.name,e),gt(t,o,n);},dt=(t,o,e,n)=>{let a=t[o].delete(e);return a&&gt(t,o,n),a},Ot=(t,o)=>Array.from(t[o].keys());G();k();$();var Wt=t=>{if(typeof t=="string")return true;if(typeof t=="object"&&t!==null){let o=t;return "name"in o||"path"in o}return false},q=(t,o)=>{if(t instanceof Error)throw t;if(Object.values(exports.NavigationOutpostVerdicts).includes(t))return t;let e=`${x} Invalid outpost outcome: ${JSON.stringify(t)}.`;if(Wt(t)){if(o.resolve(t).matched.length===0)throw new Error(e+` Route not found: ${JSON.stringify(t)}`);return t}throw new Error(e+" Expected: verdicts.ALLOW, verdicts.BLOCK, or RouteLocationRaw (string path or object with name/path).")},V=(t,o)=>(t.hooks??[exports.NavigationHooks.BEFORE_EACH]).includes(o),vt=Symbol("timeout"),jt=t=>new Promise((o,e)=>{setTimeout(()=>{let n=new Error(`Timeout after ${t}ms`);n[vt]=true,e(n);},t);}),Jt=t=>t instanceof Error&&vt in t,ft=async(t,o,e,n,a)=>{let{onError:s,defaultTimeout:i,onTimeout:u}=e,{router:c}=o,g=t.timeout??i;E(exports.DebugPoints.OUTPOST_ENTER,a.debug,n,e.debugHandler);try{let v=await t.getHandler(),O=g?await Promise.race([v(o),jt(g)]):await v(o);return q(O,c)}catch(v){if(Jt(v)){if(n.warn(`Outpost "${t.name}" timed out after ${g}ms`),E(exports.DebugPoints.OUTPOST_TIMEOUT,a.debug,n,e.debugHandler),u){let O=await u(t.name,o);return q(O,c)}return exports.NavigationOutpostVerdicts.BLOCK}if(s&&v instanceof Error){let O=await s(v,o);return q(O,c)}return n.error(`Outpost "${t.name}" threw error:`,v),E(exports.DebugPoints.ERROR_CATCH,a.debug,n,e.debugHandler),exports.NavigationOutpostVerdicts.BLOCK}},Q=async(t,o,e,n,a)=>{let{hook:s,to:i,from:u}=o,c=a.log||a.debug,g=i.matched.flatMap(d=>d.meta?.outposts??[]),v=new Set(g);g.length!==v.size&&n.warn(`Duplicate outposts detected on route "${String(i.name??i.path)}"`);let O=0,I=t.globalSorted.filter(d=>V(t.global.get(d),s)).length,B=t.routeSorted.filter(d=>v.has(d)&&V(t.route.get(d),s)).length,T=I+B;if(T===0)return exports.NavigationOutpostVerdicts.ALLOW;c&&n.info(`${s}: ${u.path} -> ${i.path} (${T} outposts)`),E(exports.DebugPoints.NAVIGATION_START,a.debug,n,e.debugHandler);for(let d of t.globalSorted){let C=t.global.get(d);if(!C||!V(C,s))continue;O++,c&&n.info(`Processing outpost ${O}/${T}: "${d}" [${s}]`);let y=await ft(C,o,e,n,a);if(y!==exports.NavigationOutpostVerdicts.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${d}":`,y),E(exports.DebugPoints.OUTPOST_BLOCK,a.debug,n,e.debugHandler),y}for(let d of t.routeSorted){if(!v.has(d))continue;let C=t.route.get(d);if(!C){n.warn(`Route outpost "${d}" not found in registry`);continue}if(!V(C,s))continue;O++,c&&n.info(`Processing outpost ${O}/${T}: "${d}" [${s}]`);let y=await ft(C,o,e,n,a);if(y!==exports.NavigationOutpostVerdicts.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${d}":`,y),E(exports.DebugPoints.OUTPOST_BLOCK,a.debug,n,e.debugHandler),y}return exports.NavigationOutpostVerdicts.ALLOW},mt=t=>{switch(t){case exports.NavigationOutpostVerdicts.ALLOW:return true;case exports.NavigationOutpostVerdicts.BLOCK:return false;default:return t}};var rt=null,Ft=false,W=async()=>{if(Ft)return null;if(!rt)try{rt=await Promise.resolve().then(()=>(Vt(),Ut));}catch{return Ft=true,null}return rt},vo=(t,o={})=>{let{log:e,debug:n,devtools:a=H,defaultPriority:s=P}=o,i=o.logger??exports.createDefaultLogger(),u=o.debugHandler??exports.createDefaultDebugHandler(),c=a&&typeof window<"u",g=lt(),v={...o,debugHandler:u},O={log:e??H,debug:n??false},I=[],B=(r,p,l)=>({verdicts:exports.NavigationOutpostVerdicts,to:r,from:p,router:t,hook:l}),T=()=>O.log||O.debug,d=r=>async(p,l)=>{let f=B(p,l,r),R=await Q(g,f,v,i,O);return mt(R)};I.push(t.beforeEach(d(exports.NavigationHooks.BEFORE_EACH))),I.push(t.beforeResolve(d(exports.NavigationHooks.BEFORE_RESOLVE)));let C=t.afterEach(async(r,p)=>{let l=B(r,p,exports.NavigationHooks.AFTER_EACH);try{await Q(g,l,v,i,O);}catch(f){i.error("Error in afterEach outpost:",f),E(exports.DebugPoints.ERROR_CATCH,O.debug,i,u);}});I.push(C);let y=r=>{let{scope:p="global",name:l,handler:f,priority:R,hooks:zt,timeout:Mt,lazy:j=false}=r,A=null,U=null,Kt=async()=>A||(j?(U||(U=f().then(D=>{if(!D.default||typeof D.default!="function")throw new Error(`Lazy outpost "${l}" must export default handler`);return A=D.default,A}).catch(D=>{throw U=null,D instanceof Error?D:new Error(String(D))})),U):(A=f,A));T()&&i.info(`Deploying ${p} outpost: ${l}${j?" (lazy)":""}`),ct(g,p,{name:l,getHandler:Kt,lazy:j,priority:R,hooks:zt,timeout:Mt},s,i),c&&W().then(D=>D?.notifyDevtoolsRefresh());},st=(r,p)=>{T()&&i.info(`Abandoning ${r} outpost: ${p}`);let l=dt(g,r,p,s);return c&&l&&W().then(f=>f?.notifyDevtoolsRefresh()),l},ut=r=>t.getRoutes().find(p=>p.name===r),pt={install(r){c&&W().then(p=>{p&&(p.setupDevtools(r,g,t,i,O,e,n,u),E(exports.DebugPoints.DEVTOOLS_INIT,O.debug,i,u),T()&&i.info("DevTools initialized via app.use(citadel)"));});},deployOutpost(r){if(Array.isArray(r))for(let p of r)y(p);else y(r);},abandonOutpost(r,p){if(Array.isArray(p)){let l=true;for(let f of p)st(r,f)||(l=false);return l}else return st(r,p)},getOutpostNames(r){return Ot(g,r)},assignOutpostToRoute(r,p){let l=ut(r);if(!l)return i.warn(`Route "${r}" not found`),false;let f=Array.isArray(p)?p:[p];l.meta.outposts||(l.meta.outposts=[]);for(let R of f)l.meta.outposts.includes(R)||l.meta.outposts.push(R);return T()&&i.info(`Assigned outposts [${f.join(", ")}] to route "${r}"`),true},revokeOutpostFromRoute(r,p){let l=ut(r);if(!l)return i.warn(`Route "${r}" not found`),false;let f=Array.isArray(p)?p:[p];if(!l.meta.outposts){for(let R of f)i.warn(`Outpost "${R}" not found in route "${r}"`);return true}for(let R of f)l.meta.outposts.includes(R)||i.warn(`Outpost "${R}" not found in route "${r}"`);return l.meta.outposts=l.meta.outposts.filter(R=>!f.includes(R)),T()&&i.info(`Revoked outposts [${f.join(", ")}] from route "${r}"`),true},destroy(){T()&&i.info("Destroying citadel");for(let r of I)r();I.length=0,g.global.clear(),g.route.clear(),g.globalSorted.length=0,g.routeSorted.length=0,c&&W().then(r=>r?.clearDevtoolsApi());}};return o.outposts&&pt.deployOutpost(o.outposts),pt};
1
+ 'use strict';var devtoolsApi=require('@vue/devtools-api');var Yt=Object.defineProperty;var h=(t,o)=>()=>(t&&(o=t(t=0)),o);var Xt=(t,o)=>{for(var e in o)Yt(t,e,{get:o[e],enumerable:true});};exports.NavigationHooks=void 0;exports.NavigationOutpostVerdicts=void 0;exports.NavigationOutpostScopes=void 0;exports.DebugPoints=void 0;var G=h(()=>{exports.NavigationHooks={BEFORE_EACH:"beforeEach",BEFORE_RESOLVE:"beforeResolve",AFTER_EACH:"afterEach"},exports.NavigationOutpostVerdicts={ALLOW:"allow",BLOCK:"block"},exports.NavigationOutpostScopes={GLOBAL:"global",ROUTE:"route"},exports.DebugPoints={NAVIGATION_START:"navigation-start",OUTPOST_ENTER:"outpost-enter",OUTPOST_BLOCK:"outpost-block",OUTPOST_TIMEOUT:"outpost-timeout",ERROR_CATCH:"error-catch",DEVTOOLS_INIT:"devtools-init",DEVTOOLS_INSPECT:"devtools-inspect"};});var H,x,P,k=h(()=>{H=typeof undefined<"u"?!!undefined.DEV:globalThis.process?.env?.NODE_ENV!=="production",x="[\u{1F3F0} NavigationCitadel]",P=100;});exports.createDefaultLogger=void 0;exports.createDefaultDebugHandler=void 0;var T,$=h(()=>{k();exports.createDefaultLogger=()=>({info:(...t)=>console.info(`\u{1F535} ${x}`,...t),warn:(...t)=>console.log(`\u{1F7E1} ${x}`,...t),error:(...t)=>console.error(`\u{1F534} ${x}`,...t),debug:(...t)=>console.log(`\u{1F7E3} ${x} [DEBUG]`,...t)}),exports.createDefaultDebugHandler=()=>()=>{debugger},T=(t,o,e,n)=>{o&&(e.debug(t),n?.(t));};});var tt,F,Nt,Rt,w,Lt,bt,Et,Tt,yt,St,ot,_t,z,M,Ct,Dt,et,nt,K=h(()=>{G();tt="navigation.citadel",F="Navigation Citadel",Nt="castle",Rt="https://kassaila.github.io/vue-router-citadel/logo_devtools.svg",w=tt+".inspector",Lt="citadel-root",bt="citadel-"+exports.NavigationOutpostScopes.GLOBAL,Et="citadel-"+exports.NavigationOutpostScopes.ROUTE,Tt="citadel-route-assignments",yt="citadel-current-route",St=16777215,ot=4372867,_t=3900150,z=9133302,M=16096779,Ct=15485081,Dt=1357990,et="vue-router-citadel:settings:",nt="logLevel";});var C,Zt,qt,Y,ht,It,xt,At,Qt,to,oo,eo,no,ao,ro,io,Gt,at,Pt=h(()=>{G();k();$();K();C=(t,o)=>({label:t,textColor:St,backgroundColor:o}),Zt=t=>t===exports.NavigationOutpostScopes.GLOBAL?z:M,qt=(t,o,e,n,a)=>(e.lazy&&a.push(C("lazy",Ct)),{id:`${t}-${n}-${o}`,label:o,tags:a}),Y=(t,o,e,n,a)=>{let s=[];for(let r of t){let u=o.get(r);u&&s.push(qt(n,r,u,e,a(u)));}return s},ht=t=>{let o=t.hooks??[exports.NavigationHooks.BEFORE_EACH],e=t.priority??P;return [C(`priority: ${e}`,ot),C(o.length===1?o[0]:`${o.length} hooks`,_t)]},It=t=>o=>{let e=o.priority??P;return [C(t,Zt(t)),C(`priority: ${e}`,ot)]},xt=t=>t.name?String(t.name):t.path,At=(t,o)=>{if(!t.name&&!t.path)return t.meta.outposts??[];try{return (t.name?o.resolve({name:t.name}):o.resolve(t.path)).matched.flatMap(n=>n.meta?.outposts??[])}catch{return t.meta.outposts??[]}},Qt=t=>{let o=[];for(let e of t.getRoutes()){let n=At(e,t);if(n.length===0)continue;let a=e.meta.outposts??[],s=n.filter(u=>!a.includes(u)).length,r=[C(`${n.length} outpost${n.length===1?"":"s"}`,M)];s>0&&r.push(C(`${s} inherited`,z)),o.push({id:`route-assignment-${xt(e)}`,label:xt(e),tags:r});}return {id:Tt,label:`Route Assignments (${o.length})`,children:o}},to=(t,o)=>{let e=o.currentRoute.value,n=Y(t.globalSorted,t.global,exports.NavigationOutpostScopes.GLOBAL,"current-route-outpost",It(exports.NavigationOutpostScopes.GLOBAL)),a=new Set(e.matched.flatMap(u=>u.meta?.outposts??[])),s=Y(t.routeSorted.filter(u=>a.has(u)),t.route,exports.NavigationOutpostScopes.ROUTE,"current-route-outpost",It(exports.NavigationOutpostScopes.ROUTE)),r=[...n,...s];return {id:yt,label:`Current Route: ${e.path} (${r.length})`,tags:[C("active",Dt)],children:r}},oo=(t,o)=>{let e=Y(t.globalSorted,t.global,exports.NavigationOutpostScopes.GLOBAL,"outpost",ht),n=Y(t.routeSorted,t.route,exports.NavigationOutpostScopes.ROUTE,"outpost",ht),a=[{id:Lt,label:"Outposts",children:[{id:bt,label:`Global (${e.length})`,tags:[C(exports.NavigationOutpostScopes.GLOBAL,z)],children:e},{id:Et,label:`Route (${n.length})`,tags:[C(exports.NavigationOutpostScopes.ROUTE,M)],children:n}]}];return o&&(a.push(Qt(o)),a.push(to(t,o))),a},eo=(t,o,e)=>({"Outpost Details":[{key:"name",value:t},{key:"scope",value:o},{key:"priority",value:e.priority??P},{key:"hooks",value:e.hooks??[exports.NavigationHooks.BEFORE_EACH]},{key:"timeout",value:e.timeout??"none (uses default)"},{key:"lazy",value:e.lazy}]}),no=/^route-assignment-(.+)$/,ao=new RegExp(`^(?:outpost|current-route-outpost)-(${exports.NavigationOutpostScopes.GLOBAL}|${exports.NavigationOutpostScopes.ROUTE})-(.+)$`),ro=(t,o)=>{let e=At(t,o),n=t.meta.outposts??[],a=e.filter(s=>!n.includes(s));return {"Route Details":[{key:"name",value:t.name?String(t.name):"unnamed"},{key:"path",value:t.path},{key:"outposts (own)",value:n},...a.length>0?[{key:"outposts (inherited)",value:a}]:[],{key:"outposts (resolved)",value:e}]}},io=(t,o,e)=>{let n=t.match(ao);if(n){let[,a,s]=n,u=(a===exports.NavigationOutpostScopes.GLOBAL?o.global:o.route).get(s);return u?eo(s,a,u):null}if(e){let a=t.match(no);if(a){let s=a[1],r=e.getRoutes().find(u=>u.name?String(u.name)===s:u.path===s);return r?ro(r,e):null}}return null},Gt=(t,o,e,n,a=false,s)=>{t.addInspector({id:w,label:F,icon:Nt}),t.on.getInspectorTree(r=>{r.inspectorId===w&&(r.rootNodes=oo(o,e));}),t.on.getInspectorState(r=>{if(r.inspectorId!==w)return;let u=io(r.nodeId,o,e);u&&(r.state=u);}),e.afterEach(()=>{at(t);}),T(exports.DebugPoints.DEVTOOLS_INSPECT,a,n,s);},at=t=>{t.sendInspectorTree(w),t.sendInspectorState(w);};});var N,kt=h(()=>{N={OFF:"off",LOG:"log",DEBUG:"debug"};});var so,uo,po,rt,lo,wt,Ht,$t,Bt=h(()=>{kt();K();so=()=>{if(typeof window>"u"||!window.localStorage)return null;try{let t=localStorage.getItem(et+nt);return t===null?null:t===N.OFF||t===N.LOG||t===N.DEBUG?t:null}catch{return null}},uo=t=>{if(!(typeof window>"u"||!window.localStorage))try{localStorage.setItem(et+nt,t);}catch{}},po=(t,o,e)=>o?N.DEBUG:t??e?N.LOG:N.OFF,rt=t=>{switch(t){case N.OFF:return {log:false,debug:false};case N.LOG:return {log:true,debug:false};case N.DEBUG:return {log:true,debug:true}}},lo=t=>t.debug?N.DEBUG:t.log?N.LOG:N.OFF,wt=(t,o,e)=>{let n=so();if(n!==null)return rt(n);let a=po(t,o,e);return rt(a)},Ht=(t,o)=>{let e=rt(o);t.log=e.log,t.debug=e.debug,uo(o);},$t=t=>({logLevel:{label:"Log level",type:"choice",defaultValue:lo(t),options:[{label:"Off",value:N.OFF},{label:"Log",value:N.LOG},{label:"Log + Debug",value:N.DEBUG}],component:"button-group"}});});var Ut={};Xt(Ut,{clearDevtoolsApi:()=>fo,notifyDevtoolsRefresh:()=>Oo,setupDevtools:()=>co});var X,co,Oo,fo,Vt=h(()=>{k();K();Pt();Bt();X=null,co=(t,o,e,n,a,s,r,u)=>{let c=wt(s,r,H);a.log=c.log,a.debug=c.debug,devtoolsApi.setupDevToolsPlugin({id:tt,label:F,logo:Rt,packageName:"vue-router-citadel",homepage:"https://kassaila.github.io/vue-router-citadel",enableEarlyProxy:true,app:t,settings:$t(a)},g=>{X=g,g.on.setPluginSettings(v=>{v.key==="logLevel"&&Ht(a,v.newValue);}),Gt(g,o,e,n,a.debug,u);});},Oo=()=>{X&&at(X);},fo=()=>{X=null;};});G();$();G();k();$();var lt=()=>({global:new Map,route:new Map,globalSorted:[],routeSorted:[]}),gt=(t,o,e)=>{let n=t[o],a=`${o}Sorted`;t[a]=Array.from(n.keys()).sort((s,r)=>{let u=n.get(s)?.priority??e,c=n.get(r)?.priority??e;return u-c});},ct=(t,o,e,n,a)=>{t[o].has(e.name)&&a.warn(`${o} outpost "${e.name}" already exists, replacing...`),t[o].set(e.name,e),gt(t,o,n);},dt=(t,o,e,n)=>{let a=t[o].delete(e);return a&&gt(t,o,n),a},Ot=(t,o)=>Array.from(t[o].keys());G();k();$();var Wt=t=>{if(typeof t=="string")return true;if(typeof t=="object"&&t!==null){let o=t;return "name"in o||"path"in o}return false},q=(t,o)=>{if(t instanceof Error)throw t;if(Object.values(exports.NavigationOutpostVerdicts).includes(t))return t;let e=`${x} Invalid outpost outcome: ${JSON.stringify(t)}.`;if(Wt(t)){if(o.resolve(t).matched.length===0)throw new Error(e+` Route not found: ${JSON.stringify(t)}`);return t}throw new Error(e+" Expected: verdicts.ALLOW, verdicts.BLOCK, or RouteLocationRaw (string path or object with name/path).")},V=(t,o)=>(t.hooks??[exports.NavigationHooks.BEFORE_EACH]).includes(o),vt=Symbol("timeout"),jt=t=>new Promise((o,e)=>{setTimeout(()=>{let n=new Error(`Timeout after ${t}ms`);n[vt]=true,e(n);},t);}),Jt=t=>t instanceof Error&&vt in t,ft=async(t,o,e,n,a)=>{let{onError:s,defaultTimeout:r,onTimeout:u}=e,{router:c}=o,g=t.timeout??r;T(exports.DebugPoints.OUTPOST_ENTER,a.debug,n,e.debugHandler);try{let v=await t.getHandler(),O=g?await Promise.race([v(o),jt(g)]):await v(o);return q(O,c)}catch(v){if(Jt(v)){if(n.warn(`Outpost "${t.name}" timed out after ${g}ms`),T(exports.DebugPoints.OUTPOST_TIMEOUT,a.debug,n,e.debugHandler),u){let O=await u(t.name,o);return q(O,c)}return exports.NavigationOutpostVerdicts.BLOCK}if(s&&v instanceof Error){let O=await s(v,o);return q(O,c)}return n.error(`Outpost "${t.name}" threw error:`,v),T(exports.DebugPoints.ERROR_CATCH,a.debug,n,e.debugHandler),exports.NavigationOutpostVerdicts.BLOCK}},Q=async(t,o,e,n,a)=>{let{hook:s,to:r,from:u}=o,c=a.log||a.debug,g=r.matched.flatMap(d=>d.meta?.outposts??[]),v=new Set(g);g.length!==v.size&&n.warn(`Duplicate outposts detected on route "${String(r.name??r.path)}"`);let O=0,I=t.globalSorted.filter(d=>{let R=t.global.get(d);return R&&V(R,s)}).length,B=t.routeSorted.filter(d=>{let R=t.route.get(d);return v.has(d)&&R&&V(R,s)}).length,y=I+B;if(y===0)return exports.NavigationOutpostVerdicts.ALLOW;c&&n.info(`${s}: ${u.path} -> ${r.path} (${y} outposts)`),T(exports.DebugPoints.NAVIGATION_START,a.debug,n,e.debugHandler);for(let d of t.globalSorted){let R=t.global.get(d);if(!R||!V(R,s))continue;O++,c&&n.info(`Processing outpost ${O}/${y}: "${d}" [${s}]`);let S=await ft(R,o,e,n,a);if(S!==exports.NavigationOutpostVerdicts.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${d}":`,S),T(exports.DebugPoints.OUTPOST_BLOCK,a.debug,n,e.debugHandler),S}for(let d of t.routeSorted){if(!v.has(d))continue;let R=t.route.get(d);if(!R){n.warn(`Route outpost "${d}" not found in registry`);continue}if(!V(R,s))continue;O++,c&&n.info(`Processing outpost ${O}/${y}: "${d}" [${s}]`);let S=await ft(R,o,e,n,a);if(S!==exports.NavigationOutpostVerdicts.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${d}":`,S),T(exports.DebugPoints.OUTPOST_BLOCK,a.debug,n,e.debugHandler),S}return exports.NavigationOutpostVerdicts.ALLOW},mt=t=>{switch(t){case exports.NavigationOutpostVerdicts.ALLOW:return true;case exports.NavigationOutpostVerdicts.BLOCK:return false;default:return t}};var it=null,Ft=false,W=async()=>{if(Ft)return null;if(!it)try{it=await Promise.resolve().then(()=>(Vt(),Ut));}catch{return Ft=true,null}return it},vo=(t,o={})=>{let{log:e,debug:n,devtools:a=H,defaultPriority:s=P}=o,r=o.logger??exports.createDefaultLogger(),u=o.debugHandler??exports.createDefaultDebugHandler(),c=a&&typeof window<"u",g=lt(),v={...o,debugHandler:u},O={log:e??H,debug:n??false},I=[],B=(i,p,l)=>({verdicts:exports.NavigationOutpostVerdicts,to:i,from:p,router:t,hook:l}),y=()=>O.log||O.debug,d=i=>async(p,l)=>{let f=B(p,l,i),L=await Q(g,f,v,r,O);return mt(L)};I.push(t.beforeEach(d(exports.NavigationHooks.BEFORE_EACH))),I.push(t.beforeResolve(d(exports.NavigationHooks.BEFORE_RESOLVE)));let R=t.afterEach(async(i,p)=>{let l=B(i,p,exports.NavigationHooks.AFTER_EACH);try{await Q(g,l,v,r,O);}catch(f){r.error("Error in afterEach outpost:",f),T(exports.DebugPoints.ERROR_CATCH,O.debug,r,u);}});I.push(R);let S=i=>{let{scope:p="global",name:l,handler:f,priority:L,hooks:zt,timeout:Mt,lazy:j=false}=i,A=null,U=null,Kt=async()=>A||(j?(U||(U=f().then(D=>{if(!D.default||typeof D.default!="function")throw new Error(`Lazy outpost "${l}" must export default handler`);return A=D.default,A}).catch(D=>{throw U=null,D instanceof Error?D:new Error(String(D))})),U):(A=f,A));y()&&r.info(`Deploying ${p} outpost: ${l}${j?" (lazy)":""}`),ct(g,p,{name:l,getHandler:Kt,lazy:j,priority:L,hooks:zt,timeout:Mt},s,r),c&&W().then(D=>D?.notifyDevtoolsRefresh());},st=(i,p)=>{y()&&r.info(`Abandoning ${i} outpost: ${p}`);let l=dt(g,i,p,s);return c&&l&&W().then(f=>f?.notifyDevtoolsRefresh()),l},ut=i=>t.getRoutes().find(p=>p.name===i),pt={install(i){c&&W().then(p=>{p&&(p.setupDevtools(i,g,t,r,O,e,n,u),T(exports.DebugPoints.DEVTOOLS_INIT,O.debug,r,u),y()&&r.info("DevTools initialized via app.use(citadel)"));});},deployOutpost(i){if(Array.isArray(i))for(let p of i)S(p);else S(i);},abandonOutpost(i,p){if(Array.isArray(p)){let l=true;for(let f of p)st(i,f)||(l=false);return l}else return st(i,p)},getOutpostNames(i){return Ot(g,i)},assignOutpostToRoute(i,p){let l=ut(i);if(!l)return r.warn(`Route "${i}" not found`),false;let f=Array.isArray(p)?p:[p];l.meta.outposts||(l.meta.outposts=[]);for(let L of f)l.meta.outposts.includes(L)||l.meta.outposts.push(L);return y()&&r.info(`Assigned outposts [${f.join(", ")}] to route "${i}"`),true},revokeOutpostFromRoute(i,p){let l=ut(i);if(!l)return r.warn(`Route "${i}" not found`),false;let f=Array.isArray(p)?p:[p];if(!l.meta.outposts){for(let L of f)r.warn(`Outpost "${L}" not found in route "${i}"`);return true}for(let L of f)l.meta.outposts.includes(L)||r.warn(`Outpost "${L}" not found in route "${i}"`);return l.meta.outposts=l.meta.outposts.filter(L=>!f.includes(L)),y()&&r.info(`Revoked outposts [${f.join(", ")}] from route "${i}"`),true},destroy(){y()&&r.info("Destroying citadel");for(let i of I)i();I.length=0,g.global.clear(),g.route.clear(),g.globalSorted.length=0,g.routeSorted.length=0,c&&W().then(i=>i?.clearDevtoolsApi());}};return o.outposts&&pt.deployOutpost(o.outposts),pt};
2
2
  exports.createNavigationCitadel=vo;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import {g,e,h,i,a,j as j$1,d,b,f}from'./chunk-5IKR7JBX.js';export{d as DebugPoints,a as NavigationHooks,c as NavigationOutpostScopes,b as NavigationOutpostVerdicts,i as createDefaultDebugHandler,h as createDefaultLogger}from'./chunk-5IKR7JBX.js';var U=()=>({global:new Map,route:new Map,globalSorted:[],routeSorted:[]}),K=(t,o,a)=>{let n=t[o],u=`${o}Sorted`;t[u]=Array.from(n.keys()).sort((f,s)=>{let N=n.get(f)?.priority??a,c=n.get(s)?.priority??a;return N-c});},j=(t,o,a,n,u)=>{t[o].has(a.name)&&u.warn(`${o} outpost "${a.name}" already exists, replacing...`),t[o].set(a.name,a),K(t,o,n);},W=(t,o,a,n)=>{let u=t[o].delete(a);return u&&K(t,o,n),u},Y=(t,o)=>Array.from(t[o].keys());var nt=t=>{if(typeof t=="string")return true;if(typeof t=="object"&&t!==null){let o=t;return "name"in o||"path"in o}return false},x=(t,o)=>{if(t instanceof Error)throw t;if(Object.values(b).includes(t))return t;let a=`${f} Invalid outpost outcome: ${JSON.stringify(t)}.`;if(nt(t)){if(o.resolve(t).matched.length===0)throw new Error(a+` Route not found: ${JSON.stringify(t)}`);return t}throw new Error(a+" Expected: verdicts.ALLOW, verdicts.BLOCK, or RouteLocationRaw (string path or object with name/path).")},T=(t,o)=>(t.hooks??[a.BEFORE_EACH]).includes(o),X=Symbol("timeout"),it=t=>new Promise((o,a)=>{setTimeout(()=>{let n=new Error(`Timeout after ${t}ms`);n[X]=true,a(n);},t);}),at=t=>t instanceof Error&&X in t,J=async(t,o,a,n,u)=>{let{onError:f,defaultTimeout:s,onTimeout:N}=a,{router:c}=o,g=t.timeout??s;j$1(d.OUTPOST_ENTER,u.debug,n,a.debugHandler);try{let O=await t.getHandler(),d=g?await Promise.race([O(o),it(g)]):await O(o);return x(d,c)}catch(O){if(at(O)){if(n.warn(`Outpost "${t.name}" timed out after ${g}ms`),j$1(d.OUTPOST_TIMEOUT,u.debug,n,a.debugHandler),N){let d=await N(t.name,o);return x(d,c)}return b.BLOCK}if(f&&O instanceof Error){let d=await f(O,o);return x(d,c)}return n.error(`Outpost "${t.name}" threw error:`,O),j$1(d.ERROR_CATCH,u.debug,n,a.debugHandler),b.BLOCK}},I=async(t,o,a,n,u)=>{let{hook:f,to:s,from:N}=o,c=u.log||u.debug,g=s.matched.flatMap(l=>l.meta?.outposts??[]),O=new Set(g);g.length!==O.size&&n.warn(`Duplicate outposts detected on route "${String(s.name??s.path)}"`);let d$1=0,E=t.globalSorted.filter(l=>T(t.global.get(l),f)).length,A=t.routeSorted.filter(l=>O.has(l)&&T(t.route.get(l),f)).length,y=E+A;if(y===0)return b.ALLOW;c&&n.info(`${f}: ${N.path} -> ${s.path} (${y} outposts)`),j$1(d.NAVIGATION_START,u.debug,n,a.debugHandler);for(let l of t.globalSorted){let L=t.global.get(l);if(!L||!T(L,f))continue;d$1++,c&&n.info(`Processing outpost ${d$1}/${y}: "${l}" [${f}]`);let b$1=await J(L,o,a,n,u);if(b$1!==b.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${l}":`,b$1),j$1(d.OUTPOST_BLOCK,u.debug,n,a.debugHandler),b$1}for(let l of t.routeSorted){if(!O.has(l))continue;let L=t.route.get(l);if(!L){n.warn(`Route outpost "${l}" not found in registry`);continue}if(!T(L,f))continue;d$1++,c&&n.info(`Processing outpost ${d$1}/${y}: "${l}" [${f}]`);let b$1=await J(L,o,a,n,u);if(b$1!==b.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${l}":`,b$1),j$1(d.OUTPOST_BLOCK,u.debug,n,a.debugHandler),b$1}return b.ALLOW},q=t=>{switch(t){case b.ALLOW:return true;case b.BLOCK:return false;default:return t}};var z=null,Q=false,H=async()=>{if(Q)return null;if(!z)try{z=await import('./devtools-3TRWBQAH.js');}catch{return Q=true,null}return z},rt=(t,o={})=>{let{log:a$1,debug:n,devtools:u=e,defaultPriority:f=g}=o,s=o.logger??h(),N=o.debugHandler??i(),c=u&&typeof window<"u",g$1=U(),O={...o,debugHandler:N},d$1={log:a$1??e,debug:n??false},E=[],A=(e,i,r)=>({verdicts:b,to:e,from:i,router:t,hook:r}),y=()=>d$1.log||d$1.debug,l=e=>async(i,r)=>{let p=A(i,r,e),v=await I(g$1,p,O,s,d$1);return q(v)};E.push(t.beforeEach(l(a.BEFORE_EACH))),E.push(t.beforeResolve(l(a.BEFORE_RESOLVE)));let L=t.afterEach(async(e,i)=>{let r=A(e,i,a.AFTER_EACH);try{await I(g$1,r,O,s,d$1);}catch(p){s.error("Error in afterEach outpost:",p),j$1(d.ERROR_CATCH,d$1.debug,s,N);}});E.push(L);let b$1=e=>{let{scope:i="global",name:r,handler:p,priority:v,hooks:Z,timeout:tt,lazy:P=false}=e,$=null,S=null,ot=async()=>$||(P?(S||(S=p().then(C=>{if(!C.default||typeof C.default!="function")throw new Error(`Lazy outpost "${r}" must export default handler`);return $=C.default,$}).catch(C=>{throw S=null,C instanceof Error?C:new Error(String(C))})),S):($=p,$));y()&&s.info(`Deploying ${i} outpost: ${r}${P?" (lazy)":""}`),j(g$1,i,{name:r,getHandler:ot,lazy:P,priority:v,hooks:Z,timeout:tt},f,s),c&&H().then(C=>C?.notifyDevtoolsRefresh());},B=(e,i)=>{y()&&s.info(`Abandoning ${e} outpost: ${i}`);let r=W(g$1,e,i,f);return c&&r&&H().then(p=>p?.notifyDevtoolsRefresh()),r},M=e=>t.getRoutes().find(i=>i.name===e),G={install(e){c&&H().then(i=>{i&&(i.setupDevtools(e,g$1,t,s,d$1,a$1,n,N),j$1(d.DEVTOOLS_INIT,d$1.debug,s,N),y()&&s.info("DevTools initialized via app.use(citadel)"));});},deployOutpost(e){if(Array.isArray(e))for(let i of e)b$1(i);else b$1(e);},abandonOutpost(e,i){if(Array.isArray(i)){let r=true;for(let p of i)B(e,p)||(r=false);return r}else return B(e,i)},getOutpostNames(e){return Y(g$1,e)},assignOutpostToRoute(e,i){let r=M(e);if(!r)return s.warn(`Route "${e}" not found`),false;let p=Array.isArray(i)?i:[i];r.meta.outposts||(r.meta.outposts=[]);for(let v of p)r.meta.outposts.includes(v)||r.meta.outposts.push(v);return y()&&s.info(`Assigned outposts [${p.join(", ")}] to route "${e}"`),true},revokeOutpostFromRoute(e,i){let r=M(e);if(!r)return s.warn(`Route "${e}" not found`),false;let p=Array.isArray(i)?i:[i];if(!r.meta.outposts){for(let v of p)s.warn(`Outpost "${v}" not found in route "${e}"`);return true}for(let v of p)r.meta.outposts.includes(v)||s.warn(`Outpost "${v}" not found in route "${e}"`);return r.meta.outposts=r.meta.outposts.filter(v=>!p.includes(v)),y()&&s.info(`Revoked outposts [${p.join(", ")}] from route "${e}"`),true},destroy(){y()&&s.info("Destroying citadel");for(let e of E)e();E.length=0,g$1.global.clear(),g$1.route.clear(),g$1.globalSorted.length=0,g$1.routeSorted.length=0,c&&H().then(e=>e?.clearDevtoolsApi());}};return o.outposts&&G.deployOutpost(o.outposts),G};export{rt as createNavigationCitadel};
1
+ import {g,e,h,i,a,j as j$1,d,b,f}from'./chunk-5IKR7JBX.js';export{d as DebugPoints,a as NavigationHooks,c as NavigationOutpostScopes,b as NavigationOutpostVerdicts,i as createDefaultDebugHandler,h as createDefaultLogger}from'./chunk-5IKR7JBX.js';var U=()=>({global:new Map,route:new Map,globalSorted:[],routeSorted:[]}),K=(t,o,a)=>{let n=t[o],u=`${o}Sorted`;t[u]=Array.from(n.keys()).sort((f,s)=>{let y=n.get(f)?.priority??a,c=n.get(s)?.priority??a;return y-c});},j=(t,o,a,n,u)=>{t[o].has(a.name)&&u.warn(`${o} outpost "${a.name}" already exists, replacing...`),t[o].set(a.name,a),K(t,o,n);},W=(t,o,a,n)=>{let u=t[o].delete(a);return u&&K(t,o,n),u},Y=(t,o)=>Array.from(t[o].keys());var nt=t=>{if(typeof t=="string")return true;if(typeof t=="object"&&t!==null){let o=t;return "name"in o||"path"in o}return false},x=(t,o)=>{if(t instanceof Error)throw t;if(Object.values(b).includes(t))return t;let a=`${f} Invalid outpost outcome: ${JSON.stringify(t)}.`;if(nt(t)){if(o.resolve(t).matched.length===0)throw new Error(a+` Route not found: ${JSON.stringify(t)}`);return t}throw new Error(a+" Expected: verdicts.ALLOW, verdicts.BLOCK, or RouteLocationRaw (string path or object with name/path).")},T=(t,o)=>(t.hooks??[a.BEFORE_EACH]).includes(o),X=Symbol("timeout"),it=t=>new Promise((o,a)=>{setTimeout(()=>{let n=new Error(`Timeout after ${t}ms`);n[X]=true,a(n);},t);}),at=t=>t instanceof Error&&X in t,J=async(t,o,a,n,u)=>{let{onError:f,defaultTimeout:s,onTimeout:y}=a,{router:c}=o,g=t.timeout??s;j$1(d.OUTPOST_ENTER,u.debug,n,a.debugHandler);try{let v=await t.getHandler(),p=g?await Promise.race([v(o),it(g)]):await v(o);return x(p,c)}catch(v){if(at(v)){if(n.warn(`Outpost "${t.name}" timed out after ${g}ms`),j$1(d.OUTPOST_TIMEOUT,u.debug,n,a.debugHandler),y){let p=await y(t.name,o);return x(p,c)}return b.BLOCK}if(f&&v instanceof Error){let p=await f(v,o);return x(p,c)}return n.error(`Outpost "${t.name}" threw error:`,v),j$1(d.ERROR_CATCH,u.debug,n,a.debugHandler),b.BLOCK}},I=async(t,o,a,n,u)=>{let{hook:f,to:s,from:y}=o,c=u.log||u.debug,g=s.matched.flatMap(l=>l.meta?.outposts??[]),v=new Set(g);g.length!==v.size&&n.warn(`Duplicate outposts detected on route "${String(s.name??s.path)}"`);let p=0,E=t.globalSorted.filter(l=>{let O=t.global.get(l);return O&&T(O,f)}).length,A=t.routeSorted.filter(l=>{let O=t.route.get(l);return v.has(l)&&O&&T(O,f)}).length,R=E+A;if(R===0)return b.ALLOW;c&&n.info(`${f}: ${y.path} -> ${s.path} (${R} outposts)`),j$1(d.NAVIGATION_START,u.debug,n,a.debugHandler);for(let l of t.globalSorted){let O=t.global.get(l);if(!O||!T(O,f))continue;p++,c&&n.info(`Processing outpost ${p}/${R}: "${l}" [${f}]`);let h=await J(O,o,a,n,u);if(h!==b.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${l}":`,h),j$1(d.OUTPOST_BLOCK,u.debug,n,a.debugHandler),h}for(let l of t.routeSorted){if(!v.has(l))continue;let O=t.route.get(l);if(!O){n.warn(`Route outpost "${l}" not found in registry`);continue}if(!T(O,f))continue;p++,c&&n.info(`Processing outpost ${p}/${R}: "${l}" [${f}]`);let h=await J(O,o,a,n,u);if(h!==b.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${l}":`,h),j$1(d.OUTPOST_BLOCK,u.debug,n,a.debugHandler),h}return b.ALLOW},q=t=>{switch(t){case b.ALLOW:return true;case b.BLOCK:return false;default:return t}};var z=null,Q=false,H=async()=>{if(Q)return null;if(!z)try{z=await import('./devtools-3TRWBQAH.js');}catch{return Q=true,null}return z},rt=(t,o={})=>{let{log:a$1,debug:n,devtools:u=e,defaultPriority:f=g}=o,s=o.logger??h(),y=o.debugHandler??i(),c=u&&typeof window<"u",g$1=U(),v={...o,debugHandler:y},p={log:a$1??e,debug:n??false},E=[],A=(e,i,r)=>({verdicts:b,to:e,from:i,router:t,hook:r}),R=()=>p.log||p.debug,l=e=>async(i,r)=>{let d=A(i,r,e),m=await I(g$1,d,v,s,p);return q(m)};E.push(t.beforeEach(l(a.BEFORE_EACH))),E.push(t.beforeResolve(l(a.BEFORE_RESOLVE)));let O=t.afterEach(async(e,i)=>{let r=A(e,i,a.AFTER_EACH);try{await I(g$1,r,v,s,p);}catch(d$1){s.error("Error in afterEach outpost:",d$1),j$1(d.ERROR_CATCH,p.debug,s,y);}});E.push(O);let h$1=e=>{let{scope:i="global",name:r,handler:d,priority:m,hooks:Z,timeout:tt,lazy:P=false}=e,$=null,S=null,ot=async()=>$||(P?(S||(S=d().then(C=>{if(!C.default||typeof C.default!="function")throw new Error(`Lazy outpost "${r}" must export default handler`);return $=C.default,$}).catch(C=>{throw S=null,C instanceof Error?C:new Error(String(C))})),S):($=d,$));R()&&s.info(`Deploying ${i} outpost: ${r}${P?" (lazy)":""}`),j(g$1,i,{name:r,getHandler:ot,lazy:P,priority:m,hooks:Z,timeout:tt},f,s),c&&H().then(C=>C?.notifyDevtoolsRefresh());},B=(e,i)=>{R()&&s.info(`Abandoning ${e} outpost: ${i}`);let r=W(g$1,e,i,f);return c&&r&&H().then(d=>d?.notifyDevtoolsRefresh()),r},M=e=>t.getRoutes().find(i=>i.name===e),G={install(e){c&&H().then(i=>{i&&(i.setupDevtools(e,g$1,t,s,p,a$1,n,y),j$1(d.DEVTOOLS_INIT,p.debug,s,y),R()&&s.info("DevTools initialized via app.use(citadel)"));});},deployOutpost(e){if(Array.isArray(e))for(let i of e)h$1(i);else h$1(e);},abandonOutpost(e,i){if(Array.isArray(i)){let r=true;for(let d of i)B(e,d)||(r=false);return r}else return B(e,i)},getOutpostNames(e){return Y(g$1,e)},assignOutpostToRoute(e,i){let r=M(e);if(!r)return s.warn(`Route "${e}" not found`),false;let d=Array.isArray(i)?i:[i];r.meta.outposts||(r.meta.outposts=[]);for(let m of d)r.meta.outposts.includes(m)||r.meta.outposts.push(m);return R()&&s.info(`Assigned outposts [${d.join(", ")}] to route "${e}"`),true},revokeOutpostFromRoute(e,i){let r=M(e);if(!r)return s.warn(`Route "${e}" not found`),false;let d=Array.isArray(i)?i:[i];if(!r.meta.outposts){for(let m of d)s.warn(`Outpost "${m}" not found in route "${e}"`);return true}for(let m of d)r.meta.outposts.includes(m)||s.warn(`Outpost "${m}" not found in route "${e}"`);return r.meta.outposts=r.meta.outposts.filter(m=>!d.includes(m)),R()&&s.info(`Revoked outposts [${d.join(", ")}] from route "${e}"`),true},destroy(){R()&&s.info("Destroying citadel");for(let e of E)e();E.length=0,g$1.global.clear(),g$1.route.clear(),g$1.globalSorted.length=0,g$1.routeSorted.length=0,c&&H().then(e=>e?.clearDevtoolsApi());}};return o.outposts&&G.deployOutpost(o.outposts),G};export{rt as createNavigationCitadel};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-router-citadel",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Structured navigation defense for Vue Router",
5
5
  "type": "module",
6
6
  "sideEffects": false,