@ngrx-traits/core 12.1.1 → 13.0.0-beta.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.
Files changed (85) hide show
  1. package/cache/cache.service.d.ts +2 -1
  2. package/create-entity-feature.d.ts +188 -17
  3. package/esm2020/cache/cache.actions.mjs +6 -0
  4. package/esm2020/cache/cache.models.mjs +30 -0
  5. package/esm2020/cache/cache.module.mjs +18 -0
  6. package/esm2020/cache/cache.reducer.mjs +138 -0
  7. package/esm2020/cache/cache.selectors.mjs +5 -0
  8. package/esm2020/cache/cache.service.mjs +72 -0
  9. package/esm2020/cache/index.mjs +7 -0
  10. package/esm2020/create-entity-feature.mjs +404 -0
  11. package/esm2020/index.mjs +7 -0
  12. package/esm2020/local-store/disable-local-trait-effects.token.mjs +7 -0
  13. package/esm2020/local-store/index.mjs +3 -0
  14. package/esm2020/local-store/traits-local-store.mjs +147 -0
  15. package/esm2020/model.mjs +2 -0
  16. package/esm2020/ngrx-traits-core.mjs +5 -0
  17. package/esm2020/public_api.mjs +2 -0
  18. package/esm2020/testing/index.mjs +2 -0
  19. package/esm2020/testing/ngrx-traits-core-testing.mjs +5 -0
  20. package/esm2020/testing/provide-mock-local-traits.mjs +36 -0
  21. package/esm2020/testing/public_api.mjs +2 -0
  22. package/esm2020/trait-effect.mjs +32 -0
  23. package/esm2020/util.mjs +70 -0
  24. package/fesm2015/{ngrx-traits-core-testing.js → ngrx-traits-core-testing.mjs} +1 -1
  25. package/fesm2015/ngrx-traits-core-testing.mjs.map +1 -0
  26. package/fesm2015/{ngrx-traits-core.js → ngrx-traits-core.mjs} +292 -69
  27. package/fesm2015/ngrx-traits-core.mjs.map +1 -0
  28. package/{esm2015/testing/provide-mock-local-traits.js → fesm2020/ngrx-traits-core-testing.mjs} +12 -8
  29. package/fesm2020/ngrx-traits-core-testing.mjs.map +1 -0
  30. package/fesm2020/ngrx-traits-core.mjs +915 -0
  31. package/fesm2020/ngrx-traits-core.mjs.map +1 -0
  32. package/local-store/disable-local-trait-effects.token.d.ts +1 -0
  33. package/local-store/traits-local-store.d.ts +73 -0
  34. package/package.json +30 -8
  35. package/src/lib/cache/README.md +100 -0
  36. package/src/lib/local-store/README.md +172 -0
  37. package/testing/package.json +5 -5
  38. package/util.d.ts +35 -0
  39. package/bundles/ngrx-traits-core-testing.umd.js +0 -52
  40. package/bundles/ngrx-traits-core-testing.umd.js.map +0 -1
  41. package/bundles/ngrx-traits-core.umd.js +0 -1212
  42. package/bundles/ngrx-traits-core.umd.js.map +0 -1
  43. package/esm2015/cache/cache.actions.js +0 -6
  44. package/esm2015/cache/cache.actions.js.map +0 -1
  45. package/esm2015/cache/cache.models.js +0 -31
  46. package/esm2015/cache/cache.models.js.map +0 -1
  47. package/esm2015/cache/cache.module.js +0 -18
  48. package/esm2015/cache/cache.module.js.map +0 -1
  49. package/esm2015/cache/cache.reducer.js +0 -141
  50. package/esm2015/cache/cache.reducer.js.map +0 -1
  51. package/esm2015/cache/cache.selectors.js +0 -5
  52. package/esm2015/cache/cache.selectors.js.map +0 -1
  53. package/esm2015/cache/cache.service.js +0 -72
  54. package/esm2015/cache/cache.service.js.map +0 -1
  55. package/esm2015/cache/index.js +0 -7
  56. package/esm2015/cache/index.js.map +0 -1
  57. package/esm2015/create-entity-feature.js +0 -283
  58. package/esm2015/create-entity-feature.js.map +0 -1
  59. package/esm2015/index.js +0 -7
  60. package/esm2015/index.js.map +0 -1
  61. package/esm2015/local-store/disable-local-trait-effects.token.js +0 -6
  62. package/esm2015/local-store/disable-local-trait-effects.token.js.map +0 -1
  63. package/esm2015/local-store/index.js +0 -3
  64. package/esm2015/local-store/index.js.map +0 -1
  65. package/esm2015/local-store/traits-local-store.js +0 -75
  66. package/esm2015/local-store/traits-local-store.js.map +0 -1
  67. package/esm2015/model.js +0 -28
  68. package/esm2015/model.js.map +0 -1
  69. package/esm2015/ngrx-traits-core.js +0 -5
  70. package/esm2015/ngrx-traits-core.js.map +0 -1
  71. package/esm2015/public_api.js +0 -2
  72. package/esm2015/public_api.js.map +0 -1
  73. package/esm2015/testing/index.js +0 -2
  74. package/esm2015/testing/index.js.map +0 -1
  75. package/esm2015/testing/ngrx-traits-core-testing.js +0 -5
  76. package/esm2015/testing/ngrx-traits-core-testing.js.map +0 -1
  77. package/esm2015/testing/provide-mock-local-traits.js.map +0 -1
  78. package/esm2015/testing/public_api.js +0 -2
  79. package/esm2015/testing/public_api.js.map +0 -1
  80. package/esm2015/trait-effect.js +0 -32
  81. package/esm2015/trait-effect.js.map +0 -1
  82. package/esm2015/util.js +0 -17
  83. package/esm2015/util.js.map +0 -1
  84. package/fesm2015/ngrx-traits-core-testing.js.map +0 -1
  85. package/fesm2015/ngrx-traits-core.js.map +0 -1
@@ -56,10 +56,11 @@ import { CacheKey } from './cache.models';
56
56
  * @param options.expires - time to expire the cache valued, if not present is infinite
57
57
  * @param options.maxCacheSize - max number of keys to store , only works if last key is variable
58
58
  */
59
- export declare function cache<T>({ store, key, source, expires, maxCacheSize, }: {
59
+ export declare function cache<T>({ store, key, source, expires, maxCacheSize, skip, }: {
60
60
  store: Store;
61
61
  key: CacheKey;
62
62
  source: Observable<T>;
63
63
  expires?: number;
64
64
  maxCacheSize?: number;
65
+ skip?: boolean;
65
66
  }): Observable<any>;
@@ -1,27 +1,101 @@
1
1
  import { Config, ExtractActionsType, ExtractSelectorsType, ExtractStateType, EntityFeatureFactory, FeatureSelectors, KeyedConfig, TraitActions, TraitFactory, TraitSelectors, TraitStateMutators, UnionToIntersection, TraitActionsFactory, TraitSelectorsFactory, TraitInitialStateFactory, TraitStateMutatorsFactory, TraitReducerFactory, TraitEffectsFactory } from './model';
2
2
  import { ActionType } from '@ngrx/store';
3
3
  import { Type } from './local-store';
4
- export declare function createTraitFactory<State = {}, A extends TraitActions = {}, S extends TraitSelectors<State> = {}, M extends TraitStateMutators<State> = {}, KEY extends string = string, C = unknown, KC = KeyedConfig<KEY, C>>(f: {
5
- key: KEY;
6
- config?: C;
7
- depends?: string[];
8
- actions?: TraitActionsFactory<A, KC>;
9
- selectors?: TraitSelectorsFactory<State, S, KC>;
10
- initialState?: TraitInitialStateFactory<State, KC>;
11
- mutators?: TraitStateMutatorsFactory<State, M, KC>;
12
- reducer?: TraitReducerFactory<State, A, S, M, KC>;
13
- effects?: TraitEffectsFactory<State, A, S, KC>;
14
- }): TraitFactory<State, A, S, M, KEY, C, KC>;
15
- export declare function createEntityFeatureFactory<F extends readonly TraitFactory[]>(...traits: F): EntityFeatureFactory<'Entity', 'Entities', ExtractStateType<F>, ExtractActionsType<F>, ExtractSelectorsType<F>>;
4
+ /**
5
+ * Creates a function that when execute will combine all the traits, and return a EntityFeatureFactory
6
+ * which combines all the traits actions, selectors , reducers and effects,
7
+ * the names param will replace any action and selector with the word Entity or Entities,
8
+ * with the corresponding entityName and entitiesName param (entityName+'s' if entitiesName is omitted).
9
+ * @param namesConfig - Optional Names for entities
10
+ * @param namesConfig.entityName - singular name for entity
11
+ * @param [namesConfig.entitiesName] - plural name for entities, defaults to entityName + 's'
12
+ * @param traits set of traits to be combined
13
+ *
14
+ * @example
15
+ *
16
+ * const featureFactory = createEntityFeatureFactory(
17
+ * { entityName: 'product' },
18
+ * addLoadEntitiesTrait<Product>(),
19
+ * addSelectEntityTrait<Product>(),
20
+ * addAsyncActionTrait({
21
+ * name: 'checkout',
22
+ * actionSuccessProps: props<{ orderId: string }>(),
23
+ * })
24
+ * );
25
+ *
26
+ * export const productsFeature = featureFactory({
27
+ * actionsGroupKey: '[Products]',
28
+ * featureSelector: 'products',
29
+ * });
30
+ */
16
31
  export declare function createEntityFeatureFactory<F extends readonly TraitFactory[], EntityName extends string, EntitiesName extends string = `${EntityName}s`>({ entityName, entitiesName, }: {
17
32
  entityName: EntityName;
18
33
  entitiesName?: EntitiesName;
19
34
  }, ...traits: F): EntityFeatureFactory<EntityName, EntitiesName, ExtractStateType<F>, ExtractActionsType<F>, ExtractSelectorsType<F>>;
20
- export declare function setPropertyReducer<State, P extends keyof State>(sourceReducer: (state: State, action: ActionType<any>) => State, property: P, propertyReducer: (state: State[P], action: ActionType<any>) => State[P]): (state: State, action: ActionType<any>) => State;
21
- export declare function setPropertiesReducer<State, P extends keyof State>(sourceReducer: (state: State, action: ActionType<any>) => State, propertiesReducers: {
22
- [key in P]: (state: State[P], action: ActionType<any>) => State[P];
23
- }): (state: State, action: ActionType<any>) => State;
24
- export declare function joinReducers<State>(firstReducer: (state: State, action: ActionType<any>) => State, secondReducer: (state: any, action: ActionType<any>) => any): (state: State, action: ActionType<any>) => State;
35
+ /**
36
+ * Creates a function that when execute will combine all the traits, and return a EntityFeatureFactory
37
+ * which combines all the traits actions, selectors , reducers and effects.
38
+ * @param traits set of traits to be combined
39
+ *
40
+ * @example
41
+ *
42
+ * const featureFactory = createEntityFeatureFactory(
43
+ * { entityName: 'product' },
44
+ * addLoadEntitiesTrait<Product>(),
45
+ * addSelectEntityTrait<Product>(),
46
+ * addAsyncActionTrait({
47
+ * name: 'checkout',
48
+ * actionSuccessProps: props<{ orderId: string }>(),
49
+ * })
50
+ * );
51
+ *
52
+ * export const productsFeature = featureFactory({
53
+ * actionsGroupKey: '[Products]',
54
+ * featureSelector: 'products',
55
+ * });
56
+ *
57
+ * productsFeature.actions.loadProducts();
58
+ */
59
+ export declare function createEntityFeatureFactory<F extends readonly TraitFactory[]>(...traits: F): EntityFeatureFactory<'Entity', 'Entities', ExtractStateType<F>, ExtractActionsType<F>, ExtractSelectorsType<F>>;
60
+ /**
61
+ * Combine a map entityFeatureFactories into one,
62
+ * grouping the actions and selectors by the key of the respective entityFeatureFactory
63
+ * @param traitFactoriesMap
64
+ *
65
+ * @example
66
+ *
67
+ * const clientsFeatureFactory = createEntityFeatureFactory(
68
+ * { entityName: 'client', entitiesName: 'clients' },
69
+ * addLoadEntitiesTrait<Client>(),
70
+ * addCrudEntitiesTrait<Client>()
71
+ * );
72
+ *
73
+ * const productOrderFeatureFactory = createEntityFeatureFactory(
74
+ * { entityName: 'productOrder' },
75
+ * addLoadEntitiesTrait<ProductOrder>(),
76
+ * addSelectEntitiesTrait<ProductOrder>()
77
+ * );
78
+ *
79
+ * const productFeatureFactory = createEntityFeatureFactory(
80
+ * { entityName: 'product' },
81
+ * addLoadEntitiesTrait<Product>(),
82
+ * addSelectEntitiesTrait<Product>()
83
+ * );
84
+ *
85
+ * const productCombinedFactory = combineEntityFeatures({
86
+ * products: productFeatureFactory,
87
+ * productOrders: productOrderFeatureFactory,
88
+ * clients: clientsFeatureFactory,
89
+ * });
90
+ *
91
+ * const combinedFeature = productCombinedFactory({
92
+ * actionsGroupKey: '[Combined]',
93
+ * featureSelector: 'combined',
94
+ * });
95
+ *
96
+ * combinedFeature.actions.client.loadClients();
97
+ * combinedFeature.actions.product.loadProducts();
98
+ */
25
99
  export declare function combineEntityFeatures<T extends {
26
100
  [key: string]: EntityFeatureFactory<any, any>;
27
101
  }, K extends keyof T, State extends {
@@ -37,11 +111,93 @@ export declare function combineEntityFeatures<T extends {
37
111
  effects: Type<any>[];
38
112
  initialState: State;
39
113
  }>(traitFactoriesMap: T): R;
114
+ /**
115
+ * Mix a map entityFeatureFactories into one, different from combine the actions and selectors a mix, not group by key like in combine, the keys are still use
116
+ * internal in the reducers and selector to separate the state
117
+ * @param traitFactoriesMap
118
+ *
119
+ * @example
120
+ *
121
+ * const clientsFeatureFactory = createEntityFeatureFactory(
122
+ * { entityName: 'client', entitiesName: 'clients' },
123
+ * addLoadEntitiesTrait<Client>(),
124
+ * addCrudEntitiesTrait<Client>()
125
+ * );
126
+ *
127
+ * const productOrderFeatureFactory = createEntityFeatureFactory(
128
+ * { entityName: 'productOrder' },
129
+ * addLoadEntitiesTrait<ProductOrder>(),
130
+ * addSelectEntitiesTrait<ProductOrder>()
131
+ * );
132
+ *
133
+ * const productFeatureFactory = createEntityFeatureFactory(
134
+ * { entityName: 'product' },
135
+ * addLoadEntitiesTrait<Product>(),
136
+ * addSelectEntitiesTrait<Product>()
137
+ * );
138
+ *
139
+ * const productMixedFactory = mixEntityFeatures({
140
+ * products: productFeatureFactory,
141
+ * productOrders: productOrderFeatureFactory,
142
+ * clients: clientsFeatureFactory,
143
+ * });
144
+ *
145
+ * const mixedFeature = productMixedFactory({
146
+ * actionsGroupKey: '[Mixed]',
147
+ * featureSelector: 'mixed',
148
+ * });
149
+ * mixedFeature.actions.loadClients();
150
+ * mixedFeature.actions.loadProducts();
151
+ *
152
+ */
40
153
  export declare function mixEntityFeatures<T extends {
41
154
  [key: string]: EntityFeatureFactory<any, any>;
42
155
  }, K extends keyof T, State extends {
43
156
  [P in K]: ExtractStateType<ReturnType<T[P]>>;
44
157
  }, A extends TraitActions & UnionToIntersection<ExtractActionsType<ReturnType<T[K]>>>, S extends TraitSelectors<any> & UnionToIntersection<FeatureSelectors<State, ExtractSelectorsType<ReturnType<T[K]>>>>, R extends EntityFeatureFactory<any, any, State, A, S>>(traitFactoriesMap: T): R;
158
+ /**
159
+ * Combines targetTraitFactory with the traitFactoriesMap using the keys as props for the targetTraitFactory state,
160
+ * and grouping the combined actions by key
161
+ * @param targetTraitFactory
162
+ * @param traitFactoriesMap
163
+ *
164
+ * @example
165
+ *
166
+ * const clientsFeatureFactory = createEntityFeatureFactory(
167
+ * { entityName: 'client', entitiesName: 'clients' },
168
+ * addLoadEntitiesTrait<Client>(),
169
+ * addCrudEntitiesTrait<Client>()
170
+ * );
171
+ *
172
+ * const productOrderFeatureFactory = createEntityFeatureFactory(
173
+ * { entityName: 'productOrder' },
174
+ * addLoadEntitiesTrait<ProductOrder>(),
175
+ * addSelectEntitiesTrait<ProductOrder>()
176
+ * );
177
+ *
178
+ * const productFeatureFactory = createEntityFeatureFactory(
179
+ * { entityName: 'product' },
180
+ * addLoadEntitiesTrait<Product>(),
181
+ * addSelectEntitiesTrait<Product>()
182
+ * );
183
+ *
184
+ * const productAddEntityPropertiesFactory = addEntityFeaturesProperties(
185
+ * productFeatureFactory,
186
+ * {
187
+ * productOrders: productOrderFeatureFactory,
188
+ * clients: clientsFeatureFactory,
189
+ * }
190
+ * );
191
+ *
192
+ * const combinedFeature = productAddEntityPropertiesFactory({
193
+ * actionsGroupKey: '[addEntityFeatures]',
194
+ * featureSelector: 'addEntityFeatures',
195
+ * });
196
+ *
197
+ * combinedFeature.actions.loadProducts();
198
+ * combinedFeature.actions.clients.loadClients();
199
+ * combinedFeature.actions.productOrders.loadProductOrders();
200
+ */
45
201
  export declare function addEntityFeaturesProperties<F extends EntityFeatureFactory<any, any>, T extends {
46
202
  [key: string]: EntityFeatureFactory<any, any, any, any, any>;
47
203
  }, K extends keyof T, State extends ExtractStateType<ReturnType<F>> & {
@@ -57,3 +213,18 @@ export declare function addEntityFeaturesProperties<F extends EntityFeatureFacto
57
213
  effects: Type<any>[];
58
214
  initialState: State;
59
215
  }>(targetTraitFactory: F, traitFactoriesMap: T): R;
216
+ /**
217
+ * Helper function to create an implementation a TraitFactory
218
+ * @param f TraitFactory implementation
219
+ */
220
+ export declare function createTraitFactory<State = {}, A extends TraitActions = {}, S extends TraitSelectors<State> = {}, M extends TraitStateMutators<State> = {}, KEY extends string = string, C = unknown, KC = KeyedConfig<KEY, C>>(f: {
221
+ key: KEY;
222
+ config?: C;
223
+ depends?: string[];
224
+ actions?: TraitActionsFactory<A, KC>;
225
+ selectors?: TraitSelectorsFactory<State, S, KC>;
226
+ initialState?: TraitInitialStateFactory<State, KC>;
227
+ mutators?: TraitStateMutatorsFactory<State, M, KC>;
228
+ reducer?: TraitReducerFactory<State, A, S, M, KC>;
229
+ effects?: TraitEffectsFactory<State, A, S, KC>;
230
+ }): TraitFactory<State, A, S, M, KEY, C, KC>;
@@ -0,0 +1,6 @@
1
+ import { createAction, props } from '@ngrx/store';
2
+ export const cache = createAction('[Cache] Cache', props());
3
+ export const hitCache = createAction('[Cache] Hit Cache', props());
4
+ export const invalidateCache = createAction('[Cache] Invalidate Cache', props());
5
+ export const deleteCache = createAction('[Cache] Delete Cache', props());
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuYWN0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvbmdyeC10cmFpdHMvY29yZS9zcmMvbGliL2NhY2hlL2NhY2hlLmFjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHbEQsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLFlBQVksQ0FDL0IsZUFBZSxFQUNmLEtBQUssRUFNRCxDQUNMLENBQUM7QUFDRixNQUFNLENBQUMsTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUNsQyxtQkFBbUIsRUFDbkIsS0FBSyxFQUFxQixDQUMzQixDQUFDO0FBQ0YsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHLFlBQVksQ0FDekMsMEJBQTBCLEVBQzFCLEtBQUssRUFBcUIsQ0FDM0IsQ0FBQztBQUNGLE1BQU0sQ0FBQyxNQUFNLFdBQVcsR0FBRyxZQUFZLENBQ3JDLHNCQUFzQixFQUN0QixLQUFLLEVBQXFCLENBQzNCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVBY3Rpb24sIHByb3BzIH0gZnJvbSAnQG5ncngvc3RvcmUnO1xuaW1wb3J0IHsgQ2FjaGVLZXkgfSBmcm9tICcuL2NhY2hlLm1vZGVscyc7XG5cbmV4cG9ydCBjb25zdCBjYWNoZSA9IGNyZWF0ZUFjdGlvbihcbiAgJ1tDYWNoZV0gQ2FjaGUnLFxuICBwcm9wczx7XG4gICAga2V5OiBDYWNoZUtleTtcbiAgICB2YWx1ZTogYW55O1xuICAgIGRhdGU6IG51bWJlcjtcbiAgICBtYXhDYWNoZVNpemU/OiBudW1iZXI7XG4gICAgZXhwaXJlcz86IG51bWJlcjtcbiAgfT4oKVxuKTtcbmV4cG9ydCBjb25zdCBoaXRDYWNoZSA9IGNyZWF0ZUFjdGlvbihcbiAgJ1tDYWNoZV0gSGl0IENhY2hlJyxcbiAgcHJvcHM8eyBrZXk6IENhY2hlS2V5IH0+KClcbik7XG5leHBvcnQgY29uc3QgaW52YWxpZGF0ZUNhY2hlID0gY3JlYXRlQWN0aW9uKFxuICAnW0NhY2hlXSBJbnZhbGlkYXRlIENhY2hlJyxcbiAgcHJvcHM8eyBrZXk6IENhY2hlS2V5IH0+KClcbik7XG5leHBvcnQgY29uc3QgZGVsZXRlQ2FjaGUgPSBjcmVhdGVBY3Rpb24oXG4gICdbQ2FjaGVdIERlbGV0ZSBDYWNoZScsXG4gIHByb3BzPHsga2V5OiBDYWNoZUtleSB9PigpXG4pO1xuIl19
@@ -0,0 +1,30 @@
1
+ function hash(key) {
2
+ return JSON.stringify(key, (_, val) => typeof val == 'object'
3
+ ? Object.keys(val)
4
+ .sort()
5
+ .reduce((result, k) => {
6
+ result[k] = val[k];
7
+ return result;
8
+ }, {})
9
+ : val);
10
+ }
11
+ export function hashKey(key) {
12
+ return typeof key === 'string'
13
+ ? [key]
14
+ : key.map((k) => {
15
+ return typeof k === 'string' ? k : hash(k);
16
+ });
17
+ }
18
+ export function getCacheValue(keys, state) {
19
+ let parent = state;
20
+ for (const key of keys) {
21
+ parent = parent?.keys?.[key];
22
+ if (!parent)
23
+ return undefined;
24
+ }
25
+ return parent?.data;
26
+ }
27
+ export function isCacheValid(cache, exp) {
28
+ return !cache.invalid && Date.now() <= cache.date + exp;
29
+ }
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUubW9kZWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9uZ3J4LXRyYWl0cy9jb3JlL3NyYy9saWIvY2FjaGUvY2FjaGUubW9kZWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWtCQSxTQUFTLElBQUksQ0FBQyxHQUFvQjtJQUNoQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQ3BDLE9BQU8sR0FBRyxJQUFJLFFBQVE7UUFDcEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO2FBQ2IsSUFBSSxFQUFFO2FBQ04sTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3BCLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbkIsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQyxFQUFFLEVBQVMsQ0FBQztRQUNqQixDQUFDLENBQUMsR0FBRyxDQUNSLENBQUM7QUFDSixDQUFDO0FBRUQsTUFBTSxVQUFVLE9BQU8sQ0FBQyxHQUFhO0lBQ25DLE9BQU8sT0FBTyxHQUFHLEtBQUssUUFBUTtRQUM1QixDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7UUFDUCxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1lBQ1osT0FBTyxPQUFPLENBQUMsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdDLENBQUMsQ0FBQyxDQUFDO0FBQ1QsQ0FBQztBQUVELE1BQU0sVUFBVSxhQUFhLENBQzNCLElBQWMsRUFDZCxLQUFpQjtJQUVqQixJQUFJLE1BQU0sR0FBMEIsS0FBSyxDQUFDO0lBQzFDLEtBQUssTUFBTSxHQUFHLElBQUksSUFBSSxFQUFFO1FBQ3RCLE1BQU0sR0FBRyxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPLFNBQVMsQ0FBQztLQUMvQjtJQUNELE9BQU8sTUFBTSxFQUFFLElBQUksQ0FBQztBQUN0QixDQUFDO0FBRUQsTUFBTSxVQUFVLFlBQVksQ0FBQyxLQUFnQixFQUFFLEdBQVc7SUFDeEQsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLEtBQUssQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDO0FBQzFELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgdHlwZSBDYWNoZUtleSA9IHN0cmluZyB8IChzdHJpbmcgfCBvYmplY3QpW107XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2FjaGVEYXRhIHtcbiAgdmFsdWU6IGFueTtcbiAgZGF0ZTogbnVtYmVyO1xuICBpbnZhbGlkOiBib29sZWFuO1xuICBoaXRDb3VudDogbnVtYmVyO1xufVxuZXhwb3J0IGludGVyZmFjZSBDYWNoZUtleXMge1xuICBrZXlzPzogeyBba2V5OiBzdHJpbmddOiBDYWNoZUtleXMgfTtcbiAgZGF0YT86IENhY2hlRGF0YTtcbn1cblxuZXhwb3J0IHR5cGUgQ2FjaGVTdGF0ZSA9IENhY2hlS2V5cztcblxuZXhwb3J0IGludGVyZmFjZSBDYWNoZUNvbmZpZyB7XG4gIGV4cGlyZXM6IG51bWJlcjtcbn1cbmZ1bmN0aW9uIGhhc2goa2V5OiBzdHJpbmcgfCBvYmplY3QpOiBzdHJpbmcge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoa2V5LCAoXywgdmFsKSA9PlxuICAgIHR5cGVvZiB2YWwgPT0gJ29iamVjdCdcbiAgICAgID8gT2JqZWN0LmtleXModmFsKVxuICAgICAgICAgIC5zb3J0KClcbiAgICAgICAgICAucmVkdWNlKChyZXN1bHQsIGspID0+IHtcbiAgICAgICAgICAgIHJlc3VsdFtrXSA9IHZhbFtrXTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgfSwge30gYXMgYW55KVxuICAgICAgOiB2YWxcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGhhc2hLZXkoa2V5OiBDYWNoZUtleSk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIHR5cGVvZiBrZXkgPT09ICdzdHJpbmcnXG4gICAgPyBba2V5XVxuICAgIDoga2V5Lm1hcCgoaykgPT4ge1xuICAgICAgICByZXR1cm4gdHlwZW9mIGsgPT09ICdzdHJpbmcnID8gayA6IGhhc2goayk7XG4gICAgICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlVmFsdWUoXG4gIGtleXM6IHN0cmluZ1tdLFxuICBzdGF0ZTogQ2FjaGVTdGF0ZVxuKTogQ2FjaGVEYXRhIHwgdW5kZWZpbmVkIHtcbiAgbGV0IHBhcmVudDogQ2FjaGVLZXlzIHwgdW5kZWZpbmVkID0gc3RhdGU7XG4gIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHtcbiAgICBwYXJlbnQgPSBwYXJlbnQ/LmtleXM/LltrZXldO1xuICAgIGlmICghcGFyZW50KSByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiBwYXJlbnQ/LmRhdGE7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0NhY2hlVmFsaWQoY2FjaGU6IENhY2hlRGF0YSwgZXhwOiBudW1iZXIpIHtcbiAgcmV0dXJuICFjYWNoZS5pbnZhbGlkICYmIERhdGUubm93KCkgPD0gY2FjaGUuZGF0ZSArIGV4cDtcbn1cbiJdfQ==
@@ -0,0 +1,18 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { StoreModule } from '@ngrx/store';
3
+ import { cacheReducer } from './cache.reducer';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@ngrx/store";
6
+ export class CacheModule {
7
+ }
8
+ CacheModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: CacheModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
9
+ CacheModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: CacheModule, imports: [i1.StoreFeatureModule] });
10
+ CacheModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: CacheModule, providers: [], imports: [[StoreModule.forFeature('cache', cacheReducer)]] });
11
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: CacheModule, decorators: [{
12
+ type: NgModule,
13
+ args: [{
14
+ imports: [StoreModule.forFeature('cache', cacheReducer)],
15
+ providers: [],
16
+ }]
17
+ }] });
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9uZ3J4LXRyYWl0cy9jb3JlL3NyYy9saWIvY2FjaGUvY2FjaGUubW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMxQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7OztBQU0vQyxNQUFNLE9BQU8sV0FBVzs7eUdBQVgsV0FBVzswR0FBWCxXQUFXOzBHQUFYLFdBQVcsYUFGWCxFQUFFLFlBREosQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQzs0RkFHN0MsV0FBVztrQkFKdkIsUUFBUTttQkFBQztvQkFDUixPQUFPLEVBQUUsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztvQkFDeEQsU0FBUyxFQUFFLEVBQUU7aUJBQ2QiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3RvcmVNb2R1bGUgfSBmcm9tICdAbmdyeC9zdG9yZSc7XG5pbXBvcnQgeyBjYWNoZVJlZHVjZXIgfSBmcm9tICcuL2NhY2hlLnJlZHVjZXInO1xuXG5ATmdNb2R1bGUoe1xuICBpbXBvcnRzOiBbU3RvcmVNb2R1bGUuZm9yRmVhdHVyZSgnY2FjaGUnLCBjYWNoZVJlZHVjZXIpXSxcbiAgcHJvdmlkZXJzOiBbXSxcbn0pXG5leHBvcnQgY2xhc3MgQ2FjaGVNb2R1bGUge31cbiJdfQ==
@@ -0,0 +1,138 @@
1
+ import { createReducer, on } from '@ngrx/store';
2
+ import { hashKey, isCacheValid, } from './cache.models';
3
+ import * as CacheActions from './cache.actions';
4
+ export const initialState = {
5
+ keys: {},
6
+ };
7
+ export const cacheReducer = createReducer(initialState, on(CacheActions.cache, (state, { key, value, date, maxCacheSize }) => setCacheValue(hashKey(key), { value, date, invalid: false }, state, maxCacheSize)), on(CacheActions.invalidateCache, (state, { key }) => {
8
+ const k = hashKey(key);
9
+ return invalidateCache(k, state);
10
+ }), on(CacheActions.deleteCache, (state, { key }) => {
11
+ const k = hashKey(key);
12
+ return deleteCacheValue(k, state);
13
+ }), on(CacheActions.hitCache, (state, { key }) => {
14
+ const k = hashKey(key);
15
+ return increaseCacheHitCount(k, state);
16
+ }));
17
+ function setCacheValue(keys, value, state, maxCacheSize, expires) {
18
+ const newState = { ...state };
19
+ let cache = newState;
20
+ let lastCache = undefined;
21
+ for (let i = 0; i < keys.length; i++) {
22
+ const key = keys[i];
23
+ cache.keys = cache?.keys ? { ...cache?.keys } : {};
24
+ let v = cache.keys[key];
25
+ v = v ? { ...v } : {};
26
+ cache.keys[key] = v;
27
+ lastCache = cache;
28
+ cache = v;
29
+ }
30
+ cache.data = cache.data
31
+ ? { ...value, hitCount: cache.data.hitCount + 1 }
32
+ : { ...value, hitCount: 1 };
33
+ if (maxCacheSize &&
34
+ lastCache?.keys &&
35
+ Object.keys(lastCache.keys).length > maxCacheSize) {
36
+ const entries = findLessHitOrOldestCacheEntries(lastCache, expires ?? Infinity, maxCacheSize);
37
+ if (entries && entries.length) {
38
+ for (const [key] of entries) {
39
+ delete lastCache.keys[key];
40
+ }
41
+ }
42
+ }
43
+ return newState;
44
+ }
45
+ function findLessHitOrOldestCacheEntries(state, expires, maxCacheSize) {
46
+ if (!state.keys)
47
+ return undefined;
48
+ const entries = Object.entries(state.keys);
49
+ // find the newest key;
50
+ const [newestKey] = entries.reduce((a, b) => {
51
+ const aDate = a[1].data?.date ?? 0;
52
+ const bDate = b[1].data?.date ?? 0;
53
+ return aDate > bDate ? a : b;
54
+ });
55
+ const sorted = entries.sort(([aKey, aValue], [bKey, bValue]) => {
56
+ // ensures the newest key always wins
57
+ if (aKey === newestKey)
58
+ return -1;
59
+ if (bKey === newestKey)
60
+ return 1;
61
+ const aValid = aValue.data && isCacheValid(aValue.data, expires) ? 1 : 0;
62
+ const bValid = bValue.data && isCacheValid(bValue.data, expires) ? 1 : 0;
63
+ const diffValid = aValid - bValid;
64
+ const diffHit = (aValue.data?.hitCount ?? 0) - (bValue.data?.hitCount ?? 0);
65
+ const diffDate = (aValue.data?.date ?? 0) - (bValue.data?.date ?? 0);
66
+ return (-1 * (diffValid === 0 ? (diffHit === 0 ? diffDate : diffHit) : diffValid));
67
+ });
68
+ return sorted.slice(maxCacheSize);
69
+ }
70
+ function deleteCacheValue(keys, state) {
71
+ const newState = { ...state };
72
+ let cache = newState;
73
+ for (const key of keys) {
74
+ if (!cache.keys)
75
+ return state;
76
+ cache.keys = { ...cache?.keys };
77
+ let v = cache.keys[key];
78
+ if (!v)
79
+ return state;
80
+ v = { ...v };
81
+ cache.keys[key] = v;
82
+ cache = v;
83
+ }
84
+ if (cache.data)
85
+ delete cache.data;
86
+ else if (cache.keys)
87
+ delete cache.keys;
88
+ return newState;
89
+ }
90
+ function invalidateCache(keys, state) {
91
+ const newState = { ...state };
92
+ let cache = newState;
93
+ for (const key of keys) {
94
+ if (!cache?.keys)
95
+ return state;
96
+ cache.keys = { ...cache?.keys };
97
+ let v = cache?.keys?.[key];
98
+ if (!v)
99
+ return state;
100
+ v = { ...v };
101
+ cache.keys[key] = v;
102
+ cache = v;
103
+ }
104
+ cache && invalidaSubKeys(cache);
105
+ return newState;
106
+ }
107
+ function increaseCacheHitCount(keys, state) {
108
+ const newState = { ...state };
109
+ let cache = newState;
110
+ for (const key of keys) {
111
+ if (!cache?.keys)
112
+ return state;
113
+ cache.keys = { ...cache?.keys };
114
+ let v = cache?.keys?.[key];
115
+ if (!v)
116
+ return state;
117
+ v = { ...v };
118
+ cache.keys[key] = v;
119
+ cache = v;
120
+ }
121
+ if (!cache.data)
122
+ return state;
123
+ cache.data = { ...cache.data, hitCount: cache.data.hitCount + 1 };
124
+ return newState;
125
+ }
126
+ function invalidaSubKeys(state) {
127
+ if (state.data) {
128
+ state.data = { ...state.data, invalid: true };
129
+ }
130
+ if (state.keys) {
131
+ state.keys = { ...state.keys };
132
+ for (const key in state.keys) {
133
+ state.keys[key] = invalidaSubKeys({ ...state.keys[key] });
134
+ }
135
+ }
136
+ return state;
137
+ }
138
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUucmVkdWNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvbmdyeC10cmFpdHMvY29yZS9zcmMvbGliL2NhY2hlL2NhY2hlLnJlZHVjZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxFQUFFLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDaEQsT0FBTyxFQUlMLE9BQU8sRUFDUCxZQUFZLEdBQ2IsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEtBQUssWUFBWSxNQUFNLGlCQUFpQixDQUFDO0FBRWhELE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBZTtJQUN0QyxJQUFJLEVBQUUsRUFBRTtDQUNULENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsYUFBYSxDQUN2QyxZQUFZLEVBQ1osRUFBRSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsRUFBRSxFQUFFLENBQ25FLGFBQWEsQ0FDWCxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQ1osRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFDL0IsS0FBSyxFQUNMLFlBQVksQ0FDYixDQUNGLEVBQ0QsRUFBRSxDQUFDLFlBQVksQ0FBQyxlQUFlLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFO0lBQ2xELE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN2QixPQUFPLGVBQWUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDbkMsQ0FBQyxDQUFDLEVBQ0YsRUFBRSxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFO0lBQzlDLE1B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QUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxJQUFJLENBQUMsQ0FBQztRQUNuQyxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLElBQUksSUFBSSxDQUFDLENBQUM7UUFDbkMsT0FBTyxLQUFLLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvQixDQUFDLENBQUMsQ0FBQztJQUNILE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFO1FBQzdELHFDQUFxQztRQUNyQyxJQUFJLElBQUksS0FBSyxTQUFTO1lBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUNsQyxJQUFJLElBQUksS0FBSyxTQUFTO1lBQUUsT0FBTyxDQUFDLENBQUM7UUFDakMsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLElBQUksSUFBSSxZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekUsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLElBQUksSUFBSSxZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekUsTUFBTSxTQUFTLEdBQUcsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNsQyxNQUFNLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsUUFBUSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxRQUFRLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDNUUsTUFBTSxRQUFRLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFF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RUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzNCLElBQUksQ0FBQyxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDckIsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNiLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BCLEtBQUssR0FBRyxDQUFDLENBQUM7S0FDWDtJQUNELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQzlCLEtBQUssQ0FBQyxJQUFJLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLENBQUMsRUFBRSxDQUFDO0lBQ2xFLE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUM7QUFFRCxTQUFTLGVBQWUsQ0FBQyxLQUFnQjtJQUN2QyxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUU7UUFDZCxLQUFLLENBQUMsSUFBSSxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztLQUMvQztJQUNELElBQUksS0FBSyxDQUFDLElBQUksRUFBRTtRQUNkLEtBQUssQ0FBQyxJQUFJLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUMvQixLQUFLLE1BQU0sR0FBRyxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUU7WUFDNUIsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxlQUFlLENBQUMsRUFBRSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQzNEO0tBQ0Y7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVSZWR1Y2VyLCBvbiB9IGZyb20gJ0BuZ3J4L3N0b3JlJztcbmltcG9ydCB7XG4gIENhY2hlRGF0YSxcbiAgQ2FjaGVLZXlzLFxuICBDYWNoZVN0YXRlLFxuICBoYXNoS2V5LFxuICBpc0NhY2hlVmFsaWQsXG59IGZyb20gJy4vY2FjaGUubW9kZWxzJztcbmltcG9ydCAqIGFzIENhY2hlQWN0aW9ucyBmcm9tICcuL2NhY2hlLmFjdGlvbnMnO1xuXG5leHBvcnQgY29uc3QgaW5pdGlhbFN0YXRlOiBDYWNoZVN0YXRlID0ge1xuICBrZXlzOiB7fSxcbn07XG5cbmV4cG9ydCBjb25zdCBjYWNoZVJlZHVjZXIgPSBjcmVhdGVSZWR1Y2VyKFxuICBpbml0aWFsU3RhdGUsXG4gIG9uKENhY2hlQWN0aW9ucy5jYWNoZSwgKHN0YXRlLCB7IGtleSwgdmFsdWUsIGRhdGUsIG1heENhY2hlU2l6ZSB9KSA9PlxuICAgIHNldENhY2hlVmFsdWUoXG4gICAgICBoYXNoS2V5KGtleSksXG4gICAgICB7IHZhbHVlLCBkYXRlLCBpbnZhbGlkOiBmYWxzZSB9LFxuICAgICAgc3RhdGUsXG4gICAgICBtYXhDYWNoZVNpemVcbiAgICApXG4gICksXG4gIG9uKENhY2hlQWN0aW9ucy5pbnZhbGlkYXRlQ2FjaGUsIChzdGF0ZSwgeyBrZXkgfSkgPT4ge1xuICAgIGNvbnN0IGsgPSBoYXNoS2V5KGtleSk7XG4gICAgcmV0dXJuIGludmFsaWRhdGVDYWNoZShrLCBzdGF0ZSk7XG4gIH0pLFxuICBvbihDYWNoZUFjdGlvbnMuZGVsZXRlQ2FjaGUsIChzdGF0ZSwgeyBrZXkgfSkgPT4ge1xuICAgIGNvbnN0IGsgPSBoYXNoS2V5KGtleSk7XG4gICAgcmV0dXJuIGRlbGV0ZUNhY2hlVmFsdWUoaywgc3RhdGUpO1xuICB9KSxcbiAgb24oQ2FjaGVBY3Rpb25zLmhpdENhY2hlLCAoc3RhdGUsIHsga2V5IH0pID0+IHtcbiAgICBjb25zdCBrID0gaGFzaEtleShrZXkpO1xuICAgIHJldHVybiBpbmNyZWFzZUNhY2hlSGl0Q291bnQoaywgc3RhdGUpO1xuICB9KVxuKTtcblxuZnVuY3Rpb24gc2V0Q2FjaGVWYWx1ZShcbiAga2V5czogc3RyaW5nW10sXG4gIHZhbHVlOiBPbWl0PENhY2hlRGF0YSwgJ2hpdENvdW50Jz4sXG4gIHN0YXRlOiBDYWNoZVN0YXRlLFxuICBtYXhDYWNoZVNpemU/OiBudW1iZXIsXG4gIGV4cGlyZXM/OiBudW1iZXJcbikge1xuICBjb25zdCBuZXdTdGF0ZSA9IHsgLi4uc3RhdGUgfTtcbiAgbGV0IGNhY2hlID0gbmV3U3RhdGU7XG4gIGxldCBsYXN0Q2FjaGU6IENhY2hlS2V5cyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3Qga2V5ID0ga2V5c1tpXTtcbiAgICBjYWNoZS5rZXlzID0gY2FjaGU/LmtleXMgPyB7IC4uLmNhY2hlPy5rZXlzIH0gOiB7fTtcbiAgICBsZXQgdiA9IGNhY2hlLmtleXNba2V5XTtcbiAgICB2ID0gdiA/IHsgLi4udiB9IDoge307XG4gICAgY2FjaGUua2V5c1trZXldID0gdjtcbiAgICBsYXN0Q2FjaGUgPSBjYWNoZTtcbiAgICBjYWNoZSA9IHY7XG4gIH1cbiAgY2FjaGUuZGF0YSA9IGNhY2hlLmRhdGFcbiAgICA/IHsgLi4udmFsdWUsIGhpdENvdW50OiBjYWNoZS5kYXRhLmhpdENvdW50ICsgMSB9XG4gICAgOiB7IC4uLnZhbHVlLCBoaXRDb3VudDogMSB9O1xuXG4gIGlmIChcbiAgICBtYXhDYWNoZVNpemUgJiZcbiAgICBsYXN0Q2FjaGU/LmtleXMgJiZcbiAgICBPYmplY3Qua2V5cyhsYXN0Q2FjaGUua2V5cykubGVuZ3RoID4gbWF4Q2FjaGVTaXplXG4gICkge1xuICAgIGNvbnN0IGVudHJpZXMgPSBmaW5kTGVzc0hpdE9yT2xkZXN0Q2FjaGVFbnRyaWVzKFxuICAgICAgbGFzdENhY2hlLFxuICAgICAgZXhwaXJlcyA/PyBJbmZpbml0eSxcbiAgICAgIG1heENhY2hlU2l6ZVxuICAgICk7XG4gICAgaWYgKGVudHJpZXMgJiYgZW50cmllcy5sZW5ndGgpIHtcbiAgICAgIGZvciAoY29uc3QgW2tleV0gb2YgZW50cmllcykge1xuICAgICAgICBkZWxldGUgbGFzdENhY2hlLmtleXNba2V5XTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIG5ld1N0YXRlO1xufVxuXG5mdW5jdGlvbiBmaW5kTGVzc0hpdE9yT2xkZXN0Q2FjaGVFbnRyaWVzKFxuICBzdGF0ZTogQ2FjaGVLZXlzLFxuICBleHBpcmVzOiBudW1iZXIsXG4gIG1heENhY2hlU2l6ZTogbnVtYmVyXG4pIHtcbiAgaWYgKCFzdGF0ZS5rZXlzKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBlbnRyaWVzID0gT2JqZWN0LmVudHJpZXMoc3RhdGUua2V5cyk7XG4gIC8vIGZpbmQgdGhlIG5ld2VzdCBrZXk7XG4gIGNvbnN0IFtuZXdlc3RLZXldID0gZW50cmllcy5yZWR1Y2UoKGEsIGIpID0+IHtcbiAgICBjb25zdCBhRGF0ZSA9IGFbMV0uZGF0YT8uZGF0ZSA/PyAwO1xuICAgIGNvbnN0IGJEYXRlID0gYlsxXS5kYXRhPy5kYXRlID8/IDA7XG4gICAgcmV0dXJuIGFEYXRlID4gYkRhdGUgPyBhIDogYjtcbiAgfSk7XG4gIGNvbnN0IHNvcnRlZCA9IGVudHJpZXMuc29ydCgoW2FLZXksIGFWYWx1ZV0sIFtiS2V5LCBiVmFsdWVdKSA9PiB7XG4gICAgLy8gZW5zdXJlcyB0aGUgbmV3ZXN0IGtleSBhbHdheXMgd2luc1xuICAgIGlmIChhS2V5ID09PSBuZXdlc3RLZXkpIHJldHVybiAtMTtcbiAgICBpZiAoYktleSA9PT0gbmV3ZXN0S2V5KSByZXR1cm4gMTtcbiAgICBjb25zdCBhVmFsaWQgPSBhVmFsdWUuZGF0YSAmJiBpc0NhY2hlVmFsaWQoYVZhbHVlLmRhdGEsIGV4cGlyZXMpID8gMSA6IDA7XG4gICAgY29uc3QgYlZhbGlkID0gYlZhbHVlLmRhdGEgJiYgaXNDYWNoZVZhbGlkKGJWYWx1ZS5kYXRhLCBleHBpcmVzKSA/IDEgOiAwO1xuICAgIGNvbnN0IGRpZmZWYWxpZCA9IGFWYWxpZCAtIGJWYWxpZDtcbiAgICBjb25zdCBkaWZmSGl0ID0gKGFWYWx1ZS5kYXRhPy5oaXRDb3VudCA/PyAwKSAtIChiVmFsdWUuZGF0YT8uaGl0Q291bnQgPz8gMCk7XG4gICAgY29uc3QgZGlmZkRhdGUgPSAoYVZhbHVlLmRhdGE/LmRhdGUgPz8gMCkgLSAoYlZhbHVlLmRhdGE/LmRhdGUgPz8gMCk7XG4gICAgcmV0dXJuIChcbiAgICAgIC0xICogKGRpZmZWYWxpZCA9PT0gMCA/IChkaWZmSGl0ID09PSAwID8gZGlmZkRhdGUgOiBkaWZmSGl0KSA6IGRpZmZWYWxpZClcbiAgICApO1xuICB9KTtcbiAgcmV0dXJuIHNvcnRlZC5zbGljZShtYXhDYWNoZVNpemUpO1xufVxuXG5mdW5jdGlvbiBkZWxldGVDYWNoZVZhbHVlKGtleXM6IHN0cmluZ1tdLCBzdGF0ZTogQ2FjaGVTdGF0ZSkge1xuICBjb25zdCBuZXdTdGF0ZSA9IHsgLi4uc3RhdGUgfTtcbiAgbGV0IGNhY2hlID0gbmV3U3RhdGU7XG4gIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHtcbiAgICBpZiAoIWNhY2hlLmtleXMpIHJldHVybiBzdGF0ZTtcbiAgICBjYWNoZS5rZXlzID0geyAuLi5jYWNoZT8ua2V5cyB9O1xuICAgIGxldCB2ID0gY2FjaGUua2V5c1trZXldO1xuICAgIGlmICghdikgcmV0dXJuIHN0YXRlO1xuICAgIHYgPSB7IC4uLnYgfTtcbiAgICBjYWNoZS5rZXlzW2tleV0gPSB2O1xuICAgIGNhY2hlID0gdjtcbiAgfVxuICBpZiAoY2FjaGUuZGF0YSkgZGVsZXRlIGNhY2hlLmRhdGE7XG4gIGVsc2UgaWYgKGNhY2hlLmtleXMpIGRlbGV0ZSBjYWNoZS5rZXlzO1xuICByZXR1cm4gbmV3U3RhdGU7XG59XG5cbmZ1bmN0aW9uIGludmFsaWRhdGVDYWNoZShrZXlzOiBzdHJpbmdbXSwgc3RhdGU6IENhY2hlU3RhdGUpIHtcbiAgY29uc3QgbmV3U3RhdGUgPSB7IC4uLnN0YXRlIH07XG4gIGxldCBjYWNoZSA9IG5ld1N0YXRlO1xuICBmb3IgKGNvbnN0IGtleSBvZiBrZXlzKSB7XG4gICAgaWYgKCFjYWNoZT8ua2V5cykgcmV0dXJuIHN0YXRlO1xuICAgIGNhY2hlLmtleXMgPSB7IC4uLmNhY2hlPy5rZXlzIH07XG4gICAgbGV0IHYgPSBjYWNoZT8ua2V5cz8uW2tleV07XG4gICAgaWYgKCF2KSByZXR1cm4gc3RhdGU7XG4gICAgdiA9IHsgLi4udiB9O1xuICAgIGNhY2hlLmtleXNba2V5XSA9IHY7XG4gICAgY2FjaGUgPSB2O1xuICB9XG4gIGNhY2hlICYmIGludmFsaWRhU3ViS2V5cyhjYWNoZSk7XG4gIHJldHVybiBuZXdTdGF0ZTtcbn1cblxuZnVuY3Rpb24gaW5jcmVhc2VDYWNoZUhpdENvdW50KGtleXM6IHN0cmluZ1tdLCBzdGF0ZTogQ2FjaGVTdGF0ZSkge1xuICBjb25zdCBuZXdTdGF0ZSA9IHsgLi4uc3RhdGUgfTtcbiAgbGV0IGNhY2hlID0gbmV3U3RhdGU7XG4gIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHtcbiAgICBpZiAoIWNhY2hlPy5rZXlzKSByZXR1cm4gc3RhdGU7XG4gICAgY2FjaGUua2V5cyA9IHsgLi4uY2FjaGU/LmtleXMgfTtcbiAgICBsZXQgdiA9IGNhY2hlPy5rZXlzPy5ba2V5XTtcbiAgICBpZiAoIXYpIHJldHVybiBzdGF0ZTtcbiAgICB2ID0geyAuLi52IH07XG4gICAgY2FjaGUua2V5c1trZXldID0gdjtcbiAgICBjYWNoZSA9IHY7XG4gIH1cbiAgaWYgKCFjYWNoZS5kYXRhKSByZXR1cm4gc3RhdGU7XG4gIGNhY2hlLmRhdGEgPSB7IC4uLmNhY2hlLmRhdGEsIGhpdENvdW50OiBjYWNoZS5kYXRhLmhpdENvdW50ICsgMSB9O1xuICByZXR1cm4gbmV3U3RhdGU7XG59XG5cbmZ1bmN0aW9uIGludmFsaWRhU3ViS2V5cyhzdGF0ZTogQ2FjaGVLZXlzKSB7XG4gIGlmIChzdGF0ZS5kYXRhKSB7XG4gICAgc3RhdGUuZGF0YSA9IHsgLi4uc3RhdGUuZGF0YSwgaW52YWxpZDogdHJ1ZSB9O1xuICB9XG4gIGlmIChzdGF0ZS5rZXlzKSB7XG4gICAgc3RhdGUua2V5cyA9IHsgLi4uc3RhdGUua2V5cyB9O1xuICAgIGZvciAoY29uc3Qga2V5IGluIHN0YXRlLmtleXMpIHtcbiAgICAgIHN0YXRlLmtleXNba2V5XSA9IGludmFsaWRhU3ViS2V5cyh7IC4uLnN0YXRlLmtleXNba2V5XSB9KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHN0YXRlO1xufVxuIl19
@@ -0,0 +1,5 @@
1
+ import { createFeatureSelector, createSelector } from '@ngrx/store';
2
+ import { getCacheValue, hashKey } from './cache.models';
3
+ export const cacheStateSelector = createFeatureSelector('cache');
4
+ export const selectCache = (key) => createSelector(cacheStateSelector, (state) => getCacheValue(hashKey(key), state));
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuc2VsZWN0b3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9uZ3J4LXRyYWl0cy9jb3JlL3NyYy9saWIvY2FjaGUvY2FjaGUuc2VsZWN0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxjQUFjLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDcEUsT0FBTyxFQUF3QixhQUFhLEVBQUUsT0FBTyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFOUUsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcscUJBQXFCLENBQWEsT0FBTyxDQUFDLENBQUM7QUFFN0UsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLENBQUMsR0FBYSxFQUFFLEVBQUUsQ0FDM0MsY0FBYyxDQUFDLGtCQUFrQixFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDM0MsYUFBYSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FDbkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZUZlYXR1cmVTZWxlY3RvciwgY3JlYXRlU2VsZWN0b3IgfSBmcm9tICdAbmdyeC9zdG9yZSc7XG5pbXBvcnQgeyBDYWNoZUtleSwgQ2FjaGVTdGF0ZSwgZ2V0Q2FjaGVWYWx1ZSwgaGFzaEtleSB9IGZyb20gJy4vY2FjaGUubW9kZWxzJztcblxuZXhwb3J0IGNvbnN0IGNhY2hlU3RhdGVTZWxlY3RvciA9IGNyZWF0ZUZlYXR1cmVTZWxlY3RvcjxDYWNoZVN0YXRlPignY2FjaGUnKTtcblxuZXhwb3J0IGNvbnN0IHNlbGVjdENhY2hlID0gKGtleTogQ2FjaGVLZXkpID0+XG4gIGNyZWF0ZVNlbGVjdG9yKGNhY2hlU3RhdGVTZWxlY3RvciwgKHN0YXRlKSA9PlxuICAgIGdldENhY2hlVmFsdWUoaGFzaEtleShrZXkpLCBzdGF0ZSlcbiAgKTtcbiJdfQ==
@@ -0,0 +1,72 @@
1
+ import { of } from 'rxjs';
2
+ import { isCacheValid } from './cache.models';
3
+ import { selectCache } from './cache.selectors';
4
+ import { concatMap, first, tap } from 'rxjs/operators';
5
+ import * as CacheActions from './cache.actions';
6
+ /**
7
+ * Cache the result of source parameter using the provided key, when call
8
+ * again if the cache is valid (exist and is not expired or invalidated)
9
+ * it will return the cache value without calling again source
10
+ * @example
11
+ * // cache for 3 min
12
+ * loadStores$ = createEffect(() => {
13
+ * return this.actions$.pipe(
14
+ * ofType(ProductStoreActions.loadStores),
15
+ * exhaustMap(() =>
16
+ * cache({
17
+ * key: ['stores'],
18
+ * store: this.store,
19
+ * source: this.storeService.getStores(),
20
+ * expire: 1000 * 60 * 3 // optional param , cache forever if not present
21
+ * }).pipe(
22
+ * map((res) => ProductStoreActions.loadStoresSuccess({ entities: res })),
23
+ * catchError(() => of(ProductStoreActions.loadStoresFail()))
24
+ * )
25
+ * )
26
+ * );
27
+ * });
28
+ * // cache top 10, for 3 mins
29
+ * loadDepartments$ = createEffect(() => {
30
+ * return this.actions$.pipe(
31
+ * ofType(this.localActions.loadDepartments),
32
+ * concatLatestFrom(() =>
33
+ * this.store.select(this.localSelectors.selectDepartmentsFilter)
34
+ * ),
35
+ * exhaustMap(([_, filters]) =>
36
+ * cache({
37
+ * key: ['stores','departments',{ storeId: filters!.storeId },
38
+ * store: this.store,
39
+ * source: this.storeService.getStoreDepartments(filters!.storeId),
40
+ * expires: 1000 * 60 * 3,
41
+ * maxCacheSize: 10,
42
+ * }).pipe(
43
+ * map((res) =>
44
+ * this.localActions.loadDepartmentsSuccess({
45
+ * entities: res,
46
+ * })
47
+ * ),
48
+ * catchError(() => of(this.localActions.loadDepartmentsFail()))
49
+ * )
50
+ * )
51
+ * );
52
+ * });
53
+ *
54
+ * @param options - configuration
55
+ * @param options.store - required ngrx store
56
+ * @param options.key - key can be string, array of string or array of string with plain objects
57
+ * @param options.source - called when cache is invalid
58
+ * @param options.expires - time to expire the cache valued, if not present is infinite
59
+ * @param options.maxCacheSize - max number of keys to store , only works if last key is variable
60
+ */
61
+ export function cache({ store, key, source, expires, maxCacheSize, skip, }) {
62
+ const exp = expires ?? Infinity;
63
+ return store.select(selectCache(key)).pipe(first(), concatMap((cache) => cache && !skip && isCacheValid(cache, exp)
64
+ ? of(cache.value).pipe(tap(() => store.dispatch(CacheActions.hitCache({ key }))))
65
+ : source.pipe(tap((value) => store.dispatch(CacheActions.cache({
66
+ key,
67
+ date: Date.now(),
68
+ value,
69
+ maxCacheSize,
70
+ }))))));
71
+ }
72
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvbmdyeC10cmFpdHMvY29yZS9zcmMvbGliL2NhY2hlL2NhY2hlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFjLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0QyxPQUFPLEVBQXVCLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2RCxPQUFPLEtBQUssWUFBWSxNQUFNLGlCQUFpQixDQUFDO0FBRWhEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzREc7QUFDSCxNQUFNLFVBQVUsS0FBSyxDQUFJLEVBQ3ZCLEtBQUssRUFDTCxHQUFHLEVBQ0gsTUFBTSxFQUNOLE9BQU8sRUFDUCxZQUFZLEVBQ1osSUFBSSxHQVFMO0lBQ0MsTUFBTSxHQUFHLEdBQUcsT0FBTyxJQUFJLFFBQVEsQ0FBQztJQUNoQyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUN4QyxLQUFLLEVBQUUsRUFDUCxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUNsQixLQUFLLElBQUksQ0FBQyxJQUFJLElBQUksWUFBWSxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUM7UUFDeEMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUNsQixHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQzFEO1FBQ0gsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ1QsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDWixLQUFLLENBQUMsUUFBUSxDQUNaLFlBQVksQ0FBQyxLQUFLLENBQUM7WUFDakIsR0FBRztZQUNILElBQUksRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO1lBQ2hCLEtBQUs7WUFDTCxZQUFZO1NBQ2IsQ0FBQyxDQUNILENBQ0YsQ0FDRixDQUNOLENBQ0YsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdG9yZSB9IGZyb20gJ0BuZ3J4L3N0b3JlJztcbmltcG9ydCB7IE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBDYWNoZURhdGEsIENhY2hlS2V5LCBpc0NhY2hlVmFsaWQgfSBmcm9tICcuL2NhY2hlLm1vZGVscyc7XG5pbXBvcnQgeyBzZWxlY3RDYWNoZSB9IGZyb20gJy4vY2FjaGUuc2VsZWN0b3JzJztcbmltcG9ydCB7IGNvbmNhdE1hcCwgZmlyc3QsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCAqIGFzIENhY2hlQWN0aW9ucyBmcm9tICcuL2NhY2hlLmFjdGlvbnMnO1xuXG4vKipcbiAqIENhY2hlIHRoZSByZXN1bHQgb2Ygc291cmNlIHBhcmFtZXRlciB1c2luZyB0aGUgcHJvdmlkZWQga2V5LCB3aGVuIGNhbGxcbiAqIGFnYWluIGlmIHRoZSBjYWNoZSBpcyB2YWxpZCAoZXhpc3QgYW5kIGlzIG5vdCBleHBpcmVkIG9yIGludmFsaWRhdGVkKVxuICogaXQgd2lsbCByZXR1cm4gdGhlIGNhY2hlIHZhbHVlIHdpdGhvdXQgY2FsbGluZyBhZ2FpbiBzb3VyY2VcbiAqIEBleGFtcGxlXG4gKiAvLyBjYWNoZSBmb3IgMyBtaW5cbiAqIGxvYWRTdG9yZXMkID0gY3JlYXRlRWZmZWN0KCgpID0+IHtcbiAqICAgcmV0dXJuIHRoaXMuYWN0aW9ucyQucGlwZShcbiAqICAgICBvZlR5cGUoUHJvZHVjdFN0b3JlQWN0aW9ucy5sb2FkU3RvcmVzKSxcbiAqICAgICBleGhhdXN0TWFwKCgpID0+XG4gKiAgICAgICBjYWNoZSh7XG4gKiAgICAgICAgIGtleTogWydzdG9yZXMnXSxcbiAqICAgICAgICAgc3RvcmU6IHRoaXMuc3RvcmUsXG4gKiAgICAgICAgIHNvdXJjZTogdGhpcy5zdG9yZVNlcnZpY2UuZ2V0U3RvcmVzKCksXG4gKiAgICAgICAgIGV4cGlyZTogMTAwMCAqIDYwICogMyAvLyBvcHRpb25hbCBwYXJhbSAsIGNhY2hlIGZvcmV2ZXIgaWYgbm90IHByZXNlbnRcbiAqICAgICAgIH0pLnBpcGUoXG4gKiAgICAgICAgIG1hcCgocmVzKSA9PiBQcm9kdWN0U3RvcmVBY3Rpb25zLmxvYWRTdG9yZXNTdWNjZXNzKHsgZW50aXRpZXM6IHJlcyB9KSksXG4gKiAgICAgICAgIGNhdGNoRXJyb3IoKCkgPT4gb2YoUHJvZHVjdFN0b3JlQWN0aW9ucy5sb2FkU3RvcmVzRmFpbCgpKSlcbiAqICAgICAgIClcbiAqICAgICApXG4gKiAgICk7XG4gKiB9KTtcbiAqIC8vIGNhY2hlIHRvcCAxMCwgZm9yIDMgbWluc1xuICogICBsb2FkRGVwYXJ0bWVudHMkID0gY3JlYXRlRWZmZWN0KCgpID0+IHtcbiAqICAgcmV0dXJuIHRoaXMuYWN0aW9ucyQucGlwZShcbiAqICAgICBvZlR5cGUodGhpcy5sb2NhbEFjdGlvbnMubG9hZERlcGFydG1lbnRzKSxcbiAqICAgICBjb25jYXRMYXRlc3RGcm9tKCgpID0+XG4gKiAgICAgICB0aGlzLnN0b3JlLnNlbGVjdCh0aGlzLmxvY2FsU2VsZWN0b3JzLnNlbGVjdERlcGFydG1lbnRzRmlsdGVyKVxuICogICAgICksXG4gKiAgICAgZXhoYXVzdE1hcCgoW18sIGZpbHRlcnNdKSA9PlxuICogICAgICAgY2FjaGUoe1xuICogICAgICAgICBrZXk6IFsnc3RvcmVzJywnZGVwYXJ0bWVudHMnLHsgc3RvcmVJZDogZmlsdGVycyEuc3RvcmVJZCB9LFxuICogICAgICAgICBzdG9yZTogdGhpcy5zdG9yZSxcbiAqICAgICAgICAgc291cmNlOiB0aGlzLnN0b3JlU2VydmljZS5nZXRTdG9yZURlcGFydG1lbnRzKGZpbHRlcnMhLnN0b3JlSWQpLFxuICogICAgICAgICBleHBpcmVzOiAxMDAwICogNjAgKiAzLFxuICogICAgICAgICBtYXhDYWNoZVNpemU6IDEwLFxuICogICAgICAgfSkucGlwZShcbiAqICAgICAgICAgbWFwKChyZXMpID0+XG4gKiAgICAgICAgICAgdGhpcy5sb2NhbEFjdGlvbnMubG9hZERlcGFydG1lbnRzU3VjY2Vzcyh7XG4gKiAgICAgICAgICAgICBlbnRpdGllczogcmVzLFxuICogICAgICAgICAgIH0pXG4gKiAgICAgICAgICksXG4gKiAgICAgICAgIGNhdGNoRXJyb3IoKCkgPT4gb2YodGhpcy5sb2NhbEFjdGlvbnMubG9hZERlcGFydG1lbnRzRmFpbCgpKSlcbiAqICAgICAgIClcbiAqICAgICApXG4gKiAgICk7XG4gKiB9KTtcbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSBvcHRpb25zLnN0b3JlIC0gcmVxdWlyZWQgbmdyeCBzdG9yZVxuICogQHBhcmFtIG9wdGlvbnMua2V5IC0ga2V5IGNhbiBiZSBzdHJpbmcsIGFycmF5IG9mIHN0cmluZyBvciBhcnJheSBvZiBzdHJpbmcgd2l0aCBwbGFpbiBvYmplY3RzXG4gKiBAcGFyYW0gb3B0aW9ucy5zb3VyY2UgLSBjYWxsZWQgd2hlbiBjYWNoZSBpcyBpbnZhbGlkXG4gKiBAcGFyYW0gb3B0aW9ucy5leHBpcmVzIC0gdGltZSB0byBleHBpcmUgdGhlIGNhY2hlIHZhbHVlZCwgaWYgbm90IHByZXNlbnQgaXMgaW5maW5pdGVcbiAqIEBwYXJhbSBvcHRpb25zLm1heENhY2hlU2l6ZSAtIG1heCBudW1iZXIgb2Yga2V5cyB0byBzdG9yZSAsIG9ubHkgd29ya3MgaWYgbGFzdCBrZXkgaXMgdmFyaWFibGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhY2hlPFQ+KHtcbiAgc3RvcmUsXG4gIGtleSxcbiAgc291cmNlLFxuICBleHBpcmVzLFxuICBtYXhDYWNoZVNpemUsXG4gIHNraXAsXG59OiB7XG4gIHN0b3JlOiBTdG9yZTtcbiAga2V5OiBDYWNoZUtleTtcbiAgc291cmNlOiBPYnNlcnZhYmxlPFQ+O1xuICBleHBpcmVzPzogbnVtYmVyO1xuICBtYXhDYWNoZVNpemU/OiBudW1iZXI7XG4gIHNraXA/OiBib29sZWFuO1xufSkge1xuICBjb25zdCBleHAgPSBleHBpcmVzID8/IEluZmluaXR5O1xuICByZXR1cm4gc3RvcmUuc2VsZWN0KHNlbGVjdENhY2hlKGtleSkpLnBpcGUoXG4gICAgZmlyc3QoKSxcbiAgICBjb25jYXRNYXAoKGNhY2hlKSA9PlxuICAgICAgY2FjaGUgJiYgIXNraXAgJiYgaXNDYWNoZVZhbGlkKGNhY2hlLCBleHApXG4gICAgICAgID8gb2YoY2FjaGUudmFsdWUpLnBpcGUoXG4gICAgICAgICAgICB0YXAoKCkgPT4gc3RvcmUuZGlzcGF0Y2goQ2FjaGVBY3Rpb25zLmhpdENhY2hlKHsga2V5IH0pKSlcbiAgICAgICAgICApXG4gICAgICAgIDogc291cmNlLnBpcGUoXG4gICAgICAgICAgICB0YXAoKHZhbHVlKSA9PlxuICAgICAgICAgICAgICBzdG9yZS5kaXNwYXRjaChcbiAgICAgICAgICAgICAgICBDYWNoZUFjdGlvbnMuY2FjaGUoe1xuICAgICAgICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgICAgICAgZGF0ZTogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICAgIHZhbHVlLFxuICAgICAgICAgICAgICAgICAgbWF4Q2FjaGVTaXplLFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIClcbiAgICAgICAgICApXG4gICAgKVxuICApO1xufVxuIl19
@@ -0,0 +1,7 @@
1
+ export * from './cache.service';
2
+ export * from './cache.module';
3
+ import { invalidateCache, deleteCache } from './cache.actions';
4
+ import { selectCache } from './cache.selectors';
5
+ export const CacheActions = { invalidateCache, deleteCache };
6
+ export const CacheSelectors = { getCache: selectCache };
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL25ncngtdHJhaXRzL2NvcmUvc3JjL2xpYi9jYWNoZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsT0FBTyxFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDaEQsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLEVBQUUsZUFBZSxFQUFFLFdBQVcsRUFBRSxDQUFDO0FBQzdELE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vY2FjaGUuc2VydmljZSc7XG5leHBvcnQgKiBmcm9tICcuL2NhY2hlLm1vZHVsZSc7XG5pbXBvcnQgeyBpbnZhbGlkYXRlQ2FjaGUsIGRlbGV0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5hY3Rpb25zJztcbmltcG9ydCB7IHNlbGVjdENhY2hlIH0gZnJvbSAnLi9jYWNoZS5zZWxlY3RvcnMnO1xuZXhwb3J0IGNvbnN0IENhY2hlQWN0aW9ucyA9IHsgaW52YWxpZGF0ZUNhY2hlLCBkZWxldGVDYWNoZSB9O1xuZXhwb3J0IGNvbnN0IENhY2hlU2VsZWN0b3JzID0geyBnZXRDYWNoZTogc2VsZWN0Q2FjaGUgfTtcbiJdfQ==