zerodrift 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +29 -21
  2. package/dist/core/BaseModel.d.ts +2 -2
  3. package/dist/core/BaseModel.js +4 -4
  4. package/dist/core/BaseSSEConnection.d.ts +1 -1
  5. package/dist/core/BaseSSEConnection.js +1 -1
  6. package/dist/core/CompoundIndexFetcher.d.ts +2 -2
  7. package/dist/core/CompoundIndexFetcher.js +3 -3
  8. package/dist/core/Database.js +1 -1
  9. package/dist/core/LazyCollection.d.ts +2 -2
  10. package/dist/core/LazyCollection.js +1 -1
  11. package/dist/core/LazyOwnedCollection.d.ts +2 -2
  12. package/dist/core/LazyOwnedCollection.js +1 -1
  13. package/dist/core/MemoryAdapter.d.ts +1 -1
  14. package/dist/core/MemoryAdapter.js +1 -1
  15. package/dist/core/ModelRegistry.d.ts +1 -1
  16. package/dist/core/ModelRegistry.js +2 -2
  17. package/dist/core/ModelStream.d.ts +3 -3
  18. package/dist/core/ModelStream.js +3 -3
  19. package/dist/core/ObjectPool.d.ts +2 -2
  20. package/dist/core/ObjectPool.js +2 -2
  21. package/dist/core/Store.d.ts +4 -4
  22. package/dist/core/Store.js +1 -1
  23. package/dist/core/StoreManager.d.ts +10 -10
  24. package/dist/core/StoreManager.js +12 -12
  25. package/dist/core/SyncConnection.d.ts +5 -5
  26. package/dist/core/SyncConnection.js +4 -4
  27. package/dist/core/Transaction.d.ts +2 -2
  28. package/dist/core/Transaction.js +1 -1
  29. package/dist/core/TransactionQueue.d.ts +6 -6
  30. package/dist/core/TransactionQueue.js +4 -4
  31. package/dist/core/decorators.d.ts +1 -1
  32. package/dist/core/decorators.js +4 -4
  33. package/dist/core/index.d.ts +16 -16
  34. package/dist/core/index.js +9 -9
  35. package/dist/core/internal.d.ts +13 -13
  36. package/dist/core/internal.js +11 -11
  37. package/dist/core/observability.js +1 -1
  38. package/dist/core/refAccessors.d.ts +2 -2
  39. package/dist/core/types.d.ts +1 -1
  40. package/dist/react/index.d.ts +10 -10
  41. package/dist/react/index.js +5 -5
  42. package/dist/schema/builders.d.ts +1 -1
  43. package/dist/schema/builders.js +1 -1
  44. package/dist/schema/compile.d.ts +1 -1
  45. package/dist/schema/compile.js +6 -6
  46. package/dist/schema/createStore.d.ts +5 -5
  47. package/dist/schema/createStore.js +4 -4
  48. package/dist/schema/extend.d.ts +2 -2
  49. package/dist/schema/index.d.ts +13 -13
  50. package/dist/schema/index.js +7 -7
  51. package/dist/schema/infer.d.ts +1 -1
  52. package/dist/schema/types.d.ts +1 -1
  53. package/dist/schema/zod.d.ts +1 -1
  54. package/dist/schema/zod.js +1 -1
  55. package/package.json +1 -1
package/README.md CHANGED
@@ -2,19 +2,27 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/zerodrift.svg)](https://www.npmjs.com/package/zerodrift)
4
4
 
5
- A TypeScript local-first sync engine. Reads are synchronous from an in-memory pool, writes are optimistic, state stays current across tabs and clients via SSE, and everything persists locally so the app survives reloads and works offline. The same engine runs in Node so agents and background workers can hold a live model just like a browser tab.
5
+ **A TypeScript sync engine with an intuitive model API that hides the hard parts of local reads, optimistic writes, offline recovery, and realtime convergence.**
6
6
 
7
- You bring the backend. The client speaks a small three-endpoint protocol that can be implemented in any language. A reference Go backend and Next.js demo live in this repo so you can run the whole loop locally.
7
+ zerodrift lets you work with synced data like normal application state. Components and headless workers read records synchronously, mutate model fields directly, call `save()`, and subscribe with typed React hooks or store APIs. Under that simple surface, the engine does the synchronization work that would otherwise spread across your codebase.
8
+
9
+ The backend stays yours. Implement bootstrap, transaction, and event-stream endpoints in any stack, or start from the included Go backend and Next.js demo. In the browser, zerodrift persists models and queued writes to IndexedDB; in Node, it can run against memory or a custom storage adapter.
10
+
11
+ The result is less sync code in every feature. Define models with decorators or schema-as-data, wire the three transport functions, and build against a small, predictable API while browser tabs, clients, and Node processes converge in the background.
12
+
13
+ The design is inspired by Linear's sync engine; see [Acknowledgments](#acknowledgments) for prior art and attribution.
8
14
 
9
15
  ## What you get
10
16
 
11
- - **Local-first reads**: every read hits an in-memory `ObjectPool` first.
12
- - **Optimistic writes**: model changes update the UI immediately, then reconcile with server deltas.
13
- - **Realtime sync**: tabs and clients stay current over SSE, without polling.
14
- - **Offline persistence**: IndexedDB stores models and queued transactions in the browser.
15
- - **Two authoring paths**: decorator classes or schema-as-data via `defineSchema(...)`.
16
- - **React and headless runtimes**: use hooks in React, or run `StoreManager` directly in Node, CLIs, and agents.
17
- - **Bring your own backend**: implement bootstrap, transaction, and SSE endpoints in the stack you already use.
17
+ - **A small API for synced data**: read records synchronously, mutate model fields directly, call `save()`, or use typed store namespaces generated from a schema.
18
+ - **App logic without cache choreography**: fetching, invalidation, optimistic updates, reconnects, offline replay, and conflict rebasing live in the engine instead of every screen.
19
+ - **Optimistic writes with real recovery**: local changes update immediately, batch into transaction POSTs, persist through reloads, and reconcile when matching server deltas arrive.
20
+ - **Relationships that stay live**: references, inverse collections, owned collections, and indexed lookups update as records hydrate, load lazily, or arrive over SSE.
21
+ - **Schema or class models**: use decorators (`@ClientModel`, `@Property`, `@Reference`) or schema-as-data (`defineSchema(...)`, `entityFromZod(...)`) without `reflect-metadata`.
22
+ - **Memory you can shape**: choose per-model `LoadStrategy` values for eager data, lazy tables, partial index-backed loading, local-only records, or ephemeral SSE-fed state.
23
+ - **Undo/redo built into the transaction layer**: track field-level changes, group atomic multi-model edits, and include custom remote actions in the same undo stack.
24
+ - **React, browser, or headless Node**: use `<SyncProvider>` and typed hooks in React, or run `StoreManager` directly in agents, workers, CLIs, and tests.
25
+ - **Your backend, your stack**: implement three HTTP endpoints in any language, with a reference Go backend and Next.js demo included.
18
26
 
19
27
  ## Install
20
28
 
@@ -33,12 +41,12 @@ Decorator path: enable `experimentalDecorators` in your `tsconfig.json` (or the
33
41
 
34
42
  ## Import paths
35
43
 
36
- | Import | Use it for |
37
- |---|---|
38
- | `zerodrift` | `StoreManager`, `BaseModel`, decorators, `MemoryAdapter`, relation field types (`RefCollection`/`BackRef`/`OwnedRefs`), and the config / error / sync types. The curated, stable surface. |
39
- | `zerodrift/schema` | `defineSchema`, `entityFromZod`, field builders, links, extensions, and typed `store.<entity>.*` APIs. |
40
- | `zerodrift/react` | `<SyncProvider>` and React hooks: `useRecord`, `useRecords`, `useRecordsByIndex`, `useRelation`, `useBatch`, `useUndoRedo`, `useBootstrapStatus`. |
41
- | `zerodrift/internal` | Engine machinery (`ObjectPool`, `TransactionQueue`, `SyncConnection`, `ModelRegistry`, …) for tooling/tests. **No stability promise** — may change between releases. |
44
+ | Import | Use it for |
45
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
46
+ | `zerodrift` | `StoreManager`, `BaseModel`, decorators, `MemoryAdapter`, relation field types (`RefCollection`/`BackRef`/`OwnedRefs`), and the config / error / sync types. The curated, stable surface. |
47
+ | `zerodrift/schema` | `defineSchema`, `entityFromZod`, field builders, links, extensions, and typed `store.<entity>.*` APIs. |
48
+ | `zerodrift/react` | `<SyncProvider>` and React hooks: `useRecord`, `useRecords`, `useRecordsByIndex`, `useRelation`, `useBatch`, `useUndoRedo`, `useBootstrapStatus`. |
49
+ | `zerodrift/internal` | Engine machinery (`ObjectPool`, `TransactionQueue`, `SyncConnection`, `ModelRegistry`, …) for tooling/tests. **No stability promise** — may change between releases. |
42
50
 
43
51
  ## Define your models
44
52
 
@@ -250,11 +258,11 @@ See [agent-docs/09-headless-and-agents.md](agent-docs/09-headless-and-agents.md)
250
258
 
251
259
  The client needs three endpoints:
252
260
 
253
- | Endpoint | Purpose |
254
- |---|---|
255
- | `GET /api/bootstrap` | Fetch initial or partial model data. |
256
- | `POST /api/transactions` | Accept queued client mutations. |
257
- | `GET /api/events` | Stream delta packets over SSE. |
261
+ | Endpoint | Purpose |
262
+ | ------------------------ | ------------------------------------ |
263
+ | `GET /api/bootstrap` | Fetch initial or partial model data. |
264
+ | `POST /api/transactions` | Accept queued client mutations. |
265
+ | `GET /api/events` | Stream delta packets over SSE. |
258
266
 
259
267
  Bootstrap returns records grouped by model name:
260
268
 
@@ -317,7 +325,7 @@ The client reconnects with `?lastSyncId=<id>` so the server can replay missed ev
317
325
  ## Run the demo
318
326
 
319
327
  A reference Go backend + Next.js app that exercises the full sync loop
320
- locally live in [`examples/`](examples/). See [examples/README.md](examples/README.md)
328
+ locally live in [examples/](examples/). See [examples/README.md](examples/README.md)
321
329
  for the one-command-each setup:
322
330
 
323
331
  ```bash
@@ -13,8 +13,8 @@
13
13
  * - BackRef for @BackReference properties
14
14
  * These are stored on __collections and __backRefs, read by the decorator getters.
15
15
  */
16
- import { type PropertyChange, type IObjectPool, type IStoreManager } from "./types";
17
- import { LazyCollectionBase, BackRef } from "./LazyCollection";
16
+ import { type PropertyChange, type IObjectPool, type IStoreManager } from "./types.js";
17
+ import { LazyCollectionBase, BackRef } from "./LazyCollection.js";
18
18
  import { type IObservableValue } from "mobx";
19
19
  export declare class BaseModel {
20
20
  id: string;
@@ -13,10 +13,10 @@
13
13
  * - BackRef for @BackReference properties
14
14
  * These are stored on __collections and __backRefs, read by the decorator getters.
15
15
  */
16
- import { ModelRegistry } from "./ModelRegistry";
17
- import { PropertyType, DEFAULT_TRANSIENT_INDEX_DEPTH, } from "./types";
18
- import { RefCollection, BackRef } from "./LazyCollection";
19
- import { OwnedRefs } from "./LazyOwnedCollection";
16
+ import { ModelRegistry } from "./ModelRegistry.js";
17
+ import { PropertyType, DEFAULT_TRANSIENT_INDEX_DEPTH, } from "./types.js";
18
+ import { RefCollection, BackRef } from "./LazyCollection.js";
19
+ import { OwnedRefs } from "./LazyOwnedCollection.js";
20
20
  import { action, computed, observable, reaction, runInAction, } from "mobx";
21
21
  // The four PropertyTypes that have MobX boxes and direct setters — the "flat scalar" fields.
22
22
  // Used by makeModelObservable (to create boxes) and assign() (to filter writable keys).
@@ -1,4 +1,4 @@
1
- import { type EngineErrorContext } from "./types";
1
+ import { type EngineErrorContext } from "./types.js";
2
2
  export interface SSEClient {
3
3
  onmessage: ((event: {
4
4
  data: string;
@@ -1,4 +1,4 @@
1
- import { toError } from "./types";
1
+ import { toError } from "./types.js";
2
2
  export const createBrowserSSEFactory = (init) => (url) => new EventSource(url, init);
3
3
  export class BaseSSEConnection {
4
4
  constructor(url, sseClientFactory = createBrowserSSEFactory(), reportError) {
@@ -14,8 +14,8 @@
14
14
  * Adopters without server JOIN support leave the flag unset; the engine
15
15
  * fans out per-parent (existing behavior).
16
16
  */
17
- import type { IndexBatchFetcher, IndexQuery } from "./BatchModelLoader";
18
- import { type ObjectPool } from "./ObjectPool";
17
+ import type { IndexBatchFetcher, IndexQuery } from "./BatchModelLoader.js";
18
+ import { type ObjectPool } from "./ObjectPool.js";
19
19
  /** Switch to a compound fetch only when at least this many pending
20
20
  * requests share a single parent FK value. Below this, the per-parent
21
21
  * fan-out wins because the compound response would over-fetch. */
@@ -14,9 +14,9 @@
14
14
  * Adopters without server JOIN support leave the flag unset; the engine
15
15
  * fans out per-parent (existing behavior).
16
16
  */
17
- import { ModelRegistry } from "./ModelRegistry";
18
- import { readFk } from "./ObjectPool";
19
- import { PropertyType } from "./types";
17
+ import { ModelRegistry } from "./ModelRegistry.js";
18
+ import { readFk } from "./ObjectPool.js";
19
+ import { PropertyType } from "./types.js";
20
20
  /** Switch to a compound fetch only when at least this many pending
21
21
  * requests share a single parent FK value. Below this, the per-parent
22
22
  * fan-out wins because the compound response would over-fetch. */
@@ -15,7 +15,7 @@
15
15
  * - Partial: DB exists with valid data, just need delta since lastSyncId
16
16
  * - Local: DB exists, no server contact needed (offline start)
17
17
  */
18
- import { ModelRegistry } from "./ModelRegistry";
18
+ import { ModelRegistry } from "./ModelRegistry.js";
19
19
  export var BootstrapType;
20
20
  (function (BootstrapType) {
21
21
  BootstrapType["Full"] = "full";
@@ -28,8 +28,8 @@
28
28
  * // or via hook:
29
29
  * const { data, isLoading } = useRelation(team?.issues);
30
30
  */
31
- import type { BaseModel } from "./BaseModel";
32
- import type { CoveringPath } from "./types";
31
+ import type { BaseModel } from "./BaseModel.js";
32
+ import type { CoveringPath } from "./types.js";
33
33
  export declare enum CollectionState {
34
34
  /** Never accessed — hydrate() computed the index values but no load yet. */
35
35
  Idle = "idle",
@@ -29,7 +29,7 @@
29
29
  * const { data, isLoading } = useRelation(team?.issues);
30
30
  */
31
31
  import { observable, runInAction, makeObservable } from "mobx";
32
- import { readFk } from "./ObjectPool";
32
+ import { readFk } from "./ObjectPool.js";
33
33
  /** Walk a `CoveringPath` from `parent` through the pool, returning the
34
34
  * leaf FK value or null if any link is missing. Depth-1 paths are a single
35
35
  * `readFk(parent, hops[0].fk)`. Deeper paths use intermediate
@@ -15,8 +15,8 @@
15
15
  * @OwnedCollection("Issue", { idsField: "issueIds" })
16
16
  * public issues: OwnedRefs<Issue>;
17
17
  */
18
- import type { BaseModel } from "./BaseModel";
19
- import { LazyCollectionBase } from "./LazyCollection";
18
+ import type { BaseModel } from "./BaseModel.js";
19
+ import { LazyCollectionBase } from "./LazyCollection.js";
20
20
  export declare class OwnedRefs<T extends BaseModel = BaseModel> extends LazyCollectionBase<T> {
21
21
  /** Live getter — reads the current IDs array from the parent model each call. */
22
22
  private idsGetter;
@@ -16,7 +16,7 @@
16
16
  * public issues: OwnedRefs<Issue>;
17
17
  */
18
18
  import { runInAction } from "mobx";
19
- import { LazyCollectionBase, CollectionState } from "./LazyCollection";
19
+ import { LazyCollectionBase, CollectionState } from "./LazyCollection.js";
20
20
  export class OwnedRefs extends LazyCollectionBase {
21
21
  constructor(referencedModelName, idsGetter) {
22
22
  super(referencedModelName);
@@ -8,7 +8,7 @@
8
8
  * storage in a server environment, implement StorageAdapter with your own
9
9
  * SQLite / Redis / file-system backend.
10
10
  */
11
- import { BootstrapType, type DatabaseMeta, type PartialIndexEntry, type StorageAdapter, type SyncActionHeader } from "./Database";
11
+ import { BootstrapType, type DatabaseMeta, type PartialIndexEntry, type StorageAdapter, type SyncActionHeader } from "./Database.js";
12
12
  export declare class MemoryAdapter implements StorageAdapter {
13
13
  private meta;
14
14
  private models;
@@ -8,7 +8,7 @@
8
8
  * storage in a server environment, implement StorageAdapter with your own
9
9
  * SQLite / Redis / file-system backend.
10
10
  */
11
- import { BootstrapType, LoadedModelsTracker, diffModelVersions, currentModelVersions, } from "./Database";
11
+ import { BootstrapType, LoadedModelsTracker, diffModelVersions, currentModelVersions, } from "./Database.js";
12
12
  export class MemoryAdapter {
13
13
  constructor() {
14
14
  this.meta = null;
@@ -8,7 +8,7 @@
8
8
  * Also computes a schemaHash — a fingerprint of all models and their properties.
9
9
  * If the hash changes between sessions, the local IndexedDB needs a migration.
10
10
  */
11
- import { type ModelMeta, type PropertyMeta, type CoveringPath } from "./types";
11
+ import { type ModelMeta, type PropertyMeta, type CoveringPath } from "./types.js";
12
12
  declare class ModelRegistryImpl {
13
13
  private models;
14
14
  private cachedHash;
@@ -8,8 +8,8 @@
8
8
  * Also computes a schemaHash — a fingerprint of all models and their properties.
9
9
  * If the hash changes between sessions, the local IndexedDB needs a migration.
10
10
  */
11
- import { hashString } from "./hash";
12
- import { LoadStrategy, PropertyType, } from "./types";
11
+ import { hashString } from "./hash.js";
12
+ import { LoadStrategy, PropertyType, } from "./types.js";
13
13
  class ModelRegistryImpl {
14
14
  constructor() {
15
15
  this.models = new Map();
@@ -3,9 +3,9 @@
3
3
  * Writes to IDB and upserts into the ObjectPool — no sync state management.
4
4
  * Ephemeral models skip IDB and are only held in the pool.
5
5
  */
6
- import type { StorageAdapter } from "./Database";
7
- import { ObjectPool } from "./ObjectPool";
8
- import { BaseSSEConnection, type SSEClientFactory, type SSEErrorReporter } from "./BaseSSEConnection";
6
+ import type { StorageAdapter } from "./Database.js";
7
+ import { ObjectPool } from "./ObjectPool.js";
8
+ import { BaseSSEConnection, type SSEClientFactory, type SSEErrorReporter } from "./BaseSSEConnection.js";
9
9
  export interface ModelUpdate {
10
10
  modelName: string;
11
11
  modelId: string;
@@ -3,9 +3,9 @@
3
3
  * Writes to IDB and upserts into the ObjectPool — no sync state management.
4
4
  * Ephemeral models skip IDB and are only held in the pool.
5
5
  */
6
- import { ModelRegistry } from "./ModelRegistry";
7
- import { BaseSSEConnection, } from "./BaseSSEConnection";
8
- import { LoadStrategy } from "./types";
6
+ import { ModelRegistry } from "./ModelRegistry.js";
7
+ import { BaseSSEConnection, } from "./BaseSSEConnection.js";
8
+ import { LoadStrategy } from "./types.js";
9
9
  export class ModelStream extends BaseSSEConnection {
10
10
  constructor(url, database, pool, onStatusChange, sseClientFactory, transform, reportError) {
11
11
  super(url, sseClientFactory, reportError);
@@ -11,8 +11,8 @@
11
11
  * adds, updates, or removes an instance of that type, all subscribers
12
12
  * are notified and their components re-render.
13
13
  */
14
- import type { BaseModel } from "./BaseModel";
15
- import { type ModelMeta } from "./types";
14
+ import type { BaseModel } from "./BaseModel.js";
15
+ import { type ModelMeta } from "./types.js";
16
16
  type Listener = () => void;
17
17
  /**
18
18
  * Read a dynamic property off a model instance. The single bridge between
@@ -12,8 +12,8 @@
12
12
  * are notified and their components re-render.
13
13
  */
14
14
  import { createAtom, runInAction } from "mobx";
15
- import { ModelRegistry } from "./ModelRegistry";
16
- import { PropertyType } from "./types";
15
+ import { ModelRegistry } from "./ModelRegistry.js";
16
+ import { PropertyType } from "./types.js";
17
17
  /**
18
18
  * Read a dynamic property off a model instance. The single bridge between
19
19
  * the typed `BaseModel` shape and the index-string access we need for
@@ -6,10 +6,10 @@
6
6
  * - PartialStore for partial models (on demand)
7
7
  * - EphemeralStore for ephemeral models (pool-only, never persisted)
8
8
  */
9
- import type { BaseModel } from "./BaseModel";
10
- import type { StorageAdapter } from "./Database";
11
- import { ObjectPool } from "./ObjectPool";
12
- import { type ModelMeta } from "./types";
9
+ import type { BaseModel } from "./BaseModel.js";
10
+ import type { StorageAdapter } from "./Database.js";
11
+ import { ObjectPool } from "./ObjectPool.js";
12
+ import { type ModelMeta } from "./types.js";
13
13
  export declare abstract class ModelStore {
14
14
  protected meta: ModelMeta;
15
15
  protected database: StorageAdapter;
@@ -6,7 +6,7 @@
6
6
  * - PartialStore for partial models (on demand)
7
7
  * - EphemeralStore for ephemeral models (pool-only, never persisted)
8
8
  */
9
- import { LoadStrategy } from "./types";
9
+ import { LoadStrategy } from "./types.js";
10
10
  export class ModelStore {
11
11
  constructor(meta, database, pool) {
12
12
  this.meta = meta;
@@ -18,14 +18,14 @@
18
18
  * storeManager.getOrLoadCollection("Issue", "teamId", teamId)
19
19
  * storeManager.getOrLoadById("DocumentContent", docId)
20
20
  */
21
- import { ObjectPool } from "./ObjectPool";
22
- import { BootstrapType, type StorageAdapter, type DatabaseMeta, type PartialIndexEntry } from "./Database";
23
- import { TransactionQueue, type TransactionSender, type UndoableActionHandlers } from "./TransactionQueue";
24
- import { type DeltaPacket, type SSEClientFactory, type SyncMessageTransform } from "./SyncConnection";
25
- import { type ModelStreamMessageTransform } from "./ModelStream";
26
- import { type IndexBatchFetcher } from "./BatchModelLoader";
27
- import { BaseModel } from "./BaseModel";
28
- import { BootstrapPhase, type ModelMeta, type PropertyMeta, type PropertyChange, type FieldTransform, type EngineErrorContext, type EngineErrorHandler, type CommitRouteHandler, type OnModelTouchedHandler } from "./types";
21
+ import { ObjectPool } from "./ObjectPool.js";
22
+ import { BootstrapType, type StorageAdapter, type DatabaseMeta, type PartialIndexEntry } from "./Database.js";
23
+ import { TransactionQueue, type TransactionSender, type UndoableActionHandlers } from "./TransactionQueue.js";
24
+ import { type DeltaPacket, type SSEClientFactory, type SyncMessageTransform } from "./SyncConnection.js";
25
+ import { type ModelStreamMessageTransform } from "./ModelStream.js";
26
+ import { type IndexBatchFetcher } from "./BatchModelLoader.js";
27
+ import { BaseModel } from "./BaseModel.js";
28
+ import { BootstrapPhase, type ModelMeta, type PropertyMeta, type PropertyChange, type FieldTransform, type EngineErrorContext, type EngineErrorHandler, type CommitRouteHandler, type OnModelTouchedHandler } from "./types.js";
29
29
  /**
30
30
  * Thrown when a delete/archive is blocked by an onDelete: "restrict" relationship.
31
31
  *
@@ -624,8 +624,8 @@ export declare class StoreManager<TContext = unknown> {
624
624
  * draft target's `assign()` doesn't re-trigger a user-facing "first edit".
625
625
  * BaseModel guards on `hasModelTouchedHandler` before calling. */
626
626
  fireModelTouched(model: BaseModel, modelName: string): void;
627
- undo(): Promise<import("./TransactionQueue").UndoResult | null>;
628
- redo(): Promise<import("./TransactionQueue").UndoResult | null>;
627
+ undo(): Promise<import("./TransactionQueue.js").UndoResult | null>;
628
+ redo(): Promise<import("./TransactionQueue.js").UndoResult | null>;
629
629
  /**
630
630
  * Run a remote side-effect that returns a `changeLogId`, and record it on
631
631
  * the undo stack so the next `undo()` invokes the consumer's
@@ -18,18 +18,18 @@
18
18
  * storeManager.getOrLoadCollection("Issue", "teamId", teamId)
19
19
  * storeManager.getOrLoadById("DocumentContent", docId)
20
20
  */
21
- import { ModelRegistry } from "./ModelRegistry";
22
- import { DEFAULT_TRANSIENT_INDEX_DEPTH } from "./types";
23
- import { ObjectPool, prop, readFk } from "./ObjectPool";
24
- import { Database, BootstrapType, } from "./Database";
25
- import { FullStore, PartialStore, EphemeralStore, } from "./Store";
26
- import { TransactionQueue, } from "./TransactionQueue";
27
- import { SyncConnection, encodeCsvList, createBrowserSSEFactory, } from "./SyncConnection";
28
- import { ModelStream } from "./ModelStream";
29
- import { BatchModelLoader } from "./BatchModelLoader";
30
- import { COMPOUND_FETCH_THRESHOLD, wrapCompoundFetcher, } from "./CompoundIndexFetcher";
31
- import { BaseModel } from "./BaseModel";
32
- import { BootstrapPhase, LoadStrategy, PropertyType, toError, } from "./types";
21
+ import { ModelRegistry } from "./ModelRegistry.js";
22
+ import { DEFAULT_TRANSIENT_INDEX_DEPTH } from "./types.js";
23
+ import { ObjectPool, prop, readFk } from "./ObjectPool.js";
24
+ import { Database, BootstrapType, } from "./Database.js";
25
+ import { FullStore, PartialStore, EphemeralStore, } from "./Store.js";
26
+ import { TransactionQueue, } from "./TransactionQueue.js";
27
+ import { SyncConnection, encodeCsvList, createBrowserSSEFactory, } from "./SyncConnection.js";
28
+ import { ModelStream } from "./ModelStream.js";
29
+ import { BatchModelLoader } from "./BatchModelLoader.js";
30
+ import { COMPOUND_FETCH_THRESHOLD, wrapCompoundFetcher, } from "./CompoundIndexFetcher.js";
31
+ import { BaseModel } from "./BaseModel.js";
32
+ import { BootstrapPhase, LoadStrategy, PropertyType, toError, } from "./types.js";
33
33
  /**
34
34
  * Thrown when a delete/archive is blocked by an onDelete: "restrict" relationship.
35
35
  *
@@ -21,11 +21,11 @@
21
21
  * `BaseModel.hydrate` dispatches FK changes for in-pool models. SyncConnection
22
22
  * only has to mutate the pool; parent collections track changes themselves.
23
23
  */
24
- import type { StorageAdapter } from "./Database";
25
- import { ObjectPool } from "./ObjectPool";
26
- import { TransactionQueue } from "./TransactionQueue";
27
- import { BaseSSEConnection, type SSEClientFactory, type SSEErrorReporter } from "./BaseSSEConnection";
28
- export { type SSEClient, type SSEClientFactory, type SSEErrorReporter, createBrowserSSEFactory, } from "./BaseSSEConnection";
24
+ import type { StorageAdapter } from "./Database.js";
25
+ import { ObjectPool } from "./ObjectPool.js";
26
+ import { TransactionQueue } from "./TransactionQueue.js";
27
+ import { BaseSSEConnection, type SSEClientFactory, type SSEErrorReporter } from "./BaseSSEConnection.js";
28
+ export { type SSEClient, type SSEClientFactory, type SSEErrorReporter, createBrowserSSEFactory, } from "./BaseSSEConnection.js";
29
29
  /**
30
30
  * Encode each element then comma-join — the right shape for a list-of-
31
31
  * strings inside a URL query parameter or a stable cache key. Commas
@@ -21,11 +21,11 @@
21
21
  * `BaseModel.hydrate` dispatches FK changes for in-pool models. SyncConnection
22
22
  * only has to mutate the pool; parent collections track changes themselves.
23
23
  */
24
- import { ModelRegistry } from "./ModelRegistry";
25
- import { LoadStrategy, PropertyType } from "./types";
26
- import { BaseSSEConnection, } from "./BaseSSEConnection";
24
+ import { ModelRegistry } from "./ModelRegistry.js";
25
+ import { LoadStrategy, PropertyType } from "./types.js";
26
+ import { BaseSSEConnection, } from "./BaseSSEConnection.js";
27
27
  // Re-export so existing imports from "@zerodrift/SyncConnection" keep working.
28
- export { createBrowserSSEFactory, } from "./BaseSSEConnection";
28
+ export { createBrowserSSEFactory, } from "./BaseSSEConnection.js";
29
29
  /** How many syncIds back to retain in the SyncAction store before pruning.
30
30
  * Covers short offline gaps where a persisted pending tx asks "was my
31
31
  * target deleted while I was away?" on next reconnect. */
@@ -7,8 +7,8 @@
7
7
  * Rebasing (UpdateTransaction): when a delta packet conflicts with our local
8
8
  * change, the server value becomes our new baseline and our value is re-applied.
9
9
  */
10
- import type { BaseModel } from "./BaseModel";
11
- import { TransactionState, type PropertyChange } from "./types";
10
+ import type { BaseModel } from "./BaseModel.js";
11
+ import { TransactionState, type PropertyChange } from "./types.js";
12
12
  export declare abstract class BaseTransaction {
13
13
  readonly id: `${string}-${string}-${string}-${string}-${string}`;
14
14
  readonly modelId: string;
@@ -7,7 +7,7 @@
7
7
  * Rebasing (UpdateTransaction): when a delta packet conflicts with our local
8
8
  * change, the server value becomes our new baseline and our value is re-applied.
9
9
  */
10
- import { TransactionState } from "./types";
10
+ import { TransactionState } from "./types.js";
11
11
  export class BaseTransaction {
12
12
  constructor(modelId, modelName) {
13
13
  this.id = crypto.randomUUID();
@@ -12,12 +12,12 @@
12
12
  *
13
13
  * The undo stack stores "entries" — either a single tx or a batch of txs.
14
14
  */
15
- import type { StorageAdapter } from "./Database";
16
- import { ObjectPool } from "./ObjectPool";
17
- import { type EngineErrorContext } from "./types";
18
- import { BaseTransaction, UpdateTransaction, type UndoableAction } from "./Transaction";
19
- import { type PropertyChange } from "./types";
20
- import type { BaseModel } from "./BaseModel";
15
+ import type { StorageAdapter } from "./Database.js";
16
+ import { ObjectPool } from "./ObjectPool.js";
17
+ import { type EngineErrorContext } from "./types.js";
18
+ import { BaseTransaction, UpdateTransaction, type UndoableAction } from "./Transaction.js";
19
+ import { type PropertyChange } from "./types.js";
20
+ import type { BaseModel } from "./BaseModel.js";
21
21
  export interface BatchResponse {
22
22
  success: boolean;
23
23
  lastSyncId: number;
@@ -12,10 +12,10 @@
12
12
  *
13
13
  * The undo stack stores "entries" — either a single tx or a batch of txs.
14
14
  */
15
- import { ModelRegistry } from "./ModelRegistry";
16
- import { toError } from "./types";
17
- import { BaseTransaction, UpdateTransaction, CreateTransaction, DeleteTransaction, ArchiveTransaction, } from "./Transaction";
18
- import { TransactionState } from "./types";
15
+ import { ModelRegistry } from "./ModelRegistry.js";
16
+ import { toError } from "./types.js";
17
+ import { BaseTransaction, UpdateTransaction, CreateTransaction, DeleteTransaction, ArchiveTransaction, } from "./Transaction.js";
18
+ import { TransactionState } from "./types.js";
19
19
  const isAction = (e) => !(e instanceof BaseTransaction);
20
20
  export class TransactionQueue {
21
21
  constructor(database, pool, undoLimit = 100) {
@@ -15,7 +15,7 @@
15
15
  * time. The engine reads that metadata later for serialization, hydration,
16
16
  * observability, indexing, and reference resolution.
17
17
  */
18
- import { LoadStrategy } from "./types";
18
+ import { LoadStrategy } from "./types.js";
19
19
  export declare function ClientModel(opts?: {
20
20
  /**
21
21
  * The registry name — what `ModelMeta.name` becomes, what
@@ -15,10 +15,10 @@
15
15
  * time. The engine reads that metadata later for serialization, hydration,
16
16
  * observability, indexing, and reference resolution.
17
17
  */
18
- import { ModelRegistry } from "./ModelRegistry";
19
- import { defineObservableProperty } from "./observability";
20
- import { PropertyType, } from "./types";
21
- import { installBackRefAccessor, installCollectionAccessor, installReferenceAccessor, } from "./refAccessors";
18
+ import { ModelRegistry } from "./ModelRegistry.js";
19
+ import { defineObservableProperty } from "./observability.js";
20
+ import { PropertyType, } from "./types.js";
21
+ import { installBackRefAccessor, installCollectionAccessor, installReferenceAccessor, } from "./refAccessors.js";
22
22
  const pendingByClass = new WeakMap();
23
23
  function getOrCreatePending(ctor) {
24
24
  let entry = pendingByClass.get(ctor);
@@ -1,16 +1,16 @@
1
- export { LoadStrategy, PropertyType, BootstrapPhase, TransactionState, } from "./types";
2
- export { dateSerializer, dateDeserializer } from "./serializers";
3
- export type { PropertyMeta, ModelMeta, FieldTransform, PropertyChange, CommitIntent, CommitRouteResult, CommitRouteHandler, OnModelTouchedHandler, OnDelete, EngineErrorContext, EngineErrorHandler, } from "./types";
4
- export { ClientModel, Property, EphemeralProperty, Reference, LazyReference, ReferenceCollection, LazyReferenceCollection, OwnedCollection, LazyOwnedCollection, BackReference, ReferenceArray, Action, Computed, } from "./decorators";
5
- export { BaseModel } from "./BaseModel";
6
- export { RefCollection, BackRef, CollectionState } from "./LazyCollection";
7
- export { OwnedRefs } from "./LazyOwnedCollection";
8
- export { MemoryAdapter } from "./MemoryAdapter";
9
- export { BootstrapType } from "./Database";
10
- export type { DatabaseMeta, StorageAdapter } from "./Database";
11
- export { StoreManager, RestrictDeleteError } from "./StoreManager";
12
- export type { BootstrapResponse, BootstrapFetcher, BootstrapFetcherOptions, FetcherContext, StoreManagerConfig, TransportConfig, LoadingConfig, PersistenceConfig, HooksConfig, AdvancedConfig, OnDemandConfig, OnDemandFetcher, OnDemandBatchFetcher, ModelStreamConfig, } from "./StoreManager";
13
- export type { UndoableAction } from "./Transaction";
14
- export type { TransactionSender, BatchResponse, UndoableActionHandlers, UndoResult, } from "./TransactionQueue";
15
- export type { SyncAction, DeltaPacket, SyncMessageTransform, } from "./SyncConnection";
16
- export type { ModelUpdate, ModelStreamMessageTransform } from "./ModelStream";
1
+ export { LoadStrategy, PropertyType, BootstrapPhase, TransactionState, } from "./types.js";
2
+ export { dateSerializer, dateDeserializer } from "./serializers.js";
3
+ export type { PropertyMeta, ModelMeta, FieldTransform, PropertyChange, CommitIntent, CommitRouteResult, CommitRouteHandler, OnModelTouchedHandler, OnDelete, EngineErrorContext, EngineErrorHandler, } from "./types.js";
4
+ export { ClientModel, Property, EphemeralProperty, Reference, LazyReference, ReferenceCollection, LazyReferenceCollection, OwnedCollection, LazyOwnedCollection, BackReference, ReferenceArray, Action, Computed, } from "./decorators.js";
5
+ export { BaseModel } from "./BaseModel.js";
6
+ export { RefCollection, BackRef, CollectionState } from "./LazyCollection.js";
7
+ export { OwnedRefs } from "./LazyOwnedCollection.js";
8
+ export { MemoryAdapter } from "./MemoryAdapter.js";
9
+ export { BootstrapType } from "./Database.js";
10
+ export type { DatabaseMeta, StorageAdapter } from "./Database.js";
11
+ export { StoreManager, RestrictDeleteError } from "./StoreManager.js";
12
+ export type { BootstrapResponse, BootstrapFetcher, BootstrapFetcherOptions, FetcherContext, StoreManagerConfig, TransportConfig, LoadingConfig, PersistenceConfig, HooksConfig, AdvancedConfig, OnDemandConfig, OnDemandFetcher, OnDemandBatchFetcher, ModelStreamConfig, } from "./StoreManager.js";
13
+ export type { UndoableAction } from "./Transaction.js";
14
+ export type { TransactionSender, BatchResponse, UndoableActionHandlers, UndoResult, } from "./TransactionQueue.js";
15
+ export type { SyncAction, DeltaPacket, SyncMessageTransform, } from "./SyncConnection.js";
16
+ export type { ModelUpdate, ModelStreamMessageTransform } from "./ModelStream.js";
@@ -1,18 +1,18 @@
1
1
  // `zerodrift` — the curated, stable adopter surface. The engine's runtime
2
2
  // machinery lives behind `zerodrift/internal` (see internal.ts).
3
3
  // ── Enums & serializers ────────────────────────────────────────────────────
4
- export { LoadStrategy, PropertyType, BootstrapPhase, TransactionState, } from "./types";
5
- export { dateSerializer, dateDeserializer } from "./serializers";
4
+ export { LoadStrategy, PropertyType, BootstrapPhase, TransactionState, } from "./types.js";
5
+ export { dateSerializer, dateDeserializer } from "./serializers.js";
6
6
  // ── Model definition ───────────────────────────────────────────────────────
7
- export { ClientModel, Property, EphemeralProperty, Reference, LazyReference, ReferenceCollection, LazyReferenceCollection, OwnedCollection, LazyOwnedCollection, BackReference, ReferenceArray, Action, Computed, } from "./decorators";
8
- export { BaseModel } from "./BaseModel";
7
+ export { ClientModel, Property, EphemeralProperty, Reference, LazyReference, ReferenceCollection, LazyReferenceCollection, OwnedCollection, LazyOwnedCollection, BackReference, ReferenceArray, Action, Computed, } from "./decorators.js";
8
+ export { BaseModel } from "./BaseModel.js";
9
9
  // Relation field types — adopters annotate model fields with these
10
10
  // (`public issues: RefCollection<Issue>`), so they stay on the curated
11
11
  // surface even though their construction is engine-internal.
12
- export { RefCollection, BackRef, CollectionState } from "./LazyCollection";
13
- export { OwnedRefs } from "./LazyOwnedCollection";
12
+ export { RefCollection, BackRef, CollectionState } from "./LazyCollection.js";
13
+ export { OwnedRefs } from "./LazyOwnedCollection.js";
14
14
  // ── Storage ────────────────────────────────────────────────────────────────
15
- export { MemoryAdapter } from "./MemoryAdapter";
16
- export { BootstrapType } from "./Database";
15
+ export { MemoryAdapter } from "./MemoryAdapter.js";
16
+ export { BootstrapType } from "./Database.js";
17
17
  // ── Engine ─────────────────────────────────────────────────────────────────
18
- export { StoreManager, RestrictDeleteError } from "./StoreManager";
18
+ export { StoreManager, RestrictDeleteError } from "./StoreManager.js";
@@ -12,16 +12,16 @@
12
12
  * bump. If you find yourself importing from here in app code, that's usually
13
13
  * a sign the curated surface is missing something — open an issue.
14
14
  */
15
- export { ObjectPool } from "./ObjectPool";
16
- export { Database } from "./Database";
17
- export { ModelRegistry } from "./ModelRegistry";
18
- export { defineObservableProperty } from "./observability";
19
- export { FullStore, PartialStore, ModelStore } from "./Store";
20
- export { BaseTransaction, UpdateTransaction, CreateTransaction, DeleteTransaction, ArchiveTransaction, } from "./Transaction";
21
- export { TransactionQueue } from "./TransactionQueue";
22
- export { SyncConnection } from "./SyncConnection";
23
- export { ModelStream } from "./ModelStream";
24
- export { normalizeConfig } from "./StoreManager";
25
- export type { NormalizedConfig } from "./StoreManager";
26
- export type { IObjectPool, IStoreManager, CoveringPath, } from "./types";
27
- export { DEFAULT_TRANSIENT_INDEX_DEPTH, toError } from "./types";
15
+ export { ObjectPool } from "./ObjectPool.js";
16
+ export { Database } from "./Database.js";
17
+ export { ModelRegistry } from "./ModelRegistry.js";
18
+ export { defineObservableProperty } from "./observability.js";
19
+ export { FullStore, PartialStore, ModelStore } from "./Store.js";
20
+ export { BaseTransaction, UpdateTransaction, CreateTransaction, DeleteTransaction, ArchiveTransaction, } from "./Transaction.js";
21
+ export { TransactionQueue } from "./TransactionQueue.js";
22
+ export { SyncConnection } from "./SyncConnection.js";
23
+ export { ModelStream } from "./ModelStream.js";
24
+ export { normalizeConfig } from "./StoreManager.js";
25
+ export type { NormalizedConfig } from "./StoreManager.js";
26
+ export type { IObjectPool, IStoreManager, CoveringPath, } from "./types.js";
27
+ export { DEFAULT_TRANSIENT_INDEX_DEPTH, toError } from "./types.js";
@@ -12,14 +12,14 @@
12
12
  * bump. If you find yourself importing from here in app code, that's usually
13
13
  * a sign the curated surface is missing something — open an issue.
14
14
  */
15
- export { ObjectPool } from "./ObjectPool";
16
- export { Database } from "./Database";
17
- export { ModelRegistry } from "./ModelRegistry";
18
- export { defineObservableProperty } from "./observability";
19
- export { FullStore, PartialStore, ModelStore } from "./Store";
20
- export { BaseTransaction, UpdateTransaction, CreateTransaction, DeleteTransaction, ArchiveTransaction, } from "./Transaction";
21
- export { TransactionQueue } from "./TransactionQueue";
22
- export { SyncConnection } from "./SyncConnection";
23
- export { ModelStream } from "./ModelStream";
24
- export { normalizeConfig } from "./StoreManager";
25
- export { DEFAULT_TRANSIENT_INDEX_DEPTH, toError } from "./types";
15
+ export { ObjectPool } from "./ObjectPool.js";
16
+ export { Database } from "./Database.js";
17
+ export { ModelRegistry } from "./ModelRegistry.js";
18
+ export { defineObservableProperty } from "./observability.js";
19
+ export { FullStore, PartialStore, ModelStore } from "./Store.js";
20
+ export { BaseTransaction, UpdateTransaction, CreateTransaction, DeleteTransaction, ArchiveTransaction, } from "./Transaction.js";
21
+ export { TransactionQueue } from "./TransactionQueue.js";
22
+ export { SyncConnection } from "./SyncConnection.js";
23
+ export { ModelStream } from "./ModelStream.js";
24
+ export { normalizeConfig } from "./StoreManager.js";
25
+ export { DEFAULT_TRANSIENT_INDEX_DEPTH, toError } from "./types.js";
@@ -19,7 +19,7 @@
19
19
  * the raw stored value (for pre-bootstrap access before observability is on).
20
20
  */
21
21
  import { observable } from "mobx";
22
- import { BaseModel } from "./BaseModel";
22
+ import { BaseModel } from "./BaseModel.js";
23
23
  export function defineObservableProperty(target, propName) {
24
24
  // Raw storage key — holds the value before the MobX box is created
25
25
  const rawKey = `__raw_${propName}`;
@@ -1,5 +1,5 @@
1
- import type { IObjectPool } from "./types";
2
- import type { LazyCollectionBase, BackRef } from "./LazyCollection";
1
+ import type { IObjectPool } from "./types.js";
2
+ import type { LazyCollectionBase, BackRef } from "./LazyCollection.js";
3
3
  export interface RefHolder {
4
4
  store: IObjectPool | null;
5
5
  [key: string]: unknown;
@@ -1,4 +1,4 @@
1
- import type { BaseModel } from "./BaseModel";
1
+ import type { BaseModel } from "./BaseModel.js";
2
2
  /** How a model is loaded into the client. Choose by *when* you need its rows. */
3
3
  export declare enum LoadStrategy {
4
4
  /** Loaded during bootstrap, fully resident, kept current by SSE. The
@@ -7,10 +7,10 @@
7
7
  * `useRecordsByIndex` (or a relation via `useRelation`).
8
8
  */
9
9
  import React from "react";
10
- import { StoreManager, type StoreManagerConfig } from "../core/StoreManager";
11
- import { BootstrapPhase } from "../core/types";
12
- import { LazyCollectionBase, BackRef } from "../core/LazyCollection";
13
- import type { BaseModel } from "../core/BaseModel";
10
+ import { StoreManager, type StoreManagerConfig } from "../core/StoreManager.js";
11
+ import { BootstrapPhase } from "../core/types.js";
12
+ import { LazyCollectionBase, BackRef } from "../core/LazyCollection.js";
13
+ import type { BaseModel } from "../core/BaseModel.js";
14
14
  export interface SyncStatus {
15
15
  phase: BootstrapPhase;
16
16
  detail?: string;
@@ -49,17 +49,17 @@ export interface AsyncResource<T> {
49
49
  * the async overload a `Promise<string>`. */
50
50
  export declare function useBatch(): StoreManager["batch"];
51
51
  export declare function useUndoRedo(): {
52
- undo: () => Promise<import("../core").UndoResult | null>;
53
- redo: () => Promise<import("../core").UndoResult | null>;
52
+ undo: () => Promise<import("../core/TransactionQueue.js").UndoResult | null>;
53
+ redo: () => Promise<import("../core/TransactionQueue.js").UndoResult | null>;
54
54
  canUndo: boolean;
55
55
  canRedo: boolean;
56
56
  };
57
57
  export declare function useRelation<T extends BaseModel = BaseModel>(relation: LazyCollectionBase<T> | null | undefined): AsyncResource<T[]>;
58
58
  export declare function useRelation<T extends BaseModel = BaseModel>(relation: BackRef<T> | null | undefined): AsyncResource<T | null>;
59
- import { type EntityNamespace, type RecordWithExtensions } from "../schema/createStore";
60
- import type { ExtensionDescriptor } from "../schema/extend";
61
- import type { EntityKey, IndexedFieldKeys } from "../schema/infer";
62
- import type { SchemaDef } from "../schema/types";
59
+ import { type EntityNamespace, type RecordWithExtensions } from "../schema/createStore.js";
60
+ import type { ExtensionDescriptor } from "../schema/extend.js";
61
+ import type { EntityKey, IndexedFieldKeys } from "../schema/infer.js";
62
+ import type { SchemaDef } from "../schema/types.js";
63
63
  type AnyNamespace = EntityNamespace<any, any, any>;
64
64
  type ModelCtor<T extends BaseModel = BaseModel> = abstract new (...args: any[]) => T;
65
65
  type Handle = AnyNamespace | ModelCtor;
@@ -8,10 +8,10 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
8
8
  * `useRecordsByIndex` (or a relation via `useRelation`).
9
9
  */
10
10
  import { createContext, useContext, useState, useEffect, useCallback, useMemo, useRef, useSyncExternalStore, useLayoutEffect, } from "react";
11
- import { StoreManager } from "../core/StoreManager";
12
- import { BootstrapPhase } from "../core/types";
13
- import { BackRef } from "../core/LazyCollection";
14
- import { readFk } from "../core/ObjectPool";
11
+ import { StoreManager } from "../core/StoreManager.js";
12
+ import { BootstrapPhase } from "../core/types.js";
13
+ import { BackRef } from "../core/LazyCollection.js";
14
+ import { readFk } from "../core/ObjectPool.js";
15
15
  // `<any>` keeps the hooks free of TContext — none of them touch it.
16
16
  const SyncContext = createContext(null);
17
17
  // ---------------------------------------------------------------------------
@@ -344,7 +344,7 @@ function useStableCallback(callback) {
344
344
  // For namespace handles the index key is constrained to the schema's
345
345
  // `.indexed()` fields; for class handles it's `string`.
346
346
  // ---------------------------------------------------------------------------
347
- import { entityNamespaceRegistryName, } from "../schema/createStore";
347
+ import { entityNamespaceRegistryName, } from "../schema/createStore.js";
348
348
  function handleRegistryName(handle) {
349
349
  if (typeof handle === "function") {
350
350
  // Set by @ClientModel (explicit { name } or ctor.name fallback).
@@ -1,4 +1,4 @@
1
- import type { AnyFieldBuilder, AnyLinkDef, EntityDef, FieldBuilder, FieldMeta, LinkDef, SchemaDef } from "./types";
1
+ import type { AnyFieldBuilder, AnyLinkDef, EntityDef, FieldBuilder, FieldMeta, LinkDef, SchemaDef } from "./types.js";
2
2
  export declare function rebuildFieldBuilder<T, M extends FieldMeta>(meta: M): FieldBuilder<T, M>;
3
3
  export declare const fields: {
4
4
  id: () => FieldBuilder<string, FieldMeta & {
@@ -1,4 +1,4 @@
1
- import { dateDeserializer, dateSerializer } from "../core/serializers";
1
+ import { dateDeserializer, dateSerializer } from "../core/serializers.js";
2
2
  function makeBuilder(meta) {
3
3
  return {
4
4
  meta,
@@ -1,4 +1,4 @@
1
- import type { SchemaDef } from "./types";
1
+ import type { SchemaDef } from "./types.js";
2
2
  export interface CompiledSchema {
3
3
  /** Registry names of every entity that was compiled. */
4
4
  modelNames: readonly string[];
@@ -1,9 +1,9 @@
1
- import { BaseModel } from "../core/BaseModel";
2
- import { hashString } from "../core/hash";
3
- import { ModelRegistry } from "../core/ModelRegistry";
4
- import { defineObservableProperty } from "../core/observability";
5
- import { installCollectionAccessor, installReferenceAccessor, } from "../core/refAccessors";
6
- import { PropertyType } from "../core/types";
1
+ import { BaseModel } from "../core/BaseModel.js";
2
+ import { hashString } from "../core/hash.js";
3
+ import { ModelRegistry } from "../core/ModelRegistry.js";
4
+ import { defineObservableProperty } from "../core/observability.js";
5
+ import { installCollectionAccessor, installReferenceAccessor, } from "../core/refAccessors.js";
6
+ import { PropertyType } from "../core/types.js";
7
7
  /**
8
8
  * Compile a `SchemaDef` produced by `defineSchema(...)` into the existing
9
9
  * `ModelRegistry`. Each schema entity becomes a synthetic `BaseModel`
@@ -1,8 +1,8 @@
1
- import type { StoreManager } from "../core/StoreManager";
2
- import type { UndoResult } from "../core/TransactionQueue";
3
- import type { ExtensionDescriptor, MergedExtensionMembers } from "./extend";
4
- import type { EntityKey, IndexedFieldKeys, InferCreateInput, InferEntity, InferUpdateInput } from "./infer";
5
- import type { SchemaDef } from "./types";
1
+ import type { StoreManager } from "../core/StoreManager.js";
2
+ import type { UndoResult } from "../core/TransactionQueue.js";
3
+ import type { ExtensionDescriptor, MergedExtensionMembers } from "./extend.js";
4
+ import type { EntityKey, IndexedFieldKeys, InferCreateInput, InferEntity, InferUpdateInput } from "./infer.js";
5
+ import type { SchemaDef } from "./types.js";
6
6
  /**
7
7
  * Curated subset of `BaseModel` lifecycle methods we expose on records so
8
8
  * imperative "mutate fields then commit" workflows have a typed path. Keeps
@@ -1,8 +1,8 @@
1
1
  import { action, computed } from "mobx";
2
- import { ModelRegistry } from "../core/ModelRegistry";
3
- import { prop } from "../core/ObjectPool";
4
- import { installActionMethod, installComputedAccessor, } from "../core/refAccessors";
5
- import { compileSchema } from "./compile";
2
+ import { ModelRegistry } from "../core/ModelRegistry.js";
3
+ import { prop } from "../core/ObjectPool.js";
4
+ import { installActionMethod, installComputedAccessor, } from "../core/refAccessors.js";
5
+ import { compileSchema } from "./compile.js";
6
6
  /**
7
7
  * Project a `SchemaDef` over a live `StoreManager`. The runtime values are
8
8
  * `BaseModel` instances that structurally satisfy the inferred record type;
@@ -1,5 +1,5 @@
1
- import type { EntityKey, InferEntity } from "./infer";
2
- import type { SchemaDef } from "./types";
1
+ import type { EntityKey, InferEntity } from "./infer.js";
2
+ import type { SchemaDef } from "./types.js";
3
3
  export type ComputedFn<S extends SchemaDef, K extends EntityKey<S>> = (record: InferEntity<S, K>) => unknown;
4
4
  export type ActionFn<S extends SchemaDef, K extends EntityKey<S>> = (record: InferEntity<S, K>, ...args: never[]) => unknown;
5
5
  export interface ExtensionDef<S extends SchemaDef, K extends EntityKey<S>> {
@@ -1,13 +1,13 @@
1
- export { LoadStrategy } from "../core/types";
2
- export { defineSchema, entity, link, fields } from "./builders";
3
- export { fields as s } from "./builders";
4
- export { compileSchema } from "./compile";
5
- export type { CompiledSchema } from "./compile";
6
- export { createStore } from "./createStore";
7
- export type { EntityStore, EntityNamespace, RecordWithExtensions, StoreApi, } from "./createStore";
8
- export { extend } from "./extend";
9
- export type { ActionFn, ComputedFn, ExtensionDef, ExtensionDescriptor, ExtensionMap, MergedExtensionMembers, } from "./extend";
10
- export { fromZod, entityFromZod } from "./zod";
11
- export type { EntityFromZodFieldOverride, EntityFromZodOpts } from "./zod";
12
- export type { EntityDef, FieldBuilder, FieldKind, FieldMeta, LinkDef, LinkFromSpec, LinkToSpec, OnDelete, SchemaDef, } from "./types";
13
- export type { EntityKey, IndexedFieldKeys, InferCreateInput, InferEntity, InferUpdateInput, RelationCollection, } from "./infer";
1
+ export { LoadStrategy } from "../core/types.js";
2
+ export { defineSchema, entity, link, fields } from "./builders.js";
3
+ export { fields as s } from "./builders.js";
4
+ export { compileSchema } from "./compile.js";
5
+ export type { CompiledSchema } from "./compile.js";
6
+ export { createStore } from "./createStore.js";
7
+ export type { EntityStore, EntityNamespace, RecordWithExtensions, StoreApi, } from "./createStore.js";
8
+ export { extend } from "./extend.js";
9
+ export type { ActionFn, ComputedFn, ExtensionDef, ExtensionDescriptor, ExtensionMap, MergedExtensionMembers, } from "./extend.js";
10
+ export { fromZod, entityFromZod } from "./zod.js";
11
+ export type { EntityFromZodFieldOverride, EntityFromZodOpts } from "./zod.js";
12
+ export type { EntityDef, FieldBuilder, FieldKind, FieldMeta, LinkDef, LinkFromSpec, LinkToSpec, OnDelete, SchemaDef, } from "./types.js";
13
+ export type { EntityKey, IndexedFieldKeys, InferCreateInput, InferEntity, InferUpdateInput, RelationCollection, } from "./infer.js";
@@ -1,8 +1,8 @@
1
1
  // Public schema-authoring surface. See agent-docs/RFC-schema-first-authoring.md.
2
- export { LoadStrategy } from "../core/types";
3
- export { defineSchema, entity, link, fields } from "./builders";
4
- export { fields as s } from "./builders";
5
- export { compileSchema } from "./compile";
6
- export { createStore } from "./createStore";
7
- export { extend } from "./extend";
8
- export { fromZod, entityFromZod } from "./zod";
2
+ export { LoadStrategy } from "../core/types.js";
3
+ export { defineSchema, entity, link, fields } from "./builders.js";
4
+ export { fields as s } from "./builders.js";
5
+ export { compileSchema } from "./compile.js";
6
+ export { createStore } from "./createStore.js";
7
+ export { extend } from "./extend.js";
8
+ export { fromZod, entityFromZod } from "./zod.js";
@@ -1,4 +1,4 @@
1
- import type { EntityDef, FieldBuilder, FieldMeta, SchemaDef } from "./types";
1
+ import type { EntityDef, FieldBuilder, FieldMeta, SchemaDef } from "./types.js";
2
2
  type FieldType<F> = F extends FieldBuilder<infer T, FieldMeta> ? T : never;
3
3
  type FieldIsNullable<F> = null extends FieldType<F> ? true : false;
4
4
  type FieldIsIndexed<F> = F extends FieldBuilder<unknown, infer M> ? M extends {
@@ -1,4 +1,4 @@
1
- import type { LoadStrategy, OnDelete } from "../core/types";
1
+ import type { LoadStrategy, OnDelete } from "../core/types.js";
2
2
  export type FieldKind = "id" | "string" | "number" | "boolean" | "date" | "json" | "refId";
3
3
  export interface FieldMeta {
4
4
  kind: FieldKind;
@@ -1,5 +1,5 @@
1
1
  import type { z } from "zod";
2
- import type { AnyFieldBuilder, EntityDef, FieldBuilder } from "./types";
2
+ import type { AnyFieldBuilder, EntityDef, FieldBuilder } from "./types.js";
3
3
  /**
4
4
  * Convert any Zod schema into the equivalent schema-first `FieldBuilder`.
5
5
  * Handles the common nullable / optional / default modifiers; anything more
@@ -1,4 +1,4 @@
1
- import { fields, entity, rebuildFieldBuilder } from "./builders";
1
+ import { fields, entity, rebuildFieldBuilder } from "./builders.js";
2
2
  const PRIMITIVE_KIND = new Map([
3
3
  ["string", fields.string],
4
4
  ["number", fields.number],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zerodrift",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "private": false,
5
5
  "description": "A TypeScript local-first sync engine: synchronous in-memory reads, optimistic writes, realtime SSE sync, offline IndexedDB persistence. Runs in the browser and in Node.",
6
6
  "license": "MIT",