@monlite/core 0.8.0 → 0.9.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
@@ -1,9 +1,134 @@
1
+ /**
2
+ * A collection. In **document** mode (default) every document is stored as JSON
3
+ * in a `data` column — schema-free. In **structured** mode (when a `schema` is
4
+ * given) the listed fields become real, typed SQL columns (fast, indexable,
5
+ * joinable) while any other fields overflow into a JSON `data` column. The CRUD
6
+ * and query API is identical in both modes.
7
+ */
8
+ declare class Collection<T = Doc> {
9
+ private readonly mon;
10
+ readonly name: string;
11
+ readonly mode: CollectionMode;
12
+ private initialized;
13
+ private readonly columnDefs;
14
+ private readonly columnOrder;
15
+ /** Declared native columns (empty in document mode). */
16
+ private readonly columns;
17
+ private readonly jsonColumns;
18
+ private insertSqlCache?;
19
+ private readonly trackPath;
20
+ constructor(mon: Monlite, name: string, options?: CollectionOptions);
21
+ private get db();
22
+ /** Run a DB operation, normalizing driver errors into typed MonliteErrors. */
23
+ private guard;
24
+ /** Native column names declared for this collection (structured mode). */
25
+ get columnNames(): string[];
26
+ private ensureTable;
27
+ private columnDdl;
28
+ /** Auto-additive migration: add declared columns missing from an existing table. */
29
+ private migrateColumns;
30
+ private rowToDoc;
31
+ private encodeColumn;
32
+ private insertColumns;
33
+ private insertSql;
34
+ /** Split an input document into a row aligned with `insertColumns()`. */
35
+ private buildInsert;
36
+ /** Build the `SET` clause + values to persist an updated document. */
37
+ private buildUpdateSet;
38
+ /** Sync store for recording local changes (both document and structured). */
39
+ private get recorder();
40
+ /** @internal Read a full document by id (mode-aware), synchronously. */
41
+ getRaw(id: string): WithId<T> | null;
42
+ /**
43
+ * @internal Apply a remote change to storage WITHOUT recording it to the
44
+ * change feed (the sync store records the `remote` feed row itself). Used by
45
+ * `@monlite/sync` so structured collections sync correctly through the same
46
+ * column/overflow split as local writes.
47
+ */
48
+ applyRemoteWrite(op: "upsert" | "delete", id: string, doc: Record<string, any> | undefined, ts: number): void;
49
+ /** @internal Notify reactivity watchers and plugins that documents changed. */
50
+ private afterWrite;
51
+ create(args: CreateArgs<T>): Promise<WithId<T>>;
52
+ createMany(args: CreateManyArgs<T>): Promise<{
53
+ count: number;
54
+ }>;
55
+ private buildFindSql;
56
+ /** @internal Synchronous core of findMany (used by reactivity). */
57
+ findManyCore(args?: FindManyArgs<T>): WithId<T>[];
58
+ /** @internal Synchronous core of exists (used by reactivity). */
59
+ existsCore(where: WhereInput<T> | undefined): boolean;
60
+ findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
61
+ findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
62
+ /** Alias of {@link findFirst} for Prisma familiarity. */
63
+ findUnique(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
64
+ /** Like {@link findFirst} but throws if no document matches. */
65
+ findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
66
+ /** True if at least one document matches. */
67
+ exists(where?: WhereInput<T>): Promise<boolean>;
68
+ /**
69
+ * Subscribe to a live query. The callback fires immediately with the current
70
+ * results (`type: "init"`) and again whenever a change affects the result set
71
+ * (row-level: only relevant changes trigger a recompute). Includes changes
72
+ * applied by `@monlite/sync`.
73
+ */
74
+ watch(args: FindManyArgs<T> | undefined, cb: (event: LiveEvent<T>) => void): WatchHandle<T>;
75
+ /** Show SQLite's query plan for a `findMany`, and whether it uses an index. */
76
+ explain(args?: FindManyArgs<T>): Promise<ExplainResult>;
77
+ findById(id: string): Promise<WithId<T> | null>;
78
+ count(args?: CountArgs<T>): Promise<number>;
79
+ /**
80
+ * Return the distinct values of a field. Array fields stored in JSON are
81
+ * unwound (each element counts as a value), matching MongoDB's `distinct`.
82
+ */
83
+ distinct(field: string, where?: WhereInput<T>): Promise<any[]>;
84
+ private runUpdate;
85
+ update(args: UpdateArgs<T>): Promise<WithId<T> | null>;
86
+ updateMany(args: UpdateArgs<T>): Promise<{
87
+ count: number;
88
+ }>;
89
+ upsert(args: UpsertArgs<T>): Promise<WithId<T>>;
90
+ private runDelete;
91
+ delete(args: DeleteArgs<T>): Promise<WithId<T> | null>;
92
+ deleteMany(args?: DeleteArgs<T>): Promise<{
93
+ count: number;
94
+ }>;
95
+ aggregate(args?: AggregateArgs<T>): Promise<AggregateResult>;
96
+ groupBy(args: GroupByArgs<T>): Promise<GroupByResult[]>;
97
+ }
98
+
99
+ /** Documents that changed in a single write, delivered to `afterWrite`. */
100
+ interface PluginChange {
101
+ collection: string;
102
+ ids: string[];
103
+ }
104
+ /**
105
+ * A monlite plugin. Plugins keep `@monlite/core` lean — heavier or optional
106
+ * capabilities (full-text search, vector, encryption) live in their own
107
+ * packages and hook in here.
108
+ */
109
+ interface MonlitePlugin {
110
+ name: string;
111
+ /** Called once when the database opens (e.g. to create auxiliary tables). */
112
+ init?(db: Monlite): void;
113
+ /**
114
+ * Called synchronously after every committed write (including changes applied
115
+ * by `@monlite/sync`), so derived state like a search index stays in sync.
116
+ */
117
+ afterWrite?(db: Monlite, change: PluginChange): void;
118
+ /**
119
+ * Methods to attach to every collection handle (e.g. `search`). The impl
120
+ * receives the collection as its first argument, then the caller's arguments.
121
+ */
122
+ collectionMethods?: Record<string, (collection: Collection<any>, ...args: any[]) => any>;
123
+ }
124
+
1
125
  /**
2
126
  * Public type surface for monlite.
3
127
  *
4
128
  * Documents are plain objects. monlite adds three system fields to every
5
129
  * stored document: `_id`, `created_at`, and `updated_at`.
6
130
  */
131
+
7
132
  /** A free-form document. */
8
133
  type Doc = Record<string, any>;
9
134
  /** System fields monlite manages on every document. */
@@ -238,6 +363,8 @@ interface MonliteOptions {
238
363
  * when installed, otherwise the built-in `node:sqlite` (Node >= 22.5).
239
364
  */
240
365
  driver?: DriverName;
366
+ /** Opt-in plugins (e.g. `@monlite/fts`). */
367
+ plugins?: MonlitePlugin[];
241
368
  /**
242
369
  * Enable sync metadata (change feed, tombstones, version tracking) so the
243
370
  * database can replicate via `@monlite/sync`. Off by default — adds zero
@@ -263,104 +390,6 @@ interface MonliteOptions {
263
390
  verbose?: (sql: string) => void;
264
391
  }
265
392
 
266
- /**
267
- * A collection. In **document** mode (default) every document is stored as JSON
268
- * in a `data` column — schema-free. In **structured** mode (when a `schema` is
269
- * given) the listed fields become real, typed SQL columns (fast, indexable,
270
- * joinable) while any other fields overflow into a JSON `data` column. The CRUD
271
- * and query API is identical in both modes.
272
- */
273
- declare class Collection<T = Doc> {
274
- private readonly mon;
275
- readonly name: string;
276
- readonly mode: CollectionMode;
277
- private initialized;
278
- private readonly columnDefs;
279
- private readonly columnOrder;
280
- /** Declared native columns (empty in document mode). */
281
- private readonly columns;
282
- private readonly jsonColumns;
283
- private insertSqlCache?;
284
- private readonly trackPath;
285
- constructor(mon: Monlite, name: string, options?: CollectionOptions);
286
- private get db();
287
- /** Run a DB operation, normalizing driver errors into typed MonliteErrors. */
288
- private guard;
289
- /** Native column names declared for this collection (structured mode). */
290
- get columnNames(): string[];
291
- private ensureTable;
292
- private columnDdl;
293
- /** Auto-additive migration: add declared columns missing from an existing table. */
294
- private migrateColumns;
295
- private rowToDoc;
296
- private encodeColumn;
297
- private insertColumns;
298
- private insertSql;
299
- /** Split an input document into a row aligned with `insertColumns()`. */
300
- private buildInsert;
301
- /** Build the `SET` clause + values to persist an updated document. */
302
- private buildUpdateSet;
303
- /** Sync store for recording local changes (both document and structured). */
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;
316
- create(args: CreateArgs<T>): Promise<WithId<T>>;
317
- createMany(args: CreateManyArgs<T>): Promise<{
318
- count: number;
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;
325
- findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
326
- findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
327
- /** Alias of {@link findFirst} for Prisma familiarity. */
328
- findUnique(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
329
- /** Like {@link findFirst} but throws if no document matches. */
330
- findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
331
- /** True if at least one document matches. */
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>;
342
- findById(id: string): Promise<WithId<T> | null>;
343
- count(args?: CountArgs<T>): Promise<number>;
344
- /**
345
- * Return the distinct values of a field. Array fields stored in JSON are
346
- * unwound (each element counts as a value), matching MongoDB's `distinct`.
347
- */
348
- distinct(field: string, where?: WhereInput<T>): Promise<any[]>;
349
- private runUpdate;
350
- update(args: UpdateArgs<T>): Promise<WithId<T> | null>;
351
- updateMany(args: UpdateArgs<T>): Promise<{
352
- count: number;
353
- }>;
354
- upsert(args: UpsertArgs<T>): Promise<WithId<T>>;
355
- private runDelete;
356
- delete(args: DeleteArgs<T>): Promise<WithId<T> | null>;
357
- deleteMany(args?: DeleteArgs<T>): Promise<{
358
- count: number;
359
- }>;
360
- aggregate(args?: AggregateArgs<T>): Promise<AggregateResult>;
361
- groupBy(args: GroupByArgs<T>): Promise<GroupByResult[]>;
362
- }
363
-
364
393
  /**
365
394
  * The minimal SQLite driver surface monlite needs. Implemented by both the
366
395
  * better-sqlite3 and the built-in node:sqlite backends so the rest of the
@@ -581,8 +610,11 @@ declare class Monlite {
581
610
  /** @internal Sync metadata store; present only when `{ sync: true }`. */
582
611
  readonly $sync?: SyncStore;
583
612
  private readonly collections;
613
+ private readonly plugins;
584
614
  private closed;
585
615
  constructor(filename: string, options?: MonliteOptions);
616
+ /** @internal Notify plugins that documents changed (post-commit). */
617
+ firePluginAfterWrite(collection: string, ids: string[]): void;
586
618
  /** Stable node id for LWW tie-breaking (only when sync is enabled). */
587
619
  get nodeId(): string | undefined;
588
620
  /** The underlying native database handle (escape hatch). */
@@ -683,4 +715,4 @@ declare function objectId(): string;
683
715
  /** True when a value looks like a monlite/ObjectId id (24 hex chars). */
684
716
  declare function isObjectId(value: unknown): value is string;
685
717
 
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 };
718
+ 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, type MonlitePlugin, MonliteQueryError, MonliteUniqueConstraintError, type OrderBy, type PluginChange, 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
@@ -1,9 +1,134 @@
1
+ /**
2
+ * A collection. In **document** mode (default) every document is stored as JSON
3
+ * in a `data` column — schema-free. In **structured** mode (when a `schema` is
4
+ * given) the listed fields become real, typed SQL columns (fast, indexable,
5
+ * joinable) while any other fields overflow into a JSON `data` column. The CRUD
6
+ * and query API is identical in both modes.
7
+ */
8
+ declare class Collection<T = Doc> {
9
+ private readonly mon;
10
+ readonly name: string;
11
+ readonly mode: CollectionMode;
12
+ private initialized;
13
+ private readonly columnDefs;
14
+ private readonly columnOrder;
15
+ /** Declared native columns (empty in document mode). */
16
+ private readonly columns;
17
+ private readonly jsonColumns;
18
+ private insertSqlCache?;
19
+ private readonly trackPath;
20
+ constructor(mon: Monlite, name: string, options?: CollectionOptions);
21
+ private get db();
22
+ /** Run a DB operation, normalizing driver errors into typed MonliteErrors. */
23
+ private guard;
24
+ /** Native column names declared for this collection (structured mode). */
25
+ get columnNames(): string[];
26
+ private ensureTable;
27
+ private columnDdl;
28
+ /** Auto-additive migration: add declared columns missing from an existing table. */
29
+ private migrateColumns;
30
+ private rowToDoc;
31
+ private encodeColumn;
32
+ private insertColumns;
33
+ private insertSql;
34
+ /** Split an input document into a row aligned with `insertColumns()`. */
35
+ private buildInsert;
36
+ /** Build the `SET` clause + values to persist an updated document. */
37
+ private buildUpdateSet;
38
+ /** Sync store for recording local changes (both document and structured). */
39
+ private get recorder();
40
+ /** @internal Read a full document by id (mode-aware), synchronously. */
41
+ getRaw(id: string): WithId<T> | null;
42
+ /**
43
+ * @internal Apply a remote change to storage WITHOUT recording it to the
44
+ * change feed (the sync store records the `remote` feed row itself). Used by
45
+ * `@monlite/sync` so structured collections sync correctly through the same
46
+ * column/overflow split as local writes.
47
+ */
48
+ applyRemoteWrite(op: "upsert" | "delete", id: string, doc: Record<string, any> | undefined, ts: number): void;
49
+ /** @internal Notify reactivity watchers and plugins that documents changed. */
50
+ private afterWrite;
51
+ create(args: CreateArgs<T>): Promise<WithId<T>>;
52
+ createMany(args: CreateManyArgs<T>): Promise<{
53
+ count: number;
54
+ }>;
55
+ private buildFindSql;
56
+ /** @internal Synchronous core of findMany (used by reactivity). */
57
+ findManyCore(args?: FindManyArgs<T>): WithId<T>[];
58
+ /** @internal Synchronous core of exists (used by reactivity). */
59
+ existsCore(where: WhereInput<T> | undefined): boolean;
60
+ findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
61
+ findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
62
+ /** Alias of {@link findFirst} for Prisma familiarity. */
63
+ findUnique(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
64
+ /** Like {@link findFirst} but throws if no document matches. */
65
+ findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
66
+ /** True if at least one document matches. */
67
+ exists(where?: WhereInput<T>): Promise<boolean>;
68
+ /**
69
+ * Subscribe to a live query. The callback fires immediately with the current
70
+ * results (`type: "init"`) and again whenever a change affects the result set
71
+ * (row-level: only relevant changes trigger a recompute). Includes changes
72
+ * applied by `@monlite/sync`.
73
+ */
74
+ watch(args: FindManyArgs<T> | undefined, cb: (event: LiveEvent<T>) => void): WatchHandle<T>;
75
+ /** Show SQLite's query plan for a `findMany`, and whether it uses an index. */
76
+ explain(args?: FindManyArgs<T>): Promise<ExplainResult>;
77
+ findById(id: string): Promise<WithId<T> | null>;
78
+ count(args?: CountArgs<T>): Promise<number>;
79
+ /**
80
+ * Return the distinct values of a field. Array fields stored in JSON are
81
+ * unwound (each element counts as a value), matching MongoDB's `distinct`.
82
+ */
83
+ distinct(field: string, where?: WhereInput<T>): Promise<any[]>;
84
+ private runUpdate;
85
+ update(args: UpdateArgs<T>): Promise<WithId<T> | null>;
86
+ updateMany(args: UpdateArgs<T>): Promise<{
87
+ count: number;
88
+ }>;
89
+ upsert(args: UpsertArgs<T>): Promise<WithId<T>>;
90
+ private runDelete;
91
+ delete(args: DeleteArgs<T>): Promise<WithId<T> | null>;
92
+ deleteMany(args?: DeleteArgs<T>): Promise<{
93
+ count: number;
94
+ }>;
95
+ aggregate(args?: AggregateArgs<T>): Promise<AggregateResult>;
96
+ groupBy(args: GroupByArgs<T>): Promise<GroupByResult[]>;
97
+ }
98
+
99
+ /** Documents that changed in a single write, delivered to `afterWrite`. */
100
+ interface PluginChange {
101
+ collection: string;
102
+ ids: string[];
103
+ }
104
+ /**
105
+ * A monlite plugin. Plugins keep `@monlite/core` lean — heavier or optional
106
+ * capabilities (full-text search, vector, encryption) live in their own
107
+ * packages and hook in here.
108
+ */
109
+ interface MonlitePlugin {
110
+ name: string;
111
+ /** Called once when the database opens (e.g. to create auxiliary tables). */
112
+ init?(db: Monlite): void;
113
+ /**
114
+ * Called synchronously after every committed write (including changes applied
115
+ * by `@monlite/sync`), so derived state like a search index stays in sync.
116
+ */
117
+ afterWrite?(db: Monlite, change: PluginChange): void;
118
+ /**
119
+ * Methods to attach to every collection handle (e.g. `search`). The impl
120
+ * receives the collection as its first argument, then the caller's arguments.
121
+ */
122
+ collectionMethods?: Record<string, (collection: Collection<any>, ...args: any[]) => any>;
123
+ }
124
+
1
125
  /**
2
126
  * Public type surface for monlite.
3
127
  *
4
128
  * Documents are plain objects. monlite adds three system fields to every
5
129
  * stored document: `_id`, `created_at`, and `updated_at`.
6
130
  */
131
+
7
132
  /** A free-form document. */
8
133
  type Doc = Record<string, any>;
9
134
  /** System fields monlite manages on every document. */
@@ -238,6 +363,8 @@ interface MonliteOptions {
238
363
  * when installed, otherwise the built-in `node:sqlite` (Node >= 22.5).
239
364
  */
240
365
  driver?: DriverName;
366
+ /** Opt-in plugins (e.g. `@monlite/fts`). */
367
+ plugins?: MonlitePlugin[];
241
368
  /**
242
369
  * Enable sync metadata (change feed, tombstones, version tracking) so the
243
370
  * database can replicate via `@monlite/sync`. Off by default — adds zero
@@ -263,104 +390,6 @@ interface MonliteOptions {
263
390
  verbose?: (sql: string) => void;
264
391
  }
265
392
 
266
- /**
267
- * A collection. In **document** mode (default) every document is stored as JSON
268
- * in a `data` column — schema-free. In **structured** mode (when a `schema` is
269
- * given) the listed fields become real, typed SQL columns (fast, indexable,
270
- * joinable) while any other fields overflow into a JSON `data` column. The CRUD
271
- * and query API is identical in both modes.
272
- */
273
- declare class Collection<T = Doc> {
274
- private readonly mon;
275
- readonly name: string;
276
- readonly mode: CollectionMode;
277
- private initialized;
278
- private readonly columnDefs;
279
- private readonly columnOrder;
280
- /** Declared native columns (empty in document mode). */
281
- private readonly columns;
282
- private readonly jsonColumns;
283
- private insertSqlCache?;
284
- private readonly trackPath;
285
- constructor(mon: Monlite, name: string, options?: CollectionOptions);
286
- private get db();
287
- /** Run a DB operation, normalizing driver errors into typed MonliteErrors. */
288
- private guard;
289
- /** Native column names declared for this collection (structured mode). */
290
- get columnNames(): string[];
291
- private ensureTable;
292
- private columnDdl;
293
- /** Auto-additive migration: add declared columns missing from an existing table. */
294
- private migrateColumns;
295
- private rowToDoc;
296
- private encodeColumn;
297
- private insertColumns;
298
- private insertSql;
299
- /** Split an input document into a row aligned with `insertColumns()`. */
300
- private buildInsert;
301
- /** Build the `SET` clause + values to persist an updated document. */
302
- private buildUpdateSet;
303
- /** Sync store for recording local changes (both document and structured). */
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;
316
- create(args: CreateArgs<T>): Promise<WithId<T>>;
317
- createMany(args: CreateManyArgs<T>): Promise<{
318
- count: number;
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;
325
- findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
326
- findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
327
- /** Alias of {@link findFirst} for Prisma familiarity. */
328
- findUnique(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
329
- /** Like {@link findFirst} but throws if no document matches. */
330
- findFirstOrThrow(args?: FindFirstArgs<T>): Promise<WithId<T>>;
331
- /** True if at least one document matches. */
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>;
342
- findById(id: string): Promise<WithId<T> | null>;
343
- count(args?: CountArgs<T>): Promise<number>;
344
- /**
345
- * Return the distinct values of a field. Array fields stored in JSON are
346
- * unwound (each element counts as a value), matching MongoDB's `distinct`.
347
- */
348
- distinct(field: string, where?: WhereInput<T>): Promise<any[]>;
349
- private runUpdate;
350
- update(args: UpdateArgs<T>): Promise<WithId<T> | null>;
351
- updateMany(args: UpdateArgs<T>): Promise<{
352
- count: number;
353
- }>;
354
- upsert(args: UpsertArgs<T>): Promise<WithId<T>>;
355
- private runDelete;
356
- delete(args: DeleteArgs<T>): Promise<WithId<T> | null>;
357
- deleteMany(args?: DeleteArgs<T>): Promise<{
358
- count: number;
359
- }>;
360
- aggregate(args?: AggregateArgs<T>): Promise<AggregateResult>;
361
- groupBy(args: GroupByArgs<T>): Promise<GroupByResult[]>;
362
- }
363
-
364
393
  /**
365
394
  * The minimal SQLite driver surface monlite needs. Implemented by both the
366
395
  * better-sqlite3 and the built-in node:sqlite backends so the rest of the
@@ -581,8 +610,11 @@ declare class Monlite {
581
610
  /** @internal Sync metadata store; present only when `{ sync: true }`. */
582
611
  readonly $sync?: SyncStore;
583
612
  private readonly collections;
613
+ private readonly plugins;
584
614
  private closed;
585
615
  constructor(filename: string, options?: MonliteOptions);
616
+ /** @internal Notify plugins that documents changed (post-commit). */
617
+ firePluginAfterWrite(collection: string, ids: string[]): void;
586
618
  /** Stable node id for LWW tie-breaking (only when sync is enabled). */
587
619
  get nodeId(): string | undefined;
588
620
  /** The underlying native database handle (escape hatch). */
@@ -683,4 +715,4 @@ declare function objectId(): string;
683
715
  /** True when a value looks like a monlite/ObjectId id (24 hex chars). */
684
716
  declare function isObjectId(value: unknown): value is string;
685
717
 
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 };
718
+ 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, type MonlitePlugin, MonliteQueryError, MonliteUniqueConstraintError, type OrderBy, type PluginChange, 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.js CHANGED
@@ -949,9 +949,11 @@ var Collection = class {
949
949
  ).run(...values);
950
950
  this.afterWrite([id]);
951
951
  }
952
- /** @internal Notify reactivity watchers that documents changed. */
952
+ /** @internal Notify reactivity watchers and plugins that documents changed. */
953
953
  afterWrite(ids) {
954
+ if (ids.length === 0) return;
954
955
  this.mon.reactor.emit(this.name, ids);
956
+ this.mon.firePluginAfterWrite(this.name, ids);
955
957
  }
956
958
  /* ----------------------------- create ----------------------------- */
957
959
  async create(args) {
@@ -1885,6 +1887,7 @@ var Monlite = class {
1885
1887
  /** @internal Sync metadata store; present only when `{ sync: true }`. */
1886
1888
  $sync;
1887
1889
  collections = /* @__PURE__ */ new Map();
1890
+ plugins;
1888
1891
  closed = false;
1889
1892
  constructor(filename, options = {}) {
1890
1893
  this.driver = createDriver(filename, {
@@ -1902,6 +1905,15 @@ var Monlite = class {
1902
1905
  if (options.sync) {
1903
1906
  this.$sync = new SyncStore(this.driver, options.nodeId, this);
1904
1907
  }
1908
+ this.plugins = options.plugins ?? [];
1909
+ for (const plugin of this.plugins) plugin.init?.(this);
1910
+ }
1911
+ /** @internal Notify plugins that documents changed (post-commit). */
1912
+ firePluginAfterWrite(collection, ids) {
1913
+ if (this.plugins.length === 0 || ids.length === 0) return;
1914
+ for (const plugin of this.plugins) {
1915
+ plugin.afterWrite?.(this, { collection, ids });
1916
+ }
1905
1917
  }
1906
1918
  /** Stable node id for LWW tie-breaking (only when sync is enabled). */
1907
1919
  get nodeId() {
@@ -1927,6 +1939,13 @@ var Monlite = class {
1927
1939
  if (!col) {
1928
1940
  col = new Collection(this, name, options);
1929
1941
  this.collections.set(name, col);
1942
+ for (const plugin of this.plugins) {
1943
+ for (const [method, impl] of Object.entries(
1944
+ plugin.collectionMethods ?? {}
1945
+ )) {
1946
+ col[method] = (...args) => impl(col, ...args);
1947
+ }
1948
+ }
1930
1949
  } else if (options?.schema) {
1931
1950
  const requested = Object.keys(options.schema);
1932
1951
  const existing = new Set(col.columnNames);