fix(core): Fix state initialization, hash detection, and validation - v2.0.25
Some checks failed
Default (tags) / security (push) Successful in 42s
Default (tags) / test (push) Successful in 1m8s
Default (tags) / release (push) Failing after 59s
Default (tags) / metadata (push) Successful in 1m8s

This commit is contained in:
2025-07-29 19:26:03 +00:00
parent 09fc53aaff
commit 02575e8baf
8 changed files with 370 additions and 61 deletions

126
readme.md
View File

@@ -1,12 +1,19 @@
# @push.rocks/smartstate
A package for handling and managing state in applications
A powerful TypeScript library for elegant state management using RxJS and reactive programming patterns
## Install
To install `@push.rocks/smartstate`, you can use pnpm (Performant Node Package Manager). Run the following command in your terminal:
To install `@push.rocks/smartstate`, you can use pnpm, npm, or yarn:
```bash
# Using pnpm (recommended)
pnpm install @push.rocks/smartstate --save
# Using npm
npm install @push.rocks/smartstate --save
# Using yarn
yarn add @push.rocks/smartstate
```
This will add `@push.rocks/smartstate` to your project's dependencies.
@@ -35,10 +42,10 @@ const myAppSmartState = new Smartstate<YourStatePartNamesEnum>();
When creating state parts, you can specify different initialization modes:
- **`'soft'`** - Allows existing state parts to remain (default behavior)
- **`'mandatory'`** - Fails if there's an existing state part with the same name
- **`'force'`** - Overwrites any existing state part
- **`'persistent'`** - Enables WebStore persistence using IndexedDB
- **`'soft'`** (default) - Returns existing state part if it exists, creates new if not
- **`'mandatory'`** - Requires state part to not exist, fails if it does
- **`'force'`** - Always creates new state part, overwriting any existing one
- **`'persistent'`** - Like 'soft' but with WebStore persistence using IndexedDB
### Defining State Parts
@@ -79,6 +86,7 @@ const userStatePart = await myAppSmartState.getStatePart<IUserState>(
You can subscribe to changes in a state part to perform actions accordingly:
```typescript
// The select() method automatically filters out undefined states
userStatePart.select().subscribe((currentState) => {
console.log(`User Logged In: ${currentState.isLoggedIn}`);
});
@@ -134,6 +142,12 @@ Both methods return a Promise with the new state, giving you flexibility in how
`StatePart` provides several useful methods for state management:
```typescript
// Get current state (may be undefined initially)
const currentState = userStatePart.getState();
if (currentState) {
console.log('Current user:', currentState.username);
}
// Wait for a specific state condition
await userStatePart.waitUntilPresent();
@@ -170,13 +184,33 @@ Persistent state automatically:
- Restores state on application restart
- Manages storage with configurable database and store names
### State Validation
`Smartstate` includes built-in state validation to ensure data integrity:
```typescript
// Basic validation (built-in)
// Ensures state is not null or undefined
await userStatePart.setState(null); // Throws error: Invalid state structure
// Custom validation by extending StatePart
class ValidatedStatePart<T> extends StatePart<string, T> {
protected validateState(stateArg: any): stateArg is T {
// Add your custom validation logic
return super.validateState(stateArg) && /* your validation */;
}
}
```
### Performance Optimization
`Smartstate` includes built-in performance optimizations:
`Smartstate` includes advanced performance optimizations:
- **State Change Detection**: Detects actual state changes to prevent unnecessary notifications when state values haven't truly changed
- **Async State Hash Detection**: Uses SHA256 hashing to detect actual state changes, preventing unnecessary notifications when state values haven't truly changed
- **Duplicate Prevention**: Identical state updates are automatically filtered out
- **Cumulative Notifications**: Batch multiple state changes into a single notification using `notifyChangeCumulative()`
- **Selective Subscriptions**: Use selectors to subscribe only to specific state properties
- **Undefined State Filtering**: The `select()` method automatically filters out undefined states
### RxJS Integration
@@ -202,19 +236,75 @@ userStatePart.select(state => state.username)
});
```
### Comprehensive Usage
### Complete Example
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.
Here's a comprehensive example showcasing the power of `@push.rocks/smartstate`:
Key features:
- **Type-safe state management** with full TypeScript support
- **Reactive state updates** using RxJS observables
- **Persistent state** with IndexedDB storage
- **Performance optimized** with state hash detection
- **Modular architecture** with separate state parts
- **Action-based updates** for predictable state modifications
```typescript
import { Smartstate, StatePart, StateAction } from '@push.rocks/smartstate';
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.
// Define your state structure
type AppStateParts = 'user' | 'settings' | 'cart';
interface IUserState {
isLoggedIn: boolean;
username?: string;
email?: string;
}
interface ICartState {
items: Array<{ id: string; quantity: number }>;
total: number;
}
// Create the smartstate instance
const appState = new Smartstate<AppStateParts>();
// Initialize state parts
const userState = await appState.getStatePart<IUserState>('user', {
isLoggedIn: false
});
const cartState = await appState.getStatePart<ICartState>('cart', {
items: [],
total: 0
}, 'persistent'); // Persists across sessions
// Create actions
const loginAction = userState.createAction<{ username: string; email: string }>(
async (statePart, payload) => {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
return {
isLoggedIn: true,
username: payload.username,
email: payload.email
};
}
);
// Subscribe to changes
userState.select(state => state.isLoggedIn).subscribe(isLoggedIn => {
console.log('Login status changed:', isLoggedIn);
});
// Dispatch actions
await loginAction.trigger({ username: 'john', email: 'john@example.com' });
```
### Key Features
`@push.rocks/smartstate` provides a robust foundation for state management:
- **🎯 Type-safe** - Full TypeScript support with intelligent type inference
- **⚡ Performance optimized** - Async state hash detection prevents unnecessary re-renders
- **💾 Persistent state** - Built-in IndexedDB support for state persistence
- **🔄 Reactive** - Powered by RxJS for elegant async handling
- **🧩 Modular** - Organize state into logical, reusable parts
- **✅ Validated** - Built-in state validation with extensible validation logic
- **🎭 Flexible init modes** - Choose how state parts are initialized
- **📦 Zero config** - Works out of the box with sensible defaults
## License and Legal Information