@plakboek/permissions 0.1.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/LICENSE +21 -0
- package/README.md +171 -0
- package/dist/index.d.ts +689 -0
- package/dist/index.js +864 -0
- package/package.json +48 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
//#region src/catalogue.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The frozen permission catalogue. This is the single source of truth for
|
|
4
|
+
* every permission string in the system (USER-05): it is owned by this
|
|
5
|
+
* package, exported read-only, and cannot be altered per installation.
|
|
6
|
+
*
|
|
7
|
+
* Label/description values are Lingui MessageDescriptor-compatible plain
|
|
8
|
+
* objects (`{ id, message }`). This package has zero runtime dependencies
|
|
9
|
+
* (D-16): it never imports `@lingui/core` itself, it only ships the message
|
|
10
|
+
* ids and English source text for a later phase's admin shell to resolve.
|
|
11
|
+
*
|
|
12
|
+
* Permission strings are `resource:action` with no own/any ownership split
|
|
13
|
+
* (D-05); publishing is always its own permission, separate from editing
|
|
14
|
+
* (D-06). This is the full v1 catalogue (D-07) — 45 permissions across 12
|
|
15
|
+
* groups. Per D-11 no wildcard or superadmin flag is added here; superadmin
|
|
16
|
+
* is a plain role holding `ALL_PERMISSIONS` (plan 01-04). Which of these
|
|
17
|
+
* permissions land on the shipped `admin` vs `superadmin` default role is
|
|
18
|
+
* also plan 01-04's concern — this file only defines what each permission
|
|
19
|
+
* string means, not who holds it by default.
|
|
20
|
+
*/
|
|
21
|
+
/** A Lingui MessageDescriptor-compatible plain object: `id` is the Lingui
|
|
22
|
+
* message key, `message` is the English source text. */
|
|
23
|
+
type PermissionMessage = {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly message: string;
|
|
26
|
+
};
|
|
27
|
+
/** Metadata carried by every catalogue entry. */
|
|
28
|
+
type PermissionMeta = {
|
|
29
|
+
readonly group: PermissionGroup;
|
|
30
|
+
readonly label: PermissionMessage;
|
|
31
|
+
readonly description: PermissionMessage;
|
|
32
|
+
};
|
|
33
|
+
/** The 12 v1 permission groups, in catalogue table order. */
|
|
34
|
+
type PermissionGroup = 'pages' | 'entries' | 'templates' | 'content-types' | 'media' | 'menus' | 'seo' | 'users' | 'audit' | 'settings' | 'api' | 'backups';
|
|
35
|
+
/**
|
|
36
|
+
* The frozen v1 permission catalogue (D-07). Every catalogue entry uses
|
|
37
|
+
* `resource:action` strings with no ownership split (D-05); publishing is
|
|
38
|
+
* its own permission, separate from editing (D-06).
|
|
39
|
+
*/
|
|
40
|
+
export declare const PERMISSIONS: {
|
|
41
|
+
readonly 'pages:read': {
|
|
42
|
+
readonly group: 'pages';
|
|
43
|
+
readonly label: {
|
|
44
|
+
readonly id: 'permissions.pages.read.label';
|
|
45
|
+
readonly message: 'View pages';
|
|
46
|
+
};
|
|
47
|
+
readonly description: {
|
|
48
|
+
readonly id: 'permissions.pages.read.description';
|
|
49
|
+
readonly message: 'See pages and their published content in the admin';
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
readonly 'pages:read-drafts': {
|
|
53
|
+
readonly group: 'pages';
|
|
54
|
+
readonly label: {
|
|
55
|
+
readonly id: 'permissions.pages.readDrafts.label';
|
|
56
|
+
readonly message: 'View page drafts';
|
|
57
|
+
};
|
|
58
|
+
readonly description: {
|
|
59
|
+
readonly id: 'permissions.pages.readDrafts.description';
|
|
60
|
+
readonly message: 'See unpublished drafts, previews and revision history of pages';
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
readonly 'pages:create': {
|
|
64
|
+
readonly group: 'pages';
|
|
65
|
+
readonly label: {
|
|
66
|
+
readonly id: 'permissions.pages.create.label';
|
|
67
|
+
readonly message: 'Create pages';
|
|
68
|
+
};
|
|
69
|
+
readonly description: {
|
|
70
|
+
readonly id: 'permissions.pages.create.description';
|
|
71
|
+
readonly message: 'Add new pages to the site';
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
readonly 'pages:edit': {
|
|
75
|
+
readonly group: 'pages';
|
|
76
|
+
readonly label: {
|
|
77
|
+
readonly id: 'permissions.pages.edit.label';
|
|
78
|
+
readonly message: 'Edit pages';
|
|
79
|
+
};
|
|
80
|
+
readonly description: {
|
|
81
|
+
readonly id: 'permissions.pages.edit.description';
|
|
82
|
+
readonly message: 'Change page content, blocks, layout, SEO fields and translations as drafts';
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
readonly 'pages:publish': {
|
|
86
|
+
readonly group: 'pages';
|
|
87
|
+
readonly label: {
|
|
88
|
+
readonly id: 'permissions.pages.publish.label';
|
|
89
|
+
readonly message: 'Publish pages';
|
|
90
|
+
};
|
|
91
|
+
readonly description: {
|
|
92
|
+
readonly id: 'permissions.pages.publish.description';
|
|
93
|
+
readonly message: 'Publish or schedule page drafts so visitors receive them';
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
readonly 'pages:delete': {
|
|
97
|
+
readonly group: 'pages';
|
|
98
|
+
readonly label: {
|
|
99
|
+
readonly id: 'permissions.pages.delete.label';
|
|
100
|
+
readonly message: 'Delete pages';
|
|
101
|
+
};
|
|
102
|
+
readonly description: {
|
|
103
|
+
readonly id: 'permissions.pages.delete.description';
|
|
104
|
+
readonly message: 'Move pages to the trash and restore them';
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
readonly 'pages:delete-permanent': {
|
|
108
|
+
readonly group: 'pages';
|
|
109
|
+
readonly label: {
|
|
110
|
+
readonly id: 'permissions.pages.deletePermanent.label';
|
|
111
|
+
readonly message: 'Permanently delete pages';
|
|
112
|
+
};
|
|
113
|
+
readonly description: {
|
|
114
|
+
readonly id: 'permissions.pages.deletePermanent.description';
|
|
115
|
+
readonly message: 'Permanently remove trashed pages';
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
readonly 'entries:read': {
|
|
119
|
+
readonly group: 'entries';
|
|
120
|
+
readonly label: {
|
|
121
|
+
readonly id: 'permissions.entries.read.label';
|
|
122
|
+
readonly message: 'View entries';
|
|
123
|
+
};
|
|
124
|
+
readonly description: {
|
|
125
|
+
readonly id: 'permissions.entries.read.description';
|
|
126
|
+
readonly message: 'See content entries and their published content in the admin';
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
readonly 'entries:read-drafts': {
|
|
130
|
+
readonly group: 'entries';
|
|
131
|
+
readonly label: {
|
|
132
|
+
readonly id: 'permissions.entries.readDrafts.label';
|
|
133
|
+
readonly message: 'View entry drafts';
|
|
134
|
+
};
|
|
135
|
+
readonly description: {
|
|
136
|
+
readonly id: 'permissions.entries.readDrafts.description';
|
|
137
|
+
readonly message: 'See unpublished drafts, previews and revision history of entries';
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
readonly 'entries:create': {
|
|
141
|
+
readonly group: 'entries';
|
|
142
|
+
readonly label: {
|
|
143
|
+
readonly id: 'permissions.entries.create.label';
|
|
144
|
+
readonly message: 'Create entries';
|
|
145
|
+
};
|
|
146
|
+
readonly description: {
|
|
147
|
+
readonly id: 'permissions.entries.create.description';
|
|
148
|
+
readonly message: 'Add new content entries';
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
readonly 'entries:edit': {
|
|
152
|
+
readonly group: 'entries';
|
|
153
|
+
readonly label: {
|
|
154
|
+
readonly id: 'permissions.entries.edit.label';
|
|
155
|
+
readonly message: 'Edit entries';
|
|
156
|
+
};
|
|
157
|
+
readonly description: {
|
|
158
|
+
readonly id: 'permissions.entries.edit.description';
|
|
159
|
+
readonly message: 'Change entry fields and translations as drafts';
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
readonly 'entries:publish': {
|
|
163
|
+
readonly group: 'entries';
|
|
164
|
+
readonly label: {
|
|
165
|
+
readonly id: 'permissions.entries.publish.label';
|
|
166
|
+
readonly message: 'Publish entries';
|
|
167
|
+
};
|
|
168
|
+
readonly description: {
|
|
169
|
+
readonly id: 'permissions.entries.publish.description';
|
|
170
|
+
readonly message: 'Publish or schedule entry drafts so visitors receive them';
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
readonly 'entries:delete': {
|
|
174
|
+
readonly group: 'entries';
|
|
175
|
+
readonly label: {
|
|
176
|
+
readonly id: 'permissions.entries.delete.label';
|
|
177
|
+
readonly message: 'Delete entries';
|
|
178
|
+
};
|
|
179
|
+
readonly description: {
|
|
180
|
+
readonly id: 'permissions.entries.delete.description';
|
|
181
|
+
readonly message: 'Move entries to the trash and restore them';
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
readonly 'entries:delete-permanent': {
|
|
185
|
+
readonly group: 'entries';
|
|
186
|
+
readonly label: {
|
|
187
|
+
readonly id: 'permissions.entries.deletePermanent.label';
|
|
188
|
+
readonly message: 'Permanently delete entries';
|
|
189
|
+
};
|
|
190
|
+
readonly description: {
|
|
191
|
+
readonly id: 'permissions.entries.deletePermanent.description';
|
|
192
|
+
readonly message: 'Permanently remove trashed entries';
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
readonly 'templates:edit': {
|
|
196
|
+
readonly group: 'templates';
|
|
197
|
+
readonly label: {
|
|
198
|
+
readonly id: 'permissions.templates.edit.label';
|
|
199
|
+
readonly message: 'Edit detail templates';
|
|
200
|
+
};
|
|
201
|
+
readonly description: {
|
|
202
|
+
readonly id: 'permissions.templates.edit.description';
|
|
203
|
+
readonly message: "Change the shared block tree used to render a content type's detail pages";
|
|
204
|
+
};
|
|
205
|
+
};
|
|
206
|
+
readonly 'templates:publish': {
|
|
207
|
+
readonly group: 'templates';
|
|
208
|
+
readonly label: {
|
|
209
|
+
readonly id: 'permissions.templates.publish.label';
|
|
210
|
+
readonly message: 'Publish detail templates';
|
|
211
|
+
};
|
|
212
|
+
readonly description: {
|
|
213
|
+
readonly id: 'permissions.templates.publish.description';
|
|
214
|
+
readonly message: 'Publish changes to shared detail templates';
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
readonly 'content-types:read': {
|
|
218
|
+
readonly group: 'content-types';
|
|
219
|
+
readonly label: {
|
|
220
|
+
readonly id: 'permissions.contentTypes.read.label';
|
|
221
|
+
readonly message: 'View content types';
|
|
222
|
+
};
|
|
223
|
+
readonly description: {
|
|
224
|
+
readonly id: 'permissions.contentTypes.read.description';
|
|
225
|
+
readonly message: 'See content types and the fields attached to them';
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
readonly 'content-types:create': {
|
|
229
|
+
readonly group: 'content-types';
|
|
230
|
+
readonly label: {
|
|
231
|
+
readonly id: 'permissions.contentTypes.create.label';
|
|
232
|
+
readonly message: 'Create content types';
|
|
233
|
+
};
|
|
234
|
+
readonly description: {
|
|
235
|
+
readonly id: 'permissions.contentTypes.create.description';
|
|
236
|
+
readonly message: 'Add new content types';
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
readonly 'content-types:edit': {
|
|
240
|
+
readonly group: 'content-types';
|
|
241
|
+
readonly label: {
|
|
242
|
+
readonly id: 'permissions.contentTypes.edit.label';
|
|
243
|
+
readonly message: 'Edit content types';
|
|
244
|
+
};
|
|
245
|
+
readonly description: {
|
|
246
|
+
readonly id: 'permissions.contentTypes.edit.description';
|
|
247
|
+
readonly message: 'Change content type settings and add, change or remove fields';
|
|
248
|
+
};
|
|
249
|
+
};
|
|
250
|
+
readonly 'content-types:delete': {
|
|
251
|
+
readonly group: 'content-types';
|
|
252
|
+
readonly label: {
|
|
253
|
+
readonly id: 'permissions.contentTypes.delete.label';
|
|
254
|
+
readonly message: 'Delete content types';
|
|
255
|
+
};
|
|
256
|
+
readonly description: {
|
|
257
|
+
readonly id: 'permissions.contentTypes.delete.description';
|
|
258
|
+
readonly message: 'Remove content types';
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
readonly 'media:read': {
|
|
262
|
+
readonly group: 'media';
|
|
263
|
+
readonly label: {
|
|
264
|
+
readonly id: 'permissions.media.read.label';
|
|
265
|
+
readonly message: 'View media';
|
|
266
|
+
};
|
|
267
|
+
readonly description: {
|
|
268
|
+
readonly id: 'permissions.media.read.description';
|
|
269
|
+
readonly message: 'Browse and search the media library';
|
|
270
|
+
};
|
|
271
|
+
};
|
|
272
|
+
readonly 'media:upload': {
|
|
273
|
+
readonly group: 'media';
|
|
274
|
+
readonly label: {
|
|
275
|
+
readonly id: 'permissions.media.upload.label';
|
|
276
|
+
readonly message: 'Upload media';
|
|
277
|
+
};
|
|
278
|
+
readonly description: {
|
|
279
|
+
readonly id: 'permissions.media.upload.description';
|
|
280
|
+
readonly message: 'Upload images and files';
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
readonly 'media:edit': {
|
|
284
|
+
readonly group: 'media';
|
|
285
|
+
readonly label: {
|
|
286
|
+
readonly id: 'permissions.media.edit.label';
|
|
287
|
+
readonly message: 'Edit media';
|
|
288
|
+
};
|
|
289
|
+
readonly description: {
|
|
290
|
+
readonly id: 'permissions.media.edit.description';
|
|
291
|
+
readonly message: 'Change alt text, copyright labels and replace assets in place';
|
|
292
|
+
};
|
|
293
|
+
};
|
|
294
|
+
readonly 'media:delete': {
|
|
295
|
+
readonly group: 'media';
|
|
296
|
+
readonly label: {
|
|
297
|
+
readonly id: 'permissions.media.delete.label';
|
|
298
|
+
readonly message: 'Delete media';
|
|
299
|
+
};
|
|
300
|
+
readonly description: {
|
|
301
|
+
readonly id: 'permissions.media.delete.description';
|
|
302
|
+
readonly message: 'Delete assets, including ones still in use after a warning';
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
readonly 'menus:read': {
|
|
306
|
+
readonly group: 'menus';
|
|
307
|
+
readonly label: {
|
|
308
|
+
readonly id: 'permissions.menus.read.label';
|
|
309
|
+
readonly message: 'View menus';
|
|
310
|
+
};
|
|
311
|
+
readonly description: {
|
|
312
|
+
readonly id: 'permissions.menus.read.description';
|
|
313
|
+
readonly message: 'See menus declared by the site and their links';
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
readonly 'menus:edit': {
|
|
317
|
+
readonly group: 'menus';
|
|
318
|
+
readonly label: {
|
|
319
|
+
readonly id: 'permissions.menus.edit.label';
|
|
320
|
+
readonly message: 'Edit menus';
|
|
321
|
+
};
|
|
322
|
+
readonly description: {
|
|
323
|
+
readonly id: 'permissions.menus.edit.description';
|
|
324
|
+
readonly message: 'Add, remove and re-arrange menu links';
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
readonly 'redirects:read': {
|
|
328
|
+
readonly group: 'seo';
|
|
329
|
+
readonly label: {
|
|
330
|
+
readonly id: 'permissions.redirects.read.label';
|
|
331
|
+
readonly message: 'View redirects';
|
|
332
|
+
};
|
|
333
|
+
readonly description: {
|
|
334
|
+
readonly id: 'permissions.redirects.read.description';
|
|
335
|
+
readonly message: 'See redirects and how long each has been active';
|
|
336
|
+
};
|
|
337
|
+
};
|
|
338
|
+
readonly 'redirects:manage': {
|
|
339
|
+
readonly group: 'seo';
|
|
340
|
+
readonly label: {
|
|
341
|
+
readonly id: 'permissions.redirects.manage.label';
|
|
342
|
+
readonly message: 'Manage redirects';
|
|
343
|
+
};
|
|
344
|
+
readonly description: {
|
|
345
|
+
readonly id: 'permissions.redirects.manage.description';
|
|
346
|
+
readonly message: 'Create, change and remove redirects';
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
readonly 'users:read': {
|
|
350
|
+
readonly group: 'users';
|
|
351
|
+
readonly label: {
|
|
352
|
+
readonly id: 'permissions.users.read.label';
|
|
353
|
+
readonly message: 'View users';
|
|
354
|
+
};
|
|
355
|
+
readonly description: {
|
|
356
|
+
readonly id: 'permissions.users.read.description';
|
|
357
|
+
readonly message: 'See users and their roles';
|
|
358
|
+
};
|
|
359
|
+
};
|
|
360
|
+
readonly 'users:create': {
|
|
361
|
+
readonly group: 'users';
|
|
362
|
+
readonly label: {
|
|
363
|
+
readonly id: 'permissions.users.create.label';
|
|
364
|
+
readonly message: 'Invite users';
|
|
365
|
+
};
|
|
366
|
+
readonly description: {
|
|
367
|
+
readonly id: 'permissions.users.create.description';
|
|
368
|
+
readonly message: 'Add users and send or resend set-password emails';
|
|
369
|
+
};
|
|
370
|
+
};
|
|
371
|
+
readonly 'users:edit': {
|
|
372
|
+
readonly group: 'users';
|
|
373
|
+
readonly label: {
|
|
374
|
+
readonly id: 'permissions.users.edit.label';
|
|
375
|
+
readonly message: 'Edit users';
|
|
376
|
+
};
|
|
377
|
+
readonly description: {
|
|
378
|
+
readonly id: 'permissions.users.edit.description';
|
|
379
|
+
readonly message: "Change other users' profile details";
|
|
380
|
+
};
|
|
381
|
+
};
|
|
382
|
+
readonly 'users:deactivate': {
|
|
383
|
+
readonly group: 'users';
|
|
384
|
+
readonly label: {
|
|
385
|
+
readonly id: 'permissions.users.deactivate.label';
|
|
386
|
+
readonly message: 'Deactivate users';
|
|
387
|
+
};
|
|
388
|
+
readonly description: {
|
|
389
|
+
readonly id: 'permissions.users.deactivate.description';
|
|
390
|
+
readonly message: 'Deactivate and reactivate users';
|
|
391
|
+
};
|
|
392
|
+
};
|
|
393
|
+
readonly 'users:assign-roles': {
|
|
394
|
+
readonly group: 'users';
|
|
395
|
+
readonly label: {
|
|
396
|
+
readonly id: 'permissions.users.assignRoles.label';
|
|
397
|
+
readonly message: 'Assign roles';
|
|
398
|
+
};
|
|
399
|
+
readonly description: {
|
|
400
|
+
readonly id: 'permissions.users.assignRoles.description';
|
|
401
|
+
readonly message: 'Assign a code-defined role to a user';
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
readonly 'users:reset-password': {
|
|
405
|
+
readonly group: 'users';
|
|
406
|
+
readonly label: {
|
|
407
|
+
readonly id: 'permissions.users.resetPassword.label';
|
|
408
|
+
readonly message: 'Reset passwords';
|
|
409
|
+
};
|
|
410
|
+
readonly description: {
|
|
411
|
+
readonly id: 'permissions.users.resetPassword.description';
|
|
412
|
+
readonly message: "Set or reset another user's password";
|
|
413
|
+
};
|
|
414
|
+
};
|
|
415
|
+
readonly 'users:impersonate': {
|
|
416
|
+
readonly group: 'users';
|
|
417
|
+
readonly label: {
|
|
418
|
+
readonly id: 'permissions.users.impersonate.label';
|
|
419
|
+
readonly message: 'Impersonate users';
|
|
420
|
+
};
|
|
421
|
+
readonly description: {
|
|
422
|
+
readonly id: 'permissions.users.impersonate.description';
|
|
423
|
+
readonly message: 'Act as another user and return to your own session';
|
|
424
|
+
};
|
|
425
|
+
};
|
|
426
|
+
readonly 'audit-log:read': {
|
|
427
|
+
readonly group: 'audit';
|
|
428
|
+
readonly label: {
|
|
429
|
+
readonly id: 'permissions.auditLog.read.label';
|
|
430
|
+
readonly message: 'View audit log';
|
|
431
|
+
};
|
|
432
|
+
readonly description: {
|
|
433
|
+
readonly id: 'permissions.auditLog.read.description';
|
|
434
|
+
readonly message: 'See the audit log of data-changing actions';
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
readonly 'settings:read': {
|
|
438
|
+
readonly group: 'settings';
|
|
439
|
+
readonly label: {
|
|
440
|
+
readonly id: 'permissions.settings.read.label';
|
|
441
|
+
readonly message: 'View settings';
|
|
442
|
+
};
|
|
443
|
+
readonly description: {
|
|
444
|
+
readonly id: 'permissions.settings.read.description';
|
|
445
|
+
readonly message: 'See installation settings';
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
readonly 'settings:manage': {
|
|
449
|
+
readonly group: 'settings';
|
|
450
|
+
readonly label: {
|
|
451
|
+
readonly id: 'permissions.settings.manage.label';
|
|
452
|
+
readonly message: 'Manage settings';
|
|
453
|
+
};
|
|
454
|
+
readonly description: {
|
|
455
|
+
readonly id: 'permissions.settings.manage.description';
|
|
456
|
+
readonly message: 'Change core configuration, styles and rules';
|
|
457
|
+
};
|
|
458
|
+
};
|
|
459
|
+
readonly 'modules:manage': {
|
|
460
|
+
readonly group: 'settings';
|
|
461
|
+
readonly label: {
|
|
462
|
+
readonly id: 'permissions.modules.manage.label';
|
|
463
|
+
readonly message: 'Manage modules';
|
|
464
|
+
};
|
|
465
|
+
readonly description: {
|
|
466
|
+
readonly id: 'permissions.modules.manage.description';
|
|
467
|
+
readonly message: 'Turn installation modules on or off';
|
|
468
|
+
};
|
|
469
|
+
};
|
|
470
|
+
readonly 'blocks:manage': {
|
|
471
|
+
readonly group: 'settings';
|
|
472
|
+
readonly label: {
|
|
473
|
+
readonly id: 'permissions.blocks.manage.label';
|
|
474
|
+
readonly message: 'Manage built-in blocks';
|
|
475
|
+
};
|
|
476
|
+
readonly description: {
|
|
477
|
+
readonly id: 'permissions.blocks.manage.description';
|
|
478
|
+
readonly message: 'Turn individual built-in sections and blocks on or off';
|
|
479
|
+
};
|
|
480
|
+
};
|
|
481
|
+
readonly 'bootstrap:run': {
|
|
482
|
+
readonly group: 'settings';
|
|
483
|
+
readonly label: {
|
|
484
|
+
readonly id: 'permissions.bootstrap.run.label';
|
|
485
|
+
readonly message: 'Run bootstrap';
|
|
486
|
+
};
|
|
487
|
+
readonly description: {
|
|
488
|
+
readonly id: 'permissions.bootstrap.run.description';
|
|
489
|
+
readonly message: 'Run installation bootstrap steps';
|
|
490
|
+
};
|
|
491
|
+
};
|
|
492
|
+
readonly 'api-tokens:create': {
|
|
493
|
+
readonly group: 'api';
|
|
494
|
+
readonly label: {
|
|
495
|
+
readonly id: 'permissions.apiTokens.create.label';
|
|
496
|
+
readonly message: 'Create API tokens';
|
|
497
|
+
};
|
|
498
|
+
readonly description: {
|
|
499
|
+
readonly id: 'permissions.apiTokens.create.description';
|
|
500
|
+
readonly message: 'Create and revoke your own API tokens for MCP clients';
|
|
501
|
+
};
|
|
502
|
+
};
|
|
503
|
+
readonly 'api-tokens:manage': {
|
|
504
|
+
readonly group: 'api';
|
|
505
|
+
readonly label: {
|
|
506
|
+
readonly id: 'permissions.apiTokens.manage.label';
|
|
507
|
+
readonly message: 'Manage API tokens';
|
|
508
|
+
};
|
|
509
|
+
readonly description: {
|
|
510
|
+
readonly id: 'permissions.apiTokens.manage.description';
|
|
511
|
+
readonly message: "See and revoke any user's API tokens";
|
|
512
|
+
};
|
|
513
|
+
};
|
|
514
|
+
readonly 'backups:manage': {
|
|
515
|
+
readonly group: 'backups';
|
|
516
|
+
readonly label: {
|
|
517
|
+
readonly id: 'permissions.backups.manage.label';
|
|
518
|
+
readonly message: 'Manage backups';
|
|
519
|
+
};
|
|
520
|
+
readonly description: {
|
|
521
|
+
readonly id: 'permissions.backups.manage.description';
|
|
522
|
+
readonly message: 'Configure backup targets and run backups';
|
|
523
|
+
};
|
|
524
|
+
};
|
|
525
|
+
readonly 'backups:restore': {
|
|
526
|
+
readonly group: 'backups';
|
|
527
|
+
readonly label: {
|
|
528
|
+
readonly id: 'permissions.backups.restore.label';
|
|
529
|
+
readonly message: 'Restore backups';
|
|
530
|
+
};
|
|
531
|
+
readonly description: {
|
|
532
|
+
readonly id: 'permissions.backups.restore.description';
|
|
533
|
+
readonly message: 'Restore the installation from a backup';
|
|
534
|
+
};
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
/** The union of every valid permission string, derived from the catalogue. */
|
|
538
|
+
type Permission = keyof typeof PERMISSIONS;
|
|
539
|
+
/** Runtime type guard for an arbitrary value being a known permission string.
|
|
540
|
+
* Uses `Object.hasOwn` (not `in` or bracket access) so inherited
|
|
541
|
+
* `Object.prototype` keys (`constructor`, `toString`, `__proto__`, ...) are
|
|
542
|
+
* never classified as permissions (T-01-08). */
|
|
543
|
+
export declare function isPermission(value: unknown): value is Permission;
|
|
544
|
+
/** Every permission string, in catalogue declaration order, frozen. */
|
|
545
|
+
export declare const ALL_PERMISSIONS: readonly Permission[];
|
|
546
|
+
/** The 12 v1 permission groups, in catalogue table order, frozen. */
|
|
547
|
+
export declare const PERMISSION_GROUPS: readonly PermissionGroup[];
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/deprecated.d.ts
|
|
550
|
+
/**
|
|
551
|
+
* D-09 breaking-change policy for permission strings:
|
|
552
|
+
*
|
|
553
|
+
* - Adding a permission is a minor version bump.
|
|
554
|
+
* - Renaming or removing a permission is a major version bump (while
|
|
555
|
+
* pre-1.0, per D-17, it is a minor bump instead) -- and the old name
|
|
556
|
+
* stays in this table, pointing at its replacement, for one major
|
|
557
|
+
* version after the rename/removal ships. Host configs that still
|
|
558
|
+
* reference the old name keep booting, with a warning (D-10); they are
|
|
559
|
+
* never rejected outright during that window.
|
|
560
|
+
* - An alias key must never equal a canonical key in `PERMISSIONS`
|
|
561
|
+
* (catalogue.ts) -- a key that renames back onto itself is not a
|
|
562
|
+
* deprecation, it is a bug in this table.
|
|
563
|
+
*
|
|
564
|
+
* No permission has been renamed or removed since the v1 catalogue shipped
|
|
565
|
+
* at 0.1.0, so this table starts empty. `DeprecatedPermission` (`keyof
|
|
566
|
+
* typeof DEPRECATED_PERMISSION_ALIASES`) is therefore `never` today -- that
|
|
567
|
+
* is intentional and still a literal type, not `string`: the first entry
|
|
568
|
+
* added here narrows it to a real literal union, it never widens.
|
|
569
|
+
*/
|
|
570
|
+
export declare const DEPRECATED_PERMISSION_ALIASES: {};
|
|
571
|
+
/** The union of every deprecated (renamed/removed) permission alias key. */
|
|
572
|
+
type DeprecatedPermission = keyof typeof DEPRECATED_PERMISSION_ALIASES;
|
|
573
|
+
/** The result of classifying an arbitrary string against the catalogue and
|
|
574
|
+
* the deprecated-alias table. */
|
|
575
|
+
type PermissionNameResolution = {
|
|
576
|
+
readonly kind: 'canonical';
|
|
577
|
+
readonly permission: Permission;
|
|
578
|
+
} | {
|
|
579
|
+
readonly kind: 'deprecated';
|
|
580
|
+
readonly alias: string;
|
|
581
|
+
readonly permission: Permission;
|
|
582
|
+
} | {
|
|
583
|
+
readonly kind: 'unknown';
|
|
584
|
+
readonly value: string;
|
|
585
|
+
};
|
|
586
|
+
/**
|
|
587
|
+
* Classify an arbitrary string as a canonical permission, a deprecated
|
|
588
|
+
* alias (per `aliases`, defaulting to the shipped
|
|
589
|
+
* `DEPRECATED_PERMISSION_ALIASES`), or unknown.
|
|
590
|
+
*
|
|
591
|
+
* Checks `isPermission` first so a canonical name is never misclassified
|
|
592
|
+
* as deprecated even if it were accidentally also present as an alias key.
|
|
593
|
+
* Alias lookup uses `Object.hasOwn` (not `in` or bracket access), so
|
|
594
|
+
* inherited `Object.prototype` keys (`__proto__`, `constructor`, ...) are
|
|
595
|
+
* always classified as unknown, never as a hit (T-01-08).
|
|
596
|
+
*/
|
|
597
|
+
export declare function resolvePermissionName(value: string, aliases?: Readonly<Record<string, Permission>>): PermissionNameResolution;
|
|
598
|
+
//#endregion
|
|
599
|
+
//#region src/roles.d.ts
|
|
600
|
+
/** A single role's permission list, as a host writes it: canonical
|
|
601
|
+
* `Permission` strings, or a still-accepted deprecated alias (D-09).
|
|
602
|
+
* `DeprecatedPermission` is `never` at 0.1.0 (no permission has been
|
|
603
|
+
* renamed/removed yet, see deprecated.ts) -- the union is written this way
|
|
604
|
+
* deliberately so it widens automatically the day the alias table gets its
|
|
605
|
+
* first real entry, without this type needing to change. */
|
|
606
|
+
type RolePermissionList = readonly (Permission | DeprecatedPermission)[];
|
|
607
|
+
/**
|
|
608
|
+
* The shape a host passes to `defineRoles`. `superadmin` is a required,
|
|
609
|
+
* reserved key (D-12); any other lowercase-kebab role key maps to its own
|
|
610
|
+
* permission list.
|
|
611
|
+
*/
|
|
612
|
+
type RoleConfig = Readonly<Record<string, RolePermissionList>> & {
|
|
613
|
+
readonly superadmin: RolePermissionList;
|
|
614
|
+
};
|
|
615
|
+
/** The validated, normalized result of `defineRoles`/`validateRoleConfig`:
|
|
616
|
+
* every role's permissions are deduped, catalogue-ordered `Permission`
|
|
617
|
+
* strings (deprecated aliases already resolved to their canonical name). */
|
|
618
|
+
type DefinedRoles<K extends string = string> = Readonly<Record<K, readonly Permission[]>>;
|
|
619
|
+
/** Emitted once per deprecated permission string accepted into a role. */
|
|
620
|
+
type DeprecatedPermissionEvent = {
|
|
621
|
+
readonly roleKey: string;
|
|
622
|
+
readonly alias: string;
|
|
623
|
+
readonly permission: Permission;
|
|
624
|
+
};
|
|
625
|
+
type DefineRolesOptions = {
|
|
626
|
+
onDeprecatedPermission?: (event: DeprecatedPermissionEvent) => void;
|
|
627
|
+
};
|
|
628
|
+
type RoleConfigIssueCode = 'MISSING_SUPERADMIN' | 'SUPERADMIN_NOT_ALL_PERMISSIONS' | 'UNKNOWN_PERMISSION' | 'INVALID_ROLE_KEY' | 'INVALID_PERMISSION_LIST' | 'INVALID_ROLE_CONFIG';
|
|
629
|
+
type RoleConfigIssue = {
|
|
630
|
+
readonly code: RoleConfigIssueCode;
|
|
631
|
+
readonly roleKey?: string;
|
|
632
|
+
readonly value?: string;
|
|
633
|
+
readonly message: string;
|
|
634
|
+
};
|
|
635
|
+
/** Thrown by `defineRoles`/`validateRoleConfig` with every problem found in
|
|
636
|
+
* the config, collected before throwing once (never one-issue-at-a-time). */
|
|
637
|
+
export declare class RoleConfigError extends Error {
|
|
638
|
+
readonly issues: readonly RoleConfigIssue[];
|
|
639
|
+
constructor(issues: readonly RoleConfigIssue[]);
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Validate and normalize a host's role config. Throws a single
|
|
643
|
+
* `RoleConfigError` listing every problem found; on success, returns a
|
|
644
|
+
* frozen, deduped, catalogue-ordered permission map per role.
|
|
645
|
+
*/
|
|
646
|
+
export declare function defineRoles<const T extends RoleConfig>(roles: T, options?: DefineRolesOptions): DefinedRoles<Extract<keyof T, string>>;
|
|
647
|
+
/**
|
|
648
|
+
* The shipped `superadmin`/`admin`/`editor` role set (D-13). Works with
|
|
649
|
+
* zero customisation (USER-04); hosts compose via
|
|
650
|
+
* `defineRoles({ ...defaultRoles, client: [...] })` (D-14).
|
|
651
|
+
*/
|
|
652
|
+
export declare const defaultRoles: {
|
|
653
|
+
readonly superadmin: readonly ("api-tokens:create" | "api-tokens:manage" | "audit-log:read" | "backups:manage" | "backups:restore" | "blocks:manage" | "bootstrap:run" | "content-types:create" | "content-types:delete" | "content-types:edit" | "content-types:read" | "entries:create" | "entries:delete" | "entries:delete-permanent" | "entries:edit" | "entries:publish" | "entries:read" | "entries:read-drafts" | "media:delete" | "media:edit" | "media:read" | "media:upload" | "menus:edit" | "menus:read" | "modules:manage" | "pages:create" | "pages:delete" | "pages:delete-permanent" | "pages:edit" | "pages:publish" | "pages:read" | "pages:read-drafts" | "redirects:manage" | "redirects:read" | "settings:manage" | "settings:read" | "templates:edit" | "templates:publish" | "users:assign-roles" | "users:create" | "users:deactivate" | "users:edit" | "users:impersonate" | "users:read" | "users:reset-password")[];
|
|
654
|
+
readonly admin: readonly ["pages:read", "pages:read-drafts", "pages:create", "pages:edit", "pages:publish", "pages:delete", "entries:read", "entries:read-drafts", "entries:create", "entries:edit", "entries:publish", "entries:delete", "templates:edit", "templates:publish", "content-types:read", "content-types:create", "content-types:edit", "content-types:delete", "media:read", "media:upload", "media:edit", "media:delete", "menus:read", "menus:edit", "redirects:read", "redirects:manage", "users:read", "users:create", "users:edit", "users:deactivate", "users:assign-roles", "users:reset-password", "audit-log:read", "settings:read", "settings:manage", "api-tokens:create", "api-tokens:manage"];
|
|
655
|
+
readonly editor: readonly ["pages:read", "pages:read-drafts", "pages:create", "pages:edit", "pages:publish", "pages:delete", "entries:read", "entries:read-drafts", "entries:create", "entries:edit", "entries:publish", "entries:delete", "templates:edit", "templates:publish", "content-types:read", "media:read", "media:upload", "media:edit", "menus:read", "menus:edit", "redirects:read", "api-tokens:create"];
|
|
656
|
+
};
|
|
657
|
+
//#endregion
|
|
658
|
+
//#region src/resolve.d.ts
|
|
659
|
+
/** Emitted when `resolve` is asked for a role key absent from the code role
|
|
660
|
+
* map. Carries only the role key, the opaque user id (when known), when it
|
|
661
|
+
* happened, and how many prior lookups for this same key were suppressed
|
|
662
|
+
* by the rate limit -- never anything else about the user (T-01-23). */
|
|
663
|
+
type OrphanedRoleEvent = {
|
|
664
|
+
readonly roleKey: string;
|
|
665
|
+
readonly userId?: string;
|
|
666
|
+
readonly occurredAt: Date;
|
|
667
|
+
readonly suppressedCount: number;
|
|
668
|
+
};
|
|
669
|
+
type OrphanedRoleHook = (event: OrphanedRoleEvent) => void;
|
|
670
|
+
type PermissionResolverOptions = {
|
|
671
|
+
onOrphanedRole?: OrphanedRoleHook;
|
|
672
|
+
rateLimitMs?: number;
|
|
673
|
+
now?: () => number;
|
|
674
|
+
};
|
|
675
|
+
type PermissionResolver = {
|
|
676
|
+
resolve(roleKey: string, context?: {
|
|
677
|
+
userId?: string;
|
|
678
|
+
}): ReadonlySet<Permission>;
|
|
679
|
+
isKnownRole(roleKey: string): boolean;
|
|
680
|
+
};
|
|
681
|
+
/**
|
|
682
|
+
* Build a resolver over a validated role map (the output of `defineRoles`).
|
|
683
|
+
* `resolve` never throws: an unknown role key returns an empty set and
|
|
684
|
+
* reports the orphan through `onOrphanedRole` (default `console.warn`),
|
|
685
|
+
* rate-limited independently per key.
|
|
686
|
+
*/
|
|
687
|
+
export declare function createPermissionResolver(roles: DefinedRoles, options?: PermissionResolverOptions): PermissionResolver;
|
|
688
|
+
//#endregion
|
|
689
|
+
export type { DefineRolesOptions, DefinedRoles, DeprecatedPermission, DeprecatedPermissionEvent, OrphanedRoleEvent, OrphanedRoleHook, Permission, PermissionGroup, PermissionMessage, PermissionMeta, PermissionNameResolution, PermissionResolver, PermissionResolverOptions, RoleConfig, RoleConfigIssue, RoleConfigIssueCode, RolePermissionList };
|