|
1 | 1 | import { EventEmitter } from 'node:events'; |
2 | 2 | import { UnleashEvents } from '../events'; |
3 | 3 | import type { |
4 | | - ClientFeaturesDelta, |
| 4 | + ApiResponse, |
5 | 5 | ClientFeaturesResponse, |
6 | 6 | EnhancedFeatureInterface, |
7 | 7 | FeatureInterface, |
@@ -134,7 +134,6 @@ export default class Repository extends EventEmitter implements EventEmitter { |
134 | 134 | mode, |
135 | 135 | eventSource, |
136 | 136 | onSave: this.save.bind(this), |
137 | | - onSaveDelta: this.saveDelta.bind(this), |
138 | 137 | }); |
139 | 138 |
|
140 | 139 | this.setupFetchingStrategyEvents(); |
@@ -207,52 +206,74 @@ export default class Repository extends EventEmitter implements EventEmitter { |
207 | 206 | return new Map(segments.map((segment) => [segment.id, segment])); |
208 | 207 | } |
209 | 208 |
|
210 | | - public async save(response: ClientFeaturesResponse, fromApi: boolean): Promise<void> { |
| 209 | + public async save(response: ApiResponse, fromApi: boolean): Promise<void> { |
211 | 210 | if (this.stopped) { |
212 | 211 | return; |
213 | 212 | } |
214 | 213 | if (fromApi) { |
215 | 214 | this.connected = true; |
216 | | - this.data = this.convertToMap(response.features); |
217 | | - this.segments = this.createSegmentLookup(response.segments); |
| 215 | + this.applyFeatureResponse(response); |
218 | 216 | } else if (!this.connected) { |
219 | 217 | // Only allow bootstrap if not connected |
220 | | - this.data = this.convertToMap(response.features); |
221 | | - this.segments = this.createSegmentLookup(response.segments); |
| 218 | + this.applyFeatureResponse(response); |
222 | 219 | } |
223 | 220 |
|
224 | 221 | this.setReady(); |
225 | | - this.emit(UnleashEvents.Changed, [...response.features]); |
226 | | - await this.storageProvider.set(this.appName, response); |
| 222 | + const newFeatures = Object.values(this.data); |
| 223 | + this.emit(UnleashEvents.Changed, newFeatures); |
| 224 | + |
| 225 | + const clientFeatureResponse: ClientFeaturesResponse = { |
| 226 | + version: 'version' in response ? response.version : 2, |
| 227 | + features: newFeatures, |
| 228 | + segments: [...this.segments.values()], |
| 229 | + }; |
| 230 | + |
| 231 | + await this.storageProvider.set(this.appName, clientFeatureResponse); |
227 | 232 | } |
228 | 233 |
|
229 | | - public async saveDelta(delta: ClientFeaturesDelta): Promise<void> { |
230 | | - if (this.stopped) { |
231 | | - return; |
| 234 | + private applyFeatureResponse(response: ApiResponse): void { |
| 235 | + if ('events' in response) { |
| 236 | + response.events.forEach((event) => { |
| 237 | + switch (event.type) { |
| 238 | + case 'feature-updated': { |
| 239 | + this.data[event.feature.name] = event.feature; |
| 240 | + break; |
| 241 | + } |
| 242 | + case 'feature-removed': { |
| 243 | + delete this.data[event.featureName]; |
| 244 | + break; |
| 245 | + } |
| 246 | + case 'segment-updated': { |
| 247 | + this.segments.set(event.segment.id, event.segment); |
| 248 | + break; |
| 249 | + } |
| 250 | + case 'segment-removed': { |
| 251 | + this.segments.delete(event.segmentId); |
| 252 | + break; |
| 253 | + } |
| 254 | + case 'hydration': { |
| 255 | + this.data = this.convertToMap(event.features); |
| 256 | + this.segments = this.createSegmentLookup(event.segments); |
| 257 | + break; |
| 258 | + } |
| 259 | + default: { |
| 260 | + this.emit( |
| 261 | + UnleashEvents.Warn, |
| 262 | + `Unknown event type received, this may or may not cause features to evaluate incorrectly: ${JSON.stringify(event)}`, |
| 263 | + ); |
| 264 | + break; |
| 265 | + } |
| 266 | + } |
| 267 | + }); |
| 268 | + } else if ('features' in response) { |
| 269 | + this.data = this.convertToMap(response.features); |
| 270 | + this.segments = this.createSegmentLookup(response.segments); |
| 271 | + } else { |
| 272 | + this.emit( |
| 273 | + UnleashEvents.Warn, |
| 274 | + `Unknown response when applying feature response: ${JSON.stringify(response)}`, |
| 275 | + ); |
232 | 276 | } |
233 | | - this.connected = true; |
234 | | - delta.events.forEach((event) => { |
235 | | - if (event.type === 'feature-updated') { |
236 | | - this.data[event.feature.name] = event.feature; |
237 | | - } else if (event.type === 'feature-removed') { |
238 | | - delete this.data[event.featureName]; |
239 | | - } else if (event.type === 'segment-updated') { |
240 | | - this.segments.set(event.segment.id, event.segment); |
241 | | - } else if (event.type === 'segment-removed') { |
242 | | - this.segments.delete(event.segmentId); |
243 | | - } else if (event.type === 'hydration') { |
244 | | - this.data = this.convertToMap(event.features); |
245 | | - this.segments = this.createSegmentLookup(event.segments); |
246 | | - } |
247 | | - }); |
248 | | - |
249 | | - this.setReady(); |
250 | | - this.emit(UnleashEvents.Changed, Object.values(this.data)); |
251 | | - await this.storageProvider.set(this.appName, { |
252 | | - features: Object.values(this.data), |
253 | | - segments: [...this.segments.values()], |
254 | | - version: 0, |
255 | | - }); |
256 | 277 | } |
257 | 278 |
|
258 | 279 | notEmpty(content: ClientFeaturesResponse): boolean { |
|
0 commit comments