@rolloutctrl/js-sdk 0.0.4 → 0.0.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
@@ -1,7 +1,9 @@
1
1
  import { FeatureFlagEnvironment, Action, EvaluationContext, EvaluationResult } from '@rolloutctrl/evaluator';
2
2
 
3
3
  interface FlagConfig extends FeatureFlagEnvironment {
4
+ id: string;
4
5
  key: string;
6
+ featureFlagEnvironmentId: string;
5
7
  }
6
8
  interface Configuration {
7
9
  projectId: string;
@@ -22,12 +24,21 @@ interface StorageAdapter {
22
24
  set(configuration: Configuration): Promise<void>;
23
25
  clear(): Promise<void>;
24
26
  }
27
+ type MetricType = 'FLAG_EVALUATION' | 'FLAG_ENABLED' | 'FLAG_DISABLED' | 'STRATEGY_MATCH' | 'VARIANT_EXPOSURE';
28
+ interface MetricEvent {
29
+ featureFlagEnvironmentId: string;
30
+ featureFlagId: string;
31
+ type: MetricType;
32
+ strategyId?: string;
33
+ variantId?: string;
34
+ }
25
35
  interface RolloutCtrlOptions {
26
36
  sdkKey: string;
27
37
  environment: string;
28
38
  apiUrl?: string;
29
39
  refreshInterval?: number;
30
40
  requestTimeout?: number;
41
+ enableMetrics?: boolean;
31
42
  bootstrap?: Configuration;
32
43
  storage?: StorageAdapter;
33
44
  }
@@ -43,8 +54,10 @@ declare class RolloutCtrlClient {
43
54
  private readonly repository;
44
55
  private readonly evaluatorManager;
45
56
  private readonly updateProvider;
57
+ private readonly metricsQueue;
46
58
  private readonly subscribers;
47
59
  private isInitialized;
60
+ private readonly trackedEvaluations;
48
61
  private readonly readyPromise;
49
62
  private resolveReady;
50
63
  private rejectReady;
@@ -61,6 +74,7 @@ declare class RolloutCtrlClient {
61
74
  isEnabled(flagKey: string, context?: EvaluationContext): boolean;
62
75
  evaluate(flagKey: string, context?: EvaluationContext): EvaluationResult;
63
76
  getVariant(flagKey: string, context?: EvaluationContext): VariantResult;
77
+ private trackEvaluation;
64
78
  can(actionKey: string, context?: EvaluationContext): boolean;
65
79
  }
66
80
 
@@ -130,4 +144,19 @@ declare class LocalStorageAdapter implements StorageAdapter {
130
144
  clear(): Promise<void>;
131
145
  }
132
146
 
133
- export { type Configuration, type ConfigurationRepository, type Evaluator, EvaluatorManager, type FlagConfig, HttpConfigurationRepository, LocalStorageAdapter, PollingUpdateProvider, RolloutCtrlClient, type RolloutCtrlOptions, SseUpdateProvider, type StorageAdapter, type UpdateProvider, type VariantResult, createEvaluator };
147
+ declare class MetricsQueue {
148
+ private readonly apiUrl;
149
+ private readonly sdkKey;
150
+ private readonly requestTimeout;
151
+ private queue;
152
+ private flushTimer;
153
+ constructor(apiUrl: string, sdkKey: string, requestTimeout: number);
154
+ start(): void;
155
+ stop(): void;
156
+ push(event: MetricEvent): void;
157
+ flush(): Promise<void>;
158
+ private flushWithRetry;
159
+ private sendBatch;
160
+ }
161
+
162
+ export { type Configuration, type ConfigurationRepository, type Evaluator, EvaluatorManager, type FlagConfig, HttpConfigurationRepository, LocalStorageAdapter, type MetricEvent, type MetricType, MetricsQueue, PollingUpdateProvider, RolloutCtrlClient, type RolloutCtrlOptions, SseUpdateProvider, type StorageAdapter, type UpdateProvider, type VariantResult, createEvaluator };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { FeatureFlagEnvironment, Action, EvaluationContext, EvaluationResult } from '@rolloutctrl/evaluator';
2
2
 
3
3
  interface FlagConfig extends FeatureFlagEnvironment {
4
+ id: string;
4
5
  key: string;
6
+ featureFlagEnvironmentId: string;
5
7
  }
6
8
  interface Configuration {
7
9
  projectId: string;
@@ -22,12 +24,21 @@ interface StorageAdapter {
22
24
  set(configuration: Configuration): Promise<void>;
23
25
  clear(): Promise<void>;
24
26
  }
27
+ type MetricType = 'FLAG_EVALUATION' | 'FLAG_ENABLED' | 'FLAG_DISABLED' | 'STRATEGY_MATCH' | 'VARIANT_EXPOSURE';
28
+ interface MetricEvent {
29
+ featureFlagEnvironmentId: string;
30
+ featureFlagId: string;
31
+ type: MetricType;
32
+ strategyId?: string;
33
+ variantId?: string;
34
+ }
25
35
  interface RolloutCtrlOptions {
26
36
  sdkKey: string;
27
37
  environment: string;
28
38
  apiUrl?: string;
29
39
  refreshInterval?: number;
30
40
  requestTimeout?: number;
41
+ enableMetrics?: boolean;
31
42
  bootstrap?: Configuration;
32
43
  storage?: StorageAdapter;
33
44
  }
@@ -43,8 +54,10 @@ declare class RolloutCtrlClient {
43
54
  private readonly repository;
44
55
  private readonly evaluatorManager;
45
56
  private readonly updateProvider;
57
+ private readonly metricsQueue;
46
58
  private readonly subscribers;
47
59
  private isInitialized;
60
+ private readonly trackedEvaluations;
48
61
  private readonly readyPromise;
49
62
  private resolveReady;
50
63
  private rejectReady;
@@ -61,6 +74,7 @@ declare class RolloutCtrlClient {
61
74
  isEnabled(flagKey: string, context?: EvaluationContext): boolean;
62
75
  evaluate(flagKey: string, context?: EvaluationContext): EvaluationResult;
63
76
  getVariant(flagKey: string, context?: EvaluationContext): VariantResult;
77
+ private trackEvaluation;
64
78
  can(actionKey: string, context?: EvaluationContext): boolean;
65
79
  }
66
80
 
@@ -130,4 +144,19 @@ declare class LocalStorageAdapter implements StorageAdapter {
130
144
  clear(): Promise<void>;
131
145
  }
132
146
 
133
- export { type Configuration, type ConfigurationRepository, type Evaluator, EvaluatorManager, type FlagConfig, HttpConfigurationRepository, LocalStorageAdapter, PollingUpdateProvider, RolloutCtrlClient, type RolloutCtrlOptions, SseUpdateProvider, type StorageAdapter, type UpdateProvider, type VariantResult, createEvaluator };
147
+ declare class MetricsQueue {
148
+ private readonly apiUrl;
149
+ private readonly sdkKey;
150
+ private readonly requestTimeout;
151
+ private queue;
152
+ private flushTimer;
153
+ constructor(apiUrl: string, sdkKey: string, requestTimeout: number);
154
+ start(): void;
155
+ stop(): void;
156
+ push(event: MetricEvent): void;
157
+ flush(): Promise<void>;
158
+ private flushWithRetry;
159
+ private sendBatch;
160
+ }
161
+
162
+ export { type Configuration, type ConfigurationRepository, type Evaluator, EvaluatorManager, type FlagConfig, HttpConfigurationRepository, LocalStorageAdapter, type MetricEvent, type MetricType, MetricsQueue, PollingUpdateProvider, RolloutCtrlClient, type RolloutCtrlOptions, SseUpdateProvider, type StorageAdapter, type UpdateProvider, type VariantResult, createEvaluator };
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  EvaluatorManager: () => EvaluatorManager,
24
24
  HttpConfigurationRepository: () => HttpConfigurationRepository,
25
25
  LocalStorageAdapter: () => LocalStorageAdapter,
26
+ MetricsQueue: () => MetricsQueue,
26
27
  PollingUpdateProvider: () => PollingUpdateProvider,
27
28
  RolloutCtrlClient: () => RolloutCtrlClient,
28
29
  SseUpdateProvider: () => SseUpdateProvider,
@@ -171,7 +172,12 @@ var HttpConfigurationRepository = class {
171
172
  return this.normalizeConfiguration(raw);
172
173
  }
173
174
  normalizeConfiguration(raw) {
174
- const flags = Array.isArray(raw.flags) ? raw.flags : Object.entries(raw.flags ?? {}).map(([key, value]) => ({ key, ...value }));
175
+ const flags = Array.isArray(raw.flags) ? raw.flags : Object.entries(raw.flags ?? {}).map(([key, value]) => ({
176
+ key,
177
+ ...value,
178
+ id: value._featureFlagId ?? value.id ?? "",
179
+ featureFlagEnvironmentId: value._featureFlagEnvironmentId ?? ""
180
+ }));
175
181
  const actions = Array.isArray(raw.actions) ? raw.actions : Object.values(raw.actions ?? {});
176
182
  return {
177
183
  projectId: raw.project?.id ?? raw.projectId ?? "",
@@ -251,6 +257,74 @@ var SseUpdateProvider = class {
251
257
  }
252
258
  };
253
259
 
260
+ // src/metrics.ts
261
+ var FLUSH_INTERVAL_MS = 3e4;
262
+ var FLUSH_BATCH_SIZE = 100;
263
+ var MAX_RETRIES = 3;
264
+ var MetricsQueue = class {
265
+ constructor(apiUrl, sdkKey, requestTimeout) {
266
+ this.apiUrl = apiUrl;
267
+ this.sdkKey = sdkKey;
268
+ this.requestTimeout = requestTimeout;
269
+ this.queue = [];
270
+ this.flushTimer = null;
271
+ }
272
+ start() {
273
+ this.flushTimer = setInterval(() => {
274
+ this.flush().catch(() => {
275
+ });
276
+ }, FLUSH_INTERVAL_MS);
277
+ }
278
+ stop() {
279
+ if (this.flushTimer !== null) {
280
+ clearInterval(this.flushTimer);
281
+ this.flushTimer = null;
282
+ }
283
+ }
284
+ push(event) {
285
+ this.queue.push(event);
286
+ if (this.queue.length >= FLUSH_BATCH_SIZE) {
287
+ this.flush().catch(() => {
288
+ });
289
+ }
290
+ }
291
+ async flush() {
292
+ await this.flushWithRetry(0);
293
+ }
294
+ async flushWithRetry(attempt) {
295
+ if (this.queue.length === 0) return;
296
+ const batch = this.queue.splice(0, this.queue.length);
297
+ try {
298
+ await this.sendBatch(batch);
299
+ } catch {
300
+ if (attempt < MAX_RETRIES) {
301
+ this.queue.unshift(...batch);
302
+ await this.flushWithRetry(attempt + 1);
303
+ }
304
+ }
305
+ }
306
+ async sendBatch(events) {
307
+ const controller = new AbortController();
308
+ const timeout = setTimeout(() => controller.abort(), this.requestTimeout);
309
+ try {
310
+ const response = await fetch(`${this.apiUrl}/sdk/metrics`, {
311
+ method: "POST",
312
+ headers: {
313
+ "x-api-key": this.sdkKey,
314
+ "Content-Type": "application/json"
315
+ },
316
+ body: JSON.stringify({ events }),
317
+ signal: controller.signal
318
+ });
319
+ if (!response.ok) {
320
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
321
+ }
322
+ } finally {
323
+ clearTimeout(timeout);
324
+ }
325
+ }
326
+ };
327
+
254
328
  // src/client.ts
255
329
  var DEFAULT_API_URL = "https://rolloutctrl.io/api";
256
330
  var DEFAULT_REFRESH_INTERVAL = 3e4;
@@ -260,14 +334,17 @@ var RolloutCtrlClient = class {
260
334
  this.emitter = new TinyEmitter();
261
335
  this.subscribers = /* @__PURE__ */ new Set();
262
336
  this.isInitialized = false;
337
+ this.trackedEvaluations = /* @__PURE__ */ new Map();
263
338
  const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
264
339
  const refreshInterval = options.refreshInterval ?? DEFAULT_REFRESH_INTERVAL;
265
340
  const requestTimeout = options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
266
341
  this.repository = new HttpConfigurationRepository(apiUrl, options.sdkKey, options.environment, requestTimeout);
267
342
  this.evaluatorManager = new EvaluatorManager();
268
343
  this.updateProvider = new PollingUpdateProvider(refreshInterval);
344
+ this.metricsQueue = options.enableMetrics ?? true ? new MetricsQueue(apiUrl, options.sdkKey, requestTimeout) : null;
269
345
  this.repository.subscribe((configuration) => {
270
346
  this.evaluatorManager.update(configuration);
347
+ this.trackedEvaluations.clear();
271
348
  options.storage?.set(configuration).catch(() => {
272
349
  });
273
350
  if (this.isInitialized) {
@@ -302,6 +379,7 @@ var RolloutCtrlClient = class {
302
379
  this.updateProvider.start(() => {
303
380
  void this.repository.refresh();
304
381
  });
382
+ this.metricsQueue?.start();
305
383
  this.emitter.emit("ready");
306
384
  this.resolveReady();
307
385
  } catch (error) {
@@ -323,6 +401,10 @@ var RolloutCtrlClient = class {
323
401
  }
324
402
  async close() {
325
403
  this.updateProvider.stop();
404
+ if (this.metricsQueue) {
405
+ this.metricsQueue.stop();
406
+ await this.metricsQueue.flush();
407
+ }
326
408
  this.subscribers.clear();
327
409
  this.emitter.emit("shutdown");
328
410
  this.emitter.removeAllListeners();
@@ -343,13 +425,44 @@ var RolloutCtrlClient = class {
343
425
  return this.evaluatorManager.get();
344
426
  }
345
427
  isEnabled(flagKey, context) {
346
- return this.getEvaluator().isEnabled(flagKey, context);
428
+ return this.evaluate(flagKey, context).enabled;
347
429
  }
348
430
  evaluate(flagKey, context) {
349
- return this.getEvaluator().evaluate(flagKey, context);
431
+ const result = this.getEvaluator().evaluate(flagKey, context);
432
+ this.trackEvaluation(flagKey, result);
433
+ return result;
350
434
  }
351
435
  getVariant(flagKey, context) {
352
- return this.getEvaluator().getVariant(flagKey, context);
436
+ return this.evaluate(flagKey, context).variant;
437
+ }
438
+ trackEvaluation(flagKey, result) {
439
+ if (!this.metricsQueue || !this.isInitialized) return;
440
+ try {
441
+ const config = this.repository.getConfiguration();
442
+ const flag = config.flags.find((f) => f.key === flagKey);
443
+ if (!flag) return;
444
+ let type;
445
+ if (result.variant) {
446
+ type = "VARIANT_EXPOSURE";
447
+ } else if (result.strategy) {
448
+ type = "STRATEGY_MATCH";
449
+ } else if (result.enabled) {
450
+ type = "FLAG_ENABLED";
451
+ } else {
452
+ type = "FLAG_DISABLED";
453
+ }
454
+ const fingerprint = `${type}:${result.strategy?.id ?? ""}:${result.variant?.id ?? ""}`;
455
+ if (this.trackedEvaluations.get(flagKey) === fingerprint) return;
456
+ this.trackedEvaluations.set(flagKey, fingerprint);
457
+ this.metricsQueue.push({
458
+ featureFlagId: flag.id,
459
+ featureFlagEnvironmentId: flag.featureFlagEnvironmentId,
460
+ type,
461
+ strategyId: result.strategy?.id,
462
+ variantId: result.variant?.id
463
+ });
464
+ } catch {
465
+ }
353
466
  }
354
467
  can(actionKey, context) {
355
468
  return this.getEvaluator().can(actionKey, context);
@@ -389,6 +502,7 @@ var LocalStorageAdapter = class {
389
502
  EvaluatorManager,
390
503
  HttpConfigurationRepository,
391
504
  LocalStorageAdapter,
505
+ MetricsQueue,
392
506
  PollingUpdateProvider,
393
507
  RolloutCtrlClient,
394
508
  SseUpdateProvider,
package/dist/index.mjs CHANGED
@@ -143,7 +143,12 @@ var HttpConfigurationRepository = class {
143
143
  return this.normalizeConfiguration(raw);
144
144
  }
145
145
  normalizeConfiguration(raw) {
146
- const flags = Array.isArray(raw.flags) ? raw.flags : Object.entries(raw.flags ?? {}).map(([key, value]) => ({ key, ...value }));
146
+ const flags = Array.isArray(raw.flags) ? raw.flags : Object.entries(raw.flags ?? {}).map(([key, value]) => ({
147
+ key,
148
+ ...value,
149
+ id: value._featureFlagId ?? value.id ?? "",
150
+ featureFlagEnvironmentId: value._featureFlagEnvironmentId ?? ""
151
+ }));
147
152
  const actions = Array.isArray(raw.actions) ? raw.actions : Object.values(raw.actions ?? {});
148
153
  return {
149
154
  projectId: raw.project?.id ?? raw.projectId ?? "",
@@ -223,6 +228,74 @@ var SseUpdateProvider = class {
223
228
  }
224
229
  };
225
230
 
231
+ // src/metrics.ts
232
+ var FLUSH_INTERVAL_MS = 3e4;
233
+ var FLUSH_BATCH_SIZE = 100;
234
+ var MAX_RETRIES = 3;
235
+ var MetricsQueue = class {
236
+ constructor(apiUrl, sdkKey, requestTimeout) {
237
+ this.apiUrl = apiUrl;
238
+ this.sdkKey = sdkKey;
239
+ this.requestTimeout = requestTimeout;
240
+ this.queue = [];
241
+ this.flushTimer = null;
242
+ }
243
+ start() {
244
+ this.flushTimer = setInterval(() => {
245
+ this.flush().catch(() => {
246
+ });
247
+ }, FLUSH_INTERVAL_MS);
248
+ }
249
+ stop() {
250
+ if (this.flushTimer !== null) {
251
+ clearInterval(this.flushTimer);
252
+ this.flushTimer = null;
253
+ }
254
+ }
255
+ push(event) {
256
+ this.queue.push(event);
257
+ if (this.queue.length >= FLUSH_BATCH_SIZE) {
258
+ this.flush().catch(() => {
259
+ });
260
+ }
261
+ }
262
+ async flush() {
263
+ await this.flushWithRetry(0);
264
+ }
265
+ async flushWithRetry(attempt) {
266
+ if (this.queue.length === 0) return;
267
+ const batch = this.queue.splice(0, this.queue.length);
268
+ try {
269
+ await this.sendBatch(batch);
270
+ } catch {
271
+ if (attempt < MAX_RETRIES) {
272
+ this.queue.unshift(...batch);
273
+ await this.flushWithRetry(attempt + 1);
274
+ }
275
+ }
276
+ }
277
+ async sendBatch(events) {
278
+ const controller = new AbortController();
279
+ const timeout = setTimeout(() => controller.abort(), this.requestTimeout);
280
+ try {
281
+ const response = await fetch(`${this.apiUrl}/sdk/metrics`, {
282
+ method: "POST",
283
+ headers: {
284
+ "x-api-key": this.sdkKey,
285
+ "Content-Type": "application/json"
286
+ },
287
+ body: JSON.stringify({ events }),
288
+ signal: controller.signal
289
+ });
290
+ if (!response.ok) {
291
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
292
+ }
293
+ } finally {
294
+ clearTimeout(timeout);
295
+ }
296
+ }
297
+ };
298
+
226
299
  // src/client.ts
227
300
  var DEFAULT_API_URL = "https://rolloutctrl.io/api";
228
301
  var DEFAULT_REFRESH_INTERVAL = 3e4;
@@ -232,14 +305,17 @@ var RolloutCtrlClient = class {
232
305
  this.emitter = new TinyEmitter();
233
306
  this.subscribers = /* @__PURE__ */ new Set();
234
307
  this.isInitialized = false;
308
+ this.trackedEvaluations = /* @__PURE__ */ new Map();
235
309
  const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
236
310
  const refreshInterval = options.refreshInterval ?? DEFAULT_REFRESH_INTERVAL;
237
311
  const requestTimeout = options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
238
312
  this.repository = new HttpConfigurationRepository(apiUrl, options.sdkKey, options.environment, requestTimeout);
239
313
  this.evaluatorManager = new EvaluatorManager();
240
314
  this.updateProvider = new PollingUpdateProvider(refreshInterval);
315
+ this.metricsQueue = options.enableMetrics ?? true ? new MetricsQueue(apiUrl, options.sdkKey, requestTimeout) : null;
241
316
  this.repository.subscribe((configuration) => {
242
317
  this.evaluatorManager.update(configuration);
318
+ this.trackedEvaluations.clear();
243
319
  options.storage?.set(configuration).catch(() => {
244
320
  });
245
321
  if (this.isInitialized) {
@@ -274,6 +350,7 @@ var RolloutCtrlClient = class {
274
350
  this.updateProvider.start(() => {
275
351
  void this.repository.refresh();
276
352
  });
353
+ this.metricsQueue?.start();
277
354
  this.emitter.emit("ready");
278
355
  this.resolveReady();
279
356
  } catch (error) {
@@ -295,6 +372,10 @@ var RolloutCtrlClient = class {
295
372
  }
296
373
  async close() {
297
374
  this.updateProvider.stop();
375
+ if (this.metricsQueue) {
376
+ this.metricsQueue.stop();
377
+ await this.metricsQueue.flush();
378
+ }
298
379
  this.subscribers.clear();
299
380
  this.emitter.emit("shutdown");
300
381
  this.emitter.removeAllListeners();
@@ -315,13 +396,44 @@ var RolloutCtrlClient = class {
315
396
  return this.evaluatorManager.get();
316
397
  }
317
398
  isEnabled(flagKey, context) {
318
- return this.getEvaluator().isEnabled(flagKey, context);
399
+ return this.evaluate(flagKey, context).enabled;
319
400
  }
320
401
  evaluate(flagKey, context) {
321
- return this.getEvaluator().evaluate(flagKey, context);
402
+ const result = this.getEvaluator().evaluate(flagKey, context);
403
+ this.trackEvaluation(flagKey, result);
404
+ return result;
322
405
  }
323
406
  getVariant(flagKey, context) {
324
- return this.getEvaluator().getVariant(flagKey, context);
407
+ return this.evaluate(flagKey, context).variant;
408
+ }
409
+ trackEvaluation(flagKey, result) {
410
+ if (!this.metricsQueue || !this.isInitialized) return;
411
+ try {
412
+ const config = this.repository.getConfiguration();
413
+ const flag = config.flags.find((f) => f.key === flagKey);
414
+ if (!flag) return;
415
+ let type;
416
+ if (result.variant) {
417
+ type = "VARIANT_EXPOSURE";
418
+ } else if (result.strategy) {
419
+ type = "STRATEGY_MATCH";
420
+ } else if (result.enabled) {
421
+ type = "FLAG_ENABLED";
422
+ } else {
423
+ type = "FLAG_DISABLED";
424
+ }
425
+ const fingerprint = `${type}:${result.strategy?.id ?? ""}:${result.variant?.id ?? ""}`;
426
+ if (this.trackedEvaluations.get(flagKey) === fingerprint) return;
427
+ this.trackedEvaluations.set(flagKey, fingerprint);
428
+ this.metricsQueue.push({
429
+ featureFlagId: flag.id,
430
+ featureFlagEnvironmentId: flag.featureFlagEnvironmentId,
431
+ type,
432
+ strategyId: result.strategy?.id,
433
+ variantId: result.variant?.id
434
+ });
435
+ } catch {
436
+ }
325
437
  }
326
438
  can(actionKey, context) {
327
439
  return this.getEvaluator().can(actionKey, context);
@@ -360,6 +472,7 @@ export {
360
472
  EvaluatorManager,
361
473
  HttpConfigurationRepository,
362
474
  LocalStorageAdapter,
475
+ MetricsQueue,
363
476
  PollingUpdateProvider,
364
477
  RolloutCtrlClient,
365
478
  SseUpdateProvider,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rolloutctrl/js-sdk",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "RolloutCtrl JavaScript SDK for browser applications",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",