@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 +70 -64
- package/package.json +3 -3
- package/LICENSE.md +0 -21
- package/index.d.mts +0 -82
- package/index.d.ts +0 -82
- package/index.js +0 -2290
- package/index.mjs +0 -2282
package/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# `@asaidimu/utils-persistence`
|
1
|
+
# `@asaidimu/utils-persistence`
|
2
|
+
|
3
|
+
**Robust Data Persistence for Web Applications**
|
2
4
|
|
3
5
|
[](https://www.npmjs.com/package/@asaidimu/utils-persistence)
|
4
6
|
[](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
|
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
|
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
|
-
###
|
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: `
|
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
|
337
|
+
// const anotherInstanceId = uuidv4();
|
317
338
|
// const anotherNotificationStore = new WebStoragePersistence<NotificationState>('app-notifications');
|
318
|
-
// anotherNotificationStore.set(
|
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 `
|
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
|
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
|
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
|
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
|
731
|
+
cd erp-utils # Navigate to the monorepo root
|
726
732
|
```
|
727
|
-
2. **Install Dependencies**:
|
733
|
+
2. **Install Dependencies**: Install all monorepo dependencies.
|
728
734
|
```bash
|
729
|
-
|
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
|
738
|
-
* `npm run test
|
739
|
-
* `npm run test:watch
|
740
|
-
* `npm run lint
|
741
|
-
* `npm run format
|
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
|
-
|
755
|
+
bun test
|
750
756
|
```
|
751
757
|
* To run tests in watch mode during development:
|
752
758
|
```bash
|
753
|
-
|
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
|
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
|
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
|
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": "
|
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": "
|
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 };
|