> ## Documentation Index
> Fetch the complete documentation index at: https://chahine.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# ORSet

> Observed-Remove Set. Concurrent add and remove operations are handled correctly.

An ORSet (Observed-Remove Set) allows concurrent adds and removes without conflicts. Each add generates a unique tag; a remove only removes the specific tags it observed — so a concurrent add of the same element wins.

## Usage without schema

```ts theme={null}
const tags = client.orset("or:article-123-tags");

tags.add("typescript");
tags.remove("javascript");

console.log(tags.elements()); // string[]

tags.onChange(elements => console.log("tags:", elements));
```

## Usage with schema

```ts theme={null}
import { Schema } from "effect";

const Item = Schema.Struct({ id: Schema.String, name: Schema.String });
const cart = client.orset("or:cart-user-42", Item);

cart.add({ id: "prod-1", name: "Keyboard" });

cart.onChange(items => {
  // items: { id: string; name: string }[]
  for (const item of items) {
    console.log(item.name);
  }
});
```

Incoming deltas are validated against the schema at runtime via `Schema.decodeUnknownSync`. Invalid entries are discarded.

## Encryption

ORSet supports end-to-end encryption. Pass an `encryption` map to `MeridianClient.create()`:

```ts theme={null}
import { Effect } from "effect";
import { MeridianClient, importAesGcmKey } from "meridian-sdk";

const key = await importAesGcmKey(process.env.SECRET_KEY!);

const client = await Effect.runPromise(
  MeridianClient.create({
    url: "wss://your-server.com",
    namespace: "my-app",
    token,
    encryption: { "or:secret-*": key },
  })
);

const tags = client.orset("or:secret-tags");
tags.add("confidential");    // wire value is encrypted — server never sees "confidential"
tags.remove("confidential"); // works correctly across all clients
console.log(tags.elements()); // ["confidential"] — decrypted locally
```

The SDK uses **deterministic nonce derivation** (nonce = `SHA-256(plaintext)[0:12]`) so that the same element always produces the same ciphertext. This is required for correctness: the server keys entries by encrypted value, and `remove()` must reconstruct the exact same key. See [Encryption](https://chahine.mintlify.site/sdk/encryption.md#orset--deterministic-encryption) for the full security analysis.

## Element depth limit

ORSet elements must be **scalars or single-level objects/arrays** (depth ≤ 1). Nested structures are rejected by the server:

```ts theme={null}
// ✅ allowed
tags.add("typescript");
tags.add(42);
tags.add({ id: "prod-1", name: "Keyboard" }); // flat object

// ❌ rejected — nested object, depth > 1
cart.add({ id: "prod-1", meta: { color: "red" } });
```

Rejected ops return a `400` error with the message `ORSet element nesting depth X exceeds maximum 1`. This limit is enforced at the server level and cannot be bypassed.

## API

| Method | Description |
| - | - |
| `add(value: T)` | Add an element |
| `remove(value: T)` | Remove all observed instances of an element |
| `has(value: T)` | Returns `true` if the element is currently in the set |
| `elements()` | Returns current elements as `T[]` |
| `onChange(fn)` | Subscribe — returns unsubscribe function |
| `stream()` | Returns an Effect `Stream<T[]>` that emits on every change |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.