@featbit/react-client-sdk 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/asyncWithFbProvider.js +73 -16
- package/dist/asyncWithFbProvider.js.map +1 -1
- package/dist/context.d.ts +4 -0
- package/dist/context.js.map +1 -1
- package/dist/provider.d.ts +8 -9
- package/dist/provider.js +53 -22
- package/dist/provider.js.map +1 -1
- package/dist/providerState.d.ts +9 -0
- package/dist/providerState.js +2 -0
- package/dist/providerState.js.map +1 -0
- package/package.json +2 -2
- package/src/asyncWithFbProvider.tsx +54 -8
- package/src/context.ts +6 -1
- package/src/provider.tsx +52 -29
- package/src/providerState.ts +10 -0
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# FeatBit Client-Side SDK for ReactJS
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
5
|
This is the React client side SDK for the feature management platform [FeatBit](https://www.featbit.co).
|
|
6
6
|
|
|
7
|
-
Be aware, this is a client side SDK, it is intended for use in a single-user context, which can be mobile, desktop or embeded applications. This SDK can only be ran in a browser environment, it is not suitable for React Native projects
|
|
7
|
+
Be aware, this is a client side SDK, it is intended for use in a single-user context, which can be mobile, desktop or embeded applications. This SDK can only be ran in a browser environment, it is not suitable for React Native projects.
|
|
8
|
+
If you are looking for React Native SDK, please check this [React Native SDK](https://github.com/featbit/featbit-react-native-sdk).
|
|
8
9
|
|
|
9
10
|
> The React SDK is based on the JavaScript SDK
|
|
10
11
|
The React SDK builds on FeatBit's JavaScript SDK to provide a better integration for use in React applications. As a result, much of the JavaScript SDK functionality is also available for the React SDK to use.
|
|
@@ -45,11 +45,23 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
45
45
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
49
|
+
var t = {};
|
|
50
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
51
|
+
t[p] = s[p];
|
|
52
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
53
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
54
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
55
|
+
t[p[i]] = s[p[i]];
|
|
56
|
+
}
|
|
57
|
+
return t;
|
|
58
|
+
};
|
|
48
59
|
import React, { useState, useEffect } from 'react';
|
|
49
60
|
import { defaultReactOptions } from './types';
|
|
50
61
|
import { Provider } from './context';
|
|
51
|
-
import { initClient } from './initClient';
|
|
52
62
|
import getFlagsProxy from "./getFlagsProxy";
|
|
63
|
+
import { FbClientBuilder } from "@featbit/js-client-sdk";
|
|
64
|
+
import { fetchFlags } from "./utils";
|
|
53
65
|
/**
|
|
54
66
|
* This is an async function which initializes feature-flags.co's JS SDK (`@featbit/js-client-sdk`)
|
|
55
67
|
* and awaits it so all flags and the fbClient are ready before the consumer app is rendered.
|
|
@@ -76,25 +88,58 @@ import getFlagsProxy from "./getFlagsProxy";
|
|
|
76
88
|
*/
|
|
77
89
|
export default function asyncWithFbProvider(config) {
|
|
78
90
|
return __awaiter(this, void 0, void 0, function () {
|
|
79
|
-
var options, userReactOptions, platform, reactOptions,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
switch (_b.label) {
|
|
91
|
+
var options, userReactOptions, platform, reactOptions, error, fetchedFlags, fbClient, e_1, bootstrapFlags, FbProvider;
|
|
92
|
+
return __generator(this, function (_a) {
|
|
93
|
+
switch (_a.label) {
|
|
83
94
|
case 0:
|
|
84
95
|
options = config.options, userReactOptions = config.reactOptions, platform = config.platform;
|
|
85
96
|
reactOptions = __assign(__assign({}, defaultReactOptions), userReactOptions);
|
|
86
|
-
|
|
97
|
+
fetchedFlags = {};
|
|
98
|
+
fbClient = new FbClientBuilder(__assign({}, options))
|
|
99
|
+
.platform(platform)
|
|
100
|
+
.build();
|
|
101
|
+
_a.label = 1;
|
|
87
102
|
case 1:
|
|
88
|
-
_a
|
|
103
|
+
_a.trys.push([1, 4, , 5]);
|
|
104
|
+
return [4 /*yield*/, fbClient.waitForInitialization()];
|
|
105
|
+
case 2:
|
|
106
|
+
_a.sent();
|
|
107
|
+
return [4 /*yield*/, fetchFlags(fbClient)];
|
|
108
|
+
case 3:
|
|
109
|
+
fetchedFlags = _a.sent();
|
|
110
|
+
return [3 /*break*/, 5];
|
|
111
|
+
case 4:
|
|
112
|
+
e_1 = _a.sent();
|
|
113
|
+
error = e_1;
|
|
114
|
+
return [3 /*break*/, 5];
|
|
115
|
+
case 5:
|
|
89
116
|
bootstrapFlags = ((options === null || options === void 0 ? void 0 : options.bootstrap) || []).reduce(function (acc, flag) {
|
|
90
117
|
acc[flag.id] = flag.variation;
|
|
91
118
|
return acc;
|
|
92
119
|
}, {});
|
|
93
120
|
FbProvider = function (_a) {
|
|
94
121
|
var children = _a.children;
|
|
95
|
-
var _b = useState(function () { return (__assign({ unproxiedFlags: fetchedFlags }, getFlagsProxy(fbClient, bootstrapFlags, fetchedFlags, reactOptions))); }), state = _b[0], setState = _b[1];
|
|
122
|
+
var _b = useState(function () { return (__assign(__assign({ unproxiedFlags: fetchedFlags }, getFlagsProxy(fbClient, bootstrapFlags, fetchedFlags, reactOptions)), { fbClient: fbClient, error: error })); }), state = _b[0], setState = _b[1];
|
|
96
123
|
useEffect(function () {
|
|
97
|
-
|
|
124
|
+
function onReady() {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
126
|
+
var unproxiedFlags;
|
|
127
|
+
return __generator(this, function (_a) {
|
|
128
|
+
switch (_a.label) {
|
|
129
|
+
case 0: return [4 /*yield*/, fetchFlags(fbClient)];
|
|
130
|
+
case 1:
|
|
131
|
+
unproxiedFlags = _a.sent();
|
|
132
|
+
setState(function (prevState) { return (__assign(__assign(__assign({}, prevState), { unproxiedFlags: unproxiedFlags }), getFlagsProxy(fbClient, bootstrapFlags, unproxiedFlags, reactOptions))); });
|
|
133
|
+
return [2 /*return*/];
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function onFailed(e) {
|
|
139
|
+
setState(function (prevState) { return (__assign(__assign({}, prevState), { error: e })); });
|
|
140
|
+
}
|
|
141
|
+
function onUpdate(changedKeys) {
|
|
142
|
+
var _this = this;
|
|
98
143
|
var updates = changedKeys.reduce(function (acc, key) { return __awaiter(_this, void 0, void 0, function () {
|
|
99
144
|
var _a, _b;
|
|
100
145
|
return __generator(this, function (_c) {
|
|
@@ -110,16 +155,28 @@ export default function asyncWithFbProvider(config) {
|
|
|
110
155
|
});
|
|
111
156
|
}); }, {});
|
|
112
157
|
if (Object.keys(updates).length > 0) {
|
|
113
|
-
setState(function (
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
return __assign({ unproxiedFlags: updatedUnproxiedFlags }, getFlagsProxy(fbClient, bootstrapFlags, updatedUnproxiedFlags, reactOptions));
|
|
158
|
+
setState(function (prevState) {
|
|
159
|
+
var updatedUnproxiedFlags = __assign(__assign({}, prevState.unproxiedFlags), updates);
|
|
160
|
+
return __assign(__assign(__assign({}, prevState), { unproxiedFlags: updatedUnproxiedFlags }), getFlagsProxy(fbClient, bootstrapFlags, updatedUnproxiedFlags, reactOptions));
|
|
117
161
|
});
|
|
118
162
|
}
|
|
119
|
-
}
|
|
163
|
+
}
|
|
164
|
+
fbClient.on('update', onUpdate);
|
|
165
|
+
// Only subscribe to ready and failed if waitForInitialization timed out
|
|
166
|
+
// because we want the introduction of init timeout to be as minimal and backwards
|
|
167
|
+
// compatible as possible.
|
|
168
|
+
if (error === null || error === void 0 ? void 0 : error.name.toLowerCase().includes('timeout')) {
|
|
169
|
+
fbClient.on('failed', onFailed);
|
|
170
|
+
fbClient.on('ready', onReady);
|
|
171
|
+
}
|
|
172
|
+
return function cleanup() {
|
|
173
|
+
fbClient.off('update', onUpdate);
|
|
174
|
+
fbClient.off('failed', onFailed);
|
|
175
|
+
fbClient.off('ready', onReady);
|
|
176
|
+
};
|
|
120
177
|
}, []);
|
|
121
|
-
var
|
|
122
|
-
return React.createElement(Provider, { value:
|
|
178
|
+
var _ = state.unproxiedFlags, rest = __rest(state, ["unproxiedFlags"]);
|
|
179
|
+
return React.createElement(Provider, { value: rest }, children);
|
|
123
180
|
};
|
|
124
181
|
return [2 /*return*/, FbProvider];
|
|
125
182
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asyncWithFbProvider.js","sourceRoot":"../src/","sources":["asyncWithFbProvider.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"asyncWithFbProvider.js","sourceRoot":"../src/","sources":["asyncWithFbProvider.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAkB,mBAAmB,EAAY,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,OAAO,UAAgB,mBAAmB,CAAC,MAAsB;;;;;;oBAC/D,OAAO,GAA8C,MAAM,QAApD,EAAgB,gBAAgB,GAAc,MAAM,aAApB,EAAE,QAAQ,GAAI,MAAM,SAAV,CAAW;oBAC7D,YAAY,yBAAO,mBAAmB,GAAK,gBAAgB,CAAC,CAAC;oBAE/D,YAAY,GAAa,EAAE,CAAC;oBAE1B,QAAQ,GAAG,IAAI,eAAe,cAAK,OAAO,EAAE;yBAC/C,QAAQ,CAAC,QAAQ,CAAC;yBAClB,KAAK,EAAE,CAAC;;;;oBAGT,qBAAM,QAAQ,CAAC,qBAAqB,EAAE,EAAA;;oBAAtC,SAAsC,CAAC;oBACxB,qBAAM,UAAU,CAAC,QAAQ,CAAC,EAAA;;oBAAzC,YAAY,GAAG,SAA0B,CAAC;;;;oBAE1C,KAAK,GAAG,GAAU,CAAC;;;oBAGf,cAAc,GAAG,CAAC,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,KAAI,EAAE,CAAC,CAAC,MAAM,CAAC,UAAC,GAA4B,EAAE,IAAS;wBAC/F,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;wBAC9B,OAAO,GAAG,CAAC;oBACb,CAAC,EAAE,EAA6B,CAAC,CAAC;oBAE5B,UAAU,GAAG,UAAC,EAAmC;4BAAlC,QAAQ,cAAA;wBACrB,IAAA,KAAoB,QAAQ,CAAC,cAAM,OAAA,qBACvC,cAAc,EAAE,YAAY,IACzB,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,CAAC,KACtE,QAAQ,UAAA,EACR,KAAK,OAAA,IACL,EALuC,CAKvC,CAAC,EALI,KAAK,QAAA,EAAE,QAAQ,QAKnB,CAAC;wBAEJ,SAAS,CAAC;4BACR,SAAe,OAAO;;;;;oDACG,qBAAM,UAAU,CAAC,QAAQ,CAAC,EAAA;;gDAA3C,cAAc,GAAG,SAA0B;gDACjD,QAAQ,CAAC,UAAC,SAAS,IAAK,OAAA,gCACnB,SAAS,KACZ,cAAc,gBAAA,KACX,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,CAAC,EAAE,EAHpD,CAGoD,CAAC,CAAC;;;;;6BAC/E;4BAED,SAAS,QAAQ,CAAC,CAAQ;gCACxB,QAAQ,CAAC,UAAC,SAAS,IAAK,OAAA,uBAAM,SAAS,KAAE,KAAK,EAAE,CAAC,IAAG,EAA5B,CAA4B,CAAC,CAAC;4BACxD,CAAC;4BAED,SAAS,QAAQ,CAAC,WAAqB;gCAAvC,iBAiBC;gCAhBC,IAAM,OAAO,GAAa,WAAW,CAAC,MAAM,CAAC,UAAO,GAAG,EAAE,GAAG;;;;;gDAC1D,KAAA,GAAG,CAAA;gDAAC,KAAA,GAAG,CAAA;gDAAI,qBAAM,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,EAAA;;gDAA5C,MAAQ,GAAG,SAAiC,CAAC;gDAC7C,sBAAO,GAAG,EAAC;;;qCACZ,EAAE,EAAc,CAAC,CAAC;gCAEnB,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;oCACnC,QAAQ,CAAC,UAAC,SAAS;wCACjB,IAAM,qBAAqB,yBAAQ,SAAS,CAAC,cAAc,GAAK,OAAO,CAAE,CAAC;wCAE1E,sCACK,SAAS,KACZ,cAAc,EAAE,qBAAqB,KAClC,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,qBAAqB,EAAE,YAAY,CAAC,EAC/E;oCACJ,CAAC,CAAC,CAAC;iCACJ;4BACH,CAAC;4BAED,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;4BAEhC,wEAAwE;4BACxE,kFAAkF;4BAClF,0BAA0B;4BAC1B,IAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,EAAE;gCACjD,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gCAChC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;6BAC/B;4BAED,OAAO,SAAS,OAAO;gCACrB,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gCACjC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gCACjC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;4BACjC,CAAC,CAAC;wBAEJ,CAAC,EAAE,EAAE,CAAC,CAAC;wBAEC,IAAgB,CAAC,GAAe,KAAK,eAApB,EAAK,IAAI,UAAM,KAAK,EAAvC,kBAA8B,CAAF,CAAY;wBAC9C,OAAO,oBAAC,QAAQ,IAAC,KAAK,EAAE,IAAI,IAAI,QAAQ,CAAa,CAAC;oBACxD,CAAC,CAAC;oBAEF,sBAAO,UAAU,EAAC;;;;CACnB"}
|
package/dist/context.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ interface FbContext {
|
|
|
8
8
|
*/
|
|
9
9
|
flagKeyMap: FlagKeyMap;
|
|
10
10
|
fbClient?: IFbClient;
|
|
11
|
+
/**
|
|
12
|
+
* FeatBit client initialization error, if there was one.
|
|
13
|
+
*/
|
|
14
|
+
error?: Error;
|
|
11
15
|
}
|
|
12
16
|
declare const context: import("react").Context<FbContext>;
|
|
13
17
|
declare const Provider: import("react").Provider<FbContext>, Consumer: import("react").Consumer<FbContext>;
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"../src/","sources":["context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"../src/","sources":["context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAmBtC,IAAM,OAAO,GAAG,aAAa,CAAY,EAAC,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAC,CAAC,CAAC;AAGzF,IAAA,QAAQ,GAEN,OAAO,SAFD,EACR,QAAQ,GACN,OAAO,SADD,CACE;AAEZ,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAa,CAAC;AACzC,eAAe,OAAO,CAAC"}
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { Component, PropsWithChildren } from "react";
|
|
2
2
|
import { EnhancedComponent, ProviderConfig, IFlagSet } from './types';
|
|
3
|
-
import { FbContext } from './context';
|
|
4
3
|
import { IFbClient } from '@featbit/js-client-sdk';
|
|
5
|
-
|
|
6
|
-
unproxiedFlags: IFlagSet;
|
|
7
|
-
}
|
|
4
|
+
import { ProviderState } from "./providerState";
|
|
8
5
|
/**
|
|
9
6
|
* The `FbProvider` is a component which accepts a config object which is used to
|
|
10
7
|
* initialize `@featbit/js-client-sdk`.
|
|
@@ -22,8 +19,8 @@ interface FbHocState extends FbContext {
|
|
|
22
19
|
* within your application. This provider is used inside the `withFbProviderHOC` and can be used instead to initialize
|
|
23
20
|
* the `@featbit/js-client-sdk`. For async initialization, check out the `asyncWithFbProvider` function
|
|
24
21
|
*/
|
|
25
|
-
declare class FbProvider extends
|
|
26
|
-
readonly state: Readonly<
|
|
22
|
+
declare class FbProvider extends Component<PropsWithChildren<ProviderConfig>, ProviderState> implements EnhancedComponent {
|
|
23
|
+
readonly state: Readonly<ProviderState>;
|
|
27
24
|
bootstrapFlags: IFlagSet;
|
|
28
25
|
constructor(props: ProviderConfig);
|
|
29
26
|
getReactOptions: () => {
|
|
@@ -31,9 +28,11 @@ declare class FbProvider extends React.Component<ProviderConfig, FbHocState> imp
|
|
|
31
28
|
sendEventsOnFlagRead: boolean;
|
|
32
29
|
};
|
|
33
30
|
subscribeToChanges: (fbClient: IFbClient) => void;
|
|
34
|
-
|
|
31
|
+
onFailed: (fbClient: IFbClient, e: Error) => void;
|
|
32
|
+
onReady: (fbClient: IFbClient, reactOptions: any) => Promise<void>;
|
|
33
|
+
prepareFbClient: () => Promise<void>;
|
|
35
34
|
componentDidMount(): Promise<void>;
|
|
36
35
|
componentDidUpdate(prevProps: ProviderConfig): Promise<void>;
|
|
37
|
-
render(): React.JSX.Element
|
|
36
|
+
render(): React.JSX.Element;
|
|
38
37
|
}
|
|
39
38
|
export default FbProvider;
|
package/dist/provider.js
CHANGED
|
@@ -60,11 +60,11 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
60
60
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
|
-
import React from "react";
|
|
63
|
+
import React, { Component } from "react";
|
|
64
64
|
import { defaultReactOptions } from './types';
|
|
65
65
|
import { Provider } from './context';
|
|
66
66
|
import { camelCaseKeys, fetchFlags } from "./utils";
|
|
67
|
-
import {
|
|
67
|
+
import { FbClientBuilder } from '@featbit/js-client-sdk';
|
|
68
68
|
import getFlagsProxy from "./getFlagsProxy";
|
|
69
69
|
/**
|
|
70
70
|
* The `FbProvider` is a component which accepts a config object which is used to
|
|
@@ -96,31 +96,67 @@ var FbProvider = /** @class */ (function (_super) {
|
|
|
96
96
|
}, {});
|
|
97
97
|
var unproxiedFlags = __assign(__assign({}, _this.state.unproxiedFlags), updates);
|
|
98
98
|
if (Object.keys(updates).length > 0) {
|
|
99
|
-
_this.setState(__assign({ unproxiedFlags: unproxiedFlags }, getFlagsProxy(fbClient, _this.bootstrapFlags, unproxiedFlags, _this.getReactOptions())));
|
|
99
|
+
_this.setState(function (prevState) { return (__assign(__assign(__assign({}, prevState), { unproxiedFlags: unproxiedFlags }), getFlagsProxy(fbClient, _this.bootstrapFlags, unproxiedFlags, _this.getReactOptions()))); });
|
|
100
100
|
}
|
|
101
101
|
});
|
|
102
102
|
};
|
|
103
|
-
_this.
|
|
104
|
-
|
|
103
|
+
_this.onFailed = function (fbClient, e) {
|
|
104
|
+
_this.setState(function (prevState) { return (__assign(__assign({}, prevState), { error: e })); });
|
|
105
|
+
};
|
|
106
|
+
_this.onReady = function (fbClient, reactOptions) { return __awaiter(_this, void 0, void 0, function () {
|
|
107
|
+
var unproxiedFlags;
|
|
108
|
+
var _this = this;
|
|
109
|
+
return __generator(this, function (_a) {
|
|
110
|
+
switch (_a.label) {
|
|
111
|
+
case 0: return [4 /*yield*/, fetchFlags(fbClient)];
|
|
112
|
+
case 1:
|
|
113
|
+
unproxiedFlags = _a.sent();
|
|
114
|
+
this.setState(function (prevState) { return (__assign(__assign(__assign({}, prevState), { unproxiedFlags: unproxiedFlags }), getFlagsProxy(fbClient, _this.bootstrapFlags, unproxiedFlags, reactOptions))); });
|
|
115
|
+
return [2 /*return*/];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}); };
|
|
119
|
+
_this.prepareFbClient = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
120
|
+
var _a, options, platform, client, reactOptions, unproxiedFlags, error, e_1;
|
|
121
|
+
var _this = this;
|
|
105
122
|
return __generator(this, function (_b) {
|
|
106
123
|
switch (_b.label) {
|
|
107
124
|
case 0:
|
|
108
125
|
_a = this.props, options = _a.options, platform = _a.platform;
|
|
109
126
|
client = this.props.fbClient;
|
|
110
127
|
reactOptions = this.getReactOptions();
|
|
128
|
+
unproxiedFlags = this.state.unproxiedFlags;
|
|
111
129
|
if (!client) return [3 /*break*/, 2];
|
|
112
130
|
return [4 /*yield*/, fetchFlags(client)];
|
|
113
131
|
case 1:
|
|
114
132
|
unproxiedFlags = _b.sent();
|
|
115
|
-
return [3 /*break*/,
|
|
116
|
-
case 2:
|
|
133
|
+
return [3 /*break*/, 7];
|
|
134
|
+
case 2:
|
|
135
|
+
client = new FbClientBuilder(__assign({}, options))
|
|
136
|
+
.platform(platform)
|
|
137
|
+
.build();
|
|
138
|
+
_b.label = 3;
|
|
117
139
|
case 3:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
client = initialisedOutput.fbClient;
|
|
121
|
-
_b.label = 4;
|
|
140
|
+
_b.trys.push([3, 6, , 7]);
|
|
141
|
+
return [4 /*yield*/, client.waitForInitialization()];
|
|
122
142
|
case 4:
|
|
123
|
-
|
|
143
|
+
_b.sent();
|
|
144
|
+
return [4 /*yield*/, fetchFlags(client)];
|
|
145
|
+
case 5:
|
|
146
|
+
unproxiedFlags = _b.sent();
|
|
147
|
+
return [3 /*break*/, 7];
|
|
148
|
+
case 6:
|
|
149
|
+
e_1 = _b.sent();
|
|
150
|
+
error = e_1;
|
|
151
|
+
if (error === null || error === void 0 ? void 0 : error.name.toLowerCase().includes('timeout')) {
|
|
152
|
+
client.on('failed', this.onFailed);
|
|
153
|
+
client.on('ready', function () {
|
|
154
|
+
_this.onReady(client, reactOptions);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return [3 /*break*/, 7];
|
|
158
|
+
case 7:
|
|
159
|
+
this.setState(function (previousState) { return (__assign(__assign(__assign(__assign({}, previousState), { unproxiedFlags: unproxiedFlags }), getFlagsProxy(client, _this.bootstrapFlags, unproxiedFlags, reactOptions)), { fbClient: client, error: error })); });
|
|
124
160
|
this.subscribeToChanges(client);
|
|
125
161
|
return [2 /*return*/];
|
|
126
162
|
}
|
|
@@ -131,7 +167,6 @@ var FbProvider = /** @class */ (function (_super) {
|
|
|
131
167
|
acc[flag.id] = flag.variation;
|
|
132
168
|
return acc;
|
|
133
169
|
}, {});
|
|
134
|
-
;
|
|
135
170
|
_this.state = {
|
|
136
171
|
flags: {},
|
|
137
172
|
unproxiedFlags: {},
|
|
@@ -160,7 +195,7 @@ var FbProvider = /** @class */ (function (_super) {
|
|
|
160
195
|
if (deferInitialization && !options) {
|
|
161
196
|
return [2 /*return*/];
|
|
162
197
|
}
|
|
163
|
-
return [4 /*yield*/, this.
|
|
198
|
+
return [4 /*yield*/, this.prepareFbClient()];
|
|
164
199
|
case 1:
|
|
165
200
|
_b.sent();
|
|
166
201
|
return [2 /*return*/];
|
|
@@ -178,7 +213,7 @@ var FbProvider = /** @class */ (function (_super) {
|
|
|
178
213
|
_b = this.props, options = _b.options, deferInitialization = _b.deferInitialization;
|
|
179
214
|
userJustLoaded = !((_a = prevProps.options) === null || _a === void 0 ? void 0 : _a.user) && (options === null || options === void 0 ? void 0 : options.user);
|
|
180
215
|
if (!(deferInitialization && userJustLoaded)) return [3 /*break*/, 2];
|
|
181
|
-
return [4 /*yield*/, this.
|
|
216
|
+
return [4 /*yield*/, this.prepareFbClient()];
|
|
182
217
|
case 1:
|
|
183
218
|
_c.sent();
|
|
184
219
|
_c.label = 2;
|
|
@@ -188,14 +223,10 @@ var FbProvider = /** @class */ (function (_super) {
|
|
|
188
223
|
});
|
|
189
224
|
};
|
|
190
225
|
FbProvider.prototype.render = function () {
|
|
191
|
-
var _a = this.state, flags = _a.flags, flagKeyMap = _a.flagKeyMap, fbClient = _a.fbClient;
|
|
192
|
-
|
|
193
|
-
if (fbClient === undefined) {
|
|
194
|
-
return null; // or Loading Indicator or any other placeholder
|
|
195
|
-
}
|
|
196
|
-
return React.createElement(Provider, { value: { flags: flags, flagKeyMap: flagKeyMap, fbClient: fbClient } }, this.props.children);
|
|
226
|
+
var _a = this.state, flags = _a.flags, flagKeyMap = _a.flagKeyMap, fbClient = _a.fbClient, error = _a.error;
|
|
227
|
+
return React.createElement(Provider, { value: { flags: flags, flagKeyMap: flagKeyMap, fbClient: fbClient, error: error } }, this.props.children);
|
|
197
228
|
};
|
|
198
229
|
return FbProvider;
|
|
199
|
-
}(
|
|
230
|
+
}(Component));
|
|
200
231
|
export default FbProvider;
|
|
201
232
|
//# sourceMappingURL=provider.js.map
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"../src/","sources":["provider.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"../src/","sources":["provider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providerState.js","sourceRoot":"../src/","sources":["providerState.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@featbit/react-client-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "FeatBit client SDK for React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"FeatBit",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"typescript": "^4.5.3"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@featbit/js-client-sdk": "^3.0.
|
|
50
|
+
"@featbit/js-client-sdk": "^3.0.6",
|
|
51
51
|
"hoist-non-react-statics": "^3.3.2",
|
|
52
52
|
"lodash.camelcase": "^4.3.0"
|
|
53
53
|
},
|
|
@@ -3,6 +3,8 @@ import { ProviderConfig, defaultReactOptions, IFlagSet } from './types';
|
|
|
3
3
|
import { Provider } from './context';
|
|
4
4
|
import { initClient } from './initClient';
|
|
5
5
|
import getFlagsProxy from "./getFlagsProxy";
|
|
6
|
+
import { FbClientBuilder } from "@featbit/js-client-sdk";
|
|
7
|
+
import { fetchFlags } from "./utils";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* This is an async function which initializes feature-flags.co's JS SDK (`@featbit/js-client-sdk`)
|
|
@@ -31,7 +33,19 @@ import getFlagsProxy from "./getFlagsProxy";
|
|
|
31
33
|
export default async function asyncWithFbProvider(config: ProviderConfig) {
|
|
32
34
|
const {options, reactOptions: userReactOptions, platform} = config;
|
|
33
35
|
const reactOptions = {...defaultReactOptions, ...userReactOptions};
|
|
34
|
-
|
|
36
|
+
let error: Error;
|
|
37
|
+
let fetchedFlags: IFlagSet = {};
|
|
38
|
+
|
|
39
|
+
const fbClient = new FbClientBuilder({...options})
|
|
40
|
+
.platform(platform)
|
|
41
|
+
.build();
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
await fbClient.waitForInitialization();
|
|
45
|
+
fetchedFlags = await fetchFlags(fbClient);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
error = e as Error;
|
|
48
|
+
}
|
|
35
49
|
|
|
36
50
|
const bootstrapFlags = (options?.bootstrap || []).reduce((acc: {[key: string]: string}, flag: any) => {
|
|
37
51
|
acc[flag.id] = flag.variation;
|
|
@@ -41,31 +55,63 @@ export default async function asyncWithFbProvider(config: ProviderConfig) {
|
|
|
41
55
|
const FbProvider = ({children}: { children: ReactNode }) => {
|
|
42
56
|
const [state, setState] = useState(() => ({
|
|
43
57
|
unproxiedFlags: fetchedFlags,
|
|
44
|
-
...getFlagsProxy(fbClient, bootstrapFlags, fetchedFlags, reactOptions)
|
|
58
|
+
...getFlagsProxy(fbClient, bootstrapFlags, fetchedFlags, reactOptions),
|
|
59
|
+
fbClient,
|
|
60
|
+
error,
|
|
45
61
|
}));
|
|
46
62
|
|
|
47
63
|
useEffect(() => {
|
|
48
|
-
|
|
64
|
+
async function onReady() {
|
|
65
|
+
const unproxiedFlags = await fetchFlags(fbClient);
|
|
66
|
+
setState((prevState) => ({
|
|
67
|
+
...prevState,
|
|
68
|
+
unproxiedFlags,
|
|
69
|
+
...getFlagsProxy(fbClient, bootstrapFlags, unproxiedFlags, reactOptions)}));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function onFailed(e: Error) {
|
|
73
|
+
setState((prevState) => ({ ...prevState, error: e }));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function onUpdate(changedKeys: string[]) {
|
|
49
77
|
const updates: IFlagSet = changedKeys.reduce(async (acc, key) => {
|
|
50
78
|
acc[key] = await fbClient.variation(key, '');
|
|
51
79
|
return acc;
|
|
52
80
|
}, {} as IFlagSet);
|
|
53
81
|
|
|
54
82
|
if (Object.keys(updates).length > 0) {
|
|
55
|
-
setState((
|
|
56
|
-
const updatedUnproxiedFlags = { ...unproxiedFlags, ...updates };
|
|
83
|
+
setState((prevState) => {
|
|
84
|
+
const updatedUnproxiedFlags = { ...prevState.unproxiedFlags, ...updates };
|
|
57
85
|
|
|
58
86
|
return {
|
|
87
|
+
...prevState,
|
|
59
88
|
unproxiedFlags: updatedUnproxiedFlags,
|
|
60
89
|
...getFlagsProxy(fbClient, bootstrapFlags, updatedUnproxiedFlags, reactOptions),
|
|
61
90
|
};
|
|
62
91
|
});
|
|
63
92
|
}
|
|
64
|
-
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fbClient.on('update', onUpdate);
|
|
96
|
+
|
|
97
|
+
// Only subscribe to ready and failed if waitForInitialization timed out
|
|
98
|
+
// because we want the introduction of init timeout to be as minimal and backwards
|
|
99
|
+
// compatible as possible.
|
|
100
|
+
if (error?.name.toLowerCase().includes('timeout')) {
|
|
101
|
+
fbClient.on('failed', onFailed);
|
|
102
|
+
fbClient.on('ready', onReady);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return function cleanup() {
|
|
106
|
+
fbClient.off('update', onUpdate);
|
|
107
|
+
fbClient.off('failed', onFailed);
|
|
108
|
+
fbClient.off('ready', onReady);
|
|
109
|
+
};
|
|
110
|
+
|
|
65
111
|
}, []);
|
|
66
112
|
|
|
67
|
-
const {
|
|
68
|
-
return <Provider value={
|
|
113
|
+
const { unproxiedFlags: _, ...rest } = state;
|
|
114
|
+
return <Provider value={rest}>{ children }</Provider>;
|
|
69
115
|
};
|
|
70
116
|
|
|
71
117
|
return FbProvider;
|
package/src/context.ts
CHANGED
|
@@ -10,7 +10,12 @@ interface FbContext {
|
|
|
10
10
|
*/
|
|
11
11
|
flagKeyMap: FlagKeyMap;
|
|
12
12
|
|
|
13
|
-
fbClient?: IFbClient
|
|
13
|
+
fbClient?: IFbClient,
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* FeatBit client initialization error, if there was one.
|
|
17
|
+
*/
|
|
18
|
+
error?: Error,
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
const context = createContext<FbContext>({flags: {}, flagKeyMap: {}, fbClient: undefined});
|
package/src/provider.tsx
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { Component, PropsWithChildren } from "react";
|
|
2
2
|
import { EnhancedComponent, ProviderConfig, defaultReactOptions, IFlagSet } from './types';
|
|
3
|
-
import { Provider
|
|
3
|
+
import { Provider } from './context';
|
|
4
4
|
import { camelCaseKeys, fetchFlags } from "./utils";
|
|
5
|
-
import {
|
|
6
|
-
import { IFbClient } from '@featbit/js-client-sdk';
|
|
5
|
+
import { FbClientBuilder, IFbClient } from '@featbit/js-client-sdk';
|
|
7
6
|
import getFlagsProxy from "./getFlagsProxy";
|
|
7
|
+
import { ProviderState } from "./providerState";
|
|
8
8
|
|
|
9
|
-
interface FbHocState extends FbContext {
|
|
10
|
-
unproxiedFlags: IFlagSet;
|
|
11
|
-
}
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
11
|
* The `FbProvider` is a component which accepts a config object which is used to
|
|
@@ -27,8 +24,8 @@ interface FbHocState extends FbContext {
|
|
|
27
24
|
* within your application. This provider is used inside the `withFbProviderHOC` and can be used instead to initialize
|
|
28
25
|
* the `@featbit/js-client-sdk`. For async initialization, check out the `asyncWithFbProvider` function
|
|
29
26
|
*/
|
|
30
|
-
class FbProvider extends
|
|
31
|
-
readonly state: Readonly<
|
|
27
|
+
class FbProvider extends Component<PropsWithChildren<ProviderConfig>, ProviderState> implements EnhancedComponent {
|
|
28
|
+
readonly state: Readonly<ProviderState>;
|
|
32
29
|
bootstrapFlags: IFlagSet;
|
|
33
30
|
|
|
34
31
|
constructor(props: ProviderConfig) {
|
|
@@ -38,7 +35,7 @@ class FbProvider extends React.Component<ProviderConfig, FbHocState> implements
|
|
|
38
35
|
this.bootstrapFlags = (options?.bootstrap || []).reduce((acc: {[key: string]: string}, flag: any) => {
|
|
39
36
|
acc[flag.id] = flag.variation;
|
|
40
37
|
return acc;
|
|
41
|
-
}, {} as {[key: string]: string})
|
|
38
|
+
}, {} as {[key: string]: string});
|
|
42
39
|
|
|
43
40
|
this.state = {
|
|
44
41
|
flags: {},
|
|
@@ -74,32 +71,63 @@ class FbProvider extends React.Component<ProviderConfig, FbHocState> implements
|
|
|
74
71
|
};
|
|
75
72
|
|
|
76
73
|
if (Object.keys(updates).length > 0) {
|
|
77
|
-
this.setState({
|
|
74
|
+
this.setState((prevState) =>({
|
|
75
|
+
...prevState,
|
|
78
76
|
unproxiedFlags,
|
|
79
77
|
...getFlagsProxy(fbClient, this.bootstrapFlags, unproxiedFlags, this.getReactOptions())
|
|
80
|
-
})
|
|
78
|
+
}))
|
|
81
79
|
}
|
|
82
80
|
});
|
|
83
81
|
};
|
|
84
82
|
|
|
85
|
-
|
|
83
|
+
onFailed = (fbClient: IFbClient, e: Error) => {
|
|
84
|
+
this.setState((prevState) => ({ ...prevState, error: e }));
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
onReady = async (fbClient: IFbClient, reactOptions: any) => {
|
|
88
|
+
const unproxiedFlags = await fetchFlags(fbClient);
|
|
89
|
+
this.setState((prevState) => ({
|
|
90
|
+
...prevState,
|
|
91
|
+
unproxiedFlags,
|
|
92
|
+
...getFlagsProxy(fbClient, this.bootstrapFlags, unproxiedFlags, reactOptions)}));
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
prepareFbClient = async () => {
|
|
86
96
|
const {options, platform} = this.props;
|
|
87
97
|
let client: IFbClient = this.props.fbClient!;
|
|
88
98
|
const reactOptions = this.getReactOptions();
|
|
89
|
-
let unproxiedFlags;
|
|
99
|
+
let unproxiedFlags = this.state.unproxiedFlags;
|
|
100
|
+
let error: Error;
|
|
101
|
+
|
|
90
102
|
if (client) {
|
|
91
103
|
unproxiedFlags = await fetchFlags(client);
|
|
92
104
|
} else {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
client = new FbClientBuilder({...options})
|
|
106
|
+
.platform(platform)
|
|
107
|
+
.build();
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
await client.waitForInitialization();
|
|
111
|
+
unproxiedFlags = await fetchFlags(client);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
error = e as Error;
|
|
114
|
+
|
|
115
|
+
if (error?.name.toLowerCase().includes('timeout')) {
|
|
116
|
+
client.on('failed', this.onFailed);
|
|
117
|
+
client.on('ready', () => {
|
|
118
|
+
this.onReady(client, reactOptions);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
96
122
|
}
|
|
97
123
|
|
|
98
|
-
this.setState({
|
|
124
|
+
this.setState((previousState) => ({
|
|
125
|
+
...previousState,
|
|
99
126
|
unproxiedFlags,
|
|
100
127
|
...getFlagsProxy(client, this.bootstrapFlags, unproxiedFlags, reactOptions),
|
|
101
|
-
fbClient: client
|
|
102
|
-
|
|
128
|
+
fbClient: client,
|
|
129
|
+
error,
|
|
130
|
+
}));
|
|
103
131
|
|
|
104
132
|
this.subscribeToChanges(client);
|
|
105
133
|
};
|
|
@@ -110,26 +138,21 @@ class FbProvider extends React.Component<ProviderConfig, FbHocState> implements
|
|
|
110
138
|
return;
|
|
111
139
|
}
|
|
112
140
|
|
|
113
|
-
await this.
|
|
141
|
+
await this.prepareFbClient();
|
|
114
142
|
}
|
|
115
143
|
|
|
116
144
|
async componentDidUpdate(prevProps: ProviderConfig) {
|
|
117
145
|
const {options, deferInitialization} = this.props;
|
|
118
146
|
const userJustLoaded = !prevProps.options?.user && options?.user;
|
|
119
147
|
if (deferInitialization && userJustLoaded) {
|
|
120
|
-
await this.
|
|
148
|
+
await this.prepareFbClient();
|
|
121
149
|
}
|
|
122
150
|
}
|
|
123
151
|
|
|
124
152
|
render() {
|
|
125
|
-
const {flags, flagKeyMap, fbClient} = this.state;
|
|
126
|
-
|
|
127
|
-
// Conditional rendering when fbClient is null
|
|
128
|
-
if (fbClient === undefined) {
|
|
129
|
-
return null; // or Loading Indicator or any other placeholder
|
|
130
|
-
}
|
|
153
|
+
const {flags, flagKeyMap, fbClient, error} = this.state;
|
|
131
154
|
|
|
132
|
-
return <Provider value={{ flags, flagKeyMap, fbClient }}>{ this.props.children }</Provider>;
|
|
155
|
+
return <Provider value={{ flags, flagKeyMap, fbClient, error }}>{ this.props.children }</Provider>;
|
|
133
156
|
}
|
|
134
157
|
}
|
|
135
158
|
|