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

# Schema and registry

Stores runtime metadata about models, properties, and relationships. Decorators populate it at import time; the sync engine reads from it at runtime.

## ModelRegistry

Two modes: a **static registry** that decorators populate at import time, and an **instance registry** constructed from a serialized snapshot for server-side use.

### Static API

Read from the global registry that decorators populate.

```ts
import { ModelRegistry } from "@stratasync/core";

const names = ModelRegistry.getModelNames();
// ["Workspace", "Project", "Task", ...]

const meta = ModelRegistry.getModelMetadata("Task");
// { name: "Task", loadStrategy: "instant" }

const props = ModelRegistry.getModelProperties("Task");
// Map { "title" => { type: "property" }, "projectId" => { type: "reference", ... } }

const hash = ModelRegistry.getSchemaHash();
// "a1b2c3d4"
```

### Static method reference

| Method                                 | Return type                     | Description                                   |
| -------------------------------------- | ------------------------------- | --------------------------------------------- |
| `registerModel(name, ctor, meta)`      | `void`                          | Registers a model (called by `@ClientModel`). |
| `registerProperty(target, name, meta)` | `void`                          | Registers a property (called by decorators).  |
| `getModelNames()`                      | `string[]`                      | All registered model names.                   |
| `getModelMetadata(name)`               | `ModelMetadata \| undefined`    | Metadata for one model.                       |
| `getModelConstructor(name)`            | `ModelConstructor \| undefined` | Constructor for a model name.                 |
| `getModelName(ctor)`                   | `string \| undefined`           | Model name for a constructor.                 |
| `hasModel(name)`                       | `boolean`                       | Whether a model is registered.                |
| `getModelMetadataEntries()`            | `[string, ModelMetadata][]`     | All metadata entries.                         |
| `getBootstrapModelNames()`             | `string[]`                      | Models with `instant` load strategy.          |
| `getPartialModelNames()`               | `string[]`                      | Models with `partial` load strategy.          |
| `getModelProperties(name)`             | `Map<string, PropertyMetadata>` | Property metadata map for a model.            |
| `getReferencedProperties(name)`        | `Map<string, PropertyMetadata>` | Reference and collection properties only.     |
| `getPropertyNames(name)`               | `string[]`                      | Sorted property names.                        |
| `getSchemaHash()`                      | `string`                        | Deterministic hash of the full schema.        |
| `snapshot()`                           | `ModelRegistrySnapshot`         | Serializable snapshot of the registry.        |

### Instance API

Use when you don't have access to decorators (for example, on the server).

```ts
import { ModelRegistry } from "@stratasync/core";

const registry = new ModelRegistry({
  models: {
    Task: {
      loadStrategy: "instant",
      fields: {
        id: {},
        title: { type: "string" },
        status: { type: "string" },
      },
      relations: {
        project: {
          kind: "belongsTo",
          model: "Project",
          foreignKey: "projectId",
        },
      },
    },
  },
});

const names = registry.getModelNames();
const hash = registry.getSchemaHash();
const model = registry.getModel("Task");
```

### Instance method reference

| Method                      | Return type                     | Description                             |
| --------------------------- | ------------------------------- | --------------------------------------- |
| `getModelNames()`           | `string[]`                      | All model names.                        |
| `getModelMetadata(name)`    | `ModelMetadata \| undefined`    | Metadata for one model.                 |
| `hasModel(name)`            | `boolean`                       | Whether a model exists.                 |
| `getModelMetadataEntries()` | `[string, ModelMetadata][]`     | All metadata entries.                   |
| `getBootstrapModelNames()`  | `string[]`                      | Models with `instant` load strategy.    |
| `getPartialModelNames()`    | `string[]`                      | Models with `partial` load strategy.    |
| `getModelProperties(name)`  | `Map<string, PropertyMetadata>` | Property metadata map.                  |
| `getPropertyNames(name)`    | `string[]`                      | Sorted property names.                  |
| `getSchemaHash()`           | `string`                        | Deterministic schema hash.              |
| `snapshot()`                | `ModelRegistrySnapshot`         | Underlying snapshot data.               |
| `getModel(name)`            | `ModelDefinition \| undefined`  | Full model definition.                  |
| `getAllModels()`            | `ModelDefinition[]`             | All model definitions.                  |
| `getBootstrapModels()`      | `ModelDefinition[]`             | Models for bootstrap loading.           |
| `getPartialModels()`        | `ModelDefinition[]`             | Partially-loaded models.                |
| `getPrimaryKey(name)`       | `string`                        | Primary key field (defaults to `"id"`). |

## computeSchemaHash

Produces a deterministic hash string for a schema, used to detect client/server mismatches.

```ts
import { computeSchemaHash, ModelRegistry } from "@stratasync/core";

const hash = computeSchemaHash(ModelRegistry.snapshot());
```

**Signature:** `computeSchemaHash(input: ModelRegistrySnapshot | SchemaDefinition): string`

Canonicalizes the snapshot (sorting names, stripping `undefined`), serializes to JSON, and returns an 8-character djb2 hex hash. The sync client compares hashes at bootstrap to decide if a full re-bootstrap is needed.

## Load strategies

Set via `@ClientModel`. See [Load strategies](/guides/load-strategies) for a full walkthrough.

| Strategy                                                     | Bootstrap | Best for                                 |
| ------------------------------------------------------------ | --------- | ---------------------------------------- |
| `"instant"`                                                  | Included  | Core data needed on every page           |
| `"lazy"` / `"partial"` / `"explicitlyRequested"` / `"local"` | Excluded  | Data loaded on demand or kept local-only |

## Schema types

### ModelMetadata

```ts
interface ModelMetadata {
  name: string;
  loadStrategy: LoadStrategy;
  partialLoadMode?: PartialLoadMode;
  usedForPartialIndexes?: boolean;
  schemaVersion?: number;
  tableName?: string;
}
```

### PropertyMetadata

```ts
interface PropertyMetadata {
  type: PropertyType;
  lazy?: boolean;
  serializer?: PropertySerializer<unknown>;
  indexed?: boolean;
  nullable?: boolean;
  referenceModel?: string;
  inverseProperty?: string;
  foreignKey?: string;
  through?: string;
}
```

### PropertyType

```ts
type PropertyType =
  | "property"
  | "ephemeralProperty"
  | "reference"
  | "referenceModel"
  | "referenceCollection"
  | "backReference"
  | "referenceArray";
```

### SchemaDefinition

Programmatic alternative to decorator-based schema registration.

```ts
interface SchemaDefinition {
  models: Record<string, ModelDefinition>;
}

interface ModelDefinition {
  name?: string;
  loadStrategy?: LoadStrategy;
  partialLoadMode?: PartialLoadMode;
  primaryKey?: string;
  groupKey?: string;
  fields?: Record<string, FieldDefinition>;
  relations?: Record<string, RelationDefinition>;
  indexes?: ModelIndexDefinition[];
  schemaVersion?: number;
  tableName?: string;
}
```