@monlite/core 0.7.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;
@@ -276,10 +311,17 @@ declare class Collection<T = Doc> {
276
311
  * column/overflow split as local writes.
277
312
  */
278
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;
279
316
  create(args: CreateArgs<T>): Promise<WithId<T>>;
280
317
  createMany(args: CreateManyArgs<T>): Promise<{
281
318
  count: number;
282
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;
283
325
  findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
284
326
  findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
285
327
  /** Alias of {@link findFirst} for Prisma familiarity. */
@@ -288,6 +330,15 @@ declare class Collection<T = Doc> {
288
330
  findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
289
331
  /** True if at least one document matches. */
290
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>;
291
342
  findById(id: string): Promise<WithId<T> | null>;
292
343
  count(args?: CountArgs<T>): Promise<number>;
293
344
  /**
@@ -476,6 +527,46 @@ declare class SyncStore {
476
527
  private ensureCollTable;
477
528
  }
478
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
+
479
570
  /**
480
571
  * A monlite database — a thin document layer over a single SQLite file.
481
572
  * Create one with {@link createDb}.
@@ -485,6 +576,8 @@ declare class Monlite {
485
576
  readonly driver: Driver;
486
577
  /** @internal */
487
578
  readonly autoIndexer: AutoIndexer;
579
+ /** @internal Reactivity hub for `collection.watch()`. */
580
+ readonly reactor: Reactor;
488
581
  /** @internal Sync metadata store; present only when `{ sync: true }`. */
489
582
  readonly $sync?: SyncStore;
490
583
  private readonly collections;
@@ -523,6 +616,11 @@ declare class Monlite {
523
616
  $drop(name: string): Promise<void>;
524
617
  /** Drop every collection in the database. */
525
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>;
526
624
  /** Close the underlying SQLite connection. */
527
625
  $disconnect(): Promise<void>;
528
626
  private assertOpen;
@@ -585,4 +683,4 @@ declare function objectId(): string;
585
683
  /** True when a value looks like a monlite/ObjectId id (24 hex chars). */
586
684
  declare function isObjectId(value: unknown): value is string;
587
685
 
588
- 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;
@@ -276,10 +311,17 @@ declare class Collection<T = Doc> {
276
311
  * column/overflow split as local writes.
277
312
  */
278
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;
279
316
  create(args: CreateArgs<T>): Promise<WithId<T>>;
280
317
  createMany(args: CreateManyArgs<T>): Promise<{
281
318
  count: number;
282
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;
283
325
  findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
284
326
  findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
285
327
  /** Alias of {@link findFirst} for Prisma familiarity. */
@@ -288,6 +330,15 @@ declare class Collection<T = Doc> {
288
330
  findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
289
331
  /** True if at least one document matches. */
290
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>;
291
342
  findById(id: string): Promise<WithId<T> | null>;
292
343
  count(args?: CountArgs<T>): Promise<number>;
293
344
  /**
@@ -476,6 +527,46 @@ declare class SyncStore {
476
527
  private ensureCollTable;
477
528
  }
478
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
+
479
570
  /**
480
571
  * A monlite database — a thin document layer over a single SQLite file.
481
572
  * Create one with {@link createDb}.
@@ -485,6 +576,8 @@ declare class Monlite {
485
576
  readonly driver: Driver;
486
577
  /** @internal */
487
578
  readonly autoIndexer: AutoIndexer;
579
+ /** @internal Reactivity hub for `collection.watch()`. */
580
+ readonly reactor: Reactor;
488
581
  /** @internal Sync metadata store; present only when `{ sync: true }`. */
489
582
  readonly $sync?: SyncStore;
490
583
  private readonly collections;
@@ -523,6 +616,11 @@ declare class Monlite {
523
616
  $drop(name: string): Promise<void>;
524
617
  /** Drop every collection in the database. */
525
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>;
526
624
  /** Close the underlying SQLite connection. */
527
625
  $disconnect(): Promise<void>;
528
626
  private assertOpen;
@@ -585,4 +683,4 @@ declare function objectId(): string;
585
683
  /** True when a value looks like a monlite/ObjectId id (24 hex chars). */
586
684
  declare function isObjectId(value: unknown): value is string;
587
685
 
588
- 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 };