storion 0.8.3 → 0.10.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +127 -21
  2. package/README.md +42 -2021
  3. package/dist/async/abortable.d.ts +295 -0
  4. package/dist/async/abortable.d.ts.map +1 -0
  5. package/dist/async/async.d.ts +86 -5
  6. package/dist/async/async.d.ts.map +1 -1
  7. package/dist/async/context.d.ts +15 -0
  8. package/dist/async/context.d.ts.map +1 -0
  9. package/dist/async/index.d.ts +16 -3
  10. package/dist/async/index.d.ts.map +1 -1
  11. package/dist/async/index.js +407 -137
  12. package/dist/async/safe.d.ts +221 -0
  13. package/dist/async/safe.d.ts.map +1 -0
  14. package/dist/async/types.d.ts +77 -29
  15. package/dist/async/types.d.ts.map +1 -1
  16. package/dist/async/wrappers.d.ts +217 -0
  17. package/dist/async/wrappers.d.ts.map +1 -0
  18. package/dist/core/effect.d.ts +34 -26
  19. package/dist/core/effect.d.ts.map +1 -1
  20. package/dist/core/equality.d.ts +25 -0
  21. package/dist/core/equality.d.ts.map +1 -1
  22. package/dist/core/focus.d.ts +20 -0
  23. package/dist/core/focus.d.ts.map +1 -0
  24. package/dist/core/focusHelpers.d.ts +258 -0
  25. package/dist/core/focusHelpers.d.ts.map +1 -0
  26. package/dist/core/middleware.d.ts +4 -4
  27. package/dist/core/store.d.ts.map +1 -1
  28. package/dist/core/storeContext.d.ts +2 -9
  29. package/dist/core/storeContext.d.ts.map +1 -1
  30. package/dist/dev.d.ts +0 -10
  31. package/dist/dev.d.ts.map +1 -1
  32. package/dist/{index-C8B6Mo8r.js → effect-BDQU8Voz.js} +1241 -583
  33. package/dist/errors.d.ts +6 -0
  34. package/dist/errors.d.ts.map +1 -1
  35. package/dist/index.d.ts +5 -4
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/network/index.d.ts +69 -0
  38. package/dist/network/index.d.ts.map +1 -0
  39. package/dist/network/retry.d.ts +53 -0
  40. package/dist/network/retry.d.ts.map +1 -0
  41. package/dist/network/services.d.ts +58 -0
  42. package/dist/network/services.d.ts.map +1 -0
  43. package/dist/network/store.d.ts +36 -0
  44. package/dist/network/store.d.ts.map +1 -0
  45. package/dist/network/utils.d.ts +9 -0
  46. package/dist/network/utils.d.ts.map +1 -0
  47. package/dist/persist/index.d.ts +1 -1
  48. package/dist/persist/index.d.ts.map +1 -1
  49. package/dist/persist/index.js +55 -31
  50. package/dist/persist/persist.d.ts +119 -62
  51. package/dist/persist/persist.d.ts.map +1 -1
  52. package/dist/pool.d.ts +77 -0
  53. package/dist/pool.d.ts.map +1 -0
  54. package/dist/react/index.d.ts +2 -2
  55. package/dist/react/index.d.ts.map +1 -1
  56. package/dist/react/index.js +245 -244
  57. package/dist/react/stable.d.ts +27 -0
  58. package/dist/react/stable.d.ts.map +1 -0
  59. package/dist/react/useStore.d.ts +38 -13
  60. package/dist/react/useStore.d.ts.map +1 -1
  61. package/dist/react/withStore.d.ts.map +1 -1
  62. package/dist/storion.js +911 -37
  63. package/dist/trigger.d.ts +12 -7
  64. package/dist/trigger.d.ts.map +1 -1
  65. package/dist/types.d.ts +133 -22
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/utils/storeTuple.d.ts +7 -0
  68. package/dist/utils/storeTuple.d.ts.map +1 -0
  69. package/package.json +5 -1
  70. package/dist/collection.d.ts +0 -34
  71. package/dist/collection.d.ts.map +0 -1
  72. package/dist/core/proxy.d.ts +0 -47
  73. package/dist/core/proxy.d.ts.map +0 -1
  74. package/dist/effect-C6h0PDDI.js +0 -446
  75. package/dist/isPromiseLike-bFkfHAbm.js +0 -6
  76. package/dist/react/useLocalStore.d.ts +0 -48
  77. package/dist/react/useLocalStore.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -8,31 +8,122 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  ## [Unreleased]
9
9
 
10
10
  ### Added
11
+
12
+ - `SelectorContext.scoped()` for component-local stores that auto-dispose on unmount
13
+ ```tsx
14
+ const { value, setValue } = useStore(({ scoped }) => {
15
+ const [state, actions, instance] = scoped(formStore);
16
+ return { value: state.value, setValue: actions.setValue };
17
+ });
18
+ ```
19
+ - `async.mixin()` for component-local async state (mutations, form submissions)
20
+
21
+ ```tsx
22
+ // Define mutation - no store needed
23
+ const submitForm = async.mixin(async (ctx, data: FormData) => {
24
+ const res = await fetch("/api/submit", {
25
+ method: "POST",
26
+ body: JSON.stringify(data),
27
+ signal: ctx.signal,
28
+ });
29
+ return res.json();
30
+ });
31
+
32
+ // Use as mixin - state is component-local, auto-disposed
33
+ const { status, submit } = useStore(({ mixin }) => {
34
+ const [state, actions] = mixin(submitForm);
35
+ return { status: state.status, submit: actions.dispatch };
36
+ });
37
+ ```
38
+
39
+ - `AsyncContext.get()` allows async handlers to access other stores' state
40
+
41
+ ```tsx
42
+ // Access other stores for cross-store mutations
43
+ const checkout = async.mixin(async (ctx, paymentMethod: string) => {
44
+ const [user] = ctx.get(userStore);
45
+ const [cart] = ctx.get(cartStore);
46
+ return fetch("/api/checkout", {
47
+ body: JSON.stringify({ userId: user.id, items: cart.items }),
48
+ });
49
+ });
50
+ ```
51
+
11
52
  - `MetaEntry.fields` now supports arrays for applying meta to multiple fields at once
12
53
  ```ts
13
- meta: [notPersisted.for(["password", "token"])]
54
+ meta: [notPersisted.for(["password", "token"])];
14
55
  ```
15
56
  - `MetaQuery.fields(type, predicate?)` method to get field names with a specific meta type
16
57
  ```ts
17
- const sessionFields = ctx.meta.fields(sessionStore); // ['token', 'userId']
18
- const highPriority = ctx.meta.fields(priority, v => v > 5);
19
- ```
20
- - `persistMiddleware` `fields` option for multi-storage patterns
21
- ```ts
22
- // Split fields between session and local storage
23
- persistMiddleware({
24
- filter: ({ meta }) => meta.any(sessionStore),
25
- fields: ({ meta }) => meta.fields(sessionStore),
26
- save: (ctx, state) => sessionStorage.setItem(ctx.displayName, JSON.stringify(state)),
27
- })
58
+ const sessionFields = ctx.meta.fields(sessionStore); // ['token', 'userId']
59
+ const highPriority = ctx.meta.fields(priority, (v) => v > 5);
28
60
  ```
29
61
  - `applyFor` now supports object form to map patterns to different middleware
30
62
  ```ts
31
63
  applyFor({
32
- "userStore": loggingMiddleware,
64
+ userStore: loggingMiddleware,
33
65
  "auth*": [authMiddleware, securityMiddleware],
34
66
  "*Cache": cacheMiddleware,
35
- })
67
+ });
68
+ ```
69
+
70
+ ### Removed
71
+
72
+ - **BREAKING**: `useLocalStore` hook removed - use `scoped()` in `useStore` selector instead
73
+
74
+ ```tsx
75
+ // Before
76
+ const [state, actions] = useLocalStore(formStore);
77
+
78
+ // After
79
+ const { state, actions } = useStore(({ scoped }) => {
80
+ const [s, a] = scoped(formStore);
81
+ return { state: s, actions: a };
82
+ });
83
+ ```
84
+
85
+ - **BREAKING**: `SelectorContext.create()` removed - creates uncontrolled instances without disposal tracking. Use `get()` for cached services or `scoped()` for component-local stores instead.
86
+
87
+ ### Changed
88
+
89
+ - **BREAKING**: `persist` API refactored for better encapsulation (renamed from `persistMiddleware`)
90
+
91
+ - New `handler` option replaces `load`/`save` callbacks
92
+ - `persistMiddleware` is now deprecated, use `persist` instead
93
+ - Handler receives `PersistContext` (extends `StoreMiddlewareContext` with `store` instance)
94
+ - Handler returns `{ load, save }` object (can be sync or async)
95
+ - `onError` signature changed to `(error, operation)` where operation is `"init" | "load" | "save"`
96
+ - Enables encapsulated async initialization (e.g., IndexedDB)
97
+
98
+ ```ts
99
+ // Before (old API)
100
+ persistMiddleware({
101
+ load: (ctx) => localStorage.getItem(ctx.displayName),
102
+ save: (ctx, state) =>
103
+ localStorage.setItem(ctx.displayName, JSON.stringify(state)),
104
+ });
105
+
106
+ // After (new API)
107
+ persist({
108
+ handler: (ctx) => {
109
+ const key = `app:${ctx.displayName}`;
110
+ return {
111
+ load: () => JSON.parse(localStorage.getItem(key) || "null"),
112
+ save: (state) => localStorage.setItem(key, JSON.stringify(state)),
113
+ };
114
+ },
115
+ });
116
+
117
+ // Async handler (IndexedDB)
118
+ persist({
119
+ handler: async (ctx) => {
120
+ const db = await openDB("app-db");
121
+ return {
122
+ load: () => db.get("stores", ctx.displayName),
123
+ save: (state) => db.put("stores", state, ctx.displayName),
124
+ };
125
+ },
126
+ });
36
127
  ```
37
128
 
38
129
  ---
@@ -40,8 +131,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
40
131
  ## [0.8.0] - 2024-12-21
41
132
 
42
133
  ### Added
134
+
43
135
  - **Persist Module** (`storion/persist`)
44
- - `persistMiddleware(options)` for automatic state persistence
136
+ - `persist(options)` for automatic state persistence
45
137
  - `notPersisted` meta for excluding stores or fields from persistence
46
138
  - Supports sync and async `load`/`save` handlers
47
139
  - `force` option to override dirty state during hydration
@@ -58,6 +150,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
58
150
  - `store.hydrate(state, { force })` - force option to override dirty properties
59
151
 
60
152
  ### Changed
153
+
61
154
  - `StoreMiddlewareContext` now includes `meta` property for querying store metadata
62
155
  - `FactoryMiddlewareContext` now includes `meta` property for querying factory metadata
63
156
 
@@ -66,6 +159,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66
159
  ## [0.7.0] - 2024-12-15
67
160
 
68
161
  ### Added
162
+
69
163
  - **DevTools Module** (`storion/devtools`)
70
164
  - `devtoolsMiddleware()` for state inspection
71
165
  - `__revertState` and `__takeSnapshot` injected actions
@@ -79,6 +173,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
79
173
  - `create()` shorthand for single-store apps returning `[instance, useHook, withStore]`
80
174
 
81
175
  ### Changed
176
+
82
177
  - Improved TypeScript inference for store actions
83
178
 
84
179
  ---
@@ -86,6 +181,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
86
181
  ## [0.6.0] - 2024-12-01
87
182
 
88
183
  ### Added
184
+
89
185
  - **Async Module** (`storion/async`)
90
186
  - `async.fresh<T>()` - throws during loading (Suspense-compatible)
91
187
  - `async.stale<T>(initialData)` - returns stale data during loading
@@ -95,6 +191,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
95
191
  - `trigger(action, deps, ...args)` for declarative data fetching in components
96
192
 
97
193
  ### Changed
194
+
98
195
  - Effects now require synchronous functions (use `ctx.safe()` for async)
99
196
 
100
197
  ---
@@ -102,6 +199,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
102
199
  ## [0.5.0] - 2024-11-15
103
200
 
104
201
  ### Added
202
+
105
203
  - **Focus (Lens-like Access)**
106
204
  - `focus(path)` for nested state access
107
205
  - Returns `[getter, setter]` tuple
@@ -119,6 +217,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
119
217
  ## [0.4.0] - 2024-11-01
120
218
 
121
219
  ### Added
220
+
122
221
  - **Middleware System**
123
222
  - `container({ middleware: [...] })` for middleware injection
124
223
  - Middleware receives `MiddlewareContext` with `type`, `next`, `resolver`
@@ -127,6 +226,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
127
226
  - `createValidationMiddleware()` built-in middleware
128
227
 
129
228
  ### Changed
229
+
130
230
  - Container now uses middleware chain pattern
131
231
 
132
232
  ---
@@ -134,6 +234,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
134
234
  ## [0.3.0] - 2024-10-15
135
235
 
136
236
  ### Added
237
+
137
238
  - **Store Lifecycle**
138
239
  - `lifetime: "keepAlive"` (default) - persists until container disposal
139
240
  - `lifetime: "autoDispose"` - disposes when no subscribers
@@ -145,6 +246,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
145
246
  - `store.reset()` to restore initial state
146
247
 
147
248
  ### Changed
249
+
148
250
  - Stores now track dirty state automatically
149
251
 
150
252
  ---
@@ -152,6 +254,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
152
254
  ## [0.2.0] - 2024-10-01
153
255
 
154
256
  ### Added
257
+
155
258
  - **Dependency Injection**
156
259
  - `container()` for managing store instances
157
260
  - `get(factory)` for resolving dependencies
@@ -161,6 +264,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
161
264
  - `useContainer()` hook
162
265
 
163
266
  ### Changed
267
+
164
268
  - Stores are now lazily instantiated via container
165
269
 
166
270
  ---
@@ -168,6 +272,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
168
272
  ## [0.1.0] - 2024-09-15
169
273
 
170
274
  ### Added
275
+
171
276
  - **Core Store**
172
277
  - `store(options)` factory function
173
278
  - `state` - reactive state object
@@ -195,22 +300,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
195
300
  ### Migrating to 0.8.0
196
301
 
197
302
  #### Meta System Changes
303
+
198
304
  If you were using internal meta APIs, update to the new public API:
199
305
 
200
306
  ```ts
201
307
  // Before (internal)
202
- spec.meta // was MetaEntry[]
308
+ spec.meta; // was MetaEntry[]
203
309
 
204
310
  // After (0.8.0)
205
- ctx.meta(persistMeta).store // query store-level
206
- ctx.meta(persistMeta).fields // query field-level
207
- ctx.meta.all(type) // get all values
208
- ctx.meta.any(type1, type2) // check existence
311
+ ctx.meta(persistMeta).store; // query store-level
312
+ ctx.meta(persistMeta).fields; // query field-level
313
+ ctx.meta.all(type); // get all values
314
+ ctx.meta.any(type1, type2); // check existence
209
315
  ```
210
316
 
211
317
  ### Migrating to 0.6.0
212
318
 
213
319
  #### Async Effects
320
+
214
321
  Effects must now be synchronous:
215
322
 
216
323
  ```ts
@@ -239,4 +346,3 @@ effect((ctx) => {
239
346
  [0.3.0]: https://github.com/linq2js/storion/compare/v0.2.0...v0.3.0
240
347
  [0.2.0]: https://github.com/linq2js/storion/compare/v0.1.0...v0.2.0
241
348
  [0.1.0]: https://github.com/linq2js/storion/releases/tag/v0.1.0
242
-