fix(core): Fix state initialization, hash detection, and validation - v2.0.25
This commit is contained in:
@@ -4,7 +4,7 @@ import { StateAction, type IActionDef } from './smartstate.classes.stateaction.j
|
||||
export class StatePart<TStatePartName, TStatePayload> {
|
||||
public name: TStatePartName;
|
||||
public state = new plugins.smartrx.rxjs.Subject<TStatePayload>();
|
||||
public stateStore: TStatePayload;
|
||||
public stateStore: TStatePayload | undefined;
|
||||
private cumulativeDeferred = plugins.smartpromise.cumulativeDefer();
|
||||
|
||||
private webStoreOptions: plugins.webstore.IWebStoreOptions;
|
||||
@@ -27,9 +27,9 @@ export class StatePart<TStatePartName, TStatePayload> {
|
||||
this.webStore = new plugins.webstore.WebStore<TStatePayload>(this.webStoreOptions);
|
||||
await this.webStore.init();
|
||||
const storedState = await this.webStore.get(String(this.name));
|
||||
if (storedState) {
|
||||
if (storedState && this.validateState(storedState)) {
|
||||
this.stateStore = storedState;
|
||||
this.notifyChange();
|
||||
await this.notifyChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ export class StatePart<TStatePartName, TStatePayload> {
|
||||
/**
|
||||
* gets the state from the state store
|
||||
*/
|
||||
public getState(): TStatePayload {
|
||||
public getState(): TStatePayload | undefined {
|
||||
return this.stateStore;
|
||||
}
|
||||
|
||||
@@ -46,8 +46,13 @@ export class StatePart<TStatePartName, TStatePayload> {
|
||||
* @param newStateArg
|
||||
*/
|
||||
public async setState(newStateArg: TStatePayload) {
|
||||
// Validate state structure
|
||||
if (!this.validateState(newStateArg)) {
|
||||
throw new Error(`Invalid state structure for state part '${this.name}'`);
|
||||
}
|
||||
|
||||
this.stateStore = newStateArg;
|
||||
this.notifyChange();
|
||||
await this.notifyChange();
|
||||
|
||||
// Save state to WebStore if initialized
|
||||
if (this.webStore) {
|
||||
@@ -56,21 +61,34 @@ export class StatePart<TStatePartName, TStatePayload> {
|
||||
return this.stateStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates state structure - can be overridden for custom validation
|
||||
* @param stateArg
|
||||
*/
|
||||
protected validateState(stateArg: any): stateArg is TStatePayload {
|
||||
// Basic validation - ensure state is not null/undefined
|
||||
// Subclasses can override for more specific validation
|
||||
return stateArg !== null && stateArg !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* notifies of a change on the state
|
||||
*/
|
||||
public notifyChange() {
|
||||
const createStateHash = (stateArg: any) => {
|
||||
return plugins.smarthashWeb.sha256FromString(plugins.smartjson.stringify(stateArg));
|
||||
public async notifyChange() {
|
||||
if (!this.stateStore) {
|
||||
return;
|
||||
}
|
||||
const createStateHash = async (stateArg: any) => {
|
||||
return await plugins.smarthashWeb.sha256FromString(plugins.smartjson.stringify(stateArg));
|
||||
};
|
||||
const currentHash = await createStateHash(this.stateStore);
|
||||
if (
|
||||
this.stateStore &&
|
||||
this.lastStateNotificationPayloadHash &&
|
||||
createStateHash(this.stateStore) === this.lastStateNotificationPayloadHash
|
||||
currentHash === this.lastStateNotificationPayloadHash
|
||||
) {
|
||||
return;
|
||||
} else {
|
||||
this.lastStateNotificationPayloadHash = this.stateStore;
|
||||
this.lastStateNotificationPayloadHash = currentHash;
|
||||
}
|
||||
this.state.next(this.stateStore);
|
||||
}
|
||||
@@ -81,7 +99,11 @@ export class StatePart<TStatePartName, TStatePayload> {
|
||||
*/
|
||||
public notifyChangeCumulative() {
|
||||
// TODO: check viability
|
||||
setTimeout(() => this.state.next(this.stateStore), 0);
|
||||
setTimeout(async () => {
|
||||
if (this.stateStore) {
|
||||
await this.notifyChange();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,6 +117,7 @@ export class StatePart<TStatePartName, TStatePayload> {
|
||||
}
|
||||
const mapped = this.state.pipe(
|
||||
plugins.smartrx.rxjs.ops.startWith(this.getState()),
|
||||
plugins.smartrx.rxjs.ops.filter((stateArg): stateArg is TStatePayload => stateArg !== undefined),
|
||||
plugins.smartrx.rxjs.ops.map((stateArg) => {
|
||||
try {
|
||||
return selectorFn(stateArg);
|
||||
|
Reference in New Issue
Block a user