@featbit/js-client-sdk 4.2.16 → 4.3.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.
Files changed (55) hide show
  1. package/README.md +24 -0
  2. package/dist/cjs/Configuration.js +3 -0
  3. package/dist/cjs/Configuration.js.map +1 -1
  4. package/dist/cjs/FbClientBuilder.js +7 -0
  5. package/dist/cjs/FbClientBuilder.js.map +1 -1
  6. package/dist/cjs/FbClientCore.js +11 -2
  7. package/dist/cjs/FbClientCore.js.map +1 -1
  8. package/dist/cjs/data-sync/WebSocketDataSynchronizer.js +10 -1
  9. package/dist/cjs/data-sync/WebSocketDataSynchronizer.js.map +1 -1
  10. package/dist/cjs/platform/browser/BrowserWebSocket.js +6 -0
  11. package/dist/cjs/platform/browser/BrowserWebSocket.js.map +1 -1
  12. package/dist/cjs/version.js +1 -1
  13. package/dist/cjs/version.js.map +1 -1
  14. package/dist/esm/Configuration.d.ts +1 -0
  15. package/dist/esm/Configuration.d.ts.map +1 -1
  16. package/dist/esm/Configuration.js +3 -0
  17. package/dist/esm/Configuration.js.map +1 -1
  18. package/dist/esm/FbClientBuilder.d.ts +4 -0
  19. package/dist/esm/FbClientBuilder.d.ts.map +1 -1
  20. package/dist/esm/FbClientBuilder.js +7 -0
  21. package/dist/esm/FbClientBuilder.js.map +1 -1
  22. package/dist/esm/FbClientCore.d.ts.map +1 -1
  23. package/dist/esm/FbClientCore.js +11 -2
  24. package/dist/esm/FbClientCore.js.map +1 -1
  25. package/dist/esm/data-sync/WebSocketDataSynchronizer.d.ts +2 -1
  26. package/dist/esm/data-sync/WebSocketDataSynchronizer.d.ts.map +1 -1
  27. package/dist/esm/data-sync/WebSocketDataSynchronizer.js +10 -1
  28. package/dist/esm/data-sync/WebSocketDataSynchronizer.js.map +1 -1
  29. package/dist/esm/options/IOptions.d.ts +8 -0
  30. package/dist/esm/options/IOptions.d.ts.map +1 -1
  31. package/dist/esm/options/IValidatedOptions.d.ts +1 -0
  32. package/dist/esm/options/IValidatedOptions.d.ts.map +1 -1
  33. package/dist/esm/platform/browser/BrowserWebSocket.d.ts +1 -0
  34. package/dist/esm/platform/browser/BrowserWebSocket.d.ts.map +1 -1
  35. package/dist/esm/platform/browser/BrowserWebSocket.js +6 -0
  36. package/dist/esm/platform/browser/BrowserWebSocket.js.map +1 -1
  37. package/dist/esm/version.d.ts +1 -1
  38. package/dist/esm/version.d.ts.map +1 -1
  39. package/dist/esm/version.js +1 -1
  40. package/dist/esm/version.js.map +1 -1
  41. package/dist/umd/featbit-js-client-sdk-4.3.0.js +2 -0
  42. package/dist/umd/featbit-js-client-sdk-4.3.0.js.map +1 -0
  43. package/dist/umd/featbit-js-client-sdk.js +1 -1
  44. package/dist/umd/featbit-js-client-sdk.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/Configuration.ts +5 -0
  47. package/src/FbClientBuilder.ts +8 -0
  48. package/src/FbClientCore.ts +19 -8
  49. package/src/data-sync/WebSocketDataSynchronizer.ts +9 -1
  50. package/src/options/IOptions.ts +9 -0
  51. package/src/options/IValidatedOptions.ts +1 -1
  52. package/src/platform/browser/BrowserWebSocket.ts +6 -0
  53. package/src/version.ts +1 -1
  54. package/dist/umd/featbit-js-client-sdk-4.2.16.js +0 -2
  55. package/dist/umd/featbit-js-client-sdk-4.2.16.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featbit/js-client-sdk",
3
- "version": "4.2.16",
3
+ "version": "4.3.0",
4
4
  "description": "https://github.com/featbit/featbit-js-client-sdk",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -43,6 +43,7 @@ const validations: Record<string, TypeValidator> = {
43
43
  disableEvents: TypeValidators.Boolean,
44
44
  pollingInterval: TypeValidators.Number,
45
45
  offline: TypeValidators.Boolean,
46
+ enablePollingFallback: TypeValidators.Boolean,
46
47
  dataSyncMode: TypeValidators.String,
47
48
  bootstrap: TypeValidators.Bootstrap,
48
49
  user: TypeValidators.User
@@ -65,6 +66,7 @@ export const defaultValues: IValidatedOptions = {
65
66
  disableEvents: false,
66
67
  pollingInterval: 30000,
67
68
  offline: false,
69
+ enablePollingFallback: false,
68
70
  store: (options: IOptions) => new InMemoryStore(),
69
71
  bootstrap: undefined,
70
72
  user: undefined,
@@ -158,6 +160,8 @@ export default class Configuration {
158
160
 
159
161
  public readonly offline: boolean;
160
162
 
163
+ public readonly enablePollingFallback: boolean;
164
+
161
165
  public readonly dataSyncMode: DataSyncModeEnum;
162
166
 
163
167
  public readonly bootstrapProvider: IBootstrapProvider = new NullBootstrapProvider();
@@ -204,6 +208,7 @@ export default class Configuration {
204
208
  this.pollingInterval = validatedOptions.pollingInterval;
205
209
 
206
210
  this.offline = validatedOptions.offline;
211
+ this.enablePollingFallback = validatedOptions.enablePollingFallback;
207
212
  if (validatedOptions.bootstrap && validatedOptions.bootstrap.length > 0) {
208
213
  try {
209
214
  this.bootstrapProvider = new JsonBootstrapProvider(validatedOptions.bootstrap);
@@ -103,6 +103,14 @@ export class FbClientBuilder {
103
103
  return this;
104
104
  }
105
105
 
106
+ /**
107
+ * Refer to {@link IOptions.enablePollingFallback}.
108
+ */
109
+ enablePollingFallback(enablePollingFallback: boolean): FbClientBuilder {
110
+ this._options.enablePollingFallback = enablePollingFallback;
111
+ return this;
112
+ }
113
+
106
114
  /**
107
115
  * Refer to {@link IOptions.pollingInterval}.
108
116
  */
@@ -130,6 +130,22 @@ export class FbClientCore implements IFbClientCore {
130
130
  patch: () => this.initSuccess()
131
131
  });
132
132
 
133
+ const createPollingSync = () => new PollingDataSynchronizer(
134
+ this.config,
135
+ new Requestor(this.config.sdkKey, this.config, this.platform.info, this.platform.requests),
136
+ () => this.store!.version,
137
+ listeners,
138
+ (e) => this.dataSourceErrorHandler(e),
139
+ );
140
+
141
+ const onWebSocketNetworkError = () => {
142
+ this.logger?.warn('WebSocket connection failed on initial attempt, falling back to polling');
143
+ this.dataSynchronizer?.stop();
144
+ const pollSync = createPollingSync();
145
+ this.dataSynchronizer = pollSync;
146
+ pollSync.start();
147
+ };
148
+
133
149
  const dataSynchronizer = this.config.dataSyncMode === DataSyncModeEnum.STREAMING
134
150
  ? new WebSocketDataSynchronizer(
135
151
  this.config.sdkKey,
@@ -138,15 +154,10 @@ export class FbClientCore implements IFbClientCore {
138
154
  this.platform.webSocket,
139
155
  () => this.store!.version,
140
156
  listeners,
141
- this.config.webSocketPingInterval
157
+ this.config.webSocketPingInterval,
158
+ this.config.enablePollingFallback ? onWebSocketNetworkError : undefined
142
159
  )
143
- : new PollingDataSynchronizer(
144
- this.config,
145
- new Requestor(this.config.sdkKey, this.config, this.platform.info, this.platform.requests),
146
- () => this.store!.version,
147
- listeners,
148
- (e) => this.dataSourceErrorHandler(e),
149
- );
160
+ : createPollingSync();
150
161
 
151
162
  this.dataSynchronizer = this.config.dataSynchronizerFactory?.(
152
163
  clientContext,
@@ -20,7 +20,8 @@ class WebSocketDataSynchronizer implements IDataSynchronizer {
20
20
  socket: IWebSocketWithEvents,
21
21
  private readonly getStoreTimestamp: () => number,
22
22
  private readonly listeners: Map<EventName, ProcessStreamResponse>,
23
- webSocketPingInterval: number
23
+ webSocketPingInterval: number,
24
+ private readonly onNetworkError?: () => void
24
25
  ) {
25
26
  const {logger, streamingUri} = clientContext;
26
27
 
@@ -50,6 +51,13 @@ class WebSocketDataSynchronizer implements IDataSynchronizer {
50
51
  }
51
52
  });
52
53
  })
54
+
55
+ if (this.onNetworkError) {
56
+ this.socket?.once('network-error', () => {
57
+ this.logger?.warn('WebSocket connection failed, falling back to polling');
58
+ this.onNetworkError!();
59
+ });
60
+ }
53
61
  }
54
62
 
55
63
  async identify(user: IUser): Promise<void> {
@@ -34,6 +34,15 @@ export interface IOptions {
34
34
  */
35
35
  dataSyncMode?: DataSyncModeEnum;
36
36
 
37
+ /**
38
+ * Whether the SDK should fall back to polling when the WebSocket connection cannot be established.
39
+ * Only applies when {@link dataSyncMode} is {@link DataSyncModeEnum.STREAMING}.
40
+ * When enabled, {@link pollingUri} must also be set.
41
+ *
42
+ * Defaults to false.
43
+ */
44
+ enablePollingFallback?: boolean;
45
+
37
46
  /**
38
47
  * The base URI of the data-sync service, mandatory if the {@link dataSyncMode} is set to {@link DataSyncModeEnum.STREAMING}.
39
48
  */
@@ -4,7 +4,6 @@ import { IOptions } from "./IOptions";
4
4
  import { IDataSynchronizer } from "../data-sync/IDataSynchronizer";
5
5
  import { DataSyncModeEnum } from "../data-sync/DataSyncMode";
6
6
  import { IUser } from "./IUser";
7
- import { IBootstrapProvider } from "../bootstrap";
8
7
  import { IFlagBase } from "../evaluation";
9
8
 
10
9
  export interface IValidatedOptions {
@@ -20,6 +19,7 @@ export interface IValidatedOptions {
20
19
  disableEvents: boolean;
21
20
  pollingInterval: number;
22
21
  offline: boolean;
22
+ enablePollingFallback: boolean;
23
23
  store: IStore | ((options: IOptions) => IStore);
24
24
  dataSynchronizer?: IDataSynchronizer;
25
25
  logger?: ILogger;
@@ -13,6 +13,7 @@ class BrowserWebSocket implements IWebSocket {
13
13
  private ws?: WebSocket;
14
14
  private retryCounter = 0;
15
15
  private closed: boolean = false;
16
+ private hasConnected: boolean = false;
16
17
 
17
18
  private _config: IWebSocketConfig = {} as IWebSocketConfig;
18
19
  private livenessTimer: ReturnType<typeof setTimeout> | undefined;
@@ -36,6 +37,7 @@ class BrowserWebSocket implements IWebSocket {
36
37
  that.ws?.addEventListener('open', function (this: WebSocket, event) {
37
38
  // this is the websocket instance to which the current listener is binded to, it's different from that.socket
38
39
  that._config.logger.info(`WebSocket connection succeeded, connection time: ${ Date.now() - startTime } ms`);
40
+ that.hasConnected = true;
39
41
  that.retryCounter = 0;
40
42
  that.doDataSync();
41
43
  that.sendPingMessage();
@@ -56,6 +58,10 @@ class BrowserWebSocket implements IWebSocket {
56
58
  that.ws?.addEventListener('error', function (event) {
57
59
  // reconnect
58
60
  that._config.logger.debug('error');
61
+ if (!that.hasConnected) {
62
+ that._config.logger.warn('WebSocket initial connection failed, emitting network-error');
63
+ that.emitter.emit('network-error');
64
+ }
59
65
  });
60
66
 
61
67
  // Listen for messages
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "4.2.16"; export const name = "@featbit/js-client-sdk";
1
+ export const version = "4.3.0"; export const name = "@featbit/js-client-sdk";
@@ -1,2 +0,0 @@
1
- !function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var i=e();for(var n in i)("object"==typeof exports?exports:t)[n]=i[n]}}(this,()=>(()=>{"use strict";var t={d:(e,i)=>{for(var n in i)t.o(i,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:i[n]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{AsyncEvent:()=>b,BaseStore:()=>kt,BasicLogger:()=>ut,BootstrapValidator:()=>X,BrowserRequests:()=>vt,BrowserWebSocket:()=>St,ClientError:()=>N,CurrentUserStorageKey:()=>a,DataSyncModeEnum:()=>jt,DateValidator:()=>et,DefaultEventProcessor:()=>K,DefaultEventQueue:()=>I,DefaultEventSender:()=>L,DefaultEventSerializer:()=>D,DeliveryStatus:()=>p,EmptyString:()=>At,EvalEvent:()=>O,EventDispatcher:()=>M,FactoryOrInstance:()=>W,FbClientBuilder:()=>ne,FbClientCore:()=>Gt,FlushEvent:()=>w,Function:()=>G,JsonBootstrapProvider:()=>c,KindValidator:()=>it,MetricEvent:()=>k,MinInt:()=>Kt,NullBootstrapProvider:()=>h,NullDataSynchronizer:()=>Nt,NullEventProcessor:()=>B,NullableBoolean:()=>Y,NumberWithMinimum:()=>H,PayloadEvent:()=>E,PollingError:()=>j,ReasonKinds:()=>f,SafeLogger:()=>ht,ShutdownEvent:()=>S,StoreItemOriginEnum:()=>l,StoreStorageKey:()=>o,StreamResponseEventType:()=>bt,StreamingError:()=>U,StringMatchingRegex:()=>Q,TimeoutError:()=>_,Type:()=>q,TypeArray:()=>J,TypeValidators:()=>nt,UnexpectedResponseError:()=>$,UserBuilder:()=>dt,UserValidator:()=>Z,ValueConverters:()=>Ot,VariationDataType:()=>g,createStreamListeners:()=>v,debounce:()=>Ft,deepCopy:()=>xt,defaultValues:()=>Vt,deserializeAll:()=>s,deserializePatch:()=>r,generateConnectionToken:()=>yt,hashSerializeUser:()=>It,isHttpRecoverable:()=>z,isNullOrUndefined:()=>u,serializeUser:()=>Pt});class i{}i.Flags={namespace:"flags"};const n=i;function s(t){const e={[n.Flags.namespace]:{}};return(null==t?void 0:t.length)&&(e[n.Flags.namespace]=t.reduce((t,e)=>(t[e.id]=Object.assign(Object.assign({},e),{version:e.timestamp||0,key:e.id,variations:e.variationOptions}),t),{})),e}function r(t){return[...(null==t?void 0:t.map(t=>({data:Object.assign(Object.assign({},t),{version:t.timestamp,key:t.id,variations:t.variationOptions}),kind:n.Flags})))||[]]}const o="fb-datastore",a="fb-user";var l;function u(t){return null==t}!function(t){t.Local="Local",t.Remote="Remote"}(l||(l={}));class c{constructor(t){const e=s((t||[]).map(t=>Object.assign(Object.assign({},t),{origin:l.Local,variationOptions:t.variationOptions||[{id:null,variation:t.variation}]})));this.dataSet={flags:e.flags,version:0}}populate(t,e,i){return new Promise((n,s)=>{if(u(this.dataSet))return n();e.init(t,this.dataSet,()=>{n(),null==i||i()})})}}class h{constructor(){this.dataSet={flags:{},version:0}}populate(t,e,i){return new Promise((t,e)=>{t(),null==i||i()})}}var d=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};const v=(t,e,i)=>{const n=new Map;return n.set("put",((t,e,i=()=>{})=>({deserializeData:s,processJson:(n,{flags:s})=>d(void 0,void 0,void 0,function*(){const r={flags:s,version:0};null==e||e.debug("Initializing all data"),yield t.init(n,r,i)})}))(t,e,null==i?void 0:i.put)),n.set("patch",((t,e,i=()=>{})=>({deserializeData:r,processJson:(n,s)=>d(void 0,void 0,void 0,function*(){if(0!==(null==s?void 0:s.length)){if((null==s?void 0:s.length)>0)for(const r of s)null==e||e.debug(`Updating ${r.data.key} in ${r.kind.namespace}`),yield t.upsert(n,r.kind,r.data,i)}else null==i||i()})}))(t,e,null==i?void 0:i.patch)),n};var g,f,p,m=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class y{constructor(t,e,i){this.store=t,this.hasEventListeners=e,this.onChange=i}init(t,e,i){return m(this,void 0,void 0,function*(){if(t!==this.store.user.keyId)return void(null==i||i());const s=this.hasEventListeners(),[r,o]=this.store.all(n.Flags),a={flags:r,version:o};yield(t=>m(this,void 0,void 0,function*(){if(!Object.keys(e.flags).some(t=>e.flags[t].origin===l.Local)&&t){const i=Object.keys(t.flags).filter(i=>t.flags[i]&&!e.flags[i]&&t.flags[i].origin===l.Local).reduce((e,i)=>(e[i]=t.flags[i],e),{});e={version:e.version,flags:Object.assign(Object.assign({},e.flags),i)}}yield this.store.init(e),Promise.resolve().then(()=>{if(s){const i=Object.keys(e).filter(t=>"version"!==t).flatMap(i=>{const n=(null==t?void 0:t[i])||{},s=e[i],r=Object.assign(Object.assign({},n),s);return Object.keys(r).filter(t=>this.isUpdated(n&&n[t],s&&s[t]))});i.length>0&&this.onChange(i)}}),null==i||i()}))(a)})}checkUpdates(t,e,i){if(!this.hasEventListeners())return;const n=Object.keys(e).filter(t=>"version"!==t).flatMap(i=>{const n=(null==t?void 0:t[i])||{},s=e[i],r=Object.assign(Object.assign({},n),s);return Object.keys(r).filter(t=>this.isUpdated(n&&n[t],s&&s[t]))});n.length>0&&this.onChange(n),null==i||i()}upsert(t,e,i,n){return m(this,void 0,void 0,function*(){if(t!==this.store.user.keyId)return void(null==n||n());const{key:s}=i,r=this.hasEventListeners(),o=t=>m(this,void 0,void 0,function*(){yield this.store.upsert(e,i),Promise.resolve().then(()=>{r&&this.isUpdated(t,i)&&this.onChange([s])}),null==n||n()});if(r){const t=this.store.get(e,s);yield o(t||void 0)}else yield o()})}isUpdated(t,e){return!(!t&&!e||t&&e&&!(e.version>=t.version&&e.variation!==t.variation))}}!function(t){t.string="string",t.boolean="boolean",t.number="number",t.json="json",t.empty=""}(g||(g={})),function(t){t.ClientNotReady="ClientNotReady",t.Match="Match",t.WrongType="WrongType",t.FlagNotFound="FlagNotFound",t.Error="Error"}(f||(f={}));class b{get hash(){return this.timestamp.toString()}constructor(){this.timestamp=(new Date).getTime(),this.isCompletedPromise=new Promise(t=>{this.resolveFn=t})}waitForCompletion(){return this.isCompletedPromise}complete(){var t;null===(t=this.resolveFn)||void 0===t||t.call(this,this)}}class w extends b{}class S extends b{}class E{constructor(){this.timestamp=(new Date).getTime()}get hash(){return this.timestamp.toString()}toPayload(){}}class k extends E{constructor(t,e,i,n){super(),this.user=t,this.eventName=e,this.appType=i,this.metricValue=n}userPayload(){return{keyId:this.user.keyId,name:this.user.name,customizedProperties:this.user.customizedProperties}}toPayload(){return{user:this.userPayload(),metrics:[{route:"index/metric",timestamp:this.timestamp,numericValue:this.metricValue,appType:this.appType,eventName:this.eventName,type:"CustomEvent"}]}}get hash(){const t=this.toPayload(),e={user:t.user,metrics:t.metrics.map(t=>Object.assign(Object.assign({},t),{timestamp:void 0}))};return JSON.stringify(e)}}class O extends E{constructor(t,e,i,n){super(),this.user=t,this.flagKey=e,this.variation=i,this.sendToExperiment=n}userPayload(){return{keyId:this.user.keyId,name:this.user.name,customizedProperties:this.user.customizedProperties}}toPayload(){return{user:this.userPayload(),variations:[{featureFlagKey:this.flagKey,sendToExperiment:this.sendToExperiment,timestamp:this.timestamp,variation:this.variation}]}}get hash(){const t=this.toPayload(),e={user:t.user,variations:t.variations.map(t=>Object.assign(Object.assign({},t),{timestamp:void 0}))};return JSON.stringify(e)}}class T{constructor(t,e,i){this.kind=t,this.value=e,this.reason=i}static flagArchived(t){return new T(f.FlagNotFound,null,`flag archived: ${t}`)}static flagNotFound(t){return new T(f.FlagNotFound,null,`flag not found: ${t}`)}static matched(t){return new T(f.Match,t,t.matchReason)}toEvalEvent(t){var e,i,n;if(this.kind!==f.Match)return null;const s=null===(e=this.value)||void 0===e?void 0:e.variations.find(t=>{var e;return t.value===(null===(e=this.value)||void 0===e?void 0:e.variation)});return new O(t,null===(i=this.value)||void 0===i?void 0:i.id,s,null===(n=this.value)||void 0===n?void 0:n.sendToExperiment)}}class P{constructor(t,e){this.store=t,this.logger=e}evaluate(t){var e;const i=this.store.get(n.Flags,t);return i?"flag archived"===i.matchReason?(null===(e=this.logger)||void 0===e||e.warn(`Evaluating an archived flag: ${t}`),T.flagArchived(t)):T.matched(i):T.flagNotFound(t)}}!function(t){t[t.Succeeded=0]="Succeeded",t[t.Failed=1]="Failed",t[t.FailedAndMustShutDown=2]="FailedAndMustShutDown"}(p||(p={}));class I{constructor(t,e){this.capacity=t,this.logger=e,this.closed=!1,this.events=[]}addEvent(t){return!this.closed&&(this.events.length>=this.capacity?(this.logger.warn("Events are being produced faster than they can be processed. We shouldn't see this."),!1):(this.events.push(t),!0))}clear(){this.events=[]}shift(){return this.events.shift()}close(){this.closed=!0}get eventsSnapshot(){return[...this.events]}get length(){return this.events.length}get isEmpty(){return 0===this.length}}function F(t,e){const{userAgent:i,version:n}=e.sdkData();return{"Content-Type":"application/json","X-User-Agent":null!=i?i:`${e.appType}/${n}`,"User-Agent":null!=i?i:`${e.appType}/${n}`,Authorization:t}}function x(t,e,i){let n;return n=t.status?`error ${t.status}${401===t.status?" (invalid SDK key)":""}`:`I/O error (${t.message||t})`,`Received ${n} for ${e} - ${null!=i?i:"giving up permanently"}`}class j extends Error{constructor(t,e){super(t),this.status=e,this.name="FbPollingError"}}class U extends Error{constructor(t,e){super(t),this.code=e,this.name="FbStreamingError"}}class $ extends Error{constructor(t){super(t),this.name="FbUnexpectedResponseError"}}class N extends Error{constructor(t){super(t),this.name="FbClientError"}}class _ extends Error{constructor(t){super(t),this.name="FeatBitTimeoutError"}}function z(t){return!(void 0===t||t>=400&&t<500&&400!==t&&408!==t&&429!==t)}const C=(t=1e3)=>{return e=void 0,i=void 0,s=function*(){return new Promise(e=>{setTimeout(e,t)})},new((n=void 0)||(n=Promise))(function(t,r){function o(t){try{l(s.next(t))}catch(t){r(t)}}function a(t){try{l(s.throw(t))}catch(t){r(t)}}function l(e){var i;e.done?t(e.value):(i=e.value,i instanceof n?i:new n(function(t){t(i)})).then(o,a)}l((s=s.apply(e,i||[])).next())});var e,i,n,s};class L{constructor(t){const{sdkKey:e,eventsUri:i,platform:n}=t,{info:s,requests:r}=n;this.defaultHeaders=F(e,s),this.eventsUri=i,this.requests=r}send(t,e){return i=this,n=void 0,r=function*(){const i={status:p.Succeeded},n=Object.assign({},this.defaultHeaders);let s;try{const{status:e}=yield this.requests.fetch(this.eventsUri,{headers:n,body:t,method:"POST"});if(e>=200&&e<=299)return i;if(s=new $(x({status:e,message:"some events were dropped"},"event posting")),!z(e))return i.status=p.FailedAndMustShutDown,i.error=s,i}catch(t){s=t}return s&&!e?(i.status=p.Failed,i.error=s,i):(yield C(),this.send(t,!1))},new((s=void 0)||(s=Promise))(function(t,e){function o(t){try{l(r.next(t))}catch(t){e(t)}}function a(t){try{l(r.throw(t))}catch(t){e(t)}}function l(e){var i;e.done?t(e.value):(i=e.value,i instanceof s?i:new s(function(t){t(i)})).then(o,a)}l((r=r.apply(i,n||[])).next())});var i,n,s,r}}class D{serialize(t){const e=t.map(t=>t instanceof O||t instanceof k?t.toPayload():null).filter(t=>null!==t);return JSON.stringify(e)}}var R=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class M{constructor(t,e){this.maxEventPerRequest=50,this.stopped=!1;const{logger:i,maxEventsInQueue:n}=t;this.logger=i,this.buffer=new I(n,this.logger),this.sender=new L(t),this.serializer=new D,this.dispatchLoop(e).then()}dispatchLoop(t){return R(this,void 0,void 0,function*(){this.logger.debug("Start dispatch loop.");let e=!0;for(;e;)try{const i=t.shift();if(void 0===i){yield C(1e3);continue}i instanceof E?this.addEventToBuffer(i):i instanceof w?yield this.triggerFlush(i):i instanceof S&&(yield this.triggerFlush(i),this.stopped=!0,e=!1)}catch(t){this.logger.error("Unexpected error in event dispatcher.",t)}this.logger.debug("Finish dispatch loop.")})}addEventToBuffer(t){this.stopped||(this.buffer.addEvent(t)?this.logger.debug("Added event to buffer."):this.logger.warn("Exceeded event queue capacity, event will be dropped. Increase capacity to avoid dropping events."))}triggerFlush(t){return R(this,void 0,void 0,function*(){if(this.stopped)return void t.complete();if(this.buffer.isEmpty)return t.complete(),void this.logger.debug("Flush empty buffer.");const e=this.buffer.eventsSnapshot;this.buffer.clear();try{yield this.flushEvents(e),this.logger.debug(`${e.length} events has been flushed.`)}catch(t){this.logger.warn("Exception happened when flushing events",t)}t.complete()})}flushEvents(t){return R(this,void 0,void 0,function*(){const e=(t=this.getUniqueEvents(t)).length;for(let i=0;i<e;i+=this.maxEventPerRequest){const n=Math.min(this.maxEventPerRequest,e-i),s=t.slice(i,i+n),r=this.serializer.serialize(s),{status:o}=yield this.sender.send(r,!0);o===p.FailedAndMustShutDown&&(this.stopped=!0)}})}getUniqueEvents(t){const e=[],i=[];for(const n of t)i.includes(n.hash)||(e.push(n),i.push(n.hash));return e}}var A=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class K{constructor(t){this.closed=!1;const{logger:e,flushInterval:i,maxEventsInQueue:n}=t;this.logger=e,this.flushInterval=i,this.eventQueue=new I(n,this.logger),this.eventDispatcher=new M(t,this.eventQueue),this.flushLoop()}flushLoop(){this.closed||setTimeout(()=>A(this,void 0,void 0,function*(){try{yield this.flush()}catch(t){this.logger.error("Unexpected error while flushing events in event processor.",t)}this.flushLoop()}),this.flushInterval)}flush(){const t=new w;return this.record(t),t.waitForCompletion()}close(){return A(this,void 0,void 0,function*(){if(this.closed)return;const t=new S;this.record(t);try{yield t.waitForCompletion()}catch(t){this.logger.error("Event processor shutdown but not complete.")}this.eventQueue.close(),this.closed=!0})}record(t){return!(u(t)||!this.eventQueue.addEvent(t)&&(t instanceof w&&t.complete(),1))}}class B{flush(){return Promise.resolve()}close(){return Promise.resolve()}record(t){return!1}}class V{static optionBelowMinimum(t,e,i){return`Config option "${t}" had invalid value of ${e}, using minimum of ${i} instead`}static unknownOption(t){return`Ignoring unknown config option "${t}"`}static wrongOptionType(t,e,i){return`Config option "${t}" should be of type ${e}, got ${i}, using default value`}static wrongOptionTypeBoolean(t,e){return`Config option "${t}" should be a boolean, got ${e}, converting to boolean`}static partialEndpoint(t){return`You have set custom uris without specifying the ${t} URI; connections may not work properly`}static mandatory(t){return`${t} is mandatory`}static invalidOptionValue(t){return`Invalid option value: ${t}`}static missingKeyInBootstrapValue(t){return`Missing key "${t}" in bootstrap value`}}class W{is(t){if(Array.isArray(t))return!1;const e=typeof t;return"function"===e||"object"===e}getType(){return"factory method or object"}}class q{constructor(t,e){this.typeName=t,this.typeOf=typeof e}is(t){return!Array.isArray(t)&&typeof t===this.typeOf}getType(){return this.typeName}}class J{constructor(t,e){this.typeName=t,this.typeOf=typeof e}is(t){return!!Array.isArray(t)&&(!(t.length>0)||t.every(t=>typeof t===this.typeOf))}getType(){return this.typeName}}class H extends q{constructor(t){super(`number with minimum value of ${t}`,0),this.min=t}is(t){return typeof t===this.typeOf&&t>=this.min}}class Q extends q{constructor(t){super(`string matching ${t}`,""),this.expression=t}is(t){return!!t.match(this.expression)}}class G{is(t){return"function"==typeof t}getType(){return"function"}}class Y{is(t){return"boolean"==typeof t||null==t}getType(){return"boolean | undefined | null"}}class X{constructor(){this.messages=[]}is(t){if("object"!=typeof t||null===t)return this.messages.push(V.invalidOptionValue("bootstrap")),!1;try{const e=t;for(let t of e){const e=Object.keys(t);if(e.includes("id")||this.messages.push(V.missingKeyInBootstrapValue("id")),e.includes("variation")||this.messages.push(V.missingKeyInBootstrapValue("variation")),e.includes("variationType")||this.messages.push(V.missingKeyInBootstrapValue("variationType")),this.messages.length>0)return!1}}catch(e){return this.messages.push(V.wrongOptionType("bootstrap",this.getType(),typeof t)),!1}return!0}getType(){return"IFlagBase[]"}}class Z{constructor(){this.messages=[]}is(t){if("object"!=typeof t||null===t)return this.messages.push(V.mandatory("user")),!1;const e=t;return"string"!=typeof e.keyId||""===e.keyId.trim()?(this.messages.push(V.mandatory("user.keyId")),!1):"string"==typeof e.name&&""!==e.name.trim()||(this.messages.push(V.mandatory("user.name")),!1)}getType(){return"user"}}const tt=/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d\d*)?(Z|[-+]\d\d(:\d\d)?)/;class et{is(t){return"number"==typeof t||"string"==typeof t&&tt.test(t)}getType(){return"date"}}class it extends Q{constructor(){super(/^(\w|\.|-)+$/)}is(t){return super.is(t)&&"kind"!==t}}class nt{static createTypeArray(t,e){return new J(t,e)}static numberWithMin(t){return new H(t)}static stringMatchingRegex(t){return new Q(t)}}function st(t){if("string"==typeof t)return t;if(void 0===t)return"undefined";if(null===t)return"null";if(Object.prototype.hasOwnProperty.call(t,"toString"))try{return t.toString()}catch(t){}if("bigint"==typeof t)return`${t}n`;try{return JSON.stringify(t)}catch(t){return t instanceof TypeError&&t.message.indexOf("circular")>=0?"[Circular]":"[Not Stringifiable]"}}nt.String=new q("string",""),nt.Number=new q("number",0),nt.ObjectOrFactory=new W,nt.Object=new q("object",{}),nt.StringArray=new J("string[]",""),nt.Boolean=new q("boolean",!0),nt.User=new Z,nt.Bootstrap=new X,nt.Function=new G,nt.Date=new et,nt.Kind=new it,nt.NullableBoolean=new Y;const rt={s:t=>st(t),d:t=>function(t){return"symbol"==typeof t?"NaN":"bigint"==typeof t?`${t}n`:String(Number(t))}(t),i:t=>function(t){return"symbol"==typeof t?"NaN":"bigint"==typeof t?`${t}n`:String(parseInt(t,10))}(t),f:t=>function(t){return"symbol"==typeof t?"NaN":String(parseFloat(t))}(t),j:t=>st(t),o:t=>st(t),O:t=>st(t),c:()=>""};function ot(...t){var e;const i=t.shift();if(nt.String.is(i)){let n="",s=0;for(;s<i.length;){const r=i.charAt(s);if("%"===r){if(s+1<i.length){const r=i.charAt(s+1);if(r in rt&&t.length){const i=t.shift();n+=null===(e=rt[r])||void 0===e?void 0:e.call(rt,i)}else n+="%"===r?"%":`%${r}`;s+=2}}else n+=r,s+=1}return t.length&&(n.length&&(n+=" "),n+=t.map(st).join(" ")),n}return t.map(st).join(" ")}const at={debug:0,info:1,warn:2,error:3,none:4},lt=["debug","info","warn","error","none"];class ut{static get(){return new ut({})}constructor(t){var e,i,n,s;this.logLevel=null!==(i=at[null!==(e=t.level)&&void 0!==e?e:"info"])&&void 0!==i?i:at.info,this.name=null!==(n=t.name)&&void 0!==n?n:"FeatBit",this.destination=null!==(s=t.destination)&&void 0!==s?s:console.log,this.formatter=t.formatter}tryFormat(...t){var e;try{return this.formatter?null===(e=this.formatter)||void 0===e?void 0:e.call(this,...t):ot(...t)}catch(e){return ot(...t)}}tryWrite(t){try{this.destination(t)}catch(e){console.error(t)}}log(t,e){if(t>=this.logLevel){const i=`${lt[t]}: [${this.name}]`;try{this.destination?this.tryWrite(`${i} ${this.tryFormat(...e)}`):console.error(...e)}catch(t){console.error(...e)}}}error(...t){this.log(at.error,t)}warn(...t){this.log(at.warn,t)}info(...t){this.log(at.info,t)}debug(...t){this.log(at.debug,t)}}const ct={error:nt.Function,warn:nt.Function,info:nt.Function,debug:nt.Function};class ht{constructor(t,e){Object.entries(ct).forEach(([e,i])=>{if(!i.is(t[e]))throw new Error(`Provided logger instance must support logger.${e}(...) method`)}),this.logger=t,this.fallback=e}log(t,e){try{this.logger[t](...e)}catch(i){this.fallback[t](...e)}}error(...t){this.log("error",t)}warn(...t){this.log("warn",t)}info(...t){this.log("info",t)}debug(...t){this.log("debug",t)}}class dt{constructor(t){this._keyId="",this._name="",this._custom=[],this._keyId=t}name(t){return this._name=t,this}custom(t,e){var i;return null===(i=this._custom)||void 0===i||i.push({name:t,value:`${e}`}),this}build(){return{name:this._name,keyId:this._keyId,customizedProperties:this._custom}}}class vt{fetch(t,e={}){return fetch(t,e)}}function gt(t){return class extends t{on(t,e,i){return this.emitter.on(t,e,i),this}addListener(t,e,i){return this.emitter.addListener(t,e,i),this}once(t,e,i){return this.emitter.once(t,e,i),this}removeListener(t,e,i){return this.emitter.removeListener(t,e,i),this}off(t,e,i){return this.emitter.off(t,e,i),this}removeAllListeners(t){return this.emitter.removeAllListeners(t),this}listeners(t){return this.emitter.listeners(t)}emit(t,...e){return this.emitter.emit(t,e),this}listenerCount(t){return this.emitter.listenerCount(t)}prependListener(t,e,i){return this.emitter.prependListener(t,e,i),this}prependOnceListener(t,e,i){return this.emitter.prependOnceListener(t,e,i),this}eventNames(){return this.emitter.eventNames()}maybeReportError(t){return this.emitter.maybeReportError(t),this}}}class ft{constructor(t){this.logger=t,this.events={}}listeningTo(t){return!!this.events[t]}on(t,e,i){return this.events[t]=this.events[t]||[],this.events[t]=this.events[t].concat({handler:e,context:i}),this}addListener(t,e,i){return this.on(t,e,i)}once(t,e,i){const n=(...s)=>{this.off(t,n,i),e.apply(i,s)};return this.on(t,n,i)}off(t,e,i){if(!this.events[t])return this;for(let n=0;n<this.events[t].length;n++)this.events[t][n].handler===e&&this.events[t][n].context===i&&(this.events[t]=this.events[t].slice(0,n).concat(this.events[t].slice(n+1)));return this}removeListener(t,e,i){return this.off(t,e,i)}removeAllListeners(t){return t?delete this.events[t]:this.events={},this}listeners(t){return this.events[t]?this.events[t].map(t=>t.handler):[]}emit(t,...e){if(!this.events[t])return this;const i=[...this.events[t]];for(let t=0;t<i.length;t++)i[t].handler.apply(i[t].context,Array.prototype.slice.call(arguments,1));return this}listenerCount(t){return this.events[t]?this.events[t].length:0}prependListener(t,e,i){return this.events[t]=this.events[t]||[],this.events[t]=[{handler:e,context:i},...this.events[t]],this}prependOnceListener(t,e,i){const n=(...s)=>{this.off(t,n,i),e.apply(i,s)};return this.prependListener(t,n,i)}eventNames(){return Object.keys(this.events)}maybeReportError(t){var e;return t?(this.listeningTo("error")?this.emit("error",t):null===(e=this.logger)||void 0===e||e.error(t),this):this}}const pt={0:"Q",1:"B",2:"W",3:"S",4:"P",5:"H",6:"D",7:"X",8:"Z",9:"U"};function mt(t,e){var i="000000000000"+t;return i.slice(i.length-e).split("").map(t=>pt[t]).join("")}function yt(t){t=t.replace(/=*$/,"");const e=Date.now(),i=mt(e,e.toString().length),n=Math.max(Math.floor(Math.random()*t.length),2);return`${mt(n,3)}${mt(i.length,2)}${t.slice(0,n)}${i}${t.slice(n)}`}var bt;!function(t){t.full="full",t.patch="patch"}(bt||(bt={}));const wt=[1e3,3e3,5e3,7e3,11e3,13e3,3e4,6e4],St=gt(class{constructor(){this.retryCounter=0,this.closed=!1,this._config={},this.emitter=new ft}identify(t){return this._config.user=t,this.doDataSync()}connect(){var t,e,i,n;let s=this;const r=Date.now(),o=this._config.streamingUri.replace(/^http/,"ws")+`?type=client&token=${yt(this._config.sdkKey)}`;this.ws=new WebSocket(o),null===(t=s.ws)||void 0===t||t.addEventListener("open",function(t){s._config.logger.info(`WebSocket connection succeeded, connection time: ${Date.now()-r} ms`),s.retryCounter=0,s.doDataSync(),s.sendPingMessage(),s.bumpLiveness()}),null===(e=s.ws)||void 0===e||e.addEventListener("close",function(t){s._config.logger.warn("WebSocket closed"),4003!==t.code&&s.reconnect()}),null===(i=s.ws)||void 0===i||i.addEventListener("error",function(t){s._config.logger.debug("error")}),null===(n=s.ws)||void 0===n||n.addEventListener("message",function(t){s.bumpLiveness();const e=JSON.parse(t.data);if("data-sync"===e.messageType){if(e.data.userKeyId!==s._config.user.keyId)return;switch(e.data.eventType){case bt.patch:s.emitter.emit("patch",e);break;case bt.full:s.emitter.emit("put",e)}}})}close(){var t;this.closed=!0,clearTimeout(this.livenessTimer),null===(t=this.ws)||void 0===t||t.close(4003,"The client is closed by user"),this.ws=void 0}config(t){t.emitter&&(this.emitter=t.emitter),this._config=Object.assign({},t)}bumpLiveness(){clearTimeout(this.livenessTimer),this.livenessTimer=setTimeout(()=>{var t;this._config.logger.warn("no server activity within timeout, recycling socket"),null===(t=this.ws)||void 0===t||t.close()},2*this._config.pingInterval)}sendPingMessage(){const t={messageType:"ping",data:null};setTimeout(()=>{var e;try{(null===(e=this.ws)||void 0===e?void 0:e.readyState)===WebSocket.OPEN?(this._config.logger.debug("sending ping"),this.ws.send(JSON.stringify(t)),this.sendPingMessage()):this._config.logger.debug(`socket closed at ${new Date}`)}catch(t){this._config.logger.debug(t)}},this._config.pingInterval)}doDataSync(){var t,e;const i={messageType:"data-sync",data:{timestamp:this._config.getStoreTimestamp(),user:this._config.user}};try{return(null===(t=this.ws)||void 0===t?void 0:t.readyState)===WebSocket.OPEN?(this._config.logger.debug("requesting data"),null===(e=this.ws)||void 0===e||e.send(JSON.stringify(i)),!0):(this._config.logger.error("not requesting data because socket not open"),!1)}catch(t){return this._config.logger.debug(t),!1}}reconnect(){if(!this.closed){this.ws=void 0;const t=wt[Math.min(this.retryCounter++,wt.length-1)];this._config.logger.info(`The client will try to reconnect in ${t} milliseconds.`),setTimeout(()=>{this._config.logger.info(`The client is trying to reconnect, flag evaluation results may be stale until reconnected, waited for: ${t} milliseconds`),this.connect()},t)}}});var Et=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class kt{constructor(){this.store={},this.initCalled=!1,this._user={}}identify(t){return Et(this,void 0,void 0,function*(){this._user=Object.assign({},t),yield this.saveUser(),yield this.loadStoreFromStorage()})}get user(){return this._user}addItem(t,e,i){return Et(this,void 0,void 0,function*(){let n=this.store[t.namespace];if(n||(n={},this.store[t.namespace]=n),Object.hasOwnProperty.call(n,e)){const t=n[e];(!t||t.version<=i.version)&&(n[e]=i)}else n[e]=i;i.version>this.store.version&&(this.store.version=i.version),yield this.dumpStoreToStorage()})}get(t,e){const i=this.store[t.namespace];if(i&&Object.prototype.hasOwnProperty.call(i,e)){const t=i[e];if(t)return t}return null}all(t){var e;const i={},n=null!==(e=this.store[t.namespace])&&void 0!==e?e:{};return Object.entries(n).forEach(([t,e])=>{e&&(i[t]=e)}),[i,this.store.version]}init(t){return Et(this,void 0,void 0,function*(){this.store=t,Object.keys(t).map(e=>{Object.entries(t[e]).forEach(([t,e])=>{const i=e;i.version>this.store.version&&(this.store.version=i.version)})}),yield this.dumpStoreToStorage(),this.initCalled=!0})}upsert(t,e){return Et(this,void 0,void 0,function*(){yield this.addItem(t,e.key,e)})}initialized(){return this.initCalled}close(){}get version(){return this.store.version}get description(){return""}saveUser(){return Et(this,void 0,void 0,function*(){})}loadStoreFromStorage(){return Et(this,void 0,void 0,function*(){})}dumpStoreToStorage(){return Et(this,void 0,void 0,function*(){})}}class Ot{static bool(t){return"TRUE"===(null==t?void 0:t.toUpperCase())?Ot.success(!0):"FALSE"===(null==t?void 0:t.toUpperCase())?Ot.success(!1):Ot.error()}static number(t){const e=Number(t);return Number.isNaN(e)?Ot.error():Ot.success(e)}static string(t){return Ot.success(t)}static json(t){try{const e=JSON.parse(t);return Ot.success(e)}catch(t){return Ot.error()}}static success(t){return{isSucceeded:!0,value:t}}static error(){return{isSucceeded:!1}}}var Tt=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};function Pt(t){var e,i;return t?`${t.keyId},${null!==(e=t.name)&&void 0!==e?e:""},${null===(i=t.customizedProperties)||void 0===i?void 0:i.sort((t,e)=>{const i=t.name.toLowerCase(),n=e.name.toLowerCase();return i<n?-1:i>n?1:0}).map(t=>`${t.name}:${t.value}`).join(",")}`:""}function It(t){return Tt(this,void 0,void 0,function*(){const e=Pt(t);if(!e)return"";const i=(new TextEncoder).encode(e),n=yield crypto.subtle.digest("SHA-256",i);return Array.from(new Uint8Array(n)).map(t=>t.toString(16).padStart(2,"0")).join("")})}const Ft=(t,e=5e3)=>{let i;return(...n)=>{clearTimeout(i),i=setTimeout(()=>{t(...n)},e)}};function xt(t){return JSON.parse(JSON.stringify(t))}var jt,Ut=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class $t extends kt{constructor(){super(),this.allStores={}}close(){}get description(){return"in-memory-store"}saveUser(){return Ut(this,void 0,void 0,function*(){})}dumpStoreToStorage(){return Ut(this,void 0,void 0,function*(){const t=yield It(this._user),e=`${o}-${t}`;this.allStores[e]=xt(this.store)})}loadStoreFromStorage(){return Ut(this,void 0,void 0,function*(){const t=yield It(this._user),e=`${o}-${t}`,i=this.allStores[e];i?this.store=i:this.store.version=0})}}!function(t){t.POLLING="polling",t.STREAMING="streaming"}(jt||(jt={}));class Nt{close(){}start(){}stop(){}identify(){return t=this,e=void 0,n=function*(){},new((i=void 0)||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())});var t,e,i,n}}var _t=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class zt{constructor(t,e,i,n,s){this.requestor=e,this.getStoreTimestamp=i,this.listeners=n,this.errorHandler=s,this.stopped=!1,this.logger=t.logger,this.pollingInterval=t.pollingInterval,this.user=t.user}poll(t,e){var i;if(this.stopped)return;const n=Date.now();null===(i=this.logger)||void 0===i||i.debug("Polling for feature flag and segments updates"),this.requestor.requestData(this.getStoreTimestamp(),this.user,(i,s)=>_t(this,void 0,void 0,function*(){var r,o,a,u,c,h,d;const v=Date.now()-n,g=Math.max(this.pollingInterval-v,0);if(null===(r=this.logger)||void 0===r||r.debug("Elapsed: %d ms, sleeping for %d ms",v,g),i){const{status:n}=i;if(!z(n)){const t=x(i,"polling request");return null===(o=this.logger)||void 0===o||o.error(t),null===(a=this.errorHandler)||void 0===a||a.call(this,new j(t,n)),void(null==e||e())}null===(u=this.logger)||void 0===u||u.warn(x(i,"polling request","will retry")),this.timeoutHandle=setTimeout(()=>{this.poll(t,e)},g)}else{let e=[],i=null===(c=this.user)||void 0===c?void 0:c.keyId,n=this.listeners.get("patch");if(s){const t=JSON.parse(s);if("data-sync"===t.messageType){switch(t.data.eventType){case bt.patch:n=this.listeners.get("patch");break;case bt.full:n=this.listeners.get("put")}({featureFlags:e,userKeyId:i}=t.data),e=e.map(t=>Object.assign(Object.assign({},t),{origin:l.Remote}))}}const r=null===(h=null==n?void 0:n.deserializeData)||void 0===h?void 0:h.call(n,e);yield null===(d=null==n?void 0:n.processJson)||void 0===d?void 0:d.call(n,i,r),null==t||t(),this.timeoutHandle=setTimeout(()=>{this.poll()},g)}}))}identify(t){return _t(this,void 0,void 0,function*(){return this.user=Object.assign({},t),this.timeoutHandle&&(clearTimeout(this.timeoutHandle),this.timeoutHandle=void 0),new Promise((t,e)=>{this.poll(t,e)})})}close(){this.stop()}start(){this.poll()}stop(){this.timeoutHandle&&(clearTimeout(this.timeoutHandle),this.timeoutHandle=void 0),this.stopped=!0}}var Ct=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class Lt{constructor(t,e,i,n){this.requests=n,this.headers=F(t,i),this.uri=e.pollingUri}request(t,e){return Ct(this,void 0,void 0,function*(){const i=yield this.requests.fetch(t,e),n=yield i.text();return{res:i,body:n}})}requestData(t,e,i){return Ct(this,void 0,void 0,function*(){const n={method:"POST",headers:this.headers,body:JSON.stringify(e)};try{const{res:e,body:s}=yield this.request(`${this.uri}?timestamp=${null!=t?t:0}`,n);if(200!==e.status&&304!==e.status){const t=new U(`Unexpected status code: ${e.status}`,e.status);return i(t,void 0)}return i(void 0,304===e.status?null:s)}catch(t){return i(t,void 0)}})}}var Dt=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};const Rt=class{constructor(t,e,i,n,s,r,o){this.getStoreTimestamp=s,this.listeners=r;const{logger:a,streamingUri:u}=i;this.logger=a,this.socket=n,this.socket.config({sdkKey:t,streamingUri:u,pingInterval:o,user:e,logger:a,getStoreTimestamp:s}),this.listeners.forEach(({deserializeData:t,processJson:e},i)=>{var n;null===(n=this.socket)||void 0===n||n.addListener(i,n=>Dt(this,void 0,void 0,function*(){var s,r;if(null===(s=this.logger)||void 0===s||s.debug(`Received ${i} event`),null==n?void 0:n.data){const{userKeyId:i}=n.data,s=n.data.featureFlags.map(t=>Object.assign(Object.assign({},t),{origin:l.Remote})),o=t(s);yield e(i,o),null===(r=this.identifyResolve)||void 0===r||r.call(this),this.identifyResolve=void 0}}))})}identify(t){var e;return Dt(this,void 0,void 0,function*(){const i=null===(e=this.socket)||void 0===e?void 0:e.identify(t);return new Promise((t,e)=>{this.identifyResolve=t,i||e(new Error("Websocket identify failed"))})})}start(){var t;this.logConnectionStarted(),null===(t=this.socket)||void 0===t||t.connect()}logConnectionStarted(){var t;this.connectionAttemptStartTime=Date.now(),null===(t=this.logger)||void 0===t||t.info(`Stream connection attempt StartTime ${this.connectionAttemptStartTime}`)}close(){this.stop()}stop(){var t;null===(t=this.socket)||void 0===t||t.close(),this.socket=void 0}};function Mt(t){return t.replace(/\/+$/,"")}const At="",Kt=2147483648,Bt={startWaitTime:nt.Number,sdkKey:nt.String,pollingUri:nt.String,streamingUri:nt.String,eventsUri:nt.String,webSocketPingInterval:nt.Number,logger:nt.Object,logLevel:nt.String,store:nt.ObjectOrFactory,dataSynchronizer:nt.ObjectOrFactory,flushInterval:nt.Number,maxEventsInQueue:nt.Number,disableEvents:nt.Boolean,pollingInterval:nt.Number,offline:nt.Boolean,dataSyncMode:nt.String,bootstrap:nt.Bootstrap,user:nt.User},Vt={startWaitTime:5e3,sdkKey:"",pollingUri:"",streamingUri:"",eventsUri:"",dataSyncMode:jt.STREAMING,sendEvents:!0,webSocketPingInterval:18e3,flushInterval:2e3,maxEventsInQueue:1e4,disableEvents:!1,pollingInterval:3e4,offline:!1,store:t=>new $t,bootstrap:void 0,user:void 0};class Wt{constructor(t={}){var e,i;this.bootstrapProvider=new h,t=t||{},this.logger=t.logger;const{errors:n,validatedOptions:s}=function(t){let e=[];const i=Object.assign({},Vt);return Object.keys(t).forEach(n=>{var s;const r=t[n],o=Bt[n];if(o)if(o.is(r))i[n]=r;else if("boolean"===o.getType())e.push(V.wrongOptionTypeBoolean(n,typeof r)),i[n]=!!r;else if(o instanceof H&&nt.Number.is(r)){const{min:t}=o;e.push(V.optionBelowMinimum(n,r,t)),i[n]=t}else o instanceof Z?(e=[...e,...o.messages],i[n]=Vt[n]):(e.push(V.wrongOptionType(n,o.getType(),typeof r)),i[n]=Vt[n]);else null===(s=t.logger)||void 0===s||s.warn(V.unknownOption(n))}),{errors:e,validatedOptions:i}}(t);if(n.forEach(t=>{var e;null===(e=this.logger)||void 0===e||e.error(t)}),this.user=s.user,function(t,e){var i,n,s;const{streamingUri:r,pollingUri:o,eventsUri:a}=t,l=u(r)||r===At,c=u(o)||o===At,h=u(a)||a===At;!e.offline&&(h||l&&c)&&(h&&(null===(i=e.logger)||void 0===i||i.error(V.partialEndpoint("eventsUri"))),e.dataSyncMode===jt.STREAMING&&l&&(null===(n=e.logger)||void 0===n||n.error(V.partialEndpoint("streamingUri"))),e.dataSyncMode===jt.POLLING&&c&&(null===(s=e.logger)||void 0===s||s.error(V.partialEndpoint("pollingUri"))))}(t,s),this.streamingUri=`${Mt(s.streamingUri)}/streaming`,this.pollingUri=`${Mt(s.pollingUri)}/api/public/sdk/client/latest-all`,this.eventsUri=`${Mt(s.eventsUri)}/api/public/insight/track`,this.startWaitTime=s.startWaitTime,this.sdkKey=s.sdkKey,this.webSocketPingInterval=s.webSocketPingInterval,this.flushInterval=s.flushInterval,this.maxEventsInQueue=s.maxEventsInQueue,this.disableEvents=s.disableEvents,this.pollingInterval=s.pollingInterval,this.offline=s.offline,s.bootstrap&&s.bootstrap.length>0)try{this.bootstrapProvider=new c(s.bootstrap)}catch(t){null===(e=this.logger)||void 0===e||e.error("Failed to parse bootstrap JSON, use NullBootstrapProvider.")}this.offline&&(null===(i=this.logger)||void 0===i||i.info("Offline mode enabled. No data synchronization with the FeatBit server will occur.")),this.dataSyncMode=s.dataSyncMode,nt.Function.is(s.dataSynchronizer)?this.dataSynchronizerFactory=s.dataSynchronizer:this.dataSynchronizerFactory=()=>s.dataSynchronizer,nt.Function.is(s.store)?this.storeFactory=s.store:this.storeFactory=()=>s.store}}class qt{constructor(t,e,i){this.sdkKey=t,this.platform=i,this.logger=e.logger,this.offline=e.offline,this.flushInterval=e.flushInterval,this.maxEventsInQueue=e.maxEventsInQueue,this.streamingUri=e.streamingUri,this.pollingUri=e.pollingUri,this.eventsUri=e.eventsUri}}class Jt{constructor(t,e){this.valid=t,this.message=e}static fromUser(t){if(!t)return Jt.contextForError("No user specified");const{keyId:e,name:i}=t;if(null==e||""===e.trim())return Jt.contextForError("key is mandatory");const n=new Jt(!0);return n._user=t,n}get user(){return this._user}get keyId(){return this._user.keyId}value(t){var e,i,n,s,r;return"keyId"===t?null===(e=this._user)||void 0===e?void 0:e.keyId:"name"===t?null===(i=this._user)||void 0===i?void 0:i.name:null===(r=null===(s=null===(n=this._user)||void 0===n?void 0:n.customizedProperties)||void 0===s?void 0:s.find(e=>e.name===t))||void 0===r?void 0:r.value}static contextForError(t){return new Jt(!1,t)}}var Ht,Qt=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};!function(t){t[t.Initializing=0]="Initializing",t[t.Initialized=1]="Initialized",t[t.Failed=2]="Failed"}(Ht||(Ht={}));class Gt{constructor(t,e,i){this.options=t,this.platform=e,this.state=Ht.Initializing,this.onError=i.onError,this.onFailed=i.onFailed,this.onReady=i.onReady;const{onUpdate:n,hasEventListeners:s}=i,r=new Wt(t);if(!r.sdkKey&&!r.offline)throw new Error("You must configure the client with an SDK key");if(!r.user)throw new Error("You must configure the client with a user");this.config=r,this.logger=r.logger,this.init(n,s)}init(t,e){var i,n,s;return Qt(this,void 0,void 0,function*(){const r=new qt(this.config.sdkKey,this.config,this.platform);if(this.store=this.config.storeFactory(r),yield this.store.identify(this.config.user),this.dataSourceUpdates=new y(this.store,e,t),this.evaluator=new P(this.store,this.logger),yield this.config.bootstrapProvider.populate(this.config.user.keyId,this.dataSourceUpdates),this.config.offline)this.eventProcessor=new B,this.dataSynchronizer=new Nt,this.initSuccess();else{this.config.disableEvents?this.eventProcessor=new B:this.eventProcessor=new K(r);const t=v(this.dataSourceUpdates,this.logger,{put:()=>this.initSuccess(),patch:()=>this.initSuccess()}),e=this.config.dataSyncMode===jt.STREAMING?new Rt(this.config.sdkKey,this.config.user,r,this.platform.webSocket,()=>this.store.version,t,this.config.webSocketPingInterval):new zt(this.config,new Lt(this.config.sdkKey,this.config,this.platform.info,this.platform.requests),()=>this.store.version,t,t=>this.dataSourceErrorHandler(t));this.dataSynchronizer=null!==(s=null===(n=(i=this.config).dataSynchronizerFactory)||void 0===n?void 0:n.call(i,r,this.store,this.dataSourceUpdates,()=>this.initSuccess(),t=>this.dataSourceErrorHandler(t)))&&void 0!==s?s:e}this.start()})}identify(t){var e,i;return Qt(this,void 0,void 0,function*(){const s=new Z;if(!s.is(t))return void s.messages.forEach(t=>{var e;null===(e=this.logger)||void 0===e||e.warn(t)});const[r,o]=this.store.all(n.Flags),a={flags:Object.assign({},r),version:o};this.config.user=t,yield this.store.identify(t);try{yield this.dataSynchronizer.identify(t)}catch(t){null===(e=this.logger)||void 0===e||e.error("dataSynchronizer unable to identify user.")}const[l,u]=this.store.all(n.Flags),c={flags:Object.assign({},l),version:u};0===Object.keys(l).length?yield this.config.bootstrapProvider.populate(t.keyId,this.dataSourceUpdates):null===(i=this.dataSourceUpdates)||void 0===i||i.checkUpdates(a,c)})}start(){this.config.offline||(this.dataSynchronizer.start(),setTimeout(()=>{var t,e;if(!this.initialized()){const i=`FbClient failed to start successfully within ${this.config.startWaitTime} milliseconds. This error usually indicates a connection issue with FeatBit or an invalid sdkKey.Please double-check your sdkKey and streamingUri/pollingUri configuration. We will continue to initialize the FbClient, it still have a chance to get to work if it's a temporary network issue`,n=new _(i);return this.state=Ht.Failed,this.rejectionReason=n,null===(t=this.initReject)||void 0===t||t.call(this,n),null===(e=this.logger)||void 0===e?void 0:e.warn(i)}},this.config.startWaitTime))}initialized(){return this.state===Ht.Initialized}waitForInitialization(){return this.initializedPromise?this.initializedPromise:this.state===Ht.Initialized?(this.initializedPromise=Promise.resolve(this),this.initializedPromise):this.state===Ht.Failed?(this.initializedPromise=Promise.reject(this.rejectionReason),this.initializedPromise):(this.initializedPromise||(this.initializedPromise=new Promise((t,e)=>{this.initResolve=t,this.initReject=e})),this.initializedPromise)}boolVariation(t,e){return this.evaluateCore(t,e,Ot.bool).value}boolVariationDetail(t,e){return this.evaluateCore(t,e,Ot.bool)}jsonVariation(t,e){return this.evaluateCore(t,e,Ot.json).value}jsonVariationDetail(t,e){return this.evaluateCore(t,e,Ot.json)}numberVariation(t,e){return this.evaluateCore(t,e,Ot.number).value}numberVariationDetail(t,e){return this.evaluateCore(t,e,Ot.number)}stringVariation(t,e){return this.evaluateCore(t,e,Ot.string).value}stringVariationDetail(t,e){return this.evaluateCore(t,e,Ot.string)}variation(t,e){return this.evaluateCore(t,e).value}variationDetail(t,e){return this.evaluateCore(t,e)}getAllVariations(){var t;const e=Jt.fromUser(this.config.user);if(!e.valid){const i=new N(`${null!==(t=e.message)&&void 0!==t?t:"User not valid;"} returning default value.`);return this.onError(i),Promise.resolve([])}const[i,s]=this.store.all(n.Flags),r=Object.keys(i).map(t=>{var e;const i=this.evaluator.evaluate(t);return{flagKey:t,kind:i.kind,reason:i.reason,value:null===(e=i.value)||void 0===e?void 0:e.variation}});return Promise.resolve(r)}close(){var t;return Qt(this,void 0,void 0,function*(){yield this.eventProcessor.close(),null===(t=this.dataSynchronizer)||void 0===t||t.close(),this.store.close()})}track(t,e){const i=new k(this.config.user,t,this.platform.info.appType,null!=e?e:1);this.eventProcessor.record(i)}flush(t){return Qt(this,void 0,void 0,function*(){try{return yield this.eventProcessor.flush(),null==t||t(!0),!0}catch(e){return null==t||t(!1),!1}})}evaluateCore(t,e,i){var s,r,o;const a=Jt.fromUser(this.config.user);if(!a.valid){const i=new N(`${null!==(s=a.message)&&void 0!==s?s:"User not valid;"} returning default value.`);return this.onError(i),{flagKey:t,kind:f.Error,reason:i.message,value:e}}const u=this.evaluator.evaluate(t);if(u.kind===f.FlagNotFound){const i=new N(u.reason);return this.onError(i),{flagKey:t,kind:u.kind,reason:u.reason,value:e}}if(this.initialized()){const e=null===(o=this.store)||void 0===o?void 0:o.get(n.Flags,t);(null==e?void 0:e.origin)===l.Remote&&this.eventProcessor.record(u.toEvalEvent(this.config.user))}else null===(r=this.logger)||void 0===r||r.warn("Variation called before FeatBit client initialization completed (did you wait for the'ready' event?)");let c;if(i)c=i;else switch(u.value.variationType){case g.boolean:c=Ot.bool;break;case g.number:c=Ot.number;break;case g.json:c=Ot.json;break;case g.string:default:c=Ot.string}const{isSucceeded:h,value:d}=c(u.value.variation);return h?{flagKey:t,kind:u.kind,reason:u.reason,value:d}:{flagKey:t,kind:f.WrongType,reason:"type mismatch",value:e}}dataSourceErrorHandler(t){var e;const i=401===t.code?new Error("Authentication failed. Double check your SDK key."):t;this.onError(i),this.onFailed(i),this.initialized()||(this.state=Ht.Failed,this.rejectionReason=i,null===(e=this.initReject)||void 0===e||e.call(this,i))}initSuccess(){var t,e;this.initialized()||(this.state=Ht.Initialized,null===(t=this.logger)||void 0===t||t.info("FbClient started successfully."),null===(e=this.initResolve)||void 0===e||e.call(this,this),this.onReady())}}const Yt="4.2.16";class Xt{get appType(){return"Browser-Client-SDK"}platformData(){return{os:{},name:"Browser",additional:{}}}sdkData(){return{name:"@featbit/js-client-sdk",version:Yt,userAgent:`${this.appType}/${Yt}`}}}class Zt{constructor(t){this.info=new Xt,this.requests=new vt,this.webSocket=new St}}var te=function(t,e,i,n){return new(i||(i=Promise))(function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i(function(t){t(e)})).then(o,a)}l((n=n.apply(t,e||[])).next())})};class ee extends kt{constructor(t){super(),this.logger=t.logger}close(){}get description(){return"local-storage-store"}saveUser(){return te(this,void 0,void 0,function*(){localStorage.setItem(a,Pt(this._user))})}dumpStoreToStorage(){return te(this,void 0,void 0,function*(){const t=yield It(this._user),e=`${o}-${t}`;localStorage.setItem(e,JSON.stringify(this.store))})}loadStoreFromStorage(){return te(this,void 0,void 0,function*(){const t=yield It(this._user),e=`${o}-${t}`,i=localStorage.getItem(e);let n=null;try{i&&i.trim().length>0&&(n=JSON.parse(i))}catch(t){this.logger.error(`error while loading local data store: ${e}`,t)}n?this.store=n:this.store.version=0})}}const ie=gt(class extends Gt{constructor(t,e=void 0){var i;const n=new ut({level:"warn",destination:console.log});let s;s=t.logger?new ht(t.logger,n):new ut({level:null!==(i=t.logLevel)&&void 0!==i?i:"warn",destination:console.log});const r=new ft(s);let{store:o}=t;o||(o=new ee(t)),super(Object.assign(Object.assign({},t),{logger:s,store:o}),null!=e?e:new Zt(Object.assign(Object.assign({},t),{logger:s})),{onError:t=>{r.listenerCount("error")&&r.emit("error",t)},onFailed:t=>{r.emit("failed",t)},onReady:()=>{r.emit("ready")},onUpdate:t=>{r.emit("update",[t]),t.forEach(t=>r.emit(`update:${t}`,t))},hasEventListeners:()=>r.eventNames().some(t=>"update"===t||"string"==typeof t&&t.startsWith("update:"))}),this.emitter=r}});class ne{constructor(t){this._options=null!=t?t:{}}build(){return new ie(this._options,this._platform)}platform(t){return this._platform=t,this}startWaitTime(t){return this._options.startWaitTime=t,this}sdkKey(t){return this._options.sdkKey=t,this}user(t){return this._options.user=t,this}streamingUri(t){return this._options.streamingUri=t,this}pollingUri(t){return this._options.pollingUri=t,this}eventsUri(t){return this._options.eventsUri=t,this}dataSyncMode(t){return this._options.dataSyncMode=t,this}pollingInterval(t){return this._options.pollingInterval=t,this}flushInterval(t){return this._options.flushInterval=t,this}maxEventsInQueue(t){return this._options.maxEventsInQueue=t,this}disableEvents(t){return this._options.disableEvents=t,this}logger(t){return this._options.logger=t,this}logLevel(t){return this._options.logLevel=t,this}offline(t){return this._options.offline=t,this}bootstrap(t){return this._options.bootstrap=t,this}dataSynchronizer(t){return this._options.dataSynchronizer=t,this}}return e})());
2
- //# sourceMappingURL=featbit-js-client-sdk-4.2.16.js.map