@push.rocks/smartstate 2.0.31 → 2.1.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/npmextra.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "githost": "code.foss.global",
17
17
  "gitscope": "push.rocks",
18
18
  "gitrepo": "smartstate",
19
- "description": "A package for handling and managing state in applications.",
19
+ "description": "A TypeScript-first reactive state management library with middleware, computed state, batching, persistence, and Web Component Context Protocol support.",
20
20
  "npmPackagename": "@push.rocks/smartstate",
21
21
  "license": "MIT",
22
22
  "keywords": [
@@ -29,7 +29,13 @@
29
29
  "state selection",
30
30
  "state notification",
31
31
  "asynchronous state",
32
- "cumulative notification"
32
+ "cumulative notification",
33
+ "middleware",
34
+ "computed state",
35
+ "batch updates",
36
+ "context protocol",
37
+ "web components",
38
+ "AbortSignal"
33
39
  ]
34
40
  },
35
41
  "release": {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@push.rocks/smartstate",
3
- "version": "2.0.31",
3
+ "version": "2.1.0",
4
4
  "private": false,
5
- "description": "A package for handling and managing state in applications.",
5
+ "description": "A TypeScript-first reactive state management library with middleware, computed state, batching, persistence, and Web Component Context Protocol support.",
6
6
  "main": "dist_ts/index.js",
7
7
  "typings": "dist_ts/index.d.ts",
8
8
  "type": "module",
@@ -22,7 +22,6 @@
22
22
  "@types/node": "^25.3.2"
23
23
  },
24
24
  "dependencies": {
25
- "@push.rocks/lik": "^6.2.2",
26
25
  "@push.rocks/smarthash": "^3.2.6",
27
26
  "@push.rocks/smartjson": "^6.0.0",
28
27
  "@push.rocks/smartpromise": "^4.2.3",
@@ -54,7 +53,13 @@
54
53
  "state selection",
55
54
  "state notification",
56
55
  "asynchronous state",
57
- "cumulative notification"
56
+ "cumulative notification",
57
+ "middleware",
58
+ "computed state",
59
+ "batch updates",
60
+ "context protocol",
61
+ "web components",
62
+ "AbortSignal"
58
63
  ],
59
64
  "homepage": "https://code.foss.global/push.rocks/smartstate",
60
65
  "repository": {
package/readme.hints.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Smartstate Implementation Notes
2
2
 
3
- ## Current API (as of v2.0.28+)
3
+ ## Current API (as of v2.0.31)
4
4
 
5
5
  ### State Part Initialization
6
6
  - State parts can be created with different init modes: 'soft' (default), 'mandatory', 'force', 'persistent'
@@ -8,53 +8,70 @@
8
8
  - 'mandatory' - requires state part to not exist, fails if it does
9
9
  - 'force' - always creates new state part, overwriting any existing
10
10
  - 'persistent' - like 'soft' but with WebStore persistence (IndexedDB)
11
- - Persistent mode automatically calls init() internally - no need to call it manually
11
+ - Persistent mode automatically calls init() internally
12
12
  - State merge order fixed: initial state takes precedence over stored state
13
13
 
14
14
  ### Actions
15
15
  - Actions are created with `createAction()` method
16
- - Two ways to dispatch actions:
17
- 1. `stateAction.trigger(payload)` - returns Promise<TStatePayload>
18
- 2. `await statePart.dispatchAction(stateAction, payload)` - returns Promise<TStatePayload>
19
- - Both methods return the same Promise, providing flexibility in usage
16
+ - Two ways to dispatch: `stateAction.trigger(payload)` or `statePart.dispatchAction(stateAction, payload)`
17
+ - Both return Promise<TStatePayload>
20
18
 
21
19
  ### State Management Methods
22
- - `select()` - returns Observable with startWith current state, filters undefined states
23
- - `waitUntilPresent()` - waits for specific state condition
20
+ - `select(fn?, { signal? })` - returns Observable, memoized by selector fn ref, supports AbortSignal
21
+ - `waitUntilPresent(fn?, number | { timeoutMs?, signal? })` - waits for state condition, backward compat with number arg
24
22
  - `stateSetup()` - async state initialization with cumulative defer
25
23
  - `notifyChangeCumulative()` - defers notification to end of call stack
26
24
  - `getState()` - returns current state or undefined
27
- - `setState()` - validates state before setting, notifies only on actual changes
25
+ - `setState()` - runs middleware, validates, persists, notifies
26
+ - `addMiddleware(fn)` - intercepts setState, returns removal function
27
+
28
+ ### Middleware
29
+ - Type: `(newState, oldState) => newState | Promise<newState>`
30
+ - Runs sequentially in insertion order before validation/persistence
31
+ - Throw to reject state changes (atomic — state unchanged on error)
32
+ - Does NOT run during initial createStatePart() hydration
33
+
34
+ ### Selector Memoization
35
+ - Uses WeakMap<Function, Observable> for fn-keyed cache
36
+ - `defaultSelectObservable` for no-arg select()
37
+ - Wrapped in `shareReplay({ bufferSize: 1, refCount: true })`
38
+ - NOT cached when AbortSignal is provided
39
+
40
+ ### Batch Updates
41
+ - `smartstate.batch(async () => {...})` — defers notifications until batch completes
42
+ - Supports nesting — only flushes at outermost level
43
+ - StatePart has `smartstateRef` set by `createStatePart()` for batch awareness
44
+ - State parts created via `new StatePart()` directly work without batching
45
+
46
+ ### Computed State
47
+ - `computed(sources, fn)` — standalone function using `combineLatest` + `map`
48
+ - Also available as `smartstate.computed(sources, fn)`
49
+ - Lazy — only subscribes when subscribed to
50
+
51
+ ### Context Protocol Bridge
52
+ - `attachContextProvider(element, { context, statePart, selectorFn? })` — returns cleanup fn
53
+ - Listens for `context-request` CustomEvent on element
54
+ - Supports one-shot and subscription modes
55
+ - Works with Lit @consume(), FAST, or any Context Protocol consumer
28
56
 
29
57
  ### State Hash Detection
30
58
  - Uses SHA256 hash to detect actual state changes
31
- - Fixed: Hash comparison now properly awaits async hash calculation
59
+ - Hash comparison properly awaits async hash calculation
32
60
  - Prevents duplicate notifications for identical state values
33
- - `notifyChange()` is now async to support proper hash comparison
34
61
 
35
62
  ### State Validation
36
63
  - Basic validation ensures state is not null/undefined
37
- - `validateState()` method can be overridden in subclasses for custom validation
38
- - Validation runs on both setState() and when loading from persistent storage
39
-
40
- ### Type System
41
- - Can use either enums or string literal types for state part names
42
- - Test uses simple string types: `type TMyStateParts = 'testStatePart'`
43
- - State can be undefined initially, handled properly in select() and other methods
44
-
45
- ## Recent Fixes (v2.0.24+)
46
- 1. Fixed state hash bug - now properly compares hash values instead of promises
47
- 2. Fixed state initialization merge order - initial state now takes precedence
48
- 3. Ensured stateStore is properly typed as potentially undefined
49
- 4. Simplified init mode logic with clear behavior for each mode
50
- 5. Added state validation with extensible validateState() method
51
- 6. Made notifyChange() async to support proper hash comparison
52
- 7. Updated select() to filter undefined states
53
-
54
- ## Dependency Versions (v2.0.30)
64
+ - `validateState()` can be overridden in subclasses
65
+
66
+ ### Key Notes
67
+ - `smartstateRef` creates circular ref between StatePart and Smartstate
68
+ - Use `===` not deep equality for StatePart comparison in tests
69
+ - Direct rxjs imports used for: Observable, shareReplay, takeUntil, combineLatest, map
70
+
71
+ ## Dependency Versions (v2.0.31)
55
72
  - @git.zone/tsbuild: ^4.1.2
56
73
  - @git.zone/tsbundle: ^2.9.0
57
74
  - @git.zone/tsrun: ^2.0.1
58
75
  - @git.zone/tstest: ^3.1.8
59
76
  - @push.rocks/smartjson: ^6.0.0
60
- - @types/node: ^25.3.2
77
+ - @types/node: ^25.3.2