@zealamic/payload-auth-rbac-plugin 1.0.0-beta.9 → 1.0.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/README.md +27 -31
- package/assets/cover-photo.jpg +0 -0
- package/dist/components/role-permission-matrix-client/default-data.js +3 -2
- package/dist/components/role-permission-matrix-client/default-data.js.map +1 -1
- package/dist/components/role-permission-matrix-client/index.js +20 -70
- package/dist/components/role-permission-matrix-client/index.js.map +1 -1
- package/dist/components/role-permission-matrix-client/matrix.module.scss +66 -0
- package/dist/components/role-permission-matrix-client/types.d.ts +4 -6
- package/dist/components/role-permission-matrix-client/types.js.map +1 -1
- package/dist/styles/variables.scss +1 -0
- package/docs/COLLECTIONS.md +440 -0
- package/docs/TRANSLATIONS.md +469 -0
- package/docs/UTILS.md +226 -0
- package/package.json +7 -28
- package/src/collections/permission-actions/default-data.ts +36 -0
- package/src/collections/permission-actions/index.ts +144 -0
- package/src/collections/permission-actions/types.ts +56 -0
- package/src/collections/permission-features/default-data.ts +30 -0
- package/src/collections/permission-features/index.ts +122 -0
- package/src/collections/permission-features/types.ts +47 -0
- package/src/collections/permissions/default-data.ts +38 -0
- package/src/collections/permissions/index.ts +160 -0
- package/src/collections/permissions/types.ts +57 -0
- package/src/collections/roles/default-data.ts +44 -0
- package/src/collections/roles/hooks/sync-permission-matrix-draft.ts +73 -0
- package/src/collections/roles/index.ts +178 -0
- package/src/collections/roles/types.ts +56 -0
- package/src/collections/roles-permissions/default-data.ts +28 -0
- package/src/collections/roles-permissions/index.ts +107 -0
- package/src/collections/roles-permissions/types.ts +42 -0
- package/src/collections/users/default-data.ts +19 -0
- package/src/collections/users/index.ts +148 -0
- package/src/collections/users/parent-path.ts +310 -0
- package/src/collections/users/types.ts +25 -0
- package/src/components/role-permission-matrix-client/default-data.ts +25 -0
- package/src/components/role-permission-matrix-client/index.tsx +369 -0
- package/src/components/role-permission-matrix-client/matrix.module.scss +66 -0
- package/src/components/role-permission-matrix-client/types.ts +16 -0
- package/src/endpoints/customEndpointHandler.ts +5 -0
- package/src/exports/client.ts +1 -0
- package/src/exports/rsc.ts +0 -0
- package/src/general-types.d.ts +5 -0
- package/src/index.ts +249 -0
- package/src/lib/constants/general.ts +1 -0
- package/src/lib/constants/index.ts +15 -0
- package/src/lib/constants/permission-action.ts +9 -0
- package/src/lib/constants/permission-feature.ts +4 -0
- package/src/lib/constants/permission.ts +4 -0
- package/src/lib/constants/role.ts +10 -0
- package/src/lib/constants/user.ts +1 -0
- package/src/lib/utils/access.ts +611 -0
- package/src/lib/utils/data.ts +7 -0
- package/src/lib/utils/fields.ts +62 -0
- package/src/lib/utils/index.ts +4 -0
- package/src/lib/utils/localization.ts +106 -0
- package/src/styles/variables.scss +1 -0
- package/src/types.ts +64 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
# Translations guide
|
|
2
|
+
|
|
3
|
+
Customize Admin labels, placeholders, select options, and permission-matrix UI text via the plugin `translations` option.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import type { RBACTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
|
|
7
|
+
import { payloadAuthRbacPlugin } from "@zealamic/payload-auth-rbac-plugin";
|
|
8
|
+
|
|
9
|
+
export default buildConfig({
|
|
10
|
+
i18n: {
|
|
11
|
+
supportedLanguages: { en, vi },
|
|
12
|
+
fallbackLanguage: "en",
|
|
13
|
+
},
|
|
14
|
+
plugins: [
|
|
15
|
+
payloadAuthRbacPlugin({
|
|
16
|
+
translations: {
|
|
17
|
+
en: {
|
|
18
|
+
/* partial overrides OK */
|
|
19
|
+
},
|
|
20
|
+
vi: {
|
|
21
|
+
/* provide full strings for vi */
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
],
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## How it works
|
|
32
|
+
|
|
33
|
+
Translations are used in **two places**:
|
|
34
|
+
|
|
35
|
+
| Layer | What it affects |
|
|
36
|
+
| ------------------------------ | ------------------------------------------------------------------------------------ |
|
|
37
|
+
| **Collection config** | Sidebar group, collection labels, field labels, placeholders, select option labels |
|
|
38
|
+
| **`config.i18n.translations`** | Permission matrix UI (`useTranslation` keys under `components.rolePermissionMatrix`) |
|
|
39
|
+
|
|
40
|
+
**Merge order when the plugin loads:**
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Plugin English defaults
|
|
44
|
+
→ deep-merge your pluginOptions.translations
|
|
45
|
+
→ deep-merge into existing config.i18n.translations
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
You only pass RBAC strings to **`payloadAuthRbacPlugin({ translations })`**. The plugin registers them into Payload i18n automatically — do **not** duplicate the same keys in `config.i18n.translations`.
|
|
49
|
+
|
|
50
|
+
Your project's `config.i18n` still owns:
|
|
51
|
+
|
|
52
|
+
- `supportedLanguages`
|
|
53
|
+
- `fallbackLanguage`
|
|
54
|
+
- Non-RBAC app strings (optional)
|
|
55
|
+
|
|
56
|
+
### Locale merge behavior
|
|
57
|
+
|
|
58
|
+
| Locale | Behavior |
|
|
59
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
60
|
+
| `en` | Partial overrides OK — missing keys inherit plugin English defaults |
|
|
61
|
+
| Other (e.g. `vi`) | **No** auto-fill from `en` — provide complete strings for that locale, or rely on Payload `fallbackLanguage` |
|
|
62
|
+
|
|
63
|
+
### Serializable values only (Payload 3 / Next.js)
|
|
64
|
+
|
|
65
|
+
Use **plain strings** (and nested objects of strings) only:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// ✅
|
|
69
|
+
labels: { singular: "Role", plural: "Roles" }
|
|
70
|
+
|
|
71
|
+
// ❌ functions, i18n library calls, class instances
|
|
72
|
+
labels: { singular: () => "Role" }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Config shape
|
|
78
|
+
|
|
79
|
+
Top-level keys = **locale codes** (`en`, `vi`, …). Must match `i18n.supportedLanguages`.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
type RBACTranslations = {
|
|
83
|
+
[locale: string]: {
|
|
84
|
+
collections?: {
|
|
85
|
+
permissionActions?: CollectionTranslations;
|
|
86
|
+
permissionFeatures?: CollectionTranslations;
|
|
87
|
+
permissions?: CollectionTranslations;
|
|
88
|
+
roles?: CollectionTranslations;
|
|
89
|
+
rolesPermissions?: CollectionTranslations;
|
|
90
|
+
users?: UsersFieldTranslations; // fields only
|
|
91
|
+
};
|
|
92
|
+
components?: {
|
|
93
|
+
rolePermissionMatrix?: MatrixTranslations;
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Collection config keys (camelCase)
|
|
100
|
+
|
|
101
|
+
| Config key | Collection slug |
|
|
102
|
+
| -------------------- | -------------------------------------- |
|
|
103
|
+
| `permissionActions` | `permission-actions` |
|
|
104
|
+
| `permissionFeatures` | `permission-features` |
|
|
105
|
+
| `permissions` | `permissions` |
|
|
106
|
+
| `roles` | `roles` |
|
|
107
|
+
| `rolesPermissions` | `roles-permissions` |
|
|
108
|
+
| `users` | Your auth collection (plugin-modified) |
|
|
109
|
+
|
|
110
|
+
Every collection block supports:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
{
|
|
114
|
+
labels?: { singular?: string; plural?: string };
|
|
115
|
+
admin?: { group?: string };
|
|
116
|
+
fields?: { [fieldName]: FieldTranslation };
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Common field keys
|
|
121
|
+
|
|
122
|
+
| Key | Used on |
|
|
123
|
+
| ------------- | -------------------- |
|
|
124
|
+
| `label` | All fields |
|
|
125
|
+
| `placeholder` | Text, number, select |
|
|
126
|
+
|
|
127
|
+
### Select option labels
|
|
128
|
+
|
|
129
|
+
Pattern: **`{value}Label`** where `{value}` is the stored option value.
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// status: active | inactive
|
|
133
|
+
status: {
|
|
134
|
+
label: "Status",
|
|
135
|
+
placeholder: "Select status",
|
|
136
|
+
activeLabel: "Active",
|
|
137
|
+
inactiveLabel: "Inactive",
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// permission-actions type: main | sub
|
|
141
|
+
type: {
|
|
142
|
+
mainLabel: "Main",
|
|
143
|
+
subLabel: "Sub",
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// roles dataScope: own | hierarchy | all
|
|
147
|
+
dataScope: {
|
|
148
|
+
ownLabel: "Own",
|
|
149
|
+
hierarchyLabel: "Hierarchy",
|
|
150
|
+
allLabel: "All",
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Per-collection field keys
|
|
157
|
+
|
|
158
|
+
All keys are optional. Defaults live in `src/collections/*/default-data.ts`.
|
|
159
|
+
|
|
160
|
+
### `permissionActions`
|
|
161
|
+
|
|
162
|
+
| Field | Keys |
|
|
163
|
+
| ----------- | ------------------------------------------------------ |
|
|
164
|
+
| `code` | `label`, `placeholder` |
|
|
165
|
+
| `type` | `label`, `placeholder`, `mainLabel`, `subLabel` |
|
|
166
|
+
| `sortOrder` | `label`, `placeholder` |
|
|
167
|
+
| `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
|
|
168
|
+
|
|
169
|
+
### `permissionFeatures`
|
|
170
|
+
|
|
171
|
+
| Field | Keys |
|
|
172
|
+
| ----------- | ------------------------------------------------------ |
|
|
173
|
+
| `code` | `label`, `placeholder` |
|
|
174
|
+
| `sortOrder` | `label`, `placeholder` |
|
|
175
|
+
| `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
|
|
176
|
+
|
|
177
|
+
### `permissions`
|
|
178
|
+
|
|
179
|
+
| Field | Keys |
|
|
180
|
+
| ------------------- | ------------------------------------------------------ |
|
|
181
|
+
| `name` | `label`, `placeholder` |
|
|
182
|
+
| `permissionFeature` | `label`, `placeholder` |
|
|
183
|
+
| `permissionAction` | `label`, `placeholder` |
|
|
184
|
+
| `sortOrder` | `label`, `placeholder` |
|
|
185
|
+
| `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
|
|
186
|
+
|
|
187
|
+
### `roles`
|
|
188
|
+
|
|
189
|
+
| Field | Keys |
|
|
190
|
+
| ----------------------------- | -------------------------------------------------------------------------------- |
|
|
191
|
+
| `code`, `name`, `description` | `label`, `placeholder` |
|
|
192
|
+
| `status` | `label`, `placeholder`, `activeLabel`, `inactiveLabel` |
|
|
193
|
+
| `dataScope` | `label`, `placeholder`, `ownLabel`, `hierarchyLabel`, `allLabel` |
|
|
194
|
+
| `permissionMatrix` | `label`, `placeholder` — **label only** for schema field `permissionMatrixDraft` |
|
|
195
|
+
|
|
196
|
+
> **Field name vs translation key:** schema field = `permissionMatrixDraft`; translation key = `permissionMatrix`. For `collections.roles.fields` overrides, use schema name `permissionMatrixDraft`.
|
|
197
|
+
|
|
198
|
+
### `rolesPermissions`
|
|
199
|
+
|
|
200
|
+
| Field | Keys |
|
|
201
|
+
| -------------------- | ---------------------- |
|
|
202
|
+
| `role`, `permission` | `label`, `placeholder` |
|
|
203
|
+
| `enabled` | `label`, `placeholder` |
|
|
204
|
+
|
|
205
|
+
### `users` (fields only)
|
|
206
|
+
|
|
207
|
+
| Field | Keys |
|
|
208
|
+
| -------------- | ---------------------- |
|
|
209
|
+
| `isSuperAdmin` | `label` |
|
|
210
|
+
| `roles` | `label`, `placeholder` |
|
|
211
|
+
| `parent` | `label`, `placeholder` |
|
|
212
|
+
|
|
213
|
+
No collection `labels` — the users collection belongs to your app.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Permission matrix UI
|
|
218
|
+
|
|
219
|
+
**Config path:** `translations.<locale>.components.rolePermissionMatrix`
|
|
220
|
+
|
|
221
|
+
Registered as Payload i18n keys: `components:rolePermissionMatrix:…`
|
|
222
|
+
|
|
223
|
+
| Key | Description |
|
|
224
|
+
| ------------------------------ | --------------------------------------------------------------- |
|
|
225
|
+
| `title` | Matrix heading |
|
|
226
|
+
| `viewInUpdateScreenOnly.label` | Shown on create screen |
|
|
227
|
+
| `loading.placeholder` | Loading state |
|
|
228
|
+
| `featuresLabel` | Features column header |
|
|
229
|
+
| `features.{code}` | Label for main feature with matching `permission-features.code` |
|
|
230
|
+
| `actionsLabel` | Actions column header |
|
|
231
|
+
| `actions.{code}` | Label for main action with matching `permission-actions.code` |
|
|
232
|
+
|
|
233
|
+
### Features (dynamic)
|
|
234
|
+
|
|
235
|
+
The matrix resolves feature row labels via:
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
components:rolePermissionMatrix:features:{featureCode}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`{featureCode}` must match **`permission-features.code` exactly** (case-sensitive).
|
|
242
|
+
|
|
243
|
+
Add one key per feature code under `translations.<locale>.components.rolePermissionMatrix.features`:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
payloadAuthRbacPlugin({
|
|
247
|
+
translations: {
|
|
248
|
+
en: {
|
|
249
|
+
components: {
|
|
250
|
+
rolePermissionMatrix: {
|
|
251
|
+
// ... others
|
|
252
|
+
featuresLabel: "Features",
|
|
253
|
+
features: {
|
|
254
|
+
label: "Features",
|
|
255
|
+
users: "Users", // permission-features.code = "users" (plugin default)
|
|
256
|
+
posts: "Posts", // permission-features.code = "posts"
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
If a key is missing, the UI falls back to `feature.id` (not `feature.code`).
|
|
266
|
+
|
|
267
|
+
### Main action labels (dynamic)
|
|
268
|
+
|
|
269
|
+
Main actions (`type: "main"`) resolve checkbox labels via:
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
components:rolePermissionMatrix:actions:{actionCode}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`{actionCode}` must match **`permission-actions.code` exactly**.
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
payloadAuthRbacPlugin({
|
|
279
|
+
translations: {
|
|
280
|
+
en: {
|
|
281
|
+
components: {
|
|
282
|
+
rolePermissionMatrix: {
|
|
283
|
+
// ... others
|
|
284
|
+
actionsLabel: "Actions",
|
|
285
|
+
actions: {
|
|
286
|
+
create: "Create", // permission-actions.code = "create" (plugin default)
|
|
287
|
+
read: "Read",
|
|
288
|
+
update: "Update",
|
|
289
|
+
delete: "Delete",
|
|
290
|
+
publish: "Publish", // permission-actions.code = "publish" (custom)
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
If a key is missing, the UI falls back to `action.id` (not `action.code`).
|
|
300
|
+
|
|
301
|
+
### Sub-action labels (limitation)
|
|
302
|
+
|
|
303
|
+
Sub-actions (`type: "sub"`) **do not** use `useTranslation` — the UI shows raw `permission-actions.code`.
|
|
304
|
+
|
|
305
|
+
**Workaround:** use readable codes when creating sub-actions (`approveDraft`, not `ad`).
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Examples
|
|
310
|
+
|
|
311
|
+
### Partial English override
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
payloadAuthRbacPlugin({
|
|
315
|
+
translations: {
|
|
316
|
+
en: {
|
|
317
|
+
collections: {
|
|
318
|
+
permissionActions: {
|
|
319
|
+
admin: { group: "Access Control" },
|
|
320
|
+
fields: {
|
|
321
|
+
code: {
|
|
322
|
+
label: "Action Code",
|
|
323
|
+
placeholder: "e.g. create, read, update, delete",
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
roles: {
|
|
328
|
+
fields: {
|
|
329
|
+
permissionMatrix: { label: "Permission Matrix" },
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
components: {
|
|
334
|
+
rolePermissionMatrix: {
|
|
335
|
+
title: "Permission Matrix",
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Bilingual (`en` + `vi`)
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import { en } from "@payloadcms/translations/languages/en";
|
|
347
|
+
import { vi } from "@payloadcms/translations/languages/vi";
|
|
348
|
+
|
|
349
|
+
export default buildConfig({
|
|
350
|
+
i18n: {
|
|
351
|
+
supportedLanguages: { en, vi },
|
|
352
|
+
fallbackLanguage: "en",
|
|
353
|
+
},
|
|
354
|
+
plugins: [
|
|
355
|
+
payloadAuthRbacPlugin({
|
|
356
|
+
translations: {
|
|
357
|
+
en: {
|
|
358
|
+
collections: {
|
|
359
|
+
roles: { labels: { singular: "Role", plural: "Roles" } },
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
vi: {
|
|
363
|
+
collections: {
|
|
364
|
+
permissionActions: {
|
|
365
|
+
labels: { singular: "Quyền thao tác", plural: "Quyền thao tác" },
|
|
366
|
+
admin: { group: "Hệ thống" },
|
|
367
|
+
fields: {
|
|
368
|
+
code: { label: "Mã quyền thao tác" },
|
|
369
|
+
status: {
|
|
370
|
+
activeLabel: "Hoạt động",
|
|
371
|
+
inactiveLabel: "Ngừng hoạt động",
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
roles: {
|
|
376
|
+
labels: { singular: "Vai trò", plural: "Vai trò" },
|
|
377
|
+
fields: {
|
|
378
|
+
permissionMatrix: { label: "Ma trận quyền" },
|
|
379
|
+
dataScope: {
|
|
380
|
+
ownLabel: "Của mình",
|
|
381
|
+
hierarchyLabel: "Phân cấp",
|
|
382
|
+
allLabel: "Tất cả",
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
users: {
|
|
387
|
+
fields: {
|
|
388
|
+
isSuperAdmin: { label: "Siêu quản trị" },
|
|
389
|
+
roles: { label: "Vai trò" },
|
|
390
|
+
parent: { label: "Quản lý trực tiếp" },
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
components: {
|
|
395
|
+
rolePermissionMatrix: {
|
|
396
|
+
title: "Ma trận quyền",
|
|
397
|
+
loading: { placeholder: "Đang tải..." },
|
|
398
|
+
featuresLabel: "Tính năng",
|
|
399
|
+
features: {
|
|
400
|
+
// Mã tính năng của permission-features
|
|
401
|
+
},
|
|
402
|
+
actionsLabel: "Hành động",
|
|
403
|
+
actions: {
|
|
404
|
+
create: "Tạo",
|
|
405
|
+
read: "Xem",
|
|
406
|
+
update: "Sửa",
|
|
407
|
+
delete: "Xóa",
|
|
408
|
+
// Mã hành đông của permission-features
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
}),
|
|
415
|
+
],
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Working demo: `dev/rbac.ts`.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## TypeScript
|
|
424
|
+
|
|
425
|
+
```ts
|
|
426
|
+
import type { RBACTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
|
|
427
|
+
|
|
428
|
+
// Per-collection types (value for one locale):
|
|
429
|
+
import type { RolesCollectionTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
|
|
430
|
+
import type { RolePermissionMatrixClientTranslations } from "@zealamic/payload-auth-rbac-plugin/types";
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Default English strings
|
|
436
|
+
|
|
437
|
+
Shipped defaults (override via `translations.en`):
|
|
438
|
+
|
|
439
|
+
| Source file | Content |
|
|
440
|
+
| -------------------------------------------------------------- | --------------------- |
|
|
441
|
+
| `src/collections/permission-actions/default-data.ts` | Permission actions |
|
|
442
|
+
| `src/collections/permission-features/default-data.ts` | Permission features |
|
|
443
|
+
| `src/collections/permissions/default-data.ts` | Permissions |
|
|
444
|
+
| `src/collections/roles/default-data.ts` | Roles + dataScope |
|
|
445
|
+
| `src/collections/roles-permissions/default-data.ts` | Role permissions join |
|
|
446
|
+
| `src/collections/users/default-data.ts` | User fields |
|
|
447
|
+
| `src/components/role-permission-matrix-client/default-data.ts` | Matrix UI |
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Quick reference
|
|
452
|
+
|
|
453
|
+
| Goal | Path |
|
|
454
|
+
| ------------------------ | --------------------------------------------------------------------------- |
|
|
455
|
+
| Sidebar group | `translations.<locale>.collections.<key>.admin.group` |
|
|
456
|
+
| Collection name | `…labels.singular` / `…labels.plural` |
|
|
457
|
+
| Field label | `…fields.<fieldName>.label` |
|
|
458
|
+
| Select option | `…fields.<fieldName>.<value>Label` |
|
|
459
|
+
| Matrix title | `…components.rolePermissionMatrix.title` |
|
|
460
|
+
| Matrix action column | `…components.rolePermissionMatrix.actions.<code>` |
|
|
461
|
+
| Override field in schema | Use **schema field name** (`permissionMatrixDraft`, not `permissionMatrix`) |
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Related docs
|
|
466
|
+
|
|
467
|
+
- [README](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/README.md) — install and quick start
|
|
468
|
+
- [COLLECTIONS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/COLLECTIONS.md) — collection schemas and customization
|
|
469
|
+
- [UTILS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/UTILS.md) — access helpers
|
package/docs/UTILS.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Utils reference
|
|
2
|
+
|
|
3
|
+
This document lists only utilities that are currently exported.
|
|
4
|
+
|
|
5
|
+
Export sources:
|
|
6
|
+
|
|
7
|
+
- `@zealamic/payload-auth-rbac-plugin`
|
|
8
|
+
- `@zealamic/payload-auth-rbac-plugin/utils`
|
|
9
|
+
|
|
10
|
+
> Barrel file: `src/lib/utils/index.ts`
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Exported modules
|
|
15
|
+
|
|
16
|
+
`src/lib/utils/index.ts` exports from:
|
|
17
|
+
|
|
18
|
+
1. `access`
|
|
19
|
+
2. `data`
|
|
20
|
+
3. `fields`
|
|
21
|
+
4. `localization`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Access exports
|
|
26
|
+
|
|
27
|
+
### `type DataScopeOptions`
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
type DataScopeOptions = {
|
|
31
|
+
createdByField?: string; // default: "createdBy"
|
|
32
|
+
usersCollectionSlug?: string; // default: "users"
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Use this to configure ownership field and users slug for hierarchy logic.
|
|
37
|
+
|
|
38
|
+
### `getPermissionAccess({ featureCode, actionCode, mode?, collectionSlug?, options? })`
|
|
39
|
+
|
|
40
|
+
Unified access helper for Payload `access` config.
|
|
41
|
+
|
|
42
|
+
You can use one function for all common access cases:
|
|
43
|
+
|
|
44
|
+
- permission-only (`create`, `readVersions`, `unlock`, ...)
|
|
45
|
+
- read with data-scope filter
|
|
46
|
+
- modify (`update` / `delete`) with per-document scope check
|
|
47
|
+
|
|
48
|
+
Parameters:
|
|
49
|
+
|
|
50
|
+
- `featureCode` (`string`): feature code in `permission-features.code`
|
|
51
|
+
- `actionCode` (`string`): action code in `permission-actions.code`
|
|
52
|
+
- `mode` (`"none" | "modify"`, optional):
|
|
53
|
+
- `"none"` (default) = permission check only
|
|
54
|
+
- `"modify"` = check one target document by `id`
|
|
55
|
+
- `collectionSlug` (`string`, optional): required when `mode: "modify"`
|
|
56
|
+
- `options` (`DataScopeOptions`, optional): data-scope config
|
|
57
|
+
|
|
58
|
+
What it returns:
|
|
59
|
+
|
|
60
|
+
- In permission-only mode: Payload access function returning `boolean`
|
|
61
|
+
- In read-scope mode (`options` provided): Payload access function returning `boolean | Where`
|
|
62
|
+
- In modify mode: Payload access function returning `boolean`
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// 1) permission-only (best for create/readVersions/unlock/etc.)
|
|
66
|
+
create: getPermissionAccess({
|
|
67
|
+
featureCode: "posts",
|
|
68
|
+
actionCode: "create",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 2) read + scope (read mode inferred when options exists)
|
|
72
|
+
read: getPermissionAccess({
|
|
73
|
+
featureCode: "posts",
|
|
74
|
+
actionCode: "read",
|
|
75
|
+
options: {
|
|
76
|
+
createdByField: "createdBy",
|
|
77
|
+
usersCollectionSlug: "users",
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// 3) update/delete + document scope (requires mode + collectionSlug)
|
|
82
|
+
update: getPermissionAccess({
|
|
83
|
+
featureCode: "posts",
|
|
84
|
+
actionCode: "update",
|
|
85
|
+
mode: "modify",
|
|
86
|
+
collectionSlug: "posts",
|
|
87
|
+
options: { createdByField: "createdBy" },
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
How it works internally:
|
|
92
|
+
|
|
93
|
+
1. deny when `req.user` is missing
|
|
94
|
+
2. allow immediately for super admin
|
|
95
|
+
3. check RBAC by `featureCode` + `actionCode`
|
|
96
|
+
4. if read-scope mode: return scope filter (`true` or `Where`)
|
|
97
|
+
5. if modify mode: load target document by `id`, then enforce data scope
|
|
98
|
+
|
|
99
|
+
When to use each mode:
|
|
100
|
+
|
|
101
|
+
- **Permission-only**: operations that do not depend on document ownership/hierarchy
|
|
102
|
+
Example: `create`, `readVersions`, `unlock`
|
|
103
|
+
- **Read-scope**: list/read access that must be filtered by owner/hierarchy/all
|
|
104
|
+
- **Modify**: `update` and `delete` where permission depends on the specific document
|
|
105
|
+
|
|
106
|
+
Common mistakes to avoid:
|
|
107
|
+
|
|
108
|
+
- `mode: "modify"` without `collectionSlug` -> always denied
|
|
109
|
+
- expecting read-scope behavior without passing `options`
|
|
110
|
+
- `featureCode` / `actionCode` not matching values in your permission collections
|
|
111
|
+
|
|
112
|
+
### `getSuperAdminAccess`
|
|
113
|
+
|
|
114
|
+
Allow only super admins.
|
|
115
|
+
|
|
116
|
+
### `getAuthenticatedOrSuperAdminAccess`
|
|
117
|
+
|
|
118
|
+
Allow current document owner or super admin.
|
|
119
|
+
|
|
120
|
+
### `resolveEffectiveDataScope(req, options?)`
|
|
121
|
+
|
|
122
|
+
Resolve effective scope from roles: `own | hierarchy | all`.
|
|
123
|
+
Widest scope wins: `all > hierarchy > own`.
|
|
124
|
+
|
|
125
|
+
### `getHierarchyVisibleUserIds(req, options?)`
|
|
126
|
+
|
|
127
|
+
Return visible user IDs in hierarchy scope (self + descendants).
|
|
128
|
+
|
|
129
|
+
### `getDataScopeReadWhere(req, options?)`
|
|
130
|
+
|
|
131
|
+
Build data-scope read filter as `Where | true`.
|
|
132
|
+
|
|
133
|
+
### `isProtectedSuperAdminUserDoc(doc)`
|
|
134
|
+
|
|
135
|
+
Guard helper for user docs with `isSuperAdmin: true`.
|
|
136
|
+
|
|
137
|
+
### `canAccessDocumentByDataScope({ req, doc, featureCode, actionCode, collectionSlug, options? })`
|
|
138
|
+
|
|
139
|
+
Low-level per-document RBAC + data-scope check.
|
|
140
|
+
|
|
141
|
+
### `mergeDataScopeWhere(base, scopeWhere)`
|
|
142
|
+
|
|
143
|
+
Merge existing `where` with scope constraints.
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const scopeWhere = await getDataScopeReadWhere(req, {
|
|
147
|
+
createdByField: "createdBy",
|
|
148
|
+
});
|
|
149
|
+
const where = mergeDataScopeWhere(
|
|
150
|
+
{ status: { equals: "published" } },
|
|
151
|
+
scopeWhere,
|
|
152
|
+
);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Data exports
|
|
158
|
+
|
|
159
|
+
### `toID(value)`
|
|
160
|
+
|
|
161
|
+
Normalize relationship/id values to string id.
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
toID("507f1f77bcf86cd799439011"); // "507f1f77bcf86cd799439011"
|
|
165
|
+
toID({ id: "507f1f77bcf86cd799439011" }); // "507f1f77bcf86cd799439011"
|
|
166
|
+
toID(undefined); // ""
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Fields exports
|
|
172
|
+
|
|
173
|
+
### `getMergedFieldAffectingData({ fields, defaultField })`
|
|
174
|
+
|
|
175
|
+
Merge one plugin default field with a user override by matching field name.
|
|
176
|
+
|
|
177
|
+
### `getArrayOfMergedFieldAffectingData({ fields, defaultFields })`
|
|
178
|
+
|
|
179
|
+
Build final fields list:
|
|
180
|
+
|
|
181
|
+
- merge defaults by matching names
|
|
182
|
+
- append unmatched custom fields
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Localization exports
|
|
187
|
+
|
|
188
|
+
### `toLocaleRecord(locales, getValue)`
|
|
189
|
+
|
|
190
|
+
Build `{ [locale]: string }` records from locale list.
|
|
191
|
+
|
|
192
|
+
### `toSelectPlaceholder(locales, getValue)`
|
|
193
|
+
|
|
194
|
+
Build serializable select placeholders (safe across Payload v3 server/client boundary).
|
|
195
|
+
|
|
196
|
+
### `getMergedTranslations({ defaultTranslations, translations })`
|
|
197
|
+
|
|
198
|
+
Deep-merge translation objects.
|
|
199
|
+
|
|
200
|
+
### `getAllTranslationsOfSpecificObject({ translations, path, locales? })`
|
|
201
|
+
|
|
202
|
+
Extract nested translation branch by path (example: `"collections.roles"`).
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Commonly paired constant export
|
|
207
|
+
|
|
208
|
+
Not from `lib/utils`, but often used with access helpers:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import { CONSTANTS } from "@zealamic/payload-auth-rbac-plugin";
|
|
212
|
+
|
|
213
|
+
CONSTANTS.ROLE.DATA_SCOPE;
|
|
214
|
+
CONSTANTS.ROLE.STATUS;
|
|
215
|
+
CONSTANTS.PERMISSION.STATUS;
|
|
216
|
+
CONSTANTS.PERMISSION_ACTION.TYPE;
|
|
217
|
+
CONSTANTS.USER.PARENT_PATH_SEPARATOR;
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Related docs
|
|
223
|
+
|
|
224
|
+
- [README](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/README.md) — install and quick start
|
|
225
|
+
- [COLLECTIONS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/COLLECTIONS.md) — collection schemas and customization
|
|
226
|
+
- [TRANSLATIONS](https://github.com/zealamic/payload-auth-rbac-plugin/blob/main/docs/TRANSLATIONS.md) — i18n keys
|