{"_id":"@electric-ax/durable-streams-state-beta","_rev":"2-37387b402276e903ea56142ef53270ee","name":"@electric-ax/durable-streams-state-beta","dist-tags":{"latest":"0.3.1"},"versions":{"0.3.0":{"name":"@electric-ax/durable-streams-state-beta","version":"0.3.0","keywords":["durable-streams","state","protocol","typescript"],"author":{"name":"Durable Stream contributors"},"license":"Apache-2.0","_id":"@electric-ax/durable-streams-state-beta@0.3.0","maintainers":[{"name":"electricsql-bot","email":"infra@electric-sql.com"}],"homepage":"https://github.com/durable-streams/durable-streams#readme","bugs":{"url":"https://github.com/durable-streams/durable-streams/issues"},"bin":{"intent":"bin/intent.js"},"dist":{"shasum":"6ee08d290574b53374189a792ed0e027016d75c6","tarball":"https://registry.npmjs.org/@electric-ax/durable-streams-state-beta/-/durable-streams-state-beta-0.3.0.tgz","fileCount":16,"integrity":"sha512-/jJyT757kz765v6vhmElYTz4E1IMa547UXuOjEYEdHW6TjubLWVve+6bc7w4rXma1AXoE6e8j3sYi+JT0aJeZw==","signatures":[{"sig":"MEQCIBCMo2kW1ibNH8QIlUy8U+rgthYSZJDBgy6WszcQ1OmKAiBs+HLtoaXs9tLwYHxZh9O918Cv3S9HrHCOGyrZZijG9g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":219931},"main":"./dist/index.cjs","type":"module","_from":"file:electric-ax-durable-streams-state-beta-0.3.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"tsdown --watch","build":"tsdown","typecheck":"tsc --noEmit"},"_npmUser":{"name":"electricsql-bot","email":"infra@electric-sql.com"},"_resolved":"/private/var/folders/8h/10dynkk10g75zmhg0gy2sd5c0000gn/T/72a5c6552871b94dcdc84b80636e96f3/electric-ax-durable-streams-state-beta-0.3.0.tgz","_integrity":"sha512-/jJyT757kz765v6vhmElYTz4E1IMa547UXuOjEYEdHW6TjubLWVve+6bc7w4rXma1AXoE6e8j3sYi+JT0aJeZw==","repository":{"url":"git+https://github.com/durable-streams/durable-streams.git","type":"git","directory":"packages/state"},"_npmVersion":"11.6.2","description":"State change event protocol for Durable Streams","directories":{},"sideEffects":false,"_nodeVersion":"24.12.0","dependencies":{"@tanstack/db":"^0.6.4","@standard-schema/spec":"^1.0.0","@durable-streams/client":"npm:@electric-ax/durable-streams-client-beta@0.3.0"},"_hasShrinkwrap":false,"devDependencies":{"tsdown":"^0.9.0","@tanstack/db":"^0.6.4","@tanstack/intent":"latest","@durable-streams/server":"npm:@electric-ax/durable-streams-server-beta@0.3.0"},"_npmOperationalInternal":{"tmp":"tmp/durable-streams-state-beta_0.3.0_1776855515321_0.34495479395759854","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@electric-ax/durable-streams-state-beta","description":"State change event protocol for Durable Streams","version":"0.3.1","author":{"name":"Durable Stream contributors"},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/durable-streams/durable-streams.git","directory":"packages/state"},"bugs":{"url":"https://github.com/durable-streams/durable-streams/issues"},"keywords":["durable-streams","state","protocol","typescript"],"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"sideEffects":false,"bin":{"intent":"bin/intent.js"},"dependencies":{"@standard-schema/spec":"^1.0.0","@tanstack/db":"^0.6.4","@electric-ax/durable-streams-client-beta":"0.3.1"},"devDependencies":{"@tanstack/db":"^0.6.4","@tanstack/intent":"latest","tsdown":"^0.9.0"},"engines":{"node":">=18.0.0"},"scripts":{"build":"tsdown","dev":"tsdown --watch","typecheck":"tsc --noEmit"},"_id":"@electric-ax/durable-streams-state-beta@0.3.1","homepage":"https://github.com/durable-streams/durable-streams#readme","_integrity":"sha512-84Y3/ERaJgXEtXRqkyK+lML59ABqg/zjsQD3YYR+EWysMsoy6f664GZ5QzTqbuxO/03nP83FuAYFDPw6jgIsCA==","_resolved":"/private/var/folders/8h/10dynkk10g75zmhg0gy2sd5c0000gn/T/a3b81e3a62dec01abf2f8d851ea553c7/electric-ax-durable-streams-state-beta-0.3.1.tgz","_from":"file:electric-ax-durable-streams-state-beta-0.3.1.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-84Y3/ERaJgXEtXRqkyK+lML59ABqg/zjsQD3YYR+EWysMsoy6f664GZ5QzTqbuxO/03nP83FuAYFDPw6jgIsCA==","shasum":"857fed0811315197c1fc974ca0ff98acf023c350","tarball":"https://registry.npmjs.org/@electric-ax/durable-streams-state-beta/-/durable-streams-state-beta-0.3.1.tgz","fileCount":16,"unpackedSize":221370,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICDe0eTEcMG0LCqMaH7FvxNDxCAyvmalnWnnTPm4zcRaAiAWi69WGJWFocfsX43JCLUVKXWMZqiqkxM8cMkLhwWM2g=="}]},"_npmUser":{"name":"electricsql-bot","email":"infra@electric-sql.com"},"directories":{},"maintainers":[{"name":"electricsql-bot","email":"infra@electric-sql.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/durable-streams-state-beta_0.3.1_1777385666289_0.6376975680796366"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-22T10:58:35.215Z","modified":"2026-04-28T14:14:26.613Z","0.3.0":"2026-04-22T10:58:35.457Z","0.3.1":"2026-04-28T14:14:26.455Z"},"bugs":{"url":"https://github.com/durable-streams/durable-streams/issues"},"author":{"name":"Durable Stream contributors"},"license":"Apache-2.0","homepage":"https://github.com/durable-streams/durable-streams#readme","keywords":["durable-streams","state","protocol","typescript"],"repository":{"type":"git","url":"git+https://github.com/durable-streams/durable-streams.git","directory":"packages/state"},"description":"State change event protocol for Durable Streams","maintainers":[{"name":"electricsql-bot","email":"infra@electric-sql.com"}],"readme":"# @durable-streams/state\n\nBuilding blocks for transmitting structured state over Durable Streams. Use these primitives for any real-time protocol: AI token streams, presence updates, collaborative editing, or database sync.\n\n## Installation\n\n```bash\npnpm add @durable-streams/state @tanstack/db\n```\n\n> **Note:** `@tanstack/db` is a peer dependency that must be installed alongside this package. This ensures type compatibility when using StreamDB collections with TanStack DB's query utilities like `useLiveQuery` from `@tanstack/react-db`.\n\n## Overview\n\nThis package provides flexible primitives for streaming structured state. You choose how much structure you need:\n\n- **Simple state updates**: Stream JSON payloads and track current values\n- **Typed collections**: Add schemas and primary keys for structured entities\n- **Reactive queries**: Build on TanStack DB for subscriptions and optimistic updates\n\nStream whatever state your protocol requires.\n\n## Quick Start\n\n### Simple State\n\nStream structured JSON and query current values:\n\n```typescript\nimport { MaterializedState } from \"@durable-streams/state\"\n\nconst state = new MaterializedState()\n\n// Apply any structured change\nstate.apply({\n  type: \"token\",\n  key: \"stream-1\",\n  value: { content: \"Hello\", model: \"claude-3\" },\n  headers: { operation: \"insert\" },\n})\n\n// Query current state\nconst token = state.get(\"token\", \"stream-1\")\nconst allTokens = state.getType(\"token\")\n```\n\n### Typed Collections\n\nAdd schemas and validation for structured entities:\n\n```typescript\nimport { createStateSchema, createStreamDB } from \"@durable-streams/state\"\n\n// Define your schema\nconst schema = createStateSchema({\n  users: {\n    schema: userSchema, // Standard Schema validator\n    type: \"user\", // Event type field\n    primaryKey: \"id\", // Primary key field name\n  },\n  messages: {\n    schema: messageSchema,\n    type: \"message\",\n    primaryKey: \"id\",\n  },\n})\n\n// Create a stream-backed database\nconst db = createStreamDB({\n  streamOptions: {\n    url: \"https://api.example.com/streams/my-stream\",\n    contentType: \"application/json\",\n  },\n  state: schema,\n})\n\n// Load initial data\nawait db.preload()\n\n// Reactive queries with useLiveQuery\nimport { useLiveQuery } from \"@tanstack/react-db\" // or solid-db, vue-db\nimport { eq } from \"@tanstack/db\"\n\nconst userQuery = useLiveQuery((q) =>\n  q\n    .from({ users: db.collections.users })\n    .where(({ users }) => eq(users.id, \"123\"))\n    .findOne()\n)\n\nconst allUsersQuery = useLiveQuery((q) =>\n  q.from({ users: db.collections.users })\n)\n```\n\n## Core Concepts\n\n### State Protocol\n\nThe Durable Streams State Protocol defines a standard format for state change events:\n\n- **Change Events**: `insert`, `update`, `delete` operations on entities\n- **Control Events**: `snapshot-start`, `snapshot-end`, `reset` signals\n- **Entity Types**: Discriminator field that routes events to collections\n- **Primary Keys**: Unique identifiers extracted from entity values\n\nSee [STATE-PROTOCOL.md](./STATE-PROTOCOL.md) for the full specification.\n\n### MaterializedState\n\nSimple in-memory state container for basic use cases:\n\n```typescript\nimport { MaterializedState } from \"@durable-streams/state\"\n\nconst state = new MaterializedState()\n\n// Apply change events\nstate.apply({\n  type: \"user\",\n  key: \"1\",\n  value: { name: \"Kyle\" },\n  headers: { operation: \"insert\" },\n})\n\n// Query state\nconst user = state.get(\"user\", \"1\")\nconst allUsers = state.getType(\"user\")\n```\n\n### StreamDB\n\nStream-backed database with TanStack DB collections. Provides reactive queries, subscriptions, and optimistic updates.\n\n## Schema Definition\n\n### createStateSchema()\n\nDefine your application state structure:\n\n```typescript\nconst schema = createStateSchema({\n  users: {\n    schema: userSchema, // Standard Schema validator\n    type: \"user\", // Event type for routing\n    primaryKey: \"id\", // Field to use as primary key\n  },\n  messages: {\n    schema: messageSchema,\n    type: \"message\",\n    primaryKey: \"id\",\n  },\n})\n```\n\n### Standard Schema Support\n\nUses [Standard Schema](https://standardschema.dev/) for validation, supporting multiple libraries:\n\n```typescript\n// Zod\nimport { z } from \"zod\"\n\nconst userSchema = z.object({\n  id: z.string(),\n  name: z.string(),\n  email: z.string().email(),\n})\n\n// Valibot\nimport * as v from \"valibot\"\n\nconst userSchema = v.object({\n  id: v.string(),\n  name: v.string(),\n  email: v.pipe(v.string(), v.email()),\n})\n\n// Manual Standard Schema\nconst userSchema = {\n  \"~standard\": {\n    version: 1,\n    vendor: \"my-app\",\n    validate: (value) => {\n      // Your validation logic\n      if (isValid(value)) {\n        return { value }\n      }\n      return { issues: [{ message: \"Invalid user\" }] }\n    },\n  },\n}\n```\n\n## Event Helpers\n\nSchema provides typed event creation helpers:\n\n```typescript\n// Insert\nconst insertEvent = schema.users.insert({\n  value: { id: \"1\", name: \"Kyle\", email: \"kyle@example.com\" },\n  key: \"1\", // Optional, defaults to value[primaryKey]\n})\n\n// Update\nconst updateEvent = schema.users.update({\n  value: { id: \"1\", name: \"Kyle Mathews\", email: \"kyle@example.com\" },\n  oldValue: { id: \"1\", name: \"Kyle\", email: \"kyle@example.com\" }, // Optional\n})\n\n// Delete\nconst deleteEvent = schema.users.delete({\n  key: \"1\",\n  oldValue: { id: \"1\", name: \"Kyle\", email: \"kyle@example.com\" }, // Optional\n})\n\n// Custom headers\nconst eventWithTxId = schema.users.insert({\n  value: { id: \"1\", name: \"Kyle\" },\n  headers: {\n    txid: crypto.randomUUID(),\n    timestamp: new Date().toISOString(),\n  },\n})\n```\n\n## StreamDB\n\n### Creating a Database\n\n```typescript\nconst db = createStreamDB({\n  streamOptions: {\n    url: \"https://api.example.com/streams/my-stream\",\n    contentType: \"application/json\",\n    // All DurableStream options supported\n    headers: { Authorization: \"Bearer token\" },\n    batching: true,\n  },\n  state: schema,\n})\n\n// The stream is created lazily when preload() is called\nawait db.preload()\n```\n\n### Reactive Queries with TanStack DB\n\nStreamDB collections are TanStack DB collections. Use TanStack DB's query builder for filtering, sorting, aggregation, and joins with **differential dataflow** - dramatically faster than JavaScript filtering:\n\n```typescript\nimport { useLiveQuery } from \"@tanstack/[framework]-db\" // react-db, solid-db, etc\nimport { eq, gt, and, count } from \"@tanstack/db\"\n\n// Simple collection access\nconst query = useLiveQuery((q) => q.from({ users: db.collections.users }))\n\n// Filtering with WHERE\nconst activeQuery = useLiveQuery((q) =>\n  q\n    .from({ users: db.collections.users })\n    .where(({ users }) => eq(users.active, true))\n)\n\n// Complex conditions\nconst query = useLiveQuery((q) =>\n  q\n    .from({ users: db.collections.users })\n    .where(({ users }) => and(eq(users.active, true), gt(users.age, 18)))\n)\n\n// Sorting and limiting\nconst topUsersQuery = useLiveQuery((q) =>\n  q\n    .from({ users: db.collections.users })\n    .orderBy(({ users }) => users.lastSeen, \"desc\")\n    .limit(10)\n)\n\n// Aggregation with GROUP BY and ordering\nconst langStatsQuery = useLiveQuery((q) => {\n  const languageCounts = q\n    .from({ events: db.collections.events })\n    .groupBy(({ events }) => events.language)\n    .select(({ events }) => ({\n      language: events.language,\n      total: count(events.id),\n    }))\n\n  return q\n    .from({ stats: languageCounts })\n    .orderBy(({ stats }) => stats.total, \"desc\")\n})\n\n// Joins across collections\nconst query = useLiveQuery((q) =>\n  q\n    .from({ messages: db.collections.messages })\n    .join({ users: db.collections.users }, ({ messages, users }) =>\n      eq(messages.userId, users.id)\n    )\n    .select(({ messages, users }) => ({\n      messageId: messages.id,\n      text: messages.text,\n      userName: users.name,\n    }))\n)\n```\n\n**Why use the query builder?**\n\n- **Differential dataflow**: Incremental updates only recompute affected results\n- **Dramatically faster**: Push filtering/sorting into the DB engine vs JavaScript\n- **Reactive**: Queries automatically update when data changes\n- **Type-safe**: Full TypeScript support with autocomplete\n\n**Framework integration**: See [TanStack DB docs](https://tanstack.com/db) for framework-specific guides:\n\n- [@tanstack/react-db](https://tanstack.com/db/latest/docs/framework/react/overview)\n- [@tanstack/solid-db](https://tanstack.com/db/latest/docs/framework/solid/overview)\n- [@tanstack/vue-db](https://tanstack.com/db/latest/docs/framework/vue/overview)\n\n### Lifecycle Methods\n\n```typescript\n// Load all data until up-to-date\nawait db.preload()\n\n// Stop syncing and cleanup\ndb.close()\n\n// Wait for a transaction to be confirmed\nawait db.utils.awaitTxId(\"txid-uuid\", 5000) // 5 second timeout\n```\n\n## Optimistic Actions\n\nDefine actions with optimistic updates and server confirmation:\n\n```typescript\nconst db = createStreamDB({\n  streamOptions: { url: streamUrl, contentType: \"application/json\" },\n  state: schema,\n  actions: ({ db, stream }) => ({\n    addUser: {\n      // Optimistic update (runs immediately)\n      onMutate: (user) => {\n        db.collections.users.insert(user)\n      },\n      // Server mutation (runs async)\n      mutationFn: async (user) => {\n        const txid = crypto.randomUUID()\n\n        await stream.append(\n          JSON.stringify(\n            schema.users.insert({\n              value: user,\n              headers: { txid },\n            })\n          )\n        )\n\n        // Wait for confirmation\n        await db.utils.awaitTxId(txid)\n      },\n    },\n\n    updateUser: {\n      onMutate: ({ id, updates }) => {\n        db.collections.users.update(id, (draft) => {\n          Object.assign(draft, updates)\n        })\n      },\n      mutationFn: async ({ id, updates }) => {\n        const txid = crypto.randomUUID()\n        const current = await db.collections.users.get(id)\n\n        await stream.append(\n          JSON.stringify(\n            schema.users.update({\n              value: { ...current, ...updates },\n              oldValue: current,\n              headers: { txid },\n            })\n          )\n        )\n\n        await db.utils.awaitTxId(txid)\n      },\n    },\n  }),\n})\n\n// Call actions\nawait db.actions.addUser({ id: \"1\", name: \"Kyle\", email: \"kyle@example.com\" })\nawait db.actions.updateUser({ id: \"1\", updates: { name: \"Kyle Mathews\" } })\n```\n\n## Framework Integration\n\nUse TanStack DB's framework adapters for reactive queries:\n\n### React\n\n```typescript\nimport { useLiveQuery } from '@tanstack/react-db'\nimport { eq } from '@tanstack/db'\n\nfunction UserProfile({ userId }: { userId: string }) {\n  const userQuery = useLiveQuery((q) =>\n    q.from({ users: db.collections.users })\n      .where(({ users }) => eq(users.id, userId))\n      .findOne()\n  )\n\n  if (userQuery.isLoading()) return <div>Loading...</div>\n  if (!userQuery.data) return <div>Not found</div>\n\n  return (\n    <div>\n      <h1>{userQuery.data.name}</h1>\n      <p>{userQuery.data.email}</p>\n    </div>\n  )\n}\n```\n\nSee [@tanstack/react-db docs](https://tanstack.com/db/latest/docs/framework/react/overview) for more.\n\n### Solid.js\n\n```typescript\nimport { useLiveQuery } from '@tanstack/solid-db'\nimport { eq } from '@tanstack/db'\n\nfunction MessageList() {\n  const messagesQuery = useLiveQuery((q) =>\n    q.from({ messages: db.collections.messages })\n      .orderBy(({ messages }) => messages.timestamp, 'desc')\n      .limit(50)\n  )\n\n  return (\n    <For each={messagesQuery.data}>\n      {(message) => <MessageCard message={message} />}\n    </For>\n  )\n}\n```\n\nSee [@tanstack/solid-db docs](https://tanstack.com/db/latest/docs/framework/solid/overview) for more.\n\n## Common Patterns\n\n### Key/Value Store\n\n```typescript\nconst schema = createStateSchema({\n  config: {\n    schema: configSchema,\n    type: \"config\",\n    primaryKey: \"key\",\n  },\n})\n\n// Set value\nawait stream.append(\n  JSON.stringify(\n    schema.config.insert({\n      value: { key: \"theme\", value: \"dark\" },\n    })\n  )\n)\n\n// Query value reactively\nconst themeQuery = useLiveQuery((q) =>\n  q\n    .from({ config: db.collections.config })\n    .where(({ config }) => eq(config.key, \"theme\"))\n    .findOne()\n)\n```\n\n### Presence Tracking\n\n```typescript\nconst schema = createStateSchema({\n  presence: {\n    schema: presenceSchema,\n    type: \"presence\",\n    primaryKey: \"userId\",\n  },\n})\n\n// Update presence\nawait stream.append(\n  JSON.stringify(\n    schema.presence.update({\n      value: {\n        userId: \"kyle\",\n        status: \"online\",\n        lastSeen: Date.now(),\n      },\n    })\n  )\n)\n\n// Query presence with TanStack DB\nconst presenceQuery = useLiveQuery((q) =>\n  q\n    .from({ presence: db.collections.presence })\n    .where(({ presence }) => eq(presence.status, \"online\"))\n)\n```\n\n### Multi-Type Chat Room\n\n```typescript\nconst schema = createStateSchema({\n  users: { schema: userSchema, type: \"user\", primaryKey: \"id\" },\n  messages: { schema: messageSchema, type: \"message\", primaryKey: \"id\" },\n  reactions: { schema: reactionSchema, type: \"reaction\", primaryKey: \"id\" },\n  typing: { schema: typingSchema, type: \"typing\", primaryKey: \"userId\" },\n})\n\n// Different types coexist in the same stream\nawait stream.append(JSON.stringify(schema.users.insert({ value: user })))\nawait stream.append(JSON.stringify(schema.messages.insert({ value: message })))\nawait stream.append(\n  JSON.stringify(schema.reactions.insert({ value: reaction }))\n)\n```\n\n## Best Practices\n\n### 1. Use Object Values\n\nStreamDB requires object values (not primitives) for the primary key pattern:\n\n```typescript\n// ❌ Won't work\n{ type: 'count', key: 'views', value: 42 }\n\n// ✅ Works\n{ type: 'count', key: 'views', value: { count: 42 } }\n```\n\n### 2. Always Call close()\n\n```typescript\nuseEffect(() => {\n  const db = createStreamDB({ streamOptions, state: schema })\n\n  return () => db.close() // Cleanup on unmount\n}, [])\n```\n\n### 3. Validate at Boundaries\n\nUse Standard Schema to validate data at system boundaries:\n\n```typescript\nconst userSchema = z.object({\n  id: z.string().uuid(),\n  email: z.string().email(),\n  age: z.number().min(0).max(150),\n})\n```\n\n### 4. Use Transaction IDs\n\nFor critical operations, always use transaction IDs to ensure confirmation:\n\n```typescript\nconst txid = crypto.randomUUID()\nawait stream.append(\n  JSON.stringify(schema.users.insert({ value: user, headers: { txid } }))\n)\nawait db.utils.awaitTxId(txid, 10000) // Wait up to 10 seconds\n```\n\n### 5. Handle Errors Gracefully\n\n```typescript\ntry {\n  await db.actions.addUser(user)\n} catch (error) {\n  if (error.message.includes(\"Timeout\")) {\n    // Handle timeout\n  } else {\n    // Handle other errors\n  }\n}\n```\n\n## API Reference\n\n### Types\n\n```typescript\nexport type Operation = \"insert\" | \"update\" | \"delete\"\n\nexport interface ChangeEvent<T = unknown> {\n  type: string\n  key: string\n  value?: T\n  old_value?: T\n  headers: ChangeHeaders\n}\n\nexport interface ChangeHeaders {\n  operation: Operation\n  txid?: string\n  timestamp?: string\n}\n\nexport interface ControlEvent {\n  headers: {\n    control: \"snapshot-start\" | \"snapshot-end\" | \"reset\"\n    offset?: string\n  }\n}\n\nexport type StateEvent<T = unknown> = ChangeEvent<T> | ControlEvent\n```\n\n### Functions\n\n```typescript\n// Create a state schema with typed collections and event helpers\nexport function createStateSchema<\n  T extends Record<string, CollectionDefinition>,\n>(collections: T): StateSchema<T>\n\n// Create a stream-backed database\nexport async function createStreamDB<\n  TDef extends StreamStateDefinition,\n  TActions extends Record<string, ActionDefinition<any>>,\n>(\n  options: CreateStreamDBOptions<TDef, TActions>\n): Promise<StreamDB<TDef> | StreamDBWithActions<TDef, TActions>>\n```\n\n### Classes\n\n```typescript\nexport class MaterializedState {\n  apply(event: ChangeEvent): void\n  applyBatch(events: ChangeEvent[]): void\n  get<T>(type: string, key: string): T | undefined\n  getType(type: string): Map<string, unknown>\n  clear(): void\n  readonly typeCount: number\n  readonly types: string[]\n}\n```\n\n## License\n\nApache-2.0\n\n## Learn More\n\n- [STATE-PROTOCOL.md](./STATE-PROTOCOL.md) - Full protocol specification\n- [Durable Streams Protocol](../../PROTOCOL.md) - Base protocol\n- [Standard Schema](https://standardschema.dev/) - Schema validation\n- [TanStack DB](https://tanstack.com/db) - Reactive collections\n","readmeFilename":"README.md"}