@getstanza/core
Advanced tools
Comparing version 0.0.5-beta to 0.0.6-beta
87
index.js
@@ -78,3 +78,2 @@ /****************************************************************************** | ||
let localStateProvider; | ||
let enablementNumberGenerator; | ||
let enablementNumber = 100; | ||
@@ -88,4 +87,4 @@ const featureChanges = new StanzaChangeTarget(); | ||
} | ||
enablementNumberGenerator = (_a = config.enablementNumberGenerator) !== null && _a !== void 0 ? _a : getEnablementNumberSimple; | ||
stanzaConfig = Object.assign(Object.assign({}, config), { | ||
enablementNumberGenerator: (_a = config.enablementNumberGenerator) !== null && _a !== void 0 ? _a : getEnablementNumberSimple, | ||
contextConfigs: config.contextConfigs.reduce(groupBy('name', ({ | ||
@@ -98,2 +97,3 @@ features | ||
localStateProvider = provider; | ||
localStateProvider.init(config.contextConfigs); | ||
getEnablementNumber().catch(e => { | ||
@@ -117,3 +117,3 @@ console.warn('Failed to get enablement number', e); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return enablementNumberGenerator().then(nr => { | ||
return stanzaConfig.enablementNumberGenerator().then(nr => { | ||
enablementNumber = nr; | ||
@@ -206,2 +206,27 @@ enablementNumberChanges.dispatchChange(nr); | ||
/** | ||
* Creates a new promise that will resolve with the same value as the original promise or time out if more than `timeout` milliseconds elapses. | ||
* @param timeout - number of milliseconds to pass before a given promise should time out | ||
* @param timeoutMessage - a message to pass to an error that gets thrown when the promise times out | ||
* @param aPromise - a promise to add timeout behavior to | ||
*/ | ||
const withTimeout = (timeout, timeoutMessage, aPromise) => __awaiter(void 0, void 0, void 0, function* () { | ||
let timeoutHandle; | ||
try { | ||
return yield Promise.race([aPromise, new Promise((_resolve, reject) => { | ||
timeoutHandle = setTimeout(() => { | ||
reject(new TimeoutError(timeout, timeoutMessage)); | ||
}, timeout); | ||
})]); | ||
} finally { | ||
clearTimeout(timeoutHandle); | ||
} | ||
}); | ||
class TimeoutError extends Error { | ||
constructor(timeout, message) { | ||
super(message); | ||
this.timeout = timeout; | ||
} | ||
} | ||
const apiFeatureStateToFeatureState = refreshTime => api => Object.assign({ | ||
@@ -213,3 +238,3 @@ featureName: api.name, | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const apiFeatureStates = yield fetchApiFeaturesStates(features); | ||
const apiFeatureStates = yield withTimeout(1000, '', fetchApiFeaturesStates(features)).catch(() => []); | ||
const refreshTime = Date.now(); | ||
@@ -236,7 +261,7 @@ const groupedFeatures = apiFeatureStates.map(apiFeatureStateToFeatureState(refreshTime)).reduce(groupBy('featureName', identity), {}); | ||
function getFeatureStatesStale(features) { | ||
const stateProvider = getStateProvider(); | ||
const featureStates = features.map(name => { | ||
var _a; | ||
return (_a = getStateProvider().getFeatureState(name)) !== null && _a !== void 0 ? _a : createFeatureState(name); | ||
return (_a = stateProvider.getFeatureState(name)) !== null && _a !== void 0 ? _a : createFeatureState(name); | ||
}); | ||
const stateProvider = getStateProvider(); | ||
featureStates.forEach(featureState => { | ||
@@ -264,8 +289,10 @@ stateProvider.setFeatureState(featureState); | ||
function featureStatesEqual(o, f) { | ||
return o.featureName === f.featureName && o.enabledPercent === f.enabledPercent && o.messageEnabled === f.messageEnabled && o.actionCodeEnabled === f.actionCodeEnabled && o.messageDisabled === f.messageDisabled && o.actionCodeDisabled === f.actionCodeDisabled; | ||
} | ||
function startPollingFeatureStateUpdates() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const stateProvider = getStateProvider(); | ||
stateProvider.addChangeListener(({ | ||
newValue | ||
}) => { | ||
featureChanges.dispatchChange(newValue); | ||
}); | ||
while (true) { | ||
@@ -283,10 +310,3 @@ yield pollFeatureStateUpdates(); | ||
}) => featureName); | ||
const newFeaturesStates = yield getFeatureStatesHot(features); | ||
const oldFeatureStatesMap = featureStates.reduce(groupBy('featureName', identity), {}); | ||
newFeaturesStates.filter(newFeaturesState => { | ||
const oldFeatureState = oldFeatureStatesMap[newFeaturesState.featureName]; | ||
return oldFeatureState == null || !featureStatesEqual(newFeaturesState, oldFeatureState); | ||
}).forEach(newFeaturesState => { | ||
featureChanges.dispatchChange(newFeaturesState); | ||
}); | ||
yield getFeatureStatesHot(features); | ||
}); | ||
@@ -305,18 +325,47 @@ } | ||
const localState = new Map(); | ||
let initialized = false; | ||
function setFeatureState(featureState) { | ||
assertInitialized(); | ||
const { | ||
featureName | ||
} = featureState; | ||
const oldValue = localState.get(featureName); | ||
if (oldValue === featureState) { | ||
return; | ||
} | ||
localState.set(featureName, featureState); | ||
featureStateChangeEmitter.dispatchChange({ | ||
oldValue, | ||
newValue: featureState | ||
}); | ||
} | ||
function getFeatureState(name) { | ||
assertInitialized(); | ||
return localState.get(name !== null && name !== void 0 ? name : ''); | ||
} | ||
function getAllFeatureStates() { | ||
assertInitialized(); | ||
return Array.from(localState.values()); | ||
} | ||
function assertInitialized() { | ||
if (!initialized) { | ||
throw new Error('Local Storage State Provider is not initialized. Please invoke `init` method before using the provider.'); | ||
} | ||
} | ||
const featureStateChangeEmitter = new StanzaChangeTarget(); | ||
return { | ||
init: () => { | ||
initialized = true; | ||
}, | ||
getFeatureState, | ||
setFeatureState, | ||
getAllFeatureStates | ||
getAllFeatureStates, | ||
addChangeListener: (...args) => { | ||
assertInitialized(); | ||
return featureStateChangeEmitter.addChangeListener(...args); | ||
}, | ||
removeChangeListener: (...args) => { | ||
assertInitialized(); | ||
featureStateChangeEmitter.removeChangeListener(...args); | ||
} | ||
}; | ||
@@ -323,0 +372,0 @@ }; |
{ | ||
"name": "@getstanza/core", | ||
"version": "0.0.5-beta", | ||
"version": "0.0.6-beta", | ||
"type": "module", | ||
@@ -5,0 +5,0 @@ "description": "Stanza core JS features", |
@@ -5,7 +5,5 @@ export interface ApiFeatureState { | ||
enabledPercent: number; | ||
actionCodeEnabled?: number; | ||
messageEnabled?: string; | ||
actionCodeDisabled?: number; | ||
messageDisabled?: string; | ||
}; | ||
} |
@@ -10,3 +10,3 @@ import { StanzaChangeTarget } from './eventEmitter'; | ||
refreshSeconds?: number; | ||
enablementNumberGenerator?: () => Promise<number>; | ||
enablementNumberGenerator: () => Promise<number>; | ||
contextConfigs: Record<string, { | ||
@@ -13,0 +13,0 @@ features: string[]; |
export interface FeatureState { | ||
featureName: string; | ||
enabledPercent: number; | ||
actionCodeEnabled?: number; | ||
messageEnabled?: string; | ||
actionCodeDisabled?: number; | ||
messageDisabled?: string; | ||
lastRefreshTime: number; | ||
} |
import { type FeatureState } from './featureState'; | ||
type LocalStateChangeListener = (event: { | ||
oldValue: FeatureState | undefined; | ||
newValue: FeatureState; | ||
}) => void; | ||
export interface LocalStateProvider { | ||
init: (config: unknown) => void; | ||
setFeatureState: (context: FeatureState) => void; | ||
getFeatureState: (name?: string) => FeatureState | undefined; | ||
getFeatureState: (name: string) => FeatureState | undefined; | ||
getAllFeatureStates: () => FeatureState[]; | ||
addChangeListener: (callback: LocalStateChangeListener) => () => void; | ||
removeChangeListener: (callback: LocalStateChangeListener) => void; | ||
} | ||
export {}; |
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
35682
28
937