@firtoz/drizzle-durable-sqlite 2.0.0 → 2.1.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +9 -1
  3. package/dist/chunk-3XAF3IZW.js +206 -0
  4. package/dist/chunk-3XAF3IZW.js.map +1 -0
  5. package/dist/chunk-DTRYQ3SF.js +36 -0
  6. package/dist/chunk-DTRYQ3SF.js.map +1 -0
  7. package/dist/chunk-JHZRO76J.js +288 -0
  8. package/dist/chunk-JHZRO76J.js.map +1 -0
  9. package/dist/chunk-NJ7RJSGZ.js +50 -0
  10. package/dist/chunk-NJ7RJSGZ.js.map +1 -0
  11. package/dist/chunk-ONDKTPGP.js +144 -0
  12. package/dist/chunk-ONDKTPGP.js.map +1 -0
  13. package/dist/chunk-PA5TYHIW.js +73 -0
  14. package/dist/chunk-PA5TYHIW.js.map +1 -0
  15. package/dist/chunk-QHM6T5OI.js +105 -0
  16. package/dist/chunk-QHM6T5OI.js.map +1 -0
  17. package/dist/chunk-YA4MAETI.js +47 -0
  18. package/dist/chunk-YA4MAETI.js.map +1 -0
  19. package/dist/drizzle-mutation-store.d.ts +20 -0
  20. package/dist/drizzle-mutation-store.js +3 -0
  21. package/dist/drizzle-mutation-store.js.map +1 -0
  22. package/dist/drizzle-partial-sync-changelog.d.ts +20 -0
  23. package/dist/drizzle-partial-sync-changelog.js +3 -0
  24. package/dist/drizzle-partial-sync-changelog.js.map +1 -0
  25. package/dist/drizzle-partial-sync-store.d.ts +22 -0
  26. package/dist/drizzle-partial-sync-store.js +4 -0
  27. package/dist/drizzle-partial-sync-store.js.map +1 -0
  28. package/dist/durable-sqlite-collection.d.ts +41 -0
  29. package/dist/durable-sqlite-collection.js +3 -0
  30. package/dist/durable-sqlite-collection.js.map +1 -0
  31. package/dist/durable-sqlite-sync-server.d.ts +48 -0
  32. package/dist/durable-sqlite-sync-server.js +3 -0
  33. package/dist/durable-sqlite-sync-server.js.map +1 -0
  34. package/dist/index.d.ts +20 -0
  35. package/dist/index.js +10 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/partial-sync-predicate-sql.d.ts +29 -0
  38. package/dist/partial-sync-predicate-sql.js +3 -0
  39. package/dist/partial-sync-predicate-sql.js.map +1 -0
  40. package/dist/partial-sync-sqlite-db.d.ts +9 -0
  41. package/dist/partial-sync-sqlite-db.js +3 -0
  42. package/dist/partial-sync-sqlite-db.js.map +1 -0
  43. package/dist/queryable-durable-object.d.ts +128 -0
  44. package/dist/queryable-durable-object.js +3 -0
  45. package/dist/queryable-durable-object.js.map +1 -0
  46. package/dist/syncable-durable-object.d.ts +58 -0
  47. package/dist/syncable-durable-object.js +4 -0
  48. package/dist/syncable-durable-object.js.map +1 -0
  49. package/package.json +20 -18
  50. package/src/durable-sqlite-collection.ts +4 -4
@@ -0,0 +1,22 @@
1
+ import { PartialSyncRowShape, PartialSyncServerBridgeStore } from '@firtoz/collection-sync';
2
+ import { InferSelectModel } from 'drizzle-orm';
3
+ import { SQLiteTable } from 'drizzle-orm/sqlite-core';
4
+ import { DrizzleChangelogHelper } from './drizzle-partial-sync-changelog.js';
5
+ import { PartialSyncSqliteDatabase } from './partial-sync-sqlite-db.js';
6
+ import { PartialSyncTableConfig } from './partial-sync-predicate-sql.js';
7
+ import 'drizzle-orm/durable-sqlite';
8
+
9
+ type CreateDrizzlePartialSyncStoreOptions<TSchema extends Record<string, unknown>, TRow extends PartialSyncRowShape> = {
10
+ db: PartialSyncSqliteDatabase<TSchema>;
11
+ table: SQLiteTable;
12
+ columnConfig: PartialSyncTableConfig;
13
+ changelogHelper: DrizzleChangelogHelper<TSchema>;
14
+ deserializeJson: (raw: string) => unknown;
15
+ /** Column name on `table` used for `changesSince` watermark (e.g. `updatedAt`). */
16
+ updatedAtColumnName: keyof TRow & string;
17
+ };
18
+ declare function createDrizzlePartialSyncStore<TSchema extends Record<string, unknown>, TRow extends PartialSyncRowShape>(options: CreateDrizzlePartialSyncStoreOptions<TSchema, TRow>): PartialSyncServerBridgeStore<TRow>;
19
+ /** Infer row type from a Drizzle SQLite table. */
20
+ type InferPartialSyncRow<TTable extends SQLiteTable> = InferSelectModel<TTable>;
21
+
22
+ export { type CreateDrizzlePartialSyncStoreOptions, type InferPartialSyncRow, createDrizzlePartialSyncStore };
@@ -0,0 +1,4 @@
1
+ export { createDrizzlePartialSyncStore } from './chunk-JHZRO76J.js';
2
+ import './chunk-QHM6T5OI.js';
3
+ //# sourceMappingURL=drizzle-partial-sync-store.js.map
4
+ //# sourceMappingURL=drizzle-partial-sync-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"drizzle-partial-sync-store.js"}
@@ -0,0 +1,41 @@
1
+ import { SyncMode, CollectionConfig, InferSchemaOutput } from '@tanstack/db';
2
+ import { Table } from 'drizzle-orm';
3
+ import { DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
4
+ import { CollectionUtils } from '@firtoz/db-helpers';
5
+ import { TableWithRequiredFields, SQLInterceptor, SelectSchema, IdOf, InsertToSelectSchema } from '@firtoz/drizzle-utils';
6
+ export { SQLInterceptor, SQLOperation } from '@firtoz/drizzle-utils';
7
+
8
+ /**
9
+ * Drizzle database type for `drizzle-orm/durable-sqlite` (Cloudflare DO SQLite).
10
+ */
11
+ type AnyDurableSqliteDatabase = DrizzleSqliteDODatabase<Record<string, unknown>>;
12
+ type DurableDrizzleSchema<TDrizzle extends AnyDurableSqliteDatabase> = TDrizzle["_"]["fullSchema"];
13
+ interface DurableSqliteCollectionConfig<TDrizzle extends AnyDurableSqliteDatabase, TTableName extends ValidTableNames<DurableDrizzleSchema<TDrizzle>>> {
14
+ drizzle: TDrizzle;
15
+ tableName: ValidTableNames<DurableDrizzleSchema<TDrizzle>> extends never ? {
16
+ $error: "The schema needs to include at least one table that uses the syncableTable function.";
17
+ } : TTableName;
18
+ /**
19
+ * Await before running sync queries (e.g. migrations finishing). Omit or leave undefined to use an already-resolved promise (no extra wait).
20
+ */
21
+ readyPromise?: Promise<void>;
22
+ syncMode?: SyncMode;
23
+ debug?: boolean;
24
+ interceptor?: SQLInterceptor;
25
+ }
26
+ type ValidTableNames<TSchema extends Record<string, unknown>> = {
27
+ [K in keyof TSchema]: TSchema[K] extends TableWithRequiredFields ? K : never;
28
+ }[keyof TSchema];
29
+ type DurableSqliteCollectionConfigResult<TTable extends Table> = Omit<CollectionConfig<InferSchemaOutput<SelectSchema<TTable>>, IdOf<TTable>, InsertToSelectSchema<TTable>, CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>>, "utils"> & {
30
+ schema: InsertToSelectSchema<TTable>;
31
+ utils: CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>;
32
+ };
33
+ /**
34
+ * TanStack DB collection configuration for a table stored in Durable Object SQLite via Drizzle.
35
+ *
36
+ * Uses `driverMode: "sync"` internally: DO SQLite runs `transactionSync`, so mutations use
37
+ * `.all()` / `.run()` inside a synchronous transaction callback (see `createSqliteTableSyncBackend` in `@firtoz/drizzle-utils`).
38
+ */
39
+ declare function durableSqliteCollectionOptions<const TDrizzle extends AnyDurableSqliteDatabase, const TTableName extends string & ValidTableNames<DurableDrizzleSchema<TDrizzle>>, TTable extends DurableDrizzleSchema<TDrizzle>[TTableName] & TableWithRequiredFields>(config: DurableSqliteCollectionConfig<TDrizzle, TTableName>): DurableSqliteCollectionConfigResult<TTable>;
40
+
41
+ export { type AnyDurableSqliteDatabase, type DurableDrizzleSchema, type DurableSqliteCollectionConfig, type DurableSqliteCollectionConfigResult, type ValidTableNames, durableSqliteCollectionOptions };
@@ -0,0 +1,3 @@
1
+ export { durableSqliteCollectionOptions } from './chunk-YA4MAETI.js';
2
+ //# sourceMappingURL=durable-sqlite-collection.js.map
3
+ //# sourceMappingURL=durable-sqlite-collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"durable-sqlite-collection.js"}
@@ -0,0 +1,48 @@
1
+ import { SyncMessage } from '@firtoz/db-helpers';
2
+
3
+ type MutationIntent<TItem> = {
4
+ clientMutationId: string;
5
+ type: "insert";
6
+ value: TItem;
7
+ } | {
8
+ clientMutationId: string;
9
+ type: "update";
10
+ key: string | number;
11
+ value: TItem;
12
+ previousValue: TItem;
13
+ } | {
14
+ clientMutationId: string;
15
+ type: "delete";
16
+ key: string | number;
17
+ } | {
18
+ clientMutationId: string;
19
+ type: "truncate";
20
+ };
21
+ interface DurableCollectionLike<TItem> {
22
+ insert: (item: Partial<TItem>) => {
23
+ isPersisted: {
24
+ promise: Promise<void>;
25
+ };
26
+ };
27
+ update: (key: string | number, updater: (draft: TItem) => void) => {
28
+ isPersisted: {
29
+ promise: Promise<void>;
30
+ };
31
+ };
32
+ delete: (key: string | number) => {
33
+ isPersisted: {
34
+ promise: Promise<void>;
35
+ };
36
+ };
37
+ utils: {
38
+ truncate: () => Promise<void>;
39
+ };
40
+ }
41
+ declare function applyDurableMutationIntents<TItem extends {
42
+ id: string | number;
43
+ }>(collection: DurableCollectionLike<TItem>, intents: MutationIntent<TItem>[]): Promise<{
44
+ changes: SyncMessage<TItem>[];
45
+ acceptedMutationIds: string[];
46
+ }>;
47
+
48
+ export { type DurableCollectionLike, applyDurableMutationIntents };
@@ -0,0 +1,3 @@
1
+ export { applyDurableMutationIntents } from './chunk-NJ7RJSGZ.js';
2
+ //# sourceMappingURL=durable-sqlite-sync-server.js.map
3
+ //# sourceMappingURL=durable-sqlite-sync-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"durable-sqlite-sync-server.js"}
@@ -0,0 +1,20 @@
1
+ export { AnyDurableSqliteDatabase, DurableDrizzleSchema, DurableSqliteCollectionConfig, DurableSqliteCollectionConfigResult, ValidTableNames, durableSqliteCollectionOptions } from './durable-sqlite-collection.js';
2
+ export { DurableCollectionLike, applyDurableMutationIntents } from './durable-sqlite-sync-server.js';
3
+ export { SyncableDurableObject, SyncableDurableObjectConfig, SyncableDurableObjectSyncRow } from './syncable-durable-object.js';
4
+ export { QueryableDurableObject, QueryableDurableObjectConfig } from './queryable-durable-object.js';
5
+ export { ChangelogOperation, DrizzleChangelogHelper, DrizzleChangelogHelperOptions, createDrizzleChangelogHelper } from './drizzle-partial-sync-changelog.js';
6
+ export { PartialSyncSqliteDatabase } from './partial-sync-sqlite-db.js';
7
+ export { CreateDrizzleMutationStoreOptions, createDrizzleMutationStore } from './drizzle-mutation-store.js';
8
+ export { CreateDrizzlePartialSyncStoreOptions, InferPartialSyncRow, createDrizzlePartialSyncStore } from './drizzle-partial-sync-store.js';
9
+ export { PartialSyncColumnKind, PartialSyncTableColumnConfig, PartialSyncTableConfig, coercePredicateScalar, columnRefForPredicate, predicateWhereFromConditions, rangeConditionToSQL, sortColumnFromConfig } from './partial-sync-predicate-sql.js';
10
+ export { SQLInterceptor, SQLOperation } from '@firtoz/drizzle-utils';
11
+ import '@tanstack/db';
12
+ import 'drizzle-orm';
13
+ import 'drizzle-orm/durable-sqlite';
14
+ import '@firtoz/db-helpers';
15
+ import 'hono/hono-base';
16
+ import 'hono/utils/http-status';
17
+ import '@firtoz/collection-sync';
18
+ import 'drizzle-orm/durable-sqlite/migrator';
19
+ import '@firtoz/websocket-do';
20
+ import 'drizzle-orm/sqlite-core';
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export { QueryableDurableObject } from './chunk-3XAF3IZW.js';
2
+ export { SyncableDurableObject } from './chunk-ONDKTPGP.js';
3
+ export { createDrizzleMutationStore } from './chunk-PA5TYHIW.js';
4
+ export { createDrizzleChangelogHelper } from './chunk-DTRYQ3SF.js';
5
+ export { createDrizzlePartialSyncStore } from './chunk-JHZRO76J.js';
6
+ export { durableSqliteCollectionOptions } from './chunk-YA4MAETI.js';
7
+ export { applyDurableMutationIntents } from './chunk-NJ7RJSGZ.js';
8
+ export { coercePredicateScalar, columnRefForPredicate, predicateWhereFromConditions, rangeConditionToSQL, sortColumnFromConfig } from './chunk-QHM6T5OI.js';
9
+ //# sourceMappingURL=index.js.map
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,29 @@
1
+ import { RangeCondition } from '@firtoz/collection-sync';
2
+ import { SQL } from 'drizzle-orm';
3
+ import { SQLiteTable, SQLiteColumn } from 'drizzle-orm/sqlite-core';
4
+
5
+ /** Column kind for predicate coercion and sort. */
6
+ type PartialSyncColumnKind = "text" | "integer";
7
+ type PartialSyncTableColumnConfig = {
8
+ kind: PartialSyncColumnKind;
9
+ /**
10
+ * When kind is `integer`, use `Math.trunc` after `Number()` (grid coordinates).
11
+ * Default false: finite number only.
12
+ */
13
+ truncateInteger?: boolean;
14
+ };
15
+ /**
16
+ * Declares which table columns exist for predicates/sorts and how to coerce literals.
17
+ * `sortableColumns` must be a subset of keys in `columns`.
18
+ */
19
+ type PartialSyncTableConfig<TSortable extends string = string> = {
20
+ columns: Record<string, PartialSyncTableColumnConfig>;
21
+ sortableColumns: readonly TSortable[];
22
+ };
23
+ declare function columnRefForPredicate(table: SQLiteTable, columnName: string, columnConfig: PartialSyncTableConfig): SQLiteColumn;
24
+ declare function coercePredicateScalar(column: string, value: unknown, columnConfig: PartialSyncTableConfig): string | number;
25
+ declare function rangeConditionToSQL(table: SQLiteTable, condition: RangeCondition, columnConfig: PartialSyncTableConfig): SQL;
26
+ declare function predicateWhereFromConditions(table: SQLiteTable, conditions: RangeCondition[], columnConfig: PartialSyncTableConfig): SQL | undefined;
27
+ declare function sortColumnFromConfig(table: SQLiteTable, columnName: string, columnConfig: PartialSyncTableConfig): SQLiteColumn;
28
+
29
+ export { type PartialSyncColumnKind, type PartialSyncTableColumnConfig, type PartialSyncTableConfig, coercePredicateScalar, columnRefForPredicate, predicateWhereFromConditions, rangeConditionToSQL, sortColumnFromConfig };
@@ -0,0 +1,3 @@
1
+ export { coercePredicateScalar, columnRefForPredicate, predicateWhereFromConditions, rangeConditionToSQL, sortColumnFromConfig } from './chunk-QHM6T5OI.js';
2
+ //# sourceMappingURL=partial-sync-predicate-sql.js.map
3
+ //# sourceMappingURL=partial-sync-predicate-sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-predicate-sql.js"}
@@ -0,0 +1,9 @@
1
+ import { DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
2
+
3
+ /**
4
+ * Drizzle Durable Object SQLite database used by partial-sync helpers.
5
+ * (Bun/libsql drivers differ in `select` overloads; use DO SQLite in Workers.)
6
+ */
7
+ type PartialSyncSqliteDatabase<TSchema extends Record<string, unknown>> = DrizzleSqliteDODatabase<TSchema>;
8
+
9
+ export type { PartialSyncSqliteDatabase };
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=partial-sync-sqlite-db.js.map
3
+ //# sourceMappingURL=partial-sync-sqlite-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"partial-sync-sqlite-db.js"}
@@ -0,0 +1,128 @@
1
+ import * as hono_hono_base from 'hono/hono-base';
2
+ import * as hono_utils_http_status from 'hono/utils/http-status';
3
+ import { PartialSyncRowShape, SyncServerMessage, SyncClientMessage, PartialSyncServerBridge, PartialSyncMutationHandler, PartialSyncServerBridgeStore, RangeCondition, SyncRange, SyncRangeSort, SyncServerBridgeStore } from '@firtoz/collection-sync';
4
+ import { SyncMessage } from '@firtoz/db-helpers';
5
+ import { StandardSchemaWebSocketDO, StandardSchemaSession, StandardSchemaSessionOptions } from '@firtoz/websocket-do';
6
+ import { drizzle, DrizzleSqliteDODatabase } from 'drizzle-orm/durable-sqlite';
7
+ import { migrate } from 'drizzle-orm/durable-sqlite/migrator';
8
+
9
+ type SessionData = {
10
+ clientId: string;
11
+ };
12
+ type MutationSyncRow = PartialSyncRowShape;
13
+ type SessionDispatch<TRow extends MutationSyncRow> = {
14
+ partialBridge: PartialSyncServerBridge<TRow>;
15
+ partialMutationHandler?: PartialSyncMutationHandler<TRow>;
16
+ };
17
+ type SessionSlot<TRow extends MutationSyncRow> = {
18
+ dispatch?: SessionDispatch<TRow>;
19
+ pending: SyncClientMessage[];
20
+ };
21
+ declare class QueryableSession<TItem extends PartialSyncRowShape, TEnv extends Cloudflare.Env> extends StandardSchemaSession<SessionData, SyncServerMessage<TItem>, SyncClientMessage, TEnv> {
22
+ private readonly sessionSlot;
23
+ clientId: string;
24
+ constructor(websocket: WebSocket, sessions: Map<WebSocket, QueryableSession<TItem, TEnv>>, options: StandardSchemaSessionOptions<SyncClientMessage, SyncServerMessage<TItem>>, sessionSlot: SessionSlot<TItem>);
25
+ }
26
+ type QueryableDurableObjectConfig<TSchema extends Record<string, unknown>, TRow extends PartialSyncRowShape = PartialSyncRowShape> = {
27
+ schema: TSchema;
28
+ migrations: Parameters<typeof migrate>[1];
29
+ queryChunkSize?: number;
30
+ seedInBackground?: boolean;
31
+ serializeJson?: (value: unknown) => string;
32
+ deserializeJson?: (raw: string) => unknown;
33
+ /**
34
+ * When set, used as the partial-sync store instead of overriding
35
+ * {@link QueryableDurableObject.queryRange}, {@link QueryableDurableObject.queryByOffset},
36
+ * and {@link QueryableDurableObject.getTotalCount}.
37
+ */
38
+ createPartialSyncStore?: (db: DrizzleSqliteDODatabase<TSchema>) => PartialSyncServerBridgeStore<TRow>;
39
+ /**
40
+ * Multiplex key for partial-sync WebSocket messages.
41
+ * When using {@link PartialSyncMutationHandler} on the same socket, use the same id unless you multiplex multiple collections.
42
+ */
43
+ collectionId?: string;
44
+ /**
45
+ * Server-side narrowing of client predicate viewports (e.g. fog of war). Passed to
46
+ * {@link PartialSyncServerBridge}.
47
+ */
48
+ resolveClientVisibility?: (clientId: string, requestedConditions: RangeCondition[]) => RangeCondition[] | Promise<RangeCondition[]>;
49
+ /**
50
+ * Optional hints for rows that left the client's range during `rangeReconcile`. Return `null` for
51
+ * fog of war (default when omitted).
52
+ */
53
+ resolveMovedHint?: (row: TRow, range: SyncRange) => Record<string, unknown> | null | Promise<Record<string, unknown> | null>;
54
+ };
55
+ declare abstract class QueryableDurableObject<TRow extends PartialSyncRowShape, TSchema extends Record<string, unknown>, TEnv extends Cloudflare.Env = Cloudflare.Env> extends StandardSchemaWebSocketDO<QueryableSession<TRow, TEnv>, SyncClientMessage, SyncServerMessage<TRow>, TEnv> {
56
+ protected db: ReturnType<typeof drizzle>;
57
+ protected bridge: PartialSyncServerBridge<TRow>;
58
+ protected partialMutationHandler?: PartialSyncMutationHandler<TRow>;
59
+ readonly app: hono_hono_base.HonoBase<{
60
+ Bindings: TEnv;
61
+ }, {
62
+ "/websocket": {
63
+ $get: {
64
+ input: {};
65
+ output: {};
66
+ outputFormat: string;
67
+ status: hono_utils_http_status.StatusCode;
68
+ };
69
+ };
70
+ } & {
71
+ "/health": {
72
+ $get: {
73
+ input: {};
74
+ output: "ok";
75
+ outputFormat: "text";
76
+ status: hono_utils_http_status.ContentfulStatusCode;
77
+ };
78
+ };
79
+ }, "/", "/health">;
80
+ constructor(ctx: DurableObjectState, env: TEnv, config: QueryableDurableObjectConfig<TSchema, TRow>);
81
+ protected queryRange(_options: {
82
+ sort: {
83
+ column: string;
84
+ direction: "asc" | "desc";
85
+ };
86
+ limit: number;
87
+ afterCursor: unknown | null;
88
+ chunkSize: number;
89
+ }): AsyncIterable<TRow[]>;
90
+ protected queryByOffset(_options: {
91
+ sort: {
92
+ column: string;
93
+ direction: "asc" | "desc";
94
+ };
95
+ limit: number;
96
+ offset: number;
97
+ chunkSize: number;
98
+ }): AsyncIterable<TRow[]>;
99
+ protected getTotalCount(): Promise<number>;
100
+ protected queryByPredicate?(_options: {
101
+ conditions: RangeCondition[];
102
+ sort?: SyncRangeSort;
103
+ limit?: number;
104
+ chunkSize: number;
105
+ }): AsyncIterable<TRow[]>;
106
+ protected getPredicateCount?(_conditions: RangeCondition[]): Promise<number>;
107
+ protected changesSince?(_options: {
108
+ range: SyncRange;
109
+ sinceVersion: number;
110
+ chunkSize: number;
111
+ }): Promise<{
112
+ changes: SyncMessage<TRow>[];
113
+ totalCount: number;
114
+ } | null>;
115
+ protected getSortValue(row: TRow, column: string): unknown;
116
+ /**
117
+ * When overridden to return a store, `mutateBatch` is handled by {@link PartialSyncMutationHandler}
118
+ * (interest-scoped `rangePatch` + `ack` with `serverVersion: 0`). `syncHello` is not handled on this path.
119
+ * Range traffic stays on {@link PartialSyncServerBridge}.
120
+ */
121
+ protected createClientMutationSyncStore(): SyncServerBridgeStore<TRow> | undefined;
122
+ protected seedData(): Promise<void>;
123
+ pushServerChanges(changes: SyncMessage<TRow>[]): Promise<void>;
124
+ protected sendToClient(clientId: string, message: SyncServerMessage<TRow>): void;
125
+ protected broadcastExcept(excludeClientId: string, message: SyncServerMessage<TRow>): void;
126
+ }
127
+
128
+ export { QueryableDurableObject, type QueryableDurableObjectConfig };
@@ -0,0 +1,3 @@
1
+ export { QueryableDurableObject } from './chunk-3XAF3IZW.js';
2
+ //# sourceMappingURL=queryable-durable-object.js.map
3
+ //# sourceMappingURL=queryable-durable-object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"queryable-durable-object.js"}
@@ -0,0 +1,58 @@
1
+ import * as hono_hono_base from 'hono/hono-base';
2
+ import * as hono_utils_http_status from 'hono/utils/http-status';
3
+ import { SyncClientMessage, SyncServerMessage, SyncServerBridge, PartialSyncRowShape } from '@firtoz/collection-sync';
4
+ import { InferSchemaOutput, SyncMode } from '@tanstack/db';
5
+ import { migrate } from 'drizzle-orm/durable-sqlite/migrator';
6
+ import { TableWithRequiredFields, SelectSchema, DrizzleSqliteTableCollection } from '@firtoz/drizzle-utils';
7
+ import { StandardSchemaWebSocketDO } from '@firtoz/websocket-do';
8
+ import { ValidTableNames } from './durable-sqlite-collection.js';
9
+ import 'drizzle-orm';
10
+ import 'drizzle-orm/durable-sqlite';
11
+ import '@firtoz/db-helpers';
12
+
13
+ /**
14
+ * Drizzle/Valibot `InferSchemaOutput` is not always structurally assignable to
15
+ * {@link PartialSyncRowShape}. Intersecting keeps inferred columns while requiring sync row keys for
16
+ * {@link SyncServerBridge}.
17
+ */
18
+ type SyncBridgeRowFromTable<TTable extends TableWithRequiredFields> = InferSchemaOutput<SelectSchema<TTable>> & PartialSyncRowShape;
19
+ type SyncableDurableObjectSyncRow<TSchema extends Record<string, unknown>, TTableName extends ValidTableNames<TSchema>> = SyncBridgeRowFromTable<TSchema[TTableName] & TableWithRequiredFields>;
20
+ type SyncableDurableObjectConfig<TSchema extends Record<string, unknown>, TTableName extends ValidTableNames<TSchema>> = {
21
+ schema: TSchema;
22
+ tableName: TTableName;
23
+ migrations: Parameters<typeof migrate>[1];
24
+ syncMode?: SyncMode;
25
+ serializeJson?: (value: unknown) => string;
26
+ deserializeJson?: (raw: string) => unknown;
27
+ };
28
+ /**
29
+ * Durable Object base class: Drizzle SQLite + {@link SyncServerBridge} + WebSocket sessions.
30
+ */
31
+ declare abstract class SyncableDurableObject<TSchema extends Record<string, unknown>, TTableName extends ValidTableNames<TSchema>, TEnv extends Cloudflare.Env = Cloudflare.Env> extends StandardSchemaWebSocketDO<any, SyncClientMessage, SyncServerMessage<unknown>, TEnv> {
32
+ protected bridge: SyncServerBridge<SyncableDurableObjectSyncRow<TSchema, TTableName>>;
33
+ protected collection: DrizzleSqliteTableCollection<TSchema[TTableName] & TableWithRequiredFields>;
34
+ readonly app: hono_hono_base.HonoBase<{
35
+ Bindings: TEnv;
36
+ }, {
37
+ "/websocket": {
38
+ $get: {
39
+ input: {};
40
+ output: {};
41
+ outputFormat: string;
42
+ status: hono_utils_http_status.StatusCode;
43
+ };
44
+ };
45
+ } & {
46
+ "/health": {
47
+ $get: {
48
+ input: {};
49
+ output: "ok";
50
+ outputFormat: "text";
51
+ status: hono_utils_http_status.ContentfulStatusCode;
52
+ };
53
+ };
54
+ }, "/", "/health">;
55
+ constructor(ctx: DurableObjectState, env: TEnv, config: SyncableDurableObjectConfig<TSchema, TTableName>);
56
+ }
57
+
58
+ export { SyncableDurableObject, type SyncableDurableObjectConfig, type SyncableDurableObjectSyncRow };
@@ -0,0 +1,4 @@
1
+ export { SyncableDurableObject } from './chunk-ONDKTPGP.js';
2
+ import './chunk-YA4MAETI.js';
3
+ //# sourceMappingURL=syncable-durable-object.js.map
4
+ //# sourceMappingURL=syncable-durable-object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"syncable-durable-object.js"}
package/package.json CHANGED
@@ -1,35 +1,37 @@
1
1
  {
2
2
  "name": "@firtoz/drizzle-durable-sqlite",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "TanStack DB collections backed by Drizzle on Cloudflare Durable Object SQLite",
5
- "main": "./src/index.ts",
6
- "module": "./src/index.ts",
7
- "types": "./src/index.ts",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
8
  "type": "module",
9
9
  "exports": {
10
10
  ".": {
11
- "types": "./src/index.ts",
12
- "import": "./src/index.ts",
13
- "require": "./src/index.ts"
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
14
13
  },
15
14
  "./durableSqliteCollectionOptions": {
16
- "types": "./src/durable-sqlite-collection.ts",
17
- "import": "./src/durable-sqlite-collection.ts",
18
- "require": "./src/durable-sqlite-collection.ts"
15
+ "types": "./dist/durable-sqlite-collection.d.ts",
16
+ "import": "./dist/durable-sqlite-collection.js"
19
17
  },
20
18
  "./*": {
21
- "types": "./src/*.ts",
22
- "import": "./src/*.ts",
23
- "require": "./src/*.ts"
19
+ "types": "./dist/*.d.ts",
20
+ "import": "./dist/*.js"
24
21
  }
25
22
  },
26
23
  "files": [
24
+ "dist/**/*.js",
25
+ "dist/**/*.js.map",
26
+ "dist/**/*.d.ts",
27
27
  "src/**/*.ts",
28
28
  "!src/**/*.test.ts",
29
29
  "README.md",
30
30
  "CHANGELOG.md"
31
31
  ],
32
32
  "scripts": {
33
+ "build": "tsup",
34
+ "prepack": "bun run build",
33
35
  "typecheck": "tsgo --noEmit -p ./tsconfig.json",
34
36
  "lint": "biome check --write src",
35
37
  "lint:ci": "biome ci src",
@@ -68,11 +70,11 @@
68
70
  "valibot": ">=1.3.1"
69
71
  },
70
72
  "dependencies": {
71
- "@firtoz/collection-sync": "^5.0.0",
72
- "@firtoz/db-helpers": "^2.1.1",
73
- "@firtoz/drizzle-utils": "^1.2.1",
74
- "@firtoz/maybe-error": "^1.5.2",
75
- "@firtoz/websocket-do": "^12.0.0"
73
+ "@firtoz/collection-sync": "^6.0.0",
74
+ "@firtoz/db-helpers": "^2.2.0",
75
+ "@firtoz/drizzle-utils": "^1.3.0",
76
+ "@firtoz/maybe-error": "^1.6.0",
77
+ "@firtoz/websocket-do": "^13.0.0"
76
78
  },
77
79
  "devDependencies": {
78
80
  "@cloudflare/workers-types": "^4.20260329.1",
@@ -16,7 +16,6 @@ import type {
16
16
  import {
17
17
  createSyncFunction,
18
18
  createInsertSchemaWithIdDefault,
19
- createGetKeyFunction,
20
19
  createCollectionConfig,
21
20
  createSqliteTableSyncBackend,
22
21
  type SQLOperation,
@@ -90,8 +89,9 @@ export function durableSqliteCollectionOptions<
90
89
 
91
90
  const table = config.drizzle._.fullSchema[tableName] as TTable;
92
91
 
93
- type TItem = InferSchemaOutput<SelectSchema<TTable>>;
94
- const getKey = createGetKeyFunction<TTable>();
92
+ const getKey = (
93
+ item: InferSchemaOutput<SelectSchema<TTable>>,
94
+ ): IdOf<TTable> => (item as { id: IdOf<TTable> }).id;
95
95
 
96
96
  const backend = createSqliteTableSyncBackend({
97
97
  drizzle: config.drizzle,
@@ -107,7 +107,7 @@ export function durableSqliteCollectionOptions<
107
107
  readyPromise: config.readyPromise ?? Promise.resolve(),
108
108
  syncMode: config.syncMode,
109
109
  debug: config.debug,
110
- getSyncPersistKey: (item: TItem) => String(getKey(item)),
110
+ getSyncPersistKey: (item) => String(getKey(item)),
111
111
  };
112
112
 
113
113
  const syncResult = createSyncFunction(baseSyncConfig, backend);