Skip to content
Strata Sync

AI agents: fetch the documentation index at llms.txt. Markdown versions are available by appending .md to any page URL, including this page's markdown.

Model base class

The Model base class provides change tracking, hydration, serialization, and CRUD operations for synced entities.

Every synced entity extends Model. Decorators register it with the ModelRegistry and wire it into the sync lifecycle.

Creating a model

import { Model, ClientModel, Property, ManyToOne } from "@stratasync/core";

@ClientModel("Task")
class Task extends Model {
  @Property()
  title = "";

  @Property()
  status = "todo";

  @Property()
  priority = 0;

  @ManyToOne("Project", "tasks")
  project!: Project;
}

@ClientModel registers the class as "Task". Each @Property marks a synced field for change tracking and delta processing.

Model properties

PropertyTypeDescription
idstringPrimary key (UUID). Set automatically on creation.
hydratedbooleanWhether lazy references have been resolved.
__modelNamestringThe registered model name (read-only getter).

Internals. __data holds raw backing data. store is the backing store reference injected by the sync client. You shouldn't need either in application code.

Instance methods

hydrate()

Resolves all lazy references and collections.

const task = await client.get<Task>("Task", taskId);
const hydrated = await task.hydrate();
// hydrated.project is a resolved Project instance

Signature: hydrate(): Promise<Hydrated<this>>

See Type utilities for details on the Hydrated<T> type.

save()

Persists pending changes. Creates an update transaction, or an insert if the model has no id.

task.title = "Updated title";
await task.save();

Signature: save(): Promise<void>

delete()

Deletes this model instance.

await task.delete();

Signature: delete(): Promise<void>

archive()

Soft-deletes by setting archivedAt.

await task.archive();

Signature: archive(): Promise<void>

unarchive()

Restores a soft-deleted model.

await task.unarchive();

Signature: unarchive(): Promise<void>

changeSnapshot()

Returns a snapshot of pending changes and their original values.

task.title = "New title";
const snapshot = task.changeSnapshot();
// snapshot.changes = { title: "New title" }
// snapshot.original = { title: "Old title" }

Signature: changeSnapshot(): ChangeSnapshot

interface ChangeSnapshot {
  changes: Record<string, unknown>;
  original: Record<string, unknown>;
}

clearChanges()

Discards all tracked changes without persisting.

Signature: clearChanges(): void

toJSON()

Serializes the model for persistence or transport.

const json = task.toJSON();
// { id: "abc-123", title: "My Task", status: "todo", ... }

Signature: toJSON(): Record<string, unknown>

_applyUpdate(changes)

Applies changes without triggering change tracking. Used internally when applying server deltas.

Signature: _applyUpdate(changes: Record<string, unknown>): void

Change tracking

Decorated properties track changes automatically. Setting a property records the original value so the model can produce a delta on save.

const task = await client.get<Task>("Task", taskId);
task.title = "Updated";
task.priority = 3;

const snapshot = task.changeSnapshot();
// snapshot.changes = { title: "Updated", priority: 3 }
// snapshot.original = { title: "Original", priority: 0 }

await task.save(); // Creates an update transaction, then clears changes

Type utilities

Hydrated<T>

Converts lazy reference fields to resolved types.

import type { Hydrated } from "@stratasync/core";

// Before hydration: task.project is LazyReference<Project>
// After hydration: task.project is Project
const hydrated: Hydrated<Task> = await task.hydrate();

LazyReference<T>

A reference that may not yet be loaded. Access triggers lazy loading when the sync client is available.

import type { LazyReference } from "@stratasync/core";

const project = await resolvePromise(task.project);