@launchdarkly/react-native-client-sdk
Version:
React Native LaunchDarkly SDK
177 lines • 8.85 kB
JavaScript
import { BasicLogger, createDefaultSourceFactoryProvider, createFDv2DataManagerBase, internal, LDClientImpl, MOBILE_DATA_SYSTEM_DEFAULTS, MOBILE_TRANSITION_TABLE, mobileFdv1Endpoints, MODE_TABLE, resolveForegroundMode, safeRegisterDebugOverridePlugins, } from '@launchdarkly/js-client-sdk-common';
import MobileDataManager from './MobileDataManager';
import validateOptions, { filterToBaseOptions } from './options';
import createPlatform from './platform';
import { ApplicationState, ConnectionManager, NetworkState, } from './platform/ConnectionManager';
import RNStateDetector from './RNStateDetector';
/**
* The React Native LaunchDarkly client. Instantiate this class to create an
* instance of the ReactNativeLDClient and pass it to the {@link LDProvider}.
*
* @example
* ```tsx
* const featureClient = new ReactNativeLDClient(MOBILE_KEY, AutoEnvAttributes.Enabled);
*
* <LDProvider client={featureClient}>
* <Welcome />
* </LDProvider>
* ```
*/
function shouldAutoSwitchLifecycle(config) {
var _a;
if (config === true) {
return true;
}
if (typeof config === 'object' && config.type === 'automatic') {
return (_a = config.lifecycle) !== null && _a !== void 0 ? _a : true;
}
return false;
}
function shouldAutoSwitchNetwork(config) {
var _a;
if (config === true) {
return true;
}
if (typeof config === 'object' && config.type === 'automatic') {
return (_a = config.network) !== null && _a !== void 0 ? _a : true;
}
return false;
}
export default class ReactNativeLDClient extends LDClientImpl {
/**
* Creates an instance of the LaunchDarkly client.
*
* @param sdkKey The LaunchDarkly mobile key.
* @param autoEnvAttributes Enable / disable Auto environment attributes. When enabled, the SDK will automatically
* provide data about the mobile environment where the application is running. To learn more,
* read [Automatic environment attributes](https://docs.launchdarkly.com/sdk/features/environment-attributes).
* for more documentation.
* @param options {@link LDOptions} to initialize the client with.
*/
constructor(sdkKey, autoEnvAttributes, options = {}) {
var _a, _b;
const { logger: customLogger, debug } = options;
const logger = customLogger !== null && customLogger !== void 0 ? customLogger : new BasicLogger({
level: debug ? 'debug' : 'info',
// eslint-disable-next-line no-console
destination: console.log,
});
const validatedRnOptions = validateOptions(options, logger);
const internalOptions = {
analyticsEventPath: `/mobile`,
diagnosticEventPath: `/mobile/events/diagnostic`,
highTimeoutThreshold: 15,
getImplementationHooks: (_environmentMetadata) => internal.safeGetHooks(logger, _environmentMetadata, validatedRnOptions.plugins),
registerDebugOverrides: (debugOverride) => safeRegisterDebugOverridePlugins(logger, debugOverride, validatedRnOptions.plugins),
credentialType: 'mobileKey',
dataSystemDefaults: MOBILE_DATA_SYSTEM_DEFAULTS,
};
const platform = createPlatform(logger, options, validatedRnOptions.storage);
const endpoints = mobileFdv1Endpoints();
const dataManagerFactory = (flagManager, configuration, baseHeaders, emitter, diagnosticsManager) => {
var _a;
if (configuration.dataSystem) {
return createFDv2DataManagerBase({
platform,
flagManager,
credential: sdkKey,
config: configuration,
baseHeaders,
emitter,
transitionTable: MOBILE_TRANSITION_TABLE,
foregroundMode: resolveForegroundMode(configuration.dataSystem, MOBILE_DATA_SYSTEM_DEFAULTS),
backgroundMode: (_a = configuration.dataSystem.backgroundConnectionMode) !== null && _a !== void 0 ? _a : 'background',
modeTable: MODE_TABLE,
sourceFactoryProvider: createDefaultSourceFactoryProvider(),
fdv1Endpoints: mobileFdv1Endpoints(),
buildQueryParams: () => [], // Mobile uses Authorization header, not query params
});
}
return new MobileDataManager(platform, flagManager, sdkKey, configuration, validatedRnOptions, endpoints.polling, endpoints.streaming, baseHeaders, emitter, diagnosticsManager);
};
super(sdkKey, autoEnvAttributes, platform, Object.assign(Object.assign({}, filterToBaseOptions(options)), { logger }), dataManagerFactory, internalOptions);
if (this.isFDv2) {
const fdv2DataManager = this.dataManager;
this.setEventSendingEnabled(true, false);
fdv2DataManager.setFlushCallback(() => this.flush());
// Wire state detection directly to FDv2 data manager using the
// validated automaticModeSwitching config from the data system.
const { automaticModeSwitching } = (_a = this.dataSystemConfig) !== null && _a !== void 0 ? _a : {};
const stateDetector = new RNStateDetector();
this._stateDetector = stateDetector;
if (shouldAutoSwitchLifecycle(automaticModeSwitching)) {
stateDetector.setApplicationStateListener((state) => {
fdv2DataManager.setLifecycleState(state === ApplicationState.Foreground ? 'foreground' : 'background');
});
}
if (shouldAutoSwitchNetwork(automaticModeSwitching)) {
stateDetector.setNetworkStateListener((state) => {
fdv2DataManager.setNetworkState(state === NetworkState.Available ? 'available' : 'unavailable');
});
}
}
else {
const initialConnectionMode = (_b = options.initialConnectionMode) !== null && _b !== void 0 ? _b : 'streaming';
this.setEventSendingEnabled(initialConnectionMode !== 'offline', false);
const dataManager = this.dataManager;
const destination = {
setNetworkAvailability: (available) => {
dataManager.setNetworkAvailability(available);
},
setEventSendingEnabled: (enabled, flush) => {
this.setEventSendingEnabled(enabled, flush);
},
setConnectionMode: async (mode) => {
dataManager.setConnectionMode(mode);
},
};
this._connectionManager = new ConnectionManager(logger, {
initialConnectionMode,
automaticNetworkHandling: validatedRnOptions.automaticNetworkHandling,
automaticBackgroundHandling: validatedRnOptions.automaticBackgroundHandling,
runInBackground: validatedRnOptions.runInBackground,
}, destination, new RNStateDetector());
}
internal.safeRegisterPlugins(logger, this.environmentMetadata, this, validatedRnOptions.plugins);
}
async close() {
var _a, _b;
(_a = this._stateDetector) === null || _a === void 0 ? void 0 : _a.stopListening();
(_b = this._connectionManager) === null || _b === void 0 ? void 0 : _b.close();
return super.close();
}
async setConnectionMode(mode) {
var _a, _b;
if (this.isFDv2) {
// FDv2 path
if (mode !== undefined && !(mode in MODE_TABLE)) {
this.logger.warn(`setConnectionMode called with invalid mode '${mode}'. ` +
`Valid modes: ${Object.keys(MODE_TABLE).join(', ')}.`);
return;
}
this.dataManager.setConnectionMode(mode);
}
else {
// FDv1 path
if (mode === undefined || mode === 'one-shot' || mode === 'background') {
this.logger.warn(`setConnectionMode('${mode}') is only supported with the FDv2 data system (dataSystem option).`);
return;
}
(_a = this._connectionManager) === null || _a === void 0 ? void 0 : _a.setConnectionMode(mode);
(_b = this._connectionManager) === null || _b === void 0 ? void 0 : _b.setOffline(mode === 'offline');
}
}
getConnectionMode() {
if (this.isFDv2) {
return this.dataManager.getCurrentMode();
}
return this.dataManager.getConnectionMode();
}
isOffline() {
if (this.isFDv2) {
return this.dataManager.getCurrentMode() === 'offline';
}
return this.dataManager.getConnectionMode() === 'offline';
}
}
//# sourceMappingURL=ReactNativeLDClient.js.map