@featurevisor/sdk 0.18.0 → 0.20.0
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.
- package/CHANGELOG.md +22 -0
- package/dist/index.js +1 -1
- package/dist/index.js.gz +0 -0
- package/dist/index.js.map +1 -1
- package/lib/conditions.js +9 -0
- package/lib/conditions.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +1 -2
- package/lib/index.js.map +1 -1
- package/lib/{client.d.ts → instance.d.ts} +46 -19
- package/lib/{client.js → instance.js} +163 -56
- package/lib/instance.js.map +1 -0
- package/package.json +3 -3
- package/src/conditions.spec.ts +44 -0
- package/src/conditions.ts +11 -0
- package/src/index.ts +1 -2
- package/src/{createInstance.spec.ts → instance.spec.ts} +3 -2
- package/src/{client.ts → instance.ts} +224 -66
- package/lib/client.js.map +0 -1
- package/lib/createInstance.d.ts +0 -58
- package/lib/createInstance.js +0 -180
- package/lib/createInstance.js.map +0 -1
- package/lib/statuses.d.ts +0 -4
- package/lib/statuses.js +0 -2
- package/lib/statuses.js.map +0 -1
- package/src/createInstance.ts +0 -306
- package/src/statuses.ts +0 -4
- /package/lib/{createInstance.spec.d.ts → instance.spec.d.ts} +0 -0
package/src/createInstance.ts
DELETED
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { DatafileContent, Attributes, StickyFeatures, InitialFeatures } from "@featurevisor/types";
|
|
2
|
-
import { FeaturevisorSDK, ConfigureBucketValue, ActivationCallback } from "./client";
|
|
3
|
-
import { createLogger, Logger } from "./logger";
|
|
4
|
-
import { Emitter } from "./emitter";
|
|
5
|
-
import { Statuses } from "./statuses";
|
|
6
|
-
|
|
7
|
-
export type ReadyCallback = () => void;
|
|
8
|
-
|
|
9
|
-
export interface InstanceOptions {
|
|
10
|
-
// from SdkOptions
|
|
11
|
-
datafile?: DatafileContent | string; // optional here, but not in SdkOptions
|
|
12
|
-
onActivation?: ActivationCallback;
|
|
13
|
-
configureBucketValue?: ConfigureBucketValue;
|
|
14
|
-
|
|
15
|
-
// additions
|
|
16
|
-
datafileUrl?: string;
|
|
17
|
-
onReady?: ReadyCallback;
|
|
18
|
-
handleDatafileFetch?: (datafileUrl: string) => Promise<DatafileContent>;
|
|
19
|
-
logger?: Logger;
|
|
20
|
-
interceptAttributes?: (attributes: Attributes) => Attributes;
|
|
21
|
-
refreshInterval?: number; // seconds
|
|
22
|
-
onRefresh?: () => void;
|
|
23
|
-
onUpdate?: () => void;
|
|
24
|
-
stickyFeatures?: StickyFeatures;
|
|
25
|
-
initialFeatures?: InitialFeatures;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type Event = "ready" | "refresh" | "update" | "activation";
|
|
29
|
-
|
|
30
|
-
// @TODO: consider renaming it to FeaturevisorSDK in next breaking semver
|
|
31
|
-
export interface FeaturevisorInstance {
|
|
32
|
-
/**
|
|
33
|
-
* From FeaturevisorSDK
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
// variation
|
|
37
|
-
getVariation: FeaturevisorSDK["getVariation"];
|
|
38
|
-
getVariationBoolean: FeaturevisorSDK["getVariationBoolean"];
|
|
39
|
-
getVariationInteger: FeaturevisorSDK["getVariationInteger"];
|
|
40
|
-
getVariationDouble: FeaturevisorSDK["getVariationDouble"];
|
|
41
|
-
getVariationString: FeaturevisorSDK["getVariationString"];
|
|
42
|
-
|
|
43
|
-
// activate
|
|
44
|
-
activate: FeaturevisorSDK["activate"];
|
|
45
|
-
activateBoolean: FeaturevisorSDK["activateBoolean"];
|
|
46
|
-
activateInteger: FeaturevisorSDK["activateInteger"];
|
|
47
|
-
activateDouble: FeaturevisorSDK["activateDouble"];
|
|
48
|
-
activateString: FeaturevisorSDK["activateString"];
|
|
49
|
-
|
|
50
|
-
// variable
|
|
51
|
-
getVariable: FeaturevisorSDK["getVariable"];
|
|
52
|
-
getVariableBoolean: FeaturevisorSDK["getVariableBoolean"];
|
|
53
|
-
getVariableInteger: FeaturevisorSDK["getVariableInteger"];
|
|
54
|
-
getVariableDouble: FeaturevisorSDK["getVariableDouble"];
|
|
55
|
-
getVariableString: FeaturevisorSDK["getVariableString"];
|
|
56
|
-
getVariableArray: FeaturevisorSDK["getVariableArray"];
|
|
57
|
-
getVariableObject: FeaturevisorSDK["getVariableObject"];
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Additions
|
|
61
|
-
*/
|
|
62
|
-
setLogLevels: Logger["setLevels"];
|
|
63
|
-
setStickyFeatures: FeaturevisorSDK["setStickyFeatures"];
|
|
64
|
-
|
|
65
|
-
refresh: () => void;
|
|
66
|
-
startRefreshing: () => void;
|
|
67
|
-
stopRefreshing: () => void;
|
|
68
|
-
|
|
69
|
-
addListener: Emitter["addListener"];
|
|
70
|
-
on: Emitter["addListener"];
|
|
71
|
-
removeListener: Emitter["removeListener"];
|
|
72
|
-
off: Emitter["removeListener"];
|
|
73
|
-
removeAllListeners: Emitter["removeAllListeners"];
|
|
74
|
-
|
|
75
|
-
isReady: () => boolean;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function fetchDatafileContent(datafileUrl, options: InstanceOptions): Promise<DatafileContent> {
|
|
79
|
-
if (options.handleDatafileFetch) {
|
|
80
|
-
return options.handleDatafileFetch(datafileUrl);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return fetch(datafileUrl).then((res) => res.json());
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
interface Listeners {
|
|
87
|
-
[key: string]: Function[];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function getInstanceFromSdk(
|
|
91
|
-
sdk: FeaturevisorSDK,
|
|
92
|
-
options: InstanceOptions,
|
|
93
|
-
logger: Logger,
|
|
94
|
-
emitter: Emitter,
|
|
95
|
-
statuses: Statuses,
|
|
96
|
-
): FeaturevisorInstance {
|
|
97
|
-
let intervalId;
|
|
98
|
-
|
|
99
|
-
const on = emitter.addListener.bind(emitter);
|
|
100
|
-
const off = emitter.removeListener.bind(emitter);
|
|
101
|
-
|
|
102
|
-
const instance: FeaturevisorInstance = {
|
|
103
|
-
// variation
|
|
104
|
-
getVariation: sdk.getVariation.bind(sdk),
|
|
105
|
-
getVariationBoolean: sdk.getVariationBoolean.bind(sdk),
|
|
106
|
-
getVariationInteger: sdk.getVariationInteger.bind(sdk),
|
|
107
|
-
getVariationDouble: sdk.getVariationDouble.bind(sdk),
|
|
108
|
-
getVariationString: sdk.getVariationString.bind(sdk),
|
|
109
|
-
|
|
110
|
-
// activate
|
|
111
|
-
activate: sdk.activate.bind(sdk),
|
|
112
|
-
activateBoolean: sdk.activateBoolean.bind(sdk),
|
|
113
|
-
activateInteger: sdk.activateInteger.bind(sdk),
|
|
114
|
-
activateDouble: sdk.activateDouble.bind(sdk),
|
|
115
|
-
activateString: sdk.activateString.bind(sdk),
|
|
116
|
-
|
|
117
|
-
// variable
|
|
118
|
-
getVariable: sdk.getVariable.bind(sdk),
|
|
119
|
-
getVariableBoolean: sdk.getVariableBoolean.bind(sdk),
|
|
120
|
-
getVariableInteger: sdk.getVariableInteger.bind(sdk),
|
|
121
|
-
getVariableDouble: sdk.getVariableDouble.bind(sdk),
|
|
122
|
-
getVariableString: sdk.getVariableString.bind(sdk),
|
|
123
|
-
getVariableArray: sdk.getVariableArray.bind(sdk),
|
|
124
|
-
getVariableObject: sdk.getVariableObject.bind(sdk),
|
|
125
|
-
|
|
126
|
-
// additions
|
|
127
|
-
setLogLevels: logger.setLevels.bind(logger),
|
|
128
|
-
setStickyFeatures: sdk.setStickyFeatures.bind(sdk),
|
|
129
|
-
|
|
130
|
-
// emitter
|
|
131
|
-
on: on,
|
|
132
|
-
addListener: on,
|
|
133
|
-
off: off,
|
|
134
|
-
removeListener: off,
|
|
135
|
-
removeAllListeners: emitter.removeAllListeners.bind(emitter),
|
|
136
|
-
|
|
137
|
-
// refresh
|
|
138
|
-
refresh() {
|
|
139
|
-
logger.debug("refreshing datafile");
|
|
140
|
-
|
|
141
|
-
if (statuses.refreshInProgress) {
|
|
142
|
-
return logger.warn("refresh in progress, skipping");
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (!options.datafileUrl) {
|
|
146
|
-
return logger.error("cannot refresh since `datafileUrl` is not provided");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
statuses.refreshInProgress = true;
|
|
150
|
-
|
|
151
|
-
fetchDatafileContent(options.datafileUrl, options)
|
|
152
|
-
.then((datafile) => {
|
|
153
|
-
const currentRevision = sdk.getRevision();
|
|
154
|
-
const newRevision = datafile.revision;
|
|
155
|
-
const isNotSameRevision = currentRevision !== newRevision;
|
|
156
|
-
|
|
157
|
-
sdk.setDatafile(datafile);
|
|
158
|
-
logger.info("refreshed datafile");
|
|
159
|
-
|
|
160
|
-
emitter.emit("refresh");
|
|
161
|
-
|
|
162
|
-
if (isNotSameRevision) {
|
|
163
|
-
emitter.emit("update");
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
statuses.refreshInProgress = false;
|
|
167
|
-
})
|
|
168
|
-
.catch((e) => {
|
|
169
|
-
logger.error("failed to refresh datafile", { error: e });
|
|
170
|
-
statuses.refreshInProgress = false;
|
|
171
|
-
});
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
startRefreshing() {
|
|
175
|
-
if (!options.datafileUrl) {
|
|
176
|
-
return logger.error("cannot start refreshing since `datafileUrl` is not provided");
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (intervalId) {
|
|
180
|
-
return logger.warn("refreshing has already started");
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (!options.refreshInterval) {
|
|
184
|
-
return logger.warn("no `refreshInterval` option provided");
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
intervalId = setInterval(() => {
|
|
188
|
-
instance.refresh();
|
|
189
|
-
}, options.refreshInterval * 1000);
|
|
190
|
-
},
|
|
191
|
-
|
|
192
|
-
stopRefreshing() {
|
|
193
|
-
if (!intervalId) {
|
|
194
|
-
return logger.warn("refreshing has not started yet");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
clearInterval(intervalId);
|
|
198
|
-
},
|
|
199
|
-
|
|
200
|
-
isReady() {
|
|
201
|
-
return statuses.ready;
|
|
202
|
-
},
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
if (options.datafileUrl && options.refreshInterval) {
|
|
206
|
-
instance.startRefreshing();
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return instance;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const emptyDatafile: DatafileContent = {
|
|
213
|
-
schemaVersion: "1",
|
|
214
|
-
revision: "unknown",
|
|
215
|
-
attributes: [],
|
|
216
|
-
segments: [],
|
|
217
|
-
features: [],
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
export function createInstance(options: InstanceOptions) {
|
|
221
|
-
if (!options.datafile && !options.datafileUrl) {
|
|
222
|
-
throw new Error(
|
|
223
|
-
"Featurevisor SDK instance cannot be created without both `datafile` and `datafileUrl` options",
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const logger = options.logger || createLogger();
|
|
228
|
-
const emitter = new Emitter();
|
|
229
|
-
const statuses: Statuses = {
|
|
230
|
-
ready: false,
|
|
231
|
-
refreshInProgress: false,
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
if (!options.datafileUrl && options.refreshInterval) {
|
|
235
|
-
logger.warn("refreshing datafile requires `datafileUrl` option");
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (options.onReady) {
|
|
239
|
-
emitter.addListener("ready", options.onReady);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (options.onActivation) {
|
|
243
|
-
emitter.addListener("activation", options.onActivation);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (options.onRefresh) {
|
|
247
|
-
emitter.addListener("refresh", options.onRefresh);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (options.onUpdate) {
|
|
251
|
-
emitter.addListener("update", options.onUpdate);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// datafile content is already provided
|
|
255
|
-
if (options.datafile) {
|
|
256
|
-
const sdk = new FeaturevisorSDK({
|
|
257
|
-
datafile: options.datafile,
|
|
258
|
-
onActivation: options.onActivation,
|
|
259
|
-
configureBucketValue: options.configureBucketValue,
|
|
260
|
-
logger,
|
|
261
|
-
emitter,
|
|
262
|
-
interceptAttributes: options.interceptAttributes,
|
|
263
|
-
stickyFeatures: options.stickyFeatures,
|
|
264
|
-
initialFeatures: options.initialFeatures,
|
|
265
|
-
statuses,
|
|
266
|
-
fromInstance: true,
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
statuses.ready = true;
|
|
270
|
-
setTimeout(function () {
|
|
271
|
-
emitter.emit("ready");
|
|
272
|
-
}, 0);
|
|
273
|
-
|
|
274
|
-
return getInstanceFromSdk(sdk, options, logger, emitter, statuses);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// datafile has to be fetched
|
|
278
|
-
const sdk = new FeaturevisorSDK({
|
|
279
|
-
datafile: emptyDatafile,
|
|
280
|
-
onActivation: options.onActivation,
|
|
281
|
-
configureBucketValue: options.configureBucketValue,
|
|
282
|
-
logger,
|
|
283
|
-
emitter,
|
|
284
|
-
interceptAttributes: options.interceptAttributes,
|
|
285
|
-
stickyFeatures: options.stickyFeatures,
|
|
286
|
-
initialFeatures: options.initialFeatures,
|
|
287
|
-
statuses,
|
|
288
|
-
fromInstance: true,
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
if (options.datafileUrl) {
|
|
292
|
-
fetchDatafileContent(options.datafileUrl, options)
|
|
293
|
-
.then((datafile) => {
|
|
294
|
-
sdk.setDatafile(datafile);
|
|
295
|
-
|
|
296
|
-
statuses.ready = true;
|
|
297
|
-
emitter.emit("ready");
|
|
298
|
-
})
|
|
299
|
-
.catch((e) => {
|
|
300
|
-
logger.error("failed to fetch datafile:");
|
|
301
|
-
console.error(e);
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return getInstanceFromSdk(sdk, options, logger, emitter, statuses);
|
|
306
|
-
}
|
package/src/statuses.ts
DELETED
|
File without changes
|