@push.rocks/smartstate 2.0.20 → 2.0.22

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.
@@ -9,5 +9,5 @@ export declare class StateAction<TStateType, TActionPayloadType> {
9
9
  statePartRef: StatePart<any, any>;
10
10
  actionDef: IActionDef<TStateType, TActionPayloadType>;
11
11
  constructor(statePartRef: StatePart<any, any>, actionDef: IActionDef<TStateType, TActionPayloadType>);
12
- trigger(payload: TActionPayloadType): void;
12
+ trigger(payload: TActionPayloadType): Promise<TStateType>;
13
13
  }
@@ -9,7 +9,7 @@ export class StateAction {
9
9
  this.actionDef = actionDef;
10
10
  }
11
11
  trigger(payload) {
12
- this.statePartRef.dispatchAction(this, payload);
12
+ return this.statePartRef.dispatchAction(this, payload);
13
13
  }
14
14
  }
15
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdGF0ZS5jbGFzc2VzLnN0YXRlYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzdGF0ZS5jbGFzc2VzLnN0YXRlYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBTTlEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFDdEIsWUFDUyxZQUFpQyxFQUNqQyxTQUFxRDtRQURyRCxpQkFBWSxHQUFaLFlBQVksQ0FBcUI7UUFDakMsY0FBUyxHQUFULFNBQVMsQ0FBNEM7SUFDM0QsQ0FBQztJQUVHLE9BQU8sQ0FBQyxPQUEyQjtRQUN4QyxJQUFJLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDbEQsQ0FBQztDQUNGIn0=
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdGF0ZS5jbGFzc2VzLnN0YXRlYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzdGF0ZS5jbGFzc2VzLnN0YXRlYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBTTlEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFDdEIsWUFDUyxZQUFpQyxFQUNqQyxTQUFxRDtRQURyRCxpQkFBWSxHQUFaLFlBQVksQ0FBcUI7UUFDakMsY0FBUyxHQUFULFNBQVMsQ0FBNEM7SUFDM0QsQ0FBQztJQUVHLE9BQU8sQ0FBQyxPQUEyQjtRQUN4QyxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUN6RCxDQUFDO0NBQ0YifQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartstate",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
4
4
  "private": false,
5
5
  "description": "A package for handling and managing state in applications.",
6
6
  "main": "dist_ts/index.js",
package/readme.hints.md CHANGED
@@ -1 +1,39 @@
1
-
1
+ # Smartstate Implementation Notes
2
+
3
+ ## Current API (as of analysis)
4
+
5
+ ### State Part Initialization
6
+ - State parts can be created with different init modes: 'soft', 'mandatory', 'force', 'persistent'
7
+ - Persistent mode automatically calls init() internally - no need to call it manually
8
+ - WebStore integration for persistent state uses IndexedDB
9
+
10
+ ### Actions
11
+ - Actions are created with `createAction()` method
12
+ - Two ways to dispatch actions:
13
+ 1. `stateAction.trigger(payload)` - returns Promise<TStatePayload>
14
+ 2. `await statePart.dispatchAction(stateAction, payload)` - returns Promise<TStatePayload>
15
+ - Both methods now return the same Promise, providing flexibility in usage
16
+
17
+ ### State Management Methods
18
+ - `select()` - returns Observable with startWith current state
19
+ - `waitUntilPresent()` - waits for specific state condition
20
+ - `stateSetup()` - async state initialization with cumulative defer
21
+ - `notifyChangeCumulative()` - defers notification to end of call stack (no callback parameter)
22
+
23
+ ### State Hash Detection
24
+ - Uses SHA256 hash to detect actual state changes
25
+ - Bug: Currently stores the state object itself as hash instead of the actual hash
26
+ - This prevents proper duplicate notification prevention
27
+
28
+ ### Type System
29
+ - Can use either enums or string literal types for state part names
30
+ - Test uses simple string types: `type TMyStateParts = 'testStatePart'`
31
+
32
+ ## Fixed Issues in Documentation
33
+ 1. Updated trigger() to return Promise (API enhancement)
34
+ 2. Added dispatchAction as alternative method
35
+ 3. Corrected notifyChangeCumulative usage
36
+ 4. Clarified persistent mode auto-init
37
+ 5. Added stateSetup documentation
38
+ 6. Fixed state hash detection description
39
+ 7. Both trigger() and dispatchAction() now return Promise for consistency
package/readme.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # @push.rocks/smartstate
2
- a package that handles state in a good way
2
+ A package for handling and managing state in applications
3
3
 
4
4
  ## Install
5
5
 
6
- To install `@push.rocks/smartstate`, you can use npm (Node Package Manager). Run the following command in your terminal:
6
+ To install `@push.rocks/smartstate`, you can use pnpm (Performant Node Package Manager). Run the following command in your terminal:
7
7
 
8
8
  ```bash
9
- npm install @push.rocks/smartstate --save
9
+ pnpm install @push.rocks/smartstate --save
10
10
  ```
11
11
 
12
12
  This will add `@push.rocks/smartstate` to your project's dependencies.
@@ -31,17 +31,30 @@ import { Smartstate, StatePart, StateAction } from '@push.rocks/smartstate';
31
31
  const myAppSmartState = new Smartstate<YourStatePartNamesEnum>();
32
32
  ```
33
33
 
34
+ ### Understanding Init Modes
35
+
36
+ When creating state parts, you can specify different initialization modes:
37
+
38
+ - **`'soft'`** - Allows existing state parts to remain (default behavior)
39
+ - **`'mandatory'`** - Fails if there's an existing state part with the same name
40
+ - **`'force'`** - Overwrites any existing state part
41
+ - **`'persistent'`** - Enables WebStore persistence using IndexedDB
42
+
34
43
  ### Defining State Parts
35
44
 
36
45
  State parts represent separable sections of your state, making it easier to manage and modularize. For example, you may have a state part for user data and another for application settings.
37
46
 
38
- Define an enum for state part names for better management:
47
+ Define state part names using either enums or string literal types:
39
48
 
40
49
  ```typescript
50
+ // Option 1: Using enums
41
51
  enum AppStateParts {
42
- UserState,
43
- SettingsState
52
+ UserState = 'UserState',
53
+ SettingsState = 'SettingsState'
44
54
  }
55
+
56
+ // Option 2: Using string literal types (simpler approach)
57
+ type AppStateParts = 'UserState' | 'SettingsState';
45
58
  ```
46
59
 
47
60
  Now, let's create a state part within our `myAppSmartState` instance:
@@ -54,8 +67,11 @@ interface IUserState {
54
67
 
55
68
  const userStatePart = await myAppSmartState.getStatePart<IUserState>(
56
69
  AppStateParts.UserState,
57
- { isLoggedIn: false } // Initial state
70
+ { isLoggedIn: false }, // Initial state
71
+ 'soft' // Init mode (optional, defaults to 'soft')
58
72
  );
73
+
74
+ // Note: Persistent state parts are automatically initialized internally
59
75
  ```
60
76
 
61
77
  ### Subscribing to State Changes
@@ -93,27 +109,110 @@ const loginUserAction = userStatePart.createAction<ILoginPayload>(async (statePa
93
109
 
94
110
  // Dispatch the action to update the state
95
111
  loginUserAction.trigger({ username: 'johnDoe' });
112
+ // or await the result
113
+ const newState = await loginUserAction.trigger({ username: 'johnDoe' });
114
+ ```
115
+
116
+ ### Dispatching Actions
117
+
118
+ There are two ways to dispatch actions:
119
+
120
+ ```typescript
121
+ // Method 1: Using trigger on the action (returns promise)
122
+ const newState = await loginUserAction.trigger({ username: 'johnDoe' });
123
+ // or fire and forget
124
+ loginUserAction.trigger({ username: 'johnDoe' });
125
+
126
+ // Method 2: Using dispatchAction on the state part (returns promise)
127
+ const newState = await userStatePart.dispatchAction(loginUserAction, { username: 'johnDoe' });
128
+ ```
129
+
130
+ Both methods return a Promise with the new state, giving you flexibility in how you handle the result.
131
+
132
+ ### Additional State Methods
133
+
134
+ `StatePart` provides several useful methods for state management:
135
+
136
+ ```typescript
137
+ // Wait for a specific state condition
138
+ await userStatePart.waitUntilPresent();
139
+
140
+ // Wait for a specific property to be present
141
+ await userStatePart.waitUntilPresent(state => state.username);
142
+
143
+ // Setup initial state with async operations
144
+ await userStatePart.stateSetup(async (statePart) => {
145
+ // Perform async initialization
146
+ const userData = await fetchUserData();
147
+ return { ...statePart.getState(), ...userData };
148
+ });
149
+
150
+ // Defer notification to end of call stack
151
+ userStatePart.notifyChangeCumulative();
96
152
  ```
97
153
 
98
- ### Persistent State
154
+ ### Persistent State with WebStore
99
155
 
100
- `Smartstate` supports the concept of persistent states, where you can maintain state across sessions. To utilize this, specify a persistent mode when getting a state part:
156
+ `Smartstate` supports persistent states using WebStore (IndexedDB-based storage), allowing you to maintain state across sessions:
101
157
 
102
158
  ```typescript
103
- const settingsStatePart = await myAppSmartState.getStatePart<AppStateParts, ISettingsState>(
159
+ const settingsStatePart = await myAppSmartState.getStatePart<ISettingsState>(
104
160
  AppStateParts.SettingsState,
105
161
  { theme: 'light' }, // Initial state
106
162
  'persistent' // Mode
107
163
  );
164
+
165
+ // Note: init() is called automatically for persistent mode
108
166
  ```
109
167
 
110
- This mode ensures that the state is saved and can be reloaded even after the application restarts, providing a seamless user experience.
168
+ Persistent state automatically:
169
+ - Saves state changes to IndexedDB
170
+ - Restores state on application restart
171
+ - Manages storage with configurable database and store names
172
+
173
+ ### Performance Optimization
174
+
175
+ `Smartstate` includes built-in performance optimizations:
176
+
177
+ - **State Change Detection**: Detects actual state changes to prevent unnecessary notifications when state values haven't truly changed
178
+ - **Cumulative Notifications**: Batch multiple state changes into a single notification using `notifyChangeCumulative()`
179
+ - **Selective Subscriptions**: Use selectors to subscribe only to specific state properties
180
+
181
+ ### RxJS Integration
182
+
183
+ `Smartstate` leverages RxJS for reactive state management:
184
+
185
+ ```typescript
186
+ // State is exposed as an RxJS Subject
187
+ const stateObservable = userStatePart.select();
188
+
189
+ // Automatically starts with current state value
190
+ stateObservable.subscribe((state) => {
191
+ console.log('Current state:', state);
192
+ });
193
+
194
+ // Use selectors for specific properties
195
+ userStatePart.select(state => state.username)
196
+ .pipe(
197
+ distinctUntilChanged(),
198
+ filter(username => username !== undefined)
199
+ )
200
+ .subscribe(username => {
201
+ console.log('Username changed:', username);
202
+ });
203
+ ```
111
204
 
112
205
  ### Comprehensive Usage
113
206
 
114
207
  Putting it all together, `@push.rocks/smartstate` offers a flexible and powerful pattern for managing application state. By modularizing state parts, subscribing to state changes, and controlling state modifications through actions, developers can maintain a clean and scalable architecture. Combining these strategies with persistent states unlocks the full potential for creating dynamic and user-friendly applications.
115
208
 
116
- Remember to leverage TypeScript for its excellent support for types and interfaces, enhancing your development experience with type checking and IntelliSense, ensuring a more reliable and maintainable codebase.
209
+ Key features:
210
+ - **Type-safe state management** with full TypeScript support
211
+ - **Reactive state updates** using RxJS observables
212
+ - **Persistent state** with IndexedDB storage
213
+ - **Performance optimized** with state hash detection
214
+ - **Modular architecture** with separate state parts
215
+ - **Action-based updates** for predictable state modifications
117
216
 
118
217
  For more complex scenarios, consider combining multiple state parts, creating hierarchical state structures, and integrating with other state management solutions as needed. With `@push.rocks/smartstate`, the possibilities are vast, empowering you to tailor the state management approach to fit the unique requirements of your project.
119
218
 
@@ -14,7 +14,7 @@ export class StateAction<TStateType, TActionPayloadType> {
14
14
  public actionDef: IActionDef<TStateType, TActionPayloadType>
15
15
  ) {}
16
16
 
17
- public trigger(payload: TActionPayloadType) {
18
- this.statePartRef.dispatchAction(this, payload);
17
+ public trigger(payload: TActionPayloadType): Promise<TStateType> {
18
+ return this.statePartRef.dispatchAction(this, payload);
19
19
  }
20
20
  }