@firtoz/drizzle-sqlite-wasm 0.2.15 → 0.2.17

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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @firtoz/drizzle-sqlite-wasm
2
2
 
3
+ ## 0.2.17
4
+
5
+ ### Patch Changes
6
+
7
+ - [`8b839f2`](https://github.com/firtoz/fullstack-toolkit/commit/8b839f2227f50409af649aab87178e039aad55dc) Thanks [@firtoz](https://github.com/firtoz)! - Export collection helper types for Drizzle-backed TanStack DB collections so users can declare collection variables with preserved select and insert inference from table schemas.
8
+
9
+ ## 0.2.16
10
+
11
+ ### Patch Changes
12
+
13
+ - [`b714ebb`](https://github.com/firtoz/fullstack-toolkit/commit/b714ebbb62ec0e3c3aa56c4105e7499fac11d1e5) Thanks [@firtoz](https://github.com/firtoz)! - Extract shared SQLite TanStack sync backend (`createSqliteTableSyncBackend`, IR→Drizzle helpers, `SQLOperation` types) into `@firtoz/drizzle-utils`. Add `@firtoz/drizzle-durable-sqlite` for Durable Object SQLite collections (`durableSqliteCollectionOptions`). Refactor `@firtoz/drizzle-sqlite-wasm` to use the shared backend with `driverMode: "async"`. `durableSqliteCollectionOptions` accepts optional `readyPromise` (defaults to immediate readiness). README documents the class-field Hono pattern, `app.fetch(request, env)` for bindings, optional `on-demand` + `preload` vs eager + `onFirstReady`, and `honoDoFetcherWithName` without a separate exported app type. Restore JSDoc on `DrizzleSqliteCollectionConfig` (`debug`, `checkpoint`, `interceptor`) for editor tooltips. Align `createStandaloneCollection` generics with `InsertToSelectSchema` from `@firtoz/drizzle-utils`.
14
+
15
+ - Updated dependencies [[`b714ebb`](https://github.com/firtoz/fullstack-toolkit/commit/b714ebbb62ec0e3c3aa56c4105e7499fac11d1e5)]:
16
+ - @firtoz/drizzle-utils@1.1.0
17
+
3
18
  ## 0.2.15
4
19
 
5
20
  ### Patch Changes
package/README.md CHANGED
@@ -227,7 +227,11 @@ Create TanStack DB collections backed by SQLite:
227
227
 
228
228
  ```typescript
229
229
  import { createCollection } from "@tanstack/db";
230
- import { drizzleCollectionOptions } from "@firtoz/drizzle-sqlite-wasm/drizzleCollectionOptions";
230
+ import {
231
+ drizzleCollectionOptions,
232
+ type DrizzleSqliteCollection,
233
+ } from "@firtoz/drizzle-sqlite-wasm";
234
+ import * as schema from "./schema";
231
235
 
232
236
  const collection = createCollection(
233
237
  drizzleCollectionOptions({
@@ -249,12 +253,16 @@ const completed = await collection.find({
249
253
  orderBy: { createdAt: "desc" },
250
254
  });
251
255
 
256
+ type TodosCollection = DrizzleSqliteCollection<typeof schema.todoTable>;
257
+
252
258
  // Subscribe to changes
253
259
  collection.subscribe((todos) => {
254
260
  console.log("Todos updated:", todos);
255
261
  });
256
262
  ```
257
263
 
264
+ Use `DrizzleSqliteCollection<TTable>` when you want a reusable collection type alias that keeps inferred select/insert types from your table.
265
+
258
266
  ### Collection Options
259
267
 
260
268
  **Config:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firtoz/drizzle-sqlite-wasm",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "Drizzle SQLite WASM bindings",
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -70,7 +70,7 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "@firtoz/db-helpers": "^2.0.0",
73
- "@firtoz/drizzle-utils": "^1.0.2",
73
+ "@firtoz/drizzle-utils": "^1.1.0",
74
74
  "@firtoz/maybe-error": "^1.5.2",
75
75
  "@firtoz/worker-helper": "^1.5.1",
76
76
  "@sqlite.org/sqlite-wasm": "^3.51.2-build8",
@@ -1,50 +1,30 @@
1
1
  import type {
2
+ Collection,
3
+ InferSchemaInput,
2
4
  InferSchemaOutput,
3
5
  SyncMode,
4
6
  CollectionConfig,
5
7
  } from "@tanstack/db";
6
- import type { IR } from "@tanstack/db";
7
- import {
8
- eq,
9
- sql,
10
- type Table,
11
- gt,
12
- gte,
13
- lt,
14
- lte,
15
- ne,
16
- and,
17
- or,
18
- not,
19
- isNull,
20
- isNotNull,
21
- like,
22
- inArray,
23
- asc,
24
- desc,
25
- type SQL,
26
- } from "drizzle-orm";
27
- import {
28
- type SQLiteUpdateSetSource,
29
- type BaseSQLiteDatabase,
30
- type SQLiteInsertValue,
31
- SQLiteColumn,
32
- } from "drizzle-orm/sqlite-core";
8
+ import type { Table } from "drizzle-orm";
9
+ import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
33
10
  import type { CollectionUtils } from "@firtoz/db-helpers";
34
11
  import type {
35
12
  SelectSchema,
13
+ InsertToSelectSchema,
36
14
  TableWithRequiredFields,
37
15
  BaseSyncConfig,
38
- SyncBackend,
16
+ IdOf,
39
17
  } from "@firtoz/drizzle-utils";
40
18
  import {
41
19
  createSyncFunction,
42
20
  createInsertSchemaWithIdDefault,
43
21
  createGetKeyFunction,
44
22
  createCollectionConfig,
23
+ createSqliteTableSyncBackend,
24
+ type SQLOperation,
25
+ type SQLInterceptor,
45
26
  } from "@firtoz/drizzle-utils";
46
- import { exhaustiveGuard } from "@firtoz/maybe-error";
47
- import type * as v from "valibot";
27
+ export type { SQLOperation, SQLInterceptor };
48
28
 
49
29
  export type AnyDrizzleDatabase = BaseSQLiteDatabase<
50
30
  "async",
@@ -56,81 +36,7 @@ export type AnyDrizzleDatabase = BaseSQLiteDatabase<
56
36
  export type DrizzleSchema<TDrizzle extends AnyDrizzleDatabase> =
57
37
  TDrizzle["_"]["fullSchema"];
58
38
 
59
- /**
60
- * Operation tracking for SQLite queries
61
- * Useful for testing and debugging to verify what operations are actually performed
62
- *
63
- * Uses discriminated unions for type safety - TypeScript can narrow the type based on the 'type' field
64
- */
65
- export type SQLOperation =
66
- | {
67
- type: "select-all";
68
- tableName: string;
69
- itemsReturned: unknown[];
70
- itemCount: number;
71
- context: string;
72
- sql?: string;
73
- timestamp: number;
74
- }
75
- | {
76
- type: "select-where";
77
- tableName: string;
78
- whereClause: string;
79
- itemsReturned: unknown[];
80
- itemCount: number;
81
- context: string;
82
- sql?: string;
83
- timestamp: number;
84
- }
85
- | {
86
- type: "write";
87
- tableName: string;
88
- itemsWritten: unknown[];
89
- writeCount: number;
90
- context: string;
91
- timestamp: number;
92
- }
93
- | {
94
- type: "insert";
95
- tableName: string;
96
- item: unknown;
97
- sql?: string;
98
- timestamp: number;
99
- }
100
- | {
101
- type: "update";
102
- tableName: string;
103
- updates: unknown;
104
- sql?: string;
105
- timestamp: number;
106
- }
107
- | {
108
- type: "delete";
109
- tableName: string;
110
- sql?: string;
111
- timestamp: number;
112
- }
113
- | {
114
- /** Raw SQL query executed directly via Drizzle (not through collection) */
115
- type: "raw-query";
116
- sql: string;
117
- params?: unknown[];
118
- method: string;
119
- rowCount: number;
120
- context: string;
121
- timestamp: number;
122
- };
123
-
124
- /**
125
- * Interceptor interface for tracking SQLite operations
126
- * Allows tests and debugging tools to observe what operations are performed
127
- */
128
- export interface SQLInterceptor {
129
- /** Called when any SQLite operation is performed */
130
- onOperation?: (operation: SQLOperation) => void;
131
- }
132
-
133
- export interface DrizzleCollectionConfig<
39
+ export interface DrizzleSqliteCollectionConfig<
134
40
  TDrizzle extends AnyDrizzleDatabase,
135
41
  TTableName extends ValidTableNames<DrizzleSchema<TDrizzle>>,
136
42
  > {
@@ -161,427 +67,50 @@ export type ValidTableNames<TSchema extends Record<string, unknown>> = {
161
67
  [K in keyof TSchema]: TSchema[K] extends TableWithRequiredFields ? K : never;
162
68
  }[keyof TSchema];
163
69
 
164
- /**
165
- * Return type for sqliteCollectionOptions - configuration object for creating SQLite collections
166
- *
167
- * Note: The third type parameter of CollectionConfig uses `any` to maintain compatibility with
168
- * TanStack DB's type system, which expects different schema types in different contexts.
169
- */
170
70
  export type SqliteCollectionConfig<TTable extends Table> = Omit<
171
71
  CollectionConfig<
172
72
  InferSchemaOutput<SelectSchema<TTable>>,
173
- string,
174
- // biome-ignore lint/suspicious/noExplicitAny: Required for TanStack DB type compatibility
175
- any
73
+ IdOf<TTable>,
74
+ InsertToSelectSchema<TTable>,
75
+ CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>
176
76
  >,
177
77
  "utils"
178
78
  > & {
179
- schema: v.GenericSchema<unknown>;
79
+ schema: InsertToSelectSchema<TTable>;
180
80
  utils: CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>;
181
81
  };
182
82
 
183
- /**
184
- * Converts TanStack DB IR BasicExpression to Drizzle SQL expression
185
- *
186
- * Supported operators that TanStack DB pushes down to backend (SUPPORTED_COLLECTION_FUNCS):
187
- * - eq, gt, lt, gte, lte, and, or, in, isNull, isUndefined, not
188
- *
189
- * Additional operators handled for completeness (won't be pushed down in on-demand mode):
190
- * - ne, isNotNull, like
191
- */
192
- function convertBasicExpressionToDrizzle<TTable extends Table>(
193
- expression: IR.BasicExpression,
194
- table: TTable,
195
- ): SQL {
196
- switch (expression.type) {
197
- case "ref": {
198
- const propRef = expression;
199
- const columnName = propRef.path[propRef.path.length - 1];
200
- const column = table[columnName as keyof typeof table];
201
-
202
- if (!column || !(column instanceof SQLiteColumn)) {
203
- console.error("[SQLite Collection] Column lookup failed:", {
204
- columnName,
205
- column,
206
- tableKeys: Object.keys(table),
207
- hasColumn: columnName in table,
208
- });
209
- throw new Error(`Column ${String(columnName)} not found in table`);
210
- }
211
-
212
- return column as unknown as SQL;
213
- }
214
- case "val": {
215
- const value = expression;
216
- return sql`${value.value}`;
217
- }
218
- case "func": {
219
- const func = expression;
220
- const args = func.args.map((arg) =>
221
- convertBasicExpressionToDrizzle(arg, table),
222
- );
223
-
224
- switch (func.name) {
225
- case "eq":
226
- return eq(args[0], args[1]);
227
- case "ne":
228
- return ne(args[0], args[1]);
229
- case "gt":
230
- return gt(args[0], args[1]);
231
- case "gte":
232
- return gte(args[0], args[1]);
233
- case "lt":
234
- return lt(args[0], args[1]);
235
- case "lte":
236
- return lte(args[0], args[1]);
237
- case "and": {
238
- const result = and(...args);
239
- if (!result) {
240
- throw new Error("Invalid 'and' expression - no arguments provided");
241
- }
242
- return result;
243
- }
244
- case "or": {
245
- const result = or(...args);
246
- if (!result) {
247
- throw new Error("Invalid 'or' expression - no arguments provided");
248
- }
249
- return result;
250
- }
251
- case "not":
252
- return not(args[0]);
253
- case "isNull":
254
- return isNull(args[0]);
255
- case "isNotNull":
256
- return isNotNull(args[0]);
257
- case "like":
258
- return like(args[0], args[1]);
259
- case "in":
260
- return inArray(args[0], args[1]);
261
- case "isUndefined":
262
- // isUndefined is same as isNull in SQLite
263
- return isNull(args[0]);
264
- default:
265
- throw new Error(`Unsupported function: ${func.name}`);
266
- }
267
- }
268
- default:
269
- exhaustiveGuard(expression);
270
- }
271
- }
272
-
273
- /**
274
- * Converts TanStack DB OrderBy to Drizzle orderBy
275
- */
276
- function convertOrderByToDrizzle<TTable extends Table>(
277
- orderBy: IR.OrderBy,
278
- table: TTable,
279
- ): SQL[] {
280
- return orderBy.map((clause) => {
281
- const expression = convertBasicExpressionToDrizzle(
282
- clause.expression,
283
- table,
284
- );
285
- const direction = clause.compareOptions.direction || "asc";
286
-
287
- return direction === "asc" ? asc(expression) : desc(expression);
288
- });
289
- }
83
+ export type DrizzleSqliteCollection<TTable extends TableWithRequiredFields> =
84
+ Collection<
85
+ InferSchemaOutput<SelectSchema<TTable>>,
86
+ IdOf<TTable>,
87
+ CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>,
88
+ InsertToSelectSchema<TTable>,
89
+ InferSchemaInput<InsertToSelectSchema<TTable>>
90
+ >;
290
91
 
291
92
  export function sqliteCollectionOptions<
292
93
  const TDrizzle extends AnyDrizzleDatabase,
293
94
  const TTableName extends string & ValidTableNames<DrizzleSchema<TDrizzle>>,
294
95
  TTable extends DrizzleSchema<TDrizzle>[TTableName] & TableWithRequiredFields,
295
96
  >(
296
- config: DrizzleCollectionConfig<TDrizzle, TTableName>,
97
+ config: DrizzleSqliteCollectionConfig<TDrizzle, TTableName>,
297
98
  ): SqliteCollectionConfig<TTable> {
298
99
  const tableName = config.tableName as string &
299
100
  ValidTableNames<DrizzleSchema<TDrizzle>>;
300
101
 
301
102
  const table = config.drizzle?._.fullSchema[tableName] as TTable;
302
103
 
303
- // Transaction queue to serialize SQLite transactions (SQLite only supports one transaction at a time)
304
- // The queue ensures transactions run sequentially and continues even if one fails
305
- let transactionQueue = Promise.resolve();
306
- const queueTransaction = <T>(fn: () => Promise<T>): Promise<T> => {
307
- // Chain this transaction after the previous one (whether it succeeded or failed)
308
- const result = transactionQueue.then(fn, fn);
309
- // Update the queue to continue after this transaction completes (success or failure)
310
- // This ensures the queue doesn't get stuck if a transaction fails
311
- transactionQueue = result.then(
312
- () => {}, // Success handler - return undefined to reset queue
313
- () => {}, // Error handler - return undefined to reset queue (queue continues)
314
- );
315
- // Return the actual result so errors propagate to the caller
316
- return result;
317
- };
318
-
319
- // Create backend-specific implementation
320
- const backend: SyncBackend<TTable> = {
321
- initialLoad: async () => {
322
- const items = (await config.drizzle
323
- .select()
324
- .from(table)) as unknown as InferSchemaOutput<SelectSchema<TTable>>[];
325
-
326
- // Log SQL operation
327
- if (config.interceptor?.onOperation) {
328
- config.interceptor.onOperation({
329
- type: "select-all",
330
- tableName: config.tableName as string,
331
- itemsReturned: items,
332
- itemCount: items.length,
333
- context: "Initial load (eager mode)",
334
- timestamp: Date.now(),
335
- });
336
- }
337
-
338
- // Log write operation
339
- if (config.interceptor?.onOperation) {
340
- config.interceptor.onOperation({
341
- type: "write",
342
- tableName: config.tableName as string,
343
- itemsWritten: items,
344
- writeCount: items.length,
345
- context: "Initial load (eager mode)",
346
- timestamp: Date.now(),
347
- });
348
- }
349
-
350
- return items as unknown as InferSchemaOutput<SelectSchema<TTable>>[];
351
- },
352
-
353
- loadSubset: async (options) => {
354
- // Build the query with optional where, orderBy, limit, and offset
355
- // Use $dynamic() to enable dynamic query building
356
- let query = config.drizzle.select().from(table).$dynamic();
357
-
358
- // Combine where with cursor expressions if present
359
- // The cursor.whereFrom gives us rows after the cursor position
360
- let hasWhere = false;
361
- if (options.where || options.cursor?.whereFrom) {
362
- let drizzleWhere: SQL | undefined;
363
-
364
- if (options.where && options.cursor?.whereFrom) {
365
- // Combine main where with cursor expression using AND
366
- const mainWhere = convertBasicExpressionToDrizzle(
367
- options.where,
368
- table,
369
- );
370
- const cursorWhere = convertBasicExpressionToDrizzle(
371
- options.cursor.whereFrom,
372
- table,
373
- );
374
- drizzleWhere = and(mainWhere, cursorWhere);
375
- } else if (options.where) {
376
- drizzleWhere = convertBasicExpressionToDrizzle(options.where, table);
377
- } else if (options.cursor?.whereFrom) {
378
- drizzleWhere = convertBasicExpressionToDrizzle(
379
- options.cursor.whereFrom,
380
- table,
381
- );
382
- }
383
-
384
- if (drizzleWhere) {
385
- query = query.where(drizzleWhere);
386
- hasWhere = true;
387
- }
388
- }
389
-
390
- if (options.orderBy) {
391
- const drizzleOrderBy = convertOrderByToDrizzle(options.orderBy, table);
392
- query = query.orderBy(...drizzleOrderBy);
393
- }
394
-
395
- if (options.limit !== undefined) {
396
- query = query.limit(options.limit);
397
- }
398
-
399
- // Apply offset for offset-based pagination
400
- if (options.offset !== undefined && options.offset > 0) {
401
- query = query.offset(options.offset);
402
- }
403
-
404
- const items = (await query) as unknown as InferSchemaOutput<
405
- SelectSchema<TTable>
406
- >[];
407
-
408
- // Log SQL operation
409
- if (config.interceptor?.onOperation) {
410
- const contextParts: string[] = ["On-demand load"];
411
- if (options.orderBy) {
412
- contextParts.push("with sorting");
413
- }
414
- if (options.limit !== undefined) {
415
- contextParts.push(`limit ${options.limit}`);
416
- }
417
- if (options.offset !== undefined && options.offset > 0) {
418
- contextParts.push(`offset ${options.offset}`);
419
- }
420
- if (options.cursor) {
421
- contextParts.push("with cursor pagination");
422
- }
423
-
424
- if (hasWhere) {
425
- config.interceptor.onOperation({
426
- type: "select-where",
427
- tableName: config.tableName as string,
428
- whereClause: "WHERE clause applied",
429
- itemsReturned: items,
430
- itemCount: items.length,
431
- context: contextParts.join(", "),
432
- timestamp: Date.now(),
433
- });
434
- } else {
435
- config.interceptor.onOperation({
436
- type: "select-all",
437
- tableName: config.tableName as string,
438
- itemsReturned: items,
439
- itemCount: items.length,
440
- context: contextParts.join(", "),
441
- timestamp: Date.now(),
442
- });
443
- }
444
- }
445
-
446
- // Log write operation
447
- if (config.interceptor?.onOperation) {
448
- const contextParts: string[] = ["On-demand load"];
449
- if (hasWhere) {
450
- contextParts.push("with WHERE clause");
451
- }
452
- if (options.orderBy) {
453
- contextParts.push("with sorting");
454
- }
455
- if (options.limit !== undefined) {
456
- contextParts.push(`limit ${options.limit}`);
457
- }
458
- if (options.offset !== undefined && options.offset > 0) {
459
- contextParts.push(`offset ${options.offset}`);
460
- }
461
-
462
- config.interceptor.onOperation({
463
- type: "write",
464
- tableName: config.tableName as string,
465
- itemsWritten: items,
466
- writeCount: items.length,
467
- context: contextParts.join(", "),
468
- timestamp: Date.now(),
469
- });
470
- }
471
-
472
- return items as unknown as InferSchemaOutput<SelectSchema<TTable>>[];
473
- },
474
-
475
- handleInsert: async (items) => {
476
- const results: Array<InferSchemaOutput<SelectSchema<TTable>>> = [];
477
-
478
- // Queue the transaction to serialize SQLite operations
479
- await queueTransaction(async () => {
480
- await config.drizzle.transaction(async (tx) => {
481
- for (const itemToInsert of items) {
482
- if (config.debug) {
483
- console.log(
484
- `[${new Date().toISOString()}] insertListener inserting`,
485
- itemToInsert,
486
- );
487
- }
488
-
489
- const result: Array<InferSchemaOutput<SelectSchema<TTable>>> =
490
- (await tx
491
- .insert(table)
492
- .values(
493
- itemToInsert as unknown as SQLiteInsertValue<typeof table>,
494
- )
495
- .returning()) as Array<InferSchemaOutput<SelectSchema<TTable>>>;
496
-
497
- if (config.debug) {
498
- console.log(
499
- `[${new Date().toISOString()}] insertListener result`,
500
- result,
501
- );
502
- }
503
-
504
- if (result.length > 0) {
505
- results.push(result[0]);
506
- }
507
- }
508
- });
509
-
510
- // Checkpoint to ensure WAL is flushed to main DB file
511
- if (config.checkpoint) {
512
- await config.checkpoint();
513
- }
514
- });
515
-
516
- return results;
517
- },
518
-
519
- handleUpdate: async (mutations) => {
520
- const results: Array<InferSchemaOutput<SelectSchema<TTable>>> = [];
521
-
522
- // Queue the transaction to serialize SQLite operations
523
- await queueTransaction(async () => {
524
- await config.drizzle.transaction(async (tx) => {
525
- for (const mutation of mutations) {
526
- if (config.debug) {
527
- console.log(
528
- `[${new Date().toISOString()}] updateListener updating`,
529
- mutation,
530
- );
531
- }
532
-
533
- const updateTime = new Date();
534
- const result: Array<InferSchemaOutput<SelectSchema<TTable>>> =
535
- (await tx
536
- .update(table)
537
- .set({
538
- ...mutation.changes,
539
- updatedAt: updateTime,
540
- } as SQLiteUpdateSetSource<typeof table>)
541
- // biome-ignore lint/suspicious/noExplicitAny: Key is string but table.id is branded type
542
- .where(eq(table.id, mutation.key as any))
543
- .returning()) as Array<InferSchemaOutput<SelectSchema<TTable>>>;
544
-
545
- if (config.debug) {
546
- console.log(
547
- `[${new Date().toISOString()}] updateListener result`,
548
- result,
549
- );
550
- }
551
-
552
- results.push(...result);
553
- }
554
- });
555
-
556
- // Checkpoint to ensure WAL is flushed to main DB file BEFORE UI updates
557
- // This ensures persistence before the updateListener completes
558
- if (config.checkpoint) {
559
- await config.checkpoint();
560
- }
561
- });
562
-
563
- return results;
564
- },
565
-
566
- handleDelete: async (mutations) => {
567
- // Queue the transaction to serialize SQLite operations
568
- await queueTransaction(async () => {
569
- await config.drizzle.transaction(async (tx) => {
570
- for (const mutation of mutations) {
571
- // biome-ignore lint/suspicious/noExplicitAny: Key is string but table.id is branded type
572
- await tx.delete(table).where(eq(table.id, mutation.key as any));
573
- }
574
- });
575
-
576
- // Checkpoint to ensure WAL is flushed to main DB file
577
- if (config.checkpoint) {
578
- await config.checkpoint();
579
- }
580
- });
581
- },
582
- };
104
+ const backend = createSqliteTableSyncBackend({
105
+ drizzle: config.drizzle,
106
+ table,
107
+ tableName: config.tableName as string,
108
+ debug: config.debug,
109
+ checkpoint: config.checkpoint,
110
+ interceptor: config.interceptor,
111
+ driverMode: "async",
112
+ });
583
113
 
584
- // Create sync function using shared utilities
585
114
  const baseSyncConfig: BaseSyncConfig<TTable> = {
586
115
  table,
587
116
  readyPromise: config.readyPromise,
@@ -591,11 +120,8 @@ export function sqliteCollectionOptions<
591
120
 
592
121
  const syncResult = createSyncFunction(baseSyncConfig, backend);
593
122
 
594
- // Create insert schema with ID default
595
- // (Other defaults like createdAt/updatedAt are handled by SQLite)
596
123
  const schema = createInsertSchemaWithIdDefault(table);
597
124
 
598
- // Create collection config using shared utilities
599
125
  const collectionConfig = createCollectionConfig({
600
126
  schema,
601
127
  getKey: createGetKeyFunction<TTable>(),
@@ -603,24 +129,21 @@ export function sqliteCollectionOptions<
603
129
  onInsert: config.debug
604
130
  ? async (params) => {
605
131
  console.log("onInsert", params);
606
- // Call the actual handler from syncResult (always defined in createSyncFunction)
607
- // biome-ignore lint/style/noNonNullAssertion: onInsert is always defined in SyncFunctionResult
132
+ // biome-ignore lint/style/noNonNullAssertion: onInsert is always defined in createSyncFunction
608
133
  await syncResult.onInsert!(params);
609
134
  }
610
135
  : undefined,
611
136
  onUpdate: config.debug
612
137
  ? async (params) => {
613
138
  console.log("onUpdate", params);
614
- // Call the actual handler from syncResult (always defined in createSyncFunction)
615
- // biome-ignore lint/style/noNonNullAssertion: onUpdate is always defined in SyncFunctionResult
139
+ // biome-ignore lint/style/noNonNullAssertion: onUpdate is always defined in createSyncFunction
616
140
  await syncResult.onUpdate!(params);
617
141
  }
618
142
  : undefined,
619
143
  onDelete: config.debug
620
144
  ? async (params) => {
621
145
  console.log("onDelete", params);
622
- // Call the actual handler from syncResult (always defined in createSyncFunction)
623
- // biome-ignore lint/style/noNonNullAssertion: onDelete is always defined in SyncFunctionResult
146
+ // biome-ignore lint/style/noNonNullAssertion: onDelete is always defined in createSyncFunction
624
147
  await syncResult.onDelete!(params);
625
148
  }
626
149
  : undefined,
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { drizzleSqliteWasm } from "./drizzle/direct";
2
2
  export {
3
3
  sqliteCollectionOptions as drizzleCollectionOptions,
4
+ type DrizzleSqliteCollection,
5
+ type SqliteCollectionConfig,
4
6
  type SQLOperation,
5
7
  type SQLInterceptor,
6
8
  } from "./collections/sqlite-collection";