@featurevisor/sdk 0.9.0 → 0.10.1

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.
@@ -1,4 +1,4 @@
1
- import { DatafileContent } from "@featurevisor/types";
1
+ import { DatafileContent, Attributes } from "@featurevisor/types";
2
2
  import { FeaturevisorSDK, ConfigureBucketValue, ActivationCallback } from "./client";
3
3
  import { createLogger, Logger } from "./logger";
4
4
 
@@ -15,6 +15,10 @@ export interface InstanceOptions {
15
15
  onReady?: ReadyCallback;
16
16
  handleDatafileFetch?: (datafileUrl: string) => Promise<DatafileContent>;
17
17
  logger?: Logger;
18
+ interceptAttributes?: (attributes: Attributes) => Attributes;
19
+ refreshInterval?: number; // seconds
20
+ onRefresh?: () => void;
21
+ onUpdate?: () => void;
18
22
  }
19
23
 
20
24
  // @TODO: consider renaming it to FeaturevisorSDK in next breaking semver
@@ -48,16 +52,30 @@ export interface FeaturevisorInstance {
48
52
 
49
53
  /**
50
54
  * Additions
51
- *
52
- * @TODO
53
55
  */
54
- // start: () => void;
55
- // stop: () => void;
56
- // refresh: () => void;
56
+ setLogLevels: Logger["setLevels"];
57
+ refresh: () => void;
58
+ startRefreshing: () => void;
59
+ stopRefreshing: () => void;
57
60
  }
58
61
 
59
- function getInstanceFromSdk(sdk: FeaturevisorSDK, options: InstanceOptions): FeaturevisorInstance {
60
- return {
62
+ function fetchDatafileContent(datafileUrl, options: InstanceOptions): Promise<DatafileContent> {
63
+ if (options.handleDatafileFetch) {
64
+ return options.handleDatafileFetch(datafileUrl);
65
+ }
66
+
67
+ return fetch(datafileUrl).then((res) => res.json());
68
+ }
69
+
70
+ function getInstanceFromSdk(
71
+ sdk: FeaturevisorSDK,
72
+ options: InstanceOptions,
73
+ logger: Logger,
74
+ ): FeaturevisorInstance {
75
+ let intervalId;
76
+ let refreshInProgress = false;
77
+
78
+ const instance: FeaturevisorInstance = {
61
79
  // variation
62
80
  getVariation: sdk.getVariation.bind(sdk),
63
81
  getVariationBoolean: sdk.getVariationBoolean.bind(sdk),
@@ -82,11 +100,78 @@ function getInstanceFromSdk(sdk: FeaturevisorSDK, options: InstanceOptions): Fea
82
100
  getVariableObject: sdk.getVariableObject.bind(sdk),
83
101
 
84
102
  // additions
85
- // @TODO
86
- // start: () => {},
87
- // stop: () => {},
88
- // refresh: () => {},
103
+ setLogLevels: logger.setLevels.bind(logger),
104
+
105
+ refresh() {
106
+ logger.debug("refreshing datafile");
107
+
108
+ if (refreshInProgress) {
109
+ return logger.warn("refresh in progress, skipping");
110
+ }
111
+
112
+ if (!options.datafileUrl) {
113
+ return logger.error("cannot refresh since `datafileUrl` is not provided");
114
+ }
115
+
116
+ refreshInProgress = true;
117
+
118
+ fetchDatafileContent(options.datafileUrl, options)
119
+ .then((datafile) => {
120
+ const currentRevision = sdk.getRevision();
121
+ const newRevision = datafile.revision;
122
+ const isNotSameRevision = currentRevision !== newRevision;
123
+
124
+ sdk.setDatafile(datafile);
125
+ logger.info("refreshed datafile");
126
+
127
+ if (typeof options.onRefresh === "function") {
128
+ options.onRefresh();
129
+ }
130
+
131
+ if (isNotSameRevision && typeof options.onUpdate === "function") {
132
+ options.onUpdate();
133
+ }
134
+
135
+ refreshInProgress = false;
136
+ })
137
+ .catch((e) => {
138
+ logger.error("failed to refresh datafile", { error: e });
139
+ refreshInProgress = false;
140
+ });
141
+ },
142
+
143
+ startRefreshing() {
144
+ if (!options.datafileUrl) {
145
+ return logger.error("cannot start refreshing since `datafileUrl` is not provided");
146
+ }
147
+
148
+ if (intervalId) {
149
+ return logger.warn("refreshing has already started");
150
+ }
151
+
152
+ if (!options.refreshInterval) {
153
+ return logger.warn("no `refreshInterval` option provided");
154
+ }
155
+
156
+ intervalId = setInterval(() => {
157
+ instance.refresh();
158
+ }, options.refreshInterval * 1000);
159
+ },
160
+
161
+ stopRefreshing() {
162
+ if (!intervalId) {
163
+ return logger.warn("refreshing has not started yet");
164
+ }
165
+
166
+ clearInterval(intervalId);
167
+ },
89
168
  };
169
+
170
+ if (options.datafileUrl && options.refreshInterval) {
171
+ instance.startRefreshing();
172
+ }
173
+
174
+ return instance;
90
175
  }
91
176
 
92
177
  const emptyDatafile: DatafileContent = {
@@ -97,14 +182,6 @@ const emptyDatafile: DatafileContent = {
97
182
  features: [],
98
183
  };
99
184
 
100
- function fetchDatafileContent(datafileUrl, options: InstanceOptions): Promise<DatafileContent> {
101
- if (options.handleDatafileFetch) {
102
- return options.handleDatafileFetch(datafileUrl);
103
- }
104
-
105
- return fetch(datafileUrl).then((res) => res.json());
106
- }
107
-
108
185
  export function createInstance(options: InstanceOptions) {
109
186
  if (!options.datafile && !options.datafileUrl) {
110
187
  throw new Error(
@@ -114,6 +191,10 @@ export function createInstance(options: InstanceOptions) {
114
191
 
115
192
  const logger = options.logger || createLogger();
116
193
 
194
+ if (!options.datafileUrl && options.refreshInterval) {
195
+ logger.warn("refreshing datafile requires `datafileUrl` option");
196
+ }
197
+
117
198
  // datafile content is already provided
118
199
  if (options.datafile) {
119
200
  const sdk = new FeaturevisorSDK({
@@ -121,6 +202,7 @@ export function createInstance(options: InstanceOptions) {
121
202
  onActivation: options.onActivation,
122
203
  configureBucketValue: options.configureBucketValue,
123
204
  logger,
205
+ interceptAttributes: options.interceptAttributes,
124
206
  });
125
207
 
126
208
  if (typeof options.onReady === "function") {
@@ -131,7 +213,7 @@ export function createInstance(options: InstanceOptions) {
131
213
  }, 0);
132
214
  }
133
215
 
134
- return getInstanceFromSdk(sdk, options);
216
+ return getInstanceFromSdk(sdk, options, logger);
135
217
  }
136
218
 
137
219
  // datafile has to be fetched
@@ -140,6 +222,7 @@ export function createInstance(options: InstanceOptions) {
140
222
  onActivation: options.onActivation,
141
223
  configureBucketValue: options.configureBucketValue,
142
224
  logger,
225
+ interceptAttributes: options.interceptAttributes,
143
226
  });
144
227
 
145
228
  if (options.datafileUrl) {
@@ -152,10 +235,10 @@ export function createInstance(options: InstanceOptions) {
152
235
  }
153
236
  })
154
237
  .catch((e) => {
155
- console.error("Featurevisor failed to fetch datafile:");
238
+ logger.error("failed to fetch datafile:");
156
239
  console.error(e);
157
240
  });
158
241
  }
159
242
 
160
- return getInstanceFromSdk(sdk, options);
243
+ return getInstanceFromSdk(sdk, options, logger);
161
244
  }