Initial Commit
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
export {
|
||||
CRUD_PERMISSIONS,
|
||||
createAdminRole,
|
||||
createEditorRole,
|
||||
createOwnerRole,
|
||||
createViewerRole,
|
||||
} from "./role-presets.js";
|
||||
@@ -0,0 +1,65 @@
|
||||
# role-presets
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Provides pre-built role factories and permission bundles for the most common access-control patterns in `@suaveplan/permissions`. Rather than requiring every application to redefine the same admin/viewer/editor roles from scratch, the presets offer sensible defaults that can be used directly or overridden with a custom permissions array.
|
||||
|
||||
## Features
|
||||
|
||||
- `createAdminRole` — full wildcard `*:*` permissions, system-protected
|
||||
- `createViewerRole` — `read` and `list` across all resources
|
||||
- `createEditorRole` — `read`, `list`, `create`, `update` across all resources
|
||||
- `createOwnerRole` — full wildcard permissions (like admin but semantically for resource owners)
|
||||
- `CRUD_PERMISSIONS` — pre-built permission sets for `posts` and `users` resources
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { createAdminRole, createViewerRole } from "@suaveplan/permissions";
|
||||
import { MemoryAdapter } from "@suaveplan/permissions";
|
||||
|
||||
const adapter = new MemoryAdapter();
|
||||
await adapter.createRole(createAdminRole());
|
||||
await adapter.createRole(createViewerRole());
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { createEditorRole } from "@suaveplan/permissions";
|
||||
|
||||
// Override permissions
|
||||
const customEditor = createEditorRole([
|
||||
{ id: "editor:posts:write", resource: "posts", action: "create" },
|
||||
{ id: "editor:posts:read", resource: "posts", action: "read" },
|
||||
]);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `createAdminRole(permissions?): Role`
|
||||
|
||||
Returns a system role with `id: "admin"` and `isSystem: true`. Default permissions: `{ resource: "*", action: "*" }`.
|
||||
|
||||
### `createViewerRole(permissions?): Role`
|
||||
|
||||
Returns a system role with `id: "viewer"`. Default: `read` and `list` on all resources.
|
||||
|
||||
### `createEditorRole(permissions?): Role`
|
||||
|
||||
Returns a system role with `id: "editor"`. Default: `read`, `list`, `create`, `update` on all resources.
|
||||
|
||||
### `createOwnerRole(permissions?): Role`
|
||||
|
||||
Returns a system role with `id: "owner"`. Default: wildcard on all resources.
|
||||
|
||||
### `CRUD_PERMISSIONS`
|
||||
|
||||
`Record<string, Permission[]>` — pre-built permission sets for `posts` and `users` resources.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All preset roles have `isSystem: true` set, which means `RoleManager.updateRole` and `RoleManager.deleteRole` will throw `SystemRoleMutationError` to prevent accidental modification. If you need to customise a system role, either pass a custom `permissions` array to the factory, or create a new non-system role and assign it alongside the preset.
|
||||
@@ -0,0 +1,76 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
CRUD_PERMISSIONS,
|
||||
createAdminRole,
|
||||
createEditorRole,
|
||||
createOwnerRole,
|
||||
createViewerRole,
|
||||
} from "./role-presets.js";
|
||||
|
||||
describe("createAdminRole", () => {
|
||||
it("has correct id and isSystem", { timeout: 5000 }, () => {
|
||||
const role = createAdminRole();
|
||||
expect(role.id).toBe("admin");
|
||||
expect(role.isSystem).toBe(true);
|
||||
});
|
||||
|
||||
it("has wildcard permission by default", { timeout: 5000 }, () => {
|
||||
const role = createAdminRole();
|
||||
expect(role.permissions[0]?.action).toBe("*");
|
||||
});
|
||||
|
||||
it("accepts custom permissions", { timeout: 5000 }, () => {
|
||||
const custom = [{ id: "x", resource: "r", action: "read" }];
|
||||
const role = createAdminRole(custom);
|
||||
expect(role.permissions).toEqual(custom);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createViewerRole", () => {
|
||||
it("has correct id", { timeout: 5000 }, () => {
|
||||
expect(createViewerRole().id).toBe("viewer");
|
||||
});
|
||||
|
||||
it("has read and list permissions", { timeout: 5000 }, () => {
|
||||
const role = createViewerRole();
|
||||
const actions = role.permissions.map((p) => p.action);
|
||||
expect(actions).toContain("read");
|
||||
expect(actions).toContain("list");
|
||||
});
|
||||
});
|
||||
|
||||
describe("createEditorRole", () => {
|
||||
it("has correct id", { timeout: 5000 }, () => {
|
||||
expect(createEditorRole().id).toBe("editor");
|
||||
});
|
||||
|
||||
it("includes create and update", { timeout: 5000 }, () => {
|
||||
const role = createEditorRole();
|
||||
const actions = role.permissions.map((p) => p.action);
|
||||
expect(actions).toContain("create");
|
||||
expect(actions).toContain("update");
|
||||
});
|
||||
});
|
||||
|
||||
describe("createOwnerRole", () => {
|
||||
it("has correct id", { timeout: 5000 }, () => {
|
||||
expect(createOwnerRole().id).toBe("owner");
|
||||
});
|
||||
|
||||
it("has wildcard permission", { timeout: 5000 }, () => {
|
||||
const role = createOwnerRole();
|
||||
expect(role.permissions[0]?.action).toBe("*");
|
||||
});
|
||||
});
|
||||
|
||||
describe("CRUD_PERMISSIONS", () => {
|
||||
it("has posts permissions", { timeout: 5000 }, () => {
|
||||
expect(CRUD_PERMISSIONS["posts"]).toBeDefined();
|
||||
expect(CRUD_PERMISSIONS["posts"]).toHaveLength(5);
|
||||
});
|
||||
|
||||
it("has users permissions", { timeout: 5000 }, () => {
|
||||
expect(CRUD_PERMISSIONS["users"]).toBeDefined();
|
||||
expect(CRUD_PERMISSIONS["users"]).toHaveLength(5);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
import type { Permission, Role } from "../../types/permissions.types.js";
|
||||
|
||||
/** Default CRUD permissions for common resources. */
|
||||
export const CRUD_PERMISSIONS: Record<string, Permission[]> = {
|
||||
posts: [
|
||||
{ id: "posts:create", resource: "posts", action: "create" },
|
||||
{ id: "posts:read", resource: "posts", action: "read" },
|
||||
{ id: "posts:update", resource: "posts", action: "update" },
|
||||
{ id: "posts:delete", resource: "posts", action: "delete" },
|
||||
{ id: "posts:list", resource: "posts", action: "list" },
|
||||
],
|
||||
users: [
|
||||
{ id: "users:create", resource: "users", action: "create" },
|
||||
{ id: "users:read", resource: "users", action: "read" },
|
||||
{ id: "users:update", resource: "users", action: "update" },
|
||||
{ id: "users:delete", resource: "users", action: "delete" },
|
||||
{ id: "users:list", resource: "users", action: "list" },
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a pre-built admin role with full wildcard permissions.
|
||||
*/
|
||||
export function createAdminRole(permissions?: Permission[]): Role {
|
||||
return {
|
||||
id: "admin",
|
||||
name: "Admin",
|
||||
isSystem: true,
|
||||
permissions: permissions ?? [
|
||||
{ id: "admin:*", resource: "*", action: "*" },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pre-built viewer role with read-only permissions.
|
||||
*/
|
||||
export function createViewerRole(permissions?: Permission[]): Role {
|
||||
return {
|
||||
id: "viewer",
|
||||
name: "Viewer",
|
||||
isSystem: true,
|
||||
permissions: permissions ?? [
|
||||
{ id: "viewer:read", resource: "*", action: "read" },
|
||||
{ id: "viewer:list", resource: "*", action: "list" },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pre-built editor role with create, read, update, and list
|
||||
* permissions.
|
||||
*/
|
||||
export function createEditorRole(permissions?: Permission[]): Role {
|
||||
return {
|
||||
id: "editor",
|
||||
name: "Editor",
|
||||
isSystem: true,
|
||||
permissions: permissions ?? [
|
||||
{ id: "editor:read", resource: "*", action: "read" },
|
||||
{ id: "editor:list", resource: "*", action: "list" },
|
||||
{ id: "editor:create", resource: "*", action: "create" },
|
||||
{ id: "editor:update", resource: "*", action: "update" },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pre-built owner role with full permissions including delete.
|
||||
*/
|
||||
export function createOwnerRole(permissions?: Permission[]): Role {
|
||||
return {
|
||||
id: "owner",
|
||||
name: "Owner",
|
||||
isSystem: true,
|
||||
permissions: permissions ?? [
|
||||
{ id: "owner:*", resource: "*", action: "*" },
|
||||
],
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user