@angular-architects/ngrx-toolkit 20.0.2 → 20.0.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.
Files changed (84) hide show
  1. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs +119 -0
  2. package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs.map +1 -0
  3. package/fesm2022/angular-architects-ngrx-toolkit.mjs +1789 -0
  4. package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +1 -0
  5. package/index.d.ts +945 -0
  6. package/package.json +21 -4
  7. package/redux-connector/index.d.ts +59 -0
  8. package/eslint.config.cjs +0 -43
  9. package/jest.config.ts +0 -22
  10. package/ng-package.json +0 -7
  11. package/project.json +0 -37
  12. package/redux-connector/docs/README.md +0 -131
  13. package/redux-connector/index.ts +0 -6
  14. package/redux-connector/ng-package.json +0 -5
  15. package/redux-connector/src/lib/create-redux.ts +0 -102
  16. package/redux-connector/src/lib/model.ts +0 -89
  17. package/redux-connector/src/lib/rxjs-interop/redux-method.ts +0 -66
  18. package/redux-connector/src/lib/signal-redux-store.ts +0 -59
  19. package/redux-connector/src/lib/util.ts +0 -22
  20. package/src/index.ts +0 -43
  21. package/src/lib/assertions/assertions.ts +0 -9
  22. package/src/lib/devtools/features/with-disabled-name-indicies.ts +0 -31
  23. package/src/lib/devtools/features/with-glitch-tracking.ts +0 -35
  24. package/src/lib/devtools/features/with-mapper.ts +0 -34
  25. package/src/lib/devtools/internal/current-action-names.ts +0 -1
  26. package/src/lib/devtools/internal/default-tracker.ts +0 -60
  27. package/src/lib/devtools/internal/devtools-feature.ts +0 -37
  28. package/src/lib/devtools/internal/devtools-syncer.service.ts +0 -202
  29. package/src/lib/devtools/internal/glitch-tracker.service.ts +0 -61
  30. package/src/lib/devtools/internal/models.ts +0 -29
  31. package/src/lib/devtools/provide-devtools-config.ts +0 -32
  32. package/src/lib/devtools/rename-devtools-name.ts +0 -21
  33. package/src/lib/devtools/tests/action-name.spec.ts +0 -48
  34. package/src/lib/devtools/tests/basic.spec.ts +0 -111
  35. package/src/lib/devtools/tests/connecting.spec.ts +0 -37
  36. package/src/lib/devtools/tests/helpers.spec.ts +0 -43
  37. package/src/lib/devtools/tests/naming.spec.ts +0 -216
  38. package/src/lib/devtools/tests/provide-devtools-config.spec.ts +0 -25
  39. package/src/lib/devtools/tests/types.spec.ts +0 -19
  40. package/src/lib/devtools/tests/update-state.spec.ts +0 -29
  41. package/src/lib/devtools/tests/with-devtools.spec.ts +0 -5
  42. package/src/lib/devtools/tests/with-glitch-tracking.spec.ts +0 -272
  43. package/src/lib/devtools/tests/with-mapper.spec.ts +0 -69
  44. package/src/lib/devtools/update-state.ts +0 -38
  45. package/src/lib/devtools/with-dev-tools-stub.ts +0 -6
  46. package/src/lib/devtools/with-devtools.ts +0 -81
  47. package/src/lib/immutable-state/deep-freeze.ts +0 -43
  48. package/src/lib/immutable-state/is-dev-mode.ts +0 -6
  49. package/src/lib/immutable-state/tests/with-immutable-state.spec.ts +0 -278
  50. package/src/lib/immutable-state/with-immutable-state.ts +0 -150
  51. package/src/lib/shared/prettify.ts +0 -3
  52. package/src/lib/shared/signal-store-models.ts +0 -30
  53. package/src/lib/shared/throw-if-null.ts +0 -7
  54. package/src/lib/storage-sync/features/with-indexed-db.ts +0 -81
  55. package/src/lib/storage-sync/features/with-local-storage.ts +0 -58
  56. package/src/lib/storage-sync/internal/indexeddb.service.ts +0 -124
  57. package/src/lib/storage-sync/internal/local-storage.service.ts +0 -19
  58. package/src/lib/storage-sync/internal/models.ts +0 -62
  59. package/src/lib/storage-sync/internal/session-storage.service.ts +0 -18
  60. package/src/lib/storage-sync/tests/indexeddb.service.spec.ts +0 -99
  61. package/src/lib/storage-sync/tests/with-storage-async.spec.ts +0 -305
  62. package/src/lib/storage-sync/tests/with-storage-sync.spec.ts +0 -273
  63. package/src/lib/storage-sync/with-storage-sync.ts +0 -236
  64. package/src/lib/with-call-state.spec.ts +0 -42
  65. package/src/lib/with-call-state.ts +0 -195
  66. package/src/lib/with-conditional.spec.ts +0 -125
  67. package/src/lib/with-conditional.ts +0 -74
  68. package/src/lib/with-data-service.spec.ts +0 -564
  69. package/src/lib/with-data-service.ts +0 -433
  70. package/src/lib/with-feature-factory.spec.ts +0 -69
  71. package/src/lib/with-feature-factory.ts +0 -56
  72. package/src/lib/with-pagination.spec.ts +0 -135
  73. package/src/lib/with-pagination.ts +0 -373
  74. package/src/lib/with-redux.spec.ts +0 -258
  75. package/src/lib/with-redux.ts +0 -387
  76. package/src/lib/with-reset.spec.ts +0 -112
  77. package/src/lib/with-reset.ts +0 -62
  78. package/src/lib/with-undo-redo.spec.ts +0 -274
  79. package/src/lib/with-undo-redo.ts +0 -200
  80. package/src/test-setup.ts +0 -6
  81. package/tsconfig.json +0 -29
  82. package/tsconfig.lib.json +0 -17
  83. package/tsconfig.lib.prod.json +0 -9
  84. package/tsconfig.spec.json +0 -17
@@ -1,273 +0,0 @@
1
- import { TestBed } from '@angular/core/testing';
2
- import { getState, patchState, signalStore, withState } from '@ngrx/signals';
3
- import { withLocalStorage } from '../features/with-local-storage';
4
- import { withStorageSync } from '../with-storage-sync';
5
-
6
- interface StateObject {
7
- foo: string;
8
- age: number;
9
- }
10
-
11
- const initialState: StateObject = {
12
- foo: 'bar',
13
- age: 18,
14
- };
15
- const key = 'FooBar';
16
-
17
- describe('withStorageSync (sync storage)', () => {
18
- beforeEach(() => {
19
- // make sure to start with a clean storage
20
- localStorage.removeItem(key);
21
- });
22
-
23
- it('adds methods for storage access to the store', () => {
24
- TestBed.runInInjectionContext(() => {
25
- const Store = signalStore(withStorageSync({ key }));
26
- const store = new Store();
27
-
28
- expect(Object.keys(store)).toEqual([
29
- 'clearStorage',
30
- 'readFromStorage',
31
- 'writeToStorage',
32
- ]);
33
- });
34
- });
35
-
36
- it('offers manual sync using provided methods', () => {
37
- TestBed.runInInjectionContext(() => {
38
- // prefill storage
39
- localStorage.setItem(
40
- key,
41
- JSON.stringify({
42
- foo: 'baz',
43
- age: 99,
44
- } as StateObject),
45
- );
46
-
47
- const Store = signalStore(
48
- { protectedState: false },
49
- withState(initialState),
50
- withStorageSync({ key, autoSync: false }),
51
- );
52
- const store = new Store();
53
- expect(getState(store)).toEqual(initialState);
54
-
55
- store.readFromStorage();
56
- expect(getState(store)).toEqual({
57
- foo: 'baz',
58
- age: 99,
59
- });
60
-
61
- patchState(store, { ...initialState });
62
- TestBed.flushEffects();
63
-
64
- let storeItem = JSON.parse(localStorage.getItem(key) || '{}');
65
- expect(storeItem).toEqual({
66
- foo: 'baz',
67
- age: 99,
68
- });
69
-
70
- store.writeToStorage();
71
- storeItem = JSON.parse(localStorage.getItem(key) || '{}');
72
- expect(storeItem).toEqual({
73
- ...initialState,
74
- });
75
-
76
- store.clearStorage();
77
- storeItem = localStorage.getItem(key);
78
- expect(storeItem).toEqual(null);
79
- });
80
- });
81
-
82
- describe('autoSync', () => {
83
- it('inits from storage and write to storage on changes when set to `true`', () => {
84
- TestBed.runInInjectionContext(() => {
85
- // prefill storage
86
- localStorage.setItem(
87
- key,
88
- JSON.stringify({
89
- foo: 'baz',
90
- age: 99,
91
- } as StateObject),
92
- );
93
-
94
- const Store = signalStore(
95
- { protectedState: false },
96
- withState(initialState),
97
- withStorageSync(key),
98
- );
99
- const store = new Store();
100
- expect(getState(store)).toEqual({
101
- foo: 'baz',
102
- age: 99,
103
- });
104
-
105
- patchState(store, { ...initialState });
106
- TestBed.flushEffects();
107
-
108
- expect(getState(store)).toEqual({
109
- ...initialState,
110
- });
111
- const storeItem = JSON.parse(localStorage.getItem(key) || '{}');
112
- expect(storeItem).toEqual({
113
- ...initialState,
114
- });
115
- });
116
- });
117
-
118
- it('does not init from storage and does write to storage on changes when set to `false`', () => {
119
- TestBed.runInInjectionContext(() => {
120
- // prefill storage
121
- localStorage.setItem(
122
- key,
123
- JSON.stringify({
124
- foo: 'baz',
125
- age: 99,
126
- } as StateObject),
127
- );
128
-
129
- const Store = signalStore(
130
- { protectedState: false },
131
- withState(initialState),
132
- withStorageSync({ key, autoSync: false }),
133
- );
134
- const store = new Store();
135
- expect(getState(store)).toEqual(initialState);
136
-
137
- patchState(store, { ...initialState });
138
- const storeItem = JSON.parse(localStorage.getItem(key) || '{}');
139
- expect(storeItem).toEqual({
140
- foo: 'baz',
141
- age: 99,
142
- });
143
- });
144
- });
145
- });
146
-
147
- describe('select', () => {
148
- it('syncs the whole state by default', () => {
149
- TestBed.runInInjectionContext(() => {
150
- const Store = signalStore(
151
- { protectedState: false },
152
- withState(initialState),
153
- withStorageSync(key),
154
- );
155
- const store = new Store();
156
-
157
- patchState(store, { foo: 'baz', age: 25 });
158
-
159
- const storeItem = JSON.parse(localStorage.getItem(key) || '{}');
160
- expect(storeItem).toEqual({
161
- foo: 'baz',
162
- age: 25,
163
- });
164
- });
165
- });
166
-
167
- it('syncs selected slices when specified', () => {
168
- TestBed.runInInjectionContext(() => {
169
- const Store = signalStore(
170
- { protectedState: false },
171
- withState(initialState),
172
- withStorageSync({ key, select: ({ foo }) => ({ foo }) }),
173
- );
174
- const store = new Store();
175
-
176
- patchState(store, { foo: 'baz' });
177
- TestBed.flushEffects();
178
-
179
- const storeItem = JSON.parse(localStorage.getItem(key) || '{}');
180
- expect(storeItem).toEqual({
181
- foo: 'baz',
182
- });
183
- });
184
- });
185
- });
186
-
187
- describe('parse/stringify', () => {
188
- it('uses custom parsing/stringification when specified', () => {
189
- const parse = (stateString: string) => {
190
- const [foo, age] = stateString.split('_');
191
- return {
192
- foo,
193
- age: +age,
194
- };
195
- };
196
-
197
- TestBed.runInInjectionContext(() => {
198
- const Store = signalStore(
199
- { protectedState: false },
200
- withState(initialState),
201
- withStorageSync({
202
- key,
203
- parse,
204
- stringify: (state) => `${state.foo}_${state.age}`,
205
- }),
206
- );
207
- const store = new Store();
208
-
209
- patchState(store, { foo: 'baz' });
210
- TestBed.flushEffects();
211
-
212
- const storeItem = parse(localStorage.getItem(key) || '');
213
- expect(storeItem).toEqual({
214
- ...initialState,
215
- foo: 'baz',
216
- });
217
- });
218
- });
219
- });
220
-
221
- describe('storage factory', () => {
222
- it('should throw an error when both config and storage strategy are provided', () => {
223
- const signalStoreFactory = () =>
224
- signalStore(
225
- withStorageSync(
226
- { key: 'foo', storage: () => localStorage },
227
- withLocalStorage(),
228
- ),
229
- );
230
-
231
- expect(signalStoreFactory).toThrow(
232
- 'You can either pass a storage strategy or a config with storage, but not both.',
233
- );
234
- });
235
-
236
- it('uses specified storage', () => {
237
- TestBed.runInInjectionContext(() => {
238
- // prefill storage
239
- sessionStorage.setItem(
240
- key,
241
- JSON.stringify({
242
- foo: 'baz',
243
- age: 99,
244
- } as StateObject),
245
- );
246
-
247
- const Store = signalStore(
248
- { protectedState: false },
249
- withState(initialState),
250
- withStorageSync({ key, storage: () => sessionStorage }),
251
- );
252
- const store = new Store();
253
- expect(getState(store)).toEqual({
254
- foo: 'baz',
255
- age: 99,
256
- });
257
-
258
- patchState(store, { ...initialState });
259
- TestBed.flushEffects();
260
-
261
- expect(getState(store)).toEqual({
262
- ...initialState,
263
- });
264
- const storeItem = JSON.parse(sessionStorage.getItem(key) || '{}');
265
- expect(storeItem).toEqual({
266
- ...initialState,
267
- });
268
-
269
- store.clearStorage();
270
- });
271
- });
272
- });
273
- });
@@ -1,236 +0,0 @@
1
- import { isPlatformServer } from '@angular/common';
2
- import { computed, effect, inject, PLATFORM_ID, signal } from '@angular/core';
3
- import {
4
- EmptyFeatureResult,
5
- getState,
6
- signalStoreFeature,
7
- SignalStoreFeature,
8
- SignalStoreFeatureResult,
9
- watchState,
10
- withHooks,
11
- withMethods,
12
- withProps,
13
- } from '@ngrx/signals';
14
- import {
15
- withLocalStorage,
16
- withSessionStorage,
17
- } from './features/with-local-storage';
18
- import {
19
- AsyncFeatureResult,
20
- AsyncStorageStrategy,
21
- SYNC_STATUS,
22
- SyncFeatureResult,
23
- SyncStorageStrategy,
24
- } from './internal/models';
25
-
26
- export type SyncConfig<State> = {
27
- /**
28
- * The key which is used to access the storage.
29
- */
30
- key: string;
31
- /**
32
- * Flag indicating if the store should read from storage on init and write to storage on every state change.
33
- *
34
- * `true` by default
35
- */
36
- autoSync?: boolean;
37
- /**
38
- * Function to select that portion of the state which should be stored.
39
- *
40
- * Returns the whole state object by default
41
- */
42
- select?: (state: State) => unknown;
43
- /**
44
- * Function used to parse the state coming from storage.
45
- *
46
- * `JSON.parse()` by default
47
- */
48
- parse?: (stateString: string) => State;
49
- /**
50
- * Function used to transform the state into a string representation.
51
- *
52
- * `JSON.stringify()` by default
53
- */
54
- stringify?: (state: State) => string;
55
-
56
- /**
57
- * @deprecated Use {@link withSessionStorage} instead.
58
- * Factory function used to switch to sessionStorage.
59
- *
60
- * `localStorage` by default
61
- */
62
- storage?: () => Storage;
63
- };
64
-
65
- // only key
66
- export function withStorageSync<Input extends SignalStoreFeatureResult>(
67
- key: string,
68
- ): SignalStoreFeature<Input, SyncFeatureResult>;
69
-
70
- // key + indexeddb
71
- export function withStorageSync<Input extends SignalStoreFeatureResult>(
72
- key: string,
73
- storageStrategy: AsyncStorageStrategy<Input['state']>,
74
- ): SignalStoreFeature<Input, AsyncFeatureResult>;
75
-
76
- // key + localStorage(or sessionStorage)
77
- export function withStorageSync<Input extends SignalStoreFeatureResult>(
78
- key: string,
79
- storageStrategy: SyncStorageStrategy<Input['state']>,
80
- ): SignalStoreFeature<Input, SyncFeatureResult>;
81
-
82
- // config + localStorage
83
- export function withStorageSync<Input extends SignalStoreFeatureResult>(
84
- config: SyncConfig<Input['state']>,
85
- ): SignalStoreFeature<Input, SyncFeatureResult>;
86
-
87
- // config + indexeddb
88
- export function withStorageSync<Input extends SignalStoreFeatureResult>(
89
- config: SyncConfig<Input['state']>,
90
- storageStrategy: AsyncStorageStrategy<Input['state']>,
91
- ): SignalStoreFeature<Input, AsyncFeatureResult>;
92
-
93
- // config + localStorage(or sessionStorage)
94
- export function withStorageSync<Input extends SignalStoreFeatureResult>(
95
- config: SyncConfig<Input['state']>,
96
- storageStrategy: SyncStorageStrategy<Input['state']>,
97
- ): SignalStoreFeature<Input, SyncFeatureResult>;
98
-
99
- export function withStorageSync<Input extends SignalStoreFeatureResult>(
100
- configOrKey: SyncConfig<Input['state']> | string,
101
- storageStrategy?:
102
- | AsyncStorageStrategy<Input['state']>
103
- | SyncStorageStrategy<Input['state']>,
104
- ): SignalStoreFeature<
105
- Input,
106
- EmptyFeatureResult & (SyncFeatureResult | AsyncFeatureResult)
107
- > {
108
- if (
109
- typeof configOrKey !== 'string' &&
110
- configOrKey.storage &&
111
- storageStrategy
112
- ) {
113
- throw new Error(
114
- 'You can either pass a storage strategy or a config with storage, but not both.',
115
- );
116
- }
117
- const config: Required<SyncConfig<Input['state']>> = {
118
- autoSync: true,
119
- select: (state: Input['state']) => state,
120
- parse: JSON.parse,
121
- stringify: JSON.stringify,
122
- storage: () => localStorage,
123
- ...(typeof configOrKey === 'string' ? { key: configOrKey } : configOrKey),
124
- };
125
-
126
- const factory =
127
- storageStrategy ??
128
- (config.storage() === localStorage
129
- ? withLocalStorage()
130
- : withSessionStorage());
131
-
132
- if (factory.type === 'sync') {
133
- return createSyncStorageSync(factory, config);
134
- } else {
135
- return createAsyncStorageSync(factory, config);
136
- }
137
- }
138
-
139
- function createSyncStorageSync(
140
- factory: SyncStorageStrategy<object>,
141
- config: Required<SyncConfig<object>>,
142
- ) {
143
- return signalStoreFeature(
144
- withMethods((store, platformId = inject(PLATFORM_ID)) => {
145
- return factory(config, store, isPlatformServer(platformId));
146
- }),
147
- withHooks({
148
- onInit(store, platformId = inject(PLATFORM_ID)) {
149
- if (isPlatformServer(platformId)) {
150
- return;
151
- }
152
-
153
- if (config.autoSync) {
154
- store.readFromStorage();
155
- watchState(store, () => store.writeToStorage());
156
- }
157
- },
158
- }),
159
- ) satisfies SignalStoreFeature<EmptyFeatureResult, SyncFeatureResult>;
160
- }
161
-
162
- function createAsyncStorageSync(
163
- factory: AsyncStorageStrategy<object>,
164
- config: Required<SyncConfig<object>>,
165
- ) {
166
- return signalStoreFeature(
167
- withProps(() => {
168
- const props = {
169
- /*
170
- // we need to have that as property (and not state)
171
- // Otherwise the state watcher fires when updating the sync status
172
- */
173
- [SYNC_STATUS]: signal<'idle' | 'syncing' | 'synced'>('idle'),
174
- };
175
-
176
- const resolves = [] as (() => void)[];
177
-
178
- effect(() => {
179
- const syncStatus = props[SYNC_STATUS]();
180
- if (syncStatus === 'synced') {
181
- resolves.forEach((resolve) => resolve());
182
- resolves.splice(0, resolves.length);
183
- }
184
- });
185
-
186
- return {
187
- ...props,
188
- isSynced: computed(() => props[SYNC_STATUS]() === 'synced'),
189
- whenSynced: () =>
190
- new Promise<void>((resolve) => {
191
- if (props[SYNC_STATUS]() === 'synced') {
192
- resolve();
193
- } else {
194
- resolves.push(resolve);
195
- }
196
- }),
197
- };
198
- }),
199
- withMethods((store, platformId = inject(PLATFORM_ID)) => {
200
- return factory(config, store, isPlatformServer(platformId));
201
- }),
202
- withHooks({
203
- async onInit(store, platformId = inject(PLATFORM_ID)) {
204
- if (isPlatformServer(platformId)) {
205
- return;
206
- }
207
-
208
- const initialState = JSON.stringify(getState(store));
209
- if (config.autoSync) {
210
- let startWatching = false;
211
- watchState(store, () => {
212
- if (!startWatching) {
213
- const currentState = JSON.stringify(getState(store));
214
-
215
- // Necessary because getState returns always a new object
216
- if (currentState === initialState) {
217
- return;
218
- }
219
-
220
- console.warn(
221
- `Writing to Store (${config.key}) happened before the state was initially read from storage.`,
222
- 'Please ensure that the store is not in syncing state via `store.whenSynced()` before writing to the state.',
223
- 'Alternatively, you can disable autoSync by passing `autoSync: false` in the config.',
224
- );
225
- return;
226
- }
227
- return store.writeToStorage();
228
- });
229
-
230
- await store.readFromStorage();
231
- startWatching = true;
232
- }
233
- },
234
- }),
235
- ) satisfies SignalStoreFeature<EmptyFeatureResult, AsyncFeatureResult>;
236
- }
@@ -1,42 +0,0 @@
1
- import { patchState, signalStore } from '@ngrx/signals';
2
- import { setLoaded, setLoading, withCallState } from './with-call-state';
3
-
4
- describe('withCallState', () => {
5
- it('should use and update a callState', () => {
6
- const DataStore = signalStore({ protectedState: false }, withCallState());
7
- const dataStore = new DataStore();
8
-
9
- patchState(dataStore, setLoading());
10
-
11
- expect(dataStore.callState()).toBe('loading');
12
- expect(dataStore.loading()).toBe(true);
13
- });
14
-
15
- it('should use the callState for a collection', () => {
16
- const DataStore = signalStore(
17
- { protectedState: false },
18
- withCallState({ collection: 'entities' }),
19
- );
20
- const dataStore = new DataStore();
21
-
22
- patchState(dataStore, setLoaded('entities'));
23
-
24
- expect(dataStore.entitiesCallState()).toBe('loaded');
25
- expect(dataStore.entitiesLoaded()).toBe(true);
26
- });
27
-
28
- it('should use the callState for multiple collections with an array', () => {
29
- const DataStore = signalStore(
30
- { protectedState: false },
31
- withCallState({ collections: ['entities', 'products'] }),
32
- );
33
- const dataStore = new DataStore();
34
-
35
- patchState(dataStore, setLoaded('entities'), setLoaded('products'));
36
-
37
- expect(dataStore.entitiesCallState()).toBe('loaded');
38
- expect(dataStore.productsCallState()).toBe('loaded');
39
- expect(dataStore.entitiesLoaded()).toBe(true);
40
- expect(dataStore.productsLoaded()).toBe(true);
41
- });
42
- });