first commit
This commit is contained in:
92
docs/identity/auth/permissions/src/cache/permission-cache/permission-cache.md
vendored
Normal file
92
docs/identity/auth/permissions/src/cache/permission-cache/permission-cache.md
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
# permission-cache
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`PermissionCache` provides a TTL-bounded, size-capped in-process cache for permission check results in `@suaveplan/permissions`. Permission checks can be expensive — they may traverse multi-level role inheritance chains and evaluate ABAC conditions — so caching their boolean outcome for frequently-checked user/resource/action triples significantly reduces latency on hot paths.
|
||||
|
||||
The cache accepts an injectable `Clock` for deterministic testing: advance the fake clock to simulate TTL expiry without wall-clock waits.
|
||||
|
||||
## Features
|
||||
|
||||
- TTL-based expiry: entries older than `ttl` ms are evicted on read
|
||||
- Size-capped: when full, the oldest entry is evicted before inserting a new one
|
||||
- `invalidate(userId)` — invalidates all entries for a specific user by key prefix
|
||||
- `invalidateAll()` — clears the entire cache (e.g. on role assignment change)
|
||||
- `size` getter — returns the current entry count (including not-yet-evicted expired entries)
|
||||
- Injectable `Clock` for deterministic test control
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { PermissionCache } from "@suaveplan/permissions";
|
||||
|
||||
const cache = new PermissionCache({ ttl: 60_000 });
|
||||
|
||||
cache.set("u1:posts:read", true);
|
||||
console.log(cache.get("u1:posts:read")); // true
|
||||
|
||||
cache.invalidate("u1");
|
||||
console.log(cache.get("u1:posts:read")); // undefined — invalidated
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { PermissionCache } from "@suaveplan/permissions";
|
||||
|
||||
let tick = 0;
|
||||
const cache = new PermissionCache({ ttl: 1000, clock: () => tick });
|
||||
|
||||
cache.set("u1:posts:read", true);
|
||||
tick = 999;
|
||||
console.log(cache.get("u1:posts:read")); // true — not yet expired
|
||||
|
||||
tick = 1001;
|
||||
console.log(cache.get("u1:posts:read")); // undefined — expired
|
||||
|
||||
// With PolicyEngine
|
||||
import { PolicyEngine, RoleManager } from "@suaveplan/permissions";
|
||||
import { MemoryAdapter } from "@suaveplan/permissions";
|
||||
|
||||
const adapter = new MemoryAdapter();
|
||||
const roleManager = new RoleManager(adapter);
|
||||
const policyEngine = new PolicyEngine(
|
||||
new PermissionManager(adapter),
|
||||
{ cache: new PermissionCache({ ttl: 30_000 }) },
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `constructor(options: PermissionCacheOptions)`
|
||||
|
||||
- `options.ttl` — entry TTL in milliseconds (required)
|
||||
- `options.maxSize` — maximum entry count before eviction (default: 1 000)
|
||||
- `options.clock` — injectable time source (default: `Date.now`)
|
||||
|
||||
### `get(key: string): boolean | undefined`
|
||||
|
||||
Returns the cached value if present and not expired, or `undefined`. Auto-evicts expired entries on read.
|
||||
|
||||
### `set(key: string, value: boolean): void`
|
||||
|
||||
Stores an entry. If the cache is at capacity, evicts the oldest entry first.
|
||||
|
||||
### `invalidate(userId: string): void`
|
||||
|
||||
Removes all entries whose key starts with `userId:`. Use after role assignment changes.
|
||||
|
||||
### `invalidateAll(): void`
|
||||
|
||||
Clears all entries.
|
||||
|
||||
### `size: number`
|
||||
|
||||
Current entry count. May include entries that are expired but not yet read (lazy eviction).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The eviction strategy is "evict the oldest-inserted entry" (Map insertion order) rather than true LRU. This keeps the implementation O(1) for all operations without the overhead of a doubly-linked list. For most permission-check workloads — where the hot users are also the most recently active — insertion-order eviction provides good cache efficiency. The `invalidate(userId)` method iterates all keys but the cache is bounded by `maxSize`, so the worst case is O(maxSize) — acceptable for typical values (≤10 000).
|
||||
Reference in New Issue
Block a user