tas-client
Advanced tools
Comparing version 0.0.668 to 0.0.762
@@ -15,3 +15,3 @@ import { IExperimentationTelemetry } from './IExperimentationTelemetry'; | ||
/** | ||
* A string containing the name for the telemetry option. | ||
* A string containing the name for the features telemetry property. | ||
* This option is implemented in IExperimentation Telemetry. | ||
@@ -21,4 +21,10 @@ * This options posts to the implementation a list of | ||
*/ | ||
telemetryPropertyName: string; | ||
featuresTelemetryPropertyName: string; | ||
/** | ||
* A string containing the name for the assignment context telemetry property. | ||
* This option is implemented in IExperimentation Telemetry. | ||
* This options posts to the implementation the assignment context. | ||
*/ | ||
assignmentContextTelemetryPropertyName: string; | ||
/** | ||
* The name for the telemetry event. This event will be posted every time a flight is queried. | ||
@@ -25,0 +31,0 @@ */ |
{ | ||
"name": "tas-client", | ||
"version": "0.0.668", | ||
"version": "0.0.762", | ||
"description": "This package is intended to be used as an endpoint client to query, refetch, and cache data from the Experimentation service (or any given endpoint). The endpoint result must follow the required structure for experimentation data.", | ||
@@ -10,3 +10,3 @@ "main": "./out/src/index", | ||
"watch": "tsc -watch -p ./", | ||
"test": "npm run compile && mocha --require source-map-support/register out/src/tests/*.js", | ||
"test": "npm run compile && mocha --require source-map-support/register out/test/*.js", | ||
"clean-build-link": "npm install && npm run compile && npm link", | ||
@@ -38,2 +38,3 @@ "format": "prettier --write \"src/**/*.{ts,tsx}\"", | ||
"source-map-support": "^0.5.16", | ||
"ts-node": "^8.10.1", | ||
"tslint": "^5.17.0", | ||
@@ -44,4 +45,4 @@ "tslint-microsoft-contrib": "^6.2.0", | ||
"dependencies": { | ||
"axios": "^0.18.0" | ||
"axios": "^0.19.0" | ||
} | ||
} |
import { IFeatureProvider } from './FeatureProvider/IFeatureProvider'; | ||
import { ExperimentationServiceState } from './ExperimentationServiceBase'; | ||
import { ExperimentationServiceConfig } from '../contracts/ExperimentationServiceConfig'; | ||
@@ -15,5 +14,4 @@ import { ExperimentationServiceAutoPolling } from './ExperimentationServiceAutoPolling'; | ||
protected featureProviders?: IFeatureProvider[]; | ||
protected state: ExperimentationServiceState; | ||
constructor(options: ExperimentationServiceConfig); | ||
protected init(): void; | ||
} |
@@ -5,3 +5,2 @@ "use strict"; | ||
const AxiosHttpClient_1 = require("./Util/AxiosHttpClient"); | ||
const ExperimentationServiceBase_1 = require("./ExperimentationServiceBase"); | ||
const ExperimentationServiceAutoPolling_1 = require("./ExperimentationServiceAutoPolling"); | ||
@@ -20,5 +19,4 @@ /** | ||
: // If no fetch interval is provided, refetch functionality is turned off. | ||
0, options.telemetryPropertyName, options.telemetryEventName, options.storageKey, options.keyValueStorage); | ||
0, options.featuresTelemetryPropertyName, options.assignmentContextTelemetryPropertyName, options.telemetryEventName, options.storageKey, options.keyValueStorage); | ||
this.options = options; | ||
this.state = ExperimentationServiceBase_1.ExperimentationServiceState.None; | ||
this.invokeInit(); | ||
@@ -31,2 +29,3 @@ } | ||
this.addFeatureProvider(new TasApiFeatureProvider_1.TasApiFeatureProvider(new AxiosHttpClient_1.AxiosHttpClient(this.options.endpoint), this.telemetry, this.filterProviders)); | ||
// This will start polling the TAS. | ||
super.init(); | ||
@@ -33,0 +32,0 @@ } |
@@ -5,2 +5,3 @@ import { ExperimentationServiceBase } from './ExperimentationServiceBase'; | ||
import { IKeyValueStorage } from '../contracts/IKeyValueStorage'; | ||
import { FeatureData } from './FeatureProvider/IFeatureProvider'; | ||
/** | ||
@@ -13,3 +14,4 @@ * Implementation of Feature provider that provides a polling feature, where the source can be re-fetched every x time given. | ||
protected refreshRateMs: number; | ||
protected telemetryPropertyName: string; | ||
protected featuresTelemetryPropertyName: string; | ||
protected assignmentContextTelemetryPropertyName: string; | ||
protected telemetryEventName: string; | ||
@@ -19,4 +21,8 @@ protected storageKey?: string | undefined; | ||
private pollingService?; | ||
constructor(telemetry: IExperimentationTelemetry, filterProviders: IExperimentationFilterProvider[], refreshRateMs: number, telemetryPropertyName: string, telemetryEventName: string, storageKey?: string | undefined, storage?: IKeyValueStorage | undefined); | ||
constructor(telemetry: IExperimentationTelemetry, filterProviders: IExperimentationFilterProvider[], refreshRateMs: number, featuresTelemetryPropertyName: string, assignmentContextTelemetryPropertyName: string, telemetryEventName: string, storageKey?: string | undefined, storage?: IKeyValueStorage | undefined); | ||
protected init(): void; | ||
/** | ||
* Wrapper that will reset the polling intervals whenever the feature data is fetched manually. | ||
*/ | ||
protected getFeaturesAsync(overrideInMemoryFeatures?: boolean): Promise<FeatureData>; | ||
} |
@@ -9,8 +9,9 @@ "use strict"; | ||
class ExperimentationServiceAutoPolling extends ExperimentationServiceBase_1.ExperimentationServiceBase { | ||
constructor(telemetry, filterProviders, refreshRateMs, telemetryPropertyName, telemetryEventName, storageKey, storage) { | ||
super(telemetry, telemetryPropertyName, telemetryEventName, storageKey, storage); | ||
constructor(telemetry, filterProviders, refreshRateMs, featuresTelemetryPropertyName, assignmentContextTelemetryPropertyName, telemetryEventName, storageKey, storage) { | ||
super(telemetry, featuresTelemetryPropertyName, assignmentContextTelemetryPropertyName, telemetryEventName, storageKey, storage); | ||
this.telemetry = telemetry; | ||
this.filterProviders = filterProviders; | ||
this.refreshRateMs = refreshRateMs; | ||
this.telemetryPropertyName = telemetryPropertyName; | ||
this.featuresTelemetryPropertyName = featuresTelemetryPropertyName; | ||
this.assignmentContextTelemetryPropertyName = assignmentContextTelemetryPropertyName; | ||
this.telemetryEventName = telemetryEventName; | ||
@@ -34,4 +35,18 @@ this.storageKey = storageKey; | ||
} | ||
/** | ||
* Wrapper that will reset the polling intervals whenever the feature data is fetched manually. | ||
*/ | ||
async getFeaturesAsync(overrideInMemoryFeatures = false) { | ||
if (!this.pollingService) { | ||
return await super.getFeaturesAsync(overrideInMemoryFeatures); | ||
} | ||
else { | ||
this.pollingService.StopPolling(); | ||
let result = await super.getFeaturesAsync(overrideInMemoryFeatures); | ||
this.pollingService.StartPolling(); | ||
return result; | ||
} | ||
} | ||
} | ||
exports.ExperimentationServiceAutoPolling = ExperimentationServiceAutoPolling; | ||
//# sourceMappingURL=ExperimentationServiceAutoPolling.js.map |
import { IExperimentationService } from '../contracts/IExperimentationService'; | ||
import { IExperimentationTelemetry } from '../contracts/IExperimentationTelemetry'; | ||
import { IKeyValueStorage } from '../contracts/IKeyValueStorage'; | ||
import { IFeatureProvider } from './FeatureProvider/IFeatureProvider'; | ||
import { IFeatureProvider, FeatureData } from './FeatureProvider/IFeatureProvider'; | ||
/** | ||
@@ -13,3 +13,4 @@ * Experimentation service to provide functionality of A/B experiments: | ||
protected telemetry: IExperimentationTelemetry; | ||
protected telemetryPropertyName: string; | ||
protected featuresTelemetryPropertyName: string; | ||
protected assignmentContextTelemetryPropertyName: string; | ||
protected telemetryEventName: string; | ||
@@ -19,4 +20,4 @@ protected storageKey?: string | undefined; | ||
protected featureProviders?: IFeatureProvider[]; | ||
protected fetchPromise?: Promise<string[][]>; | ||
protected state: ExperimentationServiceState; | ||
protected fetchPromise?: Promise<FeatureData[]>; | ||
protected featuresConsumed: boolean; | ||
private cachedTelemetryEvents; | ||
@@ -26,3 +27,3 @@ private _features; | ||
private set features(value); | ||
constructor(telemetry: IExperimentationTelemetry, telemetryPropertyName: string, telemetryEventName: string, storageKey?: string | undefined, storage?: IKeyValueStorage | undefined); | ||
constructor(telemetry: IExperimentationTelemetry, featuresTelemetryPropertyName: string, assignmentContextTelemetryPropertyName: string, telemetryEventName: string, storageKey?: string | undefined, storage?: IKeyValueStorage | undefined); | ||
/** | ||
@@ -32,3 +33,3 @@ * Gets all the features from the provider sources (not cache). | ||
*/ | ||
protected getFeaturesAsync(override?: boolean): Promise<string[]>; | ||
protected getFeaturesAsync(overrideInMemoryFeatures?: boolean): Promise<FeatureData>; | ||
/** | ||
@@ -38,4 +39,3 @@ * | ||
*/ | ||
protected updateFeatures(featureResults: string[][], override?: boolean): void; | ||
private featuresChanged; | ||
protected updateFeatures(featureResults: FeatureData[], overrideInMemoryFeatures?: boolean): void; | ||
private getFromCache; | ||
@@ -55,4 +55,2 @@ /** | ||
private PostEventToTelemetry; | ||
private setState; | ||
private isState; | ||
protected invokeInit(): void; | ||
@@ -68,6 +66,1 @@ /** | ||
} | ||
export declare enum ExperimentationServiceState { | ||
None = 0, | ||
Fetching = 1, | ||
FeaturesLoaded = 2 | ||
} |
@@ -11,11 +11,15 @@ "use strict"; | ||
class ExperimentationServiceBase { | ||
constructor(telemetry, telemetryPropertyName, telemetryEventName, storageKey, storage) { | ||
constructor(telemetry, featuresTelemetryPropertyName, assignmentContextTelemetryPropertyName, telemetryEventName, storageKey, storage) { | ||
this.telemetry = telemetry; | ||
this.telemetryPropertyName = telemetryPropertyName; | ||
this.featuresTelemetryPropertyName = featuresTelemetryPropertyName; | ||
this.assignmentContextTelemetryPropertyName = assignmentContextTelemetryPropertyName; | ||
this.telemetryEventName = telemetryEventName; | ||
this.storageKey = storageKey; | ||
this.storage = storage; | ||
this.state = ExperimentationServiceState.None; | ||
this.featuresConsumed = false; | ||
this.cachedTelemetryEvents = []; | ||
this._features = []; | ||
this._features = { | ||
features: [], | ||
assignmentContext: '' | ||
}; | ||
if (!this.storageKey) { | ||
@@ -37,3 +41,4 @@ this.storageKey = 'ABExp.Features'; | ||
if (this.telemetry) { | ||
this.telemetry.setSharedProperty(this.telemetryPropertyName, this.features.join(';')); | ||
this.telemetry.setSharedProperty(this.featuresTelemetryPropertyName, this.features.features.join(';')); | ||
this.telemetry.setSharedProperty(this.assignmentContextTelemetryPropertyName, this.features.assignmentContext); | ||
} | ||
@@ -45,3 +50,3 @@ } | ||
*/ | ||
async getFeaturesAsync(override = false) { | ||
async getFeaturesAsync(overrideInMemoryFeatures = false) { | ||
/** | ||
@@ -51,3 +56,3 @@ * If there's already a fetching promise, there's no need to call it again. | ||
*/ | ||
if (this.isState(ExperimentationServiceState.Fetching) && this.fetchPromise != null) { | ||
if (this.fetchPromise != null) { | ||
await this.fetchPromise; | ||
@@ -57,9 +62,8 @@ return this.features; | ||
if (!this.featureProviders || this.featureProviders.length === 0) { | ||
return Promise.resolve([]); | ||
return Promise.resolve({ | ||
features: [], | ||
assignmentContext: '' | ||
}); | ||
} | ||
/** | ||
* Refetching all data from all providers. | ||
*/ | ||
this.setState(ExperimentationServiceState.Fetching); | ||
/** | ||
* Fetch all from providers. | ||
@@ -72,4 +76,3 @@ */ | ||
this.fetchPromise = undefined; | ||
this.updateFeatures(featureResults, override); | ||
this.setState(ExperimentationServiceState.FeaturesLoaded); | ||
this.updateFeatures(featureResults, overrideInMemoryFeatures); | ||
/** | ||
@@ -85,3 +88,3 @@ * At this point all features have been re-fetched and cache has been updated. | ||
*/ | ||
updateFeatures(featureResults, override = false) { | ||
updateFeatures(featureResults, overrideInMemoryFeatures = false) { | ||
/** | ||
@@ -91,20 +94,18 @@ * if features comes as a null value, that is taken as if there aren't any features active, | ||
*/ | ||
let features = []; | ||
let features = { | ||
features: [], | ||
assignmentContext: '' | ||
}; | ||
for (let result of featureResults) { | ||
for (let feature of result) { | ||
if (!features.includes(feature)) { | ||
features.push(feature); | ||
for (let feature of result.features) { | ||
if (!features.features.includes(feature)) { | ||
features.features.push(feature); | ||
} | ||
} | ||
features.assignmentContext += result.assignmentContext; | ||
} | ||
/** | ||
* If features haven't changed, we return. | ||
*/ | ||
if (!this.featuresChanged(features)) { | ||
return; | ||
} | ||
/** | ||
* Set the obtained feature values to the global features variable. This stores them in memory. | ||
*/ | ||
if (override) { | ||
if (overrideInMemoryFeatures || !this.featuresConsumed) { | ||
this.features = features; | ||
@@ -119,16 +120,2 @@ } | ||
} | ||
featuresChanged(features) { | ||
if (features.length !== this.features.length) { | ||
return true; | ||
} | ||
// Since we have checked the array and removed repeated results before this step, | ||
// we can now just take the old features and check if there's any feature in there that isn't | ||
// included in the new features array. | ||
for (let feature of features) { | ||
if (!this.features.includes(feature)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
async getFromCache() { | ||
@@ -148,11 +135,11 @@ if (!this.storage) { | ||
// If features haven't been loaded, we load the features in the cache, and save them into memory. | ||
if (!this.isState(ExperimentationServiceState.FeaturesLoaded)) { | ||
if (!this.featuresConsumed) { | ||
// Features will only be get from cache once, and only if IsFlightEnabledAsync hasn't been called yet. | ||
let cachedFeatures = await this.getFromCache(); | ||
this.features = cachedFeatures || []; | ||
this.setState(ExperimentationServiceState.FeaturesLoaded); | ||
this.features = cachedFeatures || { features: [], assignmentContext: '' }; | ||
this.featuresConsumed = true; | ||
} | ||
this.PostEventToTelemetry(flight); | ||
// Use memory features to check if a flight is enabled. | ||
return this.features.includes(flight); | ||
return this.features.features.includes(flight); | ||
} | ||
@@ -166,4 +153,5 @@ /** | ||
const features = await this.getFeaturesAsync(true); | ||
this.featuresConsumed = true; | ||
this.PostEventToTelemetry(flight); | ||
return features.includes(flight); | ||
return features.features.includes(flight); | ||
} | ||
@@ -183,13 +171,2 @@ PostEventToTelemetry(flight) { | ||
} | ||
setState(state) { | ||
this.state = state; | ||
} | ||
isState(...states) { | ||
for (let st of states) { | ||
if (this.state === st) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
invokeInit() { | ||
@@ -208,8 +185,2 @@ this.init(); | ||
exports.ExperimentationServiceBase = ExperimentationServiceBase; | ||
var ExperimentationServiceState; | ||
(function (ExperimentationServiceState) { | ||
ExperimentationServiceState[ExperimentationServiceState["None"] = 0] = "None"; | ||
ExperimentationServiceState[ExperimentationServiceState["Fetching"] = 1] = "Fetching"; | ||
ExperimentationServiceState[ExperimentationServiceState["FeaturesLoaded"] = 2] = "FeaturesLoaded"; | ||
})(ExperimentationServiceState = exports.ExperimentationServiceState || (exports.ExperimentationServiceState = {})); | ||
//# sourceMappingURL=ExperimentationServiceBase.js.map |
@@ -1,2 +0,2 @@ | ||
import { IFeatureProvider } from './IFeatureProvider'; | ||
import { IFeatureProvider, FeatureData } from './IFeatureProvider'; | ||
import { IExperimentationTelemetry } from 'src/contracts/IExperimentationTelemetry'; | ||
@@ -18,7 +18,7 @@ /** | ||
*/ | ||
getFeatures(): Promise<string[]>; | ||
getFeatures(): Promise<FeatureData>; | ||
/** | ||
* Fetch method that retrieves asynchronously the required feature data. | ||
*/ | ||
protected abstract fetch(): Promise<string[]>; | ||
protected abstract fetch(): Promise<FeatureData>; | ||
} |
@@ -0,1 +1,5 @@ | ||
export interface FeatureData { | ||
features: string[]; | ||
assignmentContext: string; | ||
} | ||
export interface IFeatureProvider { | ||
@@ -5,3 +9,3 @@ /** | ||
*/ | ||
getFeatures(): Promise<string[]>; | ||
getFeatures(): Promise<FeatureData>; | ||
} |
@@ -5,2 +5,3 @@ import { IExperimentationFilterProvider } from '../../contracts/IExperimentationFilterProvider'; | ||
import { FilteredFeatureProvider } from './FilteredFeatureProvider'; | ||
import { FeatureData } from './IFeatureProvider'; | ||
/** | ||
@@ -17,5 +18,5 @@ * Feature provider implementation that calls the TAS web service to get the most recent active features. | ||
*/ | ||
fetch(): Promise<string[]>; | ||
fetch(): Promise<FeatureData>; | ||
} | ||
export interface FeatureData { | ||
export interface TASFeatureData { | ||
Features: any[]; | ||
@@ -22,0 +23,0 @@ Flights: any[]; |
@@ -48,7 +48,6 @@ "use strict"; | ||
} | ||
// Assignment Context will also be logged to telemetry. | ||
if (responseData.AssignmentContext) { | ||
this.telemetry.setSharedProperty('abexp.assignmentcontext', responseData.AssignmentContext); | ||
} | ||
return features; | ||
return { | ||
features, | ||
assignmentContext: responseData.AssignmentContext | ||
}; | ||
} | ||
@@ -55,0 +54,0 @@ } |
@@ -9,3 +9,3 @@ "use strict"; | ||
get(config) { | ||
return axios_1.default.get(this.endpoint, config); | ||
return axios_1.default.get(this.endpoint, Object.assign(Object.assign({}, config), { proxy: false })); | ||
} | ||
@@ -12,0 +12,0 @@ } |
@@ -8,3 +8,3 @@ export declare class PollingService { | ||
OnPollTick(callback: () => Promise<void>): void; | ||
StartPolling(initialPoll?: boolean): void; | ||
StartPolling(pollImmediately?: boolean): void; | ||
} |
@@ -14,3 +14,3 @@ "use strict"; | ||
} | ||
StartPolling(initialPoll = false) { | ||
StartPolling(pollImmediately = false) { | ||
if (this.intervalHandle) { | ||
@@ -23,3 +23,3 @@ this.StopPolling(); | ||
} | ||
if (initialPoll) { | ||
if (pollImmediately) { | ||
this.onTick().then(() => { return; }).catch(() => { return; }); | ||
@@ -26,0 +26,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47836
19
49
780
+ Addedaxios@0.19.2(transitive)
- Removedaxios@0.18.1(transitive)
- Removedis-buffer@2.0.5(transitive)
Updatedaxios@^0.19.0