snipe-auth-rbac 0.5.0 → 0.6.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/dist/admin/index.cjs +113 -6
- package/dist/admin/index.cjs.map +1 -1
- package/dist/admin/index.d.cts +99 -20
- package/dist/admin/index.d.ts +99 -20
- package/dist/admin/index.js +112 -6
- package/dist/admin/index.js.map +1 -1
- package/package.json +1 -1
- package/sql/0001_initial.sql +236 -59
package/dist/admin/index.d.cts
CHANGED
|
@@ -54,6 +54,21 @@ interface AdminResourceDependency {
|
|
|
54
54
|
child_resource: string;
|
|
55
55
|
action: Action;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* One row of `rbac.role_permission_overrides` — an explicit
|
|
59
|
+
* per-role suppression that takes a cell OFF even when the
|
|
60
|
+
* dependency graph would otherwise imply it (or when a direct
|
|
61
|
+
* grant row exists). Used to express "Anwalt has tenants:read
|
|
62
|
+
* but should NOT see payments, even though tenants.dependsOn
|
|
63
|
+
* includes payments".
|
|
64
|
+
*
|
|
65
|
+
* Available since 0.6.0.
|
|
66
|
+
*/
|
|
67
|
+
interface AdminRolePermissionOverride {
|
|
68
|
+
role_id: string;
|
|
69
|
+
resource: string;
|
|
70
|
+
action: Action;
|
|
71
|
+
}
|
|
57
72
|
interface AdminCompany {
|
|
58
73
|
id: string;
|
|
59
74
|
name: string;
|
|
@@ -144,6 +159,26 @@ interface AdminTransport {
|
|
|
144
159
|
* cascade on a parent toggle.
|
|
145
160
|
*/
|
|
146
161
|
listResourceDependencies(): Promise<AdminResourceDependency[]>;
|
|
162
|
+
/**
|
|
163
|
+
* 0.6.0+. Read every per-role override for the given role.
|
|
164
|
+
* Returns the (resource, action) cells that the admin has
|
|
165
|
+
* explicitly suppressed, even though dependency-graph expansion
|
|
166
|
+
* would otherwise grant them.
|
|
167
|
+
*/
|
|
168
|
+
listRolePermissionOverrides(roleId: string): Promise<AdminRolePermissionOverride[]>;
|
|
169
|
+
/**
|
|
170
|
+
* 0.6.0+. Set or clear a per-role override:
|
|
171
|
+
* * suppress=true → INSERT (idempotent via ON CONFLICT)
|
|
172
|
+
* * suppress=false → DELETE
|
|
173
|
+
* Resolver functions subtract the row from the user's expanded
|
|
174
|
+
* grant set as soon as it's written.
|
|
175
|
+
*/
|
|
176
|
+
setRolePermissionOverride(args: {
|
|
177
|
+
role_id: string;
|
|
178
|
+
resource: string;
|
|
179
|
+
action: Action;
|
|
180
|
+
suppress: boolean;
|
|
181
|
+
}): Promise<void>;
|
|
147
182
|
/**
|
|
148
183
|
* Materialise `rbac.role_permissions` rows from a template role's
|
|
149
184
|
* `default_permissions` JSONB pattern. Calls the SQL function
|
|
@@ -342,6 +377,25 @@ declare function useAdminResourceDependencies(): {
|
|
|
342
377
|
isLoading: boolean;
|
|
343
378
|
error: Error | null;
|
|
344
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* 0.6.0+. Per-role override map. Returns a Set of
|
|
382
|
+
* `"<resource>:<action>"` keys for the given role plus a
|
|
383
|
+
* `setOverride(resource, action, suppress)` mutator. Optimistic —
|
|
384
|
+
* the local set flips immediately, then a re-fetch reconciles.
|
|
385
|
+
*
|
|
386
|
+
* Use this in tandem with `useRolePermissionGrid` to render a
|
|
387
|
+
* matrix UI that distinguishes:
|
|
388
|
+
* * direct grants (the row is on rbac.role_permissions)
|
|
389
|
+
* * implied grants (resource_dependencies expansion)
|
|
390
|
+
* * overrides (this hook's set — admin clicked an implied cell
|
|
391
|
+
* off to carve it out for this specific role)
|
|
392
|
+
*/
|
|
393
|
+
declare function useRolePermissionOverrides(roleId: string | null): {
|
|
394
|
+
overrides: Set<string>;
|
|
395
|
+
setOverride: (resource: string, action: Action, suppress: boolean) => Promise<void>;
|
|
396
|
+
error: Error | null;
|
|
397
|
+
refresh: () => Promise<void>;
|
|
398
|
+
};
|
|
345
399
|
declare function useCreateCompany(): {
|
|
346
400
|
isPending: boolean;
|
|
347
401
|
error: Error | null;
|
|
@@ -368,15 +422,19 @@ interface RolePermissionGrid {
|
|
|
368
422
|
};
|
|
369
423
|
}
|
|
370
424
|
/**
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
* an
|
|
374
|
-
*
|
|
425
|
+
* Per-cell origin marker:
|
|
426
|
+
* * `'direct'` — explicit admin grant on rbac.role_permissions
|
|
427
|
+
* * `'override'` — admin set an override on rbac.role_permission_overrides
|
|
428
|
+
* (0.6.0+; cell is OFF even if a direct or
|
|
429
|
+
* implied grant would otherwise apply)
|
|
430
|
+
* * `<string>` — name of the parent resource that implies this
|
|
431
|
+
* cell via rbac.resource_dependencies
|
|
432
|
+
* * `null` — neither granted nor implied
|
|
375
433
|
*
|
|
376
434
|
* In 0.4.x this was driven by the `<action>_granted_via` columns on
|
|
377
|
-
* rbac.role_permissions. In 0.5.0 implied rows are no longer
|
|
435
|
+
* rbac.role_permissions. In 0.5.0+ implied rows are no longer
|
|
378
436
|
* materialised — origin is computed client-side from the dependency
|
|
379
|
-
* graph + the role's direct grants.
|
|
437
|
+
* graph + the role's direct grants + (0.6.0+) any overrides.
|
|
380
438
|
*/
|
|
381
439
|
interface RolePermissionOriginGrid {
|
|
382
440
|
[resource: string]: {
|
|
@@ -390,6 +448,15 @@ declare function useRolePermissionGrid(roleId: string | null): {
|
|
|
390
448
|
parent: string;
|
|
391
449
|
action: Action;
|
|
392
450
|
}[]>;
|
|
451
|
+
/** 0.6.0+. Set of `"<resource>:<action>"` for this role's overrides. */
|
|
452
|
+
overrides: Set<string>;
|
|
453
|
+
/**
|
|
454
|
+
* 0.6.0+. Suppress (`suppress=true`) or restore (`suppress=false`)
|
|
455
|
+
* an implied permission for this role. The grid + originGrid
|
|
456
|
+
* re-render with `'override'` state on the cell as soon as the
|
|
457
|
+
* optimistic flip lands.
|
|
458
|
+
*/
|
|
459
|
+
setOverride: (resource: string, action: Action, suppress: boolean) => Promise<void>;
|
|
393
460
|
isLoading: boolean;
|
|
394
461
|
error: Error | null;
|
|
395
462
|
refresh: () => Promise<void>;
|
|
@@ -405,26 +472,38 @@ interface MatrixGroup {
|
|
|
405
472
|
interface MatrixRenderArgs {
|
|
406
473
|
/** Resources grouped by their `group` label, original insertion order. */
|
|
407
474
|
groups: MatrixGroup[];
|
|
408
|
-
/**
|
|
475
|
+
/**
|
|
476
|
+
* Effective state of a cell after applying direct grants, the
|
|
477
|
+
* resource-dependency expansion, and any per-role overrides.
|
|
478
|
+
* What the resolver would answer for a user holding this role.
|
|
479
|
+
*/
|
|
409
480
|
isCellEnabled: (resource: string, action: Action) => boolean;
|
|
410
481
|
/**
|
|
411
|
-
* Origin of a single cell
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
482
|
+
* Origin of a single cell:
|
|
483
|
+
* * `'direct'` — explicit admin grant on rbac.role_permissions
|
|
484
|
+
* * `'override'` — admin suppressed it via rbac.role_permission_overrides
|
|
485
|
+
* (0.6.0+; cell is off even if a parent would imply)
|
|
486
|
+
* * `<string>` — the name of the parent resource whose
|
|
487
|
+
* `dependsOn` edge implies this cell
|
|
415
488
|
*
|
|
416
|
-
* Available since 0.4.0
|
|
417
|
-
* columns) this always returns `'direct'`.
|
|
489
|
+
* Available since 0.4.0; the `'override'` value is 0.6.0+.
|
|
418
490
|
*/
|
|
419
|
-
cellOrigin: (resource: string, action: Action) => "direct" | string;
|
|
491
|
+
cellOrigin: (resource: string, action: Action) => "direct" | "override" | string;
|
|
420
492
|
/**
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
493
|
+
* Toggle a DIRECT grant on rbac.role_permissions. Use for cells
|
|
494
|
+
* that the matrix UI shows as "direct" (no implied parent). For
|
|
495
|
+
* cells that are implied, use `setOverride` instead — that's what
|
|
496
|
+
* lets the admin opt a single role out of a cascade without
|
|
497
|
+
* touching the parent grant or the registry.
|
|
426
498
|
*/
|
|
427
499
|
setCell: (resource: string, action: Action, value: boolean) => Promise<void>;
|
|
500
|
+
/**
|
|
501
|
+
* 0.6.0+. Suppress (`suppress=true`) or restore (`suppress=false`)
|
|
502
|
+
* an implied permission for this role via
|
|
503
|
+
* rbac.role_permission_overrides. Writes are optimistic; the
|
|
504
|
+
* `cellOrigin` reflects the new state immediately.
|
|
505
|
+
*/
|
|
506
|
+
setOverride: (resource: string, action: Action, suppress: boolean) => Promise<void>;
|
|
428
507
|
isLoading: boolean;
|
|
429
508
|
isUpdating: boolean;
|
|
430
509
|
error: Error | null;
|
|
@@ -492,4 +571,4 @@ interface InviteMemberFormProps {
|
|
|
492
571
|
}
|
|
493
572
|
declare function InviteMemberForm(props: InviteMemberFormProps): react_jsx_runtime.JSX.Element;
|
|
494
573
|
|
|
495
|
-
export { type AdminCompany, type AdminMember, type AdminResourceDependency, type AdminRole, type AdminRolePermission, type AdminTransport, AdminTransportProvider, type AdminTransportProviderProps, InviteMemberForm, type InviteMemberFormProps, type InviteMemberFormRenderArgs, type MatrixGroup, type MatrixRenderArgs, PermissionsMatrix, type PermissionsMatrixProps, type RolePermissionGrid, type RolePermissionOriginGrid, RolesList, type RolesListProps, type RolesListRenderArgs, type SupabaseAdminClientOptions, createSupabaseAdminClient, extractResourceDependencies, useAdminCompanies, useAdminCompanyMembers, useAdminResourceDependencies, useAdminRolePermissions, useAdminRoles, useApplyTemplateDefaults, useCreateCompany, useCreateRole, useDeleteRole, useInviteCompanyMember, useRolePermissionGrid, useSetRolePermissionCell, useUpdateRole };
|
|
574
|
+
export { type AdminCompany, type AdminMember, type AdminResourceDependency, type AdminRole, type AdminRolePermission, type AdminRolePermissionOverride, type AdminTransport, AdminTransportProvider, type AdminTransportProviderProps, InviteMemberForm, type InviteMemberFormProps, type InviteMemberFormRenderArgs, type MatrixGroup, type MatrixRenderArgs, PermissionsMatrix, type PermissionsMatrixProps, type RolePermissionGrid, type RolePermissionOriginGrid, RolesList, type RolesListProps, type RolesListRenderArgs, type SupabaseAdminClientOptions, createSupabaseAdminClient, extractResourceDependencies, useAdminCompanies, useAdminCompanyMembers, useAdminResourceDependencies, useAdminRolePermissions, useAdminRoles, useApplyTemplateDefaults, useCreateCompany, useCreateRole, useDeleteRole, useInviteCompanyMember, useRolePermissionGrid, useRolePermissionOverrides, useSetRolePermissionCell, useUpdateRole };
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -54,6 +54,21 @@ interface AdminResourceDependency {
|
|
|
54
54
|
child_resource: string;
|
|
55
55
|
action: Action;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* One row of `rbac.role_permission_overrides` — an explicit
|
|
59
|
+
* per-role suppression that takes a cell OFF even when the
|
|
60
|
+
* dependency graph would otherwise imply it (or when a direct
|
|
61
|
+
* grant row exists). Used to express "Anwalt has tenants:read
|
|
62
|
+
* but should NOT see payments, even though tenants.dependsOn
|
|
63
|
+
* includes payments".
|
|
64
|
+
*
|
|
65
|
+
* Available since 0.6.0.
|
|
66
|
+
*/
|
|
67
|
+
interface AdminRolePermissionOverride {
|
|
68
|
+
role_id: string;
|
|
69
|
+
resource: string;
|
|
70
|
+
action: Action;
|
|
71
|
+
}
|
|
57
72
|
interface AdminCompany {
|
|
58
73
|
id: string;
|
|
59
74
|
name: string;
|
|
@@ -144,6 +159,26 @@ interface AdminTransport {
|
|
|
144
159
|
* cascade on a parent toggle.
|
|
145
160
|
*/
|
|
146
161
|
listResourceDependencies(): Promise<AdminResourceDependency[]>;
|
|
162
|
+
/**
|
|
163
|
+
* 0.6.0+. Read every per-role override for the given role.
|
|
164
|
+
* Returns the (resource, action) cells that the admin has
|
|
165
|
+
* explicitly suppressed, even though dependency-graph expansion
|
|
166
|
+
* would otherwise grant them.
|
|
167
|
+
*/
|
|
168
|
+
listRolePermissionOverrides(roleId: string): Promise<AdminRolePermissionOverride[]>;
|
|
169
|
+
/**
|
|
170
|
+
* 0.6.0+. Set or clear a per-role override:
|
|
171
|
+
* * suppress=true → INSERT (idempotent via ON CONFLICT)
|
|
172
|
+
* * suppress=false → DELETE
|
|
173
|
+
* Resolver functions subtract the row from the user's expanded
|
|
174
|
+
* grant set as soon as it's written.
|
|
175
|
+
*/
|
|
176
|
+
setRolePermissionOverride(args: {
|
|
177
|
+
role_id: string;
|
|
178
|
+
resource: string;
|
|
179
|
+
action: Action;
|
|
180
|
+
suppress: boolean;
|
|
181
|
+
}): Promise<void>;
|
|
147
182
|
/**
|
|
148
183
|
* Materialise `rbac.role_permissions` rows from a template role's
|
|
149
184
|
* `default_permissions` JSONB pattern. Calls the SQL function
|
|
@@ -342,6 +377,25 @@ declare function useAdminResourceDependencies(): {
|
|
|
342
377
|
isLoading: boolean;
|
|
343
378
|
error: Error | null;
|
|
344
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* 0.6.0+. Per-role override map. Returns a Set of
|
|
382
|
+
* `"<resource>:<action>"` keys for the given role plus a
|
|
383
|
+
* `setOverride(resource, action, suppress)` mutator. Optimistic —
|
|
384
|
+
* the local set flips immediately, then a re-fetch reconciles.
|
|
385
|
+
*
|
|
386
|
+
* Use this in tandem with `useRolePermissionGrid` to render a
|
|
387
|
+
* matrix UI that distinguishes:
|
|
388
|
+
* * direct grants (the row is on rbac.role_permissions)
|
|
389
|
+
* * implied grants (resource_dependencies expansion)
|
|
390
|
+
* * overrides (this hook's set — admin clicked an implied cell
|
|
391
|
+
* off to carve it out for this specific role)
|
|
392
|
+
*/
|
|
393
|
+
declare function useRolePermissionOverrides(roleId: string | null): {
|
|
394
|
+
overrides: Set<string>;
|
|
395
|
+
setOverride: (resource: string, action: Action, suppress: boolean) => Promise<void>;
|
|
396
|
+
error: Error | null;
|
|
397
|
+
refresh: () => Promise<void>;
|
|
398
|
+
};
|
|
345
399
|
declare function useCreateCompany(): {
|
|
346
400
|
isPending: boolean;
|
|
347
401
|
error: Error | null;
|
|
@@ -368,15 +422,19 @@ interface RolePermissionGrid {
|
|
|
368
422
|
};
|
|
369
423
|
}
|
|
370
424
|
/**
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
* an
|
|
374
|
-
*
|
|
425
|
+
* Per-cell origin marker:
|
|
426
|
+
* * `'direct'` — explicit admin grant on rbac.role_permissions
|
|
427
|
+
* * `'override'` — admin set an override on rbac.role_permission_overrides
|
|
428
|
+
* (0.6.0+; cell is OFF even if a direct or
|
|
429
|
+
* implied grant would otherwise apply)
|
|
430
|
+
* * `<string>` — name of the parent resource that implies this
|
|
431
|
+
* cell via rbac.resource_dependencies
|
|
432
|
+
* * `null` — neither granted nor implied
|
|
375
433
|
*
|
|
376
434
|
* In 0.4.x this was driven by the `<action>_granted_via` columns on
|
|
377
|
-
* rbac.role_permissions. In 0.5.0 implied rows are no longer
|
|
435
|
+
* rbac.role_permissions. In 0.5.0+ implied rows are no longer
|
|
378
436
|
* materialised — origin is computed client-side from the dependency
|
|
379
|
-
* graph + the role's direct grants.
|
|
437
|
+
* graph + the role's direct grants + (0.6.0+) any overrides.
|
|
380
438
|
*/
|
|
381
439
|
interface RolePermissionOriginGrid {
|
|
382
440
|
[resource: string]: {
|
|
@@ -390,6 +448,15 @@ declare function useRolePermissionGrid(roleId: string | null): {
|
|
|
390
448
|
parent: string;
|
|
391
449
|
action: Action;
|
|
392
450
|
}[]>;
|
|
451
|
+
/** 0.6.0+. Set of `"<resource>:<action>"` for this role's overrides. */
|
|
452
|
+
overrides: Set<string>;
|
|
453
|
+
/**
|
|
454
|
+
* 0.6.0+. Suppress (`suppress=true`) or restore (`suppress=false`)
|
|
455
|
+
* an implied permission for this role. The grid + originGrid
|
|
456
|
+
* re-render with `'override'` state on the cell as soon as the
|
|
457
|
+
* optimistic flip lands.
|
|
458
|
+
*/
|
|
459
|
+
setOverride: (resource: string, action: Action, suppress: boolean) => Promise<void>;
|
|
393
460
|
isLoading: boolean;
|
|
394
461
|
error: Error | null;
|
|
395
462
|
refresh: () => Promise<void>;
|
|
@@ -405,26 +472,38 @@ interface MatrixGroup {
|
|
|
405
472
|
interface MatrixRenderArgs {
|
|
406
473
|
/** Resources grouped by their `group` label, original insertion order. */
|
|
407
474
|
groups: MatrixGroup[];
|
|
408
|
-
/**
|
|
475
|
+
/**
|
|
476
|
+
* Effective state of a cell after applying direct grants, the
|
|
477
|
+
* resource-dependency expansion, and any per-role overrides.
|
|
478
|
+
* What the resolver would answer for a user holding this role.
|
|
479
|
+
*/
|
|
409
480
|
isCellEnabled: (resource: string, action: Action) => boolean;
|
|
410
481
|
/**
|
|
411
|
-
* Origin of a single cell
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
*
|
|
482
|
+
* Origin of a single cell:
|
|
483
|
+
* * `'direct'` — explicit admin grant on rbac.role_permissions
|
|
484
|
+
* * `'override'` — admin suppressed it via rbac.role_permission_overrides
|
|
485
|
+
* (0.6.0+; cell is off even if a parent would imply)
|
|
486
|
+
* * `<string>` — the name of the parent resource whose
|
|
487
|
+
* `dependsOn` edge implies this cell
|
|
415
488
|
*
|
|
416
|
-
* Available since 0.4.0
|
|
417
|
-
* columns) this always returns `'direct'`.
|
|
489
|
+
* Available since 0.4.0; the `'override'` value is 0.6.0+.
|
|
418
490
|
*/
|
|
419
|
-
cellOrigin: (resource: string, action: Action) => "direct" | string;
|
|
491
|
+
cellOrigin: (resource: string, action: Action) => "direct" | "override" | string;
|
|
420
492
|
/**
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
493
|
+
* Toggle a DIRECT grant on rbac.role_permissions. Use for cells
|
|
494
|
+
* that the matrix UI shows as "direct" (no implied parent). For
|
|
495
|
+
* cells that are implied, use `setOverride` instead — that's what
|
|
496
|
+
* lets the admin opt a single role out of a cascade without
|
|
497
|
+
* touching the parent grant or the registry.
|
|
426
498
|
*/
|
|
427
499
|
setCell: (resource: string, action: Action, value: boolean) => Promise<void>;
|
|
500
|
+
/**
|
|
501
|
+
* 0.6.0+. Suppress (`suppress=true`) or restore (`suppress=false`)
|
|
502
|
+
* an implied permission for this role via
|
|
503
|
+
* rbac.role_permission_overrides. Writes are optimistic; the
|
|
504
|
+
* `cellOrigin` reflects the new state immediately.
|
|
505
|
+
*/
|
|
506
|
+
setOverride: (resource: string, action: Action, suppress: boolean) => Promise<void>;
|
|
428
507
|
isLoading: boolean;
|
|
429
508
|
isUpdating: boolean;
|
|
430
509
|
error: Error | null;
|
|
@@ -492,4 +571,4 @@ interface InviteMemberFormProps {
|
|
|
492
571
|
}
|
|
493
572
|
declare function InviteMemberForm(props: InviteMemberFormProps): react_jsx_runtime.JSX.Element;
|
|
494
573
|
|
|
495
|
-
export { type AdminCompany, type AdminMember, type AdminResourceDependency, type AdminRole, type AdminRolePermission, type AdminTransport, AdminTransportProvider, type AdminTransportProviderProps, InviteMemberForm, type InviteMemberFormProps, type InviteMemberFormRenderArgs, type MatrixGroup, type MatrixRenderArgs, PermissionsMatrix, type PermissionsMatrixProps, type RolePermissionGrid, type RolePermissionOriginGrid, RolesList, type RolesListProps, type RolesListRenderArgs, type SupabaseAdminClientOptions, createSupabaseAdminClient, extractResourceDependencies, useAdminCompanies, useAdminCompanyMembers, useAdminResourceDependencies, useAdminRolePermissions, useAdminRoles, useApplyTemplateDefaults, useCreateCompany, useCreateRole, useDeleteRole, useInviteCompanyMember, useRolePermissionGrid, useSetRolePermissionCell, useUpdateRole };
|
|
574
|
+
export { type AdminCompany, type AdminMember, type AdminResourceDependency, type AdminRole, type AdminRolePermission, type AdminRolePermissionOverride, type AdminTransport, AdminTransportProvider, type AdminTransportProviderProps, InviteMemberForm, type InviteMemberFormProps, type InviteMemberFormRenderArgs, type MatrixGroup, type MatrixRenderArgs, PermissionsMatrix, type PermissionsMatrixProps, type RolePermissionGrid, type RolePermissionOriginGrid, RolesList, type RolesListProps, type RolesListRenderArgs, type SupabaseAdminClientOptions, createSupabaseAdminClient, extractResourceDependencies, useAdminCompanies, useAdminCompanyMembers, useAdminResourceDependencies, useAdminRolePermissions, useAdminRoles, useApplyTemplateDefaults, useCreateCompany, useCreateRole, useDeleteRole, useInviteCompanyMember, useRolePermissionGrid, useRolePermissionOverrides, useSetRolePermissionCell, useUpdateRole };
|
package/dist/admin/index.js
CHANGED
|
@@ -185,6 +185,32 @@ function createSupabaseAdminClient(opts) {
|
|
|
185
185
|
}
|
|
186
186
|
return data ?? [];
|
|
187
187
|
},
|
|
188
|
+
async listRolePermissionOverrides(roleId) {
|
|
189
|
+
const { data, error } = await rbac.from("role_permission_overrides").select("role_id, resource, action").eq("role_id", roleId);
|
|
190
|
+
if (error) {
|
|
191
|
+
if (/role_permission_overrides/i.test(error.message) && /does not exist/i.test(error.message)) {
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
throw new Error(`listRolePermissionOverrides: ${error.message}`);
|
|
195
|
+
}
|
|
196
|
+
return data ?? [];
|
|
197
|
+
},
|
|
198
|
+
async setRolePermissionOverride({ role_id, resource, action, suppress }) {
|
|
199
|
+
if (suppress) {
|
|
200
|
+
const { error: error2 } = await rbac.from("role_permission_overrides").upsert(
|
|
201
|
+
{ role_id, resource, action },
|
|
202
|
+
{ onConflict: "role_id,resource,action" }
|
|
203
|
+
);
|
|
204
|
+
if (error2) {
|
|
205
|
+
throw new Error(`setRolePermissionOverride(insert): ${error2.message}`);
|
|
206
|
+
}
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const { error } = await rbac.from("role_permission_overrides").delete().eq("role_id", role_id).eq("resource", resource).eq("action", action);
|
|
210
|
+
if (error) {
|
|
211
|
+
throw new Error(`setRolePermissionOverride(delete): ${error.message}`);
|
|
212
|
+
}
|
|
213
|
+
},
|
|
188
214
|
async applyTemplateDefaults({ role_id, only_missing = true }) {
|
|
189
215
|
const { data, error } = await rbac.rpc("apply_template_defaults", {
|
|
190
216
|
p_role_id: role_id,
|
|
@@ -368,6 +394,57 @@ function useAdminResourceDependencies() {
|
|
|
368
394
|
[transport]
|
|
369
395
|
);
|
|
370
396
|
}
|
|
397
|
+
function useRolePermissionOverrides(roleId) {
|
|
398
|
+
const transport = useAdminTransport();
|
|
399
|
+
const [overrides, setOverrides] = useState(() => /* @__PURE__ */ new Set());
|
|
400
|
+
const [error, setError] = useState(null);
|
|
401
|
+
const fetchOverrides = useCallback(async () => {
|
|
402
|
+
if (!roleId) {
|
|
403
|
+
setOverrides(/* @__PURE__ */ new Set());
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
const rows = await transport.listRolePermissionOverrides(roleId);
|
|
408
|
+
setOverrides(new Set(rows.map((r) => `${r.resource}:${r.action}`)));
|
|
409
|
+
setError(null);
|
|
410
|
+
} catch (e) {
|
|
411
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
412
|
+
}
|
|
413
|
+
}, [transport, roleId]);
|
|
414
|
+
useEffect(() => {
|
|
415
|
+
void fetchOverrides();
|
|
416
|
+
}, [fetchOverrides]);
|
|
417
|
+
const setOverride = useCallback(
|
|
418
|
+
async (resource, action, suppress) => {
|
|
419
|
+
if (!roleId) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const key = `${resource}:${action}`;
|
|
423
|
+
setOverrides((prev) => {
|
|
424
|
+
const next = new Set(prev);
|
|
425
|
+
if (suppress) {
|
|
426
|
+
next.add(key);
|
|
427
|
+
} else {
|
|
428
|
+
next.delete(key);
|
|
429
|
+
}
|
|
430
|
+
return next;
|
|
431
|
+
});
|
|
432
|
+
try {
|
|
433
|
+
await transport.setRolePermissionOverride({
|
|
434
|
+
role_id: roleId,
|
|
435
|
+
resource,
|
|
436
|
+
action,
|
|
437
|
+
suppress
|
|
438
|
+
});
|
|
439
|
+
} catch (e) {
|
|
440
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
441
|
+
}
|
|
442
|
+
void fetchOverrides();
|
|
443
|
+
},
|
|
444
|
+
[transport, roleId, fetchOverrides]
|
|
445
|
+
);
|
|
446
|
+
return { overrides, setOverride, error, refresh: fetchOverrides };
|
|
447
|
+
}
|
|
371
448
|
function useCreateCompany() {
|
|
372
449
|
const transport = useAdminTransport();
|
|
373
450
|
return useMutation(transport.createCompany);
|
|
@@ -379,6 +456,7 @@ function useInviteCompanyMember() {
|
|
|
379
456
|
function useRolePermissionGrid(roleId) {
|
|
380
457
|
const { data, isLoading, error, refresh } = useAdminRolePermissions(roleId);
|
|
381
458
|
const dependencies = useAdminResourceDependencies();
|
|
459
|
+
const overridesHook = useRolePermissionOverrides(roleId);
|
|
382
460
|
const setCell = useSetRolePermissionCell();
|
|
383
461
|
const transport = useAdminTransport();
|
|
384
462
|
const grid = useMemo(() => {
|
|
@@ -410,6 +488,7 @@ function useRolePermissionGrid(roleId) {
|
|
|
410
488
|
for (const child of parentsByChild.keys()) {
|
|
411
489
|
resources.add(child);
|
|
412
490
|
}
|
|
491
|
+
const overrides = overridesHook.overrides;
|
|
413
492
|
for (const resource of resources) {
|
|
414
493
|
const directs = grid[resource];
|
|
415
494
|
const cellOrigins = {
|
|
@@ -419,6 +498,10 @@ function useRolePermissionGrid(roleId) {
|
|
|
419
498
|
delete: null
|
|
420
499
|
};
|
|
421
500
|
for (const action of ACTIONS) {
|
|
501
|
+
if (overrides.has(`${resource}:${action}`)) {
|
|
502
|
+
cellOrigins[action] = "override";
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
422
505
|
if (directs?.[action]) {
|
|
423
506
|
cellOrigins[action] = "direct";
|
|
424
507
|
continue;
|
|
@@ -432,7 +515,7 @@ function useRolePermissionGrid(roleId) {
|
|
|
432
515
|
out[resource] = cellOrigins;
|
|
433
516
|
}
|
|
434
517
|
return out;
|
|
435
|
-
}, [grid, parentsByChild]);
|
|
518
|
+
}, [grid, parentsByChild, overridesHook.overrides]);
|
|
436
519
|
const updateCell = useCallback(
|
|
437
520
|
async (resource, action, value) => {
|
|
438
521
|
if (!roleId) {
|
|
@@ -454,8 +537,17 @@ function useRolePermissionGrid(roleId) {
|
|
|
454
537
|
grid,
|
|
455
538
|
originGrid,
|
|
456
539
|
parentsByChild,
|
|
540
|
+
/** 0.6.0+. Set of `"<resource>:<action>"` for this role's overrides. */
|
|
541
|
+
overrides: overridesHook.overrides,
|
|
542
|
+
/**
|
|
543
|
+
* 0.6.0+. Suppress (`suppress=true`) or restore (`suppress=false`)
|
|
544
|
+
* an implied permission for this role. The grid + originGrid
|
|
545
|
+
* re-render with `'override'` state on the cell as soon as the
|
|
546
|
+
* optimistic flip lands.
|
|
547
|
+
*/
|
|
548
|
+
setOverride: overridesHook.setOverride,
|
|
457
549
|
isLoading: isLoading || dependencies.isLoading,
|
|
458
|
-
error: error ?? dependencies.error,
|
|
550
|
+
error: error ?? dependencies.error ?? overridesHook.error,
|
|
459
551
|
refresh,
|
|
460
552
|
updateCell,
|
|
461
553
|
isUpdating: setCell.isPending,
|
|
@@ -469,16 +561,25 @@ import { useMemo as useMemo2 } from "react";
|
|
|
469
561
|
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
470
562
|
var ACTIONS2 = ["read", "write", "update", "delete"];
|
|
471
563
|
function PermissionsMatrix(props) {
|
|
472
|
-
const {
|
|
564
|
+
const {
|
|
565
|
+
grid,
|
|
566
|
+
originGrid,
|
|
567
|
+
isLoading,
|
|
568
|
+
error,
|
|
569
|
+
updateCell,
|
|
570
|
+
isUpdating,
|
|
571
|
+
setOverride: gridSetOverride
|
|
572
|
+
} = useRolePermissionGrid(props.roleId);
|
|
473
573
|
const groups = useMemo2(
|
|
474
574
|
() => groupResources(props.resources),
|
|
475
575
|
[props.resources]
|
|
476
576
|
);
|
|
477
577
|
const isCellEnabled = (resource, action) => {
|
|
478
|
-
|
|
479
|
-
|
|
578
|
+
const origin = originGrid[resource]?.[action];
|
|
579
|
+
if (origin == null || origin === "override") {
|
|
580
|
+
return false;
|
|
480
581
|
}
|
|
481
|
-
return
|
|
582
|
+
return true;
|
|
482
583
|
};
|
|
483
584
|
const cellOrigin = (resource, action) => {
|
|
484
585
|
const origin = originGrid[resource]?.[action];
|
|
@@ -487,11 +588,15 @@ function PermissionsMatrix(props) {
|
|
|
487
588
|
const setCell = async (resource, action, value) => {
|
|
488
589
|
await updateCell(resource, action, value);
|
|
489
590
|
};
|
|
591
|
+
const setOverride = async (resource, action, suppress) => {
|
|
592
|
+
await gridSetOverride(resource, action, suppress);
|
|
593
|
+
};
|
|
490
594
|
return /* @__PURE__ */ jsx2(Fragment, { children: props.children({
|
|
491
595
|
groups,
|
|
492
596
|
isCellEnabled,
|
|
493
597
|
cellOrigin,
|
|
494
598
|
setCell,
|
|
599
|
+
setOverride,
|
|
495
600
|
isLoading,
|
|
496
601
|
isUpdating,
|
|
497
602
|
error,
|
|
@@ -636,6 +741,7 @@ export {
|
|
|
636
741
|
useDeleteRole,
|
|
637
742
|
useInviteCompanyMember,
|
|
638
743
|
useRolePermissionGrid,
|
|
744
|
+
useRolePermissionOverrides,
|
|
639
745
|
useSetRolePermissionCell,
|
|
640
746
|
useUpdateRole
|
|
641
747
|
};
|