@angular-architects/ngrx-toolkit 20.0.2 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +1888 -0
  4. package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +1 -0
  5. package/index.d.ts +1084 -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-architects/ngrx-toolkit",
3
- "version": "20.0.2",
3
+ "version": "20.1.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "GitHub",
@@ -18,6 +18,23 @@
18
18
  "optional": true
19
19
  }
20
20
  },
21
- "dependencies": {},
22
- "sideEffects": false
23
- }
21
+ "dependencies": {
22
+ "tslib": "^2.3.0"
23
+ },
24
+ "sideEffects": false,
25
+ "module": "fesm2022/angular-architects-ngrx-toolkit.mjs",
26
+ "typings": "index.d.ts",
27
+ "exports": {
28
+ "./package.json": {
29
+ "default": "./package.json"
30
+ },
31
+ ".": {
32
+ "types": "./index.d.ts",
33
+ "default": "./fesm2022/angular-architects-ngrx-toolkit.mjs"
34
+ },
35
+ "./redux-connector": {
36
+ "types": "./redux-connector/index.d.ts",
37
+ "default": "./fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs"
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,59 @@
1
+ import { ActionCreator, ActionType, Prettify, Action } from '@ngrx/store/src/models';
2
+ import { Type, EnvironmentProviders, Signal, Injector } from '@angular/core';
3
+ import { DeepSignal } from '@ngrx/signals/src/deep-signal';
4
+ import { StateSignals, SignalStoreFeatureResult } from '@ngrx/signals/src/signal-store-models';
5
+ import { Observable, Unsubscribable } from 'rxjs';
6
+
7
+ type IncludePropType<T, V, WithNevers = {
8
+ [K in keyof T]: Exclude<T[K], undefined> extends V ? T[K] extends Record<string, unknown> ? IncludePropType<T[K], V> : T[K] : never;
9
+ }> = Prettify<Pick<WithNevers, {
10
+ [K in keyof WithNevers]: WithNevers[K] extends never ? never : K extends string ? K : never;
11
+ }[keyof WithNevers]>>;
12
+ type Store = Type<Record<string, unknown> & StateSignals<SignalStoreFeatureResult['state']>>;
13
+ type CreateReduxState<StoreName extends string, STORE extends Store> = {
14
+ [K in StoreName as `provide${Capitalize<K>}Store`]: (connectReduxDevtools?: boolean) => EnvironmentProviders;
15
+ } & {
16
+ [K in StoreName as `inject${Capitalize<K>}Store`]: () => InjectableReduxSlice<STORE>;
17
+ };
18
+ type Selectors<STORE extends Store> = IncludePropType<InstanceType<STORE>, Signal<unknown> | DeepSignal<unknown>>;
19
+ type Dispatch = {
20
+ dispatch: (input: Action | Observable<Action> | Signal<Action>) => Unsubscribable;
21
+ };
22
+ type InjectableReduxSlice<STORE extends Store> = Selectors<STORE> & Dispatch;
23
+ type ExtractActionTypes<Creators extends readonly ActionCreator[]> = {
24
+ [Key in keyof Creators]: Creators[Key] extends ActionCreator<infer T> ? T : never;
25
+ };
26
+ interface StoreMethod<Creators extends readonly ActionCreator[], ResultState = unknown> {
27
+ (action: ActionType<Creators[number]>): ResultState;
28
+ }
29
+ interface MapperTypes<Creators extends readonly ActionCreator[]> {
30
+ types: ExtractActionTypes<Creators>;
31
+ storeMethod: StoreMethod<Creators>;
32
+ resultMethod?: (...args: unknown[]) => unknown;
33
+ }
34
+
35
+ declare function mapAction<Creators extends readonly ActionCreator[]>(...args: [
36
+ ...creators: Creators,
37
+ storeMethod: (action: ActionType<Creators[number]>) => unknown
38
+ ]): MapperTypes<Creators>;
39
+ declare function mapAction<Creators extends readonly ActionCreator[], T>(...args: [
40
+ ...creators: Creators,
41
+ storeMethod: (action: ActionType<Creators[number]>, resultMethod: (input: T) => unknown) => unknown,
42
+ resultMethod: (input: T) => unknown
43
+ ]): MapperTypes<Creators>;
44
+ declare function withActionMappers(...mappers: MapperTypes<ActionCreator[]>[]): MapperTypes<ActionCreator[]>[];
45
+ declare function createReduxState<StoreName extends string, STORE extends Store>(storeName: StoreName, signalStore: STORE, withActionMappers: (store: InstanceType<STORE>) => MapperTypes<ActionCreator[]>[]): CreateReduxState<StoreName, STORE>;
46
+
47
+ type RxMethodInput<Input> = Input | Observable<Input> | Signal<Input>;
48
+ type RxMethodRef = {
49
+ destroy: () => void;
50
+ };
51
+ type RxMethod<Input, MethodInput = Input, MethodResult = unknown> = ((input: RxMethodInput<Input>, resultMethod: (input: MethodInput) => MethodResult) => RxMethodRef) & RxMethodRef;
52
+ declare function reduxMethod<Input, MethodInput = Input>(generator: (source$: Observable<Input>) => Observable<MethodInput>, config?: {
53
+ injector?: Injector;
54
+ }): RxMethod<Input, MethodInput>;
55
+ declare function reduxMethod<Input, MethodInput = Input, MethodResult = unknown>(generator: (source$: Observable<Input>) => Observable<MethodInput>, resultMethod: (input: MethodInput) => MethodResult, config?: {
56
+ injector?: Injector;
57
+ }): RxMethod<Input, MethodInput, MethodResult>;
58
+
59
+ export { createReduxState, mapAction, reduxMethod, withActionMappers };
package/eslint.config.cjs DELETED
@@ -1,43 +0,0 @@
1
- const nx = require('@nx/eslint-plugin');
2
- const baseConfig = require('../../eslint.config.cjs');
3
-
4
- module.exports = [
5
- ...baseConfig,
6
- {
7
- files: ['**/*.json'],
8
- rules: {
9
- '@nx/dependency-checks': [
10
- 'error',
11
- {
12
- ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs}'],
13
- },
14
- ],
15
- },
16
- languageOptions: {
17
- parser: require('jsonc-eslint-parser'),
18
- },
19
- },
20
- ...nx.configs['flat/angular'],
21
- ...nx.configs['flat/angular-template'],
22
- {
23
- files: ['**/*.ts'],
24
- rules: {
25
- '@angular-eslint/directive-selector': [
26
- 'error',
27
- {
28
- type: 'attribute',
29
- prefix: 'lib',
30
- style: 'camelCase',
31
- },
32
- ],
33
- '@angular-eslint/component-selector': [
34
- 'error',
35
- {
36
- type: 'element',
37
- prefix: 'lib',
38
- style: 'kebab-case',
39
- },
40
- ],
41
- },
42
- }
43
- ];
package/jest.config.ts DELETED
@@ -1,22 +0,0 @@
1
- export default {
2
- displayName: 'ngrx-toolkit',
3
- setupFiles: ['core-js'],
4
- preset: '../../jest.preset.js',
5
- setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
6
- coverageDirectory: '../../coverage/libs/ngrx-toolkit',
7
- transform: {
8
- '^.+\\.(ts|mjs|js|html)$': [
9
- 'jest-preset-angular',
10
- {
11
- tsconfig: '<rootDir>/tsconfig.spec.json',
12
- stringifyContentPathRegex: '\\.(html|svg)$',
13
- },
14
- ],
15
- },
16
- transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
17
- snapshotSerializers: [
18
- 'jest-preset-angular/build/serializers/no-ng-attributes',
19
- 'jest-preset-angular/build/serializers/ng-snapshot',
20
- 'jest-preset-angular/build/serializers/html-comment',
21
- ],
22
- };
package/ng-package.json DELETED
@@ -1,7 +0,0 @@
1
- {
2
- "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
- "dest": "../../dist/libs/ngrx-toolkit",
4
- "lib": {
5
- "entryFile": "src/index.ts"
6
- }
7
- }
package/project.json DELETED
@@ -1,37 +0,0 @@
1
- {
2
- "name": "ngrx-toolkit",
3
- "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
- "sourceRoot": "libs/ngrx-toolkit/src",
5
- "prefix": "ngrx-toolkit",
6
- "projectType": "library",
7
- "tags": [],
8
- "targets": {
9
- "build": {
10
- "executor": "@nx/angular:package",
11
- "outputs": ["{workspaceRoot}/dist/{projectRoot}"],
12
- "options": {
13
- "project": "libs/ngrx-toolkit/ng-package.json"
14
- },
15
- "configurations": {
16
- "production": {
17
- "tsConfig": "libs/ngrx-toolkit/tsconfig.lib.prod.json"
18
- },
19
- "development": {
20
- "tsConfig": "libs/ngrx-toolkit/tsconfig.lib.json"
21
- }
22
- },
23
- "defaultConfiguration": "production"
24
- },
25
- "test": {
26
- "executor": "@nx/jest:jest",
27
- "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
28
- "options": {
29
- "jestConfig": "libs/ngrx-toolkit/jest.config.ts"
30
- }
31
- },
32
- "lint": {
33
- "executor": "@nx/eslint:lint",
34
- "outputs": ["{options.outputFile}"]
35
- }
36
- }
37
- }
@@ -1,131 +0,0 @@
1
- # Redux Connector for the NgRx Signal Store `createReduxState()`
2
-
3
- The Redux Connector turns any `signalStore()` into a Global State Management Slice following the Redux pattern. It is available as secondary entry point, i.e. `import { createReduxState } from '@angular-architects/ngrx-toolkit/redux-connector'` and has a dependency to `@ngrx/store`.
4
-
5
- It supports:
6
-
7
- ✅ Well-known NgRx Store Actions \
8
- ✅ Global Action `dispatch()` \
9
- ✅ Angular Lazy Loading \
10
- ✅ Auto-generated `provideNamedStore()` & `injectNamedStore()` Functions \
11
- ✅ Global Action to Store Method Mappers \
12
-
13
- - [Redux Connector for the NgRx Signal Store `createReduxState()`](#redux-connector-for-the-ngrx-signal-store-createreduxstate)
14
- - [Use a present Signal Store](#use-a-present-signal-store)
15
- - [Use well-known NgRx Store Actions](#use-well-known-ngrx-store-actions)
16
- - [Map Actions to Methods](#map-actions-to-methods)
17
- - [Register an Angular Dependency Injection Provider](#register-an-angular-dependency-injection-provider)
18
- - [Use the Store in your Component](#use-the-store-in-your-component)
19
-
20
- ## Use a present Signal Store
21
-
22
- ```typescript
23
- export const FlightStore = signalStore(
24
- // State
25
- withEntities({ entity: type<Flight>(), collection: 'flight' }),
26
- withEntities({ entity: type<number>(), collection: 'hide' }),
27
- // Selectors
28
- withComputed(({ flightEntities, hideEntities }) => ({
29
- filteredFlights: computed(() => flightEntities().filter((flight) => !hideEntities().includes(flight.id))),
30
- flightCount: computed(() => flightEntities().length),
31
- })),
32
- // Updater
33
- withMethods((store) => ({
34
- setFlights: (state: { flights: Flight[] }) => patchState(store, setAllEntities(state.flights, { collection: 'flight' })),
35
- updateFlight: (state: { flight: Flight }) => patchState(store, updateEntity({ id: state.flight.id, changes: state.flight }, { collection: 'flight' })),
36
- clearFlights: () => patchState(store, removeAllEntities({ collection: 'flight' })),
37
- })),
38
- // Effects
39
- withMethods((store, flightService = inject(FlightService)) => ({
40
- loadFlights: reduxMethod<FlightFilter, { flights: Flight[] }>(
41
- pipe(
42
- switchMap((filter) => from(flightService.load({ from: filter.from, to: filter.to }))),
43
- map((flights) => ({ flights })),
44
- ),
45
- store.setFlights,
46
- ),
47
- })),
48
- );
49
- ```
50
-
51
- ## Use well-known NgRx Store Actions
52
-
53
- ```typescript
54
- export const ticketActions = createActionGroup({
55
- source: 'tickets',
56
- events: {
57
- 'flights load': props<FlightFilter>(),
58
- 'flights loaded': props<{ flights: Flight[] }>(),
59
- 'flights loaded by passenger': props<{ flights: Flight[] }>(),
60
- 'flight update': props<{ flight: Flight }>(),
61
- 'flights clear': emptyProps(),
62
- },
63
- });
64
- ```
65
-
66
- ## Map Actions to Methods
67
-
68
- ```typescript
69
- export const { provideFlightStore, injectFlightStore } = createReduxState('flight', FlightStore, (store) =>
70
- withActionMappers(
71
- mapAction(
72
- // Filtered Action
73
- ticketActions.flightsLoad,
74
- // Side-Effect
75
- store.loadFlights,
76
- // Result Action
77
- ticketActions.flightsLoaded,
78
- ),
79
- mapAction(
80
- // Filtered Actions
81
- ticketActions.flightsLoaded,
82
- ticketActions.flightsLoadedByPassenger,
83
- // State Updater Method (like Reducers)
84
- store.setFlights,
85
- ),
86
- mapAction(ticketActions.flightUpdate, store.updateFlight),
87
- mapAction(ticketActions.flightsClear, store.clearFlights),
88
- ),
89
- );
90
- ```
91
-
92
- ## Register an Angular Dependency Injection Provider
93
-
94
- ```typescript
95
- export const appRoutes: Route[] = [
96
- {
97
- path: 'flight-search-redux-connector',
98
- providers: [provideFlightStore()],
99
- component: FlightSearchReducConnectorComponent,
100
- },
101
- ];
102
- ```
103
-
104
- ## Use the Store in your Component
105
-
106
- ```typescript
107
- @Component({
108
- standalone: true,
109
- imports: [JsonPipe, RouterLink, FormsModule, FlightCardComponent],
110
- selector: 'demo-flight-search-redux-connector',
111
- templateUrl: './flight-search.component.html',
112
- })
113
- export class FlightSearchReducConnectorComponent {
114
- private store = injectFlightStore();
115
-
116
- protected flights = this.store.flightEntities;
117
-
118
- protected search() {
119
- this.store.dispatch(
120
- ticketActions.flightsLoad({
121
- from: this.localState.filter.from(),
122
- to: this.localState.filter.to(),
123
- }),
124
- );
125
- }
126
-
127
- protected reset(): void {
128
- this.store.dispatch(ticketActions.flightsClear());
129
- }
130
- }
131
- ```
@@ -1,6 +0,0 @@
1
- export {
2
- createReduxState,
3
- mapAction,
4
- withActionMappers,
5
- } from './src/lib/create-redux';
6
- export { reduxMethod } from './src/lib/rxjs-interop/redux-method';
@@ -1,5 +0,0 @@
1
- {
2
- "lib": {
3
- "entryFile": "index.ts"
4
- }
5
- }
@@ -1,102 +0,0 @@
1
- import {
2
- inject,
3
- makeEnvironmentProviders,
4
- provideEnvironmentInitializer,
5
- } from '@angular/core';
6
- import { ActionCreator, ActionType } from '@ngrx/store/src/models';
7
- import {
8
- CreateReduxState,
9
- ExtractActionTypes,
10
- MapperTypes,
11
- ServiceWithDecorator,
12
- Store,
13
- } from './model';
14
- import { SignalReduxStore, injectReduxDispatch } from './signal-redux-store';
15
- import { capitalize, isActionCreator } from './util';
16
-
17
- export function mapAction<Creators extends readonly ActionCreator[]>(
18
- ...args: [
19
- ...creators: Creators,
20
- storeMethod: (action: ActionType<Creators[number]>) => unknown,
21
- ]
22
- ): MapperTypes<Creators>;
23
- export function mapAction<Creators extends readonly ActionCreator[], T>(
24
- ...args: [
25
- ...creators: Creators,
26
- storeMethod: (
27
- action: ActionType<Creators[number]>,
28
- resultMethod: (input: T) => unknown,
29
- ) => unknown,
30
- resultMethod: (input: T) => unknown,
31
- ]
32
- ): MapperTypes<Creators>;
33
- export function mapAction<Creators extends readonly ActionCreator[]>(
34
- ...args: [
35
- ...creators: Creators,
36
- storeMethod: (action: ActionType<Creators[number]>) => unknown,
37
- resultMethod?: (input: unknown) => unknown,
38
- ]
39
- ): MapperTypes<Creators> {
40
- let resultMethod = args.pop() as unknown as
41
- | ((input: unknown) => unknown)
42
- | undefined;
43
- let storeMethod = args.pop() as unknown as (
44
- action: ActionType<Creators[number]>,
45
- ) => unknown;
46
-
47
- if (isActionCreator(storeMethod)) {
48
- args.push(storeMethod);
49
- storeMethod = resultMethod || storeMethod;
50
- resultMethod = undefined;
51
- }
52
-
53
- const types = (args as unknown as Creators).map(
54
- (creator) => creator.type,
55
- ) as unknown as ExtractActionTypes<Creators>;
56
-
57
- return {
58
- types,
59
- storeMethod,
60
- resultMethod,
61
- };
62
- }
63
-
64
- export function withActionMappers(
65
- ...mappers: MapperTypes<ActionCreator[]>[]
66
- ): MapperTypes<ActionCreator[]>[] {
67
- return mappers;
68
- }
69
-
70
- export function createReduxState<StoreName extends string, STORE extends Store>(
71
- storeName: StoreName,
72
- signalStore: STORE,
73
- withActionMappers: (
74
- store: InstanceType<STORE>,
75
- ) => MapperTypes<ActionCreator[]>[],
76
- ): CreateReduxState<StoreName, STORE> {
77
- const isRootProvider =
78
- (signalStore as ServiceWithDecorator)?.ɵprov?.providedIn === 'root';
79
- return {
80
- [`provide${capitalize(storeName)}Store`]: (connectReduxDevtools = false) =>
81
- makeEnvironmentProviders([
82
- isRootProvider ? [] : signalStore,
83
- provideEnvironmentInitializer(() => {
84
- const initializerFn = (
85
- (
86
- signalReduxStore = inject(SignalReduxStore),
87
- store = inject(signalStore),
88
- ) =>
89
- () => {
90
- if (connectReduxDevtools) {
91
- // addStoreToReduxDevtools(store, storeName, false);
92
- }
93
- signalReduxStore.connectFeatureStore(withActionMappers(store));
94
- }
95
- )();
96
- return initializerFn();
97
- }),
98
- ]),
99
- [`inject${capitalize(storeName)}Store`]: () =>
100
- Object.assign(inject(signalStore), { dispatch: injectReduxDispatch() }),
101
- } as CreateReduxState<StoreName, STORE>;
102
- }
@@ -1,89 +0,0 @@
1
- import { EnvironmentProviders, Signal, Type } from '@angular/core';
2
- import { DeepSignal } from '@ngrx/signals/src/deep-signal';
3
- import {
4
- SignalStoreFeatureResult,
5
- StateSignals,
6
- } from '@ngrx/signals/src/signal-store-models';
7
- import {
8
- Action,
9
- ActionCreator,
10
- ActionType,
11
- Prettify,
12
- } from '@ngrx/store/src/models';
13
- import { Observable, Unsubscribable } from 'rxjs';
14
-
15
- export type IncludePropType<
16
- T,
17
- V,
18
- WithNevers = {
19
- [K in keyof T]: Exclude<T[K], undefined> extends V
20
- ? T[K] extends Record<string, unknown>
21
- ? IncludePropType<T[K], V>
22
- : T[K]
23
- : never;
24
- },
25
- > = Prettify<
26
- Pick<
27
- WithNevers,
28
- {
29
- [K in keyof WithNevers]: WithNevers[K] extends never
30
- ? never
31
- : K extends string
32
- ? K
33
- : never;
34
- }[keyof WithNevers]
35
- >
36
- >;
37
-
38
- export type Store = Type<
39
- Record<string, unknown> & StateSignals<SignalStoreFeatureResult['state']>
40
- >;
41
-
42
- export type CreateReduxState<StoreName extends string, STORE extends Store> = {
43
- [K in StoreName as `provide${Capitalize<K>}Store`]: (
44
- connectReduxDevtools?: boolean,
45
- ) => EnvironmentProviders;
46
- } & {
47
- [K in StoreName as `inject${Capitalize<K>}Store`]: () => InjectableReduxSlice<STORE>;
48
- };
49
-
50
- export type Selectors<STORE extends Store> = IncludePropType<
51
- InstanceType<STORE>,
52
- Signal<unknown> | DeepSignal<unknown>
53
- >;
54
- export type Dispatch = {
55
- dispatch: (
56
- input: Action | Observable<Action> | Signal<Action>,
57
- ) => Unsubscribable;
58
- };
59
- export type InjectableReduxSlice<STORE extends Store> = Selectors<STORE> &
60
- Dispatch;
61
-
62
- export type ExtractActionTypes<Creators extends readonly ActionCreator[]> = {
63
- [Key in keyof Creators]: Creators[Key] extends ActionCreator<infer T>
64
- ? T
65
- : never;
66
- };
67
-
68
- export interface ActionMethod<T, V extends Action = Action> {
69
- (action: V): T;
70
- }
71
-
72
- export interface StoreMethod<
73
- Creators extends readonly ActionCreator[],
74
- ResultState = unknown,
75
- > {
76
- (action: ActionType<Creators[number]>): ResultState;
77
- }
78
-
79
- export interface MapperTypes<Creators extends readonly ActionCreator[]> {
80
- types: ExtractActionTypes<Creators>;
81
- storeMethod: StoreMethod<Creators>;
82
- resultMethod?: (...args: unknown[]) => unknown;
83
- }
84
-
85
- export type ServiceWithDecorator = {
86
- ɵprov?: {
87
- providedIn?: string;
88
- };
89
- };
@@ -1,66 +0,0 @@
1
- import { Injector, Signal, inject } from '@angular/core';
2
- import { rxMethod } from '@ngrx/signals/rxjs-interop';
3
- import { Observable, Unsubscribable, map, pipe } from 'rxjs';
4
-
5
- type RxMethodInput<Input> = Input | Observable<Input> | Signal<Input>;
6
-
7
- type RxMethodRef = {
8
- destroy: () => void;
9
- };
10
-
11
- type RxMethod<Input, MethodInput = Input, MethodResult = unknown> = ((
12
- input: RxMethodInput<Input>,
13
- resultMethod: (input: MethodInput) => MethodResult,
14
- ) => RxMethodRef) &
15
- RxMethodRef;
16
-
17
- export function reduxMethod<Input, MethodInput = Input>(
18
- generator: (source$: Observable<Input>) => Observable<MethodInput>,
19
- config?: { injector?: Injector },
20
- ): RxMethod<Input, MethodInput>;
21
- export function reduxMethod<Input, MethodInput = Input, MethodResult = unknown>(
22
- generator: (source$: Observable<Input>) => Observable<MethodInput>,
23
- resultMethod: (input: MethodInput) => MethodResult,
24
- config?: {
25
- injector?: Injector;
26
- },
27
- ): RxMethod<Input, MethodInput, MethodResult>;
28
- export function reduxMethod<Input, MethodInput = Input, MethodResult = unknown>(
29
- generator: (source$: Observable<Input>) => Observable<MethodInput>,
30
- resultMethodOrConfig?:
31
- | ((input: MethodInput) => MethodResult)
32
- | {
33
- injector?: Injector;
34
- },
35
- config?: {
36
- injector?: Injector;
37
- },
38
- ): RxMethod<Input, MethodInput, MethodResult> {
39
- const injector = inject(Injector);
40
-
41
- if (typeof resultMethodOrConfig === 'function') {
42
- let unsubscribable: Unsubscribable;
43
- const inputResultFn = ((
44
- input: RxMethodInput<Input>,
45
- resultMethod = resultMethodOrConfig,
46
- ) => {
47
- const rxMethodWithResult = rxMethod<Input>(
48
- pipe(generator, map(resultMethod)),
49
- {
50
- ...(config || {}),
51
- injector: config?.injector || injector,
52
- },
53
- );
54
- const rxWithInput = rxMethodWithResult(input);
55
- unsubscribable = { unsubscribe: rxWithInput.destroy.bind(rxWithInput) };
56
-
57
- return rxWithInput;
58
- }) as RxMethod<Input, MethodInput, MethodResult>;
59
-
60
- inputResultFn.destroy = () => unsubscribable?.unsubscribe();
61
-
62
- return inputResultFn;
63
- }
64
-
65
- return rxMethod<Input>(generator, resultMethodOrConfig);
66
- }
@@ -1,59 +0,0 @@
1
- import { Injectable, inject } from '@angular/core';
2
- import { rxMethod } from '@ngrx/signals/rxjs-interop';
3
- import { Action, ActionCreator } from '@ngrx/store';
4
- import { pipe, tap } from 'rxjs';
5
- import { MapperTypes } from './model';
6
- import { isUnsubscribable } from './util';
7
-
8
- @Injectable({
9
- providedIn: 'root',
10
- })
11
- export class SignalReduxStore {
12
- private mapperDict: Record<
13
- string,
14
- {
15
- storeMethod: (...args: unknown[]) => unknown;
16
- resultMethod?: (...args: unknown[]) => unknown;
17
- }
18
- > = {};
19
-
20
- dispatch = rxMethod<Action>(
21
- pipe(
22
- tap((action: Action) => {
23
- const callbacks = this.mapperDict[action.type];
24
- if (callbacks?.storeMethod) {
25
- if (
26
- isUnsubscribable(callbacks.storeMethod) &&
27
- callbacks.resultMethod
28
- ) {
29
- return callbacks.storeMethod(action, (a: Action) => {
30
- const resultAction = callbacks.resultMethod?.(a) as Action;
31
- this.dispatch(resultAction);
32
- });
33
- }
34
-
35
- return callbacks?.storeMethod(action);
36
- }
37
-
38
- return;
39
- }),
40
- ),
41
- );
42
-
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- connectFeatureStore(mappers: MapperTypes<ActionCreator<any, any>[]>[]): void {
45
- mappers.forEach((mapper) =>
46
- mapper.types.forEach(
47
- (action) =>
48
- (this.mapperDict[action] = {
49
- storeMethod: mapper.storeMethod,
50
- resultMethod: mapper.resultMethod,
51
- }),
52
- ),
53
- );
54
- }
55
- }
56
-
57
- export function injectReduxDispatch() {
58
- return inject(SignalReduxStore).dispatch;
59
- }