## Install

```typescript
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

```typescript
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.

```typescript
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** - `assignRole` checks for existing entries and silently skips duplicates. Calling `assignRole('user-1', 'editor')` twice has no effect the second time.
* **Attribute merging** - `setSubjectAttributes` shallow-merges new attributes into existing ones. To remove an attribute, set it to `null`.
* **Scoped vs unscoped roles** - stored in the same array. `getSubjectRoles` filters for entries without a scope; `getSubjectScopedRoles` filters 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](/duck-iam/integrations/adapters/prisma), [Drizzle](/duck-iam/integrations/adapters/drizzle), or [Redis](/duck-iam/integrations/adapters/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`).

```typescript
import type { IamMemory } from '@gentleduck/iam/adapters/memory'

const init: IamMemory.IInit = {
  roles: [/* ... */],
  assignments: { 'user-1': ['admin'] },
}
```