@featbit/js-client-sdk 3.0.13 → 3.0.14

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 (113) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +301 -301
  3. package/dist/esm/IFbClientCore.d.ts +1 -1
  4. package/dist/esm/IFbClientCore.d.ts.map +1 -1
  5. package/dist/esm/version.d.ts +1 -1
  6. package/dist/esm/version.js +1 -1
  7. package/dist/umd/{featbit-js-client-sdk-3.0.13.js → featbit-js-client-sdk-3.0.14.js} +2 -2
  8. package/dist/umd/featbit-js-client-sdk-3.0.14.js.map +1 -0
  9. package/dist/umd/featbit-js-client-sdk.js +1 -1
  10. package/dist/umd/featbit-js-client-sdk.js.map +1 -1
  11. package/package.json +46 -46
  12. package/src/Configuration.ts +232 -232
  13. package/src/Context.ts +61 -61
  14. package/src/FbClientBuilder.ts +167 -167
  15. package/src/FbClientCore.ts +405 -405
  16. package/src/IContextProperty.ts +3 -3
  17. package/src/IDataKind.ts +11 -11
  18. package/src/IFbClient.ts +29 -29
  19. package/src/IFbClientCore.ts +290 -290
  20. package/src/IVersionedData.ts +18 -18
  21. package/src/bootstrap/IBootstrapProvider.ts +4 -4
  22. package/src/bootstrap/JsonBootstrapProvider.ts +34 -34
  23. package/src/bootstrap/NullBootstrapProvider.ts +20 -20
  24. package/src/bootstrap/index.ts +2 -2
  25. package/src/constants.ts +1 -1
  26. package/src/data-sources/DataSourceUpdates.ts +116 -116
  27. package/src/data-sources/createStreamListeners.ts +67 -67
  28. package/src/data-sources/index.ts +1 -1
  29. package/src/data-sync/DataSyncMode.ts +3 -3
  30. package/src/data-sync/IDataSynchronizer.ts +15 -15
  31. package/src/data-sync/IRequestor.ts +10 -10
  32. package/src/data-sync/NullDataSynchronizer.ts +14 -14
  33. package/src/data-sync/PollingDataSynchronizer.ts +125 -125
  34. package/src/data-sync/Requestor.ts +61 -61
  35. package/src/data-sync/WebSocketDataSynchronizer.ts +77 -77
  36. package/src/data-sync/index.ts +8 -8
  37. package/src/data-sync/types.ts +19 -19
  38. package/src/data-sync/utils.ts +31 -31
  39. package/src/errors.ts +47 -47
  40. package/src/evaluation/EvalResult.ts +35 -35
  41. package/src/evaluation/Evaluator.ts +26 -26
  42. package/src/evaluation/IEvalDetail.ts +23 -23
  43. package/src/evaluation/ReasonKinds.ts +9 -9
  44. package/src/evaluation/data/IFlag.ts +29 -29
  45. package/src/evaluation/index.ts +4 -4
  46. package/src/events/DefaultEventProcessor.ts +83 -83
  47. package/src/events/DefaultEventQueue.ts +49 -49
  48. package/src/events/DefaultEventSender.ts +73 -73
  49. package/src/events/DefaultEventSerializer.ts +11 -11
  50. package/src/events/EventDispatcher.ts +127 -127
  51. package/src/events/EventSerializer.ts +4 -4
  52. package/src/events/IEventProcessor.ts +8 -8
  53. package/src/events/IEventQueue.ts +16 -16
  54. package/src/events/IEventSender.ts +13 -13
  55. package/src/events/NullEventProcessor.ts +15 -15
  56. package/src/events/event.ts +129 -129
  57. package/src/events/index.ts +11 -11
  58. package/src/index.ts +21 -21
  59. package/src/integrations/TestLogger.ts +24 -24
  60. package/src/integrations/index.ts +1 -1
  61. package/src/integrations/test_data/FlagBuilder.ts +59 -59
  62. package/src/integrations/test_data/TestData.ts +57 -57
  63. package/src/integrations/test_data/TestDataSynchronizer.ts +49 -49
  64. package/src/integrations/test_data/index.ts +4 -4
  65. package/src/logging/BasicLogger.ts +108 -108
  66. package/src/logging/IBasicLoggerOptions.ts +46 -46
  67. package/src/logging/ILogger.ts +49 -49
  68. package/src/logging/LogLevel.ts +8 -8
  69. package/src/logging/SafeLogger.ts +69 -69
  70. package/src/logging/format.ts +154 -154
  71. package/src/logging/index.ts +5 -5
  72. package/src/options/ClientContext.ts +39 -39
  73. package/src/options/IClientContext.ts +53 -53
  74. package/src/options/IOptions.ts +123 -123
  75. package/src/options/IUser.ts +6 -6
  76. package/src/options/IValidatedOptions.ts +29 -29
  77. package/src/options/OptionMessages.ts +35 -35
  78. package/src/options/UserBuilder.ts +35 -35
  79. package/src/options/Validators.ts +300 -300
  80. package/src/options/index.ts +7 -7
  81. package/src/platform/IInfo.ts +102 -102
  82. package/src/platform/IPlatform.ts +20 -20
  83. package/src/platform/IStore.ts +112 -112
  84. package/src/platform/IWebSocket.ts +22 -22
  85. package/src/platform/browser/BrowserInfo.ts +24 -24
  86. package/src/platform/browser/BrowserPlatform.ts +19 -19
  87. package/src/platform/browser/BrowserRequests.ts +6 -6
  88. package/src/platform/browser/BrowserWebSocket.ts +147 -147
  89. package/src/platform/browser/FbClient.ts +65 -65
  90. package/src/platform/browser/LocalStorageStore.ts +59 -59
  91. package/src/platform/index.ts +11 -11
  92. package/src/platform/requests.ts +76 -76
  93. package/src/store/BaseStore.ts +125 -125
  94. package/src/store/DataKinds.ts +6 -6
  95. package/src/store/IDataSourceUpdates.ts +68 -68
  96. package/src/store/InMemoryStore.ts +36 -36
  97. package/src/store/index.ts +5 -5
  98. package/src/store/serialization.ts +52 -52
  99. package/src/store/store.ts +37 -37
  100. package/src/utils/Emits.ts +75 -75
  101. package/src/utils/EventEmitter.ts +128 -128
  102. package/src/utils/IEventEmitter.ts +14 -14
  103. package/src/utils/Regex.ts +21 -21
  104. package/src/utils/ValueConverters.ts +55 -55
  105. package/src/utils/canonicalizeUri.ts +3 -3
  106. package/src/utils/debounce.ts +33 -33
  107. package/src/utils/http.ts +40 -40
  108. package/src/utils/index.ts +5 -5
  109. package/src/utils/isNullOrUndefined.ts +2 -2
  110. package/src/utils/serializeUser.ts +27 -27
  111. package/src/utils/sleep.ts +5 -5
  112. package/src/version.ts +1 -1
  113. package/dist/umd/featbit-js-client-sdk-3.0.13.js.map +0 -1
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 FeatBit
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2023 FeatBit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,301 +1,301 @@
1
- > **Attention**
2
- >
3
- > If you are using the v1 or v2 of the SDK, please refer to this [doc](https://github.com/featbit/featbit-js-client-sdk/tree/v2)
4
-
5
- # FeatBit Client SDK for JavaScript
6
-
7
- ## Introduction
8
-
9
- This is the Client-Side SDK for the 100% open-source feature flags management platform [FeatBit](https://github.com/featbit/featbit).
10
-
11
- Be aware, this is a client side SDK, it is intended for use in a single-user context, which can be mobile, desktop or embedded applications. This SDK can only be ran in a browser environment, it is not suitable for NodeJs applications.
12
-
13
- ## Get Started
14
-
15
- ### Installation
16
-
17
- ```bash
18
- npm install --save @featbit/js-client-sdk
19
- ```
20
- ### Prerequisite
21
-
22
- Before using the SDK, you need to obtain the environment secret (the sdkKey) and SDK URLs.
23
-
24
- Follow the documentation below to retrieve these values
25
- - [How to get environment secret](https://docs.featbit.co/sdk/faq#how-to-get-the-environment-secret)
26
- - [How to get SDK URLs](https://docs.featbit.co/sdk/faq#how-to-get-the-sdk-urls)
27
-
28
- ### Quick Start
29
-
30
- The following code demonstrates the basic usage of `@featbit/js-client-sdk`.
31
-
32
- ```javascript
33
- import { FbClientBuilder, UserBuilder } from "@featbit/js-client-sdk";
34
-
35
- const bob = new UserBuilder('a-unique-key-of-user')
36
- .name('bob')
37
- .custom('age', '18')
38
- .custom('country', 'FR')
39
- .build();
40
-
41
- // setup SDK client with websocket streaming
42
- const fbClient = new FbClientBuilder()
43
- .sdkKey("your_sdk_key")
44
- .streamingUri('ws://localhost:5100')
45
- .eventsUri("http://localhost:5100")
46
- .user(bob)
47
- .build();
48
-
49
- (async () => {
50
- // wait for the SDK to be initialized
51
- try {
52
- await fbClient.waitForInitialization();
53
- } catch(err) {
54
- // failed to initialize the SDK
55
- console.log(err);
56
- }
57
-
58
- // flag to be evaluated
59
- const flagKey = "game-runner";
60
-
61
- // evaluate a feature flag for a given user
62
- const boolVariation = await fbClient.boolVariation(flagKey, false);
63
-
64
- // switch user
65
- const alice = new UserBuilder('another-unique-key-of-user')
66
- .name('alice')
67
- .custom('country', 'UK')
68
- .custom('age', 36)
69
- .build();
70
-
71
- await fbClient.identify(alice);
72
- })();
73
- ```
74
-
75
- ## Examples
76
- - [web App](./examples/console-app)
77
- - For how to use FeatBit with React, please refer to the [react-client-sdk](https://github.com/featbit/featbit-react-client-sdk)
78
-
79
- ## SDK
80
-
81
- ### FbClient
82
-
83
- The `FbClient` is the heart of the SDK which provides access to FeatBit server. Applications should instantiate a single instance for the lifetime of the application.
84
-
85
- `FbClientBuilder` is used to construct a `FbClient` instance. The builder exposes methods to configure the SDK, and finally to create the `FbClient` instance.
86
-
87
- #### FbClient Using Streaming
88
-
89
- ```javascript
90
- import { FbClientBuilder, UserBuilder } from "@featbit/js-client-sdk";
91
-
92
- const user = new UserBuilder('a-unique-key-of-user')
93
- .name('bob')
94
- .build();
95
-
96
- const fbClient = new FbClientBuilder()
97
- .sdkKey("your_sdk_key")
98
- .streamingUri('ws://localhost:5100')
99
- .eventsUri("http://localhost:5100")
100
- .user(user)
101
- .build();
102
- ```
103
- #### FbClient Using Polling
104
-
105
- ```javascript
106
- import { FbClientBuilder, UserBuilder, DataSyncModeEnum } from "@featbit/js-client-sdk";
107
-
108
- const user = new UserBuilder('a-unique-key-of-user')
109
- .name('bob')
110
- .build();
111
-
112
- const fbClient = new FbClientBuilder()
113
- .sdkKey("your_sdk_key")
114
- .dataSyncMode(DataSyncModeEnum.POLLING)
115
- .pollingUri('http://localhost:5100')
116
- .eventsUri("http://localhost:5100")
117
- .pollingInterval(10000)
118
- .build();
119
- ```
120
-
121
- #### IUser
122
-
123
- `IUser` defines the attributes of a user for whom you are evaluating feature flags. IUser has two built-in attributes: key and name. The only mandatory attribute of a IUser is the key, which must uniquely identify each user.
124
-
125
- Besides these built-in properties, you can define any additional attributes associated with the user using `custom(string key, string value)` method on UserBuilder. Both built-in attributes and custom attributes can be referenced in targeting rules, and are included in analytics data.
126
-
127
- `UserBuilder` is used to construct a `IUser` instance. The builder exposes methods to configure the IUser, and finally to create the IUser instance.
128
-
129
- ```javascript
130
- import { UserBuilder } from "@featbit/js-client-sdk";
131
-
132
- const bob = new UserBuilder("unique_key_for_bob")
133
- .name("Bob")
134
- .custom('age', 18)
135
- .custom('country', 'FR')
136
- .build();
137
- ```
138
-
139
- ### Bootstrap
140
- If you already have the feature flags available, you can pass them to the SDK instead of requesting from the remote.
141
-
142
-
143
- > **_NOTE:_** The bootstrapped flags will be overridden by the remote flags if they are available.
144
-
145
- ```javascript
146
- // define the option with the bootstrap parameter
147
- const options = {
148
- ...
149
- bootstrap = [{
150
- // feature flag key name
151
- id: string,
152
- // variation value
153
- variation: string,
154
- // variation data type, string will be used if not specified
155
- variationType: VariationDataType
156
- }]
157
- }
158
-
159
- const fbClient = new FbClientBuilder(options).build();
160
- // or
161
- const fbClient = new FbClientBuilder()
162
- //... other options
163
- .bootstrap(options.bootstrap)
164
- .build();
165
- ```
166
-
167
- ### Evaluation
168
-
169
- After initialization, the SDK has all the feature flags locally, and it does not need to request the remote server for any feature flag evaluation. All evaluation is done locally and synchronously, the average evaluation time is less than 1 ms.
170
-
171
- There is a `variation` method that returns a flag value, and a `variationDetail` method that returns an object
172
- describing how the value was determined for each type.
173
-
174
- - boolVariation/boolVariationDetail
175
- - stringVariation/stringVariationDetail
176
- - numberVariation/numberVariationDetail
177
- - jsonVariation/jsonVariationDetail
178
-
179
- Variation calls take the feature flag key and a default value. If any error makes it impossible to
180
- evaluate the flag (for instance, the feature flag key does not match any existing flag), default value is returned.
181
-
182
- ```javascript
183
- // flag to be evaluated
184
- const flagKey = "game-runner";
185
-
186
- // evaluate a feature flag for a given user
187
- const boolVariation = await fbClient.boolVariation(flagKey, false);
188
-
189
- // evaluate a boolean flag for a given user with evaluation detail
190
- const boolVariationDetail = await fbClient.boolVariationDetail(flagKey, false);
191
- ```
192
-
193
- ### Offline Mode
194
-
195
- In some situations, you might want to stop making remote calls to FeatBit. Here is how:
196
- ```javascript
197
- import { FbClientBuilder } from "@featbit/browser-server-sdk";
198
-
199
- const fbClient = new FbClientBuilder()
200
- //... other options
201
- .offline(true)
202
- .build();
203
-
204
- ```
205
- When Offline mode is enabled, you should provide the flags with the [bootstrap](#bootstrap) option,
206
- otherwise, the SDK would return the defaul value you passed to the `variation` method.
207
-
208
- ### Events
209
-
210
- #### Wait for ready
211
-
212
- To find out when the client is ready, you can use one of two mechanisms: events or promises.
213
-
214
- The client object can emit JavaScript events. It emits a ready event when it receives initial flag values from the server. You can listen for this event to determine when the client is ready to evaluate flags.
215
-
216
- ```javascript
217
- fbClient.on('ready', () => {
218
- var flagValue = fbClient.variation("YOUR_FEATURE_KEY", defaultValue);
219
- });
220
- ```
221
-
222
- Or, you can use a promise instead of an event. The SDK has a method that returns a promise for initialization: **waitForInitialization()**. The behavior of waitUntilReady() is equivalent to the ready event. The promise resolves when the client receives its initial flag data. As with all promises, you can either use .then() to provide a callback, or use await if you are writing asynchronous code.
223
-
224
- ```javascript
225
- fbClient.waitForInitialization().then((data) => {
226
- // data has the following structure [ {id: 'featureFlagKey', variation: variationValue } ]
227
- // variationValue has the type as defined on remote
228
- // initialization succeeded, flag values are now available
229
- });
230
- // or, with await:
231
- const featureFlags = await fbClient.waitForInitialization();
232
- // initialization succeeded, flag values are now available
233
- ```
234
-
235
- The SDK only decides initialization has failed if it receives an error response indicating that the environment ID is invalid. If it has trouble connecting to FeatBit, it will keep retrying until it succeeds.
236
-
237
- #### Subscribe to flag(s) changes
238
-
239
- To get notified when a feature flag is changed, we offer two methods
240
- - subscribe to the changes of any feature flag(s)
241
-
242
- ```javascript
243
- fbClient.on('update', (keys: string[]) => {
244
- // do something when any feature flag changes
245
- });
246
-
247
- ```
248
- - subscribe to the changes of a specific feature flag
249
-
250
- ```javascript
251
- // replace feature_flag_key with your feature flag key
252
- fbClient.on('update:feature_flag_key', (key) => {
253
- const myFeature = fbClient.variation('feature_flag_key', defaultValue);
254
- });
255
-
256
- ```
257
-
258
- ### Switch user after initialization
259
- If the user changed after some process, login for example, the following method can be used to set the user after initialization.
260
-
261
- ```javascript
262
- await fbClient.identify(user);
263
- ```
264
-
265
-
266
- ### Data synchronization
267
-
268
- We use **WebSocket** or **Polling** to make the local data synchronized with the server, and then store them in localStorage by default. Whenever there is any change to a feature flag or its related data, this change will be pushed to the SDK, the average synchronization time is less than **100ms** if WebSocket is configured. Be aware the WebSocket/Polling connection may be interrupted due to internet outage, but it will be resumed automatically once the problem is gone.
269
-
270
- ### Network failure handling
271
-
272
- As all data is stored locally in the localStorage, in the following situations, the SDK would still work when there is temporarily no internet connection:
273
- - it has already received the data from previous connections
274
- - the `fbClient.bootstrap(featureFlags)` method is called with all necessary feature flags
275
-
276
- In the meantime, the SDK would try to reconnect to the server by an incremental interval, this makes sure that the websocket would be restored when the internet connection is back.
277
-
278
- ### Experiments (A/B/n Testing)
279
-
280
- We support automatic experiments for pageviews and clicks, you just need to set your experiment on our SaaS platform,
281
- then you should be able to see the result in near real time after the experiment is started.
282
-
283
- In case you need more control over the experiment data sent to our server, we offer a method to send custom event.
284
-
285
- ```javascript
286
- fbClient.track(eventName, numericValue);
287
- ```
288
-
289
- **numericValue** is not mandatory, the default value is **1.0**.
290
-
291
- Make sure `track` is called after the related feature flag is called, otherwise the custom event won't be included
292
- into the experiment result.
293
-
294
- ## Getting support
295
- - If you have a specific question about using this sdk, we encourage you
296
- to [ask it in our slack](https://join.slack.com/t/featbit/shared_invite/zt-1ew5e2vbb-x6Apan1xZOaYMnFzqZkGNQ).
297
- - If you encounter a bug or would like to request a
298
- feature, [submit an issue](https://github.com/featbit/dotnet-server-sdk/issues/new).
299
-
300
- ## See Also
301
- - [Connect To JavaScript Sdk](https://docs.featbit.co/getting-started/connect-an-sdk#javascript)
1
+ > **Attention**
2
+ >
3
+ > If you are using the v1 or v2 of the SDK, please refer to this [doc](https://github.com/featbit/featbit-js-client-sdk/tree/v2)
4
+
5
+ # FeatBit Client SDK for JavaScript
6
+
7
+ ## Introduction
8
+
9
+ This is the Client-Side SDK for the 100% open-source feature flags management platform [FeatBit](https://github.com/featbit/featbit).
10
+
11
+ Be aware, this is a client side SDK, it is intended for use in a single-user context, which can be mobile, desktop or embedded applications. This SDK can only be ran in a browser environment, it is not suitable for NodeJs applications.
12
+
13
+ ## Get Started
14
+
15
+ ### Installation
16
+
17
+ ```bash
18
+ npm install --save @featbit/js-client-sdk
19
+ ```
20
+ ### Prerequisite
21
+
22
+ Before using the SDK, you need to obtain the environment secret (the sdkKey) and SDK URLs.
23
+
24
+ Follow the documentation below to retrieve these values
25
+ - [How to get environment secret](https://docs.featbit.co/sdk/faq#how-to-get-the-environment-secret)
26
+ - [How to get SDK URLs](https://docs.featbit.co/sdk/faq#how-to-get-the-sdk-urls)
27
+
28
+ ### Quick Start
29
+
30
+ The following code demonstrates the basic usage of `@featbit/js-client-sdk`.
31
+
32
+ ```javascript
33
+ import { FbClientBuilder, UserBuilder } from "@featbit/js-client-sdk";
34
+
35
+ const bob = new UserBuilder('a-unique-key-of-user')
36
+ .name('bob')
37
+ .custom('age', '18')
38
+ .custom('country', 'FR')
39
+ .build();
40
+
41
+ // setup SDK client with websocket streaming
42
+ const fbClient = new FbClientBuilder()
43
+ .sdkKey("your_sdk_key")
44
+ .streamingUri('ws://localhost:5100')
45
+ .eventsUri("http://localhost:5100")
46
+ .user(bob)
47
+ .build();
48
+
49
+ (async () => {
50
+ // wait for the SDK to be initialized
51
+ try {
52
+ await fbClient.waitForInitialization();
53
+ } catch(err) {
54
+ // failed to initialize the SDK
55
+ console.log(err);
56
+ }
57
+
58
+ // flag to be evaluated
59
+ const flagKey = "game-runner";
60
+
61
+ // evaluate a feature flag for a given user
62
+ const boolVariation = await fbClient.boolVariation(flagKey, false);
63
+
64
+ // switch user
65
+ const alice = new UserBuilder('another-unique-key-of-user')
66
+ .name('alice')
67
+ .custom('country', 'UK')
68
+ .custom('age', 36)
69
+ .build();
70
+
71
+ await fbClient.identify(alice);
72
+ })();
73
+ ```
74
+
75
+ ## Examples
76
+ - [web App](./examples/console-app)
77
+ - For how to use FeatBit with React, please refer to the [react-client-sdk](https://github.com/featbit/featbit-react-client-sdk)
78
+
79
+ ## SDK
80
+
81
+ ### FbClient
82
+
83
+ The `FbClient` is the heart of the SDK which provides access to FeatBit server. Applications should instantiate a single instance for the lifetime of the application.
84
+
85
+ `FbClientBuilder` is used to construct a `FbClient` instance. The builder exposes methods to configure the SDK, and finally to create the `FbClient` instance.
86
+
87
+ #### FbClient Using Streaming
88
+
89
+ ```javascript
90
+ import { FbClientBuilder, UserBuilder } from "@featbit/js-client-sdk";
91
+
92
+ const user = new UserBuilder('a-unique-key-of-user')
93
+ .name('bob')
94
+ .build();
95
+
96
+ const fbClient = new FbClientBuilder()
97
+ .sdkKey("your_sdk_key")
98
+ .streamingUri('ws://localhost:5100')
99
+ .eventsUri("http://localhost:5100")
100
+ .user(user)
101
+ .build();
102
+ ```
103
+ #### FbClient Using Polling
104
+
105
+ ```javascript
106
+ import { FbClientBuilder, UserBuilder, DataSyncModeEnum } from "@featbit/js-client-sdk";
107
+
108
+ const user = new UserBuilder('a-unique-key-of-user')
109
+ .name('bob')
110
+ .build();
111
+
112
+ const fbClient = new FbClientBuilder()
113
+ .sdkKey("your_sdk_key")
114
+ .dataSyncMode(DataSyncModeEnum.POLLING)
115
+ .pollingUri('http://localhost:5100')
116
+ .eventsUri("http://localhost:5100")
117
+ .pollingInterval(10000)
118
+ .build();
119
+ ```
120
+
121
+ #### IUser
122
+
123
+ `IUser` defines the attributes of a user for whom you are evaluating feature flags. IUser has two built-in attributes: key and name. The only mandatory attribute of a IUser is the key, which must uniquely identify each user.
124
+
125
+ Besides these built-in properties, you can define any additional attributes associated with the user using `custom(string key, string value)` method on UserBuilder. Both built-in attributes and custom attributes can be referenced in targeting rules, and are included in analytics data.
126
+
127
+ `UserBuilder` is used to construct a `IUser` instance. The builder exposes methods to configure the IUser, and finally to create the IUser instance.
128
+
129
+ ```javascript
130
+ import { UserBuilder } from "@featbit/js-client-sdk";
131
+
132
+ const bob = new UserBuilder("unique_key_for_bob")
133
+ .name("Bob")
134
+ .custom('age', 18)
135
+ .custom('country', 'FR')
136
+ .build();
137
+ ```
138
+
139
+ ### Bootstrap
140
+ If you already have the feature flags available, you can pass them to the SDK instead of requesting from the remote.
141
+
142
+
143
+ > **_NOTE:_** The bootstrapped flags will be overridden by the remote flags if they are available.
144
+
145
+ ```javascript
146
+ // define the option with the bootstrap parameter
147
+ const options = {
148
+ ...
149
+ bootstrap = [{
150
+ // feature flag key name
151
+ id: string,
152
+ // variation value
153
+ variation: string,
154
+ // variation data type, string will be used if not specified
155
+ variationType: VariationDataType
156
+ }]
157
+ }
158
+
159
+ const fbClient = new FbClientBuilder(options).build();
160
+ // or
161
+ const fbClient = new FbClientBuilder()
162
+ //... other options
163
+ .bootstrap(options.bootstrap)
164
+ .build();
165
+ ```
166
+
167
+ ### Evaluation
168
+
169
+ After initialization, the SDK has all the feature flags locally, and it does not need to request the remote server for any feature flag evaluation. All evaluation is done locally and synchronously, the average evaluation time is less than 1 ms.
170
+
171
+ There is a `variation` method that returns a flag value, and a `variationDetail` method that returns an object
172
+ describing how the value was determined for each type.
173
+
174
+ - boolVariation/boolVariationDetail
175
+ - stringVariation/stringVariationDetail
176
+ - numberVariation/numberVariationDetail
177
+ - jsonVariation/jsonVariationDetail
178
+
179
+ Variation calls take the feature flag key and a default value. If any error makes it impossible to
180
+ evaluate the flag (for instance, the feature flag key does not match any existing flag), default value is returned.
181
+
182
+ ```javascript
183
+ // flag to be evaluated
184
+ const flagKey = "game-runner";
185
+
186
+ // evaluate a feature flag for a given user
187
+ const boolVariation = await fbClient.boolVariation(flagKey, false);
188
+
189
+ // evaluate a boolean flag for a given user with evaluation detail
190
+ const boolVariationDetail = await fbClient.boolVariationDetail(flagKey, false);
191
+ ```
192
+
193
+ ### Offline Mode
194
+
195
+ In some situations, you might want to stop making remote calls to FeatBit. Here is how:
196
+ ```javascript
197
+ import { FbClientBuilder } from "@featbit/browser-server-sdk";
198
+
199
+ const fbClient = new FbClientBuilder()
200
+ //... other options
201
+ .offline(true)
202
+ .build();
203
+
204
+ ```
205
+ When Offline mode is enabled, you should provide the flags with the [bootstrap](#bootstrap) option,
206
+ otherwise, the SDK would return the defaul value you passed to the `variation` method.
207
+
208
+ ### Events
209
+
210
+ #### Wait for ready
211
+
212
+ To find out when the client is ready, you can use one of two mechanisms: events or promises.
213
+
214
+ The client object can emit JavaScript events. It emits a ready event when it receives initial flag values from the server. You can listen for this event to determine when the client is ready to evaluate flags.
215
+
216
+ ```javascript
217
+ fbClient.on('ready', () => {
218
+ var flagValue = fbClient.variation("YOUR_FEATURE_KEY", defaultValue);
219
+ });
220
+ ```
221
+
222
+ Or, you can use a promise instead of an event. The SDK has a method that returns a promise for initialization: **waitForInitialization()**. The behavior of waitUntilReady() is equivalent to the ready event. The promise resolves when the client receives its initial flag data. As with all promises, you can either use .then() to provide a callback, or use await if you are writing asynchronous code.
223
+
224
+ ```javascript
225
+ fbClient.waitForInitialization().then((data) => {
226
+ // data has the following structure [ {id: 'featureFlagKey', variation: variationValue } ]
227
+ // variationValue has the type as defined on remote
228
+ // initialization succeeded, flag values are now available
229
+ });
230
+ // or, with await:
231
+ const featureFlags = await fbClient.waitForInitialization();
232
+ // initialization succeeded, flag values are now available
233
+ ```
234
+
235
+ The SDK only decides initialization has failed if it receives an error response indicating that the environment ID is invalid. If it has trouble connecting to FeatBit, it will keep retrying until it succeeds.
236
+
237
+ #### Subscribe to flag(s) changes
238
+
239
+ To get notified when a feature flag is changed, we offer two methods
240
+ - subscribe to the changes of any feature flag(s)
241
+
242
+ ```javascript
243
+ fbClient.on('update', (keys: string[]) => {
244
+ // do something when any feature flag changes
245
+ });
246
+
247
+ ```
248
+ - subscribe to the changes of a specific feature flag
249
+
250
+ ```javascript
251
+ // replace feature_flag_key with your feature flag key
252
+ fbClient.on('update:feature_flag_key', (key) => {
253
+ const myFeature = fbClient.variation('feature_flag_key', defaultValue);
254
+ });
255
+
256
+ ```
257
+
258
+ ### Switch user after initialization
259
+ If the user changed after some process, login for example, the following method can be used to set the user after initialization.
260
+
261
+ ```javascript
262
+ await fbClient.identify(user);
263
+ ```
264
+
265
+
266
+ ### Data synchronization
267
+
268
+ We use **WebSocket** or **Polling** to make the local data synchronized with the server, and then store them in localStorage by default. Whenever there is any change to a feature flag or its related data, this change will be pushed to the SDK, the average synchronization time is less than **100ms** if WebSocket is configured. Be aware the WebSocket/Polling connection may be interrupted due to internet outage, but it will be resumed automatically once the problem is gone.
269
+
270
+ ### Network failure handling
271
+
272
+ As all data is stored locally in the localStorage, in the following situations, the SDK would still work when there is temporarily no internet connection:
273
+ - it has already received the data from previous connections
274
+ - the `fbClient.bootstrap(featureFlags)` method is called with all necessary feature flags
275
+
276
+ In the meantime, the SDK would try to reconnect to the server by an incremental interval, this makes sure that the websocket would be restored when the internet connection is back.
277
+
278
+ ### Experiments (A/B/n Testing)
279
+
280
+ We support automatic experiments for pageviews and clicks, you just need to set your experiment on our SaaS platform,
281
+ then you should be able to see the result in near real time after the experiment is started.
282
+
283
+ In case you need more control over the experiment data sent to our server, we offer a method to send custom event.
284
+
285
+ ```javascript
286
+ fbClient.track(eventName, numericValue);
287
+ ```
288
+
289
+ **numericValue** is not mandatory, the default value is **1.0**.
290
+
291
+ Make sure `track` is called after the related feature flag is called, otherwise the custom event won't be included
292
+ into the experiment result.
293
+
294
+ ## Getting support
295
+ - If you have a specific question about using this sdk, we encourage you
296
+ to [ask it in our slack](https://join.slack.com/t/featbit/shared_invite/zt-1ew5e2vbb-x6Apan1xZOaYMnFzqZkGNQ).
297
+ - If you encounter a bug or would like to request a
298
+ feature, [submit an issue](https://github.com/featbit/dotnet-server-sdk/issues/new).
299
+
300
+ ## See Also
301
+ - [Connect To JavaScript Sdk](https://docs.featbit.co/getting-started/connect-an-sdk#javascript)
@@ -17,7 +17,7 @@ export interface IFbClientCore {
17
17
  * The current user. The actual type of this parameter is
18
18
  * {@link IUser}.
19
19
  */
20
- identify(user: IUser): void;
20
+ identify(user: IUser): Promise<void>;
21
21
  /**
22
22
  * Indicates whether the client is ready to be used.
23
23
  *