memory adapter
In-process Map-backed adapter for development, testing, and prototyping. Zero dependencies, no persistence.
Install
import { IamMemoryAdapter } from '@gentleduck/iam/adapters/memory'
Stores everything in Map instances. Zero dependencies. Data does not survive process restarts - use a database adapter for production.
Basic usage
import { IamMemoryAdapter } from '@gentleduck/iam/adapters/memory'
import { IamEngine } from '@gentleduck/iam'
const adapter = new IamMemoryAdapter({
roles: [
{
id: 'admin',
name: 'Administrator',
permissions: [{ action: '*', resource: '*' }],
},
{
id: 'editor',
name: 'Editor',
permissions: [
{ action: 'read', resource: '*' },
{ action: 'create', resource: 'post' },
{ action: 'update', resource: 'post' },
{ action: 'delete', resource: 'post' },
],
},
{
id: 'viewer',
name: 'Viewer',
permissions: [{ action: 'read', resource: '*' }],
},
],
policies: [
{
id: 'default',
name: 'Default Policy',
algorithm: 'deny-overrides',
rules: [
{
id: 'deny-banned',
effect: 'deny',
priority: 100,
actions: ['*'],
resources: ['*'],
conditions: {
all: [{ field: 'subject.attributes.status', operator: 'eq', value: 'banned' }],
},
},
{
id: 'allow-all',
effect: 'allow',
priority: 1,
actions: ['*'],
resources: ['*'],
conditions: { all: [] },
},
],
},
],
assignments: {
'user-1': ['admin'],
'user-2': ['editor'],
'user-3': ['viewer'],
},
})
const engine = new IamEngine({ adapter })
With subject attributes
Pass initial attributes for ABAC-style conditions.
const adapter = new IamMemoryAdapter({
roles: [...],
assignments: { 'user-1': ['editor'] },
attributes: {
'user-1': {
department: 'engineering',
level: 3,
verified: true,
},
},
})
Constructor options
| Option | Type | Description |
|---|---|---|
roles | Role[] | Initial role definitions |
policies | Policy[] | Initial policy definitions |
assignments | Record<string, string[]> | Map of subject ID to role IDs |
attributes | Record<string, Attributes> | Map of subject ID to attribute objects |
Behavior details
- Duplicate assignments -
assignRolechecks for existing entries and silently skips duplicates. CallingassignRole('user-1', 'editor')twice has no effect the second time. - Attribute merging -
setSubjectAttributesshallow-merges new attributes into existing ones. To remove an attribute, set it tonull. - Scoped vs unscoped roles - stored in the same array.
getSubjectRolesfilters for entries without a scope;getSubjectScopedRolesfilters for entries with a scope.
When to use
- Unit tests - seed known roles and assignments, assert engine behavior
- Development - get started without a database
- Prototyping - explore the policy model before committing to a schema
- CI pipelines - run integration tests without external dependencies
When NOT to use
- Production - process restarts wipe all data
- Multi-instance deploys - each node has its own isolated map
- Persistent state across deployments - every deploy resets
For production, switch to Prisma, Drizzle, or Redis.
Types
Constructor input lives under the Memory namespace at @gentleduck/iam/adapters/memory. Type-only - zero bundle cost.
IamMemory.IInit- constructor seed input (roles,policies,assignments,attributes).
import type { IamMemory } from '@gentleduck/iam/adapters/memory'
const init: IamMemory.IInit = {
roles: [/* ... */],
assignments: { 'user-1': ['admin'] },
}