Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
# permission-middleware
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Provides framework-agnostic permission checking middleware for `@suaveplan/permissions`. The `createPermissionMiddleware` factory returns a `(req, res, next)` function that reads the authenticated user from `req.user`, checks the configured permission via the adapter, and calls `next(PermissionsError)` on denial.
The `checkPermission` function provides a one-off convenience check without creating a full engine instance, useful for route handlers that need a single inline permission assertion.
## Features
- `createPermissionMiddleware(options)` — factory returning `MiddlewareFn`
- `checkPermission(userId, resource, action, adapter)` — one-off policy evaluation
- User extraction from `req.user.userId` or `req.user.sub` (JWT-compatible)
- `ResourceExtractor` and `UserExtractor` type exports
## Usage: Basic Example
```ts
import { createPermissionMiddleware, MemoryAdapter } from "@suaveplan/permissions";
const adapter = new MemoryAdapter();
const mw = createPermissionMiddleware({
resource: "posts",
action: "delete",
adapter,
});
// Attach to route: app.delete("/posts/:id", verifyJwt, mw, handler)
```
## Usage: Advanced Example
```ts
import { checkPermission } from "@suaveplan/permissions";
import { MemoryAdapter } from "@suaveplan/permissions";
const adapter = new MemoryAdapter();
// Route handler inline check
async function deletePost(userId: string, postId: string) {
const result = await checkPermission(userId, "posts", "delete", adapter);
if (!result.allowed) throw new Error(result.reason);
// ... proceed with deletion
}
```
## API Reference
### `createPermissionMiddleware(options): MiddlewareFn`
Options: `resource`, `action`, `adapter?`.
Reads user from `req.user.userId` or `req.user.sub`. Calls `next(PermissionsError)` if no user, no adapter, or permission denied.
### `checkPermission(userId, resource, action, adapter): Promise<PolicyResult>`
Creates a transient `PolicyEngine` and evaluates one permission check.
### `ResourceExtractor`
`(req: unknown) => string` — type alias.
### `UserExtractor`
`(req: unknown) => string | null` — type alias.
## Implementation Notes
The middleware user extraction checks both `userId` (from a `UserContext`) and `sub` (from a `JWTPayload`) to support both `@suaveplan/auth`'s `verifyTokenMiddleware` (which attaches `req.user` as `JWTPayload`) and custom middleware that attaches `req.user` as `UserContext`. No adapter means the middleware fails closed with a `PERM_CODES.ADAPTER_ERROR`, preventing accidental open access when misconfigured.