event-sourced-collection 0.0.8 → 0.0.9

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.
@@ -1,6 +1,36 @@
1
- import { a as BrowserPlatformConfig, c as BrowserWASQLiteDatabase, i as BrowserCoordinatorInstance, n as BrowserEventSourcedModules, o as BrowserPlatformDeps, r as createBrowserEventSourcedDB, s as BrowserPlatformResult, t as BrowserEventSourcedDBConfig } from "./browser-event-sourced-db-CCOAgE31.mjs";
2
- import { t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos-9pS.mjs";
1
+ import { L as SyncLock, P as SQLiteDriver, Q as InjectedModuleFn, Z as InjectedCreateCollection, p as EventSourcedSharedOptions } from "./types-BSdudVLh.mjs";
2
+ import { r as ModulesInput, t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos-9pS.mjs";
3
+ import { PersistedCollectionPersistence } from "@tanstack/db-sqlite-persistence-core";
3
4
 
5
+ //#region src/platforms/browser-wa-sqlite-driver.d.ts
6
+ type BrowserWASQLiteDatabase = {
7
+ execute: <TRow = unknown>(sql: string, params?: ReadonlyArray<unknown>) => Promise<ReadonlyArray<TRow>>;
8
+ close?: () => Promise<void> | void;
9
+ };
10
+ //#endregion
11
+ //#region src/platforms/browser-types.d.ts
12
+ type BrowserCoordinatorInstance = {
13
+ dispose: () => void;
14
+ };
15
+ /**
16
+ * Injected TanStack browser persistence bindings. Parameters are `never` so
17
+ * version-skewed `@tanstack/browser-db-sqlite-persistence` exports stay assignable.
18
+ */
19
+ type BrowserPlatformDeps = {
20
+ openBrowserWASQLiteOPFSDatabase: (options: never) => Promise<BrowserWASQLiteDatabase>;
21
+ createBrowserWASQLitePersistence: (options: never) => PersistedCollectionPersistence;
22
+ BrowserCollectionCoordinator: new (options: never) => BrowserCoordinatorInstance;
23
+ };
24
+ type BrowserPlatformConfig = {
25
+ databaseName: string;
26
+ coordinatorDbName?: string;
27
+ };
28
+ type BrowserPlatformResult = {
29
+ driver: SQLiteDriver;
30
+ persistence: PersistedCollectionPersistence;
31
+ close: () => Promise<void>;
32
+ };
33
+ //#endregion
4
34
  //#region src/platforms/browser.d.ts
5
35
  /**
6
36
  * Opens OPFS SQLite, a cross-tab coordinator, and TanStack persistence.
@@ -31,5 +61,91 @@ import { t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos
31
61
  */
32
62
  declare function createBrowserPlatform(deps: BrowserPlatformDeps, config: BrowserPlatformConfig): Promise<BrowserPlatformResult>;
33
63
  //#endregion
64
+ //#region src/platforms/browser-event-sourced-db.d.ts
65
+ type CollectionDefConstraint = {
66
+ getKey: (state: never) => string | number;
67
+ };
68
+ type BrowserEventSourcedModules = BrowserPlatformDeps & {
69
+ createCollection: InjectedCreateCollection;
70
+ persistedCollectionOptions: InjectedModuleFn;
71
+ };
72
+ /**
73
+ * Browser entry-point config. Shared sync/lifecycle fields come from
74
+ * {@link EventSourcedSharedOptions} (hover those properties for docs).
75
+ * Deep guide: `docs/usage.md`.
76
+ */
77
+ type BrowserEventSourcedDBConfig<TDefs extends Record<string, CollectionDefConstraint>> = Omit<EventSourcedSharedOptions, "lock" | "lockName"> & {
78
+ /**
79
+ * User collection registry. Object keys become `db.collections.<key>` and
80
+ * the wire `collectionId`. Must not collide with reserved names.
81
+ */
82
+ collections: TDefs;
83
+ /**
84
+ * OPFS SQLite database file name (e.g. `"my-app.sqlite"`). Also used as the
85
+ * default sync lock namespace so only one tab syncs for this DB at a time.
86
+ */
87
+ databaseName: string;
88
+ /**
89
+ * Name for the cross-tab collection coordinator database. Defaults to
90
+ * `databaseName` with a trailing `.sqlite` stripped.
91
+ */
92
+ coordinatorDbName?: string;
93
+ /**
94
+ * Browser OPFS persistence modules from
95
+ * `@tanstack/browser-db-sqlite-persistence` plus `createCollection`.
96
+ * Pass the imported bindings directly, or a function to keep WASM off the
97
+ * critical path.
98
+ */
99
+ modules: ModulesInput<BrowserEventSourcedModules>;
100
+ /**
101
+ * Defaults to a Web Locks–backed lock so only one tab syncs at a time.
102
+ * Pass `null` to opt out and let every tab sync independently.
103
+ */
104
+ lock?: SyncLock | null;
105
+ };
106
+ /**
107
+ * Browser-flavoured event-sourced DB: OPFS SQLite + optional Web Locks sync
108
+ * election, returned as a lazy singleton.
109
+ *
110
+ * @param config - See {@link BrowserEventSourcedDBConfig} for every option.
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * import { createBrowserEventSourcedDB } from "event-sourced-collection/browser"
115
+ * import type { CollectionDef, EventSourcedDB } from "event-sourced-collection"
116
+ *
117
+ * type Todo = { id: string; title: string }
118
+ * type Defs = { todos: CollectionDef<Todo, string> }
119
+ *
120
+ * const { ensureDb, db } = createBrowserEventSourcedDB<Defs>({
121
+ * databaseName: "app.sqlite",
122
+ * collections: { todos: { getKey: (todo) => todo.id } },
123
+ * sync: { push: "/api/sync/events", pull: "/api/sync/events" },
124
+ * modules: async () => {
125
+ * const { createCollection } = await import("@tanstack/db")
126
+ * const {
127
+ * BrowserCollectionCoordinator,
128
+ * createBrowserWASQLitePersistence,
129
+ * openBrowserWASQLiteOPFSDatabase,
130
+ * persistedCollectionOptions,
131
+ * } = await import("@tanstack/browser-db-sqlite-persistence")
132
+ * return {
133
+ * createCollection,
134
+ * BrowserCollectionCoordinator,
135
+ * createBrowserWASQLitePersistence,
136
+ * openBrowserWASQLiteOPFSDatabase,
137
+ * persistedCollectionOptions,
138
+ * }
139
+ * },
140
+ * })
141
+ *
142
+ * export async function start() {
143
+ * await ensureDb()
144
+ * }
145
+ * export { db }
146
+ * ```
147
+ */
148
+ declare function createBrowserEventSourcedDB<const TDefs extends Record<string, CollectionDefConstraint>>(config: BrowserEventSourcedDBConfig<TDefs>): EventSourcedDBHandle<TDefs>;
149
+ //#endregion
34
150
  export { type BrowserCoordinatorInstance, type BrowserEventSourcedDBConfig, type EventSourcedDBHandle as BrowserEventSourcedDBHandle, type BrowserEventSourcedModules, type BrowserPlatformConfig, type BrowserPlatformDeps, type BrowserPlatformResult, type BrowserWASQLiteDatabase, createBrowserEventSourcedDB, createBrowserPlatform };
35
151
  //# sourceMappingURL=browser.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.mts","names":[],"sources":["../src/platforms/browser.ts"],"mappings":";;;;;AA2CA;;;;;;;;;;;;;;;;AAGgC;;;;;;;;;;iBAHV,qBAAA,CACpB,IAAA,EAAM,mBAAA,EACN,MAAA,EAAQ,qBAAA,GACP,OAAA,CAAQ,qBAAA"}
1
+ {"version":3,"file":"browser.d.mts","names":[],"sources":["../src/platforms/browser-wa-sqlite-driver.ts","../src/platforms/browser-types.ts","../src/platforms/browser.ts","../src/platforms/browser-event-sourced-db.ts"],"mappings":";;;;;KAEY,uBAAA;EACV,OAAA,mBACE,GAAA,UACA,MAAA,GAAS,aAAA,cACN,OAAA,CAAQ,aAAA,CAAc,IAAA;EAC3B,KAAA,SAAc,OAAA;AAAA;;;KCJJ,0BAAA;EACV,OAAO;AAAA;;ADFT;;;KCSY,mBAAA;EACV,+BAAA,GAAkC,OAAA,YAAmB,OAAA,CAAQ,uBAAA;EAC7D,gCAAA,GAAmC,OAAA,YAAmB,8BAAA;EACtD,4BAAA,OAAmC,OAAA,YAAmB,0BAAA;AAAA;AAAA,KAG5C,qBAAA;EACV,YAAA;EACA,iBAAiB;AAAA;AAAA,KAGP,qBAAA;EACV,MAAA,EAD+B,YAAA;EAE/B,WAAA,EAAa,8BAAA;EACb,KAAA,QAAa,OAAA;AAAA;;;;;;ADvBf;;;;;;;;;;;;;;;;;;;;;AAKuB;;;iBEoCD,qBAAA,CACpB,IAAA,EAAM,mBAAA,EACN,MAAA,EAAQ,qBAAA,GACP,OAAA,CAAQ,qBAAA;;;KC9BN,uBAAA;EACH,MAAA,GAAS,KAAY;AAAA;AAAA,KAGX,0BAAA,GAA6B,mBAAA;EACvC,gBAAA,EAAkB,wBAAA;EAClB,0BAAA,EAA4B,gBAAA;AAAA;;;;;;KAQlB,2BAAA,eAA0C,MAAA,SAAe,uBAAA,KACnE,IAAA,CAAK,yBAAA;EH5BK;;;;EGiCR,WAAA,EAAa,KAAA;EH9BF;;;;EGmCX,YAAA;EHlCmB;;;;EGuCnB,iBAAA;EF3CkC;;;AAC7B;AAOT;;EE0CI,OAAA,EAAS,YAAA,CAAa,0BAAA;EFzCqC;;;;EE8C3D,IAAA,GAAO,QAAA;AAAA;;;;;;;;;;;AF5CuE;AAGlF;;;;AAEmB;AAGnB;;;;;;;;;;;;;;;AAGsB;;;;ACkBtB;;;;;;;iBC8DgB,2BAAA,qBACM,MAAA,SAAe,uBAAA,GACnC,MAAA,EAAQ,2BAAA,CAA4B,KAAA,IAAM,oBAAA,CAAA,KAAA"}
package/dist/node.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Q as InjectedModuleFn, S as PersistedCollectionPersistence, Z as InjectedCreateCollection, p as EventSourcedSharedOptions } from "./types-BSdudVLh.mjs";
2
2
  import { r as ModulesInput, t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos-9pS.mjs";
3
-
4
3
  //#region src/platforms/node.d.ts
5
4
  type NodePlatformDeps = {
6
5
  createNodeSQLitePersistence: (options: {
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.mts","names":[],"sources":["../src/platforms/node.ts","../src/platforms/node-event-sourced-db.ts"],"mappings":";;;;KAEY,gBAAA;EACV,2BAAA,GAA8B,OAAA;IAAW,QAAA;EAAA,MAAsB,8BAA8B;AAAA;AAAA,KAGnF,kBAAA;EACV,QAAQ;AAAA;AAAA,KAGE,kBAAA;EACV,WAAA,EAAa,8BAA8B;AAAA;;;AARkD;AAG/F;;;;AACU;AAGV;;;;AAC6C;AA6B7C;;;;;;;;;;;;;iBAAgB,kBAAA,CACd,IAAA,EAAM,gBAAA,EACN,MAAA,EAAQ,kBAAA,GACP,kBAAA;;;KC7BE,uBAAA;EACH,MAAA,GAAS,KAAY;AAAA;AAAA,KAGX,uBAAA;EACV,2BAAA,GAA8B,OAAA;IAAW,QAAA;EAAA,MAAsB,8BAAA,EDhBtB;ECkBzC,QAAA;EACA,gBAAA,EAAkB,wBAAA;EAClB,0BAAA,EAA4B,gBAAA;AAAA;AAAA,KAGlB,wBAAA,eAAuC,MAAA,SAAe,uBAAA,KAChE,yBAAA;EACE,WAAA,EAAa,KAAA;;;ADrBP;AAGV;ECuBI,OAAA,EAAS,YAAA,CAAa,uBAAA;AAAA;;ADtBmB;AA6B7C;;;;;;;;;;;;;;AAGqB;;;;AChC0E;;;;AAIxE;AAGvB;;;;;;;;;iBAoDgB,wBAAA,qBACM,MAAA,SAAe,uBAAA,GACnC,MAAA,EAAQ,wBAAA,CAAyB,KAAA,IAAM,oBAAA,CAAA,KAAA"}
1
+ {"version":3,"file":"node.d.mts","names":[],"sources":["../src/platforms/node.ts","../src/platforms/node-event-sourced-db.ts"],"mappings":";;;KAEY,gBAAA;EACV,2BAAA,GAA8B,OAAA;IAAW,QAAA;EAAA,MAAsB,8BAA8B;AAAA;AAAA,KAGnF,kBAAA;EACV,QAAQ;AAAA;AAAA,KAGE,kBAAA;EACV,WAAA,EAAa,8BAA8B;AAAA;;;AARkD;AAG/F;;;;AACU;AAGV;;;;AAC6C;AA6B7C;;;;;;;;;;;;;iBAAgB,kBAAA,CACd,IAAA,EAAM,gBAAA,EACN,MAAA,EAAQ,kBAAA,GACP,kBAAA;;;KC7BE,uBAAA;EACH,MAAA,GAAS,KAAY;AAAA;AAAA,KAGX,uBAAA;EACV,2BAAA,GAA8B,OAAA;IAAW,QAAA;EAAA,MAAsB,8BAAA,EDhBtB;ECkBzC,QAAA;EACA,gBAAA,EAAkB,wBAAA;EAClB,0BAAA,EAA4B,gBAAA;AAAA;AAAA,KAGlB,wBAAA,eAAuC,MAAA,SAAe,uBAAA,KAChE,yBAAA;EACE,WAAA,EAAa,KAAA;;;ADrBP;AAGV;ECuBI,OAAA,EAAS,YAAA,CAAa,uBAAA;AAAA;;ADtBmB;AA6B7C;;;;;;;;;;;;;;AAGqB;;;;AChC0E;;;;AAIxE;AAGvB;;;;;;;;;iBAoDgB,wBAAA,qBACM,MAAA,SAAe,uBAAA,GACnC,MAAA,EAAQ,wBAAA,CAAyB,KAAA,IAAM,oBAAA,CAAA,KAAA"}
@@ -0,0 +1,61 @@
1
+ import { Q as InjectedModuleFn, S as PersistedCollectionPersistence, Z as InjectedCreateCollection, p as EventSourcedSharedOptions } from "./types-BSdudVLh.mjs";
2
+ import { r as ModulesInput, t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos-9pS.mjs";
3
+
4
+ //#region src/platforms/react-native-event-sourced-db.d.ts
5
+ type CollectionDefConstraint = {
6
+ getKey: (state: never) => string | number;
7
+ };
8
+ type ReactNativeEventSourcedModules = {
9
+ createReactNativeSQLitePersistence: (options: {
10
+ database: never;
11
+ }) => PersistedCollectionPersistence; /** Already-opened op-sqlite (or compatible) database. */
12
+ database: unknown;
13
+ createCollection: InjectedCreateCollection;
14
+ persistedCollectionOptions: InjectedModuleFn;
15
+ };
16
+ /**
17
+ * React Native entry-point config. Shared sync/lifecycle fields come from
18
+ * {@link EventSourcedSharedOptions} (hover those properties for docs).
19
+ * Deep guide: `docs/usage.md`.
20
+ */
21
+ type ReactNativeEventSourcedDBConfig<TDefs extends Record<string, CollectionDefConstraint>> = EventSourcedSharedOptions & {
22
+ collections: TDefs;
23
+ /**
24
+ * React Native persistence modules from
25
+ * `@tanstack/react-native-db-sqlite-persistence` plus `createCollection`.
26
+ * Pass the imported bindings directly, or a function to delay native SQLite.
27
+ */
28
+ modules: ModulesInput<ReactNativeEventSourcedModules>;
29
+ };
30
+ /**
31
+ * React Native–flavoured event-sourced DB, returned as a lazy singleton.
32
+ *
33
+ * @param config - See {@link ReactNativeEventSourcedDBConfig} for every option.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { createReactNativeEventSourcedDB } from "event-sourced-collection/react-native"
38
+ *
39
+ * const { ensureDb, db } = createReactNativeEventSourcedDB({
40
+ * collections: { todos: { getKey: (todo: { id: string }) => todo.id } },
41
+ * modules: async () => {
42
+ * const { createCollection } = await import("@tanstack/react-native-db")
43
+ * const { createReactNativeSQLitePersistence, persistedCollectionOptions } =
44
+ * await import("@tanstack/react-native-db-sqlite-persistence")
45
+ * const { openDatabase } = await import("react-native-op-sqlite")
46
+ * return {
47
+ * createCollection,
48
+ * createReactNativeSQLitePersistence,
49
+ * persistedCollectionOptions,
50
+ * database: openDatabase({ name: "app.sqlite" }),
51
+ * }
52
+ * },
53
+ * })
54
+ *
55
+ * await ensureDb()
56
+ * ```
57
+ */
58
+ declare function createReactNativeEventSourcedDB<const TDefs extends Record<string, CollectionDefConstraint>>(config: ReactNativeEventSourcedDBConfig<TDefs>): EventSourcedDBHandle<TDefs>;
59
+ //#endregion
60
+ export { ReactNativeEventSourcedModules as n, createReactNativeEventSourcedDB as r, ReactNativeEventSourcedDBConfig as t };
61
+ //# sourceMappingURL=react-native-event-sourced-db-CTS4b8o9.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-native-event-sourced-db-CTS4b8o9.d.mts","names":[],"sources":["../src/platforms/react-native-event-sourced-db.ts"],"mappings":";;;;KAcK,uBAAA;EACH,MAAA,GAAS,KAAY;AAAA;AAAA,KAGX,8BAAA;EACV,kCAAA,GAAqC,OAAA;IACnC,QAAA;EAAA,MACI,8BAAA,EAHkC;EAKxC,QAAA;EACA,gBAAA,EAAkB,wBAAA;EAClB,0BAAA,EAA4B,gBAAA;AAAA;;;;;;KAQlB,+BAAA,eAA8C,MAAA,SAAe,uBAAA,KACvE,yBAAA;EACE,WAAA,EAAa,KAAA;EAXf;;;;;EAiBE,OAAA,EAAS,YAAA,CAAa,8BAAA;AAAA;;;;;;;;;;;;;;;;;;;;AAA8B;AAiCxD;;;;;;;;iBAAgB,+BAAA,qBACM,MAAA,SAAe,uBAAA,GACnC,MAAA,EAAQ,+BAAA,CAAgC,KAAA,IAAM,oBAAA,CAAA,KAAA"}
@@ -1,5 +1,6 @@
1
- import { Q as InjectedModuleFn, S as PersistedCollectionPersistence, Z as InjectedCreateCollection, p as EventSourcedSharedOptions } from "./types-BSdudVLh.mjs";
2
- import { r as ModulesInput, t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos-9pS.mjs";
1
+ import { S as PersistedCollectionPersistence } from "./types-BSdudVLh.mjs";
2
+ import { t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos-9pS.mjs";
3
+ import { n as ReactNativeEventSourcedModules, r as createReactNativeEventSourcedDB, t as ReactNativeEventSourcedDBConfig } from "./react-native-event-sourced-db-CTS4b8o9.mjs";
3
4
 
4
5
  //#region src/platforms/react-native.d.ts
5
6
  type ReactNativePlatformDeps = {
@@ -44,61 +45,5 @@ type ReactNativePlatformResult = {
44
45
  */
45
46
  declare function createReactNativePlatform(deps: ReactNativePlatformDeps, config: ReactNativePlatformConfig): ReactNativePlatformResult;
46
47
  //#endregion
47
- //#region src/platforms/react-native-event-sourced-db.d.ts
48
- type CollectionDefConstraint = {
49
- getKey: (state: never) => string | number;
50
- };
51
- type ReactNativeEventSourcedModules = {
52
- createReactNativeSQLitePersistence: (options: {
53
- database: never;
54
- }) => PersistedCollectionPersistence; /** Already-opened op-sqlite (or compatible) database. */
55
- database: unknown;
56
- createCollection: InjectedCreateCollection;
57
- persistedCollectionOptions: InjectedModuleFn;
58
- };
59
- /**
60
- * React Native entry-point config. Shared sync/lifecycle fields come from
61
- * {@link EventSourcedSharedOptions} (hover those properties for docs).
62
- * Deep guide: `docs/usage.md`.
63
- */
64
- type ReactNativeEventSourcedDBConfig<TDefs extends Record<string, CollectionDefConstraint>> = EventSourcedSharedOptions & {
65
- collections: TDefs;
66
- /**
67
- * React Native persistence modules from
68
- * `@tanstack/react-native-db-sqlite-persistence` plus `createCollection`.
69
- * Pass the imported bindings directly, or a function to delay native SQLite.
70
- */
71
- modules: ModulesInput<ReactNativeEventSourcedModules>;
72
- };
73
- /**
74
- * React Native–flavoured event-sourced DB, returned as a lazy singleton.
75
- *
76
- * @param config - See {@link ReactNativeEventSourcedDBConfig} for every option.
77
- *
78
- * @example
79
- * ```ts
80
- * import { createReactNativeEventSourcedDB } from "event-sourced-collection/react-native"
81
- *
82
- * const { ensureDb, db } = createReactNativeEventSourcedDB({
83
- * collections: { todos: { getKey: (todo: { id: string }) => todo.id } },
84
- * modules: async () => {
85
- * const { createCollection } = await import("@tanstack/react-native-db")
86
- * const { createReactNativeSQLitePersistence, persistedCollectionOptions } =
87
- * await import("@tanstack/react-native-db-sqlite-persistence")
88
- * const { openDatabase } = await import("react-native-op-sqlite")
89
- * return {
90
- * createCollection,
91
- * createReactNativeSQLitePersistence,
92
- * persistedCollectionOptions,
93
- * database: openDatabase({ name: "app.sqlite" }),
94
- * }
95
- * },
96
- * })
97
- *
98
- * await ensureDb()
99
- * ```
100
- */
101
- declare function createReactNativeEventSourcedDB<const TDefs extends Record<string, CollectionDefConstraint>>(config: ReactNativeEventSourcedDBConfig<TDefs>): EventSourcedDBHandle<TDefs>;
102
- //#endregion
103
48
  export { type ReactNativeEventSourcedDBConfig, type EventSourcedDBHandle as ReactNativeEventSourcedDBHandle, type ReactNativeEventSourcedModules, type ReactNativePlatformConfig, type ReactNativePlatformDeps, type ReactNativePlatformResult, createReactNativeEventSourcedDB, createReactNativePlatform };
104
49
  //# sourceMappingURL=react-native.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react-native.d.mts","names":[],"sources":["../src/platforms/react-native.ts","../src/platforms/react-native-event-sourced-db.ts"],"mappings":";;;;KAEY,uBAAA;EACV,kCAAA,GAAqC,OAAA;IACnC,QAAA;EAAA,MACI,8BAA8B;AAAA;AAAA,KAG1B,yBAAA;EACV,QAAQ;AAAA;AAAA,KAGE,yBAAA;EACV,WAAA,EAAa,8BAA8B;AAAA;;;AARP;AAGtC;;;;AACU;AAGV;;;;AAC6C;AAgC7C;;;;;;;;;;;;;;AAG4B;;iBAHZ,yBAAA,CACd,IAAA,EAAM,uBAAA,EACN,MAAA,EAAQ,yBAAA,GACP,yBAAA;;;KClCE,uBAAA;EACH,MAAA,GAAS,KAAY;AAAA;AAAA,KAGX,8BAAA;EACV,kCAAA,GAAqC,OAAA;IACnC,QAAA;EAAA,MACI,8BAAA,EDjBJ;ECmBF,QAAA;EACA,gBAAA,EAAkB,wBAAA;EAClB,0BAAA,EAA4B,gBAAA;AAAA;ADjB9B;;;;AACU;AADV,KCyBY,+BAAA,eAA8C,MAAA,SAAe,uBAAA,KACvE,yBAAA;EACE,WAAA,EAAa,KAAA;;;ADtB4B;AAgC7C;;ECJI,OAAA,EAAS,YAAA,CAAa,8BAAA;AAAA;;;;;;;;;;ADOE;;;;ACrCmE;;;;AAIxE;AAGvB;;;;;;;;;;iBAwDgB,+BAAA,qBACM,MAAA,SAAe,uBAAA,GACnC,MAAA,EAAQ,+BAAA,CAAgC,KAAA,IAAM,oBAAA,CAAA,KAAA"}
1
+ {"version":3,"file":"react-native.d.mts","names":[],"sources":["../src/platforms/react-native.ts"],"mappings":";;;;;KAEY,uBAAA;EACV,kCAAA,GAAqC,OAAA;IACnC,QAAA;EAAA,MACI,8BAA8B;AAAA;AAAA,KAG1B,yBAAA;EACV,QAAQ;AAAA;AAAA,KAGE,yBAAA;EACV,WAAA,EAAa,8BAA8B;AAAA;;;AARP;AAGtC;;;;AACU;AAGV;;;;AAC6C;AAgC7C;;;;;;;;;;;;;;AAG4B;;iBAHZ,yBAAA,CACd,IAAA,EAAM,uBAAA,EACN,MAAA,EAAQ,yBAAA,GACP,yBAAA"}
package/dist/react.d.mts CHANGED
@@ -1,8 +1,55 @@
1
- import { _ as ManualSyncResult } from "./types-BSdudVLh.mjs";
1
+ import { V as SyncStatus, _ as ManualSyncResult } from "./types-BSdudVLh.mjs";
2
2
 
3
3
  //#region src/react/format-manual-sync-message.d.ts
4
4
  declare function formatManualSyncMessage(result: ManualSyncResult): string;
5
5
  //#endregion
6
+ //#region src/react/use-ensure-db.d.ts
7
+ type UseEnsureDbOptions<TDb> = {
8
+ /** Lazy singleton opener from `createBrowserEventSourcedDB` / platform helpers. */ensureDb: () => Promise<TDb>;
9
+ /**
10
+ * Re-run init when these change (e.g. `[isAuthenticated]`).
11
+ * `ensureDb` itself stays idempotent; use this to re-apply app gates.
12
+ */
13
+ deps?: ReadonlyArray<unknown>;
14
+ /**
15
+ * After OPFS/SQLite is ready. Use for settings gates, `setSyncEnabled`,
16
+ * fire-and-forget `db.sync()`, e2e handles, etc. Errors here fail the hook.
17
+ */
18
+ onReady?: (db: TDb) => void | Promise<void>;
19
+ };
20
+ type UseEnsureDbResult = {
21
+ ready: false;
22
+ error: null;
23
+ } | {
24
+ ready: false;
25
+ error: Error;
26
+ } | {
27
+ ready: true;
28
+ error: null;
29
+ };
30
+ /**
31
+ * Browser-safe `ensureDb()` for React: runs in `useEffect`, exposes ready/error.
32
+ *
33
+ * Does not know about auth or settings — pass those through `onReady` / `deps`.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * const { ready, error } = useEnsureDb({
38
+ * ensureDb,
39
+ * deps: [isAuthenticated],
40
+ * onReady: (db) => {
41
+ * db.setSyncEnabled(isAuthenticated && settings.syncEnabled)
42
+ * if (db.getSyncEnabled()) void db.sync()
43
+ * },
44
+ * })
45
+ * ```
46
+ */
47
+ declare function useEnsureDb<TDb>({
48
+ ensureDb,
49
+ deps,
50
+ onReady
51
+ }: UseEnsureDbOptions<TDb>): UseEnsureDbResult;
52
+ //#endregion
6
53
  //#region src/react/settings-collection.d.ts
7
54
  type SettingsRow = {
8
55
  syncEnabled?: boolean;
@@ -19,35 +66,74 @@ type DbWithSettings = {
19
66
  };
20
67
  };
21
68
  //#endregion
69
+ //#region src/react/use-sync-status.d.ts
70
+ /**
71
+ * Minimal DB surface needed for sync status. Accepts the full
72
+ * {@link import("../core/types").EventSourcedDB} or a test double.
73
+ */
74
+ type SyncStatusSource = {
75
+ getSyncStatus: () => SyncStatus;
76
+ subscribeSyncStatus: (listener: (status: SyncStatus) => void) => () => void;
77
+ };
78
+ /**
79
+ * Live {@link SyncStatus} for spinners, badges, and pending counts.
80
+ *
81
+ * `getSyncStatus()` alone is a snapshot — it will go stale in React. Always
82
+ * subscribe (this hook, or `db.subscribeSyncStatus` directly).
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * import { useSyncStatus } from "event-sourced-collection/react"
87
+ *
88
+ * function SyncBadge({ db }: { db: SyncStatusSource }) {
89
+ * const { isSyncing, pendingCount } = useSyncStatus(db)
90
+ * if (isSyncing) return <Spinner />
91
+ * return <span>{pendingCount} pending</span>
92
+ * }
93
+ * ```
94
+ */
95
+ declare function useSyncStatus(db: SyncStatusSource): SyncStatus;
96
+ //#endregion
22
97
  //#region src/react/use-manual-sync.d.ts
23
98
  type UseManualSyncOptions = {
24
99
  /** When false, skips reading settings and treats sync as enabled. */enabled?: boolean;
25
100
  settingsId: string;
26
- ensureDb: () => Promise<DbWithSettings>; /** Typically `() => ensureDb().then((db) => db.manualSync())`. */
101
+ ensureDb: () => Promise<DbWithSettings>; /** Typically `() => db.manualSync()` or `() => ensureDb().then((d) => d.manualSync())`. */
27
102
  sync: () => Promise<ManualSyncResult>;
28
103
  disabledMessage?: string;
104
+ /**
105
+ * Live DB handle. When set, `syncing` follows {@link SyncStatusSource.subscribeSyncStatus}
106
+ * so the button tracks load sync, background sync, and this `runSync` call.
107
+ *
108
+ * When omitted, `syncing` is only true while `runSync` is awaiting (legacy).
109
+ */
110
+ db?: SyncStatusSource;
29
111
  };
30
112
  type UseManualSyncReturn = {
31
- syncEnabled: boolean;
113
+ syncEnabled: boolean; /** True while any sync is in flight when `db` was passed; otherwise only during `runSync`. */
32
114
  syncing: boolean;
33
115
  syncMessage: string | null;
34
116
  /**
35
- * Runs the sync callback, updates `syncing` / `syncMessage`, and returns the
36
- * raw result on success (including results that contain `errors`).
117
+ * Runs the sync callback, updates `syncMessage`, and returns the raw result
118
+ * on success (including results that contain `errors`).
37
119
  * Returns `undefined` when sync is disabled or the callback throws.
38
120
  */
39
121
  runSync: () => Promise<ManualSyncResult | undefined>;
40
122
  };
41
123
  /**
42
- * Encapsulates settings-gated manual sync UI state so callers don't format
43
- * `ManualSyncResult` themselves.
124
+ * Settings-gated manual sync UI helper.
125
+ *
126
+ * Prefer passing `db` so `syncing` shares the same global tracker as
127
+ * {@link import("./use-sync-status").useSyncStatus} — then a load-time
128
+ * `db.sync()` also disables the button / shows a spinner.
44
129
  */
45
130
  declare function useManualSync({
46
131
  enabled,
47
132
  settingsId,
48
133
  ensureDb,
49
134
  sync,
50
- disabledMessage
135
+ disabledMessage,
136
+ db
51
137
  }: UseManualSyncOptions): UseManualSyncReturn;
52
138
  //#endregion
53
139
  //#region src/react/use-sync-enabled.d.ts
@@ -65,5 +151,5 @@ declare function useSyncEnabled({
65
151
  ensureDb
66
152
  }: UseSyncEnabledOptions): boolean;
67
153
  //#endregion
68
- export { type DbWithSettings, type SettingsCollectionLike, type SettingsRow, type UseManualSyncOptions, type UseManualSyncReturn, type UseSyncEnabledOptions, formatManualSyncMessage, useManualSync, useSyncEnabled };
154
+ export { type DbWithSettings, type SettingsCollectionLike, type SettingsRow, type SyncStatusSource, type UseEnsureDbOptions, type UseEnsureDbResult, type UseManualSyncOptions, type UseManualSyncReturn, type UseSyncEnabledOptions, formatManualSyncMessage, useEnsureDb, useManualSync, useSyncEnabled, useSyncStatus };
69
155
  //# sourceMappingURL=react.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.mts","names":[],"sources":["../src/react/format-manual-sync-message.ts","../src/react/settings-collection.ts","../src/react/use-manual-sync.ts","../src/react/use-sync-enabled.ts"],"mappings":";;;iBAEgB,uBAAA,CAAwB,MAAwB,EAAhB,gBAAgB;;;KCFpD,WAAA;EACV,WAAW;AAAA;AAAA,KAGD,sBAAA;EACV,GAAA,GAAM,EAAA,aAAe,WAAW;EAChC,gBAAA,GAAmB,QAAA;IAA2B,WAAA;EAAA;AAAA;AAAA,KAGpC,cAAA;EACV,WAAA;IACE,QAAA,EAAU,sBAAsB;EAAA;AAAA;;;KCJxB,oBAAA;EFLI,qEEOd,OAAA;EACA,UAAA;EACA,QAAA,QAAgB,OAAA,CAAQ,cAAA,GFTsC;EEW9D,IAAA,QAAY,OAAA,CAAQ,gBAAA;EACpB,eAAA;AAAA;AAAA,KAGU,mBAAA;EACV,WAAA;EACA,OAAA;EACA,WAAA;EDnBW;AAGb;;;;ECsBE,OAAA,QAAe,OAAO,CAAC,gBAAA;AAAA;;;;;iBAST,aAAA;EACd,OAAA;EACA,UAAA;EACA,QAAA;EACA,IAAA;EACA;AAAA,GACC,oBAAA,GAAuB,mBAAA;;;KCrCd,qBAAA;+DAEV,OAAA;EACA,UAAA;EACA,QAAA,QAAgB,OAAO,CAAC,cAAA;AAAA;AHNsC;;;AAAA,iBGYhD,cAAA;EACd,OAAA;EACA,UAAA;EACA;AAAA,GACC,qBAAA"}
1
+ {"version":3,"file":"react.d.mts","names":[],"sources":["../src/react/format-manual-sync-message.ts","../src/react/use-ensure-db.ts","../src/react/settings-collection.ts","../src/react/use-sync-status.ts","../src/react/use-manual-sync.ts","../src/react/use-sync-enabled.ts"],"mappings":";;;iBAEgB,uBAAA,CAAwB,MAAwB,EAAhB,gBAAgB;;;KCApD,kBAAA;qFAEV,QAAA,QAAgB,OAAA,CAAQ,GAAA;EDFV;;;;ECOd,IAAA,GAAO,aAAA;;;;AAPT;EAYE,OAAA,IAAW,EAAA,EAAI,GAAA,YAAe,OAAA;AAAA;AAAA,KAGpB,iBAAA;EACN,KAAA;EAAc,KAAA;AAAA;EACd,KAAA;EAAc,KAAA,EAAO,KAAK;AAAA;EAC1B,KAAA;EAAa,KAAA;AAAA;;;;;;;;;AANoB;AAGvC;;;;;;;;iBAsBgB,WAAA;EACd,QAAA;EACA,IAAA;EACA;AAAA,GACC,kBAAA,CAAmB,GAAA,IAAO,iBAAA;;;KC3CjB,WAAA;EACV,WAAW;AAAA;AAAA,KAGD,sBAAA;EACV,GAAA,GAAM,EAAA,aAAe,WAAW;EAChC,gBAAA,GAAmB,QAAA;IAA2B,WAAA;EAAA;AAAA;AAAA,KAGpC,cAAA;EACV,WAAA;IACE,QAAA,EAAU,sBAAsB;EAAA;AAAA;;;;;AFTpC;;KGMY,gBAAA;EACV,aAAA,QAAqB,UAAA;EACrB,mBAAA,GAAsB,QAAA,GAAW,MAAA,EAAQ,UAAU;AAAA;;;AFRrD;;;;;;;;;;;;;;;iBE4BgB,aAAA,CAAc,EAAA,EAAI,gBAAA,GAAmB,UAAU;;;KCtBnD,oBAAA;EJN2B,qEIQrC,OAAA;EACA,UAAA;EACA,QAAA,QAAgB,OAAA,CAAQ,cAAA;EAExB,IAAA,QAAY,OAAA,CAAQ,gBAAA;EACpB,eAAA;EHbU;;;;;;EGoBV,EAAA,GAAK,gBAAA;AAAA;AAAA,KAGK,mBAAA;EACV,WAAA,WHxB6B;EG0B7B,OAAA;EACA,WAAA;EHzBwB;;;;;EG+BxB,OAAA,QAAe,OAAO,CAAC,gBAAA;AAAA;;AHrBc;AAGvC;;;;;iBG8BgB,aAAA;EACd,OAAA;EACA,UAAA;EACA,QAAA;EACA,IAAA;EACA,eAAA;EACA;AAAA,GACC,oBAAA,GAAuB,mBAAA;;;KClDd,qBAAA;+DAEV,OAAA;EACA,UAAA;EACA,QAAA,QAAgB,OAAO,CAAC,cAAA;AAAA;ALNsC;;;AAAA,iBKYhD,cAAA;EACd,OAAA;EACA,UAAA;EACA;AAAA,GACC,qBAAA"}
package/dist/react.mjs CHANGED
@@ -9,6 +9,58 @@ function formatManualSyncMessage(result) {
9
9
  return parts.join(" ");
10
10
  }
11
11
  //#endregion
12
+ //#region src/react/use-ensure-db.ts
13
+ /**
14
+ * Browser-safe `ensureDb()` for React: runs in `useEffect`, exposes ready/error.
15
+ *
16
+ * Does not know about auth or settings — pass those through `onReady` / `deps`.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * const { ready, error } = useEnsureDb({
21
+ * ensureDb,
22
+ * deps: [isAuthenticated],
23
+ * onReady: (db) => {
24
+ * db.setSyncEnabled(isAuthenticated && settings.syncEnabled)
25
+ * if (db.getSyncEnabled()) void db.sync()
26
+ * },
27
+ * })
28
+ * ```
29
+ */
30
+ function useEnsureDb({ ensureDb, deps = [], onReady }) {
31
+ const [ready, setReady] = useState(false);
32
+ const [error, setError] = useState(null);
33
+ useEffect(() => {
34
+ let cancelled = false;
35
+ ensureDb().then(async (db) => {
36
+ if (cancelled) return;
37
+ if (onReady) await onReady(db);
38
+ if (cancelled) return;
39
+ setReady(true);
40
+ setError(null);
41
+ }).catch((err) => {
42
+ if (cancelled) return;
43
+ setReady(false);
44
+ setError(err instanceof Error ? err : new Error(String(err)));
45
+ });
46
+ return () => {
47
+ cancelled = true;
48
+ };
49
+ }, deps);
50
+ if (error) return {
51
+ ready: false,
52
+ error
53
+ };
54
+ if (!ready) return {
55
+ ready: false,
56
+ error: null
57
+ };
58
+ return {
59
+ ready: true,
60
+ error: null
61
+ };
62
+ }
63
+ //#endregion
12
64
  //#region src/react/use-sync-enabled.ts
13
65
  /**
14
66
  * Live-reads `settings.syncEnabled` for the given settings row id.
@@ -43,27 +95,40 @@ function useSyncEnabled({ enabled = true, settingsId, ensureDb }) {
43
95
  //#region src/react/use-manual-sync.ts
44
96
  const DEFAULT_DISABLED_MESSAGE = "Sync is disabled in Settings.";
45
97
  /**
46
- * Encapsulates settings-gated manual sync UI state so callers don't format
47
- * `ManualSyncResult` themselves.
98
+ * Settings-gated manual sync UI helper.
99
+ *
100
+ * Prefer passing `db` so `syncing` shares the same global tracker as
101
+ * {@link import("./use-sync-status").useSyncStatus} — then a load-time
102
+ * `db.sync()` also disables the button / shows a spinner.
48
103
  */
49
- function useManualSync({ enabled = true, settingsId, ensureDb, sync, disabledMessage = DEFAULT_DISABLED_MESSAGE }) {
104
+ function useManualSync({ enabled = true, settingsId, ensureDb, sync, disabledMessage = DEFAULT_DISABLED_MESSAGE, db }) {
50
105
  const syncEnabled = useSyncEnabled({
51
106
  enabled,
52
107
  settingsId,
53
108
  ensureDb
54
109
  });
55
- const [syncing, setSyncing] = useState(false);
110
+ const [legacySyncing, setLegacySyncing] = useState(false);
111
+ const [liveSyncing, setLiveSyncing] = useState(() => db?.getSyncStatus().isSyncing ?? false);
56
112
  const [syncMessage, setSyncMessage] = useState(null);
113
+ useEffect(() => {
114
+ if (!db) {
115
+ setLiveSyncing(false);
116
+ return;
117
+ }
118
+ return db.subscribeSyncStatus((status) => {
119
+ setLiveSyncing(status.isSyncing);
120
+ });
121
+ }, [db]);
57
122
  return {
58
123
  syncEnabled,
59
- syncing,
124
+ syncing: db ? liveSyncing : legacySyncing,
60
125
  syncMessage,
61
126
  runSync: useCallback(async () => {
62
127
  if (!syncEnabled) {
63
128
  setSyncMessage(disabledMessage);
64
129
  return;
65
130
  }
66
- setSyncing(true);
131
+ if (!db) setLegacySyncing(true);
67
132
  setSyncMessage(null);
68
133
  try {
69
134
  const result = await sync();
@@ -73,9 +138,10 @@ function useManualSync({ enabled = true, settingsId, ensureDb, sync, disabledMes
73
138
  setSyncMessage(error instanceof Error ? error.message : "Sync failed");
74
139
  return;
75
140
  } finally {
76
- setSyncing(false);
141
+ if (!db) setLegacySyncing(false);
77
142
  }
78
143
  }, [
144
+ db,
79
145
  disabledMessage,
80
146
  sync,
81
147
  syncEnabled
@@ -83,6 +149,30 @@ function useManualSync({ enabled = true, settingsId, ensureDb, sync, disabledMes
83
149
  };
84
150
  }
85
151
  //#endregion
86
- export { formatManualSyncMessage, useManualSync, useSyncEnabled };
152
+ //#region src/react/use-sync-status.ts
153
+ /**
154
+ * Live {@link SyncStatus} for spinners, badges, and pending counts.
155
+ *
156
+ * `getSyncStatus()` alone is a snapshot — it will go stale in React. Always
157
+ * subscribe (this hook, or `db.subscribeSyncStatus` directly).
158
+ *
159
+ * @example
160
+ * ```tsx
161
+ * import { useSyncStatus } from "event-sourced-collection/react"
162
+ *
163
+ * function SyncBadge({ db }: { db: SyncStatusSource }) {
164
+ * const { isSyncing, pendingCount } = useSyncStatus(db)
165
+ * if (isSyncing) return <Spinner />
166
+ * return <span>{pendingCount} pending</span>
167
+ * }
168
+ * ```
169
+ */
170
+ function useSyncStatus(db) {
171
+ const [status, setStatus] = useState(() => db.getSyncStatus());
172
+ useEffect(() => db.subscribeSyncStatus(setStatus), [db]);
173
+ return status;
174
+ }
175
+ //#endregion
176
+ export { formatManualSyncMessage, useEnsureDb, useManualSync, useSyncEnabled, useSyncStatus };
87
177
 
88
178
  //# sourceMappingURL=react.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.mjs","names":[],"sources":["../src/react/format-manual-sync-message.ts","../src/react/use-sync-enabled.ts","../src/react/use-manual-sync.ts"],"sourcesContent":["import type { ManualSyncResult } from \"../core/types\";\n\nexport function formatManualSyncMessage(result: ManualSyncResult): string {\n if (result.errors.length > 0) {\n return `Sync failed: ${result.errors[0]?.message ?? \"Unknown error\"}`;\n }\n\n if (result.deferred) {\n return \"Another tab is already syncing.\";\n }\n\n const parts = [\n `Pushed ${result.pushed}, pulled ${result.pulled}, replayed ${result.replayed} inbox event(s).`,\n ];\n\n if (result.skipped > 0) {\n parts.push(`Skipped ${result.skipped} unrecognized event(s).`);\n }\n\n if (result.deadLettered > 0) {\n parts.push(`Moved ${result.deadLettered} rejected event(s) to the dead-letter queue.`);\n }\n\n return parts.join(\" \");\n}\n","import { useEffect, useState } from \"react\";\n\nimport type { DbWithSettings } from \"./settings-collection\";\n\nexport type UseSyncEnabledOptions = {\n /** When false, skips reading settings and returns `true`. */\n enabled?: boolean;\n settingsId: string;\n ensureDb: () => Promise<DbWithSettings>;\n};\n\n/**\n * Live-reads `settings.syncEnabled` for the given settings row id.\n */\nexport function useSyncEnabled({\n enabled = true,\n settingsId,\n ensureDb,\n}: UseSyncEnabledOptions): boolean {\n const [syncEnabled, setSyncEnabled] = useState(true);\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n let cancelled = false;\n let subscription: { unsubscribe: () => void } | undefined;\n\n void ensureDb().then((database) => {\n if (cancelled) {\n return;\n }\n\n const read = () => {\n const setting = database.collections.settings.get(settingsId);\n setSyncEnabled(setting?.syncEnabled ?? true);\n };\n\n read();\n subscription = database.collections.settings.subscribeChanges(read);\n });\n\n return () => {\n cancelled = true;\n subscription?.unsubscribe();\n };\n }, [enabled, ensureDb, settingsId]);\n\n if (!enabled) {\n return true;\n }\n\n return syncEnabled;\n}\n","import { useCallback, useState } from \"react\";\n\nimport type { ManualSyncResult } from \"../core/types\";\nimport { formatManualSyncMessage } from \"./format-manual-sync-message\";\nimport type { DbWithSettings } from \"./settings-collection\";\nimport { useSyncEnabled } from \"./use-sync-enabled\";\n\nexport type UseManualSyncOptions = {\n /** When false, skips reading settings and treats sync as enabled. */\n enabled?: boolean;\n settingsId: string;\n ensureDb: () => Promise<DbWithSettings>;\n /** Typically `() => ensureDb().then((db) => db.manualSync())`. */\n sync: () => Promise<ManualSyncResult>;\n disabledMessage?: string;\n};\n\nexport type UseManualSyncReturn = {\n syncEnabled: boolean;\n syncing: boolean;\n syncMessage: string | null;\n /**\n * Runs the sync callback, updates `syncing` / `syncMessage`, and returns the\n * raw result on success (including results that contain `errors`).\n * Returns `undefined` when sync is disabled or the callback throws.\n */\n runSync: () => Promise<ManualSyncResult | undefined>;\n};\n\nconst DEFAULT_DISABLED_MESSAGE = \"Sync is disabled in Settings.\";\n\n/**\n * Encapsulates settings-gated manual sync UI state so callers don't format\n * `ManualSyncResult` themselves.\n */\nexport function useManualSync({\n enabled = true,\n settingsId,\n ensureDb,\n sync,\n disabledMessage = DEFAULT_DISABLED_MESSAGE,\n}: UseManualSyncOptions): UseManualSyncReturn {\n const syncEnabled = useSyncEnabled({ enabled, settingsId, ensureDb });\n const [syncing, setSyncing] = useState(false);\n const [syncMessage, setSyncMessage] = useState<string | null>(null);\n\n const runSync = useCallback(async (): Promise<ManualSyncResult | undefined> => {\n if (!syncEnabled) {\n setSyncMessage(disabledMessage);\n return undefined;\n }\n\n setSyncing(true);\n setSyncMessage(null);\n\n try {\n const result = await sync();\n setSyncMessage(formatManualSyncMessage(result));\n return result;\n } catch (error) {\n setSyncMessage(error instanceof Error ? error.message : \"Sync failed\");\n return undefined;\n } finally {\n setSyncing(false);\n }\n }, [disabledMessage, sync, syncEnabled]);\n\n return {\n syncEnabled,\n syncing,\n syncMessage,\n runSync,\n };\n}\n"],"mappings":";;AAEA,SAAgB,wBAAwB,QAAkC;CACxE,IAAI,OAAO,OAAO,SAAS,GACzB,OAAO,gBAAgB,OAAO,OAAO,EAAE,EAAE,WAAW;CAGtD,IAAI,OAAO,UACT,OAAO;CAGT,MAAM,QAAQ,CACZ,UAAU,OAAO,OAAO,WAAW,OAAO,OAAO,aAAa,OAAO,SAAS,iBAChF;CAEA,IAAI,OAAO,UAAU,GACnB,MAAM,KAAK,WAAW,OAAO,QAAQ,wBAAwB;CAG/D,IAAI,OAAO,eAAe,GACxB,MAAM,KAAK,SAAS,OAAO,aAAa,6CAA6C;CAGvF,OAAO,MAAM,KAAK,GAAG;AACvB;;;;;;ACVA,SAAgB,eAAe,EAC7B,UAAU,MACV,YACA,YACiC;CACjC,MAAM,CAAC,aAAa,kBAAkB,SAAS,IAAI;CAEnD,gBAAgB;EACd,IAAI,CAAC,SACH;EAGF,IAAI,YAAY;EAChB,IAAI;EAEJ,SAAc,CAAC,CAAC,MAAM,aAAa;GACjC,IAAI,WACF;GAGF,MAAM,aAAa;IAEjB,eADgB,SAAS,YAAY,SAAS,IAAI,UAC7B,CAAC,EAAE,eAAe,IAAI;GAC7C;GAEA,KAAK;GACL,eAAe,SAAS,YAAY,SAAS,iBAAiB,IAAI;EACpE,CAAC;EAED,aAAa;GACX,YAAY;GACZ,cAAc,YAAY;EAC5B;CACF,GAAG;EAAC;EAAS;EAAU;CAAU,CAAC;CAElC,IAAI,CAAC,SACH,OAAO;CAGT,OAAO;AACT;;;ACzBA,MAAM,2BAA2B;;;;;AAMjC,SAAgB,cAAc,EAC5B,UAAU,MACV,YACA,UACA,MACA,kBAAkB,4BAC0B;CAC5C,MAAM,cAAc,eAAe;EAAE;EAAS;EAAY;CAAS,CAAC;CACpE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,aAAa,kBAAkB,SAAwB,IAAI;CAuBlE,OAAO;EACL;EACA;EACA;EACA,SAzBc,YAAY,YAAmD;GAC7E,IAAI,CAAC,aAAa;IAChB,eAAe,eAAe;IAC9B;GACF;GAEA,WAAW,IAAI;GACf,eAAe,IAAI;GAEnB,IAAI;IACF,MAAM,SAAS,MAAM,KAAK;IAC1B,eAAe,wBAAwB,MAAM,CAAC;IAC9C,OAAO;GACT,SAAS,OAAO;IACd,eAAe,iBAAiB,QAAQ,MAAM,UAAU,aAAa;IACrE;GACF,UAAU;IACR,WAAW,KAAK;GAClB;EACF,GAAG;GAAC;GAAiB;GAAM;EAAW,CAM9B;CACR;AACF"}
1
+ {"version":3,"file":"react.mjs","names":[],"sources":["../src/react/format-manual-sync-message.ts","../src/react/use-ensure-db.ts","../src/react/use-sync-enabled.ts","../src/react/use-manual-sync.ts","../src/react/use-sync-status.ts"],"sourcesContent":["import type { ManualSyncResult } from \"../core/types\";\n\nexport function formatManualSyncMessage(result: ManualSyncResult): string {\n if (result.errors.length > 0) {\n return `Sync failed: ${result.errors[0]?.message ?? \"Unknown error\"}`;\n }\n\n if (result.deferred) {\n return \"Another tab is already syncing.\";\n }\n\n const parts = [\n `Pushed ${result.pushed}, pulled ${result.pulled}, replayed ${result.replayed} inbox event(s).`,\n ];\n\n if (result.skipped > 0) {\n parts.push(`Skipped ${result.skipped} unrecognized event(s).`);\n }\n\n if (result.deadLettered > 0) {\n parts.push(`Moved ${result.deadLettered} rejected event(s) to the dead-letter queue.`);\n }\n\n return parts.join(\" \");\n}\n","import { useEffect, useState } from \"react\";\n\nexport type UseEnsureDbOptions<TDb> = {\n /** Lazy singleton opener from `createBrowserEventSourcedDB` / platform helpers. */\n ensureDb: () => Promise<TDb>;\n /**\n * Re-run init when these change (e.g. `[isAuthenticated]`).\n * `ensureDb` itself stays idempotent; use this to re-apply app gates.\n */\n deps?: ReadonlyArray<unknown>;\n /**\n * After OPFS/SQLite is ready. Use for settings gates, `setSyncEnabled`,\n * fire-and-forget `db.sync()`, e2e handles, etc. Errors here fail the hook.\n */\n onReady?: (db: TDb) => void | Promise<void>;\n};\n\nexport type UseEnsureDbResult =\n | { ready: false; error: null }\n | { ready: false; error: Error }\n | { ready: true; error: null };\n\n/**\n * Browser-safe `ensureDb()` for React: runs in `useEffect`, exposes ready/error.\n *\n * Does not know about auth or settings — pass those through `onReady` / `deps`.\n *\n * @example\n * ```tsx\n * const { ready, error } = useEnsureDb({\n * ensureDb,\n * deps: [isAuthenticated],\n * onReady: (db) => {\n * db.setSyncEnabled(isAuthenticated && settings.syncEnabled)\n * if (db.getSyncEnabled()) void db.sync()\n * },\n * })\n * ```\n */\nexport function useEnsureDb<TDb>({\n ensureDb,\n deps = [],\n onReady,\n}: UseEnsureDbOptions<TDb>): UseEnsureDbResult {\n const [ready, setReady] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n\n ensureDb()\n .then(async (db) => {\n if (cancelled) return;\n if (onReady) await onReady(db);\n if (cancelled) return;\n setReady(true);\n setError(null);\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setReady(false);\n setError(err instanceof Error ? err : new Error(String(err)));\n });\n\n return () => {\n cancelled = true;\n };\n // Caller owns stability of ensureDb / onReady; deps drive re-init.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- intentional deps array API\n }, deps);\n\n if (error) return { ready: false, error };\n if (!ready) return { ready: false, error: null };\n return { ready: true, error: null };\n}\n","import { useEffect, useState } from \"react\";\n\nimport type { DbWithSettings } from \"./settings-collection\";\n\nexport type UseSyncEnabledOptions = {\n /** When false, skips reading settings and returns `true`. */\n enabled?: boolean;\n settingsId: string;\n ensureDb: () => Promise<DbWithSettings>;\n};\n\n/**\n * Live-reads `settings.syncEnabled` for the given settings row id.\n */\nexport function useSyncEnabled({\n enabled = true,\n settingsId,\n ensureDb,\n}: UseSyncEnabledOptions): boolean {\n const [syncEnabled, setSyncEnabled] = useState(true);\n\n useEffect(() => {\n if (!enabled) {\n return;\n }\n\n let cancelled = false;\n let subscription: { unsubscribe: () => void } | undefined;\n\n void ensureDb().then((database) => {\n if (cancelled) {\n return;\n }\n\n const read = () => {\n const setting = database.collections.settings.get(settingsId);\n setSyncEnabled(setting?.syncEnabled ?? true);\n };\n\n read();\n subscription = database.collections.settings.subscribeChanges(read);\n });\n\n return () => {\n cancelled = true;\n subscription?.unsubscribe();\n };\n }, [enabled, ensureDb, settingsId]);\n\n if (!enabled) {\n return true;\n }\n\n return syncEnabled;\n}\n","import { useCallback, useEffect, useState } from \"react\";\n\nimport type { ManualSyncResult } from \"../core/types\";\nimport { formatManualSyncMessage } from \"./format-manual-sync-message\";\nimport type { DbWithSettings } from \"./settings-collection\";\nimport type { SyncStatusSource } from \"./use-sync-status\";\nimport { useSyncEnabled } from \"./use-sync-enabled\";\n\nexport type UseManualSyncOptions = {\n /** When false, skips reading settings and treats sync as enabled. */\n enabled?: boolean;\n settingsId: string;\n ensureDb: () => Promise<DbWithSettings>;\n /** Typically `() => db.manualSync()` or `() => ensureDb().then((d) => d.manualSync())`. */\n sync: () => Promise<ManualSyncResult>;\n disabledMessage?: string;\n /**\n * Live DB handle. When set, `syncing` follows {@link SyncStatusSource.subscribeSyncStatus}\n * so the button tracks load sync, background sync, and this `runSync` call.\n *\n * When omitted, `syncing` is only true while `runSync` is awaiting (legacy).\n */\n db?: SyncStatusSource;\n};\n\nexport type UseManualSyncReturn = {\n syncEnabled: boolean;\n /** True while any sync is in flight when `db` was passed; otherwise only during `runSync`. */\n syncing: boolean;\n syncMessage: string | null;\n /**\n * Runs the sync callback, updates `syncMessage`, and returns the raw result\n * on success (including results that contain `errors`).\n * Returns `undefined` when sync is disabled or the callback throws.\n */\n runSync: () => Promise<ManualSyncResult | undefined>;\n};\n\nconst DEFAULT_DISABLED_MESSAGE = \"Sync is disabled in Settings.\";\n\n/**\n * Settings-gated manual sync UI helper.\n *\n * Prefer passing `db` so `syncing` shares the same global tracker as\n * {@link import(\"./use-sync-status\").useSyncStatus} — then a load-time\n * `db.sync()` also disables the button / shows a spinner.\n */\nexport function useManualSync({\n enabled = true,\n settingsId,\n ensureDb,\n sync,\n disabledMessage = DEFAULT_DISABLED_MESSAGE,\n db,\n}: UseManualSyncOptions): UseManualSyncReturn {\n const syncEnabled = useSyncEnabled({ enabled, settingsId, ensureDb });\n const [legacySyncing, setLegacySyncing] = useState(false);\n const [liveSyncing, setLiveSyncing] = useState(() => db?.getSyncStatus().isSyncing ?? false);\n const [syncMessage, setSyncMessage] = useState<string | null>(null);\n\n useEffect(() => {\n if (!db) {\n setLiveSyncing(false);\n return;\n }\n return db.subscribeSyncStatus((status) => {\n setLiveSyncing(status.isSyncing);\n });\n }, [db]);\n\n const syncing = db ? liveSyncing : legacySyncing;\n\n const runSync = useCallback(async (): Promise<ManualSyncResult | undefined> => {\n if (!syncEnabled) {\n setSyncMessage(disabledMessage);\n return undefined;\n }\n\n if (!db) setLegacySyncing(true);\n setSyncMessage(null);\n\n try {\n const result = await sync();\n setSyncMessage(formatManualSyncMessage(result));\n return result;\n } catch (error) {\n setSyncMessage(error instanceof Error ? error.message : \"Sync failed\");\n return undefined;\n } finally {\n if (!db) setLegacySyncing(false);\n }\n }, [db, disabledMessage, sync, syncEnabled]);\n\n return {\n syncEnabled,\n syncing,\n syncMessage,\n runSync,\n };\n}\n","import { useEffect, useState } from \"react\";\n\nimport type { SyncStatus } from \"../core/types\";\n\n/**\n * Minimal DB surface needed for sync status. Accepts the full\n * {@link import(\"../core/types\").EventSourcedDB} or a test double.\n */\nexport type SyncStatusSource = {\n getSyncStatus: () => SyncStatus;\n subscribeSyncStatus: (listener: (status: SyncStatus) => void) => () => void;\n};\n\n/**\n * Live {@link SyncStatus} for spinners, badges, and pending counts.\n *\n * `getSyncStatus()` alone is a snapshot — it will go stale in React. Always\n * subscribe (this hook, or `db.subscribeSyncStatus` directly).\n *\n * @example\n * ```tsx\n * import { useSyncStatus } from \"event-sourced-collection/react\"\n *\n * function SyncBadge({ db }: { db: SyncStatusSource }) {\n * const { isSyncing, pendingCount } = useSyncStatus(db)\n * if (isSyncing) return <Spinner />\n * return <span>{pendingCount} pending</span>\n * }\n * ```\n */\nexport function useSyncStatus(db: SyncStatusSource): SyncStatus {\n const [status, setStatus] = useState(() => db.getSyncStatus());\n\n useEffect(() => db.subscribeSyncStatus(setStatus), [db]);\n\n return status;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "event-sourced-collection",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "Event-sourced local-first database built on TanStack DB persistence",
5
5
  "keywords": [
6
6
  "event-sourcing",
@@ -44,12 +44,25 @@
44
44
  "access": "public",
45
45
  "registry": "https://registry.npmjs.org/"
46
46
  },
47
+ "scripts": {
48
+ "build": "tsdown",
49
+ "dev": "tsdown --watch",
50
+ "test": "vp test run",
51
+ "test:unit": "vp test run src/__tests__/unit",
52
+ "test:integration": "vp test run src/__tests__/integration",
53
+ "check-types": "tsgo --noEmit",
54
+ "prepublishOnly": "pnpm run build",
55
+ "check-exports": "attw --pack . --profile node16 --ignore-rules cjs-resolves-to-esm",
56
+ "postbuild": "npm run check-exports",
57
+ "release": "changeset publish --no-git-checks"
58
+ },
47
59
  "dependencies": {
48
60
  "uuidv7": "^1.2.1"
49
61
  },
50
62
  "devDependencies": {
51
63
  "@arethetypeswrong/cli": "^0.18.4",
52
64
  "@changesets/cli": "^2.31.0",
65
+ "@repo/typescript-config": "workspace:*",
53
66
  "@tanstack/browser-db-sqlite-persistence": "^0.2.12",
54
67
  "@tanstack/db": "^0.7.2",
55
68
  "@tanstack/db-sqlite-persistence-core": "^0.2.12",
@@ -60,11 +73,10 @@
60
73
  "better-sqlite3": "^13.0.3",
61
74
  "react": "^19.2.0",
62
75
  "tsdown": "^0.22.3",
63
- "typescript": "6.0.3",
64
- "vite": "npm:@voidzero-dev/vite-plus-core@latest",
65
- "vite-plus": "latest",
66
- "vitest": "^4.1.10",
67
- "@repo/typescript-config": "0.0.0"
76
+ "typescript": "catalog:",
77
+ "vite": "catalog:",
78
+ "vite-plus": "catalog:",
79
+ "vitest": "catalog:"
68
80
  },
69
81
  "peerDependencies": {
70
82
  "@tanstack/browser-db-sqlite-persistence": ">=0.2.0",
@@ -94,16 +106,5 @@
94
106
  },
95
107
  "engines": {
96
108
  "node": ">=18"
97
- },
98
- "scripts": {
99
- "build": "tsdown",
100
- "dev": "tsdown --watch",
101
- "test": "vp test run",
102
- "test:unit": "vp test run src/__tests__/unit",
103
- "test:integration": "vp test run src/__tests__/integration",
104
- "check-types": "tsgo --noEmit",
105
- "check-exports": "attw --pack . --profile node16 --ignore-rules cjs-resolves-to-esm",
106
- "postbuild": "npm run check-exports",
107
- "release": "changeset publish --no-git-checks"
108
109
  }
109
- }
110
+ }
@@ -1,121 +0,0 @@
1
- import { L as SyncLock, P as SQLiteDriver, Q as InjectedModuleFn, Z as InjectedCreateCollection, p as EventSourcedSharedOptions } from "./types-BSdudVLh.mjs";
2
- import { r as ModulesInput, t as EventSourcedDBHandle } from "./create-event-sourced-db-handle-BAos-9pS.mjs";
3
- import { PersistedCollectionPersistence } from "@tanstack/db-sqlite-persistence-core";
4
-
5
- //#region src/platforms/browser-wa-sqlite-driver.d.ts
6
- type BrowserWASQLiteDatabase = {
7
- execute: <TRow = unknown>(sql: string, params?: ReadonlyArray<unknown>) => Promise<ReadonlyArray<TRow>>;
8
- close?: () => Promise<void> | void;
9
- };
10
- //#endregion
11
- //#region src/platforms/browser-types.d.ts
12
- type BrowserCoordinatorInstance = {
13
- dispose: () => void;
14
- };
15
- /**
16
- * Injected TanStack browser persistence bindings. Parameters are `never` so
17
- * version-skewed `@tanstack/browser-db-sqlite-persistence` exports stay assignable.
18
- */
19
- type BrowserPlatformDeps = {
20
- openBrowserWASQLiteOPFSDatabase: (options: never) => Promise<BrowserWASQLiteDatabase>;
21
- createBrowserWASQLitePersistence: (options: never) => PersistedCollectionPersistence;
22
- BrowserCollectionCoordinator: new (options: never) => BrowserCoordinatorInstance;
23
- };
24
- type BrowserPlatformConfig = {
25
- databaseName: string;
26
- coordinatorDbName?: string;
27
- };
28
- type BrowserPlatformResult = {
29
- driver: SQLiteDriver;
30
- persistence: PersistedCollectionPersistence;
31
- close: () => Promise<void>;
32
- };
33
- //#endregion
34
- //#region src/platforms/browser-event-sourced-db.d.ts
35
- type CollectionDefConstraint = {
36
- getKey: (state: never) => string | number;
37
- };
38
- type BrowserEventSourcedModules = BrowserPlatformDeps & {
39
- createCollection: InjectedCreateCollection;
40
- persistedCollectionOptions: InjectedModuleFn;
41
- };
42
- /**
43
- * Browser entry-point config. Shared sync/lifecycle fields come from
44
- * {@link EventSourcedSharedOptions} (hover those properties for docs).
45
- * Deep guide: `docs/usage.md`.
46
- */
47
- type BrowserEventSourcedDBConfig<TDefs extends Record<string, CollectionDefConstraint>> = Omit<EventSourcedSharedOptions, "lock" | "lockName"> & {
48
- /**
49
- * User collection registry. Object keys become `db.collections.<key>` and
50
- * the wire `collectionId`. Must not collide with reserved names.
51
- */
52
- collections: TDefs;
53
- /**
54
- * OPFS SQLite database file name (e.g. `"my-app.sqlite"`). Also used as the
55
- * default sync lock namespace so only one tab syncs for this DB at a time.
56
- */
57
- databaseName: string;
58
- /**
59
- * Name for the cross-tab collection coordinator database. Defaults to
60
- * `databaseName` with a trailing `.sqlite` stripped.
61
- */
62
- coordinatorDbName?: string;
63
- /**
64
- * Browser OPFS persistence modules from
65
- * `@tanstack/browser-db-sqlite-persistence` plus `createCollection`.
66
- * Pass the imported bindings directly, or a function to keep WASM off the
67
- * critical path.
68
- */
69
- modules: ModulesInput<BrowserEventSourcedModules>;
70
- /**
71
- * Defaults to a Web Locks–backed lock so only one tab syncs at a time.
72
- * Pass `null` to opt out and let every tab sync independently.
73
- */
74
- lock?: SyncLock | null;
75
- };
76
- /**
77
- * Browser-flavoured event-sourced DB: OPFS SQLite + optional Web Locks sync
78
- * election, returned as a lazy singleton.
79
- *
80
- * @param config - See {@link BrowserEventSourcedDBConfig} for every option.
81
- *
82
- * @example
83
- * ```ts
84
- * import { createBrowserEventSourcedDB } from "event-sourced-collection/browser"
85
- * import type { CollectionDef, EventSourcedDB } from "event-sourced-collection"
86
- *
87
- * type Todo = { id: string; title: string }
88
- * type Defs = { todos: CollectionDef<Todo, string> }
89
- *
90
- * const { ensureDb, db } = createBrowserEventSourcedDB<Defs>({
91
- * databaseName: "app.sqlite",
92
- * collections: { todos: { getKey: (todo) => todo.id } },
93
- * sync: { push: "/api/sync/events", pull: "/api/sync/events" },
94
- * modules: async () => {
95
- * const { createCollection } = await import("@tanstack/db")
96
- * const {
97
- * BrowserCollectionCoordinator,
98
- * createBrowserWASQLitePersistence,
99
- * openBrowserWASQLiteOPFSDatabase,
100
- * persistedCollectionOptions,
101
- * } = await import("@tanstack/browser-db-sqlite-persistence")
102
- * return {
103
- * createCollection,
104
- * BrowserCollectionCoordinator,
105
- * createBrowserWASQLitePersistence,
106
- * openBrowserWASQLiteOPFSDatabase,
107
- * persistedCollectionOptions,
108
- * }
109
- * },
110
- * })
111
- *
112
- * export async function start() {
113
- * await ensureDb()
114
- * }
115
- * export { db }
116
- * ```
117
- */
118
- declare function createBrowserEventSourcedDB<const TDefs extends Record<string, CollectionDefConstraint>>(config: BrowserEventSourcedDBConfig<TDefs>): EventSourcedDBHandle<TDefs>;
119
- //#endregion
120
- export { BrowserPlatformConfig as a, BrowserWASQLiteDatabase as c, BrowserCoordinatorInstance as i, BrowserEventSourcedModules as n, BrowserPlatformDeps as o, createBrowserEventSourcedDB as r, BrowserPlatformResult as s, BrowserEventSourcedDBConfig as t };
121
- //# sourceMappingURL=browser-event-sourced-db-CCOAgE31.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser-event-sourced-db-CCOAgE31.d.mts","names":[],"sources":["../src/platforms/browser-wa-sqlite-driver.ts","../src/platforms/browser-types.ts","../src/platforms/browser-event-sourced-db.ts"],"mappings":";;;;;KAEY,uBAAA;EACV,OAAA,mBACE,GAAA,UACA,MAAA,GAAS,aAAA,cACN,OAAA,CAAQ,aAAA,CAAc,IAAA;EAC3B,KAAA,SAAc,OAAA;AAAA;;;KCJJ,0BAAA;EACV,OAAO;AAAA;ADFT;;;;AAAA,KCSY,mBAAA;EACV,+BAAA,GAAkC,OAAA,YAAmB,OAAA,CAAQ,uBAAA;EAC7D,gCAAA,GAAmC,OAAA,YAAmB,8BAAA;EACtD,4BAAA,OAAmC,OAAA,YAAmB,0BAAA;AAAA;AAAA,KAG5C,qBAAA;EACV,YAAA;EACA,iBAAiB;AAAA;AAAA,KAGP,qBAAA;EACV,MAAA,EAD+B,YAAA;EAE/B,WAAA,EAAa,8BAAA;EACb,KAAA,QAAa,OAAA;AAAA;;;KCTV,uBAAA;EACH,MAAA,GAAS,KAAY;AAAA;AAAA,KAGX,0BAAA,GAA6B,mBAAA;EACvC,gBAAA,EAAkB,wBAAA;EAClB,0BAAA,EAA4B,gBAAA;AAAA;;;;;;KAQlB,2BAAA,eAA0C,MAAA,SAAe,uBAAA,KACnE,IAAA,CAAK,yBAAA;EF3BH;;;;EEgCA,WAAA,EAAa,KAAA;EF9BY;;;;EEmCzB,YAAA;;;;ADtCJ;EC2CI,iBAAA;;;AD1CK;AAOT;;;EC0CI,OAAA,EAAS,YAAA,CAAa,0BAAA;EDzC6B;;;;EC8CnD,IAAA,GAAO,QAAA;AAAA;;;;;;;;;;AD5CuE;AAGlF;;;;AAEmB;AAGnB;;;;;;;;;;;;;;;AAGsB;;;;ACZqC;;;;AAIpC;AAGvB;;;iBAqFgB,2BAAA,qBACM,MAAA,SAAe,uBAAA,GACnC,MAAA,EAAQ,2BAAA,CAA4B,KAAA,IAAM,oBAAA,CAAA,KAAA"}