react-ability-kit 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ Keep authorization logic **out of your components** and **in one place**.
|
|
|
9
9
|
|
|
10
10
|
Most React apps don’t plan to become permission nightmares — they just grow into one.
|
|
11
11
|
|
|
12
|
+
Permissions slowly spread across components as ad-hoc checks:
|
|
13
|
+
|
|
14
|
+
- `if (user.role === "admin")`
|
|
15
|
+
- `if (invoice.ownerId === user.id)`
|
|
16
|
+
- `if (permissions.includes("invoice:update"))`
|
|
17
|
+
|
|
12
18
|
This package introduces a **policy-first** approach to permissions, so your UI stays clean and your rules stay auditable.
|
|
13
19
|
|
|
14
20
|
---
|
|
@@ -50,9 +56,9 @@ if (user && user.role !== "guest") {
|
|
|
50
56
|
|
|
51
57
|
### Problems this creates
|
|
52
58
|
|
|
53
|
-
- ❌ **Logic duplication** – same rules rewritten in different places
|
|
54
|
-
- ❌ **Rules drift** – one condition changes, others don’t
|
|
55
|
-
- ❌ **Impossible to audit** – “Who can edit invoices?” → grep the whole repo
|
|
59
|
+
- ❌ **Logic duplication** – same rules rewritten in different places
|
|
60
|
+
- ❌ **Rules drift** – one condition changes, others don’t
|
|
61
|
+
- ❌ **Impossible to audit** – “Who can edit invoices?” → grep the whole repo
|
|
56
62
|
- ❌ **UI inconsistencies**
|
|
57
63
|
- Button visible but API rejects
|
|
58
64
|
- Button hidden but API allows
|
|
@@ -87,21 +93,100 @@ User ──► Policy ──► Ability ──► UI / Components
|
|
|
87
93
|
|
|
88
94
|
---
|
|
89
95
|
|
|
96
|
+
## Installation
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm install react-ability
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
or
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pnpm add react-ability
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
or
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
yarn add react-ability
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Quick start (5 minutes)
|
|
117
|
+
|
|
118
|
+
### 1️⃣ Define your abilities (policy-first)
|
|
119
|
+
|
|
120
|
+
Create a single policy file.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
// ability.ts
|
|
124
|
+
import { defineAbility } from "react-ability";
|
|
125
|
+
|
|
126
|
+
export const ability = defineAbility((allow, deny, user) => {
|
|
127
|
+
allow("read", "Invoice");
|
|
128
|
+
|
|
129
|
+
allow(
|
|
130
|
+
"update",
|
|
131
|
+
"Invoice",
|
|
132
|
+
invoice => invoice.ownerId === user.id && invoice.status === "draft"
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
deny("delete", "Invoice");
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
This file is your **single source of truth**.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### 2️⃣ Provide the ability to your app
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
import { AbilityProvider } from "react-ability";
|
|
147
|
+
import { ability } from "./ability";
|
|
148
|
+
|
|
149
|
+
export function App() {
|
|
150
|
+
return (
|
|
151
|
+
<AbilityProvider ability={ability}>
|
|
152
|
+
<YourApp />
|
|
153
|
+
</AbilityProvider>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### 3️⃣ Use permissions anywhere
|
|
161
|
+
|
|
162
|
+
#### Using the `<Can />` component
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
<Can I="update" a="Invoice" this={invoice}>
|
|
166
|
+
<EditButton />
|
|
167
|
+
</Can>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Using the `can()` function
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
const canEdit = can("update", "Invoice", invoice);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
90
178
|
## What this package actually solves
|
|
91
179
|
|
|
92
180
|
### 1️⃣ Single source of truth for permissions
|
|
93
181
|
|
|
94
182
|
```ts
|
|
95
|
-
// policy.ts
|
|
96
183
|
allow("update", "Invoice", invoice => invoice.ownerId === user.id);
|
|
97
184
|
deny("delete", "Invoice");
|
|
98
185
|
```
|
|
99
186
|
|
|
100
|
-
**Result**
|
|
101
|
-
|
|
102
187
|
- All rules live in one place
|
|
103
188
|
- Easy to review, change, and reason about
|
|
104
|
-
- No
|
|
189
|
+
- No scattered conditionals
|
|
105
190
|
|
|
106
191
|
---
|
|
107
192
|
|
|
@@ -173,14 +258,6 @@ This removes an entire class of bugs.
|
|
|
173
258
|
|
|
174
259
|
### 5️⃣ Ownership rules become first-class
|
|
175
260
|
|
|
176
|
-
❌ Scattered ownership checks
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
if (invoice.ownerId === user.id)
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
✅ Centralized ownership rule
|
|
183
|
-
|
|
184
261
|
```ts
|
|
185
262
|
allow("update", "Invoice", invoice => invoice.ownerId === user.id);
|
|
186
263
|
```
|
|
@@ -195,17 +272,9 @@ Ownership logic is now:
|
|
|
195
272
|
|
|
196
273
|
### 6️⃣ Predictable SSR & hydration
|
|
197
274
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
- Buttons appear/disappear after hydration
|
|
202
|
-
- Server/client logic diverges
|
|
203
|
-
|
|
204
|
-
With **React Ability**:
|
|
205
|
-
|
|
206
|
-
- Ability is built once from user data
|
|
207
|
-
- Server and client agree on permissions
|
|
208
|
-
- Stable, predictable rendering
|
|
275
|
+
- No permission flicker
|
|
276
|
+
- No server/client mismatch
|
|
277
|
+
- Same rules, same result everywhere
|
|
209
278
|
|
|
210
279
|
---
|
|
211
280
|
|
|
@@ -215,15 +284,7 @@ It’s not magic.
|
|
|
215
284
|
|
|
216
285
|
It simply means:
|
|
217
286
|
|
|
218
|
-
> Render children **only if the permission passes
|
|
219
|
-
|
|
220
|
-
Instead of:
|
|
221
|
-
|
|
222
|
-
```tsx
|
|
223
|
-
if (!canEdit) return null;
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
You write:
|
|
287
|
+
> Render children **only if the permission passes**
|
|
227
288
|
|
|
228
289
|
```tsx
|
|
229
290
|
<Can I="update" a="Invoice" this={invoice}>
|
|
@@ -268,7 +329,7 @@ It answers one question only:
|
|
|
268
329
|
|
|
269
330
|
- ❌ Landing pages
|
|
270
331
|
- ❌ Simple blogs
|
|
271
|
-
- ❌
|
|
332
|
+
- ❌ Admin / non-admin only apps
|
|
272
333
|
|
|
273
334
|
---
|
|
274
335
|
|