@ngstato/core 0.3.0 → 0.4.1
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/README.md +163 -101
- package/dist/index.d.mts +103 -6
- package/dist/index.d.ts +103 -6
- package/dist/index.js +296 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +295 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,101 +1,163 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# @ngstato/core
|
|
4
|
+
|
|
5
|
+
### Tired of 14 lines of RxJS for a simple API call?
|
|
6
|
+
|
|
7
|
+
**Write `async/await`. Get the same result. Ship ~3 KB instead of ~50 KB.**
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/@ngstato/core)
|
|
10
|
+
[](#)
|
|
11
|
+
[](#)
|
|
12
|
+
[](#)
|
|
13
|
+
|
|
14
|
+
[Documentation](https://becher.github.io/ngStato/) · [API Reference](https://becher.github.io/ngStato/api/core) · [Helpers](https://becher.github.io/ngStato/api/helpers)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Before / After
|
|
21
|
+
|
|
22
|
+
**NgRx** — rxMethod + pipe + tap + switchMap + from + tapResponse + patchState:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
load: rxMethod<void>(pipe(
|
|
26
|
+
tap(() => patchState(store, { loading: true })),
|
|
27
|
+
switchMap(() => from(service.getAll()).pipe(
|
|
28
|
+
tapResponse({
|
|
29
|
+
next: (users) => patchState(store, { users, loading: false }),
|
|
30
|
+
error: (e) => patchState(store, { error: e.message })
|
|
31
|
+
})
|
|
32
|
+
))
|
|
33
|
+
))
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**ngStato** — async/await:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
async load(state) {
|
|
40
|
+
state.loading = true
|
|
41
|
+
state.users = await http.get('/users')
|
|
42
|
+
state.loading = false
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @ngstato/core
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 30-second example
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { createStore } from '@ngstato/core'
|
|
58
|
+
|
|
59
|
+
const store = createStore({
|
|
60
|
+
count: 0,
|
|
61
|
+
|
|
62
|
+
selectors: { doubled: (s) => s.count * 2 },
|
|
63
|
+
|
|
64
|
+
actions: {
|
|
65
|
+
inc(state) { state.count++ },
|
|
66
|
+
add(state, n: number) { state.count += n },
|
|
67
|
+
async load(state) { state.count = await fetchCount() }
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
await store.inc()
|
|
72
|
+
store.count // 1
|
|
73
|
+
store.doubled // 2 (memoized)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Real-world store
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { createStore, http, retryable, optimistic } from '@ngstato/core'
|
|
80
|
+
|
|
81
|
+
const store = createStore({
|
|
82
|
+
users: [] as User[],
|
|
83
|
+
loading: false,
|
|
84
|
+
error: null as string | null,
|
|
85
|
+
|
|
86
|
+
selectors: {
|
|
87
|
+
total: (s) => s.users.length,
|
|
88
|
+
admins: (s) => s.users.filter(u => u.role === 'admin')
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
actions: {
|
|
92
|
+
loadUsers: retryable(async (state) => {
|
|
93
|
+
state.loading = true
|
|
94
|
+
state.users = await http.get('/users')
|
|
95
|
+
state.loading = false
|
|
96
|
+
}, { attempts: 3, backoff: 'exponential' }),
|
|
97
|
+
|
|
98
|
+
deleteUser: optimistic(
|
|
99
|
+
(state, id: string) => { state.users = state.users.filter(u => u.id !== id) },
|
|
100
|
+
async (_, id) => { await http.delete(`/users/${id}`) }
|
|
101
|
+
)
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
hooks: {
|
|
105
|
+
onInit: (store) => store.loadUsers(),
|
|
106
|
+
onError: (err, name) => console.error(`[${name}]`, err.message)
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Concurrency — without RxJS
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { exclusive, abortable, queued, retryable, optimistic } from '@ngstato/core'
|
|
115
|
+
|
|
116
|
+
actions: {
|
|
117
|
+
submit: exclusive(async (s) => { ... }), // → exhaustMap
|
|
118
|
+
search: abortable(async (s, q, { signal }) => { }), // → switchMap
|
|
119
|
+
send: queued(async (s, msg) => { ... }), // → concatMap
|
|
120
|
+
load: retryable(async (s) => { ... }, opts), // → retryWhen
|
|
121
|
+
delete: optimistic(apply, confirm), // → manual in NgRx
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Plus `debounced` · `throttled` · `distinctUntilChanged` · `forkJoin` · `race` · `combineLatest` · `fromStream` · `pipeStream` + 12 stream operators · `createEntityAdapter` · `withEntities` · `withPersist` · `mergeFeatures` · `on()` → [Full API →](https://becher.github.io/ngStato/api/helpers)
|
|
126
|
+
|
|
127
|
+
## Inter-store reactions
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import { on } from '@ngstato/core'
|
|
131
|
+
|
|
132
|
+
on([userStore.create, userStore.delete], (_, event) => {
|
|
133
|
+
console.log(`${event.name} ${event.status} in ${event.duration}ms`)
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Feature composition
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
const store = createStore({
|
|
141
|
+
items: [] as Item[],
|
|
142
|
+
...mergeFeatures(withLoading(), withPagination()),
|
|
143
|
+
actions: { async load(state) { ... } }
|
|
144
|
+
})
|
|
145
|
+
// store.loading, store.page, store.hasError — all available
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## The numbers
|
|
149
|
+
|
|
150
|
+
| | NgRx v21 | ngStato |
|
|
151
|
+
|:--|:--|:--|
|
|
152
|
+
| Bundle | ~50 KB | **~3 KB** |
|
|
153
|
+
| CRUD store | ~90 lines | **~45 lines** |
|
|
154
|
+
| Concepts for async | 9 | **1** |
|
|
155
|
+
| RxJS required | Yes | **No** |
|
|
156
|
+
|
|
157
|
+
## 📖 Documentation
|
|
158
|
+
|
|
159
|
+
**[becher.github.io/ngStato](https://becher.github.io/ngStato/)** — [Quick start](https://becher.github.io/ngStato/guide/start-in-5-min) · [Core concepts](https://becher.github.io/ngStato/guide/core-concepts) · [API](https://becher.github.io/ngStato/api/core) · [Helpers](https://becher.github.io/ngStato/api/helpers) · [NgRx migration](https://becher.github.io/ngStato/migration/ngrx-to-ngstato)
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -44,14 +44,17 @@ declare class StatoHttpError extends Error {
|
|
|
44
44
|
constructor(status: number, body: string);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
declare function createStore<S extends object>(config: S & StatoStoreConfig<S
|
|
48
|
-
|
|
47
|
+
declare function createStore<S extends object>(config: S & StatoStoreConfig<S>, __internal?: {
|
|
48
|
+
skipInit?: boolean;
|
|
49
|
+
}): any;
|
|
50
|
+
type OnEvent = {
|
|
49
51
|
name: string;
|
|
50
52
|
args: unknown[];
|
|
51
53
|
status: 'success' | 'error';
|
|
52
54
|
duration: number;
|
|
53
55
|
error?: Error;
|
|
54
|
-
}
|
|
56
|
+
};
|
|
57
|
+
declare function on<S extends object>(sourceAction: Function | Function[], handler: (store: S, event: OnEvent) => void | Promise<void>): () => void;
|
|
55
58
|
|
|
56
59
|
interface RequestOptions {
|
|
57
60
|
params?: Record<string, string | number | boolean>;
|
|
@@ -271,21 +274,103 @@ interface PersistOptions<S extends object> {
|
|
|
271
274
|
}
|
|
272
275
|
declare function withPersist<S extends object>(config: S & StatoStoreConfig<S>, options: PersistOptions<StateSlice<S>>): S & StatoStoreConfig<S>;
|
|
273
276
|
|
|
277
|
+
interface FeatureConfig {
|
|
278
|
+
state?: Record<string, unknown>;
|
|
279
|
+
actions?: Record<string, Function>;
|
|
280
|
+
computed?: Record<string, Function>;
|
|
281
|
+
selectors?: Record<string, Function>;
|
|
282
|
+
effects?: EffectEntry<any>[];
|
|
283
|
+
hooks?: Partial<StatoHooks<any>>;
|
|
284
|
+
}
|
|
285
|
+
type MergedFeature = {
|
|
286
|
+
actions?: Record<string, Function>;
|
|
287
|
+
computed?: Record<string, Function>;
|
|
288
|
+
selectors?: Record<string, Function>;
|
|
289
|
+
effects?: EffectEntry<any>[];
|
|
290
|
+
hooks?: Partial<StatoHooks<any>>;
|
|
291
|
+
[key: string]: unknown;
|
|
292
|
+
};
|
|
293
|
+
declare function mergeFeatures(...features: FeatureConfig[]): MergedFeature;
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* withProps() — Attach external properties to a store config.
|
|
297
|
+
*
|
|
298
|
+
* Properties are accessible on the store instance but NOT part of the state.
|
|
299
|
+
* Use this to expose injected services on the store object.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* // Pattern 1: Expose services on the store
|
|
304
|
+
* export const UsersStore = StatoStore(() => {
|
|
305
|
+
* const api = inject(ApiService)
|
|
306
|
+
* const notifier = inject(NotificationService)
|
|
307
|
+
*
|
|
308
|
+
* const store = createStore({
|
|
309
|
+
* users: [] as User[],
|
|
310
|
+
* loading: false,
|
|
311
|
+
*
|
|
312
|
+
* actions: {
|
|
313
|
+
* async loadUsers(state) {
|
|
314
|
+
* state.loading = true
|
|
315
|
+
* state.users = await api.getUsers() // closure over injected service
|
|
316
|
+
* state.loading = false
|
|
317
|
+
* },
|
|
318
|
+
*
|
|
319
|
+
* async deleteUser(state, id: string) {
|
|
320
|
+
* await api.deleteUser(id)
|
|
321
|
+
* state.users = state.users.filter(u => u.id !== id)
|
|
322
|
+
* notifier.success('User deleted')
|
|
323
|
+
* }
|
|
324
|
+
* }
|
|
325
|
+
* })
|
|
326
|
+
*
|
|
327
|
+
* // Attach props to the store — accessible but not in state
|
|
328
|
+
* return withProps(store, { api, notifier })
|
|
329
|
+
* })
|
|
330
|
+
*
|
|
331
|
+
* // In a component:
|
|
332
|
+
* store = injectStore(UsersStore)
|
|
333
|
+
* store.users() // Signal<User[]>
|
|
334
|
+
* store.loadUsers() // action
|
|
335
|
+
* store.api // ApiService — read-only, not in state
|
|
336
|
+
* ```
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```ts
|
|
340
|
+
* // Pattern 2: Configuration props
|
|
341
|
+
* return withProps(store, {
|
|
342
|
+
* storeName: 'Users',
|
|
343
|
+
* version: '1.0.0',
|
|
344
|
+
* config: { pageSize: 20, cacheTTL: 60_000 }
|
|
345
|
+
* })
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
declare function withProps<S extends object, P extends Record<string, unknown>>(store: S, props: P): S & Readonly<P>;
|
|
349
|
+
|
|
274
350
|
interface ActionLog {
|
|
275
351
|
id: number;
|
|
276
352
|
name: string;
|
|
353
|
+
storeName: string;
|
|
277
354
|
args: unknown[];
|
|
278
355
|
duration: number;
|
|
279
356
|
status: 'success' | 'error';
|
|
280
357
|
error?: string;
|
|
281
|
-
prevState: unknown
|
|
282
|
-
nextState: unknown
|
|
358
|
+
prevState: Record<string, unknown>;
|
|
359
|
+
nextState: Record<string, unknown>;
|
|
283
360
|
at: string;
|
|
284
361
|
}
|
|
285
362
|
interface DevToolsState {
|
|
286
363
|
logs: ActionLog[];
|
|
287
364
|
isOpen: boolean;
|
|
288
365
|
maxLogs: number;
|
|
366
|
+
activeLogId: number | null;
|
|
367
|
+
isTimeTraveling: boolean;
|
|
368
|
+
}
|
|
369
|
+
interface DevToolsSnapshot {
|
|
370
|
+
version: number;
|
|
371
|
+
timestamp: string;
|
|
372
|
+
stores: Record<string, unknown>;
|
|
373
|
+
logs: ActionLog[];
|
|
289
374
|
}
|
|
290
375
|
interface DevToolsInstance {
|
|
291
376
|
state: DevToolsState;
|
|
@@ -295,9 +380,21 @@ interface DevToolsInstance {
|
|
|
295
380
|
close: () => void;
|
|
296
381
|
toggle: () => void;
|
|
297
382
|
subscribe: (cb: (state: DevToolsState) => void) => () => void;
|
|
383
|
+
travelTo: (logId: number) => void;
|
|
384
|
+
undo: () => void;
|
|
385
|
+
redo: () => void;
|
|
386
|
+
resume: () => void;
|
|
387
|
+
replay: (logId: number) => void;
|
|
388
|
+
exportSnapshot: () => DevToolsSnapshot;
|
|
389
|
+
importSnapshot: (snapshot: DevToolsSnapshot) => void;
|
|
390
|
+
registerStore: (name: string, publicStore: any, internalStore: any) => void;
|
|
391
|
+
getStoreRegistry: () => Map<string, {
|
|
392
|
+
store: any;
|
|
393
|
+
internalStore: any;
|
|
394
|
+
}>;
|
|
298
395
|
}
|
|
299
396
|
declare function createDevTools(maxLogs?: number): DevToolsInstance;
|
|
300
397
|
declare const devTools: DevToolsInstance;
|
|
301
398
|
declare function connectDevTools(store: any, storeName: string): void;
|
|
302
399
|
|
|
303
|
-
export { type ActionLog, type DevToolsInstance, type DevToolsState, type EffectDepsFn, type EffectEntry, type EffectRunner, type EntityAdapterOptions, type EntityId, type EntityState, type PersistOptions, type PersistStorage, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, type Update, type WithEntitiesOptions, abortable, catchErrorStream, combineLatest, combineLatestStream, concatMapStream, configureHttp, connectDevTools, createDevTools, createEntityAdapter, createHttp, createStore, debounceStream, debounced, devTools, distinctUntilChanged, distinctUntilChangedStream, exclusive, exhaustMapStream, filterStream, forkJoin, fromStream, http, mapStream, mergeMapStream, on, optimistic, pipeStream, queued, race, retryStream, retryable, switchMapStream, throttleStream, throttled, withEntities, withPersist };
|
|
400
|
+
export { type ActionLog, type DevToolsInstance, type DevToolsSnapshot, type DevToolsState, type EffectDepsFn, type EffectEntry, type EffectRunner, type EntityAdapterOptions, type EntityId, type EntityState, type FeatureConfig, type MergedFeature, type OnEvent, type PersistOptions, type PersistStorage, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, type Update, type WithEntitiesOptions, abortable, catchErrorStream, combineLatest, combineLatestStream, concatMapStream, configureHttp, connectDevTools, createDevTools, createEntityAdapter, createHttp, createStore, debounceStream, debounced, devTools, distinctUntilChanged, distinctUntilChangedStream, exclusive, exhaustMapStream, filterStream, forkJoin, fromStream, http, mapStream, mergeFeatures, mergeMapStream, on, optimistic, pipeStream, queued, race, retryStream, retryable, switchMapStream, throttleStream, throttled, withEntities, withPersist, withProps };
|
package/dist/index.d.ts
CHANGED
|
@@ -44,14 +44,17 @@ declare class StatoHttpError extends Error {
|
|
|
44
44
|
constructor(status: number, body: string);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
declare function createStore<S extends object>(config: S & StatoStoreConfig<S
|
|
48
|
-
|
|
47
|
+
declare function createStore<S extends object>(config: S & StatoStoreConfig<S>, __internal?: {
|
|
48
|
+
skipInit?: boolean;
|
|
49
|
+
}): any;
|
|
50
|
+
type OnEvent = {
|
|
49
51
|
name: string;
|
|
50
52
|
args: unknown[];
|
|
51
53
|
status: 'success' | 'error';
|
|
52
54
|
duration: number;
|
|
53
55
|
error?: Error;
|
|
54
|
-
}
|
|
56
|
+
};
|
|
57
|
+
declare function on<S extends object>(sourceAction: Function | Function[], handler: (store: S, event: OnEvent) => void | Promise<void>): () => void;
|
|
55
58
|
|
|
56
59
|
interface RequestOptions {
|
|
57
60
|
params?: Record<string, string | number | boolean>;
|
|
@@ -271,21 +274,103 @@ interface PersistOptions<S extends object> {
|
|
|
271
274
|
}
|
|
272
275
|
declare function withPersist<S extends object>(config: S & StatoStoreConfig<S>, options: PersistOptions<StateSlice<S>>): S & StatoStoreConfig<S>;
|
|
273
276
|
|
|
277
|
+
interface FeatureConfig {
|
|
278
|
+
state?: Record<string, unknown>;
|
|
279
|
+
actions?: Record<string, Function>;
|
|
280
|
+
computed?: Record<string, Function>;
|
|
281
|
+
selectors?: Record<string, Function>;
|
|
282
|
+
effects?: EffectEntry<any>[];
|
|
283
|
+
hooks?: Partial<StatoHooks<any>>;
|
|
284
|
+
}
|
|
285
|
+
type MergedFeature = {
|
|
286
|
+
actions?: Record<string, Function>;
|
|
287
|
+
computed?: Record<string, Function>;
|
|
288
|
+
selectors?: Record<string, Function>;
|
|
289
|
+
effects?: EffectEntry<any>[];
|
|
290
|
+
hooks?: Partial<StatoHooks<any>>;
|
|
291
|
+
[key: string]: unknown;
|
|
292
|
+
};
|
|
293
|
+
declare function mergeFeatures(...features: FeatureConfig[]): MergedFeature;
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* withProps() — Attach external properties to a store config.
|
|
297
|
+
*
|
|
298
|
+
* Properties are accessible on the store instance but NOT part of the state.
|
|
299
|
+
* Use this to expose injected services on the store object.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* // Pattern 1: Expose services on the store
|
|
304
|
+
* export const UsersStore = StatoStore(() => {
|
|
305
|
+
* const api = inject(ApiService)
|
|
306
|
+
* const notifier = inject(NotificationService)
|
|
307
|
+
*
|
|
308
|
+
* const store = createStore({
|
|
309
|
+
* users: [] as User[],
|
|
310
|
+
* loading: false,
|
|
311
|
+
*
|
|
312
|
+
* actions: {
|
|
313
|
+
* async loadUsers(state) {
|
|
314
|
+
* state.loading = true
|
|
315
|
+
* state.users = await api.getUsers() // closure over injected service
|
|
316
|
+
* state.loading = false
|
|
317
|
+
* },
|
|
318
|
+
*
|
|
319
|
+
* async deleteUser(state, id: string) {
|
|
320
|
+
* await api.deleteUser(id)
|
|
321
|
+
* state.users = state.users.filter(u => u.id !== id)
|
|
322
|
+
* notifier.success('User deleted')
|
|
323
|
+
* }
|
|
324
|
+
* }
|
|
325
|
+
* })
|
|
326
|
+
*
|
|
327
|
+
* // Attach props to the store — accessible but not in state
|
|
328
|
+
* return withProps(store, { api, notifier })
|
|
329
|
+
* })
|
|
330
|
+
*
|
|
331
|
+
* // In a component:
|
|
332
|
+
* store = injectStore(UsersStore)
|
|
333
|
+
* store.users() // Signal<User[]>
|
|
334
|
+
* store.loadUsers() // action
|
|
335
|
+
* store.api // ApiService — read-only, not in state
|
|
336
|
+
* ```
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```ts
|
|
340
|
+
* // Pattern 2: Configuration props
|
|
341
|
+
* return withProps(store, {
|
|
342
|
+
* storeName: 'Users',
|
|
343
|
+
* version: '1.0.0',
|
|
344
|
+
* config: { pageSize: 20, cacheTTL: 60_000 }
|
|
345
|
+
* })
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
declare function withProps<S extends object, P extends Record<string, unknown>>(store: S, props: P): S & Readonly<P>;
|
|
349
|
+
|
|
274
350
|
interface ActionLog {
|
|
275
351
|
id: number;
|
|
276
352
|
name: string;
|
|
353
|
+
storeName: string;
|
|
277
354
|
args: unknown[];
|
|
278
355
|
duration: number;
|
|
279
356
|
status: 'success' | 'error';
|
|
280
357
|
error?: string;
|
|
281
|
-
prevState: unknown
|
|
282
|
-
nextState: unknown
|
|
358
|
+
prevState: Record<string, unknown>;
|
|
359
|
+
nextState: Record<string, unknown>;
|
|
283
360
|
at: string;
|
|
284
361
|
}
|
|
285
362
|
interface DevToolsState {
|
|
286
363
|
logs: ActionLog[];
|
|
287
364
|
isOpen: boolean;
|
|
288
365
|
maxLogs: number;
|
|
366
|
+
activeLogId: number | null;
|
|
367
|
+
isTimeTraveling: boolean;
|
|
368
|
+
}
|
|
369
|
+
interface DevToolsSnapshot {
|
|
370
|
+
version: number;
|
|
371
|
+
timestamp: string;
|
|
372
|
+
stores: Record<string, unknown>;
|
|
373
|
+
logs: ActionLog[];
|
|
289
374
|
}
|
|
290
375
|
interface DevToolsInstance {
|
|
291
376
|
state: DevToolsState;
|
|
@@ -295,9 +380,21 @@ interface DevToolsInstance {
|
|
|
295
380
|
close: () => void;
|
|
296
381
|
toggle: () => void;
|
|
297
382
|
subscribe: (cb: (state: DevToolsState) => void) => () => void;
|
|
383
|
+
travelTo: (logId: number) => void;
|
|
384
|
+
undo: () => void;
|
|
385
|
+
redo: () => void;
|
|
386
|
+
resume: () => void;
|
|
387
|
+
replay: (logId: number) => void;
|
|
388
|
+
exportSnapshot: () => DevToolsSnapshot;
|
|
389
|
+
importSnapshot: (snapshot: DevToolsSnapshot) => void;
|
|
390
|
+
registerStore: (name: string, publicStore: any, internalStore: any) => void;
|
|
391
|
+
getStoreRegistry: () => Map<string, {
|
|
392
|
+
store: any;
|
|
393
|
+
internalStore: any;
|
|
394
|
+
}>;
|
|
298
395
|
}
|
|
299
396
|
declare function createDevTools(maxLogs?: number): DevToolsInstance;
|
|
300
397
|
declare const devTools: DevToolsInstance;
|
|
301
398
|
declare function connectDevTools(store: any, storeName: string): void;
|
|
302
399
|
|
|
303
|
-
export { type ActionLog, type DevToolsInstance, type DevToolsState, type EffectDepsFn, type EffectEntry, type EffectRunner, type EntityAdapterOptions, type EntityId, type EntityState, type PersistOptions, type PersistStorage, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, type Update, type WithEntitiesOptions, abortable, catchErrorStream, combineLatest, combineLatestStream, concatMapStream, configureHttp, connectDevTools, createDevTools, createEntityAdapter, createHttp, createStore, debounceStream, debounced, devTools, distinctUntilChanged, distinctUntilChangedStream, exclusive, exhaustMapStream, filterStream, forkJoin, fromStream, http, mapStream, mergeMapStream, on, optimistic, pipeStream, queued, race, retryStream, retryable, switchMapStream, throttleStream, throttled, withEntities, withPersist };
|
|
400
|
+
export { type ActionLog, type DevToolsInstance, type DevToolsSnapshot, type DevToolsState, type EffectDepsFn, type EffectEntry, type EffectRunner, type EntityAdapterOptions, type EntityId, type EntityState, type FeatureConfig, type MergedFeature, type OnEvent, type PersistOptions, type PersistStorage, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, type Update, type WithEntitiesOptions, abortable, catchErrorStream, combineLatest, combineLatestStream, concatMapStream, configureHttp, connectDevTools, createDevTools, createEntityAdapter, createHttp, createStore, debounceStream, debounced, devTools, distinctUntilChanged, distinctUntilChangedStream, exclusive, exhaustMapStream, filterStream, forkJoin, fromStream, http, mapStream, mergeFeatures, mergeMapStream, on, optimistic, pipeStream, queued, race, retryStream, retryable, switchMapStream, throttleStream, throttled, withEntities, withPersist, withProps };
|