@monlite/core 0.6.0 → 0.8.0

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.
package/dist/index.d.cts CHANGED
@@ -49,6 +49,38 @@ interface ColumnInfo {
49
49
  notNull: boolean;
50
50
  primaryKey: boolean;
51
51
  }
52
+ /** An update delivered to a `watch()` subscriber. */
53
+ interface LiveEvent<T = Doc> {
54
+ /** `"init"` is the first delivery; `"change"` for every update after. */
55
+ type: "init" | "change";
56
+ /** The full current result set. */
57
+ results: WithId<T>[];
58
+ /** Documents that entered the result set since the last event. */
59
+ added: WithId<T>[];
60
+ /** Documents that left the result set. */
61
+ removed: WithId<T>[];
62
+ /** Documents still in the set whose contents changed. */
63
+ changed: WithId<T>[];
64
+ }
65
+ /** Handle returned by `collection.watch()`. */
66
+ interface WatchHandle<T = Doc> {
67
+ /** The current result set (kept up to date). */
68
+ readonly results: WithId<T>[];
69
+ /** Stop receiving updates. */
70
+ stop(): void;
71
+ }
72
+ /** Result of `collection.explain()`. */
73
+ interface ExplainResult {
74
+ sql: string;
75
+ /** Whether SQLite's planner uses an index (vs a full scan). */
76
+ usesIndex: boolean;
77
+ /** Raw EXPLAIN QUERY PLAN rows. */
78
+ plan: Array<{
79
+ id: number;
80
+ parent: number;
81
+ detail: string;
82
+ }>;
83
+ }
52
84
  /** Per-field operators, Prisma-style (no `$` prefix). */
53
85
  interface FieldFilter<V = any> {
54
86
  equals?: V | null;
@@ -257,6 +289,9 @@ declare class Collection<T = Doc> {
257
289
  /** Native column names declared for this collection (structured mode). */
258
290
  get columnNames(): string[];
259
291
  private ensureTable;
292
+ private columnDdl;
293
+ /** Auto-additive migration: add declared columns missing from an existing table. */
294
+ private migrateColumns;
260
295
  private rowToDoc;
261
296
  private encodeColumn;
262
297
  private insertColumns;
@@ -265,12 +300,28 @@ declare class Collection<T = Doc> {
265
300
  private buildInsert;
266
301
  /** Build the `SET` clause + values to persist an updated document. */
267
302
  private buildUpdateSet;
268
- /** Sync store, but only for document collections (structured sync is future work). */
303
+ /** Sync store for recording local changes (both document and structured). */
269
304
  private get recorder();
305
+ /** @internal Read a full document by id (mode-aware), synchronously. */
306
+ getRaw(id: string): WithId<T> | null;
307
+ /**
308
+ * @internal Apply a remote change to storage WITHOUT recording it to the
309
+ * change feed (the sync store records the `remote` feed row itself). Used by
310
+ * `@monlite/sync` so structured collections sync correctly through the same
311
+ * column/overflow split as local writes.
312
+ */
313
+ applyRemoteWrite(op: "upsert" | "delete", id: string, doc: Record<string, any> | undefined, ts: number): void;
314
+ /** @internal Notify reactivity watchers that documents changed. */
315
+ private afterWrite;
270
316
  create(args: CreateArgs<T>): Promise<WithId<T>>;
271
317
  createMany(args: CreateManyArgs<T>): Promise<{
272
318
  count: number;
273
319
  }>;
320
+ private buildFindSql;
321
+ /** @internal Synchronous core of findMany (used by reactivity). */
322
+ findManyCore(args?: FindManyArgs<T>): WithId<T>[];
323
+ /** @internal Synchronous core of exists (used by reactivity). */
324
+ existsCore(where: WhereInput<T> | undefined): boolean;
274
325
  findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
275
326
  findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
276
327
  /** Alias of {@link findFirst} for Prisma familiarity. */
@@ -279,6 +330,15 @@ declare class Collection<T = Doc> {
279
330
  findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
280
331
  /** True if at least one document matches. */
281
332
  exists(where?: WhereInput<T>): Promise<boolean>;
333
+ /**
334
+ * Subscribe to a live query. The callback fires immediately with the current
335
+ * results (`type: "init"`) and again whenever a change affects the result set
336
+ * (row-level: only relevant changes trigger a recompute). Includes changes
337
+ * applied by `@monlite/sync`.
338
+ */
339
+ watch(args: FindManyArgs<T> | undefined, cb: (event: LiveEvent<T>) => void): WatchHandle<T>;
340
+ /** Show SQLite's query plan for a `findMany`, and whether it uses an index. */
341
+ explain(args?: FindManyArgs<T>): Promise<ExplainResult>;
282
342
  findById(id: string): Promise<WithId<T> | null>;
283
343
  count(args?: CountArgs<T>): Promise<number>;
284
344
  /**
@@ -421,9 +481,10 @@ interface ConflictRow {
421
481
  */
422
482
  declare class SyncStore {
423
483
  private readonly db;
484
+ private readonly mon?;
424
485
  readonly nodeId: string;
425
486
  private versionSeq;
426
- constructor(db: Driver, nodeId?: string);
487
+ constructor(db: Driver, nodeId?: string, mon?: Monlite | undefined);
427
488
  private init;
428
489
  private resolveNodeId;
429
490
  /** True if this database tracks sync metadata (always, once constructed). */
@@ -462,9 +523,50 @@ declare class SyncStore {
462
523
  private recordConflict;
463
524
  conflicts(): ConflictRow[];
464
525
  private readDoc;
526
+ private tableExists;
465
527
  private ensureCollTable;
466
528
  }
467
529
 
530
+ /** Minimal query surface a {@link LiveQuery} needs (satisfied by Collection). */
531
+ interface Queryable<T> {
532
+ readonly name: string;
533
+ findManyCore(args: FindManyArgs<T>): WithId<T>[];
534
+ existsCore(where: WhereInput<T> | undefined): boolean;
535
+ }
536
+ /**
537
+ * A live query. Holds the current result set and recomputes only when a changed
538
+ * row is actually relevant to it (row-level matching): either the row is already
539
+ * in the result set, or it now matches the filter.
540
+ */
541
+ declare class LiveQuery<T = Doc> {
542
+ private readonly source;
543
+ private readonly args;
544
+ private readonly cb;
545
+ results: WithId<T>[];
546
+ stopped: boolean;
547
+ private ids;
548
+ constructor(source: Queryable<T>, args: FindManyArgs<T>, cb: (event: LiveEvent<T>) => void);
549
+ /** Called by the Reactor with the ids that changed this tick. */
550
+ notify(changedIds: Set<string>): void;
551
+ private isRelevant;
552
+ private recompute;
553
+ }
554
+ /**
555
+ * In-process reactivity hub. Collections emit `(collection, ids)` after each
556
+ * write; the reactor coalesces them per microtask and notifies live queries.
557
+ */
558
+ declare class Reactor {
559
+ private readonly byCollection;
560
+ private readonly pending;
561
+ private flushScheduled;
562
+ hasWatchers(collection: string): boolean;
563
+ register(collection: string, lq: LiveQuery<any>): void;
564
+ unregister(collection: string, lq: LiveQuery<any>): void;
565
+ /** Record that documents changed; schedule a notification flush. */
566
+ emit(collection: string, ids: string[]): void;
567
+ private flush;
568
+ }
569
+
468
570
  /**
469
571
  * A monlite database — a thin document layer over a single SQLite file.
470
572
  * Create one with {@link createDb}.
@@ -474,6 +576,8 @@ declare class Monlite {
474
576
  readonly driver: Driver;
475
577
  /** @internal */
476
578
  readonly autoIndexer: AutoIndexer;
579
+ /** @internal Reactivity hub for `collection.watch()`. */
580
+ readonly reactor: Reactor;
477
581
  /** @internal Sync metadata store; present only when `{ sync: true }`. */
478
582
  readonly $sync?: SyncStore;
479
583
  private readonly collections;
@@ -512,6 +616,11 @@ declare class Monlite {
512
616
  $drop(name: string): Promise<void>;
513
617
  /** Drop every collection in the database. */
514
618
  $dropAll(): Promise<void>;
619
+ /**
620
+ * Write a consistent on-disk snapshot of the database to `path` (via
621
+ * `VACUUM INTO`). The destination file must not already exist.
622
+ */
623
+ backup(path: string): Promise<void>;
515
624
  /** Close the underlying SQLite connection. */
516
625
  $disconnect(): Promise<void>;
517
626
  private assertOpen;
@@ -574,4 +683,4 @@ declare function objectId(): string;
574
683
  /** True when a value looks like a monlite/ObjectId id (24 hex chars). */
575
684
  declare function isObjectId(value: unknown): value is string;
576
685
 
577
- export { type AggregateArgs, type AggregateResult, type ApplyResult, Collection, type CollectionMode, type CollectionOptions, type CollectionSchema, type ColumnDef, type ColumnInfo, type ColumnType, type ConflictResolver, type ConflictRow, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, type HavingComparison, type HavingInput, type LocalChange, Monlite, MonliteConstraintError, MonliteError, MonliteForeignKeyError, MonliteNotNullError, type MonliteOptions, MonliteQueryError, MonliteUniqueConstraintError, type OrderBy, type PreparedStatement, type RemoteChange, type Select, type SortOrder, type SyncOp, type SyncStateRow, SyncStore, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type Version, type WhereInput as WhereClause, type WhereInput, type WithId, compareVersions, createDb, isObjectId, makeVersion, normalizeDriverError, objectId, versionTs };
686
+ export { type AggregateArgs, type AggregateResult, type ApplyResult, Collection, type CollectionMode, type CollectionOptions, type CollectionSchema, type ColumnDef, type ColumnInfo, type ColumnType, type ConflictResolver, type ConflictRow, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type ExplainResult, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, type HavingComparison, type HavingInput, type LiveEvent, type LocalChange, Monlite, MonliteConstraintError, MonliteError, MonliteForeignKeyError, MonliteNotNullError, type MonliteOptions, MonliteQueryError, MonliteUniqueConstraintError, type OrderBy, type PreparedStatement, type RemoteChange, type Select, type SortOrder, type SyncOp, type SyncStateRow, SyncStore, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type Version, type WatchHandle, type WhereInput as WhereClause, type WhereInput, type WithId, compareVersions, createDb, isObjectId, makeVersion, normalizeDriverError, objectId, versionTs };
package/dist/index.d.ts CHANGED
@@ -49,6 +49,38 @@ interface ColumnInfo {
49
49
  notNull: boolean;
50
50
  primaryKey: boolean;
51
51
  }
52
+ /** An update delivered to a `watch()` subscriber. */
53
+ interface LiveEvent<T = Doc> {
54
+ /** `"init"` is the first delivery; `"change"` for every update after. */
55
+ type: "init" | "change";
56
+ /** The full current result set. */
57
+ results: WithId<T>[];
58
+ /** Documents that entered the result set since the last event. */
59
+ added: WithId<T>[];
60
+ /** Documents that left the result set. */
61
+ removed: WithId<T>[];
62
+ /** Documents still in the set whose contents changed. */
63
+ changed: WithId<T>[];
64
+ }
65
+ /** Handle returned by `collection.watch()`. */
66
+ interface WatchHandle<T = Doc> {
67
+ /** The current result set (kept up to date). */
68
+ readonly results: WithId<T>[];
69
+ /** Stop receiving updates. */
70
+ stop(): void;
71
+ }
72
+ /** Result of `collection.explain()`. */
73
+ interface ExplainResult {
74
+ sql: string;
75
+ /** Whether SQLite's planner uses an index (vs a full scan). */
76
+ usesIndex: boolean;
77
+ /** Raw EXPLAIN QUERY PLAN rows. */
78
+ plan: Array<{
79
+ id: number;
80
+ parent: number;
81
+ detail: string;
82
+ }>;
83
+ }
52
84
  /** Per-field operators, Prisma-style (no `$` prefix). */
53
85
  interface FieldFilter<V = any> {
54
86
  equals?: V | null;
@@ -257,6 +289,9 @@ declare class Collection<T = Doc> {
257
289
  /** Native column names declared for this collection (structured mode). */
258
290
  get columnNames(): string[];
259
291
  private ensureTable;
292
+ private columnDdl;
293
+ /** Auto-additive migration: add declared columns missing from an existing table. */
294
+ private migrateColumns;
260
295
  private rowToDoc;
261
296
  private encodeColumn;
262
297
  private insertColumns;
@@ -265,12 +300,28 @@ declare class Collection<T = Doc> {
265
300
  private buildInsert;
266
301
  /** Build the `SET` clause + values to persist an updated document. */
267
302
  private buildUpdateSet;
268
- /** Sync store, but only for document collections (structured sync is future work). */
303
+ /** Sync store for recording local changes (both document and structured). */
269
304
  private get recorder();
305
+ /** @internal Read a full document by id (mode-aware), synchronously. */
306
+ getRaw(id: string): WithId<T> | null;
307
+ /**
308
+ * @internal Apply a remote change to storage WITHOUT recording it to the
309
+ * change feed (the sync store records the `remote` feed row itself). Used by
310
+ * `@monlite/sync` so structured collections sync correctly through the same
311
+ * column/overflow split as local writes.
312
+ */
313
+ applyRemoteWrite(op: "upsert" | "delete", id: string, doc: Record<string, any> | undefined, ts: number): void;
314
+ /** @internal Notify reactivity watchers that documents changed. */
315
+ private afterWrite;
270
316
  create(args: CreateArgs<T>): Promise<WithId<T>>;
271
317
  createMany(args: CreateManyArgs<T>): Promise<{
272
318
  count: number;
273
319
  }>;
320
+ private buildFindSql;
321
+ /** @internal Synchronous core of findMany (used by reactivity). */
322
+ findManyCore(args?: FindManyArgs<T>): WithId<T>[];
323
+ /** @internal Synchronous core of exists (used by reactivity). */
324
+ existsCore(where: WhereInput<T> | undefined): boolean;
274
325
  findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
275
326
  findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
276
327
  /** Alias of {@link findFirst} for Prisma familiarity. */
@@ -279,6 +330,15 @@ declare class Collection<T = Doc> {
279
330
  findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
280
331
  /** True if at least one document matches. */
281
332
  exists(where?: WhereInput<T>): Promise<boolean>;
333
+ /**
334
+ * Subscribe to a live query. The callback fires immediately with the current
335
+ * results (`type: "init"`) and again whenever a change affects the result set
336
+ * (row-level: only relevant changes trigger a recompute). Includes changes
337
+ * applied by `@monlite/sync`.
338
+ */
339
+ watch(args: FindManyArgs<T> | undefined, cb: (event: LiveEvent<T>) => void): WatchHandle<T>;
340
+ /** Show SQLite's query plan for a `findMany`, and whether it uses an index. */
341
+ explain(args?: FindManyArgs<T>): Promise<ExplainResult>;
282
342
  findById(id: string): Promise<WithId<T> | null>;
283
343
  count(args?: CountArgs<T>): Promise<number>;
284
344
  /**
@@ -421,9 +481,10 @@ interface ConflictRow {
421
481
  */
422
482
  declare class SyncStore {
423
483
  private readonly db;
484
+ private readonly mon?;
424
485
  readonly nodeId: string;
425
486
  private versionSeq;
426
- constructor(db: Driver, nodeId?: string);
487
+ constructor(db: Driver, nodeId?: string, mon?: Monlite | undefined);
427
488
  private init;
428
489
  private resolveNodeId;
429
490
  /** True if this database tracks sync metadata (always, once constructed). */
@@ -462,9 +523,50 @@ declare class SyncStore {
462
523
  private recordConflict;
463
524
  conflicts(): ConflictRow[];
464
525
  private readDoc;
526
+ private tableExists;
465
527
  private ensureCollTable;
466
528
  }
467
529
 
530
+ /** Minimal query surface a {@link LiveQuery} needs (satisfied by Collection). */
531
+ interface Queryable<T> {
532
+ readonly name: string;
533
+ findManyCore(args: FindManyArgs<T>): WithId<T>[];
534
+ existsCore(where: WhereInput<T> | undefined): boolean;
535
+ }
536
+ /**
537
+ * A live query. Holds the current result set and recomputes only when a changed
538
+ * row is actually relevant to it (row-level matching): either the row is already
539
+ * in the result set, or it now matches the filter.
540
+ */
541
+ declare class LiveQuery<T = Doc> {
542
+ private readonly source;
543
+ private readonly args;
544
+ private readonly cb;
545
+ results: WithId<T>[];
546
+ stopped: boolean;
547
+ private ids;
548
+ constructor(source: Queryable<T>, args: FindManyArgs<T>, cb: (event: LiveEvent<T>) => void);
549
+ /** Called by the Reactor with the ids that changed this tick. */
550
+ notify(changedIds: Set<string>): void;
551
+ private isRelevant;
552
+ private recompute;
553
+ }
554
+ /**
555
+ * In-process reactivity hub. Collections emit `(collection, ids)` after each
556
+ * write; the reactor coalesces them per microtask and notifies live queries.
557
+ */
558
+ declare class Reactor {
559
+ private readonly byCollection;
560
+ private readonly pending;
561
+ private flushScheduled;
562
+ hasWatchers(collection: string): boolean;
563
+ register(collection: string, lq: LiveQuery<any>): void;
564
+ unregister(collection: string, lq: LiveQuery<any>): void;
565
+ /** Record that documents changed; schedule a notification flush. */
566
+ emit(collection: string, ids: string[]): void;
567
+ private flush;
568
+ }
569
+
468
570
  /**
469
571
  * A monlite database — a thin document layer over a single SQLite file.
470
572
  * Create one with {@link createDb}.
@@ -474,6 +576,8 @@ declare class Monlite {
474
576
  readonly driver: Driver;
475
577
  /** @internal */
476
578
  readonly autoIndexer: AutoIndexer;
579
+ /** @internal Reactivity hub for `collection.watch()`. */
580
+ readonly reactor: Reactor;
477
581
  /** @internal Sync metadata store; present only when `{ sync: true }`. */
478
582
  readonly $sync?: SyncStore;
479
583
  private readonly collections;
@@ -512,6 +616,11 @@ declare class Monlite {
512
616
  $drop(name: string): Promise<void>;
513
617
  /** Drop every collection in the database. */
514
618
  $dropAll(): Promise<void>;
619
+ /**
620
+ * Write a consistent on-disk snapshot of the database to `path` (via
621
+ * `VACUUM INTO`). The destination file must not already exist.
622
+ */
623
+ backup(path: string): Promise<void>;
515
624
  /** Close the underlying SQLite connection. */
516
625
  $disconnect(): Promise<void>;
517
626
  private assertOpen;
@@ -574,4 +683,4 @@ declare function objectId(): string;
574
683
  /** True when a value looks like a monlite/ObjectId id (24 hex chars). */
575
684
  declare function isObjectId(value: unknown): value is string;
576
685
 
577
- export { type AggregateArgs, type AggregateResult, type ApplyResult, Collection, type CollectionMode, type CollectionOptions, type CollectionSchema, type ColumnDef, type ColumnInfo, type ColumnType, type ConflictResolver, type ConflictRow, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, type HavingComparison, type HavingInput, type LocalChange, Monlite, MonliteConstraintError, MonliteError, MonliteForeignKeyError, MonliteNotNullError, type MonliteOptions, MonliteQueryError, MonliteUniqueConstraintError, type OrderBy, type PreparedStatement, type RemoteChange, type Select, type SortOrder, type SyncOp, type SyncStateRow, SyncStore, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type Version, type WhereInput as WhereClause, type WhereInput, type WithId, compareVersions, createDb, isObjectId, makeVersion, normalizeDriverError, objectId, versionTs };
686
+ export { type AggregateArgs, type AggregateResult, type ApplyResult, Collection, type CollectionMode, type CollectionOptions, type CollectionSchema, type ColumnDef, type ColumnInfo, type ColumnType, type ConflictResolver, type ConflictRow, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type ExplainResult, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, type HavingComparison, type HavingInput, type LiveEvent, type LocalChange, Monlite, MonliteConstraintError, MonliteError, MonliteForeignKeyError, MonliteNotNullError, type MonliteOptions, MonliteQueryError, MonliteUniqueConstraintError, type OrderBy, type PreparedStatement, type RemoteChange, type Select, type SortOrder, type SyncOp, type SyncStateRow, SyncStore, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type Version, type WatchHandle, type WhereInput as WhereClause, type WhereInput, type WithId, compareVersions, createDb, isObjectId, makeVersion, normalizeDriverError, objectId, versionTs };