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.
- package/dist/browser.d.mts +118 -2
- package/dist/browser.d.mts.map +1 -1
- package/dist/node.d.mts +0 -1
- package/dist/node.d.mts.map +1 -1
- package/dist/react-native-event-sourced-db-CTS4b8o9.d.mts +61 -0
- package/dist/react-native-event-sourced-db-CTS4b8o9.d.mts.map +1 -0
- package/dist/react-native.d.mts +3 -58
- package/dist/react-native.d.mts.map +1 -1
- package/dist/react.d.mts +95 -9
- package/dist/react.d.mts.map +1 -1
- package/dist/react.mjs +98 -8
- package/dist/react.mjs.map +1 -1
- package/package.json +19 -18
- package/dist/browser-event-sourced-db-CCOAgE31.d.mts +0 -121
- package/dist/browser-event-sourced-db-CCOAgE31.d.mts.map +0 -1
package/dist/browser.d.mts
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
|
-
import {
|
|
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
|
package/dist/browser.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.mts","names":[],"sources":["../src/platforms/browser.ts"],"mappings":";;;;;
|
|
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: {
|
package/dist/node.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.mts","names":[],"sources":["../src/platforms/node.ts","../src/platforms/node-event-sourced-db.ts"],"mappings":"
|
|
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"}
|
package/dist/react-native.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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"
|
|
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((
|
|
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 `
|
|
36
|
-
*
|
|
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
|
-
*
|
|
43
|
-
*
|
|
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
|
package/dist/react.d.mts.map
CHANGED
|
@@ -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;;;
|
|
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
|
-
*
|
|
47
|
-
*
|
|
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 [
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/dist/react.mjs.map
CHANGED
|
@@ -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":";;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;;;;;;;;;;;;;;;;;;;;ACeA,SAAgB,YAAiB,EAC/B,UACA,OAAO,CAAC,GACR,WAC6C;CAC7C,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CACxC,MAAM,CAAC,OAAO,YAAY,SAAuB,IAAI;CAErD,gBAAgB;EACd,IAAI,YAAY;EAEhB,SAAS,CAAC,CACP,KAAK,OAAO,OAAO;GAClB,IAAI,WAAW;GACf,IAAI,SAAS,MAAM,QAAQ,EAAE;GAC7B,IAAI,WAAW;GACf,SAAS,IAAI;GACb,SAAS,IAAI;EACf,CAAC,CAAC,CACD,OAAO,QAAiB;GACvB,IAAI,WAAW;GACf,SAAS,KAAK;GACd,SAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;EAC9D,CAAC;EAEH,aAAa;GACX,YAAY;EACd;CAGF,GAAG,IAAI;CAEP,IAAI,OAAO,OAAO;EAAE,OAAO;EAAO;CAAM;CACxC,IAAI,CAAC,OAAO,OAAO;EAAE,OAAO;EAAO,OAAO;CAAK;CAC/C,OAAO;EAAE,OAAO;EAAM,OAAO;CAAK;AACpC;;;;;;AC5DA,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;;;AChBA,MAAM,2BAA2B;;;;;;;;AASjC,SAAgB,cAAc,EAC5B,UAAU,MACV,YACA,UACA,MACA,kBAAkB,0BAClB,MAC4C;CAC5C,MAAM,cAAc,eAAe;EAAE;EAAS;EAAY;CAAS,CAAC;CACpE,MAAM,CAAC,eAAe,oBAAoB,SAAS,KAAK;CACxD,MAAM,CAAC,aAAa,kBAAkB,eAAe,IAAI,cAAc,CAAC,CAAC,aAAa,KAAK;CAC3F,MAAM,CAAC,aAAa,kBAAkB,SAAwB,IAAI;CAElE,gBAAgB;EACd,IAAI,CAAC,IAAI;GACP,eAAe,KAAK;GACpB;EACF;EACA,OAAO,GAAG,qBAAqB,WAAW;GACxC,eAAe,OAAO,SAAS;EACjC,CAAC;CACH,GAAG,CAAC,EAAE,CAAC;CAyBP,OAAO;EACL;EACA,SAzBc,KAAK,cAAc;EA0BjC;EACA,SAzBc,YAAY,YAAmD;GAC7E,IAAI,CAAC,aAAa;IAChB,eAAe,eAAe;IAC9B;GACF;GAEA,IAAI,CAAC,IAAI,iBAAiB,IAAI;GAC9B,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,IAAI,CAAC,IAAI,iBAAiB,KAAK;GACjC;EACF,GAAG;GAAC;GAAI;GAAiB;GAAM;EAAW,CAMlC;CACR;AACF;;;;;;;;;;;;;;;;;;;;ACrEA,SAAgB,cAAc,IAAkC;CAC9D,MAAM,CAAC,QAAQ,aAAa,eAAe,GAAG,cAAc,CAAC;CAE7D,gBAAgB,GAAG,oBAAoB,SAAS,GAAG,CAAC,EAAE,CAAC;CAEvD,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "event-sourced-collection",
|
|
3
|
-
"version": "0.0.
|
|
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": "
|
|
64
|
-
"vite": "
|
|
65
|
-
"vite-plus": "
|
|
66
|
-
"vitest": "
|
|
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"}
|