@flagship.io/react-sdk 3.0.6 → 3.0.7-alpha.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.
- package/README.md +27 -27
- package/dist/Flag.js +31 -37
- package/dist/FlagshipContext.d.ts +2 -2
- package/dist/FlagshipContext.js +60 -73
- package/dist/FlagshipHooks.js +100 -180
- package/dist/constants.js +4 -4
- package/dist/index.browser.js +10236 -29
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.js +29 -28
- package/dist/index.node.js.map +1 -1
- package/dist/utils.js +18 -21
- package/package.json +101 -100
package/README.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
[](https://github.com/flagship-io/flagship-react-sdk/actions/workflows/workflow.yml) [](https://badge.fury.io/js/@flagship.io%2Freact-sdk)
|
|
2
|
-
|
|
3
|
-
## About Flagship
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<img src="https://www.flagship.io/wp-content/uploads/Flagship-horizontal-black-wake-AB.png" alt="drawing" width="150"/>
|
|
7
|
-
|
|
8
|
-
[Flagship by AB Tasty](https://www.flagship.io/) is a feature flagging platform for modern engineering and product teams. It eliminates the risks of future releases by separating code deployments from these releases :bulb: With Flagship, you have full control over the release process. You can:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- Switch features on or off through remote config.
|
|
12
|
-
- Automatically roll-out your features gradually to monitor performance and gather feedback from your most relevant users.
|
|
13
|
-
- Roll back any feature should any issues arise while testing in production.
|
|
14
|
-
- Segment users by granting access to a feature based on certain user attributes.
|
|
15
|
-
- Carry out A/B tests by easily assigning feature variations to groups of users.
|
|
16
|
-
|
|
17
|
-
<img src="https://www.flagship.io/wp-content/uploads/demo-setup.png" alt="drawing" width="600"/>
|
|
18
|
-
|
|
19
|
-
Flagship also allows you to choose whatever implementation method works for you from our many available SDKs or directly through a REST API. Additionally, our architecture is based on multi-cloud providers that offer high performance and highly-scalable managed services.
|
|
20
|
-
|
|
21
|
-
**To learn more:**
|
|
22
|
-
|
|
23
|
-
- [Solution overview](https://www.flagship.io/#showvideo) - A 5mn video demo :movie_camera:
|
|
24
|
-
- [Documentation](https://docs.developers.flagship.io/) - Our dev portal with guides, how tos, API and SDK references
|
|
25
|
-
- [Sign up for a free trial](https://www.flagship.io/sign-up/) - Create your free account
|
|
26
|
-
- [Guide to feature flagging](https://www.flagship.io/feature-flags/) - Everyhting you need to know about feature flag related use cases
|
|
27
|
-
- [Blog](https://www.flagship.io/blog/) - Additional resources about release management
|
|
1
|
+
[](https://github.com/flagship-io/flagship-react-sdk/actions/workflows/workflow.yml) [](https://badge.fury.io/js/@flagship.io%2Freact-sdk)
|
|
2
|
+
|
|
3
|
+
## About Flagship
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
<img src="https://www.flagship.io/wp-content/uploads/Flagship-horizontal-black-wake-AB.png" alt="drawing" width="150"/>
|
|
7
|
+
|
|
8
|
+
[Flagship by AB Tasty](https://www.flagship.io/) is a feature flagging platform for modern engineering and product teams. It eliminates the risks of future releases by separating code deployments from these releases :bulb: With Flagship, you have full control over the release process. You can:
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
- Switch features on or off through remote config.
|
|
12
|
+
- Automatically roll-out your features gradually to monitor performance and gather feedback from your most relevant users.
|
|
13
|
+
- Roll back any feature should any issues arise while testing in production.
|
|
14
|
+
- Segment users by granting access to a feature based on certain user attributes.
|
|
15
|
+
- Carry out A/B tests by easily assigning feature variations to groups of users.
|
|
16
|
+
|
|
17
|
+
<img src="https://www.flagship.io/wp-content/uploads/demo-setup.png" alt="drawing" width="600"/>
|
|
18
|
+
|
|
19
|
+
Flagship also allows you to choose whatever implementation method works for you from our many available SDKs or directly through a REST API. Additionally, our architecture is based on multi-cloud providers that offer high performance and highly-scalable managed services.
|
|
20
|
+
|
|
21
|
+
**To learn more:**
|
|
22
|
+
|
|
23
|
+
- [Solution overview](https://www.flagship.io/#showvideo) - A 5mn video demo :movie_camera:
|
|
24
|
+
- [Documentation](https://docs.developers.flagship.io/) - Our dev portal with guides, how tos, API and SDK references
|
|
25
|
+
- [Sign up for a free trial](https://www.flagship.io/sign-up/) - Create your free account
|
|
26
|
+
- [Guide to feature flagging](https://www.flagship.io/feature-flags/) - Everyhting you need to know about feature flag related use cases
|
|
27
|
+
- [Blog](https://www.flagship.io/blog/) - Additional resources about release management
|
package/dist/Flag.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import Flagship, { FlagMetadata } from '@flagship.io/js-sdk';
|
|
2
2
|
import { GET_FLAG_CAST_ERROR, GET_METADATA_CAST_ERROR, noVisitorMessage } from './constants';
|
|
3
3
|
import { hasSameType, logInfo, logWarn, sprintf } from './utils';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export class Flag {
|
|
5
|
+
constructor(defaultValue, key, flagsData) {
|
|
6
6
|
if (!flagsData) {
|
|
7
7
|
logWarn(Flagship.getConfig(), noVisitorMessage, 'GetFlag');
|
|
8
8
|
}
|
|
@@ -10,57 +10,51 @@ var Flag = /** @class */ (function () {
|
|
|
10
10
|
this.key = key;
|
|
11
11
|
this.flag = flagsData === null || flagsData === void 0 ? void 0 : flagsData.get(key);
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
NotSameType() {
|
|
14
14
|
var _a;
|
|
15
15
|
return this.defaultValue !== null && this.defaultValue !== undefined && !hasSameType((_a = this.flag) === null || _a === void 0 ? void 0 : _a.value, this.defaultValue);
|
|
16
|
-
}
|
|
17
|
-
|
|
16
|
+
}
|
|
17
|
+
getValue() {
|
|
18
18
|
if (!this.flag) {
|
|
19
19
|
logWarn(Flagship.getConfig(), noVisitorMessage, 'getValue');
|
|
20
20
|
return this.defaultValue;
|
|
21
21
|
}
|
|
22
22
|
if (this.NotSameType()) {
|
|
23
|
-
logInfo(Flagship.getConfig(), sprintf(GET_FLAG_CAST_ERROR, this.key),
|
|
23
|
+
logInfo(Flagship.getConfig(), sprintf(GET_FLAG_CAST_ERROR, this.key), 'getValue');
|
|
24
24
|
return this.defaultValue;
|
|
25
25
|
}
|
|
26
26
|
return this.flag.value;
|
|
27
|
-
}
|
|
28
|
-
|
|
27
|
+
}
|
|
28
|
+
exists() {
|
|
29
29
|
if (!this.flag) {
|
|
30
30
|
logWarn(Flagship.getConfig(), noVisitorMessage, 'exists');
|
|
31
31
|
return false;
|
|
32
32
|
}
|
|
33
33
|
return !!(this.flag.campaignId && this.flag.variationId && this.flag.variationGroupId);
|
|
34
|
-
}
|
|
35
|
-
|
|
34
|
+
}
|
|
35
|
+
userExposed() {
|
|
36
36
|
if (!this.flag) {
|
|
37
37
|
logWarn(Flagship.getConfig(), noVisitorMessage, 'userExposed');
|
|
38
38
|
}
|
|
39
39
|
return Promise.resolve();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
enumerable: false,
|
|
62
|
-
configurable: true
|
|
63
|
-
});
|
|
64
|
-
return Flag;
|
|
65
|
-
}());
|
|
66
|
-
export { Flag };
|
|
40
|
+
}
|
|
41
|
+
get metadata() {
|
|
42
|
+
const functionName = 'metadata';
|
|
43
|
+
if (!this.flag) {
|
|
44
|
+
logWarn(Flagship.getConfig(), noVisitorMessage, functionName);
|
|
45
|
+
return FlagMetadata.Empty();
|
|
46
|
+
}
|
|
47
|
+
if (this.NotSameType()) {
|
|
48
|
+
logInfo(Flagship.getConfig(), sprintf(GET_METADATA_CAST_ERROR, this.key), functionName);
|
|
49
|
+
return FlagMetadata.Empty();
|
|
50
|
+
}
|
|
51
|
+
return new FlagMetadata({
|
|
52
|
+
campaignId: this.flag.campaignId,
|
|
53
|
+
variationGroupId: this.flag.variationGroupId,
|
|
54
|
+
variationId: this.flag.variationId,
|
|
55
|
+
isReference: !!this.flag.isReference,
|
|
56
|
+
campaignType: this.flag.campaignType,
|
|
57
|
+
slug: this.flag.slug
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { ReactNode, Dispatch, SetStateAction } from
|
|
2
|
-
import { BucketingDTO, CampaignDTO, FlagDTO, IFlagshipConfig, primitive, Visitor } from
|
|
1
|
+
import React, { ReactNode, Dispatch, SetStateAction } from 'react';
|
|
2
|
+
import { BucketingDTO, CampaignDTO, FlagDTO, IFlagshipConfig, primitive, Visitor } from '@flagship.io/js-sdk';
|
|
3
3
|
export interface FsStatus {
|
|
4
4
|
/**
|
|
5
5
|
* Boolean. When true, the SDK is still not ready to render your App otherwise it'll use default modifications.
|
package/dist/FlagshipContext.js
CHANGED
|
@@ -1,119 +1,106 @@
|
|
|
1
|
-
var __assign = (this && this.__assign) || function () {
|
|
2
|
-
__assign = Object.assign || function(t) {
|
|
3
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
-
s = arguments[i];
|
|
5
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
-
t[p] = s[p];
|
|
7
|
-
}
|
|
8
|
-
return t;
|
|
9
|
-
};
|
|
10
|
-
return __assign.apply(this, arguments);
|
|
11
|
-
};
|
|
12
1
|
// eslint-disable-next-line no-use-before-define
|
|
13
|
-
import React, { useState, useEffect, createContext, useRef
|
|
14
|
-
import { Flagship, FlagshipStatus
|
|
15
|
-
import { getModificationsFromCampaigns, logError, useNonInitialEffect
|
|
16
|
-
|
|
17
|
-
status: { isLoading: true, isSdkReady: false }
|
|
2
|
+
import React, { useState, useEffect, createContext, useRef } from 'react';
|
|
3
|
+
import { Flagship, FlagshipStatus } from '@flagship.io/js-sdk';
|
|
4
|
+
import { getModificationsFromCampaigns, logError, useNonInitialEffect } from './utils';
|
|
5
|
+
const initStat = {
|
|
6
|
+
status: { isLoading: true, isSdkReady: false }
|
|
18
7
|
};
|
|
19
|
-
export
|
|
20
|
-
state:
|
|
8
|
+
export const FlagshipContext = createContext({
|
|
9
|
+
state: Object.assign({}, initStat)
|
|
21
10
|
});
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
var modifications = new Map();
|
|
11
|
+
export const FlagshipProvider = ({ children, fetchNow, envId, apiKey, decisionMode, decisionApiUrl, timeout, logLevel, statusChangedCallback, logManager, pollingInterval, visitorData, onInitStart, onInitDone, onBucketingSuccess, onBucketingFail, loadingComponent, onBucketingUpdated, onUpdate, enableClientCache, initialBucketing, initialCampaigns, initialModifications, initialFlagsData, fetchFlagsOnBucketingUpdated, activateDeduplicationTime, hitDeduplicationTime, visitorCacheImplementation, hitCacheImplementation, disableCache, language }) => {
|
|
12
|
+
let modifications = new Map();
|
|
25
13
|
if (initialFlagsData && initialFlagsData.forEach) {
|
|
26
|
-
initialFlagsData.forEach(
|
|
14
|
+
initialFlagsData.forEach((flag) => {
|
|
27
15
|
modifications.set(flag.key, flag);
|
|
28
16
|
});
|
|
29
17
|
}
|
|
30
18
|
else if (initialModifications && initialModifications.forEach) {
|
|
31
|
-
initialModifications.forEach(
|
|
19
|
+
initialModifications.forEach((modification) => {
|
|
32
20
|
modifications.set(modification.key, modification);
|
|
33
21
|
});
|
|
34
22
|
}
|
|
35
23
|
else if (initialCampaigns) {
|
|
36
24
|
modifications = getModificationsFromCampaigns(initialCampaigns);
|
|
37
25
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
const [state, setState] = useState(Object.assign(Object.assign({}, initStat), { modifications }));
|
|
27
|
+
const [lastModified, setLastModified] = useState();
|
|
28
|
+
const stateRef = useRef();
|
|
41
29
|
stateRef.current = state;
|
|
42
|
-
useNonInitialEffect(
|
|
30
|
+
useNonInitialEffect(() => {
|
|
43
31
|
var _a;
|
|
44
32
|
if (fetchFlagsOnBucketingUpdated) {
|
|
45
33
|
(_a = state.visitor) === null || _a === void 0 ? void 0 : _a.fetchFlags();
|
|
46
34
|
}
|
|
47
35
|
}, [lastModified]);
|
|
48
|
-
useNonInitialEffect(
|
|
36
|
+
useNonInitialEffect(() => {
|
|
49
37
|
createVisitor(true);
|
|
50
38
|
}, [JSON.stringify(visitorData)]);
|
|
51
|
-
useEffect(
|
|
39
|
+
useEffect(() => {
|
|
52
40
|
initSdk();
|
|
53
41
|
}, [envId, apiKey, decisionMode]);
|
|
54
42
|
function initializeState(param) {
|
|
55
|
-
|
|
43
|
+
const newStatus = {
|
|
56
44
|
isSdkReady: param.isSdkReady,
|
|
57
45
|
isLoading: param.isLoading,
|
|
58
46
|
isVisitorDefined: !!param.fsVisitor,
|
|
59
|
-
lastRefresh: new Date().toISOString()
|
|
47
|
+
lastRefresh: new Date().toISOString()
|
|
60
48
|
};
|
|
61
|
-
setState(
|
|
49
|
+
setState((currentState) => {
|
|
62
50
|
if (!currentState.status.firstInitSuccess) {
|
|
63
51
|
newStatus.firstInitSuccess = new Date().toISOString();
|
|
64
52
|
}
|
|
65
|
-
return
|
|
53
|
+
return Object.assign(Object.assign({}, currentState), { visitor: param.fsVisitor, modifications: param.fsVisitor.modifications, config: Flagship.getConfig(), status: Object.assign(Object.assign({}, currentState.status), newStatus) });
|
|
66
54
|
});
|
|
67
55
|
return newStatus;
|
|
68
56
|
}
|
|
69
57
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
-
|
|
58
|
+
const onVisitorReady = (fsVisitor, error) => {
|
|
71
59
|
if (error) {
|
|
72
|
-
logError(Flagship.getConfig(), error.message || error,
|
|
60
|
+
logError(Flagship.getConfig(), error.message || error, 'onReady');
|
|
73
61
|
return;
|
|
74
62
|
}
|
|
75
|
-
|
|
76
|
-
fsVisitor
|
|
63
|
+
const newStatus = initializeState({
|
|
64
|
+
fsVisitor,
|
|
77
65
|
isSdkReady: true,
|
|
78
|
-
isLoading: false
|
|
66
|
+
isLoading: false
|
|
79
67
|
});
|
|
80
68
|
if (onUpdate) {
|
|
81
69
|
onUpdate({
|
|
82
70
|
fsModifications: fsVisitor.modifications,
|
|
83
71
|
config: Flagship.getConfig(),
|
|
84
|
-
status: newStatus
|
|
72
|
+
status: newStatus
|
|
85
73
|
});
|
|
86
74
|
}
|
|
87
75
|
};
|
|
88
|
-
|
|
89
|
-
if (fetchFlags === void 0) { fetchFlags = false; }
|
|
76
|
+
const createVisitor = (fetchFlags = false) => {
|
|
90
77
|
if (!visitorData) {
|
|
91
78
|
return;
|
|
92
79
|
}
|
|
93
|
-
|
|
80
|
+
const fsVisitor = Flagship.newVisitor({
|
|
94
81
|
visitorId: visitorData.id,
|
|
95
82
|
context: visitorData.context,
|
|
96
83
|
isAuthenticated: visitorData.isAuthenticated,
|
|
97
84
|
hasConsented: visitorData.hasConsented,
|
|
98
|
-
initialCampaigns
|
|
99
|
-
initialModifications
|
|
100
|
-
initialFlagsData
|
|
85
|
+
initialCampaigns,
|
|
86
|
+
initialModifications,
|
|
87
|
+
initialFlagsData
|
|
101
88
|
});
|
|
102
|
-
fsVisitor === null || fsVisitor === void 0 ? void 0 : fsVisitor.on(
|
|
89
|
+
fsVisitor === null || fsVisitor === void 0 ? void 0 : fsVisitor.on('ready', (error) => {
|
|
103
90
|
onVisitorReady(fsVisitor, error);
|
|
104
91
|
});
|
|
105
92
|
if (!fetchNow && fsVisitor && !fetchFlags) {
|
|
106
93
|
initializeState({
|
|
107
|
-
fsVisitor
|
|
94
|
+
fsVisitor,
|
|
108
95
|
isSdkReady: true,
|
|
109
|
-
isLoading: false
|
|
96
|
+
isLoading: false
|
|
110
97
|
});
|
|
111
98
|
}
|
|
112
99
|
if (fetchFlags && !fetchNow) {
|
|
113
100
|
fsVisitor === null || fsVisitor === void 0 ? void 0 : fsVisitor.fetchFlags();
|
|
114
101
|
}
|
|
115
102
|
};
|
|
116
|
-
|
|
103
|
+
const statusChanged = (status) => {
|
|
117
104
|
if (statusChangedCallback) {
|
|
118
105
|
statusChangedCallback(status);
|
|
119
106
|
}
|
|
@@ -131,51 +118,51 @@ export var FlagshipProvider = function (_a) {
|
|
|
131
118
|
createVisitor();
|
|
132
119
|
break;
|
|
133
120
|
case FlagshipStatus.NOT_INITIALIZED:
|
|
134
|
-
setState(
|
|
121
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { config: Flagship.getConfig() })));
|
|
135
122
|
break;
|
|
136
123
|
}
|
|
137
124
|
};
|
|
138
|
-
|
|
125
|
+
const onBucketingLastModified = (lastUpdate) => {
|
|
139
126
|
if (onBucketingUpdated) {
|
|
140
127
|
onBucketingUpdated(lastUpdate);
|
|
141
128
|
}
|
|
142
129
|
setLastModified(lastUpdate);
|
|
143
130
|
};
|
|
144
|
-
|
|
131
|
+
const initSdk = () => {
|
|
145
132
|
Flagship.start(envId, apiKey, {
|
|
146
|
-
decisionMode
|
|
147
|
-
fetchNow
|
|
148
|
-
timeout
|
|
149
|
-
logLevel
|
|
133
|
+
decisionMode,
|
|
134
|
+
fetchNow,
|
|
135
|
+
timeout,
|
|
136
|
+
logLevel,
|
|
150
137
|
statusChangedCallback: statusChanged,
|
|
151
|
-
logManager
|
|
152
|
-
pollingInterval
|
|
153
|
-
onBucketingFail
|
|
154
|
-
onBucketingSuccess
|
|
155
|
-
enableClientCache
|
|
156
|
-
decisionApiUrl
|
|
138
|
+
logManager,
|
|
139
|
+
pollingInterval,
|
|
140
|
+
onBucketingFail,
|
|
141
|
+
onBucketingSuccess,
|
|
142
|
+
enableClientCache,
|
|
143
|
+
decisionApiUrl,
|
|
157
144
|
onBucketingUpdated: onBucketingLastModified,
|
|
158
|
-
initialBucketing
|
|
159
|
-
activateDeduplicationTime
|
|
160
|
-
hitDeduplicationTime
|
|
161
|
-
visitorCacheImplementation
|
|
162
|
-
hitCacheImplementation
|
|
163
|
-
disableCache
|
|
164
|
-
language
|
|
145
|
+
initialBucketing,
|
|
146
|
+
activateDeduplicationTime,
|
|
147
|
+
hitDeduplicationTime,
|
|
148
|
+
visitorCacheImplementation,
|
|
149
|
+
hitCacheImplementation,
|
|
150
|
+
disableCache,
|
|
151
|
+
language
|
|
165
152
|
});
|
|
166
153
|
};
|
|
167
|
-
|
|
168
|
-
|
|
154
|
+
const handleDisplay = () => {
|
|
155
|
+
const isFirstInit = !state.visitor;
|
|
169
156
|
if (state.status.isLoading && loadingComponent && isFirstInit && fetchNow) {
|
|
170
157
|
return React.createElement(React.Fragment, null, loadingComponent);
|
|
171
158
|
}
|
|
172
159
|
return React.createElement(React.Fragment, null, children);
|
|
173
160
|
};
|
|
174
|
-
return (React.createElement(FlagshipContext.Provider, { value: { state
|
|
161
|
+
return (React.createElement(FlagshipContext.Provider, { value: { state, setState } }, handleDisplay()));
|
|
175
162
|
};
|
|
176
163
|
FlagshipProvider.defaultProps = {
|
|
177
164
|
activateDeduplicationTime: 2,
|
|
178
165
|
hitDeduplicationTime: 2,
|
|
179
166
|
fetchNow: true,
|
|
180
|
-
language: 1
|
|
167
|
+
language: 1
|
|
181
168
|
};
|