diff --git a/android/src/main/java/com/launchdarkly/reactnative/LaunchdarklyReactNativeClientModule.java b/android/src/main/java/com/launchdarkly/reactnative/LaunchdarklyReactNativeClientModule.java index 610cd52..9bf022c 100644 --- a/android/src/main/java/com/launchdarkly/reactnative/LaunchdarklyReactNativeClientModule.java +++ b/android/src/main/java/com/launchdarkly/reactnative/LaunchdarklyReactNativeClientModule.java @@ -50,23 +50,8 @@ import timber.log.Timber; -/** - * Module bound with React Native to be called from JavaScript - */ public class LaunchdarklyReactNativeClientModule extends ReactContextBaseJavaModule { - /** - * An enum of all the supported configuration entries for LDClient configuration. - * - *

- * Each enum value has a lookup key, entry type, and internal setter associated with it. The - * lookup key is used to get the configuration value from a ReadableMap (JsonObject passed over - * the react native bridge). The entry type specifies the base type looked up from the - * ReadableMap as well as any additional conversion needed before setting the internal LDConfig - * option, see @see ConfigEntryType for more. The internal setter is a String name of the setter - * method used to pass the parsed configuration value into a LDConfig builder used for LDClient - * setup. - */ enum ConfigMapping { CONFIG_MOBILE_KEY("mobileKey", ConfigEntryType.String, "setMobileKey"), CONFIG_BASE_URI("pollUri", ConfigEntryType.Uri, "setPollUri"), @@ -87,7 +72,8 @@ enum ConfigMapping { CONFIG_WRAPPER_VERSION("wrapperVersion", ConfigEntryType.String, "setWrapperVersion"), CONFIG_MAX_CACHED_USERS("maxCachedUsers", ConfigEntryType.Integer, "setMaxCachedUsers"), CONFIG_DIAGNOSTIC_OPT_OUT("diagnosticOptOut", ConfigEntryType.Boolean, "setDiagnosticOptOut"), - CONFIG_DIAGNOSTIC_RECORDING_INTERVAL("diagnosticRecordingIntervalMillis", ConfigEntryType.Integer, "setDiagnosticRecordingIntervalMillis"); + CONFIG_DIAGNOSTIC_RECORDING_INTERVAL("diagnosticRecordingIntervalMillis", ConfigEntryType.Integer, "setDiagnosticRecordingIntervalMillis"), + CONFIG_SECONDARY_MOBILE_KEYS("secondaryMobileKeys", ConfigEntryType.Map, "setSecondaryMobileKeys"); final String key; final ConfigEntryType type; @@ -112,17 +98,6 @@ void loadFromMap(ReadableMap map, LDConfig.Builder builder) { } } - /** - * An enum of all the supported configuration entries for LDUser configuration. - * - *

- * Each enum value has a lookup key, entry type, and internal setter associated with it. The - * lookup key is used to get the configuration value from a ReadableMap (JsonObject passed over - * the react native bridge). The entry type specifies the base type looked up from the - * ReadableMap as well as any additional conversion needed before setting the internal LDUser - * option, @see ConfigEntryType for more. The internal setter is a String name of the setter - * method used to pass the parsed configuration value into a LDUser builder. - */ enum UserConfigMapping { USER_ANONYMOUS("anonymous", ConfigEntryType.Boolean, "anonymous", null), USER_IP("ip", ConfigEntryType.String, "ip", "privateIp"), @@ -163,9 +138,6 @@ void loadFromMap(ReadableMap map, LDUser.Builder builder, Set privateAtt } } - // The LDClient instance - private LDClient ldClient; - // Current feature flag listeners private Map listeners = new HashMap<>(); private Map connectionModeListeners = new HashMap<>(); private Map allFlagsListeners = new HashMap<>(); @@ -188,18 +160,15 @@ public String getName() { return "LaunchdarklyReactNativeClient"; } - // Constants used in promise rejection private static final String ERROR_INIT = "E_INITIALIZE"; private static final String ERROR_IDENTIFY = "E_IDENTIFY"; private static final String ERROR_CLOSE = "E_CLOSE"; private static final String ERROR_UNKNOWN = "E_UNKNOWN"; - // Prefix for events sent over the React Native event bridge private static final String FLAG_PREFIX = "LaunchDarkly-Flag-"; private static final String ALL_FLAGS_PREFIX = "LaunchDarkly-All-Flags-"; private static final String CONNECTION_MODE_PREFIX = "LaunchDarkly-Connection-Mode-"; - /** * Called automatically by the React Native bridging layer to associate constants with the * object used to call into native modules. @@ -215,38 +184,27 @@ public Map getConstants() { return constants; } - /** - * React Method called from JavaScript to initialize the LDClient using the supplied - * configuration. - * - * @param config LDConfig configuration, @see configBuild - * @param user LDUser configuration, @see userBuild - * @param promise Either rejected if an error was encountered, otherwise resolved with null - * once client is initialized. - */ @ReactMethod public void configure(ReadableMap config, ReadableMap user, final Promise promise) { internalConfigure(config, user, null, promise); } - /** - * React Method called from JavaScript to initialize the LDClient using the supplied - * configuration with a timeout. - * - * @param config LDConfig configuration, @see configBuild - * @param user LDUser configuration, @see userBuild - * @param timeout Integer that blocks until the latest feature flags have been retrieved from LaunchDarkly - * @param promise Either rejected if an error was encountered, otherwise resolved with null - * once client is initialized. - */ @ReactMethod public void configureWithTimeout(ReadableMap config, ReadableMap user, Integer timeout, final Promise promise) { internalConfigure(config, user, timeout, promise); } private void internalConfigure(ReadableMap config, ReadableMap user, final Integer timeout, final Promise promise) { - if (ldClient != null) { - promise.reject(ERROR_INIT, "Client was already initialized"); + try { + if (LDClient.get() != null) { + promise.reject(ERROR_INIT, "Client was already initialized"); + return; + } + } catch (LaunchDarklyException e) { + //This exception indicates that the SDK has not been initialized yet + } catch (Exception e) { + Timber.w(e); + promise.reject(ERROR_INIT, e); return; } @@ -264,7 +222,7 @@ private void internalConfigure(ReadableMap config, ReadableMap user, final Integ } if (config.hasKey("allUserAttributesPrivate") - && config.getType("allUserAttributesPrivate").equals(ConfigEntryType.Boolean.getReadableType()) + && config.getType("allUserAttributesPrivate").equals(ConfigEntryType.Boolean.getReadableType()) && config.getBoolean("allUserAttributesPrivate")) { ldConfigBuilder.allAttributesPrivate(); } @@ -275,23 +233,12 @@ private void internalConfigure(ReadableMap config, ReadableMap user, final Integ Thread background = new Thread(new Runnable() { @Override public void run() { - try { - if (timeout != null) { - ldClient = LDClient.init(application, ldConfigBuilder.build(), userBuilder.build(), timeout).get(); - } else { - ldClient = LDClient.init(application, ldConfigBuilder.build(), userBuilder.build()).get(); - } - promise.resolve(null); - } catch (InterruptedException e) { - Timber.w(e); - promise.reject(ERROR_INIT, e); - } catch (ExecutionException e) { - Timber.w(e); - promise.reject(ERROR_INIT, e); - } catch (LaunchDarklyException e) { - Timber.w(e); - promise.reject(ERROR_INIT, e); + if (timeout != null) { + LDClient.init(application, ldConfigBuilder.build(), userBuilder.build(), timeout); + } else { + LDClient.init(application, ldConfigBuilder.build(), userBuilder.build()); } + promise.resolve(null); } }); @@ -302,15 +249,6 @@ public void run() { } } - /** - * Create a LDConfig.Builder using configuration values from the options ReadableMap. - * - *

- * This will look for all configuration values specified in {@link ConfigMapping}. - * - * @param options A ReadableMap of configuration options - * @return A LDConfig.Builder configured with options - */ private LDConfig.Builder configBuild(ReadableMap options) { LDConfig.Builder builder = new LDConfig.Builder(); @@ -321,15 +259,6 @@ private LDConfig.Builder configBuild(ReadableMap options) { return builder; } - /** - * Create a LDUser.Builder using configuration values from the options ReadableMap. - * - *

- * This will look for all configuration values specified in {@link UserConfigMapping}. - * - * @param options A ReadableMap of configuration options - * @return A LDUser.Builder configured with options - */ private LDUser.Builder userBuild(ReadableMap options) { if (!options.hasKey("key")) { return null; @@ -433,180 +362,101 @@ private LDUser.Builder userBuild(ReadableMap options) { } @ReactMethod - public void boolVariation(String flagKey, Promise promise) { - boolVariationDefaultValue(flagKey, null, promise); + public void boolVariation(String flagKey, String environment, Promise promise) { + boolVariationDefaultValue(flagKey, null, environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void boolVariationDefaultValue(String flagKey, Boolean defaultValue, Promise promise) { + public void boolVariationDefaultValue(String flagKey, Boolean defaultValue, String environment, Promise promise) { try { - promise.resolve(ldClient.boolVariation(flagKey, defaultValue)); + promise.resolve(LDClient.getForMobileKey(environment).boolVariation(flagKey, defaultValue)); } catch (Exception e) { promise.resolve(defaultValue); } } @ReactMethod - public void intVariation(String flagKey, Promise promise) { - intVariationDefaultValue(flagKey, null, promise); + public void intVariation(String flagKey, String environment, Promise promise) { + intVariationDefaultValue(flagKey, null, environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void intVariationDefaultValue(String flagKey, Integer defaultValue, Promise promise) { + public void intVariationDefaultValue(String flagKey, Integer defaultValue, String environment, Promise promise) { try { - promise.resolve(ldClient.intVariation(flagKey, defaultValue)); + promise.resolve(LDClient.getForMobileKey(environment).intVariation(flagKey, defaultValue)); } catch (Exception e) { promise.resolve(defaultValue); } } @ReactMethod - public void floatVariation(String flagKey, Promise promise) { - floatVariationDefaultValue(flagKey, null, promise); + public void floatVariation(String flagKey, String environment, Promise promise) { + floatVariationDefaultValue(flagKey, null, environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void floatVariationDefaultValue(String flagKey, Double defaultValue, Promise promise) { + public void floatVariationDefaultValue(String flagKey, Float defaultValue, String environment, Promise promise) { try { - promise.resolve(ldClient.doubleVariation(flagKey, defaultValue)); + promise.resolve(LDClient.getForMobileKey(environment).doubleVariation(flagKey, defaultValue.doubleValue())); } catch (Exception e) { promise.resolve(defaultValue); } } @ReactMethod - public void stringVariation(String flagKey, Promise promise) { - stringVariationDefaultValue(flagKey, null, promise); + public void stringVariation(String flagKey, String environment, Promise promise) { + stringVariationDefaultValue(flagKey, null, environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void stringVariationDefaultValue(String flagKey, String defaultValue, Promise promise) { + public void stringVariationDefaultValue(String flagKey, String defaultValue, String environment, Promise promise) { try { - promise.resolve(ldClient.stringVariation(flagKey, defaultValue)); + promise.resolve(LDClient.getForMobileKey(environment).stringVariation(flagKey, defaultValue)); } catch (Exception e) { promise.resolve(defaultValue); } } - /** - * Looks up the current value for a flag, in the case of any issues, returns null - * value. - * - * @param flagKey The lookup key of the flag. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void jsonVariationNone(String flagKey, Promise promise) { - jsonVariationBase(flagKey, null, promise); + public void jsonVariationNone(String flagKey, String environment, Promise promise) { + jsonVariationBase(flagKey, null, environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void jsonVariationNumber(String flagKey, Double defaultValue, Promise promise) { - jsonVariationBase(flagKey, new JsonPrimitive(defaultValue), promise); + public void jsonVariationNumber(String flagKey, Double defaultValue, String environment, Promise promise) { + jsonVariationBase(flagKey, new JsonPrimitive(defaultValue), environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void jsonVariationBool(String flagKey, Boolean defaultValue, Promise promise) { - jsonVariationBase(flagKey, new JsonPrimitive(defaultValue), promise); + public void jsonVariationBool(String flagKey, Boolean defaultValue, String environment, Promise promise) { + jsonVariationBase(flagKey, new JsonPrimitive(defaultValue), environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void jsonVariationString(String flagKey, String defaultValue, Promise promise) { - jsonVariationBase(flagKey, new JsonPrimitive(defaultValue), promise); + public void jsonVariationString(String flagKey, String defaultValue, String environment, Promise promise) { + jsonVariationBase(flagKey, new JsonPrimitive(defaultValue), environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void jsonVariationArray(String flagKey, ReadableArray defaultValue, Promise promise) { - jsonVariationBase(flagKey, toJsonArray(defaultValue), promise); + public void jsonVariationArray(String flagKey, ReadableArray defaultValue, String environment, Promise promise) { + jsonVariationBase(flagKey, toJsonArray(defaultValue), environment, promise); } - /** - * Looks up the current value for a flag, in the case of any issues, returns the given default - * value. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if current value could not be acquired. - * @param promise Used to return the result to React Native - */ @ReactMethod - public void jsonVariationObject(String flagKey, ReadableMap defaultValue, Promise promise) { - jsonVariationBase(flagKey, toJsonObject(defaultValue), promise); + public void jsonVariationObject(String flagKey, ReadableMap defaultValue, String environment, Promise promise) { + jsonVariationBase(flagKey, toJsonObject(defaultValue), environment, promise); } @ReactMethod - public void boolVariationDetail(String flagKey, Promise promise) { - boolVariationDetailDefaultValue(flagKey, null, promise); + public void boolVariationDetail(String flagKey, String environment, Promise promise) { + boolVariationDetailDefaultValue(flagKey, null, environment, promise); } @ReactMethod - public void boolVariationDetailDefaultValue(String flagKey, Boolean defaultValue, Promise promise) { + public void boolVariationDetailDefaultValue(String flagKey, Boolean defaultValue, String environment, Promise promise) { EvaluationDetail detailResult; try { - detailResult = ldClient.boolVariationDetail(flagKey, defaultValue); + detailResult = LDClient.getForMobileKey(environment).boolVariationDetail(flagKey, defaultValue); } catch (Exception e) { Timber.w(e); detailResult = new EvaluationDetail(EvaluationReason.error(EvaluationReason.ErrorKind.EXCEPTION), null, defaultValue); @@ -617,15 +467,15 @@ public void boolVariationDetailDefaultValue(String flagKey, Boolean defaultValue } @ReactMethod - public void intVariationDetail(String flagKey, Promise promise) { - intVariationDetailDefaultValue(flagKey, null, promise); + public void intVariationDetail(String flagKey, String environment, Promise promise) { + intVariationDetailDefaultValue(flagKey, null, environment, promise); } @ReactMethod - public void intVariationDetailDefaultValue(String flagKey, Integer defaultValue, Promise promise) { + public void intVariationDetailDefaultValue(String flagKey, Integer defaultValue, String environment, Promise promise) { EvaluationDetail detailResult; try { - detailResult = ldClient.intVariationDetail(flagKey, defaultValue); + detailResult = LDClient.getForMobileKey(environment).intVariationDetail(flagKey, defaultValue); } catch (Exception e) { Timber.w(e); detailResult = new EvaluationDetail(EvaluationReason.error(EvaluationReason.ErrorKind.EXCEPTION), null, defaultValue); @@ -636,18 +486,19 @@ public void intVariationDetailDefaultValue(String flagKey, Integer defaultValue, } @ReactMethod - public void floatVariationDetail(String flagKey, Promise promise) { - floatVariationDetailDefaultValue(flagKey, null, promise); + public void floatVariationDetail(String flagKey, String environment, Promise promise) { + floatVariationDetailDefaultValue(flagKey, null, environment, promise); } @ReactMethod - public void floatVariationDetailDefaultValue(String flagKey, Double defaultValue, Promise promise) { + public void floatVariationDetailDefaultValue(String flagKey, Float defaultValue, String environment, Promise promise) { EvaluationDetail detailResult; + Double doubleValue = defaultValue.doubleValue(); try { - detailResult = ldClient.doubleVariationDetail(flagKey, defaultValue); + detailResult = LDClient.getForMobileKey(environment).doubleVariationDetail(flagKey, doubleValue); } catch (Exception e) { Timber.w(e); - detailResult = new EvaluationDetail(EvaluationReason.error(EvaluationReason.ErrorKind.EXCEPTION), null, defaultValue); + detailResult = new EvaluationDetail(EvaluationReason.error(EvaluationReason.ErrorKind.EXCEPTION), null, doubleValue); } JsonObject jsonObject = gson.toJsonTree(detailResult).getAsJsonObject(); WritableMap detailMap = fromJsonObject(jsonObject); @@ -655,15 +506,15 @@ public void floatVariationDetailDefaultValue(String flagKey, Double defaultValue } @ReactMethod - public void stringVariationDetail(String flagKey, Promise promise) { - stringVariationDetailDefaultValue(flagKey, null, promise); + public void stringVariationDetail(String flagKey, String environment, Promise promise) { + stringVariationDetailDefaultValue(flagKey, null, environment, promise); } @ReactMethod - public void stringVariationDetailDefaultValue(String flagKey, String defaultValue, Promise promise) { + public void stringVariationDetailDefaultValue(String flagKey, String defaultValue, String environment, Promise promise) { EvaluationDetail detailResult; try { - detailResult = ldClient.stringVariationDetail(flagKey, defaultValue); + detailResult = LDClient.getForMobileKey(environment).stringVariationDetail(flagKey, defaultValue); } catch (Exception e) { Timber.w(e); detailResult = new EvaluationDetail(EvaluationReason.error(EvaluationReason.ErrorKind.EXCEPTION), null, defaultValue); @@ -674,55 +525,49 @@ public void stringVariationDetailDefaultValue(String flagKey, String defaultValu } @ReactMethod - public void jsonVariationDetailNone(String flagKey, Promise promise) { - jsonVariationDetailBase(flagKey, null, promise); + public void jsonVariationDetailNone(String flagKey, String environment, Promise promise) { + jsonVariationDetailBase(flagKey, null, environment, promise); } @ReactMethod - public void jsonVariationDetailNumber(String flagKey, Double defaultValue, Promise promise) { - jsonVariationDetailBase(flagKey, new JsonPrimitive(defaultValue), promise); + public void jsonVariationDetailNumber(String flagKey, Double defaultValue, String environment, Promise promise) { + jsonVariationDetailBase(flagKey, new JsonPrimitive(defaultValue), environment, promise); } @ReactMethod - public void jsonVariationDetailBool(String flagKey, Boolean defaultValue, Promise promise) { - jsonVariationDetailBase(flagKey, new JsonPrimitive(defaultValue), promise); + public void jsonVariationDetailBool(String flagKey, Boolean defaultValue, String environment, Promise promise) { + jsonVariationDetailBase(flagKey, new JsonPrimitive(defaultValue), environment, promise); } @ReactMethod - public void jsonVariationDetailString(String flagKey, String defaultValue, Promise promise) { - jsonVariationDetailBase(flagKey, new JsonPrimitive(defaultValue), promise); + public void jsonVariationDetailString(String flagKey, String defaultValue, String environment, Promise promise) { + jsonVariationDetailBase(flagKey, new JsonPrimitive(defaultValue), environment, promise); } @ReactMethod - public void jsonVariationDetailArray(String flagKey, ReadableArray defaultValue, Promise promise) { - jsonVariationDetailBase(flagKey, toJsonArray(defaultValue), promise); + public void jsonVariationDetailArray(String flagKey, ReadableArray defaultValue, String environment, Promise promise) { + jsonVariationDetailBase(flagKey, toJsonArray(defaultValue), environment, promise); } @ReactMethod - public void jsonVariationDetailObject(String flagKey, ReadableMap defaultValue, Promise promise) { - jsonVariationDetailBase(flagKey, toJsonObject(defaultValue), promise); + public void jsonVariationDetailObject(String flagKey, ReadableMap defaultValue, String environment, Promise promise) { + jsonVariationDetailBase(flagKey, toJsonObject(defaultValue), environment, promise); } - /** - * Helper for jsonVariation methods. - * - * @param flagKey The lookup key of the flag. - * @param defaultValue A default value to return if the current value could not be acquired. - * @param promise Used to return the result to React Native. - */ - private void jsonVariationBase(String flagKey, JsonElement defaultValue, Promise promise) { - try { - JsonElement jsonElement = ldClient.jsonVariation(flagKey, defaultValue); + private void jsonVariationBase(String flagKey, JsonElement defaultValue, String environment, Promise promise) { + JsonElement jsonElement; + try { + jsonElement = LDClient.getForMobileKey(environment).jsonVariation(flagKey, defaultValue); resolveJsonElement(promise, jsonElement); } catch (Exception e) { resolveJsonElement(promise, defaultValue); } } - private void jsonVariationDetailBase(String flagKey, JsonElement defaultValue, Promise promise) { + private void jsonVariationDetailBase(String flagKey, JsonElement defaultValue, String environment, Promise promise) { EvaluationDetail jsonElementDetail; try { - jsonElementDetail = ldClient.jsonVariationDetail(flagKey, defaultValue); + jsonElementDetail = LDClient.getForMobileKey(environment).jsonVariationDetail(flagKey, defaultValue); } catch (Exception e) { Timber.w(e); jsonElementDetail = new EvaluationDetail(EvaluationReason.error(EvaluationReason.ErrorKind.EXCEPTION), null, defaultValue); @@ -730,14 +575,6 @@ private void jsonVariationDetailBase(String flagKey, JsonElement defaultValue, P resolveJsonElementDetail(promise, jsonElementDetail); } - - /** - * Converts the jsonElement to a React Native bridge compatible type and resolves the promise - * with it's value. - * - * @param promise Promise to resolve - * @param jsonElement Value to convert and resolve promise with. - */ private void resolveJsonElement(Promise promise, JsonElement jsonElement) { if (jsonElement == null || jsonElement.isJsonNull()) { promise.resolve(null); @@ -765,319 +602,237 @@ private void resolveJsonElementDetail(Promise promise, EvaluationDetail flags = ldClient.allFlags(); - - // Convert map of all flags into WritableMap for React Native - WritableMap response = new WritableNativeMap(); - for (Map.Entry entry : flags.entrySet()) { - if (entry.getValue() == null) { - response.putNull(entry.getKey()); - } else if (entry.getValue() instanceof String) { - try { - JsonElement parsedJson = new JsonParser().parse((String) entry.getValue()); - if (parsedJson.isJsonObject()) { - response.putMap(entry.getKey(), fromJsonObject((JsonObject) parsedJson.getAsJsonObject())); - } else if (parsedJson.isJsonArray()) { - response.putArray(entry.getKey(), fromJsonArray((JsonArray) parsedJson.getAsJsonArray())); - } else { + try { + Map flags = LDClient.getForMobileKey(environment).allFlags(); + + WritableMap response = new WritableNativeMap(); + for (Map.Entry entry : flags.entrySet()) { + if (entry.getValue() == null) { + response.putNull(entry.getKey()); + } else if (entry.getValue() instanceof String) { + try { + JsonElement parsedJson = new JsonParser().parse((String) entry.getValue()); + if (parsedJson.isJsonObject()) { + response.putMap(entry.getKey(), fromJsonObject((JsonObject) parsedJson.getAsJsonObject())); + } else if (parsedJson.isJsonArray()) { + response.putArray(entry.getKey(), fromJsonArray((JsonArray) parsedJson.getAsJsonArray())); + } else { + response.putString(entry.getKey(),(String) entry.getValue()); + } + } catch (JsonParseException e) { response.putString(entry.getKey(),(String) entry.getValue()); } - } catch (JsonParseException e) { - response.putString(entry.getKey(),(String) entry.getValue()); - } - } else if (entry.getValue() instanceof Boolean) { - response.putBoolean(entry.getKey(), (Boolean) entry.getValue()); - } else if (entry.getValue() instanceof Double) { - response.putDouble(entry.getKey(), (Double) entry.getValue()); - } else if (entry.getValue() instanceof Float) { - response.putDouble(entry.getKey(), (Float) entry.getValue()); - } else if (entry.getValue() instanceof Integer) { - response.putInt(entry.getKey(), (Integer) entry.getValue()); - } else if (entry.getValue() instanceof JsonNull) { - response.putNull(entry.getKey()); - } else if (entry.getValue() instanceof JsonArray) { - response.putArray(entry.getKey(), fromJsonArray((JsonArray) entry.getValue())); - } else if (entry.getValue() instanceof JsonObject) { - response.putMap(entry.getKey(), fromJsonObject((JsonObject) entry.getValue())); - } else if (entry.getValue() instanceof JsonPrimitive) { - JsonPrimitive primitive = (JsonPrimitive) entry.getValue(); - if (primitive.isString()) { - response.putString(entry.getKey(), primitive.getAsString()); - } else if (primitive.isBoolean()) { - response.putBoolean(entry.getKey(), primitive.getAsBoolean()); - } else if (primitive.isNumber()) { - response.putDouble(entry.getKey(), primitive.getAsDouble()); + } else if (entry.getValue() instanceof Boolean) { + response.putBoolean(entry.getKey(), (Boolean) entry.getValue()); + } else if (entry.getValue() instanceof Double) { + response.putDouble(entry.getKey(), (Double) entry.getValue()); + } else if (entry.getValue() instanceof Float) { + response.putDouble(entry.getKey(), (Float) entry.getValue()); + } else if (entry.getValue() instanceof Integer) { + response.putInt(entry.getKey(), (Integer) entry.getValue()); + } else if (entry.getValue() instanceof JsonNull) { + response.putNull(entry.getKey()); + } else if (entry.getValue() instanceof JsonArray) { + response.putArray(entry.getKey(), fromJsonArray((JsonArray) entry.getValue())); + } else if (entry.getValue() instanceof JsonObject) { + response.putMap(entry.getKey(), fromJsonObject((JsonObject) entry.getValue())); + } else if (entry.getValue() instanceof JsonPrimitive) { + JsonPrimitive primitive = (JsonPrimitive) entry.getValue(); + if (primitive.isString()) { + response.putString(entry.getKey(), primitive.getAsString()); + } else if (primitive.isBoolean()) { + response.putBoolean(entry.getKey(), primitive.getAsBoolean()); + } else if (primitive.isNumber()) { + response.putDouble(entry.getKey(), primitive.getAsDouble()); + } } } + promise.resolve(response); + } catch (Exception e) { + Timber.w(e); } - promise.resolve(response); } - /** - * Runs the SDK's trackData method with a number as custom data - *

- * Separately typed methods are necessary at the React Native bridging layer requires that - * bridged method types disambiguate the value type. - * - * @param eventName Name of the event to track - * @param data The Double data to attach to the tracking event - */ @ReactMethod - public void trackNumber(String eventName, Double data) { + public void trackNumber(String eventName, Double data, String environment) { try { - ldClient.track(eventName, new JsonPrimitive(data)); + LDClient.getForMobileKey(environment).track(eventName, new JsonPrimitive(data)); } catch (Exception e) { Timber.w(e); } } - /** - * Runs the SDK's trackData method with a Boolean as custom data - *

- * Separately typed methods are necessary at the React Native bridging layer requires that - * bridged method types disambiguate the value type. - * - * @param eventName Name of the event to track - * @param data The Boolean data to attach to the tracking event - */ @ReactMethod - public void trackBool(String eventName, Boolean data) { + public void trackBool(String eventName, Boolean data, String environment) { try { - ldClient.track(eventName, new JsonPrimitive(data)); + LDClient.getForMobileKey(environment).track(eventName, new JsonPrimitive(data)); } catch (Exception e) { Timber.w(e); } } - /** - * Runs the SDK's trackData method with a String as custom data - *

- * Separately typed methods are necessary at the React Native bridging layer requires that - * bridged method types disambiguate the value type. - * - * @param eventName Name of the event to track - * @param data The String data to attach to the tracking event - */ @ReactMethod - public void trackString(String eventName, String data) { + public void trackString(String eventName, String data, String environment) { try { - ldClient.track(eventName, new JsonPrimitive(data)); + LDClient.getForMobileKey(environment).track(eventName, new JsonPrimitive(data)); } catch (Exception e) { Timber.w(e); } } - /** - * Runs the SDK's trackData method with an Array as custom data - *

- * Separately typed methods are necessary at the React Native bridging layer requires that - * bridged method types disambiguate the value type. - * - * @param eventName Name of the event to track - * @param data The Array data to attach to the tracking event - */ @ReactMethod - public void trackArray(String eventName, ReadableArray data) { + public void trackArray(String eventName, ReadableArray data, String environment) { try { - ldClient.track(eventName, toJsonArray(data)); + LDClient.getForMobileKey(environment).track(eventName, toJsonArray(data)); } catch (Exception e) { Timber.w(e); } } - /** - * Runs the SDK's trackData method with an object as custom data - *

- * Separately typed methods are necessary at the React Native bridging layer requires that - * bridged method types disambiguate the value type. - * - * @param eventName Name of the event to track - * @param data The Map(Object) data to attach to the tracking event - */ @ReactMethod - public void trackObject(String eventName, ReadableMap data) { + public void trackObject(String eventName, ReadableMap data, String environment) { try { - ldClient.track(eventName, toJsonObject(data)); + LDClient.getForMobileKey(environment).track(eventName, toJsonObject(data)); } catch (Exception e) { Timber.w(e); } } - /** - * Track an event with a custom name. - * - * @param eventName Name of the event - */ @ReactMethod - public void track(String eventName) { + public void track(String eventName, String environment) { try { - ldClient.track(eventName); + LDClient.getForMobileKey(environment).track(eventName); } catch (Exception e) { Timber.w(e); } } @ReactMethod - public void trackNumberMetricValue(String eventName, Double data, Double metricValue) { + public void trackNumberMetricValue(String eventName, Double data, Double metricValue, String environment) { try { - ldClient.track(eventName, new JsonPrimitive(data), metricValue); + LDClient.getForMobileKey(environment).track(eventName, new JsonPrimitive(data), metricValue); } catch (Exception e) { Timber.w(e); } } @ReactMethod - public void trackBoolMetricValue(String eventName, Boolean data, Double metricValue) { + public void trackBoolMetricValue(String eventName, Boolean data, Double metricValue, String environment) { try { - ldClient.track(eventName, new JsonPrimitive(data), metricValue); + LDClient.getForMobileKey(environment).track(eventName, new JsonPrimitive(data), metricValue); } catch (Exception e) { Timber.w(e); } } @ReactMethod - public void trackStringMetricValue(String eventName, String data, Double metricValue) { + public void trackStringMetricValue(String eventName, String data, Double metricValue, String environment) { try { - ldClient.track(eventName, new JsonPrimitive(data), metricValue); + LDClient.getForMobileKey(environment).track(eventName, new JsonPrimitive(data), metricValue); } catch (Exception e) { Timber.w(e); } } @ReactMethod - public void trackArrayMetricValue(String eventName, ReadableArray data, Double metricValue) { + public void trackArrayMetricValue(String eventName, ReadableArray data, Double metricValue, String environment) { try { - ldClient.track(eventName, toJsonArray(data), metricValue); + LDClient.getForMobileKey(environment).track(eventName, toJsonArray(data), metricValue); } catch (Exception e) { Timber.w(e); } } @ReactMethod - public void trackObjectMetricValue(String eventName, ReadableMap data, Double metricValue) { + public void trackObjectMetricValue(String eventName, ReadableMap data, Double metricValue, String environment) { try { - ldClient.track(eventName, toJsonObject(data), metricValue); + LDClient.getForMobileKey(environment).track(eventName, toJsonObject(data), metricValue); } catch (Exception e) { Timber.w(e); } } @ReactMethod - public void trackMetricValue(String eventName, Double metricValue) { + public void trackMetricValue(String eventName, Double metricValue, String environment) { try { - ldClient.track(eventName, new JsonPrimitive(""), metricValue); + LDClient.getForMobileKey(environment).track(eventName, new JsonPrimitive(""), metricValue); } catch (Exception e) { Timber.w(e); } } - /** - * Shuts down any network connections maintained by the client and puts the client in offline - * mode. - */ @ReactMethod public void setOffline(Promise promise) { try { - ldClient.setOffline(); + LDClient.get().setOffline(); promise.resolve(true); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } - /** - * Checks if the client is offline - * - * @param promise resolved with boolean value of whether client is offline, or rejected on error - */ @ReactMethod public void isOffline(Promise promise) { try { - boolean result = ldClient.isOffline(); + boolean result = LDClient.get().isOffline(); promise.resolve(result); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } - /** - * Restores network connectivity for the client, if the client was previously in offline mode. - */ @ReactMethod public void setOnline(Promise promise) { try { - ldClient.setOnline(); + LDClient.get().setOnline(); promise.resolve(true); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } - /** - * Checks if the client is initialized - * - * @param promise resolved with boolean value of whether client is initialized, or rejected on - * error - */ @ReactMethod - public void isInitialized(Promise promise) { - if (ldClient == null) { - promise.resolve(false); - return; - } - + public void isInitialized(String environment, Promise promise) { try { - boolean result = ldClient.isInitialized(); + boolean result = LDClient.getForMobileKey(environment).isInitialized(); promise.resolve(result); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } - /** - * Triggers a background flush of pending events waiting to be sent to LaunchDarkly. - */ @ReactMethod public void flush() { try { - ldClient.flush(); + LDClient.get().flush(); } catch (Exception e) { Timber.w(e); } } - /** - * Triggers a background flush and then closes all connections to LaunchDarkly. - */ @ReactMethod public void close(Promise promise) { try { - ldClient.close(); + LDClient.get().close(); promise.resolve(true); } catch (Exception e) { promise.reject(ERROR_CLOSE, e); } } - /** - * Calls LaunchDarkly's identify call that selects the user flags are pulled for, and tracking - * events refer to. - * - * @param options User configuration ReadableMap (JS Object) - * @param promise Resolved with null when identify complete or rejected with error - */ @ReactMethod public void identify(ReadableMap options, final Promise promise) { final LDUser.Builder userBuilder = userBuild(options); @@ -1089,7 +844,7 @@ public void identify(ReadableMap options, final Promise promise) { @Override public void run() { try { - ldClient.identify(userBuilder.build()).get(); + LDClient.get().identify(userBuilder.build()).get(); promise.resolve(null); } catch (InterruptedException e) { Timber.w(e); @@ -1107,48 +862,52 @@ public void run() { } @ReactMethod - public void getConnectionMode(Promise promise) { + public void getConnectionMode(String environment,Promise promise) { try { - promise.resolve(ldClient.getConnectionInformation().getConnectionMode().name()); + promise.resolve(LDClient.getForMobileKey(environment).getConnectionInformation().getConnectionMode().name()); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } @ReactMethod - public void getLastSuccessfulConnection(Promise promise) { + public void getLastSuccessfulConnection(String environment,Promise promise) { try { - promise.resolve(ldClient.getConnectionInformation().getLastSuccessfulConnection().intValue()); + promise.resolve(LDClient.getForMobileKey(environment).getConnectionInformation().getLastSuccessfulConnection().intValue()); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } @ReactMethod - public void getLastFailedConnection(Promise promise) { + public void getLastFailedConnection(String environment,Promise promise) { try { - promise.resolve(ldClient.getConnectionInformation().getLastFailedConnection().intValue()); + promise.resolve(LDClient.getForMobileKey(environment).getConnectionInformation().getLastFailedConnection().intValue()); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } @ReactMethod - public void getLastFailure(Promise promise) { + public void getLastFailure(String environment,Promise promise) { try { - promise.resolve(ldClient.getConnectionInformation().getLastFailure().getFailureType().name()); + promise.resolve(LDClient.getForMobileKey(environment).getConnectionInformation().getLastFailure().getFailureType().name()); } catch (Exception e) { promise.reject(ERROR_UNKNOWN, e); } } + private String envConcat(String environment, String identifier) { + return environment.concat(";").concat(identifier); + } + @ReactMethod - public void registerFeatureFlagListener(String flagKey) { + public void registerFeatureFlagListener(final String flagKey, final String environment) { FeatureFlagChangeListener listener = new FeatureFlagChangeListener() { @Override public void onFeatureFlagChange(String flagKey) { WritableMap result = Arguments.createMap(); - result.putString("flagKey", flagKey); + result.putString("flagKey", envConcat(environment, flagKey)); getReactApplicationContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) @@ -1157,7 +916,7 @@ public void onFeatureFlagChange(String flagKey) { }; try { - ldClient.registerFeatureFlagListener(flagKey, listener); + LDClient.getForMobileKey(environment).registerFeatureFlagListener(flagKey, listener); listeners.put(flagKey, listener); } catch (Exception e) { Timber.w(e); @@ -1165,10 +924,10 @@ public void onFeatureFlagChange(String flagKey) { } @ReactMethod - public void unregisterFeatureFlagListener(String flagKey) { + public void unregisterFeatureFlagListener(String flagKey, String environment) { try { if (listeners.containsKey(flagKey)) { - ldClient.unregisterFeatureFlagListener(flagKey, listeners.get(flagKey)); + LDClient.getForMobileKey(environment).unregisterFeatureFlagListener(flagKey, listeners.get(flagKey)); listeners.remove(flagKey); } } catch (Exception e) { @@ -1177,12 +936,13 @@ public void unregisterFeatureFlagListener(String flagKey) { } @ReactMethod - public void registerCurrentConnectionModeListener(String listenerId) { + public void registerCurrentConnectionModeListener(final String listenerId, final String environment) { LDStatusListener listener = new LDStatusListener() { @Override public void onConnectionModeChanged(ConnectionInformation connectionInfo) { WritableMap result = Arguments.createMap(); result.putString("connectionMode", gson.toJson(connectionInfo)); + result.putString("listenerId", envConcat(environment, listenerId)); getReactApplicationContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) @@ -1194,7 +954,7 @@ public void onInternalFailure(LDFailure ldFailure) {} }; try { - ldClient.registerStatusListener(listener); + LDClient.getForMobileKey(environment).registerStatusListener(listener); connectionModeListeners.put(listenerId, listener); } catch (Exception e) { Timber.w(e); @@ -1202,10 +962,10 @@ public void onInternalFailure(LDFailure ldFailure) {} } @ReactMethod - public void unregisterCurrentConnectionModeListener(String listenerId) { + public void unregisterCurrentConnectionModeListener(String listenerId, String environment) { try { if (connectionModeListeners.containsKey(listenerId)) { - ldClient.unregisterStatusListener(connectionModeListeners.get(listenerId)); + LDClient.getForMobileKey(environment).unregisterStatusListener(connectionModeListeners.get(listenerId)); connectionModeListeners.remove(listenerId); } } catch (Exception e) { @@ -1214,12 +974,13 @@ public void unregisterCurrentConnectionModeListener(String listenerId) { } @ReactMethod - public void registerAllFlagsListener(String listenerId) { + public void registerAllFlagsListener(final String listenerId, final String environment) { LDAllFlagsListener listener = new LDAllFlagsListener() { @Override public void onChange(List flagKeys) { WritableMap result = Arguments.createMap(); result.putString("flagKeys", gson.toJson(flagKeys)); + result.putString("listenerId", envConcat(environment, listenerId)); getReactApplicationContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) @@ -1228,7 +989,7 @@ public void onChange(List flagKeys) { }; try { - ldClient.registerAllFlagsListener(listener); + LDClient.getForMobileKey(environment).registerAllFlagsListener(listener); allFlagsListeners.put(listenerId, listener); } catch (Exception e) { Timber.w(e); @@ -1236,10 +997,10 @@ public void onChange(List flagKeys) { } @ReactMethod - public void unregisterAllFlagsListener(String listenerId) { + public void unregisterAllFlagsListener(String listenerId, String environment) { try { if (allFlagsListeners.containsKey(listenerId)) { - ldClient.unregisterAllFlagsListener(allFlagsListeners.get(listenerId)); + LDClient.getForMobileKey(environment).unregisterAllFlagsListener(allFlagsListeners.get(listenerId)); allFlagsListeners.remove(listenerId); } } catch (Exception e) { @@ -1247,15 +1008,6 @@ public void unregisterAllFlagsListener(String listenerId) { } } - /** - * Convert a ReadableMap into a JsonObject - *

- * This will recursively convert internal ReadableMaps and ReadableArrays into JsonObjects and - * JsonArrays. - * - * @param readableMap A ReadableMap to be converted to a JsonObject - * @return A JsonObject containing the converted elements from the ReadableMap. - */ private static JsonObject toJsonObject(ReadableMap readableMap) { if (readableMap == null) return null; @@ -1293,15 +1045,6 @@ private static JsonObject toJsonObject(ReadableMap readableMap) { return jsonObject; } - /** - * Convert a ReadableArray into a JsonArray - *

- * This will recursively convert internal ReadableMaps and ReadableArrays into JsonObjects and - * JsonArrays. - * - * @param readableArray A ReadableArray to be converted to a JsonArray - * @return A JsonArray containing the converted elements from the ReadableArray - */ private static JsonArray toJsonArray(ReadableArray readableArray) { if (readableArray == null) return null; @@ -1336,15 +1079,6 @@ private static JsonArray toJsonArray(ReadableArray readableArray) { return jsonArray; } - /** - * Convert a JsonArray into a WritableArray - *

- * This will recursively convert internal JsonObjects and JsonArrays into WritableMaps and - * WritableArrays. - * - * @param jsonArray A JsonArray to be converted into a WritableArray - * @return A WritableArray containing converted elements from the JsonArray - */ private static WritableArray fromJsonArray(JsonArray jsonArray) { if (jsonArray == null) return null; @@ -1371,16 +1105,6 @@ private static WritableArray fromJsonArray(JsonArray jsonArray) { return result; } - - /** - * Convert a JsonObject into a WritableMap - *

- * This will recursively convert internal JsonObjects and JsonArrays into WritableMaps and - * WritableArrays. - * - * @param jsonObject A JsonObject to be converted into a WritableMap - * @return A WritableMap containing converted elements from the jsonObject - */ private static WritableMap fromJsonObject(JsonObject jsonObject) { if (jsonObject == null) return null; @@ -1407,32 +1131,10 @@ private static WritableMap fromJsonObject(JsonObject jsonObject) { return result; } - /** - * A support interface for defining how a ConfigEntryType is read and converted from a - * ReadableMap of configuration entries. - * - * @param The returned type of a value read from the config entry. - */ interface ConvertFromReadable { - /** - * Reads a config entry from map by key and converts to the appropriate return type of the - * ConfigEntryType. - * - * @param map A ReadableMap to get the raw config entry - * @param key The key to look up the config entry from the map - * @return An appropriate return value for the ConfigEntryType - */ T getFromMap(ReadableMap map, String key); } - /** - * An enum for the supported types of config entries. - * - *

- * Each type of config entry has a base ReadableType for checking that a ReadableMap contains an - * entry of the correct type, as well as an implementation of ConvertFromReadable for retrieving - * and converting a ReadableMap entry into a non base type for configuration processing. - */ enum ConfigEntryType implements ConvertFromReadable { String(ReadableType.String) { public String getFromMap(ReadableMap map, String key) { @@ -1464,6 +1166,11 @@ public Boolean getFromMap(ReadableMap map, String key) { return map.getBoolean(key); } }, + Map(ReadableType.Map) { + public Map getFromMap(ReadableMap map, String key) { + return map.getMap(key).toHashMap(); + } + }, StringSet(ReadableType.Array) { public Set getFromMap(ReadableMap map, String key) { ReadableArray array = map.getArray(key); @@ -1488,13 +1195,6 @@ ReadableType getReadableType() { } } - /** - * A helper for looking up a method from a Java class (reflection). - * - * @param cls The class to look up the method from - * @param methodName The name of the method to look up - * @return The looked up method (or null) - */ private static Method findSetter(Class cls, String methodName) { for (Method method : cls.getMethods()) { if (method.getName().equals(methodName) && method.getParameterTypes().length == 1) diff --git a/index.d.ts b/index.d.ts index 1bd1d8e..860e678 100644 --- a/index.d.ts +++ b/index.d.ts @@ -161,6 +161,11 @@ declare module 'launchdarkly-react-native-client-sdk' { */ diagnosticRecordingIntervalMillis?: number; + /** + * The mapping of environment names as keys to mobile keys for each environment as values. + */ + secondaryMobileKeys?: Record; + /** * Whether to treat all user attributes as private for event reporting for all users. * The SDK will not include private attribute values in analytics events, but private attribute names will be sent. @@ -179,6 +184,13 @@ declare module 'launchdarkly-react-native-client-sdk' { */ key: string; + /** + * The secondary key for the user. See the + * [documentation](https://docs.launchdarkly.com/home/managing-flags/targeting-users#percentage-rollout-logic) + * for more information on it's use for percentage rollout bucketing. + */ + secondary?: string; + /** * The user's name. * @@ -434,10 +446,12 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing the flag's value. */ - boolVariation(flagKey: string, defaultValue: boolean): Promise; + boolVariation(flagKey: string, defaultValue: boolean, environment?: string): Promise; /** * Determines the variation of an integer feature flag for the current user. @@ -446,10 +460,12 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing the flag's value. */ - intVariation(flagKey: string, defaultValue: number): Promise; + intVariation(flagKey: string, defaultValue: number, environment?: string): Promise; /** * Determines the variation of a floating-point feature flag for the current user. @@ -458,10 +474,12 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing the flag's value. */ - floatVariation(flagKey: string, defaultValue: number): Promise; + floatVariation(flagKey: string, defaultValue: number, environment?: string): Promise; /** * Determines the variation of a string feature flag for the current user. @@ -470,10 +488,12 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing the flag's value. */ - stringVariation(flagKey: string, defaultValue: string): Promise; + stringVariation(flagKey: string, defaultValue: string, environment?: string): Promise; /** * Determines the variation of a JSON feature flag for the current user. @@ -482,12 +502,15 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing the flag's value. */ jsonVariation( flagKey: string, defaultValue: Record, + environment?: string ): Promise>; /** @@ -503,12 +526,15 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing an [[LDEvaluationDetail]] object containing the value and explanation. */ boolVariationDetail( flagKey: string, defaultValue: boolean, + environment?: string ): Promise>; /** @@ -524,12 +550,15 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing an [[LDEvaluationDetail]] object containing the value and explanation. */ intVariationDetail( flagKey: string, defaultValue: number, + environment?: string ): Promise>; /** @@ -545,12 +574,15 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing an [[LDEvaluationDetail]] object containing the value and explanation. */ floatVariationDetail( flagKey: string, defaultValue: number, + environment?: string ): Promise>; /** @@ -566,12 +598,15 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing an [[LDEvaluationDetail]] object containing the value and explanation. */ stringVariationDetail( flagKey: string, defaultValue: string, + environment?: string ): Promise>; /** @@ -587,24 +622,29 @@ declare module 'launchdarkly-react-native-client-sdk' { * The unique key of the feature flag. * @param defaultValue * The default value of the flag, to be used if the value is not available from LaunchDarkly. + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing an [[LDEvaluationDetail]] object containing the value and explanation. */ jsonVariationDetail( flagKey: string, defaultValue: Record, + environment?: string ): Promise>>; /** * Returns a map of all available flags to the current user's values. * + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise containing an object in which each key is a feature flag key and each value is the flag value. * The promise will be rejected if the SDK has not yet completed initialization. * Note that there is no way to specify a default value for each flag as there is with the * `*Variation` methods, so any flag that cannot be evaluated will have a null value. */ - allFlags(): Promise; + allFlags(environment?: string): Promise; /** * Track events to use in goals or A/B tests. @@ -615,8 +655,10 @@ declare module 'launchdarkly-react-native-client-sdk' { * Optional additional information to associate with the event. * @param metricValue * Optional numeric value to attach to the tracked event + * @param environment + * Optional string to execute the function in a different environment than the default. */ - track(eventName: string, data?: any, metricValue?: number): void; + track(eventName: string, data?: any, metricValue?: number, environment?: string): void; /** * Checks whether the client has been put into offline mode. This is true only if [[setOffline]] @@ -659,10 +701,12 @@ declare module 'launchdarkly-react-native-client-sdk' { * * This function only works when running in Android. On iOS, this function will return a rejected promise. * + * @param environment + * Optional environment name to obtain the result from the corresponding secondary environment * @returns * A promise contianing true if the client is initialized or offline */ - isInitialized(): Promise; + isInitialized(environment?: string): Promise; /** * Flushes all pending analytics events. @@ -697,10 +741,13 @@ declare module 'launchdarkly-react-native-client-sdk' { * The flag key to attach the callback to * @param callback * The callback to attach to the flag key + * @param environment + * Optional string to execute the function in a different environment than the default. */ registerFeatureFlagListener( flagKey: string, callback: (flagKey: string) => void, + environment?: string ): void; /** @@ -710,10 +757,13 @@ declare module 'launchdarkly-react-native-client-sdk' { * The flag key to remove the callback from * @param callback * The callback to remove from the flag key + * @param environment + * Optional string to execute the function in a different environment than the default. */ unregisterFeatureFlagListener( flagKey: string, callback: (flagKey: string) => void, + environment?: string ): void; /** @@ -730,30 +780,36 @@ declare module 'launchdarkly-react-native-client-sdk' { * - `'SHUTDOWN'`: (Android specific enum value) The shutdown state indicates the SDK has been permanently shutdown as a result of a call to close(). * - `'ESTABLISHING_STREAMING_CONNECTION'`: (iOS specific enum value) The SDK is attempting to connect to LaunchDarkly by streaming. * + * @param environment + * Optional string to execute the function in a different environment than the default. * @returns * A promise containing a LDConnectionMode enum value representing the status of the connection to LaunchDarkly. */ - getConnectionMode(): Promise; + getConnectionMode(environment?: string): Promise; /** * Returns the most recent successful flag cache update in millis from the epoch * or null if flags have never been retrieved. * + * @param environment + * Optional string to execute the function in a different environment than the default. * @returns * A promise containing a number representing the status of the connection to LaunchDarkly, * or null if a successful connection has yet to be established. */ - getLastSuccessfulConnection(): Promise; + getLastSuccessfulConnection(environment?: string): Promise; /** * Most recent unsuccessful flag cache update attempt in millis from the epoch * or null if flag update has never been attempted. * + * @param environment + * Optional string to execute the function in a different environment than the default. * @returns * A promise containing a number representing the status of the connection to LaunchDarkly, * or null if a failed connection has yet to occur. */ - getLastFailedConnection(): Promise; + getLastFailedConnection(environment?: string): Promise; /** * Returns the most recent connection failure reason or null. @@ -769,11 +825,13 @@ declare module 'launchdarkly-react-native-client-sdk' { * - `'NETWORK_FAILURE'`: (Android specific enum value) A network request for polling, or the EventSource stream reported a failure. * - `'INVALID_RESPONSE_BODY'`: (Android specific enum value) A response body received either through polling or streaming was unable to be parsed. * + * @param environment + * Optional string to execute the function in a different environment than the default. * @returns * A promise containing a LDFailureReason enum value representing the reason for the most recently failed * connection to LaunchDarkly, or null if a failed connection has yet to occur. */ - getLastFailure(): Promise; + getLastFailure(environment?: string): Promise; /** * Registers a callback to be called on connection status updates. @@ -782,19 +840,24 @@ declare module 'launchdarkly-react-native-client-sdk' { * The listener to be called on a connection status update * @param callback * The callback to attach to the connection status update + * @param environment + * Optional string to execute the function in a different environment than the default. */ registerCurrentConnectionModeListener( listenerId: string, callback: (connectionMode: string) => void, + environment?: string ): void; /** * Unregisters a callback so that it will no longer be called on connection status updates. * * @param listenerId - * The listener to remoce the callback from + * The listener to remove the callback from + * @param environment + * Optional string to execute the function in a different environment than the default. */ - unregisterCurrentConnectionModeListener(listenerId: string): void; + unregisterCurrentConnectionModeListener(listenerId: string, environment?: string): void; /** * Registers a callback to be called when a flag update is processed by the SDK. @@ -803,10 +866,13 @@ declare module 'launchdarkly-react-native-client-sdk' { * The listener to be called when a flag update is processed * @param callback * The callback to attach to the flag update + * @param environment + * Optional string to execute the function in a different environment than the default. */ registerAllFlagsListener( listenerId: string, callback: (updatedFlags: string[]) => void, + environment?: string ): void; /** @@ -814,8 +880,10 @@ declare module 'launchdarkly-react-native-client-sdk' { * * @param listenerId * The listener to be removed + * @param environment + * Optional string to execute the function in a different environment than the default. */ - unregisterAllFlagsListener(listenerId: string): void; + unregisterAllFlagsListener(listenerId: string, environment?: string): void; } } diff --git a/index.js b/index.js index b443f29..9dcea3d 100644 --- a/index.js +++ b/index.js @@ -37,138 +37,150 @@ export default class LDClient { } } - boolVariation(flagKey, defaultValue) { + boolVariation(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.boolVariation(flagKey); + return LaunchdarklyReactNativeClient.boolVariation(flagKey, env); } else { - return LaunchdarklyReactNativeClient.boolVariationDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.boolVariationDefaultValue(flagKey, defaultValue, env); } } - intVariation(flagKey, defaultValue) { + intVariation(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.intVariation(flagKey); + return LaunchdarklyReactNativeClient.intVariation(flagKey, env); } else { - return LaunchdarklyReactNativeClient.intVariationDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.intVariationDefaultValue(flagKey, defaultValue, env); } } - floatVariation(flagKey, defaultValue) { + floatVariation(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.floatVariation(flagKey); + return LaunchdarklyReactNativeClient.floatVariation(flagKey, env); } else { - return LaunchdarklyReactNativeClient.floatVariationDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.floatVariationDefaultValue(flagKey, defaultValue, env); } } - stringVariation(flagKey, defaultValue) { + stringVariation(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.stringVariation(flagKey); + return LaunchdarklyReactNativeClient.stringVariation(flagKey, env); } else { - return LaunchdarklyReactNativeClient.stringVariationDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.stringVariationDefaultValue(flagKey, defaultValue, env); } } - jsonVariation(flagKey, defaultValue) { + jsonVariation(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.jsonVariationNone(flagKey); + return LaunchdarklyReactNativeClient.jsonVariationNone(flagKey, env); } else if (typeof defaultValue === 'number') { - return LaunchdarklyReactNativeClient.jsonVariationNumber(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationNumber(flagKey, defaultValue, env); } else if (typeof defaultValue === 'boolean') { - return LaunchdarklyReactNativeClient.jsonVariationBool(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationBool(flagKey, defaultValue, env); } else if (typeof defaultValue === 'string') { - return LaunchdarklyReactNativeClient.jsonVariationString(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationString(flagKey, defaultValue, env); } else if (Array.isArray(defaultValue)) { - return LaunchdarklyReactNativeClient.jsonVariationArray(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationArray(flagKey, defaultValue, env); } else { // Should be an object - return LaunchdarklyReactNativeClient.jsonVariationObject(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationObject(flagKey, defaultValue, env); } } - boolVariationDetail(flagKey, defaultValue) { + boolVariationDetail(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.boolVariationDetail(flagKey); + return LaunchdarklyReactNativeClient.boolVariationDetail(flagKey, env); } else { - return LaunchdarklyReactNativeClient.boolVariationDetailDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.boolVariationDetailDefaultValue(flagKey, defaultValue, env); } } - intVariationDetail(flagKey, defaultValue) { + intVariationDetail(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.intVariationDetail(flagKey); + return LaunchdarklyReactNativeClient.intVariationDetail(flagKey, env); } else { - return LaunchdarklyReactNativeClient.intVariationDetailDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.intVariationDetailDefaultValue(flagKey, defaultValue, env); } } - floatVariationDetail(flagKey, defaultValue) { + floatVariationDetail(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.floatVariationDetail(flagKey); + return LaunchdarklyReactNativeClient.floatVariationDetail(flagKey, env); } else { - return LaunchdarklyReactNativeClient.floatVariationDetailDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.floatVariationDetailDefaultValue(flagKey, defaultValue, env); } } - stringVariationDetail(flagKey, defaultValue) { + stringVariationDetail(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.stringVariationDetail(flagKey); + return LaunchdarklyReactNativeClient.stringVariationDetail(flagKey, env); } else { - return LaunchdarklyReactNativeClient.stringVariationDetailDefaultValue(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.stringVariationDetailDefaultValue(flagKey, defaultValue, env); } } - jsonVariationDetail(flagKey, defaultValue) { + jsonVariationDetail(flagKey, defaultValue, environment) { + const env = environment !== undefined ? environment : "default"; if (defaultValue == undefined) { - return LaunchdarklyReactNativeClient.jsonVariationDetailNone(flagKey); + return LaunchdarklyReactNativeClient.jsonVariationDetailNone(flagKey, env); } else if (typeof defaultValue === 'number') { - return LaunchdarklyReactNativeClient.jsonVariationDetailNumber(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationDetailNumber(flagKey, defaultValue, env); } else if (typeof defaultValue === 'boolean') { - return LaunchdarklyReactNativeClient.jsonVariationDetailBool(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationDetailBool(flagKey, defaultValue, env); } else if (typeof defaultValue === 'string') { - return LaunchdarklyReactNativeClient.jsonVariationDetailString(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationDetailString(flagKey, defaultValue, env); } else if (Array.isArray(defaultValue)) { - return LaunchdarklyReactNativeClient.jsonVariationDetailArray(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationDetailArray(flagKey, defaultValue, env); } else { // Should be an object - return LaunchdarklyReactNativeClient.jsonVariationDetailObject(flagKey, defaultValue); + return LaunchdarklyReactNativeClient.jsonVariationDetailObject(flagKey, defaultValue, env); } } - allFlags() { - return LaunchdarklyReactNativeClient.allFlags(); + allFlags(environment) { + const env = environment !== undefined ? environment : "default"; + return LaunchdarklyReactNativeClient.allFlags(env); } - track(eventName, data, metricValue) { + track(eventName, data, metricValue, environment) { + const env = environment !== undefined ? environment : "default"; if (metricValue) { if (data === null || typeof data === 'undefined') { - LaunchdarklyReactNativeClient.trackMetricValue(eventName, metricValue); + LaunchdarklyReactNativeClient.trackMetricValue(eventName, metricValue, env); } else if (typeof data === 'number') { - LaunchdarklyReactNativeClient.trackNumberMetricValue(eventName, data, metricValue); + LaunchdarklyReactNativeClient.trackNumberMetricValue(eventName, data, metricValue, env); } else if (typeof data === 'boolean') { - LaunchdarklyReactNativeClient.trackBoolMetricValue(eventName, data, metricValue); + LaunchdarklyReactNativeClient.trackBoolMetricValue(eventName, data, metricValue, env); } else if (typeof data === 'string') { - LaunchdarklyReactNativeClient.trackStringMetricValue(eventName, data, metricValue); + LaunchdarklyReactNativeClient.trackStringMetricValue(eventName, data, metricValue, env); } else if (Array.isArray(data)) { - LaunchdarklyReactNativeClient.trackArrayMetricValue(eventName, data, metricValue); + LaunchdarklyReactNativeClient.trackArrayMetricValue(eventName, data, metricValue, env); } else { // should be an object - LaunchdarklyReactNativeClient.trackObjectMetricValue(eventName, data, metricValue); + LaunchdarklyReactNativeClient.trackObjectMetricValue(eventName, data, metricValue, env); } } else { if (data === null || typeof data === 'undefined') { - LaunchdarklyReactNativeClient.track(eventName); + LaunchdarklyReactNativeClient.track(eventName, env); } else if (typeof data === 'number') { - LaunchdarklyReactNativeClient.trackNumber(eventName, data); + LaunchdarklyReactNativeClient.trackNumber(eventName, data, env); } else if (typeof data === 'boolean') { - LaunchdarklyReactNativeClient.trackBool(eventName, data); + LaunchdarklyReactNativeClient.trackBool(eventName, data, env); } else if (typeof data === 'string') { - LaunchdarklyReactNativeClient.trackString(eventName, data); + LaunchdarklyReactNativeClient.trackString(eventName, data, env); } else if (Array.isArray(data)) { - LaunchdarklyReactNativeClient.trackArray(eventName, data); + LaunchdarklyReactNativeClient.trackArray(eventName, data, env); } else { // should be an object - LaunchdarklyReactNativeClient.trackObject(eventName, data); + LaunchdarklyReactNativeClient.trackObject(eventName, data, env); } } } @@ -185,8 +197,9 @@ export default class LDClient { return LaunchdarklyReactNativeClient.setOnline(); } - isInitialized() { - return LaunchdarklyReactNativeClient.isInitialized(); + isInitialized(environment) { + const env = environment !== undefined ? environment : "default"; + return LaunchdarklyReactNativeClient.isInitialized(env); } flush() { @@ -219,94 +232,121 @@ export default class LDClient { _allFlagsUpdateListener(changedFlags) { const flagKeys = changedFlags.flagKeys; - let listeners = Object.values(this.allFlagsListeners); - for (const listener of listeners) { - listener(flagKeys); + const listenerId = changedFlags.listenerId; + for (const [key, value] of Object.entries(this.allFlagsListeners)) { + if (key == listenerId) { + key(flagKeys); + } } } _connectionModeUpdateListener(connectionStatus) { const connectionMode = connectionStatus.connectionMode; - let listeners = Object.values(this.connectionModeListeners); - for (const listener of listeners) { - listener(connectionMode); + const listenerId = connectionStatus.listenerId; + for (const [key, value] of Object.entries(this.connectionModeListeners)) { + if (key == listenerId) { + key(connectionMode); + } } } - registerFeatureFlagListener(flagKey, callback) { + _envConcat(env, flagKey) { + return env.concat(";", flagKey) + } + + registerFeatureFlagListener(flagKey, callback, environment) { if (typeof callback !== "function") { return; } + const env = environment !== undefined ? environment : "default"; + const multiFlagKey = this._envConcat(env, flagKey); - if (this.flagListeners.hasOwnProperty(flagKey)) { - this.flagListeners[flagKey].push(callback); + if (this.flagListeners.hasOwnProperty(multiFlagKey)) { + this.flagListeners[multiFlagKey].push(callback); } else { - this.flagListeners[flagKey] = [callback]; + this.flagListeners[multiFlagKey] = [callback]; - LaunchdarklyReactNativeClient.registerFeatureFlagListener(flagKey); + LaunchdarklyReactNativeClient.registerFeatureFlagListener(flagKey, env); } } - unregisterFeatureFlagListener(flagKey, callback) { - if (!this.flagListeners.hasOwnProperty(flagKey)) + unregisterFeatureFlagListener(flagKey, callback, environment) { + const env = environment !== undefined ? environment : "default"; + const multiFlagKey = this._envConcat(env, flagKey); + if (!this.flagListeners.hasOwnProperty(multiFlagKey)) { return; + } - this.flagListeners[flagKey] = - this.flagListeners[flagKey].filter(listener => listener != callback); + this.flagListeners[multiFlagKey] = + this.flagListeners[multiFlagKey].filter(listener => listener != callback); - if (this.flagListeners[flagKey].length == 0) { - LaunchdarklyReactNativeClient.unregisterFeatureFlagListener(flagKey); - delete this.flagListeners[flagKey]; + if (this.flagListeners[multiFlagKey].length == 0) { + LaunchdarklyReactNativeClient.unregisterFeatureFlagListener(flagKey, env); + delete this.flagListeners[multiFlagKey]; } } - registerCurrentConnectionModeListener(listenerId, callback) { + registerCurrentConnectionModeListener(listenerId, callback, environment) { if (typeof callback !== "function") { return; } + const env = environment !== undefined ? environment : "default"; + const multiListenerId = this._envConcat(env, flagKey); - this.connectionModeListeners[listenerId] = callback; - LaunchdarklyReactNativeClient.registerCurrentConnectionModeListener(listenerId); + this.connectionModeListeners[multiListenerId] = callback; + LaunchdarklyReactNativeClient.registerCurrentConnectionModeListener(listenerId, env); } - unregisterCurrentConnectionModeListener(listenerId) { - if (!this.connectionModeListeners.hasOwnProperty(listenerId)) + unregisterCurrentConnectionModeListener(listenerId, environment) { + const env = environment !== undefined ? environment : "default"; + const multiListenerId = this._envConcat(env, flagKey); + if (!this.connectionModeListeners.hasOwnProperty(multiListenerId)) { return; + } - LaunchdarklyReactNativeClient.unregisterCurrentConnectionModeListener(listenerId); - delete this.connectionModeListeners[listenerId]; + LaunchdarklyReactNativeClient.unregisterCurrentConnectionModeListener(listenerId, env); + delete this.connectionModeListeners[multiListenerId]; } - registerAllFlagsListener(listenerId, callback) { + registerAllFlagsListener(listenerId, callback, environment) { if (typeof callback !== "function") { return; } + const env = environment !== undefined ? environment : "default"; + const multiListenerId = this._envConcat(env, flagKey); - this.allFlagsListeners[listenerId] = callback; - LaunchdarklyReactNativeClient.registerAllFlagsListener(listenerId); + this.allFlagsListeners[multiListenerId] = callback; + LaunchdarklyReactNativeClient.registerAllFlagsListener(listenerId, env); } - unregisterAllFlagsListener(listenerId) { - if (!this.allFlagsListeners.hasOwnProperty(listenerId)) + unregisterAllFlagsListener(listenerId, environment) { + const env = environment !== undefined ? environment : "default"; + const multiListenerId = this._envConcat(env, flagKey); + if (!this.allFlagsListeners.hasOwnProperty(multiListenerId)) { return; + } - LaunchdarklyReactNativeClient.unregisterAllFlagsListener(listenerId); - delete this.allFlagsListeners[listenerId]; + LaunchdarklyReactNativeClient.unregisterAllFlagsListener(listenerId, env); + delete this.allFlagsListeners[multiListenerId]; } - getConnectionMode() { - return LaunchdarklyReactNativeClient.getConnectionMode(); + getConnectionMode(environment) { + const env = environment !== undefined ? environment : "default"; + return LaunchdarklyReactNativeClient.getConnectionMode(env); } - getLastSuccessfulConnection() { - return LaunchdarklyReactNativeClient.getLastSuccessfulConnection(); + getLastSuccessfulConnection(environment) { + const env = environment !== undefined ? environment : "default"; + return LaunchdarklyReactNativeClient.getLastSuccessfulConnection(env); } - getLastFailedConnection() { - return LaunchdarklyReactNativeClient.getLastFailedConnection(); + getLastFailedConnection(environment) { + const env = environment !== undefined ? environment : "default"; + return LaunchdarklyReactNativeClient.getLastFailedConnection(env); } - getLastFailure() { - return LaunchdarklyReactNativeClient.getLastFailure(); + getLastFailure(environment) { + const env = environment !== undefined ? environment : "default"; + return LaunchdarklyReactNativeClient.getLastFailure(env); } } diff --git a/ios/LaunchdarklyReactNativeClient.swift b/ios/LaunchdarklyReactNativeClient.swift index f3966b8..0dd1488 100644 --- a/ios/LaunchdarklyReactNativeClient.swift +++ b/ios/LaunchdarklyReactNativeClient.swift @@ -48,7 +48,8 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { } } else { LDClient.start(config: config!, user: user, completion: {() -> Void in - resolve(nil)}) + resolve(nil) + }) } } } @@ -134,6 +135,10 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { ldConfig.diagnosticRecordingInterval = TimeInterval(config["diagnosticRecordingIntervalMillis"] as! Float / 1000) } + if config["secondaryMobileKeys"] != nil { + try! ldConfig.setSecondaryMobileKeys(config["secondaryMobileKeys"] as! [String: String]) + } + if config["allUserAttributesPrivate"] != nil { ldConfig.allUserAttributesPrivate = config["allUserAttributesPrivate"] as! Bool } @@ -146,6 +151,10 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { private func userBuild(userDict: NSDictionary) -> LDUser? { var user = LDUser() user.key = userDict["key"] as! String + + if userDict["secondary"] != nil { + user.secondary = userDict["secondary"] as? String + } if userDict["name"] != nil { user.name = userDict["name"] as? String @@ -190,253 +199,253 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { return user } - @objc func boolVariationDefaultValue(_ flagKey: String, defaultValue: ObjCBool, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue.boolValue) as Bool) + @objc func boolVariationDefaultValue(_ flagKey: String, defaultValue: ObjCBool, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue.boolValue) as Bool) } - @objc func intVariationDefaultValue(_ flagKey: String, defaultValue: Int, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue) as Int) + @objc func intVariationDefaultValue(_ flagKey: String, defaultValue: Int, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue) as Int) } - @objc func floatVariationDefaultValue(_ flagKey: String, defaultValue: CGFloat, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: Double(defaultValue)) as Double) + @objc func floatVariationDefaultValue(_ flagKey: String, defaultValue: CGFloat, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: Double(defaultValue)) as Double) } - @objc func stringVariationDefaultValue(_ flagKey: String, defaultValue: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue) as String) + @objc func stringVariationDefaultValue(_ flagKey: String, defaultValue: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue) as String) } - @objc func boolVariation(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let boolFlagValue: Bool? = LDClient.get()!.variation(forKey: flagKey) + @objc func boolVariation(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let boolFlagValue: Bool? = LDClient.get(environment: environment)!.variation(forKey: flagKey) resolve(boolFlagValue) } - @objc func intVariation(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let intFlagValue: Int? = LDClient.get()!.variation(forKey: flagKey) + @objc func intVariation(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let intFlagValue: Int? = LDClient.get(environment: environment)!.variation(forKey: flagKey) resolve(intFlagValue) } - @objc func floatVariation(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let floatFlagValue: Double? = LDClient.get()!.variation(forKey: flagKey) + @objc func floatVariation(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let floatFlagValue: Double? = LDClient.get(environment: environment)!.variation(forKey: flagKey) resolve(floatFlagValue) } - @objc func stringVariation(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let stringFlagValue: String? = LDClient.get()!.variation(forKey: flagKey) + @objc func stringVariation(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let stringFlagValue: String? = LDClient.get(environment: environment)!.variation(forKey: flagKey) resolve(stringFlagValue) } - @objc func jsonVariationNone(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let jsonFlagValue: Dictionary? = LDClient.get()!.variation(forKey: flagKey) + @objc func jsonVariationNone(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let jsonFlagValue: Dictionary? = LDClient.get(environment: environment)!.variation(forKey: flagKey) resolve(jsonFlagValue) } - @objc func jsonVariationNumber(_ flagKey: String, defaultValue: Double, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue) as Double) + @objc func jsonVariationNumber(_ flagKey: String, defaultValue: Double, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue) as Double) } - @objc func jsonVariationBool(_ flagKey: String, defaultValue: Bool, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue) as Bool) + @objc func jsonVariationBool(_ flagKey: String, defaultValue: Bool, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue) as Bool) } - @objc func jsonVariationString(_ flagKey: String, defaultValue: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue) as String) + @objc func jsonVariationString(_ flagKey: String, defaultValue: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue) as String) } - @objc func jsonVariationArray(_ flagKey: String, defaultValue: Array, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue) as Array) + @objc func jsonVariationArray(_ flagKey: String, defaultValue: Array, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue) as Array) } - @objc func jsonVariationObject(_ flagKey: String, defaultValue: NSDictionary, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.variation(forKey: flagKey, defaultValue: defaultValue.swiftDictionary) as NSDictionary) + @objc func jsonVariationObject(_ flagKey: String, defaultValue: NSDictionary, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.variation(forKey: flagKey, defaultValue: defaultValue.swiftDictionary) as NSDictionary) } - @objc func boolVariationDetailDefaultValue(_ flagKey: String, defaultValue: ObjCBool, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue.boolValue) + @objc func boolVariationDetailDefaultValue(_ flagKey: String, defaultValue: ObjCBool, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue.boolValue) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func intVariationDetailDefaultValue(_ flagKey: String, defaultValue: Int, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue) + @objc func intVariationDetailDefaultValue(_ flagKey: String, defaultValue: Int, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func floatVariationDetailDefaultValue(_ flagKey: String, defaultValue: CGFloat, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: Double(defaultValue)) + @objc func floatVariationDetailDefaultValue(_ flagKey: String, defaultValue: CGFloat, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: Double(defaultValue)) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func stringVariationDetailDefaultValue(_ flagKey: String, defaultValue: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue) + @objc func stringVariationDetailDefaultValue(_ flagKey: String, defaultValue: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func boolVariationDetail(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail: LDEvaluationDetail = LDClient.get()!.variationDetail(forKey: flagKey) + @objc func boolVariationDetail(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail: LDEvaluationDetail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func intVariationDetail(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail: LDEvaluationDetail = LDClient.get()!.variationDetail(forKey: flagKey) + @objc func intVariationDetail(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail: LDEvaluationDetail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func floatVariationDetail(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail: LDEvaluationDetail = LDClient.get()!.variationDetail(forKey: flagKey) + @objc func floatVariationDetail(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail: LDEvaluationDetail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func stringVariationDetail(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail: LDEvaluationDetail = LDClient.get()!.variationDetail(forKey: flagKey) + @objc func stringVariationDetail(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail: LDEvaluationDetail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func jsonVariationDetailNone(_ flagKey: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail: LDEvaluationDetail?> = LDClient.get()!.variationDetail(forKey: flagKey) + @objc func jsonVariationDetailNone(_ flagKey: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail: LDEvaluationDetail?> = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func jsonVariationDetailNumber(_ flagKey: String, defaultValue: Double, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue) + @objc func jsonVariationDetailNumber(_ flagKey: String, defaultValue: Double, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func jsonVariationDetailBool(_ flagKey: String, defaultValue: Bool, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue) + @objc func jsonVariationDetailBool(_ flagKey: String, defaultValue: Bool, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func jsonVariationDetailString(_ flagKey: String, defaultValue: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue) + @objc func jsonVariationDetailString(_ flagKey: String, defaultValue: String, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func jsonVariationDetailArray(_ flagKey: String, defaultValue: Array, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue) + @objc func jsonVariationDetailArray(_ flagKey: String, defaultValue: Array, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func jsonVariationDetailObject(_ flagKey: String, defaultValue: NSDictionary, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let detail = LDClient.get()!.variationDetail(forKey: flagKey, defaultValue: defaultValue.swiftDictionary) + @objc func jsonVariationDetailObject(_ flagKey: String, defaultValue: NSDictionary, environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let detail = LDClient.get(environment: environment)!.variationDetail(forKey: flagKey, defaultValue: defaultValue.swiftDictionary) let jsonObject: NSDictionary = [ - "value": (detail.value as Any?) ?? NSNull(), - "variationIndex": (detail.variationIndex as Any?) ?? NSNull(), - "reason": (detail.reason as Any?) ?? NSNull() + "value": (detail.value as Any), + "variationIndex": (detail.variationIndex as Any), + "reason": (detail.reason as Any) ] resolve(jsonObject) } - @objc func trackNumber(_ eventName: String, data: NSNumber) -> Void { - try? LDClient.get()!.track(key: eventName, data: data) + @objc func trackNumber(_ eventName: String, data: NSNumber, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data) } - @objc func trackBool(_ eventName: String, data: ObjCBool) -> Void { - try? LDClient.get()!.track(key: eventName, data: data.boolValue) + @objc func trackBool(_ eventName: String, data: ObjCBool, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data.boolValue) } - @objc func trackString(_ eventName: String, data: String) -> Void { - try? LDClient.get()!.track(key: eventName, data: data) + @objc func trackString(_ eventName: String, data: String, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data) } - @objc func trackArray(_ eventName: String, data: NSArray) -> Void { - try? LDClient.get()!.track(key: eventName, data: data) + @objc func trackArray(_ eventName: String, data: NSArray, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data) } - @objc func trackObject(_ eventName: String, data: NSDictionary) -> Void { - try? LDClient.get()!.track(key: eventName, data: data.swiftDictionary) + @objc func trackObject(_ eventName: String, data: NSDictionary, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data.swiftDictionary) } - @objc func track(_ eventName: String) -> Void { - try? LDClient.get()!.track(key: eventName) + @objc func track(_ eventName: String, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName) } - @objc func trackNumberMetricValue(_ eventName: String, data: NSNumber, metricValue: NSNumber) -> Void { - try? LDClient.get()!.track(key: eventName, data: data, metricValue: Double(truncating: metricValue)) + @objc func trackNumberMetricValue(_ eventName: String, data: NSNumber, metricValue: NSNumber, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data, metricValue: Double(truncating: metricValue)) } - @objc func trackBoolMetricValue(_ eventName: String, data: ObjCBool, metricValue: NSNumber) -> Void { - try? LDClient.get()!.track(key: eventName, data: data.boolValue, metricValue: Double(truncating: metricValue)) + @objc func trackBoolMetricValue(_ eventName: String, data: ObjCBool, metricValue: NSNumber, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data.boolValue, metricValue: Double(truncating: metricValue)) } - @objc func trackStringMetricValue(_ eventName: String, data: String, metricValue: NSNumber) -> Void { - try? LDClient.get()!.track(key: eventName, data: data, metricValue: Double(truncating: metricValue)) + @objc func trackStringMetricValue(_ eventName: String, data: String, metricValue: NSNumber, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data, metricValue: Double(truncating: metricValue)) } - @objc func trackArrayMetricValue(_ eventName: String, data: NSArray, metricValue: NSNumber) -> Void { - try? LDClient.get()!.track(key: eventName, data: data, metricValue: Double(truncating: metricValue)) + @objc func trackArrayMetricValue(_ eventName: String, data: NSArray, metricValue: NSNumber, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data, metricValue: Double(truncating: metricValue)) } - @objc func trackObjectMetricValue(_ eventName: String, data: NSDictionary, metricValue: NSNumber) -> Void { - try? LDClient.get()!.track(key: eventName, data: data.swiftDictionary, metricValue: Double(truncating: metricValue)) + @objc func trackObjectMetricValue(_ eventName: String, data: NSDictionary, metricValue: NSNumber, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, data: data.swiftDictionary, metricValue: Double(truncating: metricValue)) } - @objc func trackMetricValue(_ eventName: String, metricValue: NSNumber) -> Void { - try? LDClient.get()!.track(key: eventName, metricValue: Double(truncating: metricValue)) + @objc func trackMetricValue(_ eventName: String, metricValue: NSNumber, environment: String) -> Void { + try? LDClient.get(environment: environment)!.track(key: eventName, metricValue: Double(truncating: metricValue)) } @objc func setOffline(_ resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @@ -446,7 +455,7 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { } @objc func isOffline(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(!LDClient.get()!.isOnline) + resolve(LDClient.get()!.isOnline) } @objc func setOnline(_ resolve: @escaping RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @@ -475,9 +484,9 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { } } - @objc func allFlags(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + @objc func allFlags(_ environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { var allFlagsDict: [String: Any] = [:] - if let allFlags = LDClient.get()!.allFlags { + if let allFlags = LDClient.get(environment: environment)!.allFlags { for (key, value) in allFlags { allFlagsDict[key] = value } @@ -485,36 +494,8 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { resolve(allFlagsDict as NSDictionary) } - @objc func registerFeatureFlagListener(_ flagKey: String) -> Void { - let flagChangeOwner = flagKey as LDObserverOwner - if listenerKeys[flagKey] == nil { - listenerKeys[flagKey] = flagChangeOwner - } else { - return - } - LDClient.get()!.observe(keys: [flagKey], owner: flagChangeOwner, handler: { (changedFlags) in - if changedFlags[flagKey] != nil && self.bridge != nil { - self.sendEvent(withName: self.FLAG_PREFIX, body: ["flagKey": flagKey]) - } - }) - } - - private func unregisterListener(_ key: String) -> Void { - let owner = key as LDObserverOwner - if listenerKeys[key] != nil { - listenerKeys.removeValue(forKey: key) - } else { - return - } - LDClient.get()!.stopObserving(owner: owner) - } - - @objc func unregisterFeatureFlagListener(_ flagKey: String) -> Void { - unregisterListener(flagKey) - } - - @objc func getConnectionMode(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let connectionInformation = LDClient.get()!.getConnectionInformation() + @objc func getConnectionMode(_ environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let connectionInformation = LDClient.get(environment: environment)!.getConnectionInformation() var connectionMode: String switch connectionInformation.currentConnectionMode { case .streaming: @@ -530,16 +511,16 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { } // lastKnownFlagValidity is nil if either no connection has ever been successfully made or if the SDK has an active streaming connection. It will have a value if 1) in polling mode and at least one poll has completed successfully, or 2) if in streaming mode whenever the streaming connection closes. - @objc func getLastSuccessfulConnection(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.getConnectionInformation().lastKnownFlagValidity ?? 0) + @objc func getLastSuccessfulConnection(_ environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.getConnectionInformation().lastKnownFlagValidity ?? 0) } - @objc func getLastFailedConnection(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - resolve(LDClient.get()!.getConnectionInformation().lastFailedConnection ?? 0) + @objc func getLastFailedConnection(_ environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + resolve(LDClient.get(environment: environment)!.getConnectionInformation().lastFailedConnection ?? 0) } - @objc func getLastFailure(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { - let connectionInformation = LDClient.get()!.getConnectionInformation() + @objc func getLastFailure(_ environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + let connectionInformation = LDClient.get(environment: environment)!.getConnectionInformation() var failureReason: String switch connectionInformation.lastConnectionFailureReason { case .unauthorized: @@ -553,48 +534,80 @@ class LaunchdarklyReactNativeClient: RCTEventEmitter { } resolve(failureReason) } + + private func envConcat(environment: String, identifier: String) -> String { + return environment + ";" + identifier + } + + @objc func registerFeatureFlagListener(_ flagKey: String, environment: String) -> Void { + let flagChangeOwner = flagKey as LDObserverOwner + if listenerKeys[flagKey] == nil { + listenerKeys[flagKey] = flagChangeOwner + } else { + return + } + LDClient.get(environment: environment)!.observe(keys: [flagKey], owner: flagChangeOwner, handler: { (changedFlags) in + if changedFlags[flagKey] != nil && self.bridge != nil { + self.sendEvent(withName: self.FLAG_PREFIX, body: ["flagKey": self.envConcat(environment: environment, identifier: flagKey)]) + } + }) + } + + private func unregisterListener(_ key: String, _ environment: String) -> Void { + let owner = key as LDObserverOwner + if listenerKeys[key] != nil { + listenerKeys.removeValue(forKey: key) + } else { + return + } + LDClient.get(environment: environment)!.stopObserving(owner: owner) + } + + @objc func unregisterFeatureFlagListener(_ flagKey: String, environment: String) -> Void { + unregisterListener(flagKey, environment) + } - @objc func registerCurrentConnectionModeListener(_ listenerId: String) -> Void { + @objc func registerCurrentConnectionModeListener(_ listenerId: String, environment: String) -> Void { let currentConnectionModeOwner = listenerId as LDObserverOwner if listenerKeys[listenerId] == nil { listenerKeys.removeValue(forKey: listenerId) } else { return } - LDClient.get()!.observeCurrentConnectionMode(owner: currentConnectionModeOwner, handler: { (connectionMode) in + LDClient.get(environment: environment)!.observeCurrentConnectionMode(owner: currentConnectionModeOwner, handler: { (connectionMode) in if self.bridge != nil { - self.sendEvent(withName: self.CONNECTION_MODE_PREFIX, body: ["connectionMode": connectionMode]) + self.sendEvent(withName: self.CONNECTION_MODE_PREFIX, body: ["connectionMode": connectionMode, "listenerId": self.envConcat(environment: environment, identifier: listenerId)]) } }) } - @objc func unregisterCurrentConnectionModeListener(_ listenerId: String) -> Void { - unregisterListener(listenerId) + @objc func unregisterCurrentConnectionModeListener(_ listenerId: String, environment: String) -> Void { + unregisterListener(listenerId, environment) } - @objc func registerAllFlagsListener(_ listenerId: String) -> Void { + @objc func registerAllFlagsListener(_ listenerId: String, environment: String) -> Void { let flagChangeOwner = listenerId as LDObserverOwner if listenerKeys[listenerId] == nil { listenerKeys[listenerId] = flagChangeOwner } else { return } - LDClient.get()!.observeAll(owner: flagChangeOwner, handler: { (changedFlags) in + LDClient.get(environment: environment)!.observeAll(owner: flagChangeOwner, handler: { (changedFlags) in if self.bridge != nil { - self.sendEvent(withName: self.ALL_FLAGS_PREFIX, body: ["flagKeys": changedFlags.keys.description]) + self.sendEvent(withName: self.ALL_FLAGS_PREFIX, body: ["flagKeys": changedFlags.keys.description, "listenerId": self.envConcat(environment: environment, identifier: listenerId)]) } }) } - @objc func unregisterAllFlagsListener(_ listenerId: String) -> Void { - unregisterListener(listenerId) + @objc func unregisterAllFlagsListener(_ listenerId: String, environment: String) -> Void { + unregisterListener(listenerId, environment) } - @objc func isInitialized(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { + @objc func isInitialized(_ environment: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { if LDClient.get() == nil { resolve(false) } else { - resolve(LDClient.get()!.isInitialized) + resolve(LDClient.get(environment: environment)!.isInitialized) } } } diff --git a/ios/LaunchdarklyReactNativeClientBridge.m b/ios/LaunchdarklyReactNativeClientBridge.m index af3931a..76bf0c3 100644 --- a/ios/LaunchdarklyReactNativeClientBridge.m +++ b/ios/LaunchdarklyReactNativeClientBridge.m @@ -7,85 +7,85 @@ @interface RCT_EXTERN_MODULE(LaunchdarklyReactNativeClient, RCTEventEmitter) RCT_EXTERN_METHOD(configureWithTimeout:(NSDictionary *)config userConfig:(NSDictionary *)userConfig timeout:(NSInteger *)timeout resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(boolVariationDefaultValue:(NSString *)flagKey defaultValue:(BOOL *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(boolVariationDefaultValue:(NSString *)flagKey defaultValue:(BOOL *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(intVariationDefaultValue:(NSString *)flagKey defaultValue:(NSInteger *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(intVariationDefaultValue:(NSString *)flagKey defaultValue:(NSInteger *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(floatVariationDefaultValue:(NSString *)flagKey defaultValue:(CGFloat *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(floatVariationDefaultValue:(NSString *)flagKey defaultValue:(CGFloat *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(stringVariationDefaultValue:(NSString *)flagKey defaultValue:(NSString *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(stringVariationDefaultValue:(NSString *)flagKey defaultValue:(NSString *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(boolVariation:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(boolVariation:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(intVariation:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(intVariation:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(floatVariation:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(floatVariation:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(stringVariation:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(stringVariation:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationNone:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationNone:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationNumber:(NSString *)flagKey defaultValue:(NSNumber *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationNumber:(NSString *)flagKey defaultValue:(NSNumber *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationBool:(NSString *)flagKey defaultValue:(BOOL *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationBool:(NSString *)flagKey defaultValue:(BOOL *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationString:(NSString *)flagKey defaultValue:(NSString *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationString:(NSString *)flagKey defaultValue:(NSString *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationArray:(NSString *)flagKey defaultValue:(NSArray *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationArray:(NSString *)flagKey defaultValue:(NSArray *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationObject:(NSString *)flagKey defaultValue:(NSDictionary *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationObject:(NSString *)flagKey defaultValue:(NSDictionary *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(boolVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(BOOL *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(boolVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(BOOL *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(intVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(NSInteger *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(intVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(NSInteger *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(floatVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(CGFloat *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(floatVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(CGFloat *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(stringVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(NSString *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(stringVariationDetailDefaultValue:(NSString *)flagKey defaultValue:(NSString *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(boolVariationDetail:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(boolVariationDetail:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(intVariationDetail:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(intVariationDetail:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(floatVariationDetail:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(floatVariationDetail:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(stringVariationDetail:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(stringVariationDetail:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationDetailNone:(NSString *)flagKey resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationDetailNone:(NSString *)flagKey environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationDetailNumber:(NSString *)flagKey defaultValue:(NSNumber *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationDetailNumber:(NSString *)flagKey defaultValue:(NSNumber *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationDetailBool:(NSString *)flagKey defaultValue:(BOOL *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationDetailBool:(NSString *)flagKey defaultValue:(BOOL *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationDetailString:(NSString *)flagKey defaultValue:(NSString *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationDetailString:(NSString *)flagKey defaultValue:(NSString *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationDetailArray:(NSString *)flagKey defaultValue:(NSArray *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationDetailArray:(NSString *)flagKey defaultValue:(NSArray *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(jsonVariationDetailObject:(NSString *)flagKey defaultValue:(NSDictionary *)defaultValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(jsonVariationDetailObject:(NSString *)flagKey defaultValue:(NSDictionary *)defaultValue environment:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(trackBool:(NSString *)eventName data:(BOOL *)data) +RCT_EXTERN_METHOD(trackBool:(NSString *)eventName data:(BOOL *)data environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackArray:(NSString *)eventName data:(NSArray *)data) +RCT_EXTERN_METHOD(trackArray:(NSString *)eventName data:(NSArray *)data environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackNumber:(NSString *)eventName data:(NSNumber * _Nonnull)data) +RCT_EXTERN_METHOD(trackNumber:(NSString *)eventName data:(NSNumber * _Nonnull)data environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackString:(NSString *)eventName data:(NSString *)data) +RCT_EXTERN_METHOD(trackString:(NSString *)eventName data:(NSString *)data environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackObject:(NSString *)eventName data:(NSDictionary *)data) +RCT_EXTERN_METHOD(trackObject:(NSString *)eventName data:(NSDictionary *)data environment:(NSString *)environment) -RCT_EXTERN_METHOD(track:(NSString *)eventName) +RCT_EXTERN_METHOD(track:(NSString *)eventName environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackBoolMetricValue:(NSString *)eventName data:(BOOL *)data metricValue:(NSNumber * _Nonnull)metricValue) +RCT_EXTERN_METHOD(trackBoolMetricValue:(NSString *)eventName data:(BOOL *)data metricValue:(NSNumber * _Nonnull)metricValue environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackArrayMetricValue:(NSString *)eventName data:(NSArray *)data metricValue:(NSNumber * _Nonnull)metricValue) +RCT_EXTERN_METHOD(trackArrayMetricValue:(NSString *)eventName data:(NSArray *)data metricValue:(NSNumber * _Nonnull)metricValue environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackNumberMetricValue:(NSString *)eventName data:(NSNumber * _Nonnull)data metricValue:(NSNumber * _Nonnull)metricValue) +RCT_EXTERN_METHOD(trackNumberMetricValue:(NSString *)eventName data:(NSNumber *)data metricValue:(NSNumber * _Nonnull)metricValue environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackStringMetricValue:(NSString *)eventName data:(NSString *)data metricValue:(NSNumber * _Nonnull)metricValue) +RCT_EXTERN_METHOD(trackStringMetricValue:(NSString *)eventName data:(NSString *)data metricValue:(NSNumber * _Nonnull)metricValue environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackObjectMetricValue:(NSString *)eventName data:(NSDictionary *)data metricValue:(NSNumber * _Nonnull)metricValue) +RCT_EXTERN_METHOD(trackObjectMetricValue:(NSString *)eventName data:(NSDictionary *)data metricValue:(NSNumber * _Nonnull)metricValue environment:(NSString *)environment) -RCT_EXTERN_METHOD(trackMetricValue:(NSString *)eventName metricValue:(NSNumber * _Nonnull)metricValue) +RCT_EXTERN_METHOD(trackMetricValue:(NSString *)eventName metricValue:(NSNumber * _Nonnull)metricValue environment:(NSString *)environment) RCT_EXTERN_METHOD(setOffline:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) @@ -99,28 +99,28 @@ @interface RCT_EXTERN_MODULE(LaunchdarklyReactNativeClient, RCTEventEmitter) RCT_EXTERN_METHOD(identify:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(allFlags:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(allFlags:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(registerFeatureFlagListener:(NSString *)flagKey) +RCT_EXTERN_METHOD(registerFeatureFlagListener:(NSString *)flagKey environment:(NSString *)environment) -RCT_EXTERN_METHOD(unregisterFeatureFlagListener:(NSString *)flagKey) +RCT_EXTERN_METHOD(unregisterFeatureFlagListener:(NSString *)flagKey environment:(NSString *)environment) -RCT_EXTERN_METHOD(registerCurrentConnectionModeListener:(NSString *)listenerId) +RCT_EXTERN_METHOD(registerCurrentConnectionModeListener:(NSString *)listenerId environment:(NSString *)environment) -RCT_EXTERN_METHOD(unregisterCurrentConnectionModeListener:(NSString *)listenerId) +RCT_EXTERN_METHOD(unregisterCurrentConnectionModeListener:(NSString *)listenerId environment:(NSString *)environment) -RCT_EXTERN_METHOD(registerAllFlagsListener:(NSString *)listenerId) +RCT_EXTERN_METHOD(registerAllFlagsListener:(NSString *)listenerId environment:(NSString *)environment) -RCT_EXTERN_METHOD(unregisterAllFlagsListener:(NSString *)listenerId) +RCT_EXTERN_METHOD(unregisterAllFlagsListener:(NSString *)listenerId environment:(NSString *)environment) -RCT_EXTERN_METHOD(isInitialized:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(isInitialized:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(getConnectionMode:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getConnectionMode:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(getLastSuccessfulConnection:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getLastSuccessfulConnection:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(getLastFailedConnection:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getLastFailedConnection:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) -RCT_EXTERN_METHOD(getLastFailure:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getLastFailure:(NSString *)environment resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) @end diff --git a/test-types.ts b/test-types.ts index f311656..94b3b69 100644 --- a/test-types.ts +++ b/test-types.ts @@ -41,6 +41,7 @@ async function tests() { offline: true, debugMode: true, evaluationReasons: true, + secondaryMobileKeys: {'test' : 'fake_key'}, maxCachedUsers: 6, diagnosticOptOut: true, diagnosticRecordingIntervalMillis: 100000, @@ -49,6 +50,7 @@ async function tests() { const userWithKeyOnly: LDUser = { key: 'user' }; const user: LDUser = { key: 'user', + secondary: 'user.secondary', name: 'name', firstName: 'first', lastName: 'last', @@ -64,7 +66,7 @@ async function tests() { const timeoutClient: LDClient = new LDClient(); const configure: null = await client.configure(configWithAllOptions, user); - const configureWithTimeout: null = await timeoutClient.configure(configWithAllOptions, user, 10); + const configureWithTimeout: null = await timeoutClient.configure(configWithAllOptions, userWithKeyOnly, 10); const identify: null = await client.identify(user); const boolFlagValue: boolean = await client.boolVariation('key', false); @@ -79,6 +81,12 @@ async function tests() { const stringDetail: LDEvaluationDetail = await client.stringVariationDetail('key', 'default'); const jsonDetail: LDEvaluationDetail> = await client.jsonVariationDetail('key', jsonObj); + const boolDetailMulti: LDEvaluationDetail = await client.boolVariationDetail('key', false, 'test'); + const intDetailMulti: LDEvaluationDetail = await client.intVariationDetail('key', 2, 'test'); + const floatDetailMulti: LDEvaluationDetail = await client.floatVariationDetail('key', 2.3, 'test'); + const stringDetailMulti: LDEvaluationDetail = await client.stringVariationDetail('key', 'default', 'test'); + const jsonDetailMulti: LDEvaluationDetail> = await client.jsonVariationDetail('key', jsonObj, 'test'); + const detailIndex: number | undefined = boolDetail.variationIndex; const detailReason: LDEvaluationReason = boolDetail.reason; const detailBoolValue: boolean = boolDetail.value;