vue-router-citadel 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -2
- package/README.md +2 -2
- package/dist/{chunk-5IKR7JBX.js → chunk-W4ASYKYO.js} +1 -1
- package/dist/{devtools-3TRWBQAH.js → devtools-OVHNQHN4.js} +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +45 -19
- package/dist/index.d.ts +45 -19
- package/dist/index.js +1 -1
- package/package.json +21 -21
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,32 @@ 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.3.0] - 2026-05-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Per-outpost `onError` and `onTimeout` handlers on `NavigationOutpost`. When set, they replace the
|
|
15
|
+
citadel-level handler for that outpost; otherwise the citadel-level handler (or default `BLOCK`)
|
|
16
|
+
applies. Enables per-outpost error policies (e.g. report `auth` failures to Sentry but silently
|
|
17
|
+
allow on `preload` errors)
|
|
18
|
+
- `OutpostBehaviorOptions` interface exported — shared optional fields (`priority`, `hooks`,
|
|
19
|
+
`timeout`, `onError`, `onTimeout`) used by both `NavigationOutpost` and
|
|
20
|
+
`RegisteredNavigationOutpost`
|
|
21
|
+
- `NavigationOutpostErrorHandler` and `NavigationOutpostTimeoutHandler` types exported — handler
|
|
22
|
+
signatures for citadel-level and per-outpost error/timeout callbacks
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- `onError` is now invoked for non-`Error` throws. Previously the handler was skipped when an
|
|
27
|
+
outpost threw a non-`Error` value (string, object, etc.) and navigation fell through to the
|
|
28
|
+
default `BLOCK`. Such values are now wrapped via `new Error(String(value))` before being passed to
|
|
29
|
+
`onError`
|
|
30
|
+
- Throws from inside `onError` / `onTimeout` are now caught. Previously they propagated out of the
|
|
31
|
+
guard. They are now logged and the outpost resolves to `BLOCK`. The same applies if the verdict
|
|
32
|
+
returned by these handlers fails `normalizeOutcome` validation
|
|
33
|
+
|
|
8
34
|
## [0.2.2] - 2026-03-17
|
|
9
35
|
|
|
10
36
|
### Fixed
|
|
@@ -103,7 +129,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
103
129
|
- `check:lint` — ESLint check (alias)
|
|
104
130
|
- `check:types` — TypeScript type checking (`tsc --noEmit`)
|
|
105
131
|
- `check:format` — format check alias
|
|
106
|
-
- `check:size` — bundle size check ([size-limit](https://github.com/ai/size-limit)
|
|
132
|
+
- `check:size` — bundle size check ([size-limit](https://github.com/ai/size-limit))
|
|
107
133
|
- `check:all` — full validation chain (format + lint + types + tests + build + size)
|
|
108
134
|
- `release:check` — pre-release verification (check:all + pack --dry-run)
|
|
109
135
|
- `release:publish` — publish to npm with full checks
|
|
@@ -181,4 +207,4 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
181
207
|
- `eslint-config-prettier` for conflict-free coexistence with Prettier
|
|
182
208
|
- 3 custom local rules: `switch-case-braces`, `jsdoc-comment-style`, `prefer-arrow-without-this`
|
|
183
209
|
- npm scripts: `lint`, `lint:fix`, `check:lint`; integrated into `check:all` and `lint-staged`
|
|
184
|
-
- [size-limit](https://github.com/ai/size-limit) — bundle size control
|
|
210
|
+
- [size-limit](https://github.com/ai/size-limit) — bundle size control
|
package/README.md
CHANGED
|
@@ -28,8 +28,8 @@ Think of it as turning your router into a fortress.
|
|
|
28
28
|
- 📋 **Priority-based execution** — deterministic outpost ordering with numeric priorities
|
|
29
29
|
- 🪝 **All navigation hooks** — beforeEach, beforeResolve, afterEach support per outpost
|
|
30
30
|
- 🔄 **Dynamic management** — deploy, abandon, and reassign outposts at runtime
|
|
31
|
-
- ⏱️ **Timeout control & error handling** — global and per-outpost timeout
|
|
32
|
-
|
|
31
|
+
- ⏱️ **Timeout control & error handling** — global and per-outpost timeout and error handlers.
|
|
32
|
+
Override citadel-level handlers per outpost with redirect or block verdicts.
|
|
33
33
|
- 🔒 **Type-safe** — full TypeScript support with declaration merging for outpost names. IDE
|
|
34
34
|
autocomplete and compile-time validation.
|
|
35
35
|
- 🦥 **Lazy outposts** — dynamic imports with automatic caching for code splitting
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var r={BEFORE_EACH:"beforeEach",BEFORE_RESOLVE:"beforeResolve",AFTER_EACH:"afterEach"},n={ALLOW:"allow",BLOCK:"block"},s={GLOBAL:"global",ROUTE:"route"},p={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 g=typeof import.meta?.env<"u"?!!import.meta.env.DEV:globalThis.process?.env?.NODE_ENV!=="production",o="[\u{1F3F0} NavigationCitadel]",O=100;var d=()=>({info:(...t)=>console.info(`\u{1F535} ${o}`,...t),warn:(...t)=>console.log(`\u{1F7E1} ${o}`,...t),error:(...t)=>console.error(`\u{1F534} ${o}`,...t),debug:(...t)=>console.log(`\u{1F7E3} ${o} [DEBUG]`,...t)}),v=()=>()=>{debugger},c=(t,e,a,i)=>{e&&(a.debug(t),i?.(t));};export{r as a,n as b,s as c,p as d,g as e,o as f,O as g,d as h,v as i,c as j};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {c as c$1,j as j$1,d as d$1,g as g$1,a,e}from'./chunk-
|
|
1
|
+
import {c as c$1,j as j$1,d as d$1,g as g$1,a,e}from'./chunk-W4ASYKYO.js';import {setupDevToolsPlugin}from'@vue/devtools-api';var m="navigation.citadel",g="Navigation Citadel",A="castle",x="https://kassaila.github.io/vue-router-citadel/logo_devtools.svg",c=m+".inspector",y="citadel-root",U="citadel-"+c$1.GLOBAL,P="citadel-"+c$1.ROUTE,B="citadel-route-assignments",k="citadel-current-route",V=16777215,N=4372867,$=3900150,d=9133302,L=16096779,F=15485081,w=1357990,S="vue-router-citadel:settings:",v="logLevel";var p=(t,e)=>({label:t,textColor:V,backgroundColor:e}),q=t=>t===c$1.GLOBAL?d:L,J=(t,e,o,s,n)=>(o.lazy&&n.push(p("lazy",F)),{id:`${t}-${s}-${e}`,label:e,tags:n}),_=(t,e,o,s,n)=>{let a=[];for(let r of t){let i=e.get(r);i&&a.push(J(s,r,i,o,n(i)));}return a},z=t=>{let e=t.hooks??[a.BEFORE_EACH],o=t.priority??g$1;return [p(`priority: ${o}`,N),p(e.length===1?e[0]:`${e.length} hooks`,$)]},H=t=>e=>{let o=e.priority??g$1;return [p(t,q(t)),p(`priority: ${o}`,N)]},M=t=>t.name?String(t.name):t.path,Y=(t,e)=>{if(!t.name&&!t.path)return t.meta.outposts??[];try{return (t.name?e.resolve({name:t.name}):e.resolve(t.path)).matched.flatMap(s=>s.meta?.outposts??[])}catch{return t.meta.outposts??[]}},Q=t=>{let e=[];for(let o of t.getRoutes()){let s=Y(o,t);if(s.length===0)continue;let n=o.meta.outposts??[],a=s.filter(i=>!n.includes(i)).length,r=[p(`${s.length} outpost${s.length===1?"":"s"}`,L)];a>0&&r.push(p(`${a} inherited`,d)),e.push({id:`route-assignment-${M(o)}`,label:M(o),tags:r});}return {id:B,label:`Route Assignments (${e.length})`,children:e}},W=(t,e)=>{let o=e.currentRoute.value,s=_(t.globalSorted,t.global,c$1.GLOBAL,"current-route-outpost",H(c$1.GLOBAL)),n=new Set(o.matched.flatMap(i=>i.meta?.outposts??[])),a=_(t.routeSorted.filter(i=>n.has(i)),t.route,c$1.ROUTE,"current-route-outpost",H(c$1.ROUTE)),r=[...s,...a];return {id:k,label:`Current Route: ${o.path} (${r.length})`,tags:[p("active",w)],children:r}},tt=(t,e)=>{let o=_(t.globalSorted,t.global,c$1.GLOBAL,"outpost",z),s=_(t.routeSorted,t.route,c$1.ROUTE,"outpost",z),n=[{id:y,label:"Outposts",children:[{id:U,label:`Global (${o.length})`,tags:[p(c$1.GLOBAL,d)],children:o},{id:P,label:`Route (${s.length})`,tags:[p(c$1.ROUTE,L)],children:s}]}];return e&&(n.push(Q(e)),n.push(W(t,e))),n},et=(t,e,o)=>({"Outpost Details":[{key:"name",value:t},{key:"scope",value:e},{key:"priority",value:o.priority??g$1},{key:"hooks",value:o.hooks??[a.BEFORE_EACH]},{key:"timeout",value:o.timeout??"none (uses default)"},{key:"lazy",value:o.lazy}]}),ot=/^route-assignment-(.+)$/,nt=new RegExp(`^(?:outpost|current-route-outpost)-(${c$1.GLOBAL}|${c$1.ROUTE})-(.+)$`),st=(t,e)=>{let o=Y(t,e),s=t.meta.outposts??[],n=o.filter(a=>!s.includes(a));return {"Route Details":[{key:"name",value:t.name?String(t.name):"unnamed"},{key:"path",value:t.path},{key:"outposts (own)",value:s},...n.length>0?[{key:"outposts (inherited)",value:n}]:[],{key:"outposts (resolved)",value:o}]}},rt=(t,e,o)=>{let s=t.match(nt);if(s){let[,n,a]=s,i=(n===c$1.GLOBAL?e.global:e.route).get(a);return i?et(a,n,i):null}if(o){let n=t.match(ot);if(n){let a=n[1],r=o.getRoutes().find(i=>i.name?String(i.name)===a:i.path===a);return r?st(r,o):null}}return null},X=(t,e,o,s,n=false,a)=>{t.addInspector({id:c,label:g,icon:A}),t.on.getInspectorTree(r=>{r.inspectorId===c&&(r.rootNodes=tt(e,o));}),t.on.getInspectorState(r=>{if(r.inspectorId!==c)return;let i=rt(r.nodeId,e,o);i&&(r.state=i);}),o.afterEach(()=>{f(t);}),j$1(d$1.DEVTOOLS_INSPECT,n,s,a);},f=t=>{t.sendInspectorTree(c),t.sendInspectorState(c);};var u={OFF:"off",LOG:"log",DEBUG:"debug"};var it=()=>{if(typeof window>"u"||!window.localStorage)return null;try{let t=localStorage.getItem(S+v);return t===null?null:t===u.OFF||t===u.LOG||t===u.DEBUG?t:null}catch{return null}},at=t=>{if(!(typeof window>"u"||!window.localStorage))try{localStorage.setItem(S+v,t);}catch{}},lt=(t,e,o)=>e?u.DEBUG:t??o?u.LOG:u.OFF,I=t=>{switch(t){case u.LOG:return {log:true,debug:false};case u.DEBUG:return {log:true,debug:true};case u.OFF:default:return {log:false,debug:false}}},ut=t=>t.debug?u.DEBUG:t.log?u.LOG:u.OFF,K=(t,e,o)=>{let s=it();if(s!==null)return I(s);let n=lt(t,e,o);return I(n)},Z=(t,e)=>{let o=I(e);t.log=o.log,t.debug=o.debug,at(e);},j=t=>({logLevel:{label:"Log level",type:"choice",defaultValue:ut(t),options:[{label:"Off",value:u.OFF},{label:"Log",value:u.LOG},{label:"Log + Debug",value:u.DEBUG}],component:"button-group"}});var R=null,Ct=(t,e$1,o,s,n,a,r,i)=>{let G=K(a,r,e);n.log=G.log,n.debug=G.debug,setupDevToolsPlugin({id:m,label:g,logo:x,packageName:"vue-router-citadel",homepage:"https://kassaila.github.io/vue-router-citadel",enableEarlyProxy:true,app:t,settings:j(n)},T=>{R=T,T.on.setPluginSettings(C=>{C.key==="logLevel"&&Z(n,C.newValue);}),X(T,e$1,o,s,n.debug,i);});},Dt=()=>{R&&f(R);},bt=()=>{R=null;};
|
|
2
2
|
export{bt as clearDevtoolsApi,Dt as notifyDevtoolsRefresh,Ct as setupDevtools};
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var devtoolsApi=require('@vue/devtools-api');var Yt=Object.defineProperty;var D=(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=D(()=>{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=D(()=>{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 y,$=D(()=>{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},y=(t,o,e,n)=>{o&&(e.debug(t),n?.(t));};});var tt,F,Nt,Rt,w,Lt,bt,Tt,yt,Et,St,ot,_t,z,M,Ct,ht,et,nt,K=D(()=>{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,Tt="citadel-"+exports.NavigationOutpostScopes.ROUTE,yt="citadel-route-assignments",Et="citadel-current-route",St=16777215,ot=4372867,_t=3900150,z=9133302,M=16096779,Ct=15485081,ht=1357990,et="vue-router-citadel:settings:",nt="logLevel";});var C,qt,Qt,Y,Dt,It,xt,At,to,oo,eo,no,ao,ro,io,so,Gt,at,Pt=D(()=>{G();k();$();K();C=(t,o)=>({label:t,textColor:St,backgroundColor:o}),qt=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 i=[];for(let r of t){let u=o.get(r);u&&i.push(Qt(n,r,u,e,a(u)));}return i},Dt=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,qt(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??[]}},to=t=>{let o=[];for(let e of t.getRoutes()){let n=At(e,t);if(n.length===0)continue;let a=e.meta.outposts??[],i=n.filter(u=>!a.includes(u)).length,r=[C(`${n.length} outpost${n.length===1?"":"s"}`,M)];i>0&&r.push(C(`${i} inherited`,z)),o.push({id:`route-assignment-${xt(e)}`,label:xt(e),tags:r});}return {id:yt,label:`Route Assignments (${o.length})`,children:o}},oo=(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??[])),i=Y(t.routeSorted.filter(u=>a.has(u)),t.route,exports.NavigationOutpostScopes.ROUTE,"current-route-outpost",It(exports.NavigationOutpostScopes.ROUTE)),r=[...n,...i];return {id:Et,label:`Current Route: ${e.path} (${r.length})`,tags:[C("active",ht)],children:r}},eo=(t,o)=>{let e=Y(t.globalSorted,t.global,exports.NavigationOutpostScopes.GLOBAL,"outpost",Dt),n=Y(t.routeSorted,t.route,exports.NavigationOutpostScopes.ROUTE,"outpost",Dt),a=[{id:Lt,label:"Outposts",children:[{id:bt,label:`Global (${e.length})`,tags:[C(exports.NavigationOutpostScopes.GLOBAL,z)],children:e},{id:Tt,label:`Route (${n.length})`,tags:[C(exports.NavigationOutpostScopes.ROUTE,M)],children:n}]}];return o&&(a.push(to(o)),a.push(oo(t,o))),a},no=(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}]}),ao=/^route-assignment-(.+)$/,ro=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(i=>!n.includes(i));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}]}},so=(t,o,e)=>{let n=t.match(ro);if(n){let[,a,i]=n,u=(a===exports.NavigationOutpostScopes.GLOBAL?o.global:o.route).get(i);return u?no(i,a,u):null}if(e){let a=t.match(ao);if(a){let i=a[1],r=e.getRoutes().find(u=>u.name?String(u.name)===i:u.path===i);return r?io(r,e):null}}return null},Gt=(t,o,e,n,a=false,i)=>{t.addInspector({id:w,label:F,icon:Nt}),t.on.getInspectorTree(r=>{r.inspectorId===w&&(r.rootNodes=eo(o,e));}),t.on.getInspectorState(r=>{if(r.inspectorId!==w)return;let u=so(r.nodeId,o,e);u&&(r.state=u);}),e.afterEach(()=>{at(t);}),y(exports.DebugPoints.DEVTOOLS_INSPECT,a,n,i);},at=t=>{t.sendInspectorTree(w),t.sendInspectorState(w);};});var N,kt=D(()=>{N={OFF:"off",LOG:"log",DEBUG:"debug"};});var uo,po,lo,rt,go,wt,Ht,$t,Bt=D(()=>{kt();K();uo=()=>{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}},po=t=>{if(!(typeof window>"u"||!window.localStorage))try{localStorage.setItem(et+nt,t);}catch{}},lo=(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}}},go=t=>t.debug?N.DEBUG:t.log?N.LOG:N.OFF,wt=(t,o,e)=>{let n=uo();if(n!==null)return rt(n);let a=lo(t,o,e);return rt(a)},Ht=(t,o)=>{let e=rt(o);t.log=e.log,t.debug=e.debug,po(o);},$t=t=>({logLevel:{label:"Log level",type:"choice",defaultValue:go(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:()=>mo,setupDevtools:()=>Oo});var X,Oo,mo,fo,Vt=D(()=>{k();K();Pt();Bt();X=null,Oo=(t,o,e,n,a,i,r,u)=>{let c=wt(i,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(f=>{f.key==="logLevel"&&Ht(a,f.newValue);}),Gt(g,o,e,n,a.debug,u);});},mo=()=>{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((i,r)=>{let u=n.get(i)?.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&>(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),ft=Symbol("timeout"),jt=t=>{let o;return {promise:new Promise((n,a)=>{o=setTimeout(()=>{let i=new Error(`Timeout after ${t}ms`);i[ft]=true,a(i);},t);}),cancel:()=>clearTimeout(o)}},Jt=async(t,o)=>{let{promise:e,cancel:n}=jt(o);try{return await Promise.race([t,e])}finally{n();}},Zt=t=>t instanceof Error&&ft in t,mt=async(t,o,e,n,a)=>{let{onError:i,defaultTimeout:r,onTimeout:u}=e,{router:c}=o,g=t.timeout??r;y(exports.DebugPoints.OUTPOST_ENTER,a.debug,n,e.debugHandler);try{let f=await t.getHandler(),O=g?await Jt(f(o),g):await f(o);return q(O,c)}catch(f){if(Zt(f)){if(n.warn(`Outpost "${t.name}" timed out after ${g}ms`),y(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(i&&f instanceof Error){let O=await i(f,o);return q(O,c)}return n.error(`Outpost "${t.name}" threw error:`,f),y(exports.DebugPoints.ERROR_CATCH,a.debug,n,e.debugHandler),exports.NavigationOutpostVerdicts.BLOCK}},Q=async(t,o,e,n,a)=>{let{hook:i,to:r,from:u}=o,c=a.log||a.debug,g=r.matched.flatMap(d=>d.meta?.outposts??[]),f=new Set(g);g.length!==f.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,i)}).length,B=t.routeSorted.filter(d=>{let R=t.route.get(d);return f.has(d)&&R&&V(R,i)}).length,E=I+B;if(E===0)return exports.NavigationOutpostVerdicts.ALLOW;c&&n.info(`${i}: ${u.path} -> ${r.path} (${E} outposts)`),y(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,i))continue;O++,c&&n.info(`Processing outpost ${O}/${E}: "${d}" [${i}]`);let S=await mt(R,o,e,n,a);if(S!==exports.NavigationOutpostVerdicts.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${d}":`,S),y(exports.DebugPoints.OUTPOST_BLOCK,a.debug,n,e.debugHandler),S}for(let d of t.routeSorted){if(!f.has(d))continue;let R=t.route.get(d);if(!R){n.warn(`Route outpost "${d}" not found in registry`);continue}if(!V(R,i))continue;O++,c&&n.info(`Processing outpost ${O}/${E}: "${d}" [${i}]`);let S=await mt(R,o,e,n,a);if(S!==exports.NavigationOutpostVerdicts.ALLOW)return c&&n.warn(`Patrol stopped by outpost "${d}":`,S),y(exports.DebugPoints.OUTPOST_BLOCK,a.debug,n,e.debugHandler),S}return exports.NavigationOutpostVerdicts.ALLOW},vt=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:i=P}=o,r=o.logger??exports.createDefaultLogger(),u=o.debugHandler??exports.createDefaultDebugHandler(),c=a&&typeof window<"u",g=lt(),f={...o,debugHandler:u},O={log:e??H,debug:n??false},I=[],B=(s,p,l)=>({verdicts:exports.NavigationOutpostVerdicts,to:s,from:p,router:t,hook:l}),E=()=>O.log||O.debug,d=s=>async(p,l)=>{let m=B(p,l,s),L=await Q(g,m,f,r,O);return vt(L)};I.push(t.beforeEach(d(exports.NavigationHooks.BEFORE_EACH))),I.push(t.beforeResolve(d(exports.NavigationHooks.BEFORE_RESOLVE)));let R=t.afterEach(async(s,p)=>{let l=B(s,p,exports.NavigationHooks.AFTER_EACH);try{await Q(g,l,f,r,O);}catch(m){r.error("Error in afterEach outpost:",m),y(exports.DebugPoints.ERROR_CATCH,O.debug,r,u);}});I.push(R);let S=s=>{let{scope:p="global",name:l,handler:m,priority:L,hooks:zt,timeout:Mt,lazy:j=false}=s,A=null,U=null,Kt=async()=>A||(j?(U||(U=m().then(h=>{if(!h.default||typeof h.default!="function")throw new Error(`Lazy outpost "${l}" must export default handler`);return A=h.default,A}).catch(h=>{throw U=null,h instanceof Error?h:new Error(String(h))})),U):(A=m,A));E()&&r.info(`Deploying ${p} outpost: ${l}${j?" (lazy)":""}`),ct(g,p,{name:l,getHandler:Kt,lazy:j,priority:L,hooks:zt,timeout:Mt},i,r),c&&W().then(h=>h?.notifyDevtoolsRefresh());},st=(s,p)=>{E()&&r.info(`Abandoning ${s} outpost: ${p}`);let l=dt(g,s,p,i);return c&&l&&W().then(m=>m?.notifyDevtoolsRefresh()),l},ut=s=>t.getRoutes().find(p=>p.name===s),pt={install(s){c&&W().then(p=>{p&&(p.setupDevtools(s,g,t,r,O,e,n,u),y(exports.DebugPoints.DEVTOOLS_INIT,O.debug,r,u),E()&&r.info("DevTools initialized via app.use(citadel)"));});},deployOutpost(s){if(Array.isArray(s))for(let p of s)S(p);else S(s);},abandonOutpost(s,p){if(Array.isArray(p)){let l=true;for(let m of p)st(s,m)||(l=false);return l}else return st(s,p)},getOutpostNames(s){return Ot(g,s)},assignOutpostToRoute(s,p){let l=ut(s);if(!l)return r.warn(`Route "${s}" not found`),false;let m=Array.isArray(p)?p:[p];l.meta.outposts||(l.meta.outposts=[]);for(let L of m)l.meta.outposts.includes(L)||l.meta.outposts.push(L);return E()&&r.info(`Assigned outposts [${m.join(", ")}] to route "${s}"`),true},revokeOutpostFromRoute(s,p){let l=ut(s);if(!l)return r.warn(`Route "${s}" not found`),false;let m=Array.isArray(p)?p:[p];if(!l.meta.outposts){for(let L of m)r.warn(`Outpost "${L}" not found in route "${s}"`);return true}for(let L of m)l.meta.outposts.includes(L)||r.warn(`Outpost "${L}" not found in route "${s}"`);return l.meta.outposts=l.meta.outposts.filter(L=>!m.includes(L)),E()&&r.info(`Revoked outposts [${m.join(", ")}] from route "${s}"`),true},destroy(){E()&&r.info("Destroying citadel");for(let s of I)s();I.length=0,g.global.clear(),g.route.clear(),g.globalSorted.length=0,g.routeSorted.length=0,c&&W().then(s=>s?.clearDevtoolsApi());}};return o.outposts&&pt.deployOutpost(o.outposts),pt};
|
|
2
|
-
exports.createNavigationCitadel=
|
|
1
|
+
'use strict';var devtoolsApi=require('@vue/devtools-api');var Wt=Object.defineProperty;var D=(t,o)=>()=>(t&&(o=t(t=0)),o);var jt=(t,o)=>{for(var e in o)Wt(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=D(()=>{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 k,x,P,H=D(()=>{k=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,$=D(()=>{H();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 Q,F,Nt,Rt,w,Lt,bt,Tt,Et,yt,St,tt,_t,z,M,Ct,ht,ot,et,K=D(()=>{G();Q="navigation.citadel",F="Navigation Citadel",Nt="castle",Rt="https://kassaila.github.io/vue-router-citadel/logo_devtools.svg",w=Q+".inspector",Lt="citadel-root",bt="citadel-"+exports.NavigationOutpostScopes.GLOBAL,Tt="citadel-"+exports.NavigationOutpostScopes.ROUTE,Et="citadel-route-assignments",yt="citadel-current-route",St=16777215,tt=4372867,_t=3900150,z=9133302,M=16096779,Ct=15485081,ht=1357990,ot="vue-router-citadel:settings:",et="logLevel";});var C,oo,eo,Y,Dt,It,xt,At,no,ro,ao,io,so,uo,po,lo,Gt,nt,Pt=D(()=>{G();H();$();K();C=(t,o)=>({label:t,textColor:St,backgroundColor:o}),oo=t=>t===exports.NavigationOutpostScopes.GLOBAL?z:M,eo=(t,o,e,n,r)=>(e.lazy&&r.push(C("lazy",Ct)),{id:`${t}-${n}-${o}`,label:o,tags:r}),Y=(t,o,e,n,r)=>{let i=[];for(let a of t){let u=o.get(a);u&&i.push(eo(n,a,u,e,r(u)));}return i},Dt=t=>{let o=t.hooks??[exports.NavigationHooks.BEFORE_EACH],e=t.priority??P;return [C(`priority: ${e}`,tt),C(o.length===1?o[0]:`${o.length} hooks`,_t)]},It=t=>o=>{let e=o.priority??P;return [C(t,oo(t)),C(`priority: ${e}`,tt)]},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??[]}},no=t=>{let o=[];for(let e of t.getRoutes()){let n=At(e,t);if(n.length===0)continue;let r=e.meta.outposts??[],i=n.filter(u=>!r.includes(u)).length,a=[C(`${n.length} outpost${n.length===1?"":"s"}`,M)];i>0&&a.push(C(`${i} inherited`,z)),o.push({id:`route-assignment-${xt(e)}`,label:xt(e),tags:a});}return {id:Et,label:`Route Assignments (${o.length})`,children:o}},ro=(t,o)=>{let e=o.currentRoute.value,n=Y(t.globalSorted,t.global,exports.NavigationOutpostScopes.GLOBAL,"current-route-outpost",It(exports.NavigationOutpostScopes.GLOBAL)),r=new Set(e.matched.flatMap(u=>u.meta?.outposts??[])),i=Y(t.routeSorted.filter(u=>r.has(u)),t.route,exports.NavigationOutpostScopes.ROUTE,"current-route-outpost",It(exports.NavigationOutpostScopes.ROUTE)),a=[...n,...i];return {id:yt,label:`Current Route: ${e.path} (${a.length})`,tags:[C("active",ht)],children:a}},ao=(t,o)=>{let e=Y(t.globalSorted,t.global,exports.NavigationOutpostScopes.GLOBAL,"outpost",Dt),n=Y(t.routeSorted,t.route,exports.NavigationOutpostScopes.ROUTE,"outpost",Dt),r=[{id:Lt,label:"Outposts",children:[{id:bt,label:`Global (${e.length})`,tags:[C(exports.NavigationOutpostScopes.GLOBAL,z)],children:e},{id:Tt,label:`Route (${n.length})`,tags:[C(exports.NavigationOutpostScopes.ROUTE,M)],children:n}]}];return o&&(r.push(no(o)),r.push(ro(t,o))),r},io=(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}]}),so=/^route-assignment-(.+)$/,uo=new RegExp(`^(?:outpost|current-route-outpost)-(${exports.NavigationOutpostScopes.GLOBAL}|${exports.NavigationOutpostScopes.ROUTE})-(.+)$`),po=(t,o)=>{let e=At(t,o),n=t.meta.outposts??[],r=e.filter(i=>!n.includes(i));return {"Route Details":[{key:"name",value:t.name?String(t.name):"unnamed"},{key:"path",value:t.path},{key:"outposts (own)",value:n},...r.length>0?[{key:"outposts (inherited)",value:r}]:[],{key:"outposts (resolved)",value:e}]}},lo=(t,o,e)=>{let n=t.match(uo);if(n){let[,r,i]=n,u=(r===exports.NavigationOutpostScopes.GLOBAL?o.global:o.route).get(i);return u?io(i,r,u):null}if(e){let r=t.match(so);if(r){let i=r[1],a=e.getRoutes().find(u=>u.name?String(u.name)===i:u.path===i);return a?po(a,e):null}}return null},Gt=(t,o,e,n,r=false,i)=>{t.addInspector({id:w,label:F,icon:Nt}),t.on.getInspectorTree(a=>{a.inspectorId===w&&(a.rootNodes=ao(o,e));}),t.on.getInspectorState(a=>{if(a.inspectorId!==w)return;let u=lo(a.nodeId,o,e);u&&(a.state=u);}),e.afterEach(()=>{nt(t);}),T(exports.DebugPoints.DEVTOOLS_INSPECT,r,n,i);},nt=t=>{t.sendInspectorTree(w),t.sendInspectorState(w);};});var m,Ht=D(()=>{m={OFF:"off",LOG:"log",DEBUG:"debug"};});var go,co,Oo,rt,vo,wt,kt,$t,Bt=D(()=>{Ht();K();go=()=>{if(typeof window>"u"||!window.localStorage)return null;try{let t=localStorage.getItem(ot+et);return t===null?null:t===m.OFF||t===m.LOG||t===m.DEBUG?t:null}catch{return null}},co=t=>{if(!(typeof window>"u"||!window.localStorage))try{localStorage.setItem(ot+et,t);}catch{}},Oo=(t,o,e)=>o?m.DEBUG:t??e?m.LOG:m.OFF,rt=t=>{switch(t){case m.LOG:return {log:true,debug:false};case m.DEBUG:return {log:true,debug:true};case m.OFF:default:return {log:false,debug:false}}},vo=t=>t.debug?m.DEBUG:t.log?m.LOG:m.OFF,wt=(t,o,e)=>{let n=go();if(n!==null)return rt(n);let r=Oo(t,o,e);return rt(r)},kt=(t,o)=>{let e=rt(o);t.log=e.log,t.debug=e.debug,co(o);},$t=t=>({logLevel:{label:"Log level",type:"choice",defaultValue:vo(t),options:[{label:"Off",value:m.OFF},{label:"Log",value:m.LOG},{label:"Log + Debug",value:m.DEBUG}],component:"button-group"}});});var Ut={};jt(Ut,{clearDevtoolsApi:()=>Ro,notifyDevtoolsRefresh:()=>No,setupDevtools:()=>fo});var X,fo,No,Ro,Vt=D(()=>{H();K();Pt();Bt();X=null,fo=(t,o,e,n,r,i,a,u)=>{let g=wt(i,a,k);r.log=g.log,r.debug=g.debug,devtoolsApi.setupDevToolsPlugin({id:Q,label:F,logo:Rt,packageName:"vue-router-citadel",homepage:"https://kassaila.github.io/vue-router-citadel",enableEarlyProxy:true,app:t,settings:$t(r)},c=>{X=c,c.on.setPluginSettings(N=>{N.key==="logLevel"&&kt(r,N.newValue);}),Gt(c,o,e,n,r.debug,u);});},No=()=>{X&&nt(X);},Ro=()=>{X=null;};});G();$();G();H();$();var pt=()=>({global:new Map,route:new Map,globalSorted:[],routeSorted:[]}),lt=(t,o,e)=>{let n=t[o],r=`${o}Sorted`;t[r]=Array.from(n.keys()).sort((i,a)=>{let u=n.get(i)?.priority??e,g=n.get(a)?.priority??e;return u-g});},gt=(t,o,e,n,r)=>{t[o].has(e.name)&&r.warn(`${o} outpost "${e.name}" already exists, replacing...`),t[o].set(e.name,e),lt(t,o,n);},ct=(t,o,e,n)=>{let r=t[o].delete(e);return r&<(t,o,n),r},dt=(t,o)=>Array.from(t[o].keys());G();H();$();var Jt=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},Ot=(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(Jt(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),mt=Symbol("timeout"),Zt=t=>{let o;return {promise:new Promise((n,r)=>{o=setTimeout(()=>{let i=new Error(`Timeout after ${t}ms`);i[mt]=true,r(i);},t);}),cancel:()=>clearTimeout(o)}},qt=async(t,o)=>{let{promise:e,cancel:n}=Zt(o);try{return await Promise.race([t,e])}finally{n();}},Qt=t=>t instanceof Error&&mt in t,to=t=>t instanceof Error?t:new Error(String(t)),vt=async(t,o,e,n,r)=>{let{router:i}=o,a=t.timeout??e.defaultTimeout;T(exports.DebugPoints.OUTPOST_ENTER,r.debug,n,e.debugHandler);let u=async g=>{try{return Ot(await g(),i)}catch(c){return n.error(`Recovery handler for "${t.name}" threw error:`,c),T(exports.DebugPoints.ERROR_CATCH,r.debug,n,e.debugHandler),exports.NavigationOutpostVerdicts.BLOCK}};try{let g=await t.getHandler(),c=a?await qt(g(o),a):await g(o);return Ot(c,i)}catch(g){if(Qt(g)){n.warn(`Outpost "${t.name}" timed out after ${a}ms`),T(exports.DebugPoints.OUTPOST_TIMEOUT,r.debug,n,e.debugHandler);let N=t.onTimeout??e.onTimeout;return N?u(()=>N(t.name,o)):exports.NavigationOutpostVerdicts.BLOCK}let c=t.onError??e.onError;if(c){let N=to(g);return u(()=>c(N,o))}return n.error(`Outpost "${t.name}" threw error:`,g),T(exports.DebugPoints.ERROR_CATCH,r.debug,n,e.debugHandler),exports.NavigationOutpostVerdicts.BLOCK}},q=async(t,o,e,n,r)=>{let{hook:i,to:a,from:u}=o,g=r.log||r.debug,c=a.matched.flatMap(d=>d.meta?.outposts??[]),N=new Set(c);c.length!==N.size&&n.warn(`Duplicate outposts detected on route "${String(a.name??a.path)}"`);let E=0,I=t.globalSorted.filter(d=>{let f=t.global.get(d);return f&&V(f,i)}).length,B=t.routeSorted.filter(d=>{let f=t.route.get(d);return N.has(d)&&f&&V(f,i)}).length,y=I+B;if(y===0)return exports.NavigationOutpostVerdicts.ALLOW;g&&n.info(`${i}: ${u.path} -> ${a.path} (${y} outposts)`),T(exports.DebugPoints.NAVIGATION_START,r.debug,n,e.debugHandler);for(let d of t.globalSorted){let f=t.global.get(d);if(!f||!V(f,i))continue;E++,g&&n.info(`Processing outpost ${E}/${y}: "${d}" [${i}]`);let S=await vt(f,o,e,n,r);if(S!==exports.NavigationOutpostVerdicts.ALLOW)return g&&n.warn(`Patrol stopped by outpost "${d}":`,S),T(exports.DebugPoints.OUTPOST_BLOCK,r.debug,n,e.debugHandler),S}for(let d of t.routeSorted){if(!N.has(d))continue;let f=t.route.get(d);if(!f){n.warn(`Route outpost "${d}" not found in registry`);continue}if(!V(f,i))continue;E++,g&&n.info(`Processing outpost ${E}/${y}: "${d}" [${i}]`);let S=await vt(f,o,e,n,r);if(S!==exports.NavigationOutpostVerdicts.ALLOW)return g&&n.warn(`Patrol stopped by outpost "${d}":`,S),T(exports.DebugPoints.OUTPOST_BLOCK,r.debug,n,e.debugHandler),S}return exports.NavigationOutpostVerdicts.ALLOW},ft=t=>{switch(t){case exports.NavigationOutpostVerdicts.ALLOW:return true;case exports.NavigationOutpostVerdicts.BLOCK:return false;default:return t}};var at=null,Ft=false,W=async()=>{if(Ft)return null;if(!at)try{at=await Promise.resolve().then(()=>(Vt(),Ut));}catch{return Ft=true,null}return at},Lo=(t,o={})=>{let{log:e,debug:n,devtools:r=k,defaultPriority:i=P}=o,a=o.logger??exports.createDefaultLogger(),u=o.debugHandler??exports.createDefaultDebugHandler(),g=r&&typeof window<"u",c=pt(),N={...o,debugHandler:u},E={log:e??k,debug:n??false},I=[],B=(s,p,l)=>({verdicts:exports.NavigationOutpostVerdicts,to:s,from:p,router:t,hook:l}),y=()=>E.log||E.debug,d=s=>async(p,l)=>{let O=B(p,l,s),b=await q(c,O,N,a,E);return ft(b)};I.push(t.beforeEach(d(exports.NavigationHooks.BEFORE_EACH))),I.push(t.beforeResolve(d(exports.NavigationHooks.BEFORE_RESOLVE)));let f=t.afterEach(async(s,p)=>{let l=B(s,p,exports.NavigationHooks.AFTER_EACH);try{await q(c,l,N,a,E);}catch(O){a.error("Error in afterEach outpost:",O),T(exports.DebugPoints.ERROR_CATCH,E.debug,a,u);}});I.push(f);let S=s=>{let{scope:p="global",name:l,handler:O,priority:b,hooks:zt,timeout:Mt,lazy:j=false,onError:Kt,onTimeout:Yt}=s,A=null,U=null,Xt=async()=>A||(j?(U||(U=O().then(h=>{if(!h.default||typeof h.default!="function")throw new Error(`Lazy outpost "${l}" must export default handler`);return A=h.default,A}).catch(h=>{throw U=null,h instanceof Error?h:new Error(String(h))})),U):(A=O,A));y()&&a.info(`Deploying ${p} outpost: ${l}${j?" (lazy)":""}`),gt(c,p,{name:l,getHandler:Xt,lazy:j,priority:b,hooks:zt,timeout:Mt,onError:Kt,onTimeout:Yt},i,a),g&&W().then(h=>h?.notifyDevtoolsRefresh());},it=(s,p)=>{y()&&a.info(`Abandoning ${s} outpost: ${p}`);let l=ct(c,s,p,i);return g&&l&&W().then(O=>O?.notifyDevtoolsRefresh()),l},st=s=>t.getRoutes().find(p=>p.name===s),ut={install(s){g&&W().then(p=>{p&&(p.setupDevtools(s,c,t,a,E,e,n,u),T(exports.DebugPoints.DEVTOOLS_INIT,E.debug,a,u),y()&&a.info("DevTools initialized via app.use(citadel)"));});},deployOutpost(s){if(Array.isArray(s))for(let p of s)S(p);else S(s);},abandonOutpost(s,p){if(Array.isArray(p)){let l=true;for(let O of p)it(s,O)||(l=false);return l}else return it(s,p)},getOutpostNames(s){return dt(c,s)},assignOutpostToRoute(s,p){let l=st(s);if(!l)return a.warn(`Route "${s}" not found`),false;let O=Array.isArray(p)?p:[p];l.meta.outposts||(l.meta.outposts=[]);for(let b of O)l.meta.outposts.includes(b)||l.meta.outposts.push(b);return y()&&a.info(`Assigned outposts [${O.join(", ")}] to route "${s}"`),true},revokeOutpostFromRoute(s,p){let l=st(s);if(!l)return a.warn(`Route "${s}" not found`),false;let O=Array.isArray(p)?p:[p];if(!l.meta.outposts){for(let b of O)a.warn(`Outpost "${b}" not found in route "${s}"`);return true}for(let b of O)l.meta.outposts.includes(b)||a.warn(`Outpost "${b}" not found in route "${s}"`);return l.meta.outposts=l.meta.outposts.filter(b=>!O.includes(b)),y()&&a.info(`Revoked outposts [${O.join(", ")}] from route "${s}"`),true},destroy(){y()&&a.info("Destroying citadel");for(let s of I)s();I.length=0,c.global.clear(),c.route.clear(),c.globalSorted.length=0,c.routeSorted.length=0,g&&W().then(s=>s?.clearDevtoolsApi());}};return o.outposts&&ut.deployOutpost(o.outposts),ut};
|
|
2
|
+
exports.createNavigationCitadel=Lo;
|
package/dist/index.d.cts
CHANGED
|
@@ -163,18 +163,57 @@ type NavigationOutpostOutcome = NavigationOutpostVerdict | RouteLocationRaw | Er
|
|
|
163
163
|
* Navigation outpost handler function signature
|
|
164
164
|
*/
|
|
165
165
|
type NavigationOutpostHandler = (ctx: NavigationOutpostContext) => NavigationOutpostOutcome | Promise<NavigationOutpostOutcome>;
|
|
166
|
+
/**
|
|
167
|
+
* Error handler signature — called when an outpost handler throws.
|
|
168
|
+
* Used for citadel-level `onError` and per-outpost `onError`.
|
|
169
|
+
*/
|
|
170
|
+
type NavigationOutpostErrorHandler = (error: Error, ctx: NavigationOutpostContext) => NavigationOutpostOutcome | Promise<NavigationOutpostOutcome>;
|
|
171
|
+
/**
|
|
172
|
+
* Timeout handler signature — called when an outpost exceeds its timeout.
|
|
173
|
+
* Used for citadel-level `onTimeout` and per-outpost `onTimeout`.
|
|
174
|
+
*/
|
|
175
|
+
type NavigationOutpostTimeoutHandler = (outpostName: string, ctx: NavigationOutpostContext) => NavigationOutpostOutcome | Promise<NavigationOutpostOutcome>;
|
|
166
176
|
/**
|
|
167
177
|
* Lazy outpost loader — returns a module with default export
|
|
168
178
|
*/
|
|
169
179
|
type LazyOutpostLoader = () => Promise<{
|
|
170
180
|
default: NavigationOutpostHandler;
|
|
171
181
|
}>;
|
|
182
|
+
/**
|
|
183
|
+
* Shared optional behavior for outposts. Used by both `NavigationOutpost` (deployment input)
|
|
184
|
+
* and `RegisteredNavigationOutpost` (runtime form).
|
|
185
|
+
*/
|
|
186
|
+
interface OutpostBehaviorOptions {
|
|
187
|
+
/**
|
|
188
|
+
* Priority for outposts (lower = processed first). Default: 100
|
|
189
|
+
*/
|
|
190
|
+
priority?: number;
|
|
191
|
+
/**
|
|
192
|
+
* Hooks this outpost should run on. Default: ['beforeEach']
|
|
193
|
+
*/
|
|
194
|
+
hooks?: NavigationHook[];
|
|
195
|
+
/**
|
|
196
|
+
* Timeout for this outpost in milliseconds. Overrides defaultTimeout.
|
|
197
|
+
* Note: For lazy outposts, timeout applies only to handler execution, not module loading.
|
|
198
|
+
*/
|
|
199
|
+
timeout?: number;
|
|
200
|
+
/**
|
|
201
|
+
* Per-outpost error handler. Replaces the citadel-level `onError` for this outpost.
|
|
202
|
+
* If absent, falls back to the citadel-level `onError`, then to the default behavior (BLOCK).
|
|
203
|
+
*/
|
|
204
|
+
onError?: NavigationOutpostErrorHandler;
|
|
205
|
+
/**
|
|
206
|
+
* Per-outpost timeout handler. Replaces the citadel-level `onTimeout` for this outpost.
|
|
207
|
+
* If absent, falls back to the citadel-level `onTimeout`, then to the default behavior (BLOCK).
|
|
208
|
+
*/
|
|
209
|
+
onTimeout?: NavigationOutpostTimeoutHandler;
|
|
210
|
+
}
|
|
172
211
|
/**
|
|
173
212
|
* Navigation outpost configuration.
|
|
174
213
|
* Generic parameter S constrains the name field based on scope.
|
|
175
214
|
* Generic parameter L constrains handler type based on lazy flag.
|
|
176
215
|
*/
|
|
177
|
-
interface NavigationOutpost<S extends NavigationOutpostScope = 'global', L extends boolean = false> {
|
|
216
|
+
interface NavigationOutpost<S extends NavigationOutpostScope = 'global', L extends boolean = false> extends OutpostBehaviorOptions {
|
|
178
217
|
/**
|
|
179
218
|
* Outpost scope. Default: 'global'
|
|
180
219
|
*/
|
|
@@ -189,19 +228,6 @@ interface NavigationOutpost<S extends NavigationOutpostScope = 'global', L exten
|
|
|
189
228
|
* When lazy: false (default), must be a NavigationOutpostHandler.
|
|
190
229
|
*/
|
|
191
230
|
handler: L extends true ? LazyOutpostLoader : NavigationOutpostHandler;
|
|
192
|
-
/**
|
|
193
|
-
* Priority for outposts (lower = processed first). Default: 100
|
|
194
|
-
*/
|
|
195
|
-
priority?: number;
|
|
196
|
-
/**
|
|
197
|
-
* Hooks this outpost should run on. Default: ['beforeEach']
|
|
198
|
-
*/
|
|
199
|
-
hooks?: NavigationHook[];
|
|
200
|
-
/**
|
|
201
|
-
* Timeout for this outpost in milliseconds. Overrides defaultTimeout.
|
|
202
|
-
* Note: For lazy outposts, timeout applies only to handler execution, not module loading.
|
|
203
|
-
*/
|
|
204
|
-
timeout?: number;
|
|
205
231
|
/**
|
|
206
232
|
* Mark handler as lazy-loaded. Default: false.
|
|
207
233
|
* When true, handler must return Promise<{ default: NavigationOutpostHandler }>.
|
|
@@ -215,7 +241,7 @@ interface NavigationCitadelOptions {
|
|
|
215
241
|
/**
|
|
216
242
|
* Initial outposts to deploy on citadel creation
|
|
217
243
|
*/
|
|
218
|
-
outposts?: NavigationOutpost<NavigationOutpostScope, boolean
|
|
244
|
+
outposts?: Array<NavigationOutpost<NavigationOutpostScope, boolean>>;
|
|
219
245
|
/**
|
|
220
246
|
* Enable logging for non-critical events. Default: __DEV__
|
|
221
247
|
* Critical events (errors, timeouts) are always logged regardless of this setting.
|
|
@@ -260,7 +286,7 @@ interface NavigationCitadelOptions {
|
|
|
260
286
|
/**
|
|
261
287
|
* Global error handler
|
|
262
288
|
*/
|
|
263
|
-
onError?:
|
|
289
|
+
onError?: NavigationOutpostErrorHandler;
|
|
264
290
|
/**
|
|
265
291
|
* Default priority for outposts. Default: 100
|
|
266
292
|
*/
|
|
@@ -272,7 +298,7 @@ interface NavigationCitadelOptions {
|
|
|
272
298
|
/**
|
|
273
299
|
* Handler called when outpost times out
|
|
274
300
|
*/
|
|
275
|
-
onTimeout?:
|
|
301
|
+
onTimeout?: NavigationOutpostTimeoutHandler;
|
|
276
302
|
}
|
|
277
303
|
/**
|
|
278
304
|
* Public API returned by createNavigationCitadel
|
|
@@ -286,7 +312,7 @@ interface NavigationCitadelAPI {
|
|
|
286
312
|
/**
|
|
287
313
|
* Deploy one or multiple outposts
|
|
288
314
|
*/
|
|
289
|
-
deployOutpost: <S extends NavigationOutpostScope = 'global', L extends boolean = false>(options: NavigationOutpost<S, L> | NavigationOutpost<S, L
|
|
315
|
+
deployOutpost: <S extends NavigationOutpostScope = 'global', L extends boolean = false>(options: NavigationOutpost<S, L> | Array<NavigationOutpost<S, L>>) => void;
|
|
290
316
|
/**
|
|
291
317
|
* Remove one or multiple global outposts by name(s)
|
|
292
318
|
*/
|
|
@@ -369,4 +395,4 @@ declare const createDefaultDebugHandler: () => DebugHandler;
|
|
|
369
395
|
*/
|
|
370
396
|
declare const createNavigationCitadel: (router: Router, options?: NavigationCitadelOptions) => NavigationCitadelAPI;
|
|
371
397
|
|
|
372
|
-
export { type CitadelLogger, type DebugHandler, type DebugPoint, DebugPoints, type GlobalOutpostName, type GlobalOutpostRegistry, type LazyOutpostLoader, type NavigationCitadelAPI, type NavigationCitadelOptions, type NavigationHook, NavigationHooks, type NavigationOutpost, type NavigationOutpostContext, type NavigationOutpostHandler, type NavigationOutpostScope, NavigationOutpostScopes, NavigationOutpostVerdicts, type OutpostName, type RouteOutpostName, type RouteOutpostRegistry, createDefaultDebugHandler, createDefaultLogger, createNavigationCitadel };
|
|
398
|
+
export { type CitadelLogger, type DebugHandler, type DebugPoint, DebugPoints, type GlobalOutpostName, type GlobalOutpostRegistry, type LazyOutpostLoader, type NavigationCitadelAPI, type NavigationCitadelOptions, type NavigationHook, NavigationHooks, type NavigationOutpost, type NavigationOutpostContext, type NavigationOutpostErrorHandler, type NavigationOutpostHandler, type NavigationOutpostScope, NavigationOutpostScopes, type NavigationOutpostTimeoutHandler, NavigationOutpostVerdicts, type OutpostBehaviorOptions, type OutpostName, type RouteOutpostName, type RouteOutpostRegistry, createDefaultDebugHandler, createDefaultLogger, createNavigationCitadel };
|
package/dist/index.d.ts
CHANGED
|
@@ -163,18 +163,57 @@ type NavigationOutpostOutcome = NavigationOutpostVerdict | RouteLocationRaw | Er
|
|
|
163
163
|
* Navigation outpost handler function signature
|
|
164
164
|
*/
|
|
165
165
|
type NavigationOutpostHandler = (ctx: NavigationOutpostContext) => NavigationOutpostOutcome | Promise<NavigationOutpostOutcome>;
|
|
166
|
+
/**
|
|
167
|
+
* Error handler signature — called when an outpost handler throws.
|
|
168
|
+
* Used for citadel-level `onError` and per-outpost `onError`.
|
|
169
|
+
*/
|
|
170
|
+
type NavigationOutpostErrorHandler = (error: Error, ctx: NavigationOutpostContext) => NavigationOutpostOutcome | Promise<NavigationOutpostOutcome>;
|
|
171
|
+
/**
|
|
172
|
+
* Timeout handler signature — called when an outpost exceeds its timeout.
|
|
173
|
+
* Used for citadel-level `onTimeout` and per-outpost `onTimeout`.
|
|
174
|
+
*/
|
|
175
|
+
type NavigationOutpostTimeoutHandler = (outpostName: string, ctx: NavigationOutpostContext) => NavigationOutpostOutcome | Promise<NavigationOutpostOutcome>;
|
|
166
176
|
/**
|
|
167
177
|
* Lazy outpost loader — returns a module with default export
|
|
168
178
|
*/
|
|
169
179
|
type LazyOutpostLoader = () => Promise<{
|
|
170
180
|
default: NavigationOutpostHandler;
|
|
171
181
|
}>;
|
|
182
|
+
/**
|
|
183
|
+
* Shared optional behavior for outposts. Used by both `NavigationOutpost` (deployment input)
|
|
184
|
+
* and `RegisteredNavigationOutpost` (runtime form).
|
|
185
|
+
*/
|
|
186
|
+
interface OutpostBehaviorOptions {
|
|
187
|
+
/**
|
|
188
|
+
* Priority for outposts (lower = processed first). Default: 100
|
|
189
|
+
*/
|
|
190
|
+
priority?: number;
|
|
191
|
+
/**
|
|
192
|
+
* Hooks this outpost should run on. Default: ['beforeEach']
|
|
193
|
+
*/
|
|
194
|
+
hooks?: NavigationHook[];
|
|
195
|
+
/**
|
|
196
|
+
* Timeout for this outpost in milliseconds. Overrides defaultTimeout.
|
|
197
|
+
* Note: For lazy outposts, timeout applies only to handler execution, not module loading.
|
|
198
|
+
*/
|
|
199
|
+
timeout?: number;
|
|
200
|
+
/**
|
|
201
|
+
* Per-outpost error handler. Replaces the citadel-level `onError` for this outpost.
|
|
202
|
+
* If absent, falls back to the citadel-level `onError`, then to the default behavior (BLOCK).
|
|
203
|
+
*/
|
|
204
|
+
onError?: NavigationOutpostErrorHandler;
|
|
205
|
+
/**
|
|
206
|
+
* Per-outpost timeout handler. Replaces the citadel-level `onTimeout` for this outpost.
|
|
207
|
+
* If absent, falls back to the citadel-level `onTimeout`, then to the default behavior (BLOCK).
|
|
208
|
+
*/
|
|
209
|
+
onTimeout?: NavigationOutpostTimeoutHandler;
|
|
210
|
+
}
|
|
172
211
|
/**
|
|
173
212
|
* Navigation outpost configuration.
|
|
174
213
|
* Generic parameter S constrains the name field based on scope.
|
|
175
214
|
* Generic parameter L constrains handler type based on lazy flag.
|
|
176
215
|
*/
|
|
177
|
-
interface NavigationOutpost<S extends NavigationOutpostScope = 'global', L extends boolean = false> {
|
|
216
|
+
interface NavigationOutpost<S extends NavigationOutpostScope = 'global', L extends boolean = false> extends OutpostBehaviorOptions {
|
|
178
217
|
/**
|
|
179
218
|
* Outpost scope. Default: 'global'
|
|
180
219
|
*/
|
|
@@ -189,19 +228,6 @@ interface NavigationOutpost<S extends NavigationOutpostScope = 'global', L exten
|
|
|
189
228
|
* When lazy: false (default), must be a NavigationOutpostHandler.
|
|
190
229
|
*/
|
|
191
230
|
handler: L extends true ? LazyOutpostLoader : NavigationOutpostHandler;
|
|
192
|
-
/**
|
|
193
|
-
* Priority for outposts (lower = processed first). Default: 100
|
|
194
|
-
*/
|
|
195
|
-
priority?: number;
|
|
196
|
-
/**
|
|
197
|
-
* Hooks this outpost should run on. Default: ['beforeEach']
|
|
198
|
-
*/
|
|
199
|
-
hooks?: NavigationHook[];
|
|
200
|
-
/**
|
|
201
|
-
* Timeout for this outpost in milliseconds. Overrides defaultTimeout.
|
|
202
|
-
* Note: For lazy outposts, timeout applies only to handler execution, not module loading.
|
|
203
|
-
*/
|
|
204
|
-
timeout?: number;
|
|
205
231
|
/**
|
|
206
232
|
* Mark handler as lazy-loaded. Default: false.
|
|
207
233
|
* When true, handler must return Promise<{ default: NavigationOutpostHandler }>.
|
|
@@ -215,7 +241,7 @@ interface NavigationCitadelOptions {
|
|
|
215
241
|
/**
|
|
216
242
|
* Initial outposts to deploy on citadel creation
|
|
217
243
|
*/
|
|
218
|
-
outposts?: NavigationOutpost<NavigationOutpostScope, boolean
|
|
244
|
+
outposts?: Array<NavigationOutpost<NavigationOutpostScope, boolean>>;
|
|
219
245
|
/**
|
|
220
246
|
* Enable logging for non-critical events. Default: __DEV__
|
|
221
247
|
* Critical events (errors, timeouts) are always logged regardless of this setting.
|
|
@@ -260,7 +286,7 @@ interface NavigationCitadelOptions {
|
|
|
260
286
|
/**
|
|
261
287
|
* Global error handler
|
|
262
288
|
*/
|
|
263
|
-
onError?:
|
|
289
|
+
onError?: NavigationOutpostErrorHandler;
|
|
264
290
|
/**
|
|
265
291
|
* Default priority for outposts. Default: 100
|
|
266
292
|
*/
|
|
@@ -272,7 +298,7 @@ interface NavigationCitadelOptions {
|
|
|
272
298
|
/**
|
|
273
299
|
* Handler called when outpost times out
|
|
274
300
|
*/
|
|
275
|
-
onTimeout?:
|
|
301
|
+
onTimeout?: NavigationOutpostTimeoutHandler;
|
|
276
302
|
}
|
|
277
303
|
/**
|
|
278
304
|
* Public API returned by createNavigationCitadel
|
|
@@ -286,7 +312,7 @@ interface NavigationCitadelAPI {
|
|
|
286
312
|
/**
|
|
287
313
|
* Deploy one or multiple outposts
|
|
288
314
|
*/
|
|
289
|
-
deployOutpost: <S extends NavigationOutpostScope = 'global', L extends boolean = false>(options: NavigationOutpost<S, L> | NavigationOutpost<S, L
|
|
315
|
+
deployOutpost: <S extends NavigationOutpostScope = 'global', L extends boolean = false>(options: NavigationOutpost<S, L> | Array<NavigationOutpost<S, L>>) => void;
|
|
290
316
|
/**
|
|
291
317
|
* Remove one or multiple global outposts by name(s)
|
|
292
318
|
*/
|
|
@@ -369,4 +395,4 @@ declare const createDefaultDebugHandler: () => DebugHandler;
|
|
|
369
395
|
*/
|
|
370
396
|
declare const createNavigationCitadel: (router: Router, options?: NavigationCitadelOptions) => NavigationCitadelAPI;
|
|
371
397
|
|
|
372
|
-
export { type CitadelLogger, type DebugHandler, type DebugPoint, DebugPoints, type GlobalOutpostName, type GlobalOutpostRegistry, type LazyOutpostLoader, type NavigationCitadelAPI, type NavigationCitadelOptions, type NavigationHook, NavigationHooks, type NavigationOutpost, type NavigationOutpostContext, type NavigationOutpostHandler, type NavigationOutpostScope, NavigationOutpostScopes, NavigationOutpostVerdicts, type OutpostName, type RouteOutpostName, type RouteOutpostRegistry, createDefaultDebugHandler, createDefaultLogger, createNavigationCitadel };
|
|
398
|
+
export { type CitadelLogger, type DebugHandler, type DebugPoint, DebugPoints, type GlobalOutpostName, type GlobalOutpostRegistry, type LazyOutpostLoader, type NavigationCitadelAPI, type NavigationCitadelOptions, type NavigationHook, NavigationHooks, type NavigationOutpost, type NavigationOutpostContext, type NavigationOutpostErrorHandler, type NavigationOutpostHandler, type NavigationOutpostScope, NavigationOutpostScopes, type NavigationOutpostTimeoutHandler, NavigationOutpostVerdicts, type OutpostBehaviorOptions, type OutpostName, type RouteOutpostName, type RouteOutpostRegistry, createDefaultDebugHandler, createDefaultLogger, createNavigationCitadel };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {g,e,h,i,a,j as j$1,d,b,f}from'./chunk-
|
|
1
|
+
import {g,e,h,i,a,j as j$1,d,b,f}from'./chunk-W4ASYKYO.js';export{d as DebugPoints,a as NavigationHooks,c as NavigationOutpostScopes,b as NavigationOutpostVerdicts,i as createDefaultDebugHandler,h as createDefaultLogger}from'./chunk-W4ASYKYO.js';var F=()=>({global:new Map,route:new Map,globalSorted:[],routeSorted:[]}),K=(t,o,r)=>{let n=t[o],u=`${o}Sorted`;t[u]=Array.from(n.keys()).sort((c,a)=>{let y=n.get(c)?.priority??r,l=n.get(a)?.priority??r;return y-l});},U=(t,o,r,n,u)=>{t[o].has(r.name)&&u.warn(`${o} outpost "${r.name}" already exists, replacing...`),t[o].set(r.name,r),K(t,o,n);},W=(t,o,r,n)=>{let u=t[o].delete(r);return u&&K(t,o,n),u},j=(t,o)=>Array.from(t[o].keys());var it=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},Y=(t,o)=>{if(t instanceof Error)throw t;if(Object.values(b).includes(t))return t;let r=`${f} Invalid outpost outcome: ${JSON.stringify(t)}.`;if(it(t)){if(o.resolve(t).matched.length===0)throw new Error(r+` Route not found: ${JSON.stringify(t)}`);return t}throw new Error(r+" Expected: verdicts.ALLOW, verdicts.BLOCK, or RouteLocationRaw (string path or object with name/path).")},H=(t,o)=>(t.hooks??[a.BEFORE_EACH]).includes(o),X=Symbol("timeout"),at=t=>{let o;return {promise:new Promise((n,u)=>{o=setTimeout(()=>{let c=new Error(`Timeout after ${t}ms`);c[X]=true,u(c);},t);}),cancel:()=>clearTimeout(o)}},st=async(t,o)=>{let{promise:r,cancel:n}=at(o);try{return await Promise.race([t,r])}finally{n();}},ut=t=>t instanceof Error&&X in t,lt=t=>t instanceof Error?t:new Error(String(t)),J=async(t,o,r,n,u)=>{let{router:c}=o,a=t.timeout??r.defaultTimeout;j$1(d.OUTPOST_ENTER,u.debug,n,r.debugHandler);let y=async l=>{try{return Y(await l(),c)}catch(p){return n.error(`Recovery handler for "${t.name}" threw error:`,p),j$1(d.ERROR_CATCH,u.debug,n,r.debugHandler),b.BLOCK}};try{let l=await t.getHandler(),p=a?await st(l(o),a):await l(o);return Y(p,c)}catch(l){if(ut(l)){n.warn(`Outpost "${t.name}" timed out after ${a}ms`),j$1(d.OUTPOST_TIMEOUT,u.debug,n,r.debugHandler);let R=t.onTimeout??r.onTimeout;return R?y(()=>R(t.name,o)):b.BLOCK}let p=t.onError??r.onError;if(p){let R=lt(l);return y(()=>p(R,o))}return n.error(`Outpost "${t.name}" threw error:`,l),j$1(d.ERROR_CATCH,u.debug,n,r.debugHandler),b.BLOCK}},x=async(t,o,r,n,u)=>{let{hook:c,to:a,from:y}=o,l=u.log||u.debug,p=a.matched.flatMap(d=>d.meta?.outposts??[]),R=new Set(p);p.length!==R.size&&n.warn(`Duplicate outposts detected on route "${String(a.name??a.path)}"`);let m=0,C=t.globalSorted.filter(d=>{let f=t.global.get(d);return f&&H(f,c)}).length,$=t.routeSorted.filter(d=>{let f=t.route.get(d);return R.has(d)&&f&&H(f,c)}).length,b$1=C+$;if(b$1===0)return b.ALLOW;l&&n.info(`${c}: ${y.path} -> ${a.path} (${b$1} outposts)`),j$1(d.NAVIGATION_START,u.debug,n,r.debugHandler);for(let d$1 of t.globalSorted){let f=t.global.get(d$1);if(!f||!H(f,c))continue;m++,l&&n.info(`Processing outpost ${m}/${b$1}: "${d$1}" [${c}]`);let E=await J(f,o,r,n,u);if(E!==b.ALLOW)return l&&n.warn(`Patrol stopped by outpost "${d$1}":`,E),j$1(d.OUTPOST_BLOCK,u.debug,n,r.debugHandler),E}for(let d$1 of t.routeSorted){if(!R.has(d$1))continue;let f=t.route.get(d$1);if(!f){n.warn(`Route outpost "${d$1}" not found in registry`);continue}if(!H(f,c))continue;m++,l&&n.info(`Processing outpost ${m}/${b$1}: "${d$1}" [${c}]`);let E=await J(f,o,r,n,u);if(E!==b.ALLOW)return l&&n.warn(`Patrol stopped by outpost "${d$1}":`,E),j$1(d.OUTPOST_BLOCK,u.debug,n,r.debugHandler),E}return b.ALLOW},q=t=>{switch(t){case b.ALLOW:return true;case b.BLOCK:return false;default:return t}};var I=null,Q=false,P=async()=>{if(Q)return null;if(!I)try{I=await import('./devtools-OVHNQHN4.js');}catch{return Q=true,null}return I},pt=(t,o={})=>{let{log:r,debug:n,devtools:u=e,defaultPriority:c=g}=o,a$1=o.logger??h(),y=o.debugHandler??i(),l=u&&typeof window<"u",p=F(),R={...o,debugHandler:y},m={log:r??e,debug:n??false},C=[],$=(e,i,s)=>({verdicts:b,to:e,from:i,router:t,hook:s}),b$1=()=>m.log||m.debug,d$1=e=>async(i,s)=>{let g=$(i,s,e),v=await x(p,g,R,a$1,m);return q(v)};C.push(t.beforeEach(d$1(a.BEFORE_EACH))),C.push(t.beforeResolve(d$1(a.BEFORE_RESOLVE)));let f=t.afterEach(async(e,i)=>{let s=$(e,i,a.AFTER_EACH);try{await x(p,s,R,a$1,m);}catch(g){a$1.error("Error in afterEach outpost:",g),j$1(d.ERROR_CATCH,m.debug,a$1,y);}});C.push(f);let E=e=>{let{scope:i="global",name:s,handler:g,priority:v,hooks:Z,timeout:tt,lazy:S=false,onError:ot,onTimeout:et}=e,w=null,A=null,nt=async()=>w||(S?(A||(A=g().then(T=>{if(!T.default||typeof T.default!="function")throw new Error(`Lazy outpost "${s}" must export default handler`);return w=T.default,w}).catch(T=>{throw A=null,T instanceof Error?T:new Error(String(T))})),A):(w=g,w));b$1()&&a$1.info(`Deploying ${i} outpost: ${s}${S?" (lazy)":""}`),U(p,i,{name:s,getHandler:nt,lazy:S,priority:v,hooks:Z,timeout:tt,onError:ot,onTimeout:et},c,a$1),l&&P().then(T=>T?.notifyDevtoolsRefresh());},z=(e,i)=>{b$1()&&a$1.info(`Abandoning ${e} outpost: ${i}`);let s=W(p,e,i,c);return l&&s&&P().then(g=>g?.notifyDevtoolsRefresh()),s},B=e=>t.getRoutes().find(i=>i.name===e),M={install(e){l&&P().then(i=>{i&&(i.setupDevtools(e,p,t,a$1,m,r,n,y),j$1(d.DEVTOOLS_INIT,m.debug,a$1,y),b$1()&&a$1.info("DevTools initialized via app.use(citadel)"));});},deployOutpost(e){if(Array.isArray(e))for(let i of e)E(i);else E(e);},abandonOutpost(e,i){if(Array.isArray(i)){let s=true;for(let g of i)z(e,g)||(s=false);return s}else return z(e,i)},getOutpostNames(e){return j(p,e)},assignOutpostToRoute(e,i){let s=B(e);if(!s)return a$1.warn(`Route "${e}" not found`),false;let g=Array.isArray(i)?i:[i];s.meta.outposts||(s.meta.outposts=[]);for(let v of g)s.meta.outposts.includes(v)||s.meta.outposts.push(v);return b$1()&&a$1.info(`Assigned outposts [${g.join(", ")}] to route "${e}"`),true},revokeOutpostFromRoute(e,i){let s=B(e);if(!s)return a$1.warn(`Route "${e}" not found`),false;let g=Array.isArray(i)?i:[i];if(!s.meta.outposts){for(let v of g)a$1.warn(`Outpost "${v}" not found in route "${e}"`);return true}for(let v of g)s.meta.outposts.includes(v)||a$1.warn(`Outpost "${v}" not found in route "${e}"`);return s.meta.outposts=s.meta.outposts.filter(v=>!g.includes(v)),b$1()&&a$1.info(`Revoked outposts [${g.join(", ")}] from route "${e}"`),true},destroy(){b$1()&&a$1.info("Destroying citadel");for(let e of C)e();C.length=0,p.global.clear(),p.route.clear(),p.globalSorted.length=0,p.routeSorted.length=0,l&&P().then(e=>e?.clearDevtoolsApi());}};return o.outposts&&M.deployOutpost(o.outposts),M};export{pt as createNavigationCitadel};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-router-citadel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Structured navigation defense for Vue Router",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -62,9 +62,6 @@
|
|
|
62
62
|
],
|
|
63
63
|
"author": "Kassaila",
|
|
64
64
|
"license": "MIT",
|
|
65
|
-
"engines": {
|
|
66
|
-
"node": ">=22.0.0"
|
|
67
|
-
},
|
|
68
65
|
"repository": {
|
|
69
66
|
"type": "git",
|
|
70
67
|
"url": "git+https://github.com/Kassaila/vue-router-citadel.git"
|
|
@@ -81,25 +78,28 @@
|
|
|
81
78
|
"@vue/devtools-api": "^8.0.5"
|
|
82
79
|
},
|
|
83
80
|
"devDependencies": {
|
|
84
|
-
"@commitlint/cli": "^20.
|
|
85
|
-
"@commitlint/config-conventional": "^20.
|
|
86
|
-
"@eslint/js": "^
|
|
87
|
-
"@size-limit/preset-small-lib": "^12.0.
|
|
88
|
-
"@
|
|
89
|
-
"@
|
|
90
|
-
"
|
|
81
|
+
"@commitlint/cli": "^20.5.0",
|
|
82
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
83
|
+
"@eslint/js": "^10.0.1",
|
|
84
|
+
"@size-limit/preset-small-lib": "^12.0.1",
|
|
85
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
86
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
87
|
+
"@vue/devtools-kit": "^8.1.1",
|
|
88
|
+
"eslint": "^10.1.0",
|
|
91
89
|
"eslint-config-prettier": "^10.1.8",
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
90
|
+
"eslint-plugin-import-x": "^4.16.2",
|
|
91
|
+
"eslint-plugin-kassaila": "^0.2.0",
|
|
92
|
+
"happy-dom": "^20.8.8",
|
|
93
|
+
"husky": "^9.1.7",
|
|
94
|
+
"lint-staged": "^16.4.0",
|
|
95
|
+
"prettier": "^3.8.1",
|
|
96
|
+
"size-limit": "^12.0.1",
|
|
97
|
+
"tsup": "^8.5.1",
|
|
98
|
+
"typescript": "^5.9.3",
|
|
99
|
+
"typescript-eslint": "^8.57.2",
|
|
100
100
|
"vitepress": "^1.6.4",
|
|
101
|
-
"vitepress-
|
|
102
|
-
"vitest": "^4.
|
|
101
|
+
"vitepress-mermaid-viewer": "^0.4.0",
|
|
102
|
+
"vitest": "^4.1.2",
|
|
103
103
|
"vue": "^3.5.27",
|
|
104
104
|
"vue-router": "^5.0.2"
|
|
105
105
|
}
|