@slimr/dbsync 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +183 -0
  2. package/cjs/DbRepository.d.ts +59 -0
  3. package/cjs/DbRepository.js +78 -0
  4. package/cjs/DbRepository.js.map +1 -0
  5. package/cjs/DbSync.d.ts +51 -0
  6. package/cjs/DbSync.js +123 -0
  7. package/cjs/DbSync.js.map +1 -0
  8. package/cjs/DbTransaction.d.ts +60 -0
  9. package/cjs/DbTransaction.js +82 -0
  10. package/cjs/DbTransaction.js.map +1 -0
  11. package/cjs/DbTxRepository.d.ts +41 -0
  12. package/cjs/DbTxRepository.js +56 -0
  13. package/cjs/DbTxRepository.js.map +1 -0
  14. package/cjs/MigrationManager.d.ts +60 -0
  15. package/cjs/MigrationManager.js +69 -0
  16. package/cjs/MigrationManager.js.map +1 -0
  17. package/cjs/Repository.d.ts +59 -0
  18. package/cjs/Repository.js +78 -0
  19. package/cjs/Repository.js.map +1 -0
  20. package/cjs/adapters/RestAdapter.d.ts +13 -0
  21. package/cjs/adapters/RestAdapter.js +47 -0
  22. package/cjs/adapters/RestAdapter.js.map +1 -0
  23. package/cjs/adapters/index.d.ts +2 -0
  24. package/cjs/adapters/index.js +19 -0
  25. package/cjs/adapters/index.js.map +1 -0
  26. package/cjs/adapters/types.d.ts +11 -0
  27. package/cjs/adapters/types.js +3 -0
  28. package/cjs/adapters/types.js.map +1 -0
  29. package/cjs/index.d.ts +3 -0
  30. package/cjs/index.js +20 -0
  31. package/cjs/index.js.map +1 -0
  32. package/cjs/internal/AuthManager.d.ts +13 -0
  33. package/cjs/internal/AuthManager.js +34 -0
  34. package/cjs/internal/AuthManager.js.map +1 -0
  35. package/cjs/internal/DbTransaction.d.ts +60 -0
  36. package/cjs/internal/DbTransaction.js +82 -0
  37. package/cjs/internal/DbTransaction.js.map +1 -0
  38. package/cjs/internal/EventBus.d.ts +16 -0
  39. package/cjs/internal/EventBus.js +41 -0
  40. package/cjs/internal/EventBus.js.map +1 -0
  41. package/cjs/internal/MigrationManager.d.ts +60 -0
  42. package/cjs/internal/MigrationManager.js +69 -0
  43. package/cjs/internal/MigrationManager.js.map +1 -0
  44. package/cjs/internal/StorageManager.d.ts +20 -0
  45. package/cjs/internal/StorageManager.js +148 -0
  46. package/cjs/internal/StorageManager.js.map +1 -0
  47. package/cjs/internal/SyncEngine.d.ts +27 -0
  48. package/cjs/internal/SyncEngine.js +191 -0
  49. package/cjs/internal/SyncEngine.js.map +1 -0
  50. package/cjs/internal/utils.d.ts +1 -0
  51. package/cjs/internal/utils.js +7 -0
  52. package/cjs/internal/utils.js.map +1 -0
  53. package/cjs/react.d.ts +1 -0
  54. package/cjs/react.js +18 -0
  55. package/cjs/react.js.map +1 -0
  56. package/cjs/useDbQuery.d.ts +13 -0
  57. package/cjs/useDbQuery.js +59 -0
  58. package/cjs/useDbQuery.js.map +1 -0
  59. package/cjs/util/promiseWithResolvers.d.ts +11 -0
  60. package/cjs/util/promiseWithResolvers.js +19 -0
  61. package/cjs/util/promiseWithResolvers.js.map +1 -0
  62. package/esm/DbRepository.d.ts +59 -0
  63. package/esm/DbRepository.js +74 -0
  64. package/esm/DbRepository.js.map +1 -0
  65. package/esm/DbSync.d.ts +51 -0
  66. package/esm/DbSync.js +119 -0
  67. package/esm/DbSync.js.map +1 -0
  68. package/esm/DbTransaction.d.ts +60 -0
  69. package/esm/DbTransaction.js +78 -0
  70. package/esm/DbTransaction.js.map +1 -0
  71. package/esm/DbTxRepository.d.ts +41 -0
  72. package/esm/DbTxRepository.js +52 -0
  73. package/esm/DbTxRepository.js.map +1 -0
  74. package/esm/MigrationManager.d.ts +60 -0
  75. package/esm/MigrationManager.js +65 -0
  76. package/esm/MigrationManager.js.map +1 -0
  77. package/esm/Repository.d.ts +59 -0
  78. package/esm/Repository.js +74 -0
  79. package/esm/Repository.js.map +1 -0
  80. package/esm/adapters/RestAdapter.d.ts +13 -0
  81. package/esm/adapters/RestAdapter.js +43 -0
  82. package/esm/adapters/RestAdapter.js.map +1 -0
  83. package/esm/adapters/index.d.ts +2 -0
  84. package/esm/adapters/index.js +3 -0
  85. package/esm/adapters/index.js.map +1 -0
  86. package/esm/adapters/types.d.ts +11 -0
  87. package/esm/adapters/types.js +2 -0
  88. package/esm/adapters/types.js.map +1 -0
  89. package/esm/index.d.ts +3 -0
  90. package/esm/index.js +4 -0
  91. package/esm/index.js.map +1 -0
  92. package/esm/internal/AuthManager.d.ts +13 -0
  93. package/esm/internal/AuthManager.js +30 -0
  94. package/esm/internal/AuthManager.js.map +1 -0
  95. package/esm/internal/DbTransaction.d.ts +60 -0
  96. package/esm/internal/DbTransaction.js +78 -0
  97. package/esm/internal/DbTransaction.js.map +1 -0
  98. package/esm/internal/EventBus.d.ts +16 -0
  99. package/esm/internal/EventBus.js +37 -0
  100. package/esm/internal/EventBus.js.map +1 -0
  101. package/esm/internal/MigrationManager.d.ts +60 -0
  102. package/esm/internal/MigrationManager.js +65 -0
  103. package/esm/internal/MigrationManager.js.map +1 -0
  104. package/esm/internal/StorageManager.d.ts +20 -0
  105. package/esm/internal/StorageManager.js +144 -0
  106. package/esm/internal/StorageManager.js.map +1 -0
  107. package/esm/internal/SyncEngine.d.ts +27 -0
  108. package/esm/internal/SyncEngine.js +187 -0
  109. package/esm/internal/SyncEngine.js.map +1 -0
  110. package/esm/internal/utils.d.ts +1 -0
  111. package/esm/internal/utils.js +4 -0
  112. package/esm/internal/utils.js.map +1 -0
  113. package/esm/react.d.ts +1 -0
  114. package/esm/react.js +2 -0
  115. package/esm/react.js.map +1 -0
  116. package/esm/useDbQuery.d.ts +13 -0
  117. package/esm/useDbQuery.js +56 -0
  118. package/esm/useDbQuery.js.map +1 -0
  119. package/esm/util/promiseWithResolvers.d.ts +11 -0
  120. package/esm/util/promiseWithResolvers.js +16 -0
  121. package/esm/util/promiseWithResolvers.js.map +1 -0
  122. package/package.json +44 -0
package/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # 🪶 @slimr/dbsync [![npm package](https://img.shields.io/npm/v/@slimr/dbsync.svg?style=flat-square)](https://npmjs.org/package/@slimr/dbsync)
2
+
3
+ A powerfully slim, offline-first IndexedDB ORM and sync engine.
4
+
5
+ `@slimr/dbsync` provides a simple, Promise-based NoSQL API for browser data while automatically turning your app into a robust offline-first experience. It quietly queues changes made offline and perfectly synchronizes a local IndexedDB with a remote `@slimr/swift-crud` backed SQL database via background polling and Web Locks.
6
+
7
+ ## Context
8
+
9
+ `@slimr` is a set of slim React (hence '@slimr') libs. Check them all out on [github](https://github.com/bdombro/slimr)!
10
+
11
+ ## Why use `dbsync`?
12
+
13
+ - 🚀 **Zero-Config Schemas:** Define your tables and indexes in JS. `dbsync` automatically calculates schema signatures and handles IndexedDB `onupgradeneeded` version bumping and cross-device schema sync seamlessly.
14
+ - ⚡️ **Offline-First Resilience:** Read and write instantly, network or no network. Mutations are automatically written to a background queue and flushed to the backend as soon as connectivity is restored.
15
+ - 🔄 **Cross-Tab Reactivity:** Utilizing an internal Pub/Sub system and `BroadcastChannel`, any data changes (either local or synced from the server) instantly trigger subscribers, ensuring UI hooks eagerly re-render across all open tabs.
16
+ - 🔐 **First-Class Identity:** Deeply integrated with backend authentication, managing `isAuth` state, logins, and securely wiping local databases on logout.
17
+ - 🌱 **Zero Dependencies:** Built entirely on standard Web APIs (IndexedDB, BroadcastChannel, Web Locks, `fetch`). Fits the `@slimr` ethos perfectly.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @slimr/dbsync
23
+ ```
24
+
25
+ ## Quick Start
26
+ You instantiate `dbsync` by supplying your backend [adapter](./src/adapters/Adapters.md) and your table/index definitions. Afterwards, you must call `.init()` to safely generate the database.
27
+
28
+ ```typescript
29
+ import { DbSync } from '@slimr/dbsync';
30
+ import { RestAdapter } from '@slimr/dbsync/adapters';
31
+
32
+ const dbAdapter = new RestAdapter({ url: 'https://api.myapp.com' });
33
+
34
+ const db = new DbSync({
35
+ adapter: dbAdapter,
36
+ tables: {
37
+ posts: { indexes: ['userId', 'updatedAt'] },
38
+ users: { indexes: ['email'] }
39
+ }
40
+ });
41
+
42
+ // Await init before usage
43
+ await db.init();
44
+ ```
45
+
46
+ ## Schema Versioning
47
+
48
+ `@slimr/dbsync` automatically manages your IndexedDB database versioning to prevent schema mismatches and corruption across tabs and devices.
49
+
50
+ By default, you don't even need to provide a `version`. The library calculates a **deterministic schema signature** based on the tables and indexes you define in `tables`. If you modify your schema, the signature changes, the local IndexedDB version is automatically incremented, and this schema change is announced to the backend. Other tabs and devices syncing from the server will detect the new signature and safely reload to adapt to the new schema without mutating data out-of-bounds.
51
+
52
+ If you prefer explicit control, you can provide an exact `version: number` in the config. `@slimr/dbsync` will strictly enforce that exact version across the network instead.
53
+
54
+ ## The ORM API
55
+ Once initialized, `dbsync` acts as a fast NoSQL document store. To support offline-first behavior, you should generate IDs locally using `db.uuid()`.
56
+
57
+ ### Basic CRUD
58
+ ```typescript
59
+ // Create
60
+ const newPost = await db.put('posts', {
61
+ id: db.genUuid(),
62
+ content: 'Hello World!',
63
+ userId: 'user_123'
64
+ });
65
+
66
+ // Read
67
+ const myPost = await db.get('posts', newPost.id);
68
+ const allPosts = await db.findAll('posts');
69
+
70
+ // Delete
71
+ await db.delete('posts', newPost.id);
72
+ ```
73
+
74
+
75
+ ### Typed Repositories (`DbRepository`)
76
+ For a cleaner developer experience, you can wrap a table in a `DbRepository`. This automatically binds the table name and TypeScript generic to the CRUD methods so you don't have to repeat them everywhere.
77
+
78
+ ```typescript
79
+ import { DbRepository } from '@slimr/dbsync';
80
+
81
+ interface Post { id: string; content: string; }
82
+ const postsRepo = new DbRepository<Post>(db, 'posts');
83
+
84
+ // Types act natively without passing the table name again
85
+ await postsRepo.put({ id: '1', content: 'Cleaner code!' });
86
+ const post = await postsRepo.findById('1');
87
+ ```
88
+
89
+ ### Atomic Transactions
90
+ Need to update multiple records or cross-table data safely? Buffer them in memory and commit them all at once. In contrast to the transaction API of IndexedDB, `DbSync` transactions are purely in-memory and only hit the database when you call `commit()`. This means you can batch as many operations as you want without worrying about transaction timeouts, locks,
91
+ or the indexeddb quirk where it automatically commits after a certain number of operations.
92
+
93
+ ```typescript
94
+ const tx = db.getTransaction();
95
+
96
+ tx.put('posts', { id: '1', content: 'Atomic write 1' });
97
+ tx.put('posts', { id: '2', content: 'Atomic write 2' });
98
+ tx.delete('users', 'bad_user');
99
+
100
+ // Writes hit the database together
101
+ await tx.commit();
102
+ ```
103
+
104
+ Alternatively, you can create a `DbTxRepository`, similar to `DbRepository`, to encapsulate the raw table name semantics and enforce typescript hinting across your consumer app via a singleton:
105
+
106
+ ```typescript
107
+ import { DbTxRepository } from '@slimr/dbsync';
108
+
109
+ class Tx {
110
+ private tx = db.getTransaction();
111
+
112
+ // Wrap your tables for strict typings & intellisense
113
+ posts = new DbTxRepository<Post>(this.tx, 'posts');
114
+ users = new DbTxRepository<User>(this.tx, 'users');
115
+
116
+ commit = () => this.tx.commit();
117
+ }
118
+
119
+ const tx = new Tx();
120
+ tx.posts.put({ id: '1', content: 'Atomic write 1' });
121
+ tx.posts.put({ id: '2', content: 'Atomic write 2' });
122
+ tx.users.delete('bad_user');
123
+
124
+ // Writes hit the database together
125
+ await tx.commit();
126
+ ```
127
+
128
+ ### UI Reactivity (Pub/Sub)
129
+ Whenever a table is modified—whether by you manually, or by a background Sync Engine pull—`dbsync` announces the change.
130
+
131
+ ```typescript
132
+ const sub = db.subscribe((updatedStores) => {
133
+ if (updatedStores.includes('posts')) {
134
+ console.log('The posts table was just updated!');
135
+ // Trigger your React state re-render here
136
+ }
137
+ });
138
+
139
+ // Clean up on component unmount
140
+ sub.close();
141
+ ```
142
+
143
+ ### React Hook (`useDbQuery`)
144
+ For React users, `@slimr/dbsync` exports a built-in `useDbQuery` hook that makes binding components to your data effortless. It executes your query natively and instantly re-renders the component whenever the underlying table changes locally or remotely!
145
+
146
+ ```tsx
147
+ import { useDbQuery } from '@slimr/dbsync/react';
148
+
149
+ function PostList({ db }) {
150
+ // Re-renders automatically whenever the 'posts' table changes!
151
+ const posts = useDbQuery(db, 'posts', () => db.findAll('posts'));
152
+
153
+ if (!posts) return <Spinner />;
154
+ return <ul>{posts.map(p => <li key={p.id}>{p.content}</li>)}</ul>;
155
+ }
156
+ ```
157
+
158
+ ## The Offline Sync Engine
159
+ By routing your `put` and `delete` operations exclusively through the `DbSync` class, updates are silently logged into highly scalable native `dirtyQueue` and `deletedQueue` tables under-the-hood.
160
+
161
+ To boot up the network synchronizer to clear those queues and fetch server updates:
162
+
163
+ ```typescript
164
+ // Start polling the swift-crud backend every 5 seconds
165
+ db.enable();
166
+
167
+ // Stop polling
168
+ db.disable();
169
+ ```
170
+
171
+ Only one tab on a user's device will act as the "Leader" and poll the network at any time using **Web Locks**. All other tabs remain completely idle and rely on `BroadcastChannel` messages from the Leader tab to reactively update their UI when fresh data drops.
172
+
173
+
174
+ ## Session Management
175
+ Because offline data is fundamentally tied to an authenticated session, `DbSync` wraps the core identity commands to ensure background syncing strictly follows network permissions.
176
+
177
+ ```typescript
178
+ // Authenticate and unlock syncing
179
+ await db.login('user@email.com', '123456');
180
+
181
+ // Wipe the IndexedDB totally clean + log out immediately
182
+ await db.reset();
183
+ ```
@@ -0,0 +1,59 @@
1
+ import type { DbSync } from "./DbSync.js";
2
+ /**
3
+ * A typed repository wrapper for a single `DbSync` object store.
4
+ * Provides a localized CRUD interface to minimize boilerplate and
5
+ * enforce consistent data types for a specific table.
6
+ */
7
+ export declare class DbRepository<T> {
8
+ protected db: DbSync;
9
+ readonly storeName: string;
10
+ /**
11
+ * Initializes a new repository tied to a specific object store.
12
+ *
13
+ * @param db The centralized `DbSync` instance.
14
+ * @param storeName The name of the object store this repository will manage.
15
+ */
16
+ constructor(db: DbSync, storeName: string);
17
+ /**
18
+ * Retrieves a single record by its primary key.
19
+ *
20
+ * @param id The primary key of the record to retrieve.
21
+ * @returns A promise resolving to the typed record, or `undefined` if not found.
22
+ */
23
+ findById(id: string | number): Promise<T | undefined>;
24
+ /**
25
+ * Retrieves all records currently held in the object store.
26
+ *
27
+ * @returns A promise resolving to an array of all typed records.
28
+ */
29
+ findAll(): Promise<T[]>;
30
+ /**
31
+ * Inserts a new record into the object store.
32
+ *
33
+ * @param value The object payload to insert.
34
+ * @param key An optional explicit primary key.
35
+ * @returns A promise resolving to the newly inserted record.
36
+ */
37
+ add(value: Partial<T>, key?: string | number): Promise<T>;
38
+ /**
39
+ * Inserts or updates an existing record in the object store.
40
+ *
41
+ * @param value The complete object to upsert.
42
+ * @param key An optional explicit primary key.
43
+ * @returns A promise resolving to the upserted record.
44
+ */
45
+ put(value: T, key?: string | number): Promise<T>;
46
+ /**
47
+ * Removes a record from the object store by its primary key.
48
+ *
49
+ * @param key The primary key of the record to delete.
50
+ * @returns A promise resolving when the deletion is complete.
51
+ */
52
+ delete(key: string | number): Promise<void>;
53
+ /**
54
+ * Discards all records present in the object store.
55
+ *
56
+ * @returns A promise resolving when the store has been completely cleared.
57
+ */
58
+ clear(): Promise<void>;
59
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DbRepository = void 0;
4
+ /**
5
+ * A typed repository wrapper for a single `DbSync` object store.
6
+ * Provides a localized CRUD interface to minimize boilerplate and
7
+ * enforce consistent data types for a specific table.
8
+ */
9
+ class DbRepository {
10
+ db;
11
+ storeName;
12
+ /**
13
+ * Initializes a new repository tied to a specific object store.
14
+ *
15
+ * @param db The centralized `DbSync` instance.
16
+ * @param storeName The name of the object store this repository will manage.
17
+ */
18
+ constructor(db, storeName) {
19
+ this.db = db;
20
+ this.storeName = storeName;
21
+ }
22
+ /**
23
+ * Retrieves a single record by its primary key.
24
+ *
25
+ * @param id The primary key of the record to retrieve.
26
+ * @returns A promise resolving to the typed record, or `undefined` if not found.
27
+ */
28
+ async findById(id) {
29
+ return this.db.get(this.storeName, id);
30
+ }
31
+ /**
32
+ * Retrieves all records currently held in the object store.
33
+ *
34
+ * @returns A promise resolving to an array of all typed records.
35
+ */
36
+ async findAll() {
37
+ return this.db.findAll(this.storeName);
38
+ }
39
+ /**
40
+ * Inserts a new record into the object store.
41
+ *
42
+ * @param value The object payload to insert.
43
+ * @param key An optional explicit primary key.
44
+ * @returns A promise resolving to the newly inserted record.
45
+ */
46
+ async add(value, key) {
47
+ return this.db.add(this.storeName, value, key);
48
+ }
49
+ /**
50
+ * Inserts or updates an existing record in the object store.
51
+ *
52
+ * @param value The complete object to upsert.
53
+ * @param key An optional explicit primary key.
54
+ * @returns A promise resolving to the upserted record.
55
+ */
56
+ async put(value, key) {
57
+ return this.db.put(this.storeName, value, key);
58
+ }
59
+ /**
60
+ * Removes a record from the object store by its primary key.
61
+ *
62
+ * @param key The primary key of the record to delete.
63
+ * @returns A promise resolving when the deletion is complete.
64
+ */
65
+ async delete(key) {
66
+ return this.db.delete(this.storeName, key);
67
+ }
68
+ /**
69
+ * Discards all records present in the object store.
70
+ *
71
+ * @returns A promise resolving when the store has been completely cleared.
72
+ */
73
+ async clear() {
74
+ return this.db.clear(this.storeName);
75
+ }
76
+ }
77
+ exports.DbRepository = DbRepository;
78
+ //# sourceMappingURL=DbRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DbRepository.js","sourceRoot":"","sources":["../src/DbRepository.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACH,MAAa,YAAY;IAQb;IACM;IARjB;;;;;OAKG;IACH,YACW,EAAU,EACJ,SAAiB;QADvB,OAAE,GAAF,EAAE,CAAQ;QACJ,cAAS,GAAT,SAAS,CAAQ;IAC/B,CAAC;IAEJ;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAmB;QACjC,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAC1C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO;QACZ,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAI,IAAI,CAAC,SAAS,CAAC,CAAA;IAC1C,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CAAC,KAAiB,EAAE,GAAqB;QACjD,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAI,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;IAClD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CAAC,KAAQ,EAAE,GAAqB;QACxC,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAI,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;IAClD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,GAAoB;QAChC,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;IAC3C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACV,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;CACD;AAvED,oCAuEC"}
@@ -0,0 +1,51 @@
1
+ import type { BackendAdapter } from "./adapters/types.js";
2
+ import { type SyncState } from "./internal/EventBus.js";
3
+ import { StorageManager } from "./internal/StorageManager.js";
4
+ export interface DbSyncConfig {
5
+ adapter: BackendAdapter;
6
+ version?: number;
7
+ tables: Record<string, {
8
+ indexes?: string[];
9
+ }>;
10
+ }
11
+ export type { SyncState };
12
+ export declare class DbSync {
13
+ syncInterval: number;
14
+ config: DbSyncConfig;
15
+ private events;
16
+ storage: StorageManager;
17
+ private syncEngine;
18
+ private authManager;
19
+ constructor(config: DbSyncConfig);
20
+ genUuid(): `${string}-${string}-${string}-${string}-${string}`;
21
+ get initted(): boolean;
22
+ init(): Promise<void>;
23
+ getTransaction(): import("./internal/DbTransaction.js").DbTransaction;
24
+ get<T>(storeName: string, id: string | number): Promise<T | undefined>;
25
+ findAll<T>(storeName: string): Promise<T[]>;
26
+ add<T>(storeName: string, value: any, key?: string | number): Promise<T>;
27
+ put<T>(storeName: string, value: any, key?: string | number): Promise<T>;
28
+ delete(storeName: string, key: string | number): Promise<void>;
29
+ clear(storeName: string): Promise<void>;
30
+ subscribe(callback: (stores: string[]) => void): {
31
+ close: () => boolean;
32
+ };
33
+ onSyncStateChange(callback: (state: SyncState) => void): {
34
+ close: () => boolean;
35
+ };
36
+ get isAuth(): boolean;
37
+ checkAuth(): Promise<boolean>;
38
+ login(email: string, code: string): Promise<void>;
39
+ logout(): Promise<void>;
40
+ reset(): Promise<void>;
41
+ get isEnabled(): boolean;
42
+ get isLive(): boolean;
43
+ enable(): void;
44
+ disable(): void;
45
+ waitForLive(): Promise<void>;
46
+ triggerSync(): Promise<void>;
47
+ startSyncInterval(): void;
48
+ stopSyncInterval(): void;
49
+ protected onSchemaChangeDetected(): void;
50
+ dispose(): void;
51
+ }
package/cjs/DbSync.js ADDED
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DbSync = void 0;
4
+ const AuthManager_js_1 = require("./internal/AuthManager.js");
5
+ const EventBus_js_1 = require("./internal/EventBus.js");
6
+ const StorageManager_js_1 = require("./internal/StorageManager.js");
7
+ const SyncEngine_js_1 = require("./internal/SyncEngine.js");
8
+ const utils_js_1 = require("./internal/utils.js");
9
+ class DbSync {
10
+ syncInterval = 5000;
11
+ config;
12
+ // Internal managers
13
+ events;
14
+ storage; // Public for tests currently (we can wrap it later)
15
+ syncEngine;
16
+ authManager;
17
+ constructor(config) {
18
+ this.config = config;
19
+ this.events = new EventBus_js_1.EventBus();
20
+ const adapter = config.adapter;
21
+ const onSchemaChange = () => this.onSchemaChangeDetected();
22
+ this.storage = new StorageManager_js_1.StorageManager(config, this.events, onSchemaChange);
23
+ this.authManager = new AuthManager_js_1.AuthManager(adapter, this.storage, () => this.disable());
24
+ this.syncEngine = new SyncEngine_js_1.SyncEngine(config, this.syncInterval, this.events, this.storage, this.authManager, adapter, onSchemaChange);
25
+ }
26
+ // Facade to Utils
27
+ genUuid() {
28
+ return (0, utils_js_1.genUuid)();
29
+ }
30
+ // Facade to StorageManager
31
+ get initted() {
32
+ return this.storage.initted;
33
+ }
34
+ async init() {
35
+ return this.storage.init();
36
+ }
37
+ getTransaction() {
38
+ return this.storage.getTransaction();
39
+ } // Exported temporarily for tests
40
+ async get(storeName, id) {
41
+ return this.storage.get(storeName, id);
42
+ }
43
+ async findAll(storeName) {
44
+ return this.storage.findAll(storeName);
45
+ }
46
+ async add(storeName, value, key) {
47
+ await this.storage.executeTransaction([{ type: "add", storeName, value, key }]);
48
+ return value;
49
+ }
50
+ async put(storeName, value, key) {
51
+ await this.storage.executeTransaction([{ type: "put", storeName, value, key }]);
52
+ return value;
53
+ }
54
+ async delete(storeName, key) {
55
+ await this.storage.executeTransaction([{ type: "delete", storeName, key }]);
56
+ }
57
+ async clear(storeName) {
58
+ await this.storage.executeTransaction([{ type: "clear", storeName }]);
59
+ }
60
+ // Facade to EventBus
61
+ subscribe(callback) {
62
+ return this.events.subscribe(callback);
63
+ }
64
+ onSyncStateChange(callback) {
65
+ return this.events.onSyncStateChange(callback);
66
+ }
67
+ // Facade to AuthManager
68
+ get isAuth() {
69
+ return this.authManager.isAuth;
70
+ }
71
+ async checkAuth() {
72
+ return this.authManager.checkAuth();
73
+ }
74
+ async login(email, code) {
75
+ return this.authManager.login(email, code);
76
+ }
77
+ async logout() {
78
+ return this.authManager.logout();
79
+ }
80
+ async reset() {
81
+ return this.authManager.reset();
82
+ }
83
+ // Facade to SyncEngine
84
+ get isEnabled() {
85
+ return this.syncEngine.isEnabled;
86
+ }
87
+ get isLive() {
88
+ return this.syncEngine.isLive;
89
+ }
90
+ enable() {
91
+ this.syncEngine.enable();
92
+ }
93
+ disable() {
94
+ this.syncEngine.disable();
95
+ }
96
+ async waitForLive() {
97
+ return this.syncEngine.waitForLive();
98
+ }
99
+ async triggerSync() {
100
+ return this.syncEngine.triggerSync();
101
+ }
102
+ // Legacy aliases
103
+ startSyncInterval() {
104
+ this.enable();
105
+ }
106
+ stopSyncInterval() {
107
+ this.disable();
108
+ }
109
+ onSchemaChangeDetected() {
110
+ this.storage.dispose();
111
+ this.disable();
112
+ if (typeof window !== "undefined") {
113
+ window.location.reload();
114
+ }
115
+ }
116
+ dispose() {
117
+ this.disable();
118
+ this.events.dispose();
119
+ this.storage.dispose();
120
+ }
121
+ }
122
+ exports.DbSync = DbSync;
123
+ //# sourceMappingURL=DbSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DbSync.js","sourceRoot":"","sources":["../src/DbSync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Represents an atomic sequence of write operations.
3
+ * Operations are queued in memory and only executed against the target
4
+ * database when `commit()` is called.
5
+ */
6
+ export declare class DbTransaction {
7
+ private executor;
8
+ /**
9
+ * Stores the pending CRUD operations.
10
+ * @internal Evaluated and executed by the executor function upon `commit()`.
11
+ */
12
+ private operations;
13
+ /**
14
+ * Initializes the transaction with an execution engine.
15
+ * Should be instantiated via `DbSync.getTransaction()` rather than directly.
16
+ *
17
+ * @internal
18
+ * @param executor Provides the context needed to process the queued operations.
19
+ */
20
+ constructor(executor: (ops: any[]) => Promise<void>);
21
+ /**
22
+ * Queues an insertion operation.
23
+ *
24
+ * @param storeName The name of the target object store.
25
+ * @param value The object payload to insert.
26
+ * @param key An optional explicit primary key.
27
+ */
28
+ add(storeName: string, value: any, key?: string | number): void;
29
+ /**
30
+ * Queues an upsert (insert or update) operation.
31
+ *
32
+ * @param storeName The name of the target object store.
33
+ * @param value The object payload to write.
34
+ * @param key An optional explicit primary key.
35
+ */
36
+ put(storeName: string, value: any, key?: string | number): void;
37
+ /**
38
+ * Queues a deletion operation.
39
+ *
40
+ * @param storeName The name of the target object store.
41
+ * @param key The primary key of the record to remove.
42
+ */
43
+ delete(storeName: string, key: string | number): void;
44
+ /**
45
+ * Queues an operation to remove all records from an object store.
46
+ *
47
+ * @param storeName The name of the object store to clear.
48
+ */
49
+ clear(storeName: string): void;
50
+ /**
51
+ * Executes all queued operations atomically within a single database transaction.
52
+ *
53
+ * @returns A promise that resolves when the transaction successfully completes.
54
+ */
55
+ commit(): Promise<void>;
56
+ /**
57
+ * Discards all pending operations without modifying the database.
58
+ */
59
+ cancel(): void;
60
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ // DbTransaction does not depend on DbSync now
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.DbTransaction = void 0;
5
+ /**
6
+ * Represents an atomic sequence of write operations.
7
+ * Operations are queued in memory and only executed against the target
8
+ * database when `commit()` is called.
9
+ */
10
+ class DbTransaction {
11
+ executor;
12
+ /**
13
+ * Stores the pending CRUD operations.
14
+ * @internal Evaluated and executed by the executor function upon `commit()`.
15
+ */
16
+ operations = [];
17
+ /**
18
+ * Initializes the transaction with an execution engine.
19
+ * Should be instantiated via `DbSync.getTransaction()` rather than directly.
20
+ *
21
+ * @internal
22
+ * @param executor Provides the context needed to process the queued operations.
23
+ */
24
+ constructor(executor) {
25
+ this.executor = executor;
26
+ }
27
+ /**
28
+ * Queues an insertion operation.
29
+ *
30
+ * @param storeName The name of the target object store.
31
+ * @param value The object payload to insert.
32
+ * @param key An optional explicit primary key.
33
+ */
34
+ add(storeName, value, key) {
35
+ this.operations.push({ type: "add", storeName, value, key });
36
+ }
37
+ /**
38
+ * Queues an upsert (insert or update) operation.
39
+ *
40
+ * @param storeName The name of the target object store.
41
+ * @param value The object payload to write.
42
+ * @param key An optional explicit primary key.
43
+ */
44
+ put(storeName, value, key) {
45
+ this.operations.push({ type: "put", storeName, value, key });
46
+ }
47
+ /**
48
+ * Queues a deletion operation.
49
+ *
50
+ * @param storeName The name of the target object store.
51
+ * @param key The primary key of the record to remove.
52
+ */
53
+ delete(storeName, key) {
54
+ this.operations.push({ type: "delete", storeName, key });
55
+ }
56
+ /**
57
+ * Queues an operation to remove all records from an object store.
58
+ *
59
+ * @param storeName The name of the object store to clear.
60
+ */
61
+ clear(storeName) {
62
+ this.operations.push({ type: "clear", storeName });
63
+ }
64
+ /**
65
+ * Executes all queued operations atomically within a single database transaction.
66
+ *
67
+ * @returns A promise that resolves when the transaction successfully completes.
68
+ */
69
+ async commit() {
70
+ if (this.operations.length === 0)
71
+ return;
72
+ return this.executor(this.operations);
73
+ }
74
+ /**
75
+ * Discards all pending operations without modifying the database.
76
+ */
77
+ cancel() {
78
+ this.operations = [];
79
+ }
80
+ }
81
+ exports.DbTransaction = DbTransaction;
82
+ //# sourceMappingURL=DbTransaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DbTransaction.js","sourceRoot":"","sources":["../src/DbTransaction.ts"],"names":[],"mappings":";AAAA,8CAA8C;;;AAE9C;;;;GAIG;AACH,MAAa,aAAa;IAmBL;IAlBpB;;;OAGG;IACK,UAAU,GAKZ,EAAE,CAAA;IAER;;;;;;OAMG;IACH,YAAoB,QAAuC;QAAvC,aAAQ,GAAR,QAAQ,CAA+B;IAAG,CAAC;IAE/D;;;;;;OAMG;IACH,GAAG,CAAC,SAAiB,EAAE,KAAU,EAAE,GAAqB;QACvD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED;;;;;;OAMG;IACH,GAAG,CAAC,SAAiB,EAAE,KAAU,EAAE,GAAqB;QACvD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,SAAiB,EAAE,GAAoB;QAC7C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAA;IACzD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAiB;QACtB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;IACnD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM;QACX,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QACxC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACtC,CAAC;IAED;;OAEG;IACH,MAAM;QACL,IAAI,CAAC,UAAU,GAAG,EAAE,CAAA;IACrB,CAAC;CACD;AA9ED,sCA8EC"}