@microphi/store 2.11.0 → 2.11.3

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 CHANGED
@@ -1,252 +1,200 @@
1
- # @microphi/store
1
+ # @microphi/store [![npm](https://img.shields.io/npm/v/@microphi/store)](https://www.npmjs.com/package/@microphi/store)
2
2
 
3
- @microphi/store is a pure RxJS state manager.
3
+ > Pure RxJS state manager driven by `@Effect` / `@Reduce` decorators
4
4
 
5
5
  ## Install
6
- With your favourite package manager install
6
+
7
+ ```sh
8
+ npm i @microphi/store @microphi/di rxjs reflect-metadata
7
9
  ```
8
- @microphi/store
10
+
11
+ Enable legacy decorators in `tsconfig.json`:
12
+
13
+ ```json
14
+ {
15
+ "compilerOptions": {
16
+ "experimentalDecorators": true
17
+ }
18
+ }
9
19
  ```
10
20
 
21
+ ## How to use
22
+
11
23
  ### Define the state
24
+
12
25
  ```typescript
13
- interface ItemsState {
26
+ interface UsersState {
14
27
  users: string[];
15
- selected?: [number, string];
28
+ selected?: string;
16
29
  }
17
30
  ```
18
31
 
19
32
  ### Define the actions
33
+
34
+ Every action returns an `Observable`; its arguments are what `dispatch` takes.
35
+
20
36
  ```typescript
21
- interface ItemsActions {
22
- // An action MUST always return an Observable
37
+ interface UsersActions {
23
38
  findAll: () => Observable<string[]>;
24
- // select: (name: string) => Observable<[number, string]>;
39
+ findOne: (id: string) => Observable<string>;
25
40
  }
26
41
  ```
27
- ### Implement effects and reducers in the store
42
+
43
+ ### Implement effects and reducers
44
+
45
+ For each action the store needs an `@Effect()` method named like the action and an `@Reduce()` method named `on` + `PascalCase(action)`. A missing one throws when the store is constructed.
28
46
 
29
47
  ```typescript
30
- import { Store, Effect, Reduce } from '@microphi/store';
48
+ import { Observable, of } from 'rxjs';
49
+ import { Effect, makeStore, Reduce, Store } from '@microphi/store';
31
50
 
32
- // -> Create a class that extends `Store` such as
33
- class MyStore extends Store<ItemsState, ItemsActions>
34
- implements makeStore<ItemsState, ItemsActions> {
35
- // -> optionally implement `makeStore` to add extra type checking
51
+ class UsersStore extends Store<UsersState, UsersActions>
52
+ // optional: type-checks that every effect and reducer is implemented
53
+ implements makeStore<UsersState, UsersActions> {
36
54
 
37
55
  constructor() {
38
- // -> Set the initial state
39
- super({
40
- users: ['alice', 'bob'],
41
- });
56
+ // initial state, must be serializable: each instance gets its own deep copy
57
+ super({ users: ['alice', 'bob'] });
42
58
  }
43
59
 
44
60
  @Effect()
45
- // -> Implement `findAll` method
46
61
  findAll(): Observable<string[]> {
47
- // - Simulate an async call
48
- return of(['alice', 'bob', 'carl', 'denise']);
62
+ return of(['carl', 'denise']);
49
63
  }
50
64
 
51
- @Reduce() // - Decorate with `@Reduce` so the `Store` knows this is a reducer
52
- // -> Method name MUST be `on` + capitalized `actionName`
53
- // its first argument is always the current state
54
- // its second argument is the output of its action without the Observable.
55
- public onFindAll(state: ItemsState, payload: string[]) {
56
- // -> add state transition logic here
57
-
58
- // -> Return the new state
59
- return {
60
- users: [...state.users, ...payload]
61
- };
65
+ // receives the current state and the value emitted by the effect
66
+ @Reduce()
67
+ onFindAll(state: UsersState, users: string[]): UsersState {
68
+ return { ...state, users: [...state.users, ...users] };
69
+ }
70
+
71
+ @Effect()
72
+ findOne(id: string): Observable<string> {
73
+ return fromFetch(`https://my.endpoint/users/${id}`).pipe(switchMap((r) => r.json()));
74
+ }
75
+
76
+ @Reduce()
77
+ onFindOne(state: UsersState, selected: string): UsersState {
78
+ return { ...state, selected };
62
79
  }
63
80
  }
64
81
  ```
65
82
 
66
- ### Dispatch and select state
83
+ ### Dispatch and select
84
+
67
85
  ```typescript
68
- // given an instance of the store
69
- const store = new MyStore();
86
+ const store = new UsersStore();
70
87
 
71
- // subscribe to any state change
72
- store.state$.subscribe((state) => console.log({ state }) );
88
+ // every state change
89
+ store.state$.subscribe((state) => console.log(state));
73
90
 
74
- // or better select a projection of the state
75
- store.select(({users}) => users).subscribe((users) => console.log({ users }));
91
+ // or a projection, emitted only when it changes
92
+ store.select(({ users }) => users).subscribe((users) => console.log(users));
76
93
 
77
- // finally dispatch an action
78
94
  store.dispatch('findAll');
79
-
95
+ store.dispatch('findOne', 'alice'); // arguments are type-checked against UsersActions
80
96
  ```
81
97
 
82
- #### Watch loading state
83
- We assume every action to be an asyncronious task so every action as a loading state associated to it. Loading state can we subscribed such as:
84
- ```typescript
85
- store.getLoadingFor('findAll').subscribe((loading) => {
86
-
87
- console.log({loading});
98
+ ### Loading and errors
88
99
 
89
- });
100
+ Every action is treated as async, so each has a loading state:
90
101
 
102
+ ```typescript
103
+ store.getLoadingFor('findOne').subscribe((loading) => console.log({ loading }));
91
104
  ```
92
105
 
93
- ### Choose the right strategy
94
- We assume that an action always execute an async effect. Internally such effect is wrapped in a RxJS pipe, as such there are several way this can be done.
95
- So for example when we dispatch an action such as `findOne` let's say its effect is a call to and endpoint to retrieve an entity by its id.
96
- Dependending on the scenario we may want to `switchMap`, `mergeMap` or `concatMap`.
106
+ `loading$` carries the full event: `{ code, payload, status, response?, error? }`.
97
107
 
98
- This can be achieved passing the `strategy` argument to the `@Effect` decorator such as:
108
+ If an effect errors, the error is logged and emitted on `loading$` (with `status: false` and `error`), the state is left untouched and the action can be dispatched again.
99
109
 
100
- ```typescript
110
+ ### Effects that emit more than once
101
111
 
102
- class MyStore extends Store<ItemsState, ItemsActions>
103
- implements makeStore<ItemsState, ItemsActions> {
112
+ The reducer runs for every value the effect emits, so a long-lived effect (a connection, a socket) keeps updating the state after the dispatch that started it.
104
113
 
105
- constructor() {
106
- super({
107
- users: ['alice', 'bob'],
108
- selected: undefined,
114
+ ## Strategies
109
115
 
110
- });
111
- }
116
+ When an action is dispatched again while its previous effect is still running, the strategy passed to `@Effect` decides what happens:
112
117
 
113
- @Effect('mergeMap')
114
- findOne(id: string): Observable<string> {
115
- return fromFetch(`http://my.super.endpoint/${id}`)
116
- }
118
+ | Strategy | Behaviour |
119
+ |---|---|
120
+ | `switchMap` (default) | the pending effect is cancelled, only the latest one reduces |
121
+ | `mergeMap` | effects run in parallel, each reduces as it completes |
122
+ | `concatMap` | effects run one after the other, in dispatch order |
117
123
 
118
- @Reduce()
119
- public onFindOne(state: ItemsState, select: string) {
120
- return {
121
- ...state,
122
- selected,
123
- };
124
- }
124
+ ```typescript
125
+ @Effect('mergeMap')
126
+ findOne(id: string): Observable<string> {
127
+ return fromFetch(`https://my.endpoint/users/${id}`).pipe(switchMap((r) => r.json()));
125
128
  }
126
129
  ```
127
130
 
128
- ### Operators
129
- When dispatching actions some RxJS operators can be applied using decorators:
131
+ ## Operators
132
+
133
+ ### `@Cache`
130
134
 
131
- #### Cache
132
- It caches the value returned from the effect (i.e.: its observable) for 300_000 (default) milliseconds (i.e.: 5 mins) or the amount of milliseconds provided in the `ttl` field.
133
- The effect will be cached according to its arguments. I.e.: like a memoized function `@Cache` will get check arguments and cache their result separately.
135
+ Caches the Observable an effect returns, per store instance and per arguments, so a cached dispatch does not call the effect method again. The Observable itself is resubscribed: a cold one (like `fromFetch`) re-runs its request unless it is shared, e.g. with `shareReplay(1)`.
134
136
 
135
- Optionally a `trackBy` function can be provided in order to customized how arguments are considered for caching.
136
- If not provided `JSON.stringify` is used to serialize the arguments.
137
- If provided `trackBy` will have the exact same arguments of the effect being annotated.
138
137
  ```typescript
138
+ @Effect('mergeMap')
139
+ @Cache({ ttl: 1_000, trackBy: (id: string) => id.toLowerCase() })
140
+ findOne(id: string): Observable<string> {
141
+ return fromFetch(`https://my.endpoint/users/${id}`).pipe(
142
+ switchMap((r) => r.json()),
143
+ shareReplay(1),
144
+ );
145
+ }
146
+ ```
139
147
 
140
- class MyStore extends Store<ItemsState, ItemsActions>
141
- implements makeStore<ItemsState, ItemsActions> {
148
+ - `ttl`: time to live in ms, default 5 minutes
149
+ - `trackBy`: builds the cache key from the effect's arguments, default `JSON.stringify(args)`
142
150
 
143
- constructor() {
144
- super({
145
- users: ['alice', 'bob'],
146
- selected: undefined,
151
+ `@Cache` lives in `@microphi/di` and works on any class; it is re-exported here.
147
152
 
148
- });
149
- }
153
+ ### `@DebounceTime`
150
154
 
151
- @Effect('mergeMap')
152
- @Cache({ttl: 1_000, trackBy: (id: string) => id.toLowerCase()})
153
- findOne(id: string): Observable<string> {
154
- return fromFetch(`http://my.super.endpoint/${id}`)
155
- }
155
+ Debounces dispatches of the action, as `debounceTime` in an RxJS pipe:
156
156
 
157
- @Reduce()
158
- public onFindOne(state: ItemsState, select: string) {
159
- return {
160
- ...state,
161
- selected,
162
- };
163
- }
157
+ ```typescript
158
+ @Effect('switchMap')
159
+ @DebounceTime(300)
160
+ search(query: string): Observable<string[]> {
161
+ return fromFetch(`https://my.endpoint/search?q=${query}`).pipe(switchMap((r) => r.json()));
164
162
  }
165
163
  ```
166
164
 
165
+ ### `@DelayTime`
167
166
 
168
- #### DebounceTime
169
- It will debouce calling the effect as in a RxJS pipe
167
+ Delays each effect's result, as `delay` in an RxJS pipe:
170
168
 
171
169
  ```typescript
172
-
173
- class MyStore extends Store<ItemsState, ItemsActions>
174
- implements makeStore<ItemsState, ItemsActions> {
175
-
176
- constructor() {
177
- super({
178
- users: ['alice', 'bob'],
179
- selected: undefined,
180
-
181
- });
182
- }
183
-
184
- @Effect('mergeMap')
185
- @DebounceTime(300)
186
- findOne(id: string): Observable<string> {
187
- return fromFetch(`http://my.super.endpoint/${id}`)
188
- }
189
-
190
- @Reduce()
191
- public onFindOne(state: ItemsState, select: string) {
192
- return {
193
- ...state,
194
- selected,
195
- };
196
- }
170
+ /**
171
+ * with concatMap this rate-limits the effect to one call per 100 ms
172
+ */
173
+ @Effect('concatMap')
174
+ @DelayTime(100)
175
+ track(id: string) {
176
+ return fromFetch(`https://my.endpoint/track/${id}`);
197
177
  }
198
178
  ```
199
179
 
200
- #### DelayTime
201
- It will deley an effect as in a RxJS pipe.
202
- ```typescript
203
- class TestClass extends Store<State, Actions> {
204
-
205
- /**
206
- * this effect will be rate limited at one call per 100 ms
207
- */
208
- @Effect('concatMap')
209
- @DelayTime(100)
210
- effectWithDelay(id: string) {
211
- return fromFetch(`http://my.super.endpoint/${id}`)
212
- }
213
-
214
- @Reduce()
215
- onEffectWithDelay(state: State, payload: string): State {
216
- return {...state, items: [...state.items, payload]};
217
- }
218
- }
219
- ```
220
- ⚠️ Note the use of `concatMap` strategy. If another strategy is used the effect of `@DelayTime` may be not what really expected.
221
- Please see [delay.spec.ts](./src/lib/operators/delay.spec.ts) for all possible combination of `strategy` and `@DelayTime`
180
+ ⚠️ With strategies other than `concatMap` the result may not be what you expect: see [delay.spec.ts](./src/lib/operators/delay.spec.ts) for every combination.
181
+
182
+ `@DebounceTime` and `@DelayTime` are read by the store's dispatch pipeline, so they only have an effect on a `Store` subclass.
222
183
 
223
184
  ## .skills
185
+
224
186
  Automation agents can invoke the following skills when working inside `packages/store`.
225
187
 
226
188
  ### build-store-lib
227
189
  - Goal: emit both ESM and CJS bundles from `src`.
228
- - Run from repo root (ensures workspace deps resolve):
229
- 1. `npm install` (first run or when deps change).
230
- 2. `npm run build -- --scope @microphi/store` to leverage Lerna caching, or `cd packages/store && npm run build` for isolated builds.
231
- - Checks: confirm `packages/store/lib/esm/index.js` and `packages/store/lib/cjs/index.js` are regenerated.
190
+ - From the repo root: `npm install` (first run or when deps change), then `npm run build -w packages/di -w packages/store` (store needs di's `lib/` output).
191
+ - Checks: `packages/store/lib/esm/index.js` and `packages/store/lib/cjs/index.js` are regenerated.
232
192
 
233
193
  ### test-store-lib
234
- - Goal: execute package-specific Jest suite with coverage, mirroring CI.
235
- - Commands:
236
- 1. `cd packages/store`.
237
- 2. `npm run test:ci` (wraps `jest --coverage --ci`).
238
- - When debugging a single spec use `npx jest src/lib/store/store.spec.ts --runTestsByPath` within this folder.
194
+ - Goal: run the package's vitest suite with coverage, mirroring CI.
195
+ - `cd packages/store && npm run test:ci` (wraps `vitest run --coverage`).
196
+ - Single spec: `npx vitest run src/lib/store/store.spec.ts` within this folder.
239
197
 
240
198
  ### lint-store-lib
241
- - Goal: enforce the repo’s TypeScript + ESLint rules before commits.
242
- - Commands:
243
- 1. `cd packages/store`.
244
- 2. `npm run lint:ci` (runs `eslint ./src`).
245
- - Fix order: apply autofixes via `npx eslint ./src --fix`, rerun lint, then tests.
246
-
247
- ### release-store-docs
248
- - Goal: regenerate docs after updating public APIs.
249
- - Commands:
250
- 1. From repo root `npm run docs -- --scope @microphi/store` if scoped docs exist, otherwise invoke `npm run docs` to rebuild all packages.
251
- 2. Run `npm run postdocs` to refresh aggregated docs.
252
- - Verify README snippets still compile by running the TypeScript samples inside `examples/` or via `ts-node` scratch files as needed.
199
+ - Goal: enforce the repo's TypeScript + ESLint rules before commits.
200
+ - `cd packages/store && npm run lint` (runs `eslint ./src`); autofix with `npx eslint ./src --fix`, then rerun lint and tests.
@@ -3,5 +3,6 @@ export * from './lib/effect/effect';
3
3
  export * from './lib/reduce/reduce';
4
4
  export * from './lib/operators/cache';
5
5
  export * from './lib/operators/debounce';
6
+ export * from './lib/operators/delay';
6
7
  export * from './lib/store/types';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC"}
package/lib/cjs/index.js CHANGED
@@ -9,4 +9,5 @@ tslib_1.__exportStar(require("./lib/effect/effect"), exports);
9
9
  tslib_1.__exportStar(require("./lib/reduce/reduce"), exports);
10
10
  tslib_1.__exportStar(require("./lib/operators/cache"), exports);
11
11
  tslib_1.__exportStar(require("./lib/operators/debounce"), exports);
12
+ tslib_1.__exportStar(require("./lib/operators/delay"), exports);
12
13
  tslib_1.__exportStar(require("./lib/store/types"), exports);
@@ -1,21 +1,5 @@
1
- import { Store } from '../store/store';
2
1
  import { Observable } from 'rxjs';
3
- import { Fn, Key } from '../store/types';
4
- import 'reflect-metadata';
5
- export declare const CacheSymbol: unique symbol;
6
- export interface CacheOptions {
7
- /**
8
- * time to live in milliseconds
9
- */
10
- ttl?: number;
11
- /**
12
- * This function has the same arguments as the decorated method
13
- */
14
- trackBy?: (...args: any[]) => string | number;
15
- }
2
+ export { Cache, CacheSymbol } from '@microphi/di';
3
+ export type { CacheEntry, CacheMap, CacheOptions } from '@microphi/di';
16
4
  export type EffectMethod = (...args: any[]) => Observable<any>;
17
- /**
18
- * Caches an effect's value
19
- */
20
- export declare function Cache(options?: CacheOptions): <S extends Store<any, any>>(_target: S, property: Key, descriptor: TypedPropertyDescriptor<Fn>) => void;
21
5
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/lib/operators/cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,kBAAkB,CAAC;AAE1B,eAAO,MAAM,WAAW,eAAmB,CAAC;AAE5C,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,GAAC,MAAM,CAAC;CAC7C;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC;AAE/D;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,wCAEE,CAAC,YAAY,GAAG,cAAc,wBAAwB,EAAE,CAAC,UA2CtG"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/lib/operators/cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAIlC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC"}
@@ -1,39 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Cache = exports.CacheSymbol = void 0;
4
- require("reflect-metadata");
5
- exports.CacheSymbol = Symbol('@Cache');
6
- /**
7
- * Caches an effect's value
8
- */
9
- function Cache(options) {
10
- return (_target, property, descriptor) => {
11
- const originalFn = descriptor.value;
12
- if (originalFn) {
13
- descriptor.value = function (...args) {
14
- const root = this;
15
- const cache = root[exports.CacheSymbol];
16
- // this can grow huge
17
- // shall we put some sort of cap?
18
- const key = options?.trackBy ? options.trackBy(...args) : JSON.stringify(args);
19
- const id = `${property}:${key}`;
20
- const cached = cache.get(id);
21
- if (cached) {
22
- // check ttl given timestamp
23
- const timestamp = cached.timestamp;
24
- const now = Date.now();
25
- const ttl = now - timestamp;
26
- const maxTtl = options?.ttl || 300000; // 5 minutes
27
- if (ttl <= maxTtl) {
28
- const value = cached.value;
29
- return value;
30
- }
31
- }
32
- const retValue = originalFn.apply(this, args);
33
- cache.set(id, { value: retValue, timestamp: Date.now() });
34
- return retValue;
35
- };
36
- }
37
- };
38
- }
39
- exports.Cache = Cache;
3
+ exports.CacheSymbol = exports.Cache = void 0;
4
+ // `@Cache` lives in `@microphi/di` so that it can be used on any class.
5
+ // It is re-exported here to keep the store's public API unchanged.
6
+ var di_1 = require("@microphi/di");
7
+ Object.defineProperty(exports, "Cache", { enumerable: true, get: function () { return di_1.Cache; } });
8
+ Object.defineProperty(exports, "CacheSymbol", { enumerable: true, get: function () { return di_1.CacheSymbol; } });
@@ -5,7 +5,7 @@ require("reflect-metadata");
5
5
  const scan_instance_1 = require("../utilities/scan-instance");
6
6
  exports.ReduceSymbol = Symbol('@Reduce');
7
7
  function Reduce() {
8
- return (target, propertyKey, descriptor) => {
8
+ return (target, propertyKey) => {
9
9
  // by convention a reducer have name such as onFindAll
10
10
  // where findAll is the associated action
11
11
  // with the following we extract the action's name
@@ -1,14 +1,11 @@
1
1
  import { BehaviorSubject, Observable, SchedulerLike } from 'rxjs';
2
2
  import { Effect } from '../effect/effect';
3
- import { CacheSymbol } from '../operators/cache';
3
+ import { CacheMap, CacheSymbol } from '../operators/cache';
4
4
  import { Reducer } from '../reduce/reduce';
5
5
  import { getPayloadFromActionType, LoadingState } from './types';
6
6
  export declare abstract class Store<State, A> {
7
7
  private initialState;
8
- protected [CacheSymbol]: Map<string, {
9
- timestamp: number;
10
- value: Observable<any>;
11
- }>;
8
+ protected [CacheSymbol]: CacheMap;
12
9
  private readonly actions;
13
10
  readonly effects: Effect[];
14
11
  readonly reducers: Reducer[];
@@ -16,7 +13,7 @@ export declare abstract class Store<State, A> {
16
13
  get loading$(): Observable<LoadingState<A>>;
17
14
  protected readonly _store$: BehaviorSubject<State>;
18
15
  get state$(): Observable<State>;
19
- constructor(initialState: State, scheduler?: SchedulerLike);
16
+ constructor(initialState: State, _scheduler?: SchedulerLike);
20
17
  select<R>(projection: (s: State) => R): Observable<R>;
21
18
  getLoadingFor<C extends keyof A>(action: C): Observable<boolean>;
22
19
  dispatch<C extends keyof A>(action: C, ...payload: getPayloadFromActionType<A, C>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/store.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,eAAe,EAAS,UAAU,EAAM,aAAa,EAAW,MAAM,MAAM,CAAC;AAErG,OAAO,EAAE,MAAM,EAA8B,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,EAAe,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAM,wBAAwB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGrE,8BAAsB,KAAK,CAAC,KAAK,EAAE,CAAC;IA0BtB,OAAO,CAAC,YAAY;IAxBhC,SAAS,CAAC,CAAC,WAAW,CAAC;mBAA+B,MAAM;eAAS,WAAW,GAAG,CAAC;OAAK;IAEzF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoE;IAE5F,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAE3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;IAG7B,OAAO,CAAC,SAAS,CAAkC;IAEnD,IAAW,QAAQ,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAEjD;IAED,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC,CAGhD;IAEF,IAAW,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,CAErC;gBAEmB,YAAY,EAAE,KAAK,EAAE,SAAS,GAAE,aAA6B;IAyFjF,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC;IAOrC,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC;IAOhE,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,EACxB,MAAM,EAAE,CAAC,EACT,GAAG,OAAO,EAAE,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC;IAa5C,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG;IAIxC,OAAO,CAAC,MAAM,CAAC,WAAW;IAU1B,OAAO,CAAC,MAAM,CAAC,cAAc;IAS7B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,YAAY;CAarB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/store.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,eAAe,EAAS,UAAU,EAAM,aAAa,EAAW,MAAM,MAAM,CAAC;AAErG,OAAO,EAAE,MAAM,EAA8B,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAe,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAM,wBAAwB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGrE,8BAAsB,KAAK,CAAC,KAAK,EAAE,CAAC;IA0BtB,OAAO,CAAC,YAAY;IAxBhC,SAAS,CAAC,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAa;IAE9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoE;IAE5F,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAE3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;IAG7B,OAAO,CAAC,SAAS,CAAkC;IAEnD,IAAW,QAAQ,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAEjD;IAED,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC,CAGhD;IAEF,IAAW,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,CAErC;gBAEmB,YAAY,EAAE,KAAK,EAAE,UAAU,GAAE,aAA6B;IAyFlF,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC;IAOrC,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC;IAOhE,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,EACxB,MAAM,EAAE,CAAC,EACT,GAAG,OAAO,EAAE,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC;IAa5C,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG;IAIxC,OAAO,CAAC,MAAM,CAAC,WAAW;IAU1B,OAAO,CAAC,MAAM,CAAC,cAAc;IAS7B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,YAAY;CAarB"}
@@ -17,7 +17,7 @@ class Store {
17
17
  get state$() {
18
18
  return this._store$.asObservable();
19
19
  }
20
- constructor(initialState, scheduler = rxjs_1.asapScheduler) {
20
+ constructor(initialState, _scheduler = rxjs_1.asapScheduler) {
21
21
  this.initialState = initialState;
22
22
  this[_a] = new Map();
23
23
  this.actions = new Map();
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC;AAElC,MAAM,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAEzC,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,wBAAwB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IACvD,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,GACpC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAC9C,CAAC,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAE7B,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,SAAS,IAAI,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAEnE,MAAM,MAAM,WAAW,CAAC,OAAO,IAAI;KAEhC,CAAC,IAAI,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW,CAAC,SAAS,CAAC,GAC3D,KAAK,GACL,OAAO,CAAC,CAAC,CAAC;CACf,CAAA;AAED,MAAM,MAAM,SAAS,CAAC,KAAK,EAAE,OAAO,IAClC;KACG,CAAC,IAAI,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAC3D,GAID;KAEG,CAAC,IAAI,MAAM,OAAO,IAAI,KAAK,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,UAAU,CAAC,MAAM,CAAC,CAAC,GAC7G,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,KAAK,GACnC,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GACrC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,KAAK,GACrC,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,KAAK;CAE7B,CAAC;AAEJ,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;CACjB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC;AAElC,MAAM,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAEzC,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C,MAAM,MAAM,wBAAwB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IACvD,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,GAAG,GACpC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,GAAG,GAC9C,CAAC,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAE7B,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,SAAS,IAAI,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAEnE,MAAM,MAAM,WAAW,CAAC,OAAO,IAAI;KAEhC,CAAC,IAAI,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW,CAAC,SAAS,CAAC,GAC3D,KAAK,GACL,OAAO,CAAC,CAAC,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,KAAK,EAAE,OAAO,IAClC;KACG,CAAC,IAAI,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAC3D,GAID;KAEG,CAAC,IAAI,MAAM,OAAO,IAAI,KAAK,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,UAAU,CAAC,MAAM,CAAC,CAAC,GAC3G,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,KAAK,GACnC,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GACrC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,KAAK,GACrC,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,KAAK;CAE/B,CAAC;AAEJ,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;CACjB"}
@@ -14,7 +14,7 @@ function scanInstance(instance, cb) {
14
14
  try {
15
15
  proto = Object.getPrototypeOf(proto);
16
16
  }
17
- catch (e) {
17
+ catch {
18
18
  proto = null;
19
19
  }
20
20
  }
@@ -3,5 +3,6 @@ export * from './lib/effect/effect';
3
3
  export * from './lib/reduce/reduce';
4
4
  export * from './lib/operators/cache';
5
5
  export * from './lib/operators/debounce';
6
+ export * from './lib/operators/delay';
6
7
  export * from './lib/store/types';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC"}
package/lib/esm/index.js CHANGED
@@ -6,4 +6,5 @@ export * from './lib/effect/effect';
6
6
  export * from './lib/reduce/reduce';
7
7
  export * from './lib/operators/cache';
8
8
  export * from './lib/operators/debounce';
9
+ export * from './lib/operators/delay';
9
10
  export * from './lib/store/types';
@@ -1,21 +1,5 @@
1
- import { Store } from '../store/store';
2
1
  import { Observable } from 'rxjs';
3
- import { Fn, Key } from '../store/types';
4
- import 'reflect-metadata';
5
- export declare const CacheSymbol: unique symbol;
6
- export interface CacheOptions {
7
- /**
8
- * time to live in milliseconds
9
- */
10
- ttl?: number;
11
- /**
12
- * This function has the same arguments as the decorated method
13
- */
14
- trackBy?: (...args: any[]) => string | number;
15
- }
2
+ export { Cache, CacheSymbol } from '@microphi/di';
3
+ export type { CacheEntry, CacheMap, CacheOptions } from '@microphi/di';
16
4
  export type EffectMethod = (...args: any[]) => Observable<any>;
17
- /**
18
- * Caches an effect's value
19
- */
20
- export declare function Cache(options?: CacheOptions): <S extends Store<any, any>>(_target: S, property: Key, descriptor: TypedPropertyDescriptor<Fn>) => void;
21
5
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/lib/operators/cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,kBAAkB,CAAC;AAE1B,eAAO,MAAM,WAAW,eAAmB,CAAC;AAE5C,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,GAAC,MAAM,CAAC;CAC7C;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC;AAE/D;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,wCAEE,CAAC,YAAY,GAAG,cAAc,wBAAwB,EAAE,CAAC,UA2CtG"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../../src/lib/operators/cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAIlC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC"}
@@ -1,35 +1,3 @@
1
- import 'reflect-metadata';
2
- export const CacheSymbol = Symbol('@Cache');
3
- /**
4
- * Caches an effect's value
5
- */
6
- export function Cache(options) {
7
- return (_target, property, descriptor) => {
8
- const originalFn = descriptor.value;
9
- if (originalFn) {
10
- descriptor.value = function (...args) {
11
- const root = this;
12
- const cache = root[CacheSymbol];
13
- // this can grow huge
14
- // shall we put some sort of cap?
15
- const key = options?.trackBy ? options.trackBy(...args) : JSON.stringify(args);
16
- const id = `${property}:${key}`;
17
- const cached = cache.get(id);
18
- if (cached) {
19
- // check ttl given timestamp
20
- const timestamp = cached.timestamp;
21
- const now = Date.now();
22
- const ttl = now - timestamp;
23
- const maxTtl = options?.ttl || 300000; // 5 minutes
24
- if (ttl <= maxTtl) {
25
- const value = cached.value;
26
- return value;
27
- }
28
- }
29
- const retValue = originalFn.apply(this, args);
30
- cache.set(id, { value: retValue, timestamp: Date.now() });
31
- return retValue;
32
- };
33
- }
34
- };
35
- }
1
+ // `@Cache` lives in `@microphi/di` so that it can be used on any class.
2
+ // It is re-exported here to keep the store's public API unchanged.
3
+ export { Cache, CacheSymbol } from '@microphi/di';