Skip to content

Commit deb67c1

Browse files
authoredJul 8, 2024··
feat!: resolver signatures changes for easier overrides, cache exposure (#990)
Signed-off-by: Todd Baert <[email protected]>
1 parent 6311bab commit deb67c1

File tree

2 files changed

+64
-40
lines changed

2 files changed

+64
-40
lines changed
 

Diff for: ‎libs/providers/ofrep-web/src/lib/model/in-memory-cache.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import { FlagValue, ResolutionDetails } from '@openfeature/web-sdk';
22
import { ResolutionError } from './resolution-error';
33

44
/**
5-
* inMemoryCache is a type representing the internal cache of the flags.
5+
* FlagCache is a type representing the internal cache of the flags.
66
*/
7-
export type InMemoryCache = { [key: string]: ResolutionDetails<FlagValue> | ResolutionError };
7+
export type FlagCache = { [key: string]: ResolutionDetails<FlagValue> | ResolutionError };

Diff for: ‎libs/providers/ofrep-web/src/lib/ofrep-web-provider.ts

+62-38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
import {
2+
InvalidContextError,
3+
ParseError,
4+
StandardResolutionReasons,
5+
TargetingKeyMissingError,
6+
} from '@openfeature/core';
7+
import {
8+
EvaluationFailureErrorCode,
9+
EvaluationRequest,
10+
EvaluationResponse,
11+
OFREPApi,
12+
OFREPApiFetchError,
13+
OFREPApiTooManyRequestsError,
14+
OFREPApiUnauthorizedError,
15+
OFREPForbiddenError,
16+
RequestOptions,
17+
handleEvaluationError,
18+
isEvaluationFailureResponse,
19+
isEvaluationSuccessResponse,
20+
} from '@openfeature/ofrep-core';
121
import {
222
ClientProviderEvents,
323
EvaluationContext,
@@ -15,30 +35,10 @@ import {
1535
ResolutionDetails,
1636
TypeMismatchError,
1737
} from '@openfeature/web-sdk';
18-
import { OFREPWebProviderOptions } from './model/ofrep-web-provider-options';
19-
import {
20-
EvaluationFailureErrorCode,
21-
EvaluationRequest,
22-
EvaluationResponse,
23-
handleEvaluationError,
24-
isEvaluationFailureResponse,
25-
isEvaluationSuccessResponse,
26-
OFREPApi,
27-
OFREPApiFetchError,
28-
OFREPApiTooManyRequestsError,
29-
OFREPApiUnauthorizedError,
30-
OFREPForbiddenError,
31-
RequestOptions,
32-
} from '@openfeature/ofrep-core';
33-
import {
34-
InvalidContextError,
35-
ParseError,
36-
StandardResolutionReasons,
37-
TargetingKeyMissingError,
38-
} from '@openfeature/core';
39-
import { isResolutionError, ResolutionError } from './model/resolution-error';
4038
import { BulkEvaluationStatus, EvaluateFlagsResponse } from './model/evaluate-flags-response';
41-
import { InMemoryCache } from './model/in-memory-cache';
39+
import { FlagCache } from './model/in-memory-cache';
40+
import { OFREPWebProviderOptions } from './model/ofrep-web-provider-options';
41+
import { isResolutionError } from './model/resolution-error';
4242

4343
export class OFREPWebProvider implements Provider {
4444
DEFAULT_POLL_INTERVAL = 30000;
@@ -47,19 +47,18 @@ export class OFREPWebProvider implements Provider {
4747
name: 'OpenFeature Remote Evaluation Protocol Web Provider',
4848
};
4949
readonly runsOn = 'client';
50-
events = new OpenFeatureEventEmitter();
51-
hooks?: Hook[] | undefined;
50+
readonly events = new OpenFeatureEventEmitter();
51+
readonly hooks?: Hook[] | undefined;
5252

5353
// logger is the Open Feature logger to use
5454
private _logger?: Logger;
5555
// _options is the options used to configure the provider.
5656
private _options: OFREPWebProviderOptions;
57-
5857
private _ofrepAPI: OFREPApi;
5958
private _etag: string | null;
6059
private _pollingInterval: number;
6160
private _retryPollingAfter: Date | undefined;
62-
private _cache: InMemoryCache = {};
61+
private _flagCache: FlagCache = {};
6362
private _context: EvaluationContext | undefined;
6463
private _pollingIntervalId?: number;
6564

@@ -71,11 +70,18 @@ export class OFREPWebProvider implements Provider {
7170
this._pollingInterval = this._options.pollInterval ?? this.DEFAULT_POLL_INTERVAL;
7271
}
7372

73+
/**
74+
* Returns a shallow copy of the flag cache, which is updated at initialization/context-change/configuration-change once the flags are re-evaluated.
75+
*/
76+
get flagCache(): FlagCache {
77+
return { ...this._flagCache };
78+
}
79+
7480
/**
7581
* Initialize the provider, it will evaluate the flags and start the polling if it is not disabled.
7682
* @param context - the context to use for the evaluation
7783
*/
78-
async initialize?(context?: EvaluationContext | undefined): Promise<void> {
84+
async initialize(context?: EvaluationContext | undefined): Promise<void> {
7985
try {
8086
this._context = context;
8187
await this._evaluateFlags(context);
@@ -92,19 +98,37 @@ export class OFREPWebProvider implements Provider {
9298
throw error;
9399
}
94100
}
95-
96-
resolveBooleanEvaluation(flagKey: string): ResolutionDetails<boolean> {
101+
/* eslint-disable @typescript-eslint/no-unused-vars*/
102+
/* to make overrides easier we keep these unused vars */
103+
resolveBooleanEvaluation(
104+
flagKey: string,
105+
defaultValue: boolean,
106+
context: EvaluationContext,
107+
): ResolutionDetails<boolean> {
97108
return this.evaluate(flagKey, 'boolean');
98109
}
99-
resolveStringEvaluation(flagKey: string): ResolutionDetails<string> {
110+
resolveStringEvaluation(
111+
flagKey: string,
112+
defaultValue: string,
113+
context: EvaluationContext,
114+
): ResolutionDetails<string> {
100115
return this.evaluate(flagKey, 'string');
101116
}
102-
resolveNumberEvaluation(flagKey: string): ResolutionDetails<number> {
117+
resolveNumberEvaluation(
118+
flagKey: string,
119+
defaultValue: number,
120+
context: EvaluationContext,
121+
): ResolutionDetails<number> {
103122
return this.evaluate(flagKey, 'number');
104123
}
105-
resolveObjectEvaluation<T extends JsonValue>(flagKey: string): ResolutionDetails<T> {
124+
resolveObjectEvaluation<T extends JsonValue>(
125+
flagKey: string,
126+
defaultValue: T,
127+
context: EvaluationContext,
128+
): ResolutionDetails<T> {
106129
return this.evaluate(flagKey, 'object');
107130
}
131+
/* eslint-enable @typescript-eslint/no-unused-vars */
108132

109133
/**
110134
* onContextChange is called when the context changes, it will re-evaluate the flags with the new context
@@ -183,7 +207,7 @@ export class OFREPWebProvider implements Provider {
183207
}
184208

185209
const bulkSuccessResp = response.value;
186-
const newCache: InMemoryCache = {};
210+
const newCache: FlagCache = {};
187211

188212
bulkSuccessResp.flags?.forEach((evalResp: EvaluationResponse) => {
189213
if (isEvaluationFailureResponse(evalResp)) {
@@ -203,8 +227,8 @@ export class OFREPWebProvider implements Provider {
203227
};
204228
}
205229
});
206-
const listUpdatedFlags = this._getListUpdatedFlags(this._cache, newCache);
207-
this._cache = newCache;
230+
const listUpdatedFlags = this._getListUpdatedFlags(this._flagCache, newCache);
231+
this._flagCache = newCache;
208232
this._etag = response.httpResponse?.headers.get('etag');
209233
return { status: BulkEvaluationStatus.SUCCESS_WITH_CHANGES, flags: listUpdatedFlags };
210234
} catch (error) {
@@ -222,7 +246,7 @@ export class OFREPWebProvider implements Provider {
222246
* @param newCache
223247
* @private
224248
*/
225-
private _getListUpdatedFlags(oldCache: InMemoryCache, newCache: InMemoryCache): string[] {
249+
private _getListUpdatedFlags(oldCache: FlagCache, newCache: FlagCache): string[] {
226250
const changedKeys: string[] = [];
227251
const oldKeys = Object.keys(oldCache);
228252
const newKeys = Object.keys(newCache);
@@ -251,7 +275,7 @@ export class OFREPWebProvider implements Provider {
251275
* @private
252276
*/
253277
private evaluate<T extends FlagValue>(flagKey: string, type: string): ResolutionDetails<T> {
254-
const resolved = this._cache[flagKey];
278+
const resolved = this._flagCache[flagKey];
255279
if (!resolved) {
256280
throw new FlagNotFoundError(`flag key ${flagKey} not found in cache`);
257281
}

0 commit comments

Comments
 (0)
Please sign in to comment.