@flipfeatureflag/core 0.1.4 → 0.1.6

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/dist/index.d.mts CHANGED
@@ -102,6 +102,10 @@ declare class FlipFlagClient {
102
102
  private metricsTimer?;
103
103
  private metricsBuffer;
104
104
  private context;
105
+ private started;
106
+ private refreshInFlight?;
107
+ private pendingFlagKeys;
108
+ private pendingFullRefresh;
105
109
  constructor(options: FlipFlagClientOptions);
106
110
  start(): Promise<void>;
107
111
  stop(): void;
package/dist/index.d.ts CHANGED
@@ -102,6 +102,10 @@ declare class FlipFlagClient {
102
102
  private metricsTimer?;
103
103
  private metricsBuffer;
104
104
  private context;
105
+ private started;
106
+ private refreshInFlight?;
107
+ private pendingFlagKeys;
108
+ private pendingFullRefresh;
105
109
  constructor(options: FlipFlagClientOptions);
106
110
  start(): Promise<void>;
107
111
  stop(): void;
package/dist/index.js CHANGED
@@ -139,6 +139,9 @@ var FlipFlagClient = class {
139
139
  this.status = { ready: false };
140
140
  this.evaluations = /* @__PURE__ */ new Map();
141
141
  this.metricsBuffer = new MetricsBuffer();
142
+ this.started = false;
143
+ this.pendingFlagKeys = /* @__PURE__ */ new Set();
144
+ this.pendingFullRefresh = false;
142
145
  if (!options.url) {
143
146
  throw new Error("flipFeatureFlag SDK requires url");
144
147
  }
@@ -159,6 +162,10 @@ var FlipFlagClient = class {
159
162
  });
160
163
  }
161
164
  async start() {
165
+ if (this.started) {
166
+ return;
167
+ }
168
+ this.started = true;
162
169
  await this.refresh();
163
170
  if (!this.options.disableRefresh) {
164
171
  this.refreshTimer = setInterval(() => {
@@ -180,6 +187,7 @@ var FlipFlagClient = class {
180
187
  clearInterval(this.metricsTimer);
181
188
  this.metricsTimer = void 0;
182
189
  }
190
+ this.started = false;
183
191
  }
184
192
  on(event, listener) {
185
193
  this.emitter.on(event, listener);
@@ -238,22 +246,44 @@ var FlipFlagClient = class {
238
246
  return evaluation;
239
247
  }
240
248
  async refresh(flagKeys) {
241
- try {
242
- const response = await this.http.evaluate({
243
- env: this.options.env,
244
- context: this.context,
245
- flagKeys
246
- });
247
- this.applyEvaluate(response);
248
- if (!this.status.ready) {
249
- this.status.ready = true;
250
- this.emitter.emit("ready");
249
+ if (flagKeys && flagKeys.length > 0) {
250
+ for (const key of flagKeys) {
251
+ this.pendingFlagKeys.add(key);
251
252
  }
252
- this.emitter.emit("update");
253
- } catch (error) {
254
- this.status.error = error;
255
- this.emitter.emit("error", error);
253
+ } else {
254
+ this.pendingFullRefresh = true;
255
+ }
256
+ if (this.refreshInFlight) {
257
+ return this.refreshInFlight;
256
258
  }
259
+ this.refreshInFlight = (async () => {
260
+ const shouldFull = this.pendingFullRefresh;
261
+ const keys = shouldFull ? void 0 : Array.from(this.pendingFlagKeys);
262
+ this.pendingFlagKeys.clear();
263
+ this.pendingFullRefresh = false;
264
+ try {
265
+ const response = await this.http.evaluate({
266
+ env: this.options.env,
267
+ context: this.context,
268
+ flagKeys: keys
269
+ });
270
+ this.applyEvaluate(response);
271
+ if (!this.status.ready) {
272
+ this.status.ready = true;
273
+ this.emitter.emit("ready");
274
+ }
275
+ this.emitter.emit("update");
276
+ } catch (error) {
277
+ this.status.error = error;
278
+ this.emitter.emit("error", error);
279
+ } finally {
280
+ this.refreshInFlight = void 0;
281
+ }
282
+ if (this.pendingFullRefresh || this.pendingFlagKeys.size > 0) {
283
+ return this.refresh();
284
+ }
285
+ })();
286
+ return this.refreshInFlight;
257
287
  }
258
288
  applyEvaluate(response) {
259
289
  this.evaluations.clear();
package/dist/index.mjs CHANGED
@@ -113,6 +113,9 @@ var FlipFlagClient = class {
113
113
  this.status = { ready: false };
114
114
  this.evaluations = /* @__PURE__ */ new Map();
115
115
  this.metricsBuffer = new MetricsBuffer();
116
+ this.started = false;
117
+ this.pendingFlagKeys = /* @__PURE__ */ new Set();
118
+ this.pendingFullRefresh = false;
116
119
  if (!options.url) {
117
120
  throw new Error("flipFeatureFlag SDK requires url");
118
121
  }
@@ -133,6 +136,10 @@ var FlipFlagClient = class {
133
136
  });
134
137
  }
135
138
  async start() {
139
+ if (this.started) {
140
+ return;
141
+ }
142
+ this.started = true;
136
143
  await this.refresh();
137
144
  if (!this.options.disableRefresh) {
138
145
  this.refreshTimer = setInterval(() => {
@@ -154,6 +161,7 @@ var FlipFlagClient = class {
154
161
  clearInterval(this.metricsTimer);
155
162
  this.metricsTimer = void 0;
156
163
  }
164
+ this.started = false;
157
165
  }
158
166
  on(event, listener) {
159
167
  this.emitter.on(event, listener);
@@ -212,22 +220,44 @@ var FlipFlagClient = class {
212
220
  return evaluation;
213
221
  }
214
222
  async refresh(flagKeys) {
215
- try {
216
- const response = await this.http.evaluate({
217
- env: this.options.env,
218
- context: this.context,
219
- flagKeys
220
- });
221
- this.applyEvaluate(response);
222
- if (!this.status.ready) {
223
- this.status.ready = true;
224
- this.emitter.emit("ready");
223
+ if (flagKeys && flagKeys.length > 0) {
224
+ for (const key of flagKeys) {
225
+ this.pendingFlagKeys.add(key);
225
226
  }
226
- this.emitter.emit("update");
227
- } catch (error) {
228
- this.status.error = error;
229
- this.emitter.emit("error", error);
227
+ } else {
228
+ this.pendingFullRefresh = true;
229
+ }
230
+ if (this.refreshInFlight) {
231
+ return this.refreshInFlight;
230
232
  }
233
+ this.refreshInFlight = (async () => {
234
+ const shouldFull = this.pendingFullRefresh;
235
+ const keys = shouldFull ? void 0 : Array.from(this.pendingFlagKeys);
236
+ this.pendingFlagKeys.clear();
237
+ this.pendingFullRefresh = false;
238
+ try {
239
+ const response = await this.http.evaluate({
240
+ env: this.options.env,
241
+ context: this.context,
242
+ flagKeys: keys
243
+ });
244
+ this.applyEvaluate(response);
245
+ if (!this.status.ready) {
246
+ this.status.ready = true;
247
+ this.emitter.emit("ready");
248
+ }
249
+ this.emitter.emit("update");
250
+ } catch (error) {
251
+ this.status.error = error;
252
+ this.emitter.emit("error", error);
253
+ } finally {
254
+ this.refreshInFlight = void 0;
255
+ }
256
+ if (this.pendingFullRefresh || this.pendingFlagKeys.size > 0) {
257
+ return this.refresh();
258
+ }
259
+ })();
260
+ return this.refreshInFlight;
231
261
  }
232
262
  applyEvaluate(response) {
233
263
  this.evaluations.clear();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flipfeatureflag/core",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "flipFeatureFlag core SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
package/src/client.ts CHANGED
@@ -26,6 +26,10 @@ export class FlipFlagClient {
26
26
  private metricsTimer?: ReturnType<typeof setInterval>;
27
27
  private metricsBuffer = new MetricsBuffer();
28
28
  private context: SdkContext;
29
+ private started = false;
30
+ private refreshInFlight?: Promise<void>;
31
+ private pendingFlagKeys = new Set<string>();
32
+ private pendingFullRefresh = false;
29
33
 
30
34
  constructor(options: FlipFlagClientOptions) {
31
35
  if (!options.url) {
@@ -52,6 +56,10 @@ export class FlipFlagClient {
52
56
  }
53
57
 
54
58
  async start(): Promise<void> {
59
+ if (this.started) {
60
+ return;
61
+ }
62
+ this.started = true;
55
63
  await this.refresh();
56
64
 
57
65
  if (!this.options.disableRefresh) {
@@ -76,6 +84,7 @@ export class FlipFlagClient {
76
84
  clearInterval(this.metricsTimer);
77
85
  this.metricsTimer = undefined;
78
86
  }
87
+ this.started = false;
79
88
  }
80
89
 
81
90
  on(event: FlipFlagEvent, listener: FlipFlagListener) {
@@ -145,25 +154,52 @@ export class FlipFlagClient {
145
154
  return evaluation;
146
155
  }
147
156
 
148
- private async refresh(flagKeys?: string[]) {
149
- try {
150
- const response = await this.http.evaluate({
151
- env: this.options.env,
152
- context: this.context,
153
- flagKeys,
154
- });
155
- this.applyEvaluate(response);
156
-
157
- if (!this.status.ready) {
158
- this.status.ready = true;
159
- this.emitter.emit("ready");
157
+ private async refresh(flagKeys?: string[]): Promise<void> {
158
+ if (flagKeys && flagKeys.length > 0) {
159
+ for (const key of flagKeys) {
160
+ this.pendingFlagKeys.add(key);
160
161
  }
162
+ } else {
163
+ this.pendingFullRefresh = true;
164
+ }
161
165
 
162
- this.emitter.emit("update");
163
- } catch (error) {
164
- this.status.error = error as Error;
165
- this.emitter.emit("error", error);
166
+ if (this.refreshInFlight) {
167
+ return this.refreshInFlight;
166
168
  }
169
+
170
+ this.refreshInFlight = (async () => {
171
+ const shouldFull = this.pendingFullRefresh;
172
+ const keys = shouldFull ? undefined : Array.from(this.pendingFlagKeys);
173
+ this.pendingFlagKeys.clear();
174
+ this.pendingFullRefresh = false;
175
+
176
+ try {
177
+ const response = await this.http.evaluate({
178
+ env: this.options.env,
179
+ context: this.context,
180
+ flagKeys: keys,
181
+ });
182
+ this.applyEvaluate(response);
183
+
184
+ if (!this.status.ready) {
185
+ this.status.ready = true;
186
+ this.emitter.emit("ready");
187
+ }
188
+
189
+ this.emitter.emit("update");
190
+ } catch (error) {
191
+ this.status.error = error as Error;
192
+ this.emitter.emit("error", error);
193
+ } finally {
194
+ this.refreshInFlight = undefined;
195
+ }
196
+
197
+ if (this.pendingFullRefresh || this.pendingFlagKeys.size > 0) {
198
+ return this.refresh();
199
+ }
200
+ })();
201
+
202
+ return this.refreshInFlight;
167
203
  }
168
204
 
169
205
  private applyEvaluate(response: SdkEvaluateResponse) {