@asaidimu/utils-persistence 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,6 @@
1
- # `@asaidimu/utils-persistence` - Robust Data Persistence for Web Applications
1
+ # `@asaidimu/utils-persistence`
2
+
3
+ **Robust Data Persistence for Web Applications**
2
4
 
3
5
  [![npm version](https://img.shields.io/npm/v/@asaidimu/utils-persistence.svg?style=flat-square)](https://www.npmjs.com/package/@asaidimu/utils-persistence)
4
6
  [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE)
@@ -12,6 +14,9 @@
12
14
  * [Installation & Setup](#installation--setup)
13
15
  * [Usage Documentation](#usage-documentation)
14
16
  * [Core Interface: `SimplePersistence`](#core-interface-simplepersistence)
17
+ * [The Power of Adapters](#the-power-of-adapters)
18
+ * [Usage Guidelines](#usage-guidelines-for-those-consuming-the-simplepersistence-interface)
19
+ * [When to Use and When to Avoid `SimplePersistence`](#when-to-use-and-when-to-avoid-simplepersistence)
15
20
  * [Web Storage Persistence (`WebStoragePersistence`)](#web-storage-persistence-webstoragepersistence)
16
21
  * [IndexedDB Persistence (`IndexedDBPersistence`)](#indexeddb-persistence-indexeddbpersistence)
17
22
  * [Ephemeral Persistence (`EphemeralPersistence`)](#ephemeral-persistence-ephemeralpersistence)
@@ -35,7 +40,7 @@ This library is ideal for single-page applications (SPAs) that require robust st
35
40
  * `WebStoragePersistence`: Supports both `localStorage` (default) and `sessionStorage` for simple key-value storage. Ideal for user preferences or small, temporary data.
36
41
  * `IndexedDBPersistence`: Provides robust, high-capacity, and structured data storage for more complex needs like offline caching or large datasets. Leverages `@asaidimu/indexed` for simplified IndexedDB interactions.
37
42
  * `EphemeralPersistence`: Offers an in-memory store with cross-tab synchronization using a Last Write Wins (LWW) strategy. Ideal for transient, session-specific shared state that does not need to persist across page reloads.
38
- * **Automatic Cross-Instance Synchronization**: Real-time updates across multiple browser tabs, windows, or even components within the same tab. This is achieved by leveraging native `StorageEvent` (for `localStorage`) and `BroadcastChannel`-based event buses (for `WebStoragePersistence`, `IndexedDBPersistence`, and `EphemeralPersistence`).
43
+ * **Automatic Cross-Instance Synchronization**: Real-time updates across multiple browser tabs, windows, or even components within the same tab. This is achieved by leveraging native `StorageEvent` (for `localStorage`) and `BroadcastChannel`-based event buses (from `@asaidimu/events`) for `WebStoragePersistence`, `IndexedDBPersistence`, and `EphemeralPersistence`.
39
44
  * **Type-Safe**: Fully written in TypeScript, providing strong typing, compile-time checks, and autocompletion for a better developer experience.
40
45
  * **Lightweight & Minimal Dependencies**: Designed to be small and efficient, relying on a few focused internal utilities (`@asaidimu/events`, `@asaidimu/indexed`, `@asaidimu/query`).
41
46
  * **Robust Error Handling**: Includes internal error handling for common storage operations, providing clearer debugging messages when issues arise.
@@ -51,7 +56,7 @@ This library is ideal for single-page applications (SPAs) that require robust st
51
56
  To use `@asaidimu/utils-persistence`, you need:
52
57
 
53
58
  * Node.js (LTS version recommended)
54
- * npm or Yarn package manager
59
+ * npm, Yarn, or Bun package manager
55
60
  * A modern web browser environment (e.g., Chrome, Firefox, Safari, Edge) that supports `localStorage`, `sessionStorage`, `IndexedDB`, and `BroadcastChannel`.
56
61
 
57
62
  ### Installation Steps
@@ -59,13 +64,29 @@ To use `@asaidimu/utils-persistence`, you need:
59
64
  Install the package using your preferred package manager:
60
65
 
61
66
  ```bash
62
- # Using Yarn
67
+ # Using Bun
63
68
  bun add @asaidimu/utils-persistence
69
+
70
+ # Using Yarn
71
+ yarn add @asaidimu/utils-persistence
72
+
73
+ # Using npm
74
+ npm install @asaidimu/utils-persistence
75
+ ```
76
+
77
+ If you plan to use `uuid` for generating `instanceId`s as recommended in the examples, install it separately:
78
+
79
+ ```bash
80
+ bun add uuid
81
+ # or
82
+ yarn add uuid
83
+ # or
84
+ npm install uuid
64
85
  ```
65
86
 
66
87
  ### Configuration
67
88
 
68
- This library does not require global configuration. All settings are passed directly to the constructor of the respective persistence adapter during instantiation.
89
+ This library does not require global configuration. All settings are passed directly to the constructor of the respective persistence adapter during instantiation. For instance, `IndexedDBPersistence` requires a configuration object for its database and collection details.
69
90
 
70
91
  ### Verification
71
92
 
@@ -97,16 +118,6 @@ The library exposes a common interface `SimplePersistence<T>` that all adapters
97
118
 
98
119
  Every persistence adapter in this library implements the `SimplePersistence<T>` interface, where `T` is the type of data you want to persist. This interface is designed to be flexible, supporting both synchronous and asynchronous operations, and is especially geared towards handling multi-instance scenarios (e.g., multiple browser tabs or independent components sharing the same data).
99
120
 
100
- #### The Power of Adapters
101
- The adapter pattern used by `SimplePersistence<T>` is a key strength, enabling seamless swapping of persistence backends without altering application logic. This decoupling offers several advantages:
102
- - **Interchangeability**: Switch between storage mechanisms (e.g., `localStorage`, `IndexedDB`, an in-memory store, or a remote API) by simply changing the adapter, keeping the interface consistent.
103
- - **Scalability**: Start with a lightweight adapter (e.g., `EphemeralPersistence` for prototyping) and transition to a robust solution (e.g., `IndexedDBPersistence` or a server-based database) as needs evolve, with minimal changes to the consuming code.
104
- - **Extensibility**: Easily create custom adapters for new storage technologies or environments (e.g., file systems, serverless functions) while adhering to the same interface.
105
- - **Environment-Agnostic**: Use the same interface in browser, server, or hybrid applications, supporting diverse use cases like offline-first apps or cross-tab synchronization.
106
- - **Testing Simplicity**: Implement mock adapters for testing, isolating persistence logic without touching real storage.
107
-
108
- This flexibility ensures that the persistence layer can adapt to varying requirements, from small-scale prototypes to production-grade systems, while maintaining a consistent and predictable API.
109
-
110
121
  ```typescript
111
122
  export interface SimplePersistence<T> {
112
123
  /**
@@ -147,7 +158,17 @@ export interface SimplePersistence<T> {
147
158
  }
148
159
  ```
149
160
 
150
- ### Usage and Implementation Guidelines
161
+ ### The Power of Adapters
162
+ The adapter pattern used by `SimplePersistence<T>` is a key strength, enabling seamless swapping of persistence backends without altering application logic. This decoupling offers several advantages:
163
+ - **Interchangeability**: Switch between storage mechanisms (e.g., `localStorage`, `IndexedDB`, an in-memory store, or a remote API) by simply changing the adapter, keeping the interface consistent.
164
+ - **Scalability**: Start with a lightweight adapter (e.g., `EphemeralPersistence` for prototyping) and transition to a robust solution (e.g., `IndexedDBPersistence` or a server-based database) as needs evolve, with minimal changes to the consuming code.
165
+ - **Extensibility**: Easily create custom adapters for new storage technologies or environments (e.g., file systems, serverless functions) while adhering to the same interface.
166
+ - **Environment-Agnostic**: Use the same interface in browser, server, or hybrid applications, supporting diverse use cases like offline-first apps or cross-tab synchronization.
167
+ - **Testing Simplicity**: Implement mock adapters for testing, isolating persistence logic without touching real storage.
168
+
169
+ This flexibility ensures that the persistence layer can adapt to varying requirements, from small-scale prototypes to production-grade systems, while maintaining a consistent and predictable API.
170
+
171
+ ### Usage Guidelines (For those consuming the `SimplePersistence` interface)
151
172
 
152
173
  This section provides practical advice for consuming the `SimplePersistence<T>` interface.
153
174
 
@@ -172,7 +193,7 @@ It enables robust **multi-instance synchronization**. When multiple instances (e
172
193
 
173
194
  * **Generate Once:** Create a unique UUID for your consumer instance at its very beginning (e.g., when your main application component mounts or your service initializes).
174
195
  ```typescript
175
- import { v4 as uuidv4 } from 'uuid'; // Requires 'uuid' library to be installed: `npm install uuid`
196
+ import { v4 as uuidv4 } from 'uuid'; // Requires 'uuid' library to be installed: `bun add uuid`
176
197
 
177
198
  interface MyAppState {
178
199
  data: string;
@@ -279,7 +300,7 @@ It enables robust **multi-instance synchronization**. When multiple instances (e
279
300
  const settingsStore = new WebStoragePersistence<Settings>('app-settings');
280
301
 
281
302
  async function retrieveGlobalState() {
282
- const storedState = await settingsStore.get(); // Await for async adapters
303
+ const storedState = await settingsStore.get(); // Await for async adapters if it returns a Promise
283
304
  if (storedState) {
284
305
  console.log("Retrieved global app settings:", storedState);
285
306
  // Integrate storedState into your application's current state
@@ -313,9 +334,9 @@ It enables robust **multi-instance synchronization**. When multiple instances (e
313
334
 
314
335
  // To simulate a change from another instance, open a new browser tab
315
336
  // and run something like:
316
- // const anotherInstance = uuidv4();
337
+ // const anotherInstanceId = uuidv4();
317
338
  // const anotherNotificationStore = new WebStoragePersistence<NotificationState>('app-notifications');
318
- // anotherNotificationStore.set(anotherInstance, { count: 5, lastMessage: 'New notification!' });
339
+ // anotherNotificationStore.set(anotherInstanceId, { count: 5, lastMessage: 'New notification!' });
319
340
 
320
341
  // When no longer needed:
321
342
  // unsubscribe();
@@ -333,7 +354,7 @@ It enables robust **multi-instance synchronization**. When multiple instances (e
333
354
 
334
355
  async function resetUserData() {
335
356
  console.log("Attempting to clear all persisted user data...");
336
- const success = await userDataStore.clear(); // Await for async adapters
357
+ const success = await userDataStore.clear(); // Await for async adapters if it returns a Promise
337
358
  if (success) {
338
359
  console.log("All persisted user data cleared successfully.");
339
360
  } else {
@@ -651,51 +672,35 @@ async function manageSessionState() {
651
672
 
652
673
  The `@asaidimu/utils-persistence` library is structured to be modular and extensible, adhering strictly to the `SimplePersistence` interface as its core contract. This design promotes interchangeability and ease of maintenance.
653
674
 
654
- ### Directory Structure
655
-
656
- ```
657
- src/persistence/
658
- ├── index.ts # Export entry point for all persistence modules (SimplePersistence, WebStoragePersistence, IndexedDBPersistence, EphemeralPersistence)
659
- ├── types.ts # Defines the SimplePersistence interface and shared types (e.g., StorageEvents)
660
- ├── local-storage.ts # Implements SimplePersistence using Web Storage (localStorage/sessionStorage)
661
- ├── ephemeral.ts # Implements SimplePersistence using an in-memory store with LWW cross-tab sync
662
- ├── indexedb.ts # Implements SimplePersistence using IndexedDB
663
- ├── fixtures.ts # Generic test suite helper for SimplePersistence implementations
664
- ├── local-storage.test.ts # Test suite for WebStoragePersistence (assumed from local-storage.ts existence)
665
- ├── ephemeral.test.ts # Test suite for EphemeralPersistence
666
- └── indexedb.test.ts # Comprehensive test suite for the IndexedDBPersistence adapter
667
- └── README.md # This documentation file
668
- ```
669
-
670
675
  ### Core Components
671
676
 
672
677
  * **`SimplePersistence<T>` (in `types.ts`)**: This is the fundamental TypeScript interface that defines the contract for any persistence adapter. It ensures a consistent API for `set`, `get`, `subscribe`, and `clear` operations, regardless of the underlying storage mechanism.
673
- * **`WebStoragePersistence<T>` (in `local-storage.ts`)**:
678
+ * **`WebStoragePersistence<T>` (in `webstorage.ts`)**:
674
679
  * **Purpose**: Provides simple key-value persistence leveraging the browser's `localStorage` or `sessionStorage` APIs.
675
680
  * **Mechanism**: Directly interacts with `window.localStorage` or `window.sessionStorage`. Data is serialized/deserialized using `JSON.stringify` and `JSON.parse`.
676
- * **Synchronization**: Utilizes `window.addEventListener('storage', ...)` for `localStorage` (which triggers when changes occur in *other* tabs) and the `@asaidimu/events` event bus (which uses `BroadcastChannel` internally) to ensure real-time updates across multiple browser tabs for both `localStorage` and `sessionStorage`.
681
+ * **Synchronization**: Utilizes `window.addEventListener('storage', ...)` for `localStorage` (which triggers when changes occur in *other* tabs on the same origin) and the `@asaidimu/events` event bus (which uses `BroadcastChannel` internally) to ensure real-time updates across multiple browser tabs for both `localStorage` and `sessionStorage`.
677
682
  * **`EphemeralPersistence<T>` (in `ephemeral.ts`)**:
678
683
  * **Purpose**: Offers an in-memory store for transient data that needs cross-tab synchronization but *not* persistence across page reloads.
679
- * **Mechanism**: Stores data in a private class property.
684
+ * **Mechanism**: Stores data in a private class property. Data is cloned using `structuredClone` to prevent direct mutation issues.
680
685
  * **Synchronization**: Leverages the `@asaidimu/events` event bus (via `BroadcastChannel`) for cross-instance synchronization. It implements a Last Write Wins (LWW) strategy based on timestamps included in the broadcast events, ensuring all tabs converge to the most recently written state.
681
686
  * **`IndexedDBPersistence<T>` (in `indexedb.ts`)**:
682
687
  * **Purpose**: Provides robust, asynchronous persistence using the browser's `IndexedDB` API, suitable for larger datasets and structured data.
683
- * **Mechanism**: Builds upon `@asaidimu/indexed` for simplified IndexedDB interactions (handling databases, object stores, and transactions) and `@asaidimu/query` for declarative data querying.
684
- * **Shared Resources**: Employs a `SharedResources` singleton pattern to manage and cache database connections and collections efficiently across multiple instances of `IndexedDBPersistence`. This avoids redundant connections and ensures a single source of truth for IndexedDB operations within the application. It also manages a shared event bus per `database`/`store` combination.
688
+ * **Mechanism**: Builds upon `@asaidimu/indexed` for simplified IndexedDB interactions (handling databases, object stores, and transactions) and `@asaidimu/query` for declarative data querying. Data is stored in a specific `collection` (object store) within a `database`, identified by a `store` key.
689
+ * **Shared Resources**: Employs a `SharedResources` singleton pattern to manage and cache `Database` connections, `Collection` instances, and `EventBus` instances efficiently across multiple `IndexedDBPersistence` instances. This avoids redundant connections, ensures a single source of truth for IndexedDB operations, and manages global event listeners effectively.
685
690
  * **Synchronization**: Leverages the `@asaidimu/events` event bus (via `BroadcastChannel`) for cross-instance synchronization of IndexedDB changes, notifying other instances about updates.
686
691
  * **`@asaidimu/events`**: An internal utility package that provides a powerful, cross-tab compatible event bus using `BroadcastChannel`. It's crucial for enabling the automatic synchronization features of all persistence adapters.
687
- * **`@asaidimu/indexed` & `@asaidimu/query`**: These are internal utility packages specifically used by `IndexedDBPersistence` to abstract and simplify complex interactions with the native IndexedDB API, offering a more declarative and promise-based interface.
692
+ * **`@asaidimu/indexed` & `@asaidimu/query`**: These are internal utility packages specifically used by `IndexedDBPersistence` to abstract and simplify complex interactions with the native IndexedDB API, offering a more declarative and promise-based interface. `@asaidimu/indexed` handles database schema, versions, and CRUD operations, while `@asaidimu/query` provides a query builder for data retrieval.
688
693
 
689
694
  ### Data Flow for State Changes
690
695
 
691
696
  1. **Setting State (`set(instanceId, state)`):**
692
- * The provided `state` (of type `T`) is first serialized into a format suitable for the underlying storage (e.g., `JSON.stringify` for web storage, or directly as an object for IndexedDB/Ephemeral).
693
- * It's then saved to the respective storage mechanism (`localStorage`, `sessionStorage`, in-memory, or an IndexedDB object store).
694
- * An event (of type `store:updated`) is immediately `emit`ted on an internal event bus (from `@asaidimu/events`). This event includes the `instanceId` of the updater, the `storageKey`/`store` identifying the data, and the new `state`. For `EphemeralPersistence`, a `timestamp` is also included for LWW. This event is broadcast to other browser tabs via `BroadcastChannel` (managed by `@asaidimu/events`).
697
+ * The provided `state` (of type `T`) is first serialized into a format suitable for the underlying storage (e.g., `JSON.stringify` for web storage, or `structuredClone` for ephemeral, or directly as an object for IndexedDB).
698
+ * It's then saved to the respective storage mechanism (`localStorage`, `sessionStorage`, in-memory, or an IndexedDB object store). For IndexedDB, existing data for the given `store` key is updated, or new data is created.
699
+ * An event (of type `store:updated`) is immediately `emit`ted on an internal event bus (from `@asaidimu/events`). This event includes the `instanceId` of the updater, the `storageKey`/`store` identifying the data, and the new `state`. For `EphemeralPersistence`, a `timestamp` is also included for LWW resolution. This event is broadcast to other browser tabs via `BroadcastChannel` (managed by `@asaidimu/events`).
695
700
  * For `localStorage`, native `StorageEvent`s also trigger when the value is set from another tab. The `WebStoragePersistence` adapter listens for these native events and re-emits them on its internal event bus, ensuring consistent notification pathways.
696
701
  2. **Getting State (`get()`):**
697
702
  * The adapter retrieves the serialized data using the configured `storageKey` or `store` from the underlying storage.
698
- * It attempts to parse/deserialize the data back into the original `T` type (e.g., `JSON.parse`).
703
+ * It attempts to parse/deserialize the data back into the original `T` type (e.g., `JSON.parse` or direct access).
699
704
  * Returns the deserialized data, or `null` if the data is not found or cannot be parsed.
700
705
  3. **Subscribing to Changes (`subscribe(instanceId, callback)`):**
701
706
  * A consumer instance registers a `callback` function with its unique `instanceId` to listen for `store:updated` events on the internal event bus.
@@ -710,6 +715,7 @@ For example, you could create adapters for:
710
715
 
711
716
  * **Remote Backend API**: An adapter that persists data to a remote server endpoint via `fetch` or `XMLHttpRequest`, enabling cross-device synchronization.
712
717
  * **Service Worker Cache API**: Leverage Service Workers for advanced caching strategies, providing highly performant offline capabilities.
718
+ * **Custom Local Storage**: Implement a persistence layer over a custom browser extension storage or a file system in an Electron app.
713
719
 
714
720
  ---
715
721
 
@@ -719,26 +725,26 @@ We welcome contributions to `@asaidimu/utils-persistence`! Please follow these g
719
725
 
720
726
  ### Development Setup
721
727
 
722
- 1. **Clone the Repository**: This library is likely part of a larger monorepo.
728
+ 1. **Clone the Repository**: This library is part of a larger monorepo.
723
729
  ```bash
724
730
  git clone https://github.com/asaidimu/erp-utils.git # Or the actual monorepo URL
725
- cd erp-utils-packages/utils-src/persistence # Adjust path as necessary
731
+ cd erp-utils # Navigate to the monorepo root
726
732
  ```
727
- 2. **Install Dependencies**: Navigate to the root of the monorepo first if applicable, then install.
733
+ 2. **Install Dependencies**: Install all monorepo dependencies.
728
734
  ```bash
729
- npm install # or yarn install
735
+ bun install # or yarn install or npm install
730
736
  ```
731
737
  This will install all necessary development dependencies, including TypeScript, Vitest, ESLint, and Prettier.
732
738
 
733
739
  ### Scripts
734
740
 
735
- The following `npm` scripts are available for development:
741
+ The following `npm` scripts are available for development within the `src/persistence` directory (or can be run from the monorepo root if configured):
736
742
 
737
- * `npm run build`: Compiles the TypeScript source files to JavaScript.
738
- * `npm run test`: Runs the test suite using `vitest`.
739
- * `npm run test:watch`: Runs tests in watch mode, re-running on file changes.
740
- * `npm run lint`: Lints the codebase using ESLint to identify potential issues and enforce coding standards.
741
- * `npm run format`: Formats the code using Prettier to ensure consistent code style.
743
+ * `bun run build` (or `npm run build`): Compiles the TypeScript source files to JavaScript.
744
+ * `bun run test` (or `npm run test`): Runs the test suite using `vitest`.
745
+ * `bun run test:watch` (or `npm run test:watch`): Runs tests in watch mode, re-running on file changes.
746
+ * `bun run lint` (or `npm run lint`): Lints the codebase using ESLint to identify potential issues and enforce coding standards.
747
+ * `bun run format` (or `npm run format`): Formats the code using Prettier to ensure consistent code style.
742
748
 
743
749
  ### Testing
744
750
 
@@ -746,11 +752,11 @@ Tests are crucial for maintaining the quality and stability of the library. The
746
752
 
747
753
  * To run all tests:
748
754
  ```bash
749
- npm test
755
+ bun test
750
756
  ```
751
757
  * To run tests in watch mode during development:
752
758
  ```bash
753
- npm run test:watch
759
+ bun test:watch
754
760
  ```
755
761
  * Ensure that your changes are covered by new or existing tests, and that all tests pass before submitting a pull request. The `fixtures.ts` file provides a generic test suite (`testSimplePersistence`) for any `SimplePersistence` implementation, ensuring consistent behavior across adapters.
756
762
 
@@ -758,7 +764,7 @@ Tests are crucial for maintaining the quality and stability of the library. The
758
764
 
759
765
  * **Fork the repository** and create your branch from `main`.
760
766
  * **Follow existing coding standards**: Adhere to the TypeScript, ESLint, and Prettier configurations defined in the project.
761
- * **Commit messages**: Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for clear and consistent commit history (e.g., `feat: add new adapter`, `fix: resolve subscription issue`, `docs: update README`).
767
+ * **Commit messages**: Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for clear and consistent commit history (e.g., `feat(persistence): add new adapter`, `fix(webstorage): resolve subscription issue`, `docs(readme): update usage examples`).
762
768
  * **Pull Requests**:
763
769
  * Open a pull request against the `main` branch.
764
770
  * Provide a clear and detailed description of your changes, including the problem solved and the approach taken.
@@ -768,7 +774,7 @@ Tests are crucial for maintaining the quality and stability of the library. The
768
774
 
769
775
  ### Issue Reporting
770
776
 
771
- If you find a bug or have a feature request, please open an issue on our [GitHub Issues page](https://github.com/asaidimu/erp-utils-issues). When reporting a bug, please include:
777
+ If you find a bug or have a feature request, please open an issue on our [GitHub Issues page](https://github.com/asaidimu/erp-utils/issues). When reporting a bug, please include:
772
778
 
773
779
  * A clear, concise title.
774
780
  * Steps to reproduce the issue.
@@ -784,7 +790,7 @@ If you find a bug or have a feature request, please open an issue on our [GitHub
784
790
  ### Troubleshooting
785
791
 
786
792
  * **Storage Limits**: Be aware that browser storage mechanisms have size limitations. `localStorage` and `sessionStorage` typically offer 5-10 MB, while `IndexedDB` can store much larger amounts (often gigabytes, depending on browser and available disk space). For large data sets, always prefer `IndexedDBPersistence`.
787
- * **JSON Parsing Errors**: `WebStoragePersistence`, `IndexedDBPersistence` (for the `data` field), and `EphemeralPersistence` serialize and deserialize your data using `JSON.stringify` and `JSON.parse` (or `structuredClone` for `EphemeralPersistence`). Ensure that the `state` object you are passing to `set` is a valid JSON-serializable object (i.e., it doesn't contain circular references, functions, or Symbols that JSON cannot handle).
793
+ * **JSON Parsing Errors**: `WebStoragePersistence` and `IndexedDBPersistence` (for the `data` field) serialize and deserialize your data using `JSON.stringify` and `JSON.parse`. `EphemeralPersistence` uses `structuredClone`. Ensure that the `state` object you are passing to `set` is a valid JSON-serializable object (i.e., it doesn't contain circular references, functions, or Symbols that JSON cannot handle).
788
794
  * **Cross-Origin Restrictions**: Browser storage is typically restricted to the same origin (protocol, host, port). You cannot access data stored by a different origin. Ensure your application is running on the same origin across all tabs for cross-tab synchronization to work.
789
795
  * **`IndexedDBPersistence` Asynchronous Nature**: Remember that `IndexedDBPersistence` methods (`set`, `get`, `clear`, `close`) return `Promise`s. Always use `await` or `.then()` to handle their results and ensure operations complete before proceeding. Forgetting to `await` can lead to unexpected behavior or race conditions.
790
796
  * **`EphemeralPersistence` Data Loss**: Data stored with `EphemeralPersistence` is *not* persisted across page reloads or browser restarts. It is strictly an in-memory solution synchronized across active tabs for the current browsing session. If you need data to survive refreshes, use `WebStoragePersistence` or `IndexedDBPersistence`.
@@ -815,11 +821,11 @@ Use `WebStoragePersistence` for small, persistent key-value data, and `IndexedDB
815
821
 
816
822
  ### Changelog
817
823
 
818
- For detailed changes between versions, please refer to the [CHANGELOG.md](CHANGELOG.md) file in the project's root directory (or specific package directory).
824
+ For detailed changes between versions, please refer to the [CHANGELOG.md](https://github.com/asaidimu/erp-utils/blob/main/packages/utils/src/persistence/CHANGELOG.md) file in the project's root directory (or specific package directory).
819
825
 
820
826
  ### License
821
827
 
822
- This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
828
+ This project is licensed under the MIT License. See the [LICENSE](https://github.com/asaidimu/erp-utils/blob/main/LICENSE) file for details.
823
829
 
824
830
  ### Acknowledgments
825
831
 
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@asaidimu/utils-persistence",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Persistence utilities.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
7
7
  "types": "index.d.ts",
8
8
  "files": [
9
- "./*"
9
+ "./dist/*"
10
10
  ],
11
11
  "keywords": [
12
12
  "typescript",
@@ -51,7 +51,7 @@
51
51
  [
52
52
  "@semantic-release/npm",
53
53
  {
54
- "pkgRoot": "../../dist/persistence"
54
+ "pkgRoot": "."
55
55
  }
56
56
  ],
57
57
  [
package/LICENSE.md DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Saidimu
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/index.d.mts DELETED
@@ -1,82 +0,0 @@
1
- import { S as SimplePersistence } from '../types-D26luDbE.js';
2
- export { a as StorageEvents } from '../types-D26luDbE.js';
3
-
4
- /**
5
- * Implements SimplePersistence using web storage (localStorage or sessionStorage).
6
- * Supports cross-tab synchronization via an event bus and native storage events when using localStorage.
7
- */
8
- declare class WebStoragePersistence<T extends object> implements SimplePersistence<T> {
9
- private readonly storageKey;
10
- private readonly eventBus;
11
- private readonly storage;
12
- /**
13
- * Initializes a new instance of WebStoragePersistence.
14
- * @param storageKey The key under which data is stored in web storage (e.g., 'user-profile').
15
- * @param session Optional flag; if true, uses sessionStorage instead of localStorage (default: false).
16
- */
17
- constructor(storageKey: string, session?: boolean);
18
- /**
19
- * Initializes the event bus with configured settings.
20
- * @returns Configured event bus instance.
21
- */
22
- private initializeEventBus;
23
- /**
24
- * Sets up a listener for native storage events to synchronize across tabs (localStorage only).
25
- */
26
- private setupStorageEventListener;
27
- /**
28
- * Persists the provided state to web storage and notifies subscribers.
29
- * @param instanceId Unique identifier of the instance making the update.
30
- * @param state The state to persist.
31
- * @returns True if successful, false if an error occurs.
32
- */
33
- set(instanceId: string, state: T): boolean;
34
- /**
35
- * Retrieves the current state from web storage.
36
- * @returns The persisted state, or null if not found or invalid.
37
- */
38
- get(): T | null;
39
- /**
40
- * Subscribes to updates in the persisted state, excluding the instance’s own changes.
41
- * @param instanceId Unique identifier of the subscribing instance.
42
- * @param onStateChange Callback to invoke with the updated state.
43
- * @returns Function to unsubscribe from updates.
44
- */
45
- subscribe(instanceId: string, onStateChange: (state: T) => void): () => void;
46
- /**
47
- * Removes the persisted state from web storage.
48
- * @returns True if successful, false if an error occurs.
49
- */
50
- clear(): boolean;
51
- }
52
-
53
- /**
54
- * Configuration for database connections
55
- */
56
- interface DatabaseConfig {
57
- store: string;
58
- database: string;
59
- collection: string;
60
- enableTelemetry?: boolean;
61
- }
62
- /**
63
- * IndexedDB persistence adapter with configurable database support
64
- */
65
- declare class IndexedDBPersistence<T> implements SimplePersistence<T> {
66
- private collection;
67
- private collectionPromise;
68
- private config;
69
- private eventBus;
70
- constructor(config: DatabaseConfig);
71
- private getCollection;
72
- set(id: string, state: T): Promise<boolean>;
73
- get(): Promise<T | null>;
74
- subscribe(id: string, callback: (state: T) => void): () => void;
75
- clear(): Promise<boolean>;
76
- /**
77
- * Close a specific database
78
- */
79
- close(): Promise<void>;
80
- }
81
-
82
- export { IndexedDBPersistence, SimplePersistence, WebStoragePersistence };
package/index.d.ts DELETED
@@ -1,82 +0,0 @@
1
- import { S as SimplePersistence } from '../types-D26luDbE.js';
2
- export { a as StorageEvents } from '../types-D26luDbE.js';
3
-
4
- /**
5
- * Implements SimplePersistence using web storage (localStorage or sessionStorage).
6
- * Supports cross-tab synchronization via an event bus and native storage events when using localStorage.
7
- */
8
- declare class WebStoragePersistence<T extends object> implements SimplePersistence<T> {
9
- private readonly storageKey;
10
- private readonly eventBus;
11
- private readonly storage;
12
- /**
13
- * Initializes a new instance of WebStoragePersistence.
14
- * @param storageKey The key under which data is stored in web storage (e.g., 'user-profile').
15
- * @param session Optional flag; if true, uses sessionStorage instead of localStorage (default: false).
16
- */
17
- constructor(storageKey: string, session?: boolean);
18
- /**
19
- * Initializes the event bus with configured settings.
20
- * @returns Configured event bus instance.
21
- */
22
- private initializeEventBus;
23
- /**
24
- * Sets up a listener for native storage events to synchronize across tabs (localStorage only).
25
- */
26
- private setupStorageEventListener;
27
- /**
28
- * Persists the provided state to web storage and notifies subscribers.
29
- * @param instanceId Unique identifier of the instance making the update.
30
- * @param state The state to persist.
31
- * @returns True if successful, false if an error occurs.
32
- */
33
- set(instanceId: string, state: T): boolean;
34
- /**
35
- * Retrieves the current state from web storage.
36
- * @returns The persisted state, or null if not found or invalid.
37
- */
38
- get(): T | null;
39
- /**
40
- * Subscribes to updates in the persisted state, excluding the instance’s own changes.
41
- * @param instanceId Unique identifier of the subscribing instance.
42
- * @param onStateChange Callback to invoke with the updated state.
43
- * @returns Function to unsubscribe from updates.
44
- */
45
- subscribe(instanceId: string, onStateChange: (state: T) => void): () => void;
46
- /**
47
- * Removes the persisted state from web storage.
48
- * @returns True if successful, false if an error occurs.
49
- */
50
- clear(): boolean;
51
- }
52
-
53
- /**
54
- * Configuration for database connections
55
- */
56
- interface DatabaseConfig {
57
- store: string;
58
- database: string;
59
- collection: string;
60
- enableTelemetry?: boolean;
61
- }
62
- /**
63
- * IndexedDB persistence adapter with configurable database support
64
- */
65
- declare class IndexedDBPersistence<T> implements SimplePersistence<T> {
66
- private collection;
67
- private collectionPromise;
68
- private config;
69
- private eventBus;
70
- constructor(config: DatabaseConfig);
71
- private getCollection;
72
- set(id: string, state: T): Promise<boolean>;
73
- get(): Promise<T | null>;
74
- subscribe(id: string, callback: (state: T) => void): () => void;
75
- clear(): Promise<boolean>;
76
- /**
77
- * Close a specific database
78
- */
79
- close(): Promise<void>;
80
- }
81
-
82
- export { IndexedDBPersistence, SimplePersistence, WebStoragePersistence };