@push.rocks/smartstate 2.0.23 → 2.0.25

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.
@@ -4,7 +4,7 @@ import { StateAction, type IActionDef } from './smartstate.classes.stateaction.j
4
4
  export class StatePart<TStatePartName, TStatePayload> {
5
5
  public name: TStatePartName;
6
6
  public state = new plugins.smartrx.rxjs.Subject<TStatePayload>();
7
- public stateStore: TStatePayload;
7
+ public stateStore: TStatePayload | undefined;
8
8
  private cumulativeDeferred = plugins.smartpromise.cumulativeDefer();
9
9
 
10
10
  private webStoreOptions: plugins.webstore.IWebStoreOptions;
@@ -27,9 +27,9 @@ export class StatePart<TStatePartName, TStatePayload> {
27
27
  this.webStore = new plugins.webstore.WebStore<TStatePayload>(this.webStoreOptions);
28
28
  await this.webStore.init();
29
29
  const storedState = await this.webStore.get(String(this.name));
30
- if (storedState) {
30
+ if (storedState && this.validateState(storedState)) {
31
31
  this.stateStore = storedState;
32
- this.notifyChange();
32
+ await this.notifyChange();
33
33
  }
34
34
  }
35
35
  }
@@ -37,7 +37,7 @@ export class StatePart<TStatePartName, TStatePayload> {
37
37
  /**
38
38
  * gets the state from the state store
39
39
  */
40
- public getState(): TStatePayload {
40
+ public getState(): TStatePayload | undefined {
41
41
  return this.stateStore;
42
42
  }
43
43
 
@@ -46,8 +46,13 @@ export class StatePart<TStatePartName, TStatePayload> {
46
46
  * @param newStateArg
47
47
  */
48
48
  public async setState(newStateArg: TStatePayload) {
49
+ // Validate state structure
50
+ if (!this.validateState(newStateArg)) {
51
+ throw new Error(`Invalid state structure for state part '${this.name}'`);
52
+ }
53
+
49
54
  this.stateStore = newStateArg;
50
- this.notifyChange();
55
+ await this.notifyChange();
51
56
 
52
57
  // Save state to WebStore if initialized
53
58
  if (this.webStore) {
@@ -56,21 +61,34 @@ export class StatePart<TStatePartName, TStatePayload> {
56
61
  return this.stateStore;
57
62
  }
58
63
 
64
+ /**
65
+ * Validates state structure - can be overridden for custom validation
66
+ * @param stateArg
67
+ */
68
+ protected validateState(stateArg: any): stateArg is TStatePayload {
69
+ // Basic validation - ensure state is not null/undefined
70
+ // Subclasses can override for more specific validation
71
+ return stateArg !== null && stateArg !== undefined;
72
+ }
73
+
59
74
  /**
60
75
  * notifies of a change on the state
61
76
  */
62
- public notifyChange() {
63
- const createStateHash = (stateArg: any) => {
64
- return plugins.smarthashWeb.sha256FromString(plugins.smartjson.stringify(stateArg));
77
+ public async notifyChange() {
78
+ if (!this.stateStore) {
79
+ return;
80
+ }
81
+ const createStateHash = async (stateArg: any) => {
82
+ return await plugins.smarthashWeb.sha256FromString(plugins.smartjson.stringify(stateArg));
65
83
  };
84
+ const currentHash = await createStateHash(this.stateStore);
66
85
  if (
67
- this.stateStore &&
68
86
  this.lastStateNotificationPayloadHash &&
69
- createStateHash(this.stateStore) === this.lastStateNotificationPayloadHash
87
+ currentHash === this.lastStateNotificationPayloadHash
70
88
  ) {
71
89
  return;
72
90
  } else {
73
- this.lastStateNotificationPayloadHash = this.stateStore;
91
+ this.lastStateNotificationPayloadHash = currentHash;
74
92
  }
75
93
  this.state.next(this.stateStore);
76
94
  }
@@ -81,7 +99,11 @@ export class StatePart<TStatePartName, TStatePayload> {
81
99
  */
82
100
  public notifyChangeCumulative() {
83
101
  // TODO: check viability
84
- setTimeout(() => this.state.next(this.stateStore), 0);
102
+ setTimeout(async () => {
103
+ if (this.stateStore) {
104
+ await this.notifyChange();
105
+ }
106
+ }, 0);
85
107
  }
86
108
 
87
109
  /**
@@ -95,6 +117,7 @@ export class StatePart<TStatePartName, TStatePayload> {
95
117
  }
96
118
  const mapped = this.state.pipe(
97
119
  plugins.smartrx.rxjs.ops.startWith(this.getState()),
120
+ plugins.smartrx.rxjs.ops.filter((stateArg): stateArg is TStatePayload => stateArg !== undefined),
98
121
  plugins.smartrx.rxjs.ops.map((stateArg) => {
99
122
  try {
100
123
  return selectorFn(stateArg);