Skip to content

Domain Model & Entity Ecosystem ​

Core technical specification of the entities, records and event contracts that @actdim/livestruct manages. For usage see Core Concepts; for the full symbol list see API Reference.

1. Entity Overview ​

EntityTypeIdentityLifetime
StoreLiveStoreInstanceLiveStructConfig.name (LiveStore storeId) + sessionIdcreateLiveStruct() until close()
CollectionLiveCollection<T>collection namecached per store until dispose()
DocumentLiveDocument<T>(collection, id)cached per collection until deleted or disposed
Persisted rowdocs table row / DocumentRecord<T>key = makeDocKey(collection, id)until DocDeleted
BlobUint8Array / Float32Array in a BlobStoreSHA-256 hex of tag byte + bytescontent-addressed, shared by identical payloads

2. Persisted Record (docs table) ​

All collections share one table defined in src/engine/schema.ts:

ColumnTypeMeaning
keyTEXT, primary key`${collection}\u0001${id}`
collectionTEXTCollection name.
idTEXTDocument id within the collection.
bodyTEXT, default '{}'JSON document body.
revINTEGER, default 1Revision; incremented by every replace, patch and path set.
updatedAtINTEGERMillisecond timestamp carried by the event.
blobsTEXT, default '{}'JSON map of blob name to SHA-256 hash.
mutationIdTEXTId of the last mutation (echo suppression).
overlayIdTEXTOverlay id of the last mutation (tentative overlay matching).
originTEXTlocal, remote or migration.

Index: idx_docs_collection_updatedAt (collection, updatedAt).

The in-memory projection of a row is DocumentRecord<T>: { collection, id, rev, data, blobs, updatedAt }, where blobs is a BlobMap of rehydrated typed arrays (filled by getDoc, empty for queryDocs).

3. Events (Write Model) ​

LiveStore synced events (namespace livestruct.v1.), all carrying collection, id, mutationId, origin, updatedAt:

EventExtra fieldsMaterializer
DocInserteddata, blobs?, overlayId?INSERT ... rev = 1 ... ON CONFLICT (key) DO NOTHING
DocReplaceddata, blobs?, overlayId?upsert; on conflict replace body, rev = rev + 1
DocPatchedpatch, blobs?, overlayId?body = json_patch(body, ?), rev = rev + 1
DocPathSetpath, value, overlayId?body = json_set(body, ?, json(?)), rev = rev + 1
DocDeleted-DELETE FROM docs WHERE key = ?

data, patch, value and blobs are JSON strings; binary payloads never appear in events (only hashes).

Application-level writes map to events as follows:

APIEvent(s)
collection.create, engine.insertDoc, commitRaw({ type: 'insert' })DocInserted
doc.replace, engine.updateDoc, commitRaw({ type: 'update' })DocReplaced
doc.patch (via scheduler), engine.patchDoc, commitRaw({ type: 'patch' })DocPatched
doc.patchPath (via scheduler), engine.setPathDocDocPathSet
collection.delete, engine.deleteDoc, commitRaw({ type: 'delete' })DocDeleted
legacy v1 migrationDocInserted with origin: 'migration'

4. Document State Model ​

A LiveDocument combines three layers into the visible data:

StateisPendingisTentativedata
Committedfalsefalsecommitted body
Pendingtruefalsecommitted body + local pending patches
Tentativefalsetruecommitted body + remote overlay patch

5. Change Data Capture Contract ​

CDCEvent<T> (src/engine/types.ts):

FieldMeaning
typeinsert, update or delete.
kindAdds replace for full-body replacement.
collection, idTarget document.
revRevision after the change.
deltaPatch (local patch) or full body (inserts, replaces, remote updates).
dataFull body after the change (absent for deletes).
timestampMilliseconds.
mutationId, overlayIdCorrelation ids for echo suppression and overlay matching.
originlocal, remote or migration.

LiveEngineAccess<T>.cdc$ (the per-collection view used by doc.engine) carries type, id, delta, and mutationId / overlayId when present.

6. Diagnostic Events ​

LiveStructEvent (src/document/types.ts): type (local_patch, overlay_sent, overlay_received, commit, remote_commit), collection, id, timestamp, optional rev, overlayId, senderSessionId, origin, patch.

7. Ephemeral Messages ​

OverlayChannel messages on BroadcastChannel livestruct:<storeId>:overlay:

  • OverlayMessage - { type: 'overlay', collection, id, patch, overlayId, senderSessionId, timestamp }.
  • CommitMessage - { type: 'commit', collection, id, overlayId, patch?, rev?, senderSessionId, timestamp }.

They are never persisted.

8. Value Constraints ​

Document bodies must be JSON-safe (assertJsonSafe): no NaN / Infinity, functions, symbols, bigints, Date, Map, Set, typed arrays, ArrayBuffer, class instances or circular references. Violations throw LiveStructValueError with the offending path.

Released under the MIT License.