vue-accessguard 1.0.0 → 1.0.2
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/README.md +8 -3
- package/dist/vue-access-guard.es.js +61 -50
- package/dist/vue-access-guard.umd.js +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="
|
|
2
|
+
<img src="https://unpkg.com/vue-accessguard/dist/logo.png" alt="AccessGuard Logo" width="100%" />
|
|
3
3
|
</div>
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# vue-accessguard
|
|
6
6
|
|
|
7
7
|
The **vue-accessguard** library is a robust, lightweight **Role-Based Access Control (RBAC)** solution for **Vue 3** applications. It provides granular control over UI rendering and module protection using Directives, Components, and Composables for protecting views depending on user *roles* or *permissions*. It supports dynamic **Wildcard Matching** (e.g. `*` for Super Admin or `resource:*` for namespaces).
|
|
8
8
|
|
|
@@ -169,7 +169,12 @@ Vue-accessguard scales linearly with enterprise needs with built in string-based
|
|
|
169
169
|
|
|
170
170
|
## Storybook
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
Interactive visual documentation is available online:
|
|
173
|
+
👉 **[View Live Storybook Documentation](https://sawalabs.github.io/Vue-AccessGuard/)**
|
|
174
|
+
|
|
175
|
+
### Running Locally
|
|
176
|
+
|
|
177
|
+
You can also visually test permission mocking by launching Storybook locally:
|
|
173
178
|
|
|
174
179
|
```bash
|
|
175
180
|
pnpm run storybook
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
const
|
|
1
|
+
import { defineComponent as f, toRef as v, provide as h, effectScope as G, watchEffect as w, inject as S, computed as R } from "vue";
|
|
2
|
+
const i = Symbol("AccessGuard"), x = f({
|
|
3
3
|
name: "AccessGuardProvider",
|
|
4
4
|
props: {
|
|
5
5
|
user: {
|
|
@@ -8,65 +8,73 @@ const u = /* @__PURE__ */ Symbol("AccessGuard"), b = l({
|
|
|
8
8
|
}
|
|
9
9
|
},
|
|
10
10
|
setup(r, { slots: n }) {
|
|
11
|
-
const
|
|
12
|
-
return
|
|
13
|
-
user:
|
|
14
|
-
}), () =>
|
|
11
|
+
const c = v(r, "user");
|
|
12
|
+
return h(i, {
|
|
13
|
+
user: c
|
|
14
|
+
}), () => {
|
|
15
|
+
var t;
|
|
16
|
+
return (t = n.default) == null ? void 0 : t.call(n);
|
|
17
|
+
};
|
|
15
18
|
}
|
|
16
19
|
});
|
|
17
|
-
function
|
|
18
|
-
if (!r
|
|
19
|
-
const t = Array.isArray(n) ? n : [n], e = (
|
|
20
|
-
if (r.includes("*") || r.includes(
|
|
21
|
-
const [
|
|
22
|
-
return r.includes(
|
|
20
|
+
function m(r, n, c = "any") {
|
|
21
|
+
if (!(r != null && r.length)) return !1;
|
|
22
|
+
const t = Array.isArray(n) ? n : [n], e = (s) => {
|
|
23
|
+
if (r.includes("*") || r.includes(s)) return !0;
|
|
24
|
+
const [o] = s.split(":"), a = `${o}:*`;
|
|
25
|
+
return r.includes(a);
|
|
23
26
|
};
|
|
24
|
-
return
|
|
27
|
+
return c === "all" ? t.every(e) : t.some(e);
|
|
25
28
|
}
|
|
26
|
-
const
|
|
29
|
+
const b = {
|
|
27
30
|
mounted(r, n) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
var o;
|
|
32
|
+
const c = n.instance;
|
|
33
|
+
if (!c) return;
|
|
34
|
+
let t = c.$.parent, e;
|
|
31
35
|
for (; t && !e; )
|
|
32
|
-
e = t.provides
|
|
36
|
+
e = (o = t.provides) == null ? void 0 : o[i], t = t.parent;
|
|
33
37
|
if (!e)
|
|
34
38
|
throw new Error("[AccessGuard] v-can used outside AccessGuardProvider");
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const s = G();
|
|
40
|
+
s.run(() => {
|
|
41
|
+
w(() => {
|
|
42
|
+
var l;
|
|
43
|
+
const a = n.value;
|
|
44
|
+
let u, d = "any";
|
|
45
|
+
typeof a == "string" || Array.isArray(a) ? u = a : (u = a.permission, d = a.mode ?? "any");
|
|
46
|
+
const y = ((l = e.user.value) == null ? void 0 : l.permissions) ?? [], A = m(y, u, d);
|
|
47
|
+
r.style.display = A ? "" : "none";
|
|
43
48
|
});
|
|
44
|
-
}), r._scope =
|
|
49
|
+
}), r._scope = s;
|
|
45
50
|
},
|
|
46
51
|
unmounted(r) {
|
|
47
|
-
|
|
52
|
+
var n;
|
|
53
|
+
(n = r._scope) == null || n.stop();
|
|
48
54
|
}
|
|
49
55
|
};
|
|
50
|
-
function
|
|
51
|
-
const r =
|
|
52
|
-
|
|
56
|
+
function p() {
|
|
57
|
+
const r = S(
|
|
58
|
+
i
|
|
53
59
|
);
|
|
54
60
|
if (!r)
|
|
55
61
|
throw new Error("useAccessGuard must be used within AccessGuardProvider");
|
|
56
62
|
const n = (t, e = "any") => {
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
var o;
|
|
64
|
+
const s = ((o = r.user.value) == null ? void 0 : o.permissions) || [];
|
|
65
|
+
return m(s, t, e);
|
|
59
66
|
};
|
|
60
67
|
return {
|
|
61
68
|
can: n,
|
|
62
69
|
cannot: (t, e) => !n(t, e),
|
|
63
70
|
hasRole: (t, e = "any") => {
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
var a;
|
|
72
|
+
const s = ((a = r.user.value) == null ? void 0 : a.roles) || [], o = Array.isArray(t) ? t : [t];
|
|
73
|
+
return e === "all" ? o.every((u) => s.includes(u)) : o.some((u) => s.includes(u));
|
|
66
74
|
}
|
|
67
75
|
};
|
|
68
76
|
}
|
|
69
|
-
const
|
|
77
|
+
const E = f({
|
|
70
78
|
name: "Guard",
|
|
71
79
|
props: {
|
|
72
80
|
permission: {
|
|
@@ -83,30 +91,33 @@ const g = l({
|
|
|
83
91
|
}
|
|
84
92
|
},
|
|
85
93
|
setup(r, { slots: n }) {
|
|
86
|
-
const
|
|
94
|
+
const c = p(), t = R(() => {
|
|
87
95
|
if (!r.permission && !r.role) return !0;
|
|
88
96
|
let e = !0;
|
|
89
|
-
return r.permission && (e = e &&
|
|
97
|
+
return r.permission && (e = e && c.can(r.permission, r.mode)), r.role && e && (e = e && c.hasRole(r.role, r.mode)), e;
|
|
90
98
|
});
|
|
91
|
-
return () =>
|
|
99
|
+
return () => {
|
|
100
|
+
var e;
|
|
101
|
+
return t.value ? (e = n.default) == null ? void 0 : e.call(n) : null;
|
|
102
|
+
};
|
|
92
103
|
}
|
|
93
104
|
});
|
|
94
|
-
function
|
|
95
|
-
const { can: n, hasRole:
|
|
105
|
+
function j(r) {
|
|
106
|
+
const { can: n, hasRole: c } = p();
|
|
96
107
|
return r.beforeEach((t) => {
|
|
97
108
|
const e = t.meta;
|
|
98
|
-
if (e.permission && !n(e.permission, e.mode) || e.role && !
|
|
109
|
+
if (e.permission && !n(e.permission, e.mode) || e.role && !c(e.role, e.mode))
|
|
99
110
|
return e.redirect || "/";
|
|
100
111
|
});
|
|
101
112
|
}
|
|
102
|
-
function
|
|
103
|
-
r.directive("can",
|
|
113
|
+
function q(r) {
|
|
114
|
+
r.directive("can", b);
|
|
104
115
|
}
|
|
105
116
|
export {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
x as AccessGuardProvider,
|
|
118
|
+
i as AccessGuardSymbol,
|
|
119
|
+
E as Guard,
|
|
120
|
+
j as applyAccessGuard,
|
|
121
|
+
q as install,
|
|
122
|
+
p as useAccessGuard
|
|
112
123
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(c,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],s):(c=typeof globalThis<"u"?globalThis:c||self,s(c.VueAccessGuard={},c.Vue))})(this,(function(c,s){"use strict";const l=Symbol("AccessGuard"),A=s.defineComponent({name:"AccessGuardProvider",props:{user:{type:Object,required:!0}},setup(r,{slots:n}){const o=s.toRef(r,"user");return s.provide(l,{user:o}),()=>{var t;return(t=n.default)==null?void 0:t.call(n)}}});function m(r,n,o="any"){if(!(r!=null&&r.length))return!1;const t=Array.isArray(n)?n:[n],e=u=>{if(r.includes("*")||r.includes(u))return!0;const[i]=u.split(":"),a=`${i}:*`;return r.includes(a)};return o==="all"?t.every(e):t.some(e)}const G={mounted(r,n){var i;const o=n.instance;if(!o)return;let t=o.$.parent,e;for(;t&&!e;)e=(i=t.provides)==null?void 0:i[l],t=t.parent;if(!e)throw new Error("[AccessGuard] v-can used outside AccessGuardProvider");const u=s.effectScope();u.run(()=>{s.watchEffect(()=>{var p;const a=n.value;let d,y="any";typeof a=="string"||Array.isArray(a)?d=a:(d=a.permission,y=a.mode??"any");const S=((p=e.user.value)==null?void 0:p.permissions)??[],b=m(S,d,y);r.style.display=b?"":"none"})}),r._scope=u},unmounted(r){var n;(n=r._scope)==null||n.stop()}};function f(){const r=s.inject(l);if(!r)throw new Error("useAccessGuard must be used within AccessGuardProvider");const n=(t,e="any")=>{var i;const u=((i=r.user.value)==null?void 0:i.permissions)||[];return m(u,t,e)};return{can:n,cannot:(t,e)=>!n(t,e),hasRole:(t,e="any")=>{var a;const u=((a=r.user.value)==null?void 0:a.roles)||[],i=Array.isArray(t)?t:[t];return e==="all"?i.every(d=>u.includes(d)):i.some(d=>u.includes(d))}}}const h=s.defineComponent({name:"Guard",props:{permission:{type:[String,Array],required:!1},role:{type:[String,Array],required:!1},mode:{type:String,default:"any"}},setup(r,{slots:n}){const o=f(),t=s.computed(()=>{if(!r.permission&&!r.role)return!0;let e=!0;return r.permission&&(e=e&&o.can(r.permission,r.mode)),r.role&&e&&(e=e&&o.hasRole(r.role,r.mode)),e});return()=>{var e;return t.value?(e=n.default)==null?void 0:e.call(n):null}}});function v(r){const{can:n,hasRole:o}=f();return r.beforeEach(t=>{const e=t.meta;if(e.permission&&!n(e.permission,e.mode)||e.role&&!o(e.role,e.mode))return e.redirect||"/"})}function w(r){r.directive("can",G)}c.AccessGuardProvider=A,c.AccessGuardSymbol=l,c.Guard=h,c.applyAccessGuard=v,c.install=w,c.useAccessGuard=f,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-accessguard",
|
|
3
|
+
"license": "MIT",
|
|
3
4
|
"publishConfig": {
|
|
4
5
|
"access": "public"
|
|
5
6
|
},
|
|
6
|
-
"version": "1.0.
|
|
7
|
+
"version": "1.0.2",
|
|
7
8
|
"type": "module",
|
|
8
9
|
"main": "dist/vue-access-guard.umd.js",
|
|
9
10
|
"module": "dist/vue-access-guard.es.js",
|
|
@@ -35,12 +36,13 @@
|
|
|
35
36
|
"@vitest/coverage-v8": "4.0.18",
|
|
36
37
|
"@vue/test-utils": "^2.4.6",
|
|
37
38
|
"@vue/tsconfig": "^0.8.1",
|
|
39
|
+
"gh-pages": "^6.3.0",
|
|
38
40
|
"jsdom": "^28.1.0",
|
|
39
41
|
"playwright": "^1.58.2",
|
|
40
42
|
"storybook": "^8.6.17",
|
|
41
43
|
"storybook-vue3-router": "^4.0.1",
|
|
42
44
|
"typescript": "~5.9.3",
|
|
43
|
-
"vite": "^
|
|
45
|
+
"vite": "^6.0.0",
|
|
44
46
|
"vitest": "^4.0.18",
|
|
45
47
|
"vue-router": "^4.6.4",
|
|
46
48
|
"vue-tsc": "^3.1.5"
|
|
@@ -53,6 +55,7 @@
|
|
|
53
55
|
"dev": "vite",
|
|
54
56
|
"build": "vue-tsc -b && vite build",
|
|
55
57
|
"storybook": "storybook dev -p 6006",
|
|
56
|
-
"build-storybook": "storybook build"
|
|
58
|
+
"build-storybook": "storybook build",
|
|
59
|
+
"deploy-storybook": "storybook build && gh-pages -d storybook-static"
|
|
57
60
|
}
|
|
58
61
|
}
|