> ## Documentation Index
> Fetch the complete documentation index at: https://docs.collab-kit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Stores

> Schema-driven, type-safe KV stores synced in real time.

Stores are schema-driven key-value stores that sync across all connected clients in real time. Define a schema, and the SDK gives you fully typed CRUD operations with automatic validation and real-time change events.

Access stores via `client.stores.<storeName>`.

<Note>
  Editors can write stores. Viewers receive store updates and can read stores, but `set`, `update`, and `delete` are blocked for viewer sessions.
</Note>

## Schema Definition

Define your store schemas using `defineStores()` from `@collab-kit/utils` and pass to the client constructor:

```typescript theme={null}
import { defineStores } from '@collab-kit/utils';

const stores = defineStores({
  tasks: {
    title: { type: 'string', required: true },
    completed: { type: 'boolean', default: false },
    assignee: { type: 'string' },
  },
  settings: {
    theme: { type: 'string', required: true, default: 'light' },
    fontSize: { type: 'number', required: true, default: 14 },
    notifications: { type: 'boolean', default: true },
  },
});

const client = new CollabKitClient({
  serverUrl: 'https://api.collab-kit.com',
  authToken: '<jwt>',
  stores,
});
```

| Option     | Type                                | Description                                                        |
| ---------- | ----------------------------------- | ------------------------------------------------------------------ |
| `type`     | `'string' \| 'number' \| 'boolean'` | The primitive type of the field                                    |
| `required` | `boolean`                           | If `true`, the field must be present on `set`. Defaults to `false` |
| `default`  | `string \| number \| boolean`       | Default value applied when the field is missing on `set`           |

## Methods

### Add Entry

**`set({ key, value })`**

Create or overwrite an entry. Required fields (without defaults) must be provided:

```typescript theme={null}
await client.stores.tasks.set({
  key: 'task-1',
  value: { title: 'Build stores feature', assignee: 'user-001' },
});
// 'completed' defaults to false (from schema)
```

### Get Entry

**`get({ key })`**

Fetch a single entry by key. Returns `null` if the key doesn't exist:

```typescript theme={null}
const task = await client.stores.tasks.get({ key: 'task-1' });
// { title: 'Build stores feature', completed: false, assignee: 'user-001' } | null
```

### Get All Entries

**`getAll()`**

Fetch all entries in the store:

```typescript theme={null}
const all = await client.stores.tasks.getAll();
// [{ key: 'task-1', value: { title: '...', completed: false, assignee: '...' } }]
```

### Update Entry

**`update({ key, value })`**

Partially update an existing entry. Only the provided fields are validated and merged:

```typescript theme={null}
await client.stores.tasks.update({
  key: 'task-1',
  value: { completed: true },
});
// Only 'completed' is updated; 'title' and 'assignee' remain unchanged
```

### Delete Entry

**`delete({ key })`**

Delete an entry by key:

```typescript theme={null}
await client.stores.tasks.delete({ key: 'task-1' });
```

### Sync Store

**`sync()`**

Force a full sync of the store from the server:

```typescript theme={null}
await client.stores.tasks.sync();
```

## Events

You can listen to changes made to a store like so:

```typescript theme={null}
client.stores.tasks.on('changed', (event) => {
  console.log(event.key);    // 'task-1'
  console.log(event.action); // 'set' | 'update' | 'delete'
  console.log(event.value);  // the new value (or null on delete)
});

// Alternatively, subscribe to a specific key
client.stores.tasks.on('task-1', (value) => {
  console.log('task-1 changed:', value);
});
```

| Event         | Payload                                                                    | Description                          |
| ------------- | -------------------------------------------------------------------------- | ------------------------------------ |
| `changes`     | `{ key: string, action: 'set' \| 'update' \| 'delete', value: T \| null }` | Store changes along with the action  |
| `<store-key>` | `T`                                                                        | Value as defined in the store schema |

<Note>
  Store events fire for changes made by **other clients**. Your own `set`/`update`/`delete` calls resolve with the new value directly.
</Note>

## Validation

The client validates values against the schema before sending them to the server:

* **`set`**: All `required` fields (without `default`) must be provided. Default values are applied for missing fields that have defaults.
* **`update`**: Only provided fields are validated against their schema types.
* **Type checking**: Values must match the declared `type` (`string`, `number`, or `boolean`).

If validation fails, the operation throws an error before making a network request.

## Examples

### Task Store

```typescript theme={null}
import CollabKitClient from '@collab-kit/client';
import { defineStores } from '@collab-kit/utils';

const stores = defineStores({
  tasks: {
    title: { type: 'string', required: true },
    completed: { type: 'boolean', default: false },
    assignee: { type: 'string' },
  },
});

// Listen for changes from other clients
client.stores.tasks.on('changed', ({ key, action, value }) => {
  console.log(`[${action}] ${key}:`, value);
  renderTaskList();
});

// Create a task
await client.stores.tasks.set({
  key: 'task-1',
  value: { title: 'Ship v1' },
});

// Mark complete
await client.stores.tasks.update({
  key: 'task-1',
  value: { completed: true },
});
```
