http-request-manager 18.7.21 → 18.7.27

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 (198) hide show
  1. package/fesm2022/http-request-manager.mjs +7633 -0
  2. package/fesm2022/http-request-manager.mjs.map +1 -0
  3. package/http-request-manager-18.7.27.tgz +0 -0
  4. package/package.json +16 -5
  5. package/types/http-request-manager.d.ts +2277 -0
  6. package/ARCHITECTURE.md +0 -483
  7. package/DATABASE_README.md +0 -1176
  8. package/HTTP_MANAGER_README.md +0 -579
  9. package/HTTP_SINGNALS_MANAGER_README.md +0 -654
  10. package/HTTP_STATE_MANAGER_README.md +0 -948
  11. package/INTERCEPTOR_README.md +0 -549
  12. package/LOCAL_STORAGE_README.md +0 -1056
  13. package/STORE_STATE_MANAGER_README.md +0 -1322
  14. package/UTILS_README.md +0 -1186
  15. package/WS_MANAGER_README.md +0 -613
  16. package/ng-package.json +0 -8
  17. package/src/lib/http-request-manager.module.ts +0 -132
  18. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.html +0 -65
  19. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.scss +0 -0
  20. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.ts +0 -224
  21. package/src/lib/http-request-services-demo/http-request-services-demo.component.html +0 -114
  22. package/src/lib/http-request-services-demo/http-request-services-demo.component.scss +0 -6
  23. package/src/lib/http-request-services-demo/http-request-services-demo.component.ts +0 -52
  24. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.html +0 -195
  25. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.scss +0 -17
  26. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.ts +0 -206
  27. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.html +0 -200
  28. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.scss +0 -17
  29. package/src/lib/http-request-services-demo/local-storage-signals-demo/local-storage-signals-demo.component.ts +0 -212
  30. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.html +0 -53
  31. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.scss +0 -60
  32. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.ts +0 -72
  33. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.ts +0 -28
  34. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.html +0 -10
  35. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.scss +0 -29
  36. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.ts +0 -100
  37. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.ts +0 -22
  38. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.html +0 -8
  39. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.scss +0 -19
  40. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.ts +0 -26
  41. package/src/lib/http-request-services-demo/request-manager-demo/models/app-session.model.ts +0 -30
  42. package/src/lib/http-request-services-demo/request-manager-demo/models/app.model.ts +0 -19
  43. package/src/lib/http-request-services-demo/request-manager-demo/models/get-sample.model.ts +0 -25
  44. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.ts +0 -19
  45. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-details.ts +0 -24
  46. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.ts +0 -30
  47. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client.model.ts +0 -49
  48. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.ts +0 -33
  49. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.html +0 -392
  50. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.scss +0 -24
  51. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.ts +0 -461
  52. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.html +0 -393
  53. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.scss +0 -24
  54. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.ts +0 -421
  55. package/src/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.ts +0 -87
  56. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/services/state-data-request.service.ts +0 -120
  57. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.css +0 -0
  58. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.html +0 -3
  59. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-ai-messaging/ws-ai-messaging.component.ts +0 -16
  60. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.css +0 -0
  61. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.html +0 -3
  62. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-chats/ws-chats.component.ts +0 -16
  63. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.css +0 -31
  64. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.html +0 -72
  65. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.scss +0 -41
  66. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.spec.ts +0 -205
  67. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-data-control/ws-data-control.component.ts +0 -77
  68. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.css +0 -11
  69. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.html +0 -96
  70. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.spec.ts +0 -31
  71. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-messaging/ws-messaging.component.ts +0 -229
  72. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.css +0 -30
  73. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.html +0 -172
  74. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.spec.ts +0 -31
  75. package/src/lib/http-request-services-demo/request-manager-ws-demo/components/ws-notifications/ws-notifications.component.ts +0 -239
  76. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/oidc-client.model.ts +0 -31
  77. package/src/lib/http-request-services-demo/request-manager-ws-demo/models/user-data.model.ts +0 -32
  78. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.css +0 -0
  79. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.html +0 -84
  80. package/src/lib/http-request-services-demo/request-manager-ws-demo/request-manager-ws-demo.component.ts +0 -41
  81. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/index.ts +0 -3
  82. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/message-service-demo.service.ts +0 -83
  83. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/notification-service-demo.service.ts +0 -147
  84. package/src/lib/http-request-services-demo/request-manager-ws-demo/services/state-service-demo.service.ts +0 -158
  85. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.html +0 -53
  86. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.scss +0 -60
  87. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/download-file/download-file.component.ts +0 -72
  88. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-download.module.ts +0 -28
  89. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.html +0 -10
  90. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.scss +0 -29
  91. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/file-downloader.component.ts +0 -100
  92. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/models/download-labels-model.ts +0 -22
  93. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.html +0 -8
  94. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.scss +0 -19
  95. package/src/lib/http-request-services-demo/request-signals-manager-demo/file-downloader/spinner/spinner.component.ts +0 -26
  96. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app-session.model.ts +0 -30
  97. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/app.model.ts +0 -19
  98. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/get-sample.model.ts +0 -25
  99. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-ai-prompt.ts +0 -19
  100. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-details.ts +0 -24
  101. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client-info.ts +0 -30
  102. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-client.model.ts +0 -49
  103. package/src/lib/http-request-services-demo/request-signals-manager-demo/models/sample-mapper-client-info.ts +0 -33
  104. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.html +0 -380
  105. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.scss +0 -24
  106. package/src/lib/http-request-services-demo/request-signals-manager-demo/request-signals-manager-demo.component.ts +0 -410
  107. package/src/lib/http-request-services-demo/store-state-manager-demo/models/settings.model.ts +0 -28
  108. package/src/lib/http-request-services-demo/store-state-manager-demo/services/settings-state.service.ts +0 -48
  109. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.css +0 -0
  110. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.html +0 -23
  111. package/src/lib/http-request-services-demo/store-state-manager-demo/store-state-manager-demo.component.ts +0 -36
  112. package/src/lib/index.ts +0 -3
  113. package/src/lib/interceptors/credentials.interceptor.ts +0 -16
  114. package/src/lib/interceptors/index.ts +0 -6
  115. package/src/lib/interceptors/models/error-settings.model.ts +0 -22
  116. package/src/lib/interceptors/models/index.ts +0 -2
  117. package/src/lib/interceptors/proxy-debugger.interceptor.ts +0 -46
  118. package/src/lib/interceptors/request-error.interceptor.ts +0 -65
  119. package/src/lib/interceptors/request-header.interceptor.ts +0 -53
  120. package/src/lib/models/config-http-options.model.ts +0 -42
  121. package/src/lib/models/config-local-storage-options.model.ts +0 -27
  122. package/src/lib/models/config-options.model.ts +0 -27
  123. package/src/lib/models/config-token.model.ts +0 -9
  124. package/src/lib/models/data-type.enum.ts +0 -5
  125. package/src/lib/models/database-storage.model.ts +0 -24
  126. package/src/lib/models/index.ts +0 -12
  127. package/src/lib/models/retry-options.model.ts +0 -22
  128. package/src/lib/services/database-manager-service/database.manager.service.ts +0 -262
  129. package/src/lib/services/database-manager-service/db.storage.service.ts +0 -207
  130. package/src/lib/services/database-manager-service/index.ts +0 -4
  131. package/src/lib/services/database-manager-service/models/index.ts +0 -2
  132. package/src/lib/services/database-manager-service/models/table-schema.ts +0 -33
  133. package/src/lib/services/index.ts +0 -12
  134. package/src/lib/services/local-storage-manager-service/index.ts +0 -4
  135. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.spec.ts +0 -71
  136. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.ts +0 -426
  137. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.spec.ts +0 -67
  138. package/src/lib/services/local-storage-manager-service/local-storage-signals-manager.service.ts +0 -345
  139. package/src/lib/services/local-storage-manager-service/models/global-store-options.model.ts +0 -30
  140. package/src/lib/services/local-storage-manager-service/models/index.ts +0 -6
  141. package/src/lib/services/local-storage-manager-service/models/setting-options.model.ts +0 -35
  142. package/src/lib/services/local-storage-manager-service/models/storage-data.model.ts +0 -24
  143. package/src/lib/services/local-storage-manager-service/models/storage-option.model.ts +0 -32
  144. package/src/lib/services/local-storage-manager-service/models/storage-type.enum.ts +0 -5
  145. package/src/lib/services/request-manager-services/README.md +0 -268
  146. package/src/lib/services/request-manager-services/http-manager-signals.service.ts +0 -246
  147. package/src/lib/services/request-manager-services/http-manager.service.spec.ts +0 -232
  148. package/src/lib/services/request-manager-services/http-manager.service.ts +0 -274
  149. package/src/lib/services/request-manager-services/index.ts +0 -8
  150. package/src/lib/services/request-manager-services/request-signals.service.ts +0 -214
  151. package/src/lib/services/request-manager-services/request.service.ts +0 -309
  152. package/src/lib/services/request-manager-services/rxjs-operators/countdown.ts +0 -17
  153. package/src/lib/services/request-manager-services/rxjs-operators/delay-retry.ts +0 -16
  154. package/src/lib/services/request-manager-services/rxjs-operators/index.ts +0 -4
  155. package/src/lib/services/request-manager-services/rxjs-operators/request-polling.ts +0 -35
  156. package/src/lib/services/request-manager-services/rxjs-operators/request-streaming.ts +0 -436
  157. package/src/lib/services/request-manager-state-service/http-manager-state.store.ts +0 -1321
  158. package/src/lib/services/request-manager-state-service/index.ts +0 -3
  159. package/src/lib/services/request-manager-state-service/models/api-request.model.ts +0 -61
  160. package/src/lib/services/request-manager-state-service/models/index.ts +0 -6
  161. package/src/lib/services/request-manager-state-service/models/request-options.model.ts +0 -22
  162. package/src/lib/services/request-manager-state-service/models/stream-type.enum.ts +0 -13
  163. package/src/lib/services/request-manager-state-service/models/ws-options.model.ts +0 -39
  164. package/src/lib/services/store-state-manager-service/index.ts +0 -3
  165. package/src/lib/services/store-state-manager-service/models/index.ts +0 -2
  166. package/src/lib/services/store-state-manager-service/models/state-storage-options.model.ts +0 -24
  167. package/src/lib/services/store-state-manager-service/store-state-manager.service.ts +0 -88
  168. package/src/lib/services/utils/app.service.spec.ts +0 -25
  169. package/src/lib/services/utils/app.service.ts +0 -21
  170. package/src/lib/services/utils/encryption/README.md +0 -79
  171. package/src/lib/services/utils/encryption/asymmetrical-encryption.service.ts +0 -282
  172. package/src/lib/services/utils/encryption/encryption-test.service.ts +0 -39
  173. package/src/lib/services/utils/encryption/index.ts +0 -5
  174. package/src/lib/services/utils/encryption/random.ts +0 -81
  175. package/src/lib/services/utils/encryption/symmetrical-encryption.service.ts +0 -93
  176. package/src/lib/services/utils/headers.service.spec.ts +0 -80
  177. package/src/lib/services/utils/headers.service.ts +0 -18
  178. package/src/lib/services/utils/index.ts +0 -7
  179. package/src/lib/services/utils/object-merger.service.spec.ts +0 -18
  180. package/src/lib/services/utils/object-merger.service.ts +0 -78
  181. package/src/lib/services/utils/path-query.service.spec.ts +0 -117
  182. package/src/lib/services/utils/path-query.service.ts +0 -69
  183. package/src/lib/services/utils/random-color.utils.ts +0 -83
  184. package/src/lib/services/utils/utils.service.spec.ts +0 -165
  185. package/src/lib/services/utils/utils.service.ts +0 -192
  186. package/src/lib/services/ws-manager-service/index.ts +0 -4
  187. package/src/lib/services/ws-manager-service/models/channel-info.model.ts +0 -24
  188. package/src/lib/services/ws-manager-service/models/channel-message-data.model.ts +0 -24
  189. package/src/lib/services/ws-manager-service/models/channel-message.model.ts +0 -24
  190. package/src/lib/services/ws-manager-service/models/communication-type.enum.ts +0 -5
  191. package/src/lib/services/ws-manager-service/models/index.ts +0 -5
  192. package/src/lib/services/ws-manager-service/models/ws-user.model.ts +0 -38
  193. package/src/lib/services/ws-manager-service/services/index.ts +0 -3
  194. package/src/lib/services/ws-manager-service/services/websocket.service.ts +0 -392
  195. package/src/public-api.ts +0 -14
  196. package/tsconfig.lib.json +0 -32
  197. package/tsconfig.lib.prod.json +0 -10
  198. package/tsconfig.spec.json +0 -14
@@ -1,1322 +0,0 @@
1
- # Store State Manager Service
2
-
3
- The `StoreStateManagerService` extends `ComponentStore` to provide persistent state management synchronized with local or session storage. It bridges the gap between in-memory state and persistent storage.
4
-
5
- ## Overview
6
-
7
- This service provides:
8
-
9
- - **ComponentStore Extension** - Full ComponentStore functionality with persistence
10
- - **Storage Synchronization** - Automatic state save/restore from localStorage/sessionStorage
11
- - **Encryption Support** - Optional encryption for sensitive state data
12
- - **Model Adaptation** - Support for model adapters to ensure state structure
13
- - **Reactivity** - Maintains all ComponentStore benefits (selectors, updaters, effects)
14
- - **Migration Support** - Built-in support for state migrations
15
-
16
- ## Installation
17
-
18
- ```typescript
19
- import { HttpRequestManagerModule } from 'http-request-manager';
20
-
21
- @NgModule({
22
- imports: [HttpRequestManagerModule.forRoot({
23
- LocalStorageOptions: {
24
- storageName: 'app-state',
25
- options: { encrypted: true }
26
- }
27
- })]
28
- })
29
- export class AppModule { }
30
- ```
31
-
32
- ## Basic Usage
33
-
34
- ### Creating a Persistent State Service
35
-
36
- ```typescript
37
- import { Injectable } from '@angular/core';
38
- import { StoreStateManagerService, StateStorageOptions, SettingOptions } from 'http-request-manager';
39
- import { StorageType } from 'http-request-manager';
40
-
41
- interface UserSettings {
42
- theme: 'light' | 'dark';
43
- language: string;
44
- notifications: boolean;
45
- emailDigest: boolean;
46
- autoSave: boolean;
47
- }
48
-
49
- @Injectable({
50
- providedIn: 'root'
51
- })
52
- export class UserSettingsStateService extends StoreStateManagerService<UserSettings> {
53
-
54
- constructor() {
55
- super(
56
- StateStorageOptions.adapt({
57
- store: 'user-settings', // Unique store name
58
- options: SettingOptions.adapt({
59
- storage: StorageType.GLOBAL, // localStorage
60
- encrypted: true, // Encrypt sensitive data
61
- expiresIn: '30d' // 30 days expiration
62
- }),
63
- model: UserSettings.adapt // Model adapter for validation
64
- })
65
- );
66
- }
67
-
68
- // Public API methods
69
- updateTheme(theme: 'light' | 'dark') {
70
- this.updateData({ theme });
71
- }
72
-
73
- updateLanguage(language: string) {
74
- this.updateData({ language });
75
- }
76
-
77
- toggleNotifications() {
78
- this.updateData(state => ({
79
- ...state,
80
- notifications: !state.notifications
81
- }));
82
- }
83
-
84
- toggleEmailDigest() {
85
- this.updateData(state => ({
86
- ...state,
87
- emailDigest: !state.emailDigest
88
- }));
89
- }
90
-
91
- updateAutoSave(enabled: boolean) {
92
- this.updateData({ autoSave: enabled });
93
- }
94
-
95
- resetToDefaults() {
96
- this.updateData({
97
- theme: 'light',
98
- language: 'en',
99
- notifications: true,
100
- emailDigest: false,
101
- autoSave: true
102
- });
103
- }
104
- }
105
- ```
106
-
107
- ### Using in Components
108
-
109
- ```typescript
110
- import { Component, inject } from '@angular/core';
111
- import { UserSettingsStateService } from './user-settings-state.service';
112
-
113
- @Component({
114
- selector: 'app-settings',
115
- template: `
116
- <div class="settings-container">
117
- <h2>User Settings</h2>
118
-
119
- <div class="setting-section">
120
- <h3>Appearance</h3>
121
- <div class="setting-item">
122
- <label>Theme:</label>
123
- <select [value]="settings?.theme" (change)="updateTheme($any($event.target).value)">
124
- <option value="light">Light</option>
125
- <option value="dark">Dark</option>
126
- </select>
127
- </div>
128
- </div>
129
-
130
- <div class="setting-section">
131
- <h3>Localization</h3>
132
- <div class="setting-item">
133
- <label>Language:</label>
134
- <select [value]="settings?.language" (change)="updateLanguage($any($event.target).value)">
135
- <option value="en">English</option>
136
- <option value="es">Español</option>
137
- <option value="fr">Français</option>
138
- </select>
139
- </div>
140
- </div>
141
-
142
- <div class="setting-section">
143
- <h3>Notifications</h3>
144
- <div class="setting-item">
145
- <label>
146
- <input type="checkbox" [checked]="settings?.notifications"
147
- (change)="toggleNotifications()">
148
- Enable Push Notifications
149
- </label>
150
- </div>
151
- <div class="setting-item">
152
- <label>
153
- <input type="checkbox" [checked]="settings?.emailDigest"
154
- (change)="toggleEmailDigest()">
155
- Weekly Email Digest
156
- </label>
157
- </div>
158
- </div>
159
-
160
- <div class="setting-section">
161
- <h3>Preferences</h3>
162
- <div class="setting-item">
163
- <label>
164
- <input type="checkbox" [checked]="settings?.autoSave"
165
- (change)="updateAutoSave($any($event.target).checked)">
166
- Auto-save Changes
167
- </label>
168
- </div>
169
- </div>
170
-
171
- <div class="actions">
172
- <button (click)="resetToDefaults()">Reset to Defaults</button>
173
- <button (click)="exportSettings()">Export Settings</button>
174
- <button (click)="clearSettings()">Clear All</button>
175
- </div>
176
-
177
- <div class="storage-info" *ngIf="storageInfo">
178
- <p>Last updated: {{ storageInfo.lastUpdated | date:'medium' }}</p>
179
- <p>Storage type: {{ storageInfo.storageType }}</p>
180
- <p>Encrypted: {{ storageInfo.encrypted ? 'Yes' : 'No' }}</p>
181
- </div>
182
- </div>
183
- `
184
- })
185
- export class SettingsComponent {
186
- private settingsStore = inject(UserSettingsStateService);
187
-
188
- settings = this.settingsStore.data$;
189
- storageInfo = this.settingsStore.storageInfo$;
190
-
191
- updateTheme(theme: 'light' | 'dark') {
192
- this.settingsStore.updateTheme(theme);
193
- }
194
-
195
- updateLanguage(language: string) {
196
- this.settingsStore.updateLanguage(language);
197
- }
198
-
199
- toggleNotifications() {
200
- this.settingsStore.toggleNotifications();
201
- }
202
-
203
- toggleEmailDigest() {
204
- this.settingsStore.toggleEmailDigest();
205
- }
206
-
207
- updateAutoSave(enabled: boolean) {
208
- this.settingsStore.updateAutoSave(enabled);
209
- }
210
-
211
- resetToDefaults() {
212
- this.settingsStore.resetToDefaults();
213
- }
214
-
215
- exportSettings() {
216
- const settings = this.settingsStore.exportData();
217
- console.log('Settings exported:', settings);
218
- }
219
-
220
- clearSettings() {
221
- this.settingsStore.clearData();
222
- }
223
- }
224
- ```
225
-
226
- ## API Reference
227
-
228
- ### Constructor Options
229
-
230
- #### StateStorageOptions
231
-
232
- ```typescript
233
- interface StateStorageOptions {
234
- store: string; // Unique store name
235
- options: SettingOptions; // Storage configuration
236
- model?: Function; // Model adapter for validation
237
- version?: number; // State version for migrations
238
- }
239
- ```
240
-
241
- ### State Management Methods
242
-
243
- #### updateData(updater: ((state: T) => T) | T): void
244
-
245
- Update state with new data or updater function:
246
-
247
- ```typescript
248
- // Direct update
249
- this.store.updateData({ theme: 'dark' });
250
-
251
- // Function update
252
- this.store.updateData(state => ({
253
- ...state,
254
- notifications: !state.notifications
255
- }));
256
- ```
257
-
258
- #### clearData(): void
259
-
260
- Clear all stored data:
261
-
262
- ```typescript
263
- this.store.clearData();
264
- ```
265
-
266
- ### Selectors
267
-
268
- #### data$: Observable<T>
269
-
270
- Get current state:
271
-
272
- ```typescript
273
- settings$ = this.store.data$;
274
-
275
- <div *ngIf="settings$ | async as settings">
276
- Theme: {{ settings.theme }}
277
- </div>
278
- ```
279
-
280
- #### storageInfo$: Observable<any>
281
-
282
- Get storage metadata:
283
-
284
- ```typescript
285
- info$ = this.store.storageInfo$;
286
-
287
- <div *ngIf="info$ | async as info">
288
- Last updated: {{ info.lastUpdated }}
289
- Encrypted: {{ info.encrypted }}
290
- </div>
291
- ```
292
-
293
- ### Data Operations
294
-
295
- #### exportData(): any
296
-
297
- Export current state:
298
-
299
- ```typescript
300
- const exportedData = this.store.exportData();
301
- console.log('Exported state:', exportedData);
302
- ```
303
-
304
- #### importData(data: any): void
305
-
306
- Import state data:
307
-
308
- ```typescript
309
- this.store.importData({
310
- theme: 'dark',
311
- language: 'en',
312
- notifications: true
313
- });
314
- ```
315
-
316
- ## Advanced Examples
317
-
318
- ### Shopping Cart State
319
-
320
- ```typescript
321
- interface CartItem {
322
- id: string;
323
- name: string;
324
- price: number;
325
- quantity: number;
326
- image?: string;
327
- }
328
-
329
- interface CartState {
330
- items: CartItem[];
331
- total: number;
332
- itemCount: number;
333
- lastUpdated: Date;
334
- promoCode?: string;
335
- discount: number;
336
- }
337
-
338
- @Injectable()
339
- export class ShoppingCartStateService extends StoreStateManagerService<CartState> {
340
-
341
- constructor() {
342
- super(
343
- StateStorageOptions.adapt({
344
- store: 'shopping-cart',
345
- options: SettingOptions.adapt({
346
- storage: StorageType.GLOBAL,
347
- encrypted: false,
348
- expiresIn: '7d'
349
- }),
350
- model: CartState.adapt
351
- })
352
- );
353
- }
354
-
355
- // Cart operations
356
- addItem(item: Omit<CartItem, 'quantity'>) {
357
- this.updateData(state => {
358
- const existingItem = state.items.find(i => i.id === item.id);
359
-
360
- let newItems: CartItem[];
361
- if (existingItem) {
362
- newItems = state.items.map(i =>
363
- i.id === item.id
364
- ? { ...i, quantity: i.quantity + 1 }
365
- : i
366
- );
367
- } else {
368
- newItems = [...state.items, { ...item, quantity: 1 }];
369
- }
370
-
371
- return this.calculateTotals({ ...state, items: newItems });
372
- });
373
- }
374
-
375
- removeItem(itemId: string) {
376
- this.updateData(state => ({
377
- ...state,
378
- items: state.items.filter(item => item.id !== itemId),
379
- lastUpdated: new Date()
380
- }));
381
- }
382
-
383
- updateQuantity(itemId: string, quantity: number) {
384
- if (quantity <= 0) {
385
- this.removeItem(itemId);
386
- return;
387
- }
388
-
389
- this.updateData(state => {
390
- const newItems = state.items.map(item =>
391
- item.id === itemId ? { ...item, quantity } : item
392
- );
393
-
394
- return this.calculateTotals({ ...state, items: newItems });
395
- });
396
- }
397
-
398
- clearCart() {
399
- this.updateData({
400
- items: [],
401
- total: 0,
402
- itemCount: 0,
403
- lastUpdated: new Date(),
404
- discount: 0
405
- });
406
- }
407
-
408
- applyPromoCode(promoCode: string) {
409
- this.updateData(state => {
410
- const discount = this.calculateDiscount(promoCode, state.total);
411
- return {
412
- ...state,
413
- promoCode,
414
- discount,
415
- lastUpdated: new Date()
416
- };
417
- });
418
- }
419
-
420
- removePromoCode() {
421
- this.updateData(state => ({
422
- ...state,
423
- promoCode: undefined,
424
- discount: 0,
425
- lastUpdated: new Date()
426
- }));
427
- }
428
-
429
- // Computed values
430
- getTotal() {
431
- return this.data$.pipe(map(state => state.total));
432
- }
433
-
434
- getItemCount() {
435
- return this.data$.pipe(map(state => state.itemCount));
436
- }
437
-
438
- getItems() {
439
- return this.data$.pipe(map(state => state.items));
440
- }
441
-
442
- hasItems() {
443
- return this.data$.pipe(map(state => state.items.length > 0));
444
- }
445
-
446
- getDiscount() {
447
- return this.data$.pipe(map(state => state.discount));
448
- }
449
-
450
- // Private helpers
451
- private calculateTotals(state: CartState): CartState {
452
- const subtotal = state.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
453
- const discountAmount = (subtotal * state.discount) / 100;
454
- const total = subtotal - discountAmount;
455
- const itemCount = state.items.reduce((sum, item) => sum + item.quantity, 0);
456
-
457
- return {
458
- ...state,
459
- total,
460
- itemCount,
461
- lastUpdated: new Date()
462
- };
463
- }
464
-
465
- private calculateDiscount(promoCode: string, total: number): number {
466
- const discounts: { [key: string]: number } = {
467
- 'SAVE10': 10,
468
- 'WELCOME20': 20,
469
- 'HOLIDAY15': 15
470
- };
471
-
472
- return discounts[promoCode.toUpperCase()] || 0;
473
- }
474
- }
475
- ```
476
-
477
- ### Multi-tenant Application State
478
-
479
- ```typescript
480
- interface TenantInfo {
481
- id: string;
482
- name: string;
483
- domain: string;
484
- logo?: string;
485
- theme: {
486
- primary: string;
487
- secondary: string;
488
- accent: string;
489
- };
490
- features: string[];
491
- settings: {
492
- maxUsers: number;
493
- storageLimit: number;
494
- apiRateLimit: number;
495
- };
496
- }
497
-
498
- interface UserInfo {
499
- id: string;
500
- tenantId: string;
501
- email: string;
502
- name: string;
503
- role: 'admin' | 'user' | 'guest';
504
- permissions: string[];
505
- lastLogin: Date;
506
- }
507
-
508
- interface AppState {
509
- tenant: TenantInfo | null;
510
- user: UserInfo | null;
511
- isAuthenticated: boolean;
512
- preferences: {
513
- sidebarCollapsed: boolean;
514
- theme: 'light' | 'dark' | 'auto';
515
- language: string;
516
- notifications: {
517
- email: boolean;
518
- push: boolean;
519
- sms: boolean;
520
- };
521
- };
522
- ui: {
523
- loading: boolean;
524
- error: string | null;
525
- breadcrumbs: Array<{ label: string; url: string }>;
526
- };
527
- }
528
-
529
- @Injectable()
530
- export class AppStateService extends StoreStateManagerService<AppState> {
531
-
532
- constructor() {
533
- super(
534
- StateStorageOptions.adapt({
535
- store: 'app-state',
536
- options: SettingOptions.adapt({
537
- storage: StorageType.GLOBAL,
538
- encrypted: true, // Encrypt sensitive data
539
- expiresIn: '24h'
540
- }),
541
- model: AppState.adapt,
542
- version: 1 // For future migrations
543
- })
544
- );
545
- }
546
-
547
- // Authentication
548
- login(user: UserInfo, tenant: TenantInfo) {
549
- this.updateData({
550
- user,
551
- tenant,
552
- isAuthenticated: true,
553
- ui: {
554
- ...this.getCurrentState().ui,
555
- error: null
556
- }
557
- });
558
- }
559
-
560
- logout() {
561
- this.updateData({
562
- user: null,
563
- tenant: null,
564
- isAuthenticated: false,
565
- preferences: {
566
- ...this.getCurrentState().preferences,
567
- // Keep user preferences but clear auth data
568
- }
569
- });
570
- }
571
-
572
- updateUser(user: Partial<UserInfo>) {
573
- this.updateData(state => ({
574
- ...state,
575
- user: state.user ? { ...state.user, ...user } : null
576
- }));
577
- }
578
-
579
- // Tenant management
580
- switchTenant(tenant: TenantInfo) {
581
- this.updateData(state => ({
582
- ...state,
583
- tenant,
584
- user: state.user ? { ...state.user, tenantId: tenant.id } : null
585
- }));
586
- }
587
-
588
- updateTenantSettings(settings: Partial<TenantInfo['settings']>) {
589
- this.updateData(state => ({
590
- ...state,
591
- tenant: state.tenant ? {
592
- ...state.tenant,
593
- settings: { ...state.tenant.settings, ...settings }
594
- } : null
595
- }));
596
- }
597
-
598
- // Preferences
599
- updatePreferences(preferences: Partial<AppState['preferences']>) {
600
- this.updateData(state => ({
601
- ...state,
602
- preferences: { ...state.preferences, ...preferences }
603
- }));
604
- }
605
-
606
- toggleSidebar() {
607
- this.updateData(state => ({
608
- ...state,
609
- preferences: {
610
- ...state.preferences,
611
- sidebarCollapsed: !state.preferences.sidebarCollapsed
612
- }
613
- }));
614
- }
615
-
616
- setTheme(theme: 'light' | 'dark' | 'auto') {
617
- this.updatePreferences({ theme });
618
- }
619
-
620
- setLanguage(language: string) {
621
- this.updatePreferences({ language });
622
- }
623
-
624
- updateNotificationSettings(settings: Partial<AppState['preferences']['notifications']>) {
625
- this.updateData(state => ({
626
- ...state,
627
- preferences: {
628
- ...state.preferences,
629
- notifications: {
630
- ...state.preferences.notifications,
631
- ...settings
632
- }
633
- }
634
- }));
635
- }
636
-
637
- // UI State
638
- setLoading(loading: boolean) {
639
- this.updateData(state => ({
640
- ...state,
641
- ui: { ...state.ui, loading }
642
- }));
643
- }
644
-
645
- setError(error: string | null) {
646
- this.updateData(state => ({
647
- ...state,
648
- ui: { ...state.ui, error }
649
- }));
650
- }
651
-
652
- clearError() {
653
- this.setError(null);
654
- }
655
-
656
- setBreadcrumbs(breadcrumbs: Array<{ label: string; url: string }>) {
657
- this.updateData(state => ({
658
- ...state,
659
- ui: { ...state.ui, breadcrumbs }
660
- }));
661
- }
662
-
663
- // Computed selectors
664
- isAdmin() {
665
- return this.data$.pipe(map(state => state.user?.role === 'admin'));
666
- }
667
-
668
- isAuthenticated() {
669
- return this.data$.pipe(map(state => state.isAuthenticated));
670
- }
671
-
672
- currentTenant() {
673
- return this.data$.pipe(map(state => state.tenant));
674
- }
675
-
676
- currentUser() {
677
- return this.data$.pipe(map(state => state.user));
678
- }
679
-
680
- hasPermission(permission: string) {
681
- return this.data$.pipe(
682
- map(state => state.user?.permissions.includes(permission) || false)
683
- );
684
- }
685
-
686
- isFeatureEnabled(feature: string) {
687
- return this.data$.pipe(
688
- map(state => state.tenant?.features.includes(feature) || false)
689
- );
690
- }
691
-
692
- // Data persistence
693
- exportState() {
694
- return this.exportData();
695
- }
696
-
697
- importState(state: Partial<AppState>) {
698
- this.importData({ ...this.getCurrentState(), ...state });
699
- }
700
-
701
- // Migration support
702
- migrateFromVersion1(state: any): AppState {
703
- // Example migration logic
704
- return {
705
- ...state,
706
- ui: {
707
- ...state.ui,
708
- breadcrumbs: state.ui?.breadcrumbs || []
709
- }
710
- };
711
- }
712
-
713
- // Private helper
714
- private getCurrentState(): AppState {
715
- let currentState: AppState | undefined;
716
- this.data$.pipe(take(1)).subscribe(state => currentState = state);
717
- return currentState!;
718
- }
719
- }
720
- ```
721
-
722
- ### Game Progress Tracking
723
-
724
- ```typescript
725
- interface GameLevel {
726
- id: string;
727
- name: string;
728
- completed: boolean;
729
- score: number;
730
- stars: number; // 0-3 stars
731
- timeSpent: number; // in seconds
732
- completedAt?: Date;
733
- }
734
-
735
- interface GameProgress {
736
- playerId: string;
737
- totalScore: number;
738
- currentLevel: string;
739
- unlockedLevels: string[];
740
- levels: GameLevel[];
741
- achievements: string[];
742
- settings: {
743
- soundEnabled: boolean;
744
- musicEnabled: boolean;
745
- difficulty: 'easy' | 'normal' | 'hard';
746
- showHints: boolean;
747
- };
748
- statistics: {
749
- totalPlayTime: number;
750
- levelsCompleted: number;
751
- totalStars: number;
752
- averageScore: number;
753
- bestStreak: number;
754
- currentStreak: number;
755
- };
756
- }
757
-
758
- @Injectable()
759
- export class GameProgressStateService extends StoreStateManagerService<GameProgress> {
760
-
761
- constructor() {
762
- super(
763
- StateStorageOptions.adapt({
764
- store: `game-progress-${this.getPlayerId()}`,
765
- options: SettingOptions.adapt({
766
- storage: StorageType.GLOBAL,
767
- encrypted: false,
768
- expiresIn: '1y' // Keep progress for a year
769
- }),
770
- model: GameProgress.adapt
771
- })
772
- );
773
- }
774
-
775
- // Level management
776
- completeLevel(levelId: string, score: number, timeSpent: number, stars: number) {
777
- this.updateData(state => {
778
- const levelIndex = state.levels.findIndex(l => l.id === levelId);
779
- if (levelIndex === -1) return state;
780
-
781
- const updatedLevels = [...state.levels];
782
- const level = { ...updatedLevels[levelIndex] };
783
-
784
- if (!level.completed || score > level.score) {
785
- level.completed = true;
786
- level.score = score;
787
- level.stars = Math.max(level.stars, stars);
788
- level.timeSpent = timeSpent;
789
- level.completedAt = new Date();
790
-
791
- updatedLevels[levelIndex] = level;
792
-
793
- // Unlock next level
794
- const nextLevelIndex = levelIndex + 1;
795
- const unlockedLevels = [...state.unlockedLevels];
796
- if (nextLevelIndex < state.levels.length) {
797
- const nextLevel = state.levels[nextLevelIndex];
798
- if (!unlockedLevels.includes(nextLevel.id)) {
799
- unlockedLevels.push(nextLevel.id);
800
- }
801
- }
802
-
803
- // Update statistics
804
- const statistics = this.calculateStatistics({ ...state, levels: updatedLevels, unlockedLevels });
805
-
806
- return {
807
- ...state,
808
- levels: updatedLevels,
809
- unlockedLevels,
810
- currentLevel: nextLevelIndex < state.levels.length ? state.levels[nextLevelIndex].id : state.currentLevel,
811
- statistics
812
- };
813
- }
814
-
815
- return state;
816
- });
817
- }
818
-
819
- resetLevel(levelId: string) {
820
- this.updateData(state => {
821
- const levelIndex = state.levels.findIndex(l => l.id === levelId);
822
- if (levelIndex === -1) return state;
823
-
824
- const updatedLevels = [...state.levels];
825
- updatedLevels[levelIndex] = {
826
- ...updatedLevels[levelIndex],
827
- completed: false,
828
- score: 0,
829
- stars: 0,
830
- timeSpent: 0,
831
- completedAt: undefined
832
- };
833
-
834
- return {
835
- ...state,
836
- levels: updatedLevels,
837
- statistics: this.calculateStatistics({ ...state, levels: updatedLevels })
838
- };
839
- });
840
- }
841
-
842
- unlockLevel(levelId: string) {
843
- this.updateData(state => {
844
- if (!state.unlockedLevels.includes(levelId)) {
845
- return {
846
- ...state,
847
- unlockedLevels: [...state.unlockedLevels, levelId]
848
- };
849
- }
850
- return state;
851
- });
852
- }
853
-
854
- // Achievement system
855
- unlockAchievement(achievementId: string) {
856
- this.updateData(state => {
857
- if (!state.achievements.includes(achievementId)) {
858
- return {
859
- ...state,
860
- achievements: [...state.achievements, achievementId]
861
- };
862
- }
863
- return state;
864
- });
865
- }
866
-
867
- // Settings
868
- updateSettings(settings: Partial<GameProgress['settings']>) {
869
- this.updateData(state => ({
870
- ...state,
871
- settings: { ...state.settings, ...settings }
872
- }));
873
- }
874
-
875
- toggleSound() {
876
- this.updateData(state => ({
877
- ...state,
878
- settings: {
879
- ...state.settings,
880
- soundEnabled: !state.settings.soundEnabled
881
- }
882
- }));
883
- }
884
-
885
- toggleMusic() {
886
- this.updateData(state => ({
887
- ...state,
888
- settings: {
889
- ...state.settings,
890
- musicEnabled: !state.settings.musicEnabled
891
- }
892
- }));
893
- }
894
-
895
- setDifficulty(difficulty: 'easy' | 'normal' | 'hard') {
896
- this.updateSettings({ difficulty });
897
- }
898
-
899
- // Progress queries
900
- getCompletedLevels() {
901
- return this.data$.pipe(
902
- map(state => state.levels.filter(level => level.completed))
903
- );
904
- }
905
-
906
- getLevelProgress(levelId: string) {
907
- return this.data$.pipe(
908
- map(state => state.levels.find(level => level.id === levelId))
909
- );
910
- }
911
-
912
- isLevelUnlocked(levelId: string) {
913
- return this.data$.pipe(
914
- map(state => state.unlockedLevels.includes(levelId))
915
- );
916
- }
917
-
918
- getTotalStars() {
919
- return this.data$.pipe(
920
- map(state => state.statistics.totalStars)
921
- );
922
- }
923
-
924
- getCompletionPercentage() {
925
- return this.data$.pipe(
926
- map(state => {
927
- const completedLevels = state.levels.filter(l => l.completed).length;
928
- return (completedLevels / state.levels.length) * 100;
929
- })
930
- );
931
- }
932
-
933
- getNextLevel() {
934
- return this.data$.pipe(
935
- map(state => {
936
- const currentLevelIndex = state.levels.findIndex(l => l.id === state.currentLevel);
937
- return state.levels[currentLevelIndex + 1] || null;
938
- })
939
- );
940
- }
941
-
942
- // Statistics
943
- private calculateStatistics(state: GameProgress): GameProgress['statistics'] {
944
- const completedLevels = state.levels.filter(l => l.completed);
945
- const totalPlayTime = state.statistics.totalPlayTime +
946
- completedLevels.reduce((sum, level) => sum + level.timeSpent, 0);
947
- const totalStars = completedLevels.reduce((sum, level) => sum + level.stars, 0);
948
- const averageScore = completedLevels.length > 0
949
- ? completedLevels.reduce((sum, level) => sum + level.score, 0) / completedLevels.length
950
- : 0;
951
-
952
- // Calculate streak (consecutive levels completed)
953
- let currentStreak = 0;
954
- for (let i = 0; i < state.levels.length; i++) {
955
- if (state.levels[i].completed) {
956
- currentStreak++;
957
- } else {
958
- break;
959
- }
960
- }
961
-
962
- return {
963
- ...state.statistics,
964
- totalPlayTime,
965
- levelsCompleted: completedLevels.length,
966
- totalStars,
967
- averageScore,
968
- bestStreak: Math.max(state.statistics.bestStreak, currentStreak),
969
- currentStreak
970
- };
971
- }
972
-
973
- // Data management
974
- exportProgress() {
975
- return this.exportData();
976
- }
977
-
978
- importProgress(progressData: GameProgress) {
979
- this.importData(progressData);
980
- }
981
-
982
- resetAllProgress() {
983
- this.updateData({
984
- playerId: this.getPlayerId(),
985
- totalScore: 0,
986
- currentLevel: 'level-1',
987
- unlockedLevels: ['level-1'],
988
- levels: this.initializeLevels(),
989
- achievements: [],
990
- settings: {
991
- soundEnabled: true,
992
- musicEnabled: true,
993
- difficulty: 'normal',
994
- showHints: true
995
- },
996
- statistics: {
997
- totalPlayTime: 0,
998
- levelsCompleted: 0,
999
- totalStars: 0,
1000
- averageScore: 0,
1001
- bestStreak: 0,
1002
- currentStreak: 0
1003
- }
1004
- });
1005
- }
1006
-
1007
- private getPlayerId(): string {
1008
- // Generate or retrieve player ID
1009
- let playerId = localStorage.getItem('playerId');
1010
- if (!playerId) {
1011
- playerId = 'player-' + Date.now();
1012
- localStorage.setItem('playerId', playerId);
1013
- }
1014
- return playerId;
1015
- }
1016
-
1017
- private initializeLevels(): GameLevel[] {
1018
- // Initialize game levels - this would come from your game data
1019
- return [
1020
- { id: 'level-1', name: 'Tutorial', completed: false, score: 0, stars: 0, timeSpent: 0 },
1021
- { id: 'level-2', name: 'Getting Started', completed: false, score: 0, stars: 0, timeSpent: 0 },
1022
- { id: 'level-3', name: 'First Challenge', completed: false, score: 0, stars: 0, timeSpent: 0 },
1023
- // ... more levels
1024
- ];
1025
- }
1026
- }
1027
- ```
1028
-
1029
- ## State Migration
1030
-
1031
- ### Version Management
1032
-
1033
- ```typescript
1034
- @Injectable()
1035
- export class MigratableStateService extends StoreStateManagerService<any> {
1036
-
1037
- constructor() {
1038
- super(
1039
- StateStorageOptions.adapt({
1040
- store: 'migratable-state',
1041
- options: SettingOptions.adapt({
1042
- storage: StorageType.GLOBAL,
1043
- encrypted: false
1044
- }),
1045
- version: 2 // Current version
1046
- })
1047
- );
1048
- }
1049
-
1050
- // Handle migrations
1051
- protected override handleMigration(storedData: any, currentVersion: number): any {
1052
- let migratedData = storedData;
1053
- let version = currentVersion;
1054
-
1055
- // Migrate from version 1 to 2
1056
- if (version < 2) {
1057
- migratedData = this.migrateFromV1ToV2(migratedData);
1058
- version = 2;
1059
- }
1060
-
1061
- // Future migrations would go here
1062
- // if (version < 3) {
1063
- // migratedData = this.migrateFromV2ToV3(migratedData);
1064
- // version = 3;
1065
- // }
1066
-
1067
- return { data: migratedData, version };
1068
- }
1069
-
1070
- private migrateFromV1ToV2(data: any): any {
1071
- // Example migration: add new field with default value
1072
- return {
1073
- ...data,
1074
- newField: data.newField || 'default-value',
1075
- migratedAt: new Date()
1076
- };
1077
- }
1078
- }
1079
- ```
1080
-
1081
- ## Best Practices
1082
-
1083
- ### 1. Model Validation
1084
-
1085
- ```typescript
1086
- // ✅ Good - Use model adapters for validation
1087
- @Injectable()
1088
- export class ValidatedStateService extends StoreStateManagerService<UserSettings> {
1089
-
1090
- constructor() {
1091
- super(
1092
- StateStorageOptions.adapt({
1093
- store: 'validated-settings',
1094
- model: UserSettings.adapt // Validates and normalizes data
1095
- })
1096
- );
1097
- }
1098
- }
1099
-
1100
- // ❌ Avoid - No model validation
1101
- super(
1102
- StateStorageOptions.adapt({
1103
- store: 'settings',
1104
- // No model validation
1105
- })
1106
- );
1107
- ```
1108
-
1109
- ### 2. Appropriate Storage Types
1110
-
1111
- ```typescript
1112
- // ✅ Good - Choose appropriate storage
1113
- // Session-specific data
1114
- super(StateStorageOptions.adapt({
1115
- store: 'temp-calculation',
1116
- options: SettingOptions.adapt({
1117
- storage: StorageType.SESSION // Cleared on browser close
1118
- })
1119
- }));
1120
-
1121
- // Persistent user preferences
1122
- super(StateStorageOptions.adapt({
1123
- store: 'user-preferences',
1124
- options: SettingOptions.adapt({
1125
- storage: StorageType.GLOBAL // Persists across sessions
1126
- })
1127
- }));
1128
- ```
1129
-
1130
- ### 3. Error Handling
1131
-
1132
- ```typescript
1133
- // ✅ Good - Handle storage errors gracefully
1134
- updateData(updater: ((state: T) => T) | T): void {
1135
- try {
1136
- super.updateData(updater);
1137
- } catch (error) {
1138
- console.error('Failed to update state:', error);
1139
- // Optionally show user notification
1140
- this.showErrorNotification('Failed to save changes');
1141
- }
1142
- }
1143
- ```
1144
-
1145
- ### 4. State Size Management
1146
-
1147
- ```typescript
1148
- // ✅ Good - Keep state size reasonable
1149
- @Injectable()
1150
- export class OptimizedStateService extends StoreStateManagerService<AppState> {
1151
-
1152
- updateData(updater: ((state: T) => T) | T): void {
1153
- super.updateData(state => {
1154
- const newState = typeof updater === 'function' ? updater(state) : updater;
1155
-
1156
- // Prune old data if state becomes too large
1157
- if (this.getStateSize(newState) > MAX_STATE_SIZE) {
1158
- return this.pruneState(newState);
1159
- }
1160
-
1161
- return newState;
1162
- });
1163
- }
1164
-
1165
- private getStateSize(state: any): number {
1166
- return JSON.stringify(state).length;
1167
- }
1168
-
1169
- private pruneState(state: any): any {
1170
- // Remove old log entries, cache data, etc.
1171
- return {
1172
- ...state,
1173
- logs: state.logs?.slice(-100), // Keep only recent logs
1174
- cache: undefined // Clear cache
1175
- };
1176
- }
1177
- }
1178
- ```
1179
-
1180
- ## Performance Optimization
1181
-
1182
- ### Selective Persistence
1183
-
1184
- ```typescript
1185
- @Injectable()
1186
- export class SelectivePersistenceService extends StoreStateManagerService<any> {
1187
-
1188
- // Only persist specific parts of state
1189
- protected override shouldPersist(key: string, value: any): boolean {
1190
- // Don't persist large objects or temporary data
1191
- if (key === 'tempData' || key === 'largeCache') {
1192
- return false;
1193
- }
1194
-
1195
- // Don't persist computed values
1196
- if (key.startsWith('computed') || key.startsWith('derived')) {
1197
- return false;
1198
- }
1199
-
1200
- return true;
1201
- }
1202
-
1203
- // Custom persistence logic
1204
- protected override persistState(state: any): void {
1205
- const persistentState = this.filterPersistentData(state);
1206
- super.persistState(persistentState);
1207
- }
1208
-
1209
- private filterPersistentData(state: any): any {
1210
- const { tempData, largeCache, computedValues, ...persistentState } = state;
1211
- return persistentState;
1212
- }
1213
- }
1214
- ```
1215
-
1216
- ### Debounced Updates
1217
-
1218
- ```typescript
1219
- @Injectable()
1220
- export class DebouncedStateService extends StoreStateManagerService<any> {
1221
-
1222
- private updateTimeout?: any;
1223
-
1224
- updateData(updater: ((state: T) => T) | T): void {
1225
- // Clear previous timeout
1226
- if (this.updateTimeout) {
1227
- clearTimeout(this.updateTimeout);
1228
- }
1229
-
1230
- // Debounce updates to avoid excessive storage writes
1231
- this.updateTimeout = setTimeout(() => {
1232
- super.updateData(updater);
1233
- }, 500); // 500ms debounce
1234
- }
1235
- }
1236
- ```
1237
-
1238
- ## Troubleshooting
1239
-
1240
- ### Common Issues
1241
-
1242
- #### 1. Storage Quota Exceeded
1243
- ```typescript
1244
- // Monitor storage usage
1245
- @Injectable()
1246
- export class StorageMonitoringService extends StoreStateManagerService<any> {
1247
-
1248
- updateData(updater: ((state: T) => T) | T): void {
1249
- try {
1250
- super.updateData(updater);
1251
- } catch (error) {
1252
- if (error.name === 'QuotaExceededError') {
1253
- this.handleQuotaExceeded();
1254
- } else {
1255
- throw error;
1256
- }
1257
- }
1258
- }
1259
-
1260
- private handleQuotaExceeded() {
1261
- // Clean up old data
1262
- this.cleanupOldData();
1263
-
1264
- // Retry the update
1265
- super.updateData(this.pendingUpdate);
1266
- }
1267
-
1268
- private cleanupOldData() {
1269
- // Remove old state versions, logs, etc.
1270
- const oldKeys = Object.keys(localStorage).filter(key =>
1271
- key.startsWith('app-state-') && key !== this.storeName
1272
- );
1273
- oldKeys.forEach(key => localStorage.removeItem(key));
1274
- }
1275
- }
1276
- ```
1277
-
1278
- #### 2. Corrupted State Data
1279
- ```typescript
1280
- // Handle corrupted data gracefully
1281
- protected override handleMigration(storedData: any, currentVersion: number): any {
1282
- try {
1283
- return super.handleMigration(storedData, currentVersion);
1284
- } catch (error) {
1285
- console.warn('Corrupted state data detected, resetting to defaults');
1286
-
1287
- // Reset to default state
1288
- return {
1289
- data: this.getDefaultState(),
1290
- version: currentVersion
1291
- };
1292
- }
1293
- }
1294
- ```
1295
-
1296
- #### 3. Encryption Issues
1297
- ```typescript
1298
- // Ensure APP_ID is provided for encryption
1299
- @NgModule({
1300
- providers: [
1301
- { provide: APP_ID, useValue: "your-unique-guid-here" }
1302
- ]
1303
- })
1304
- export class AppModule { }
1305
-
1306
- // Handle encryption errors
1307
- protected override encryptData(data: any): string {
1308
- try {
1309
- return super.encryptData(data);
1310
- } catch (error) {
1311
- console.warn('Encryption failed, storing without encryption');
1312
- return JSON.stringify(data);
1313
- }
1314
- }
1315
- ```
1316
-
1317
- ## Related Documentation
1318
-
1319
- - [ComponentStore Documentation](https://ngrx.io/guide/component-store)
1320
- - [Local Storage Service](local-storage/README.md)
1321
- - [HTTP State Service](http-state/README.md)
1322
- - [Architecture Overview](../architecture/README.md)