npm package: @statedelta/core
Description: Core interfaces and types for StateDelta packages
Author: Anderson D. Rosa
Latest version: 0.2.0

# @statedelta/core

> Core interfaces and types for StateDelta packages.

## Overview

Provides:

1. **IEngine** - Minimal deterministic engine contract for Assembler/Persist
2. **Traceable/IStore/ISession** - Base interfaces for stores
3. **Capabilities** - Registry for providers, middlewares, plugins
4. **Document Protocol** - Header/entry format for state documents

## Installation

```bash
pnpm add @statedelta/core
```

## IEngine (Deterministic Contract)

Minimal interface that any engine must implement to work with Assembler.

**Core principle:** Effects are the ONLY external input. Same Effects + Same Tick = Same State.

```typescript
interface IEngine {
  // State
  readonly tick: number;
  readonly locked: boolean;

  // Effects (determinism)
  applyEffect(type: string, payload: unknown): void;   // Gameplay - SAVES
  recoverEffect(type: string, payload: unknown): void; // Replay - NOT saved
  getEffects(): Effect[];
  clearEffects(): void;

  // Execution
  step(): StepResult;

  // Snapshot
  toSnapshot(): IEngineSnapshot;
  recovery(snapshot: IEngineSnapshot): void;

  // Lifecycle
  reset(): void;
  destroy(): void;
}
```

### Effect

External input that changes the deterministic world (the "butterfly"):

```typescript
interface Effect {
  tick: number;       // When applied
  type: string;       // 'player:move', 'seed', 'timestamp'
  payload: unknown;   // Data
  ts: number;         // Timestamp
}
```

### Recovery Flow

```typescript
// Gameplay - effects are SAVED
engine.applyEffect('seed', 12345);
engine.applyEffect('player:move', { dx: 1, dy: 0 });
engine.step();

// Recovery - effects are NOT saved (already in replay)
for (const effect of snapshot.effects) {
  engine.recoverEffect(effect.type, effect.payload);
  while (engine.tick < effect.tick && !engine.locked) {
    engine.step();
  }
}
```

## Traceable

Base interface for all runtime-addable entities.

```typescript
interface Traceable {
  id: string;
  creator: string;      // Who created (immutable, audit)
  owner: string;        // Who controls (mutable, ACL)
  createdAt?: string;
  lifetime?: Lifetime;  // 'eternal' | 'session' | 'stage' | 'step' | '$signal'
  enabled?: boolean | '$signal';
  namespace?: string;   // 'game.combat', 'shop.cart'
  tags?: string[];
  description?: string;
}
```

## IStore<T>

Base interface for all stores with consistent CRUD and queries.

```typescript
interface IStore<T extends Traceable> {
  // CRUD
  add(entity: T): T;
  addMany(entities: T[]): T[];
  get(id: string): T | undefined;
  has(id: string): boolean;
  all(): T[];
  size: number;
  update(id: string, updates: Partial<T>): T;
  remove(id: string): boolean;
  removeMany(ids: string[]): number;
  clear(): void;

  // Queries O(1)
  getByOwner(owner: string): T[];
  getByCreator(creator: string): T[];
  getByLifetime(lifetime: Lifetime): T[];
  getByNamespace(pattern: string): T[];  // supports glob
  getByTags(tags: string[], mode?: 'all' | 'any'): T[];
  query(q: BaseQuery): T[];

  // Lifecycle
  cleanup(lifetime: Lifetime): number;
  cleanupAll(): number;
  enable(id: string): boolean;
  disable(id: string): boolean;

  // Session
  createSession(options?: SessionOptions): ISession<T>;
}
```

## ISession<T>

Scoped view of a store for specific contexts.

```typescript
interface ISession<T extends Traceable> {
  id: string;

  // Read (from parent + temporary)
  get(id: string): T | undefined;
  has(id: string): boolean;
  all(): T[];
  size: number;

  // Queries (on session indexes)
  getByOwner(owner: string): T[];
  getByNamespace(pattern: string): T[];
  query(q: BaseQuery): T[];

  // Temporary entities
  addTemporary(entity: T, lifetime?: Lifetime): T;
  removeTemporary(id: string): boolean;
  isTemporary(id: string): boolean;

  // Lifecycle
  cleanup(lifetime: Lifetime): number;
  destroy(): void;
}
```

## EventEmitter

Type-safe event emitter used by all stores.

```typescript
class MyStore extends EventEmitter<StoreEvents<MyEntity>> {
  add(entity: MyEntity) {
    // ...
    this.emit('added', entity);
  }
}
```

## Patch & DispatchResult

JSON Patch (RFC 6902) types for state mutations.

```typescript
interface Patch {
  op: 'add' | 'remove' | 'replace' | 'move' | 'copy' | 'test';
  path: string;
  value?: unknown;
  from?: string;
}

interface DispatchResult<T = unknown> {
  success: boolean;
  value?: T;
  patches?: Patch[];
  events?: DomainEvent[];
  error?: string;
}
```

## Query Helpers

```typescript
// Namespace matching (supports glob)
matchesNamespace('game.combat', 'game.*')   // true
matchesNamespace('game.combat.damage', 'game.**')  // true

// Tag matching
matchesTags(['a', 'b'], { $all: ['a'] })  // true
matchesTags(['a', 'b'], { $any: ['c'] })  // false
matchesTags(['a'], { $none: ['b'] })      // true
```

## License

MIT