@react-native-firebase/remote-config 21.7.4 → 21.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [21.8.0](https://github.com/invertase/react-native-firebase/compare/v21.7.4...v21.8.0) (2025-02-10)
7
+
8
+ ### Features
9
+
10
+ - **remote-config:** support for custom signals ([#8274](https://github.com/invertase/react-native-firebase/issues/8274)) ([94c6a27](https://github.com/invertase/react-native-firebase/commit/94c6a27e6692138cd32394218a492d17d68de0f0))
11
+
12
+ ### Bug Fixes
13
+
14
+ - do not ship unit tests in released packages ([e71dadf](https://github.com/invertase/react-native-firebase/commit/e71dadfc1c0cad2e89c94100913af31ddf7d9c91))
15
+
6
16
  ## [21.7.4](https://github.com/invertase/react-native-firebase/compare/v21.7.3...v21.7.4) (2025-02-08)
7
17
 
8
18
  ### Bug Fixes
@@ -25,8 +25,10 @@ import android.content.res.Resources;
25
25
  import android.content.res.XmlResourceParser;
26
26
  import android.os.Bundle;
27
27
  import com.google.android.gms.tasks.Task;
28
+ import com.google.android.gms.tasks.TaskCompletionSource;
28
29
  import com.google.android.gms.tasks.Tasks;
29
30
  import com.google.firebase.FirebaseApp;
31
+ import com.google.firebase.remoteconfig.CustomSignals;
30
32
  import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
31
33
  import com.google.firebase.remoteconfig.FirebaseRemoteConfigInfo;
32
34
  import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
@@ -199,6 +201,40 @@ public class UniversalFirebaseConfigModule extends UniversalFirebaseModule {
199
201
  return convertedConfigBundle;
200
202
  }
201
203
 
204
+ Task<Void> setCustomSignals(String appName, HashMap<String, Object> customSignalsMap) {
205
+ TaskCompletionSource<Void> taskCompletionSource = new TaskCompletionSource<>();
206
+
207
+ FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
208
+
209
+ getExecutor().execute(
210
+ () -> {
211
+ try {
212
+ CustomSignals.Builder customSignals = new CustomSignals.Builder();
213
+ for (Map.Entry<String, Object> entry : customSignalsMap.entrySet()) {
214
+ Object value = entry.getValue();
215
+ if (value instanceof String) {
216
+ customSignals.put(entry.getKey(), (String) value);
217
+ } else if (value instanceof Long) {
218
+ customSignals.put(entry.getKey(), (Long) value);
219
+ } else if (value instanceof Integer) {
220
+ customSignals.put(entry.getKey(), ((Integer) value).longValue());
221
+ } else if (value instanceof Double) {
222
+ customSignals.put(entry.getKey(), (Double) value);
223
+ } else if (value == null) {
224
+ customSignals.put(entry.getKey(), null);
225
+ }
226
+ }
227
+
228
+ Tasks.await(FirebaseRemoteConfig.getInstance(firebaseApp).setCustomSignals(customSignals.build()));
229
+ taskCompletionSource.setResult(null);
230
+ } catch (Exception e) {
231
+ taskCompletionSource.setException(e);
232
+ }
233
+ });
234
+
235
+ return taskCompletionSource.getTask();
236
+ }
237
+
202
238
  public Map<String, Object> getConstantsForApp(String appName) {
203
239
  Map<String, Object> appConstants = new HashMap<>();
204
240
  FirebaseRemoteConfigInfo remoteConfigInfo =
@@ -255,6 +255,20 @@ public class ReactNativeFirebaseConfigModule extends ReactNativeFirebaseModule {
255
255
  }
256
256
  }
257
257
 
258
+ @ReactMethod
259
+ public void setCustomSignals(String appName, ReadableMap customSignals, Promise promise) {
260
+ module
261
+ .setCustomSignals(appName, customSignals.toHashMap())
262
+ .addOnCompleteListener(
263
+ task -> {
264
+ if (task.isSuccessful()) {
265
+ promise.resolve(resultWithConstants(task.getResult()));
266
+ } else {
267
+ rejectPromiseWithExceptionMap(promise, task.getException());
268
+ }
269
+ });
270
+ }
271
+
258
272
  private WritableMap resultWithConstants(Object result) {
259
273
  Map<String, Object> responseMap = new HashMap<>(2);
260
274
  responseMap.put("result", result);
@@ -305,6 +305,24 @@ RCT_EXPORT_METHOD(removeConfigUpdateRegistration : (FIRApp *)firebaseApp) {
305
305
  }
306
306
  }
307
307
 
308
+ RCT_EXPORT_METHOD(setCustomSignals
309
+ : (FIRApp *)firebaseApp
310
+ : (NSDictionary *)customSignals
311
+ : (RCTPromiseResolveBlock)resolve
312
+ : (RCTPromiseRejectBlock)reject) {
313
+ [[FIRRemoteConfig remoteConfigWithApp:firebaseApp]
314
+ setCustomSignals:customSignals
315
+ withCompletion:^(NSError *_Nullable error) {
316
+ if (error != nil) {
317
+ [RNFBSharedUtils rejectPromiseWithNSError:reject error:error];
318
+ } else {
319
+ resolve(nil);
320
+ }
321
+ }];
322
+
323
+ resolve([self resultWithConstants:[NSNull null] firebaseApp:firebaseApp]);
324
+ }
325
+
308
326
  #pragma mark -
309
327
  #pragma mark Internal Helper Methods
310
328
 
@@ -207,3 +207,26 @@ export function onConfigUpdated(
207
207
  remoteConfig: RemoteConfig,
208
208
  callback: (config: ConfigValues) => void,
209
209
  ): () => void;
210
+
211
+ /**
212
+ * Defines the type for representing custom signals and their values.
213
+ * The values in CustomSignals must be one of the following types: string, number, or null.
214
+ * There are additional limitations on key and value length, for a full description see https://firebase.google.com/docs/remote-config/parameters?template_type=client#custom_signal_conditions
215
+ * Failing to stay within these limitations will result in a silent API failure with only a warning in device logs
216
+ */
217
+
218
+ export interface CustomSignals {
219
+ [key: string]: string | number | null;
220
+ }
221
+
222
+ /**
223
+ * Sets the custom signals for the app instance.
224
+ * @param {RemoteConfig} remoteConfig - RemoteConfig instance
225
+ * @param {CustomSignals} customSignals - CustomSignals
226
+ * @returns {Promise<void>}
227
+ */
228
+
229
+ export declare function setCustomSignals(
230
+ remoteConfig: RemoteConfig,
231
+ customSignals: CustomSignals,
232
+ ): Promise<void>;
@@ -26,6 +26,7 @@ import { getApp } from '@react-native-firebase/app';
26
26
  * @typedef {import('..').FirebaseRemoteConfigTypes.ConfigValues} ConfigValues
27
27
  * @typedef {import('..').FirebaseRemoteConfigTypes.LastFetchStatusType} LastFetchStatusType
28
28
  * @typedef {import('..').FirebaseRemoteConfigTypes.RemoteConfigLogLevel} RemoteConfigLogLevel
29
+ * @typedef {import('.').CustomSignals} CustomSignals
29
30
  */
30
31
 
31
32
  /**
@@ -243,3 +244,20 @@ export function setDefaultsFromResource(remoteConfig, resourceName) {
243
244
  export function onConfigUpdated(remoteConfig, callback) {
244
245
  return remoteConfig.onConfigUpdated(callback);
245
246
  }
247
+
248
+ /**
249
+ * Sets the custom signals for the app instance.
250
+ * @param {RemoteConfig} remoteConfig - RemoteConfig instance
251
+ * @param {CustomSignals} customSignals - CustomSignals
252
+ * @returns {Promise<void>}
253
+ */
254
+ export async function setCustomSignals(remoteConfig, customSignals) {
255
+ for (const [key, value] of Object.entries(customSignals)) {
256
+ if (typeof value !== 'string' && typeof value !== 'number' && value !== null) {
257
+ throw new Error(
258
+ `firebase.remoteConfig().setCustomSignals(): Invalid type for custom signal '${key}': ${typeof value}. Expected 'string', 'number', or 'null'.`,
259
+ );
260
+ }
261
+ }
262
+ return remoteConfig._promiseWithConstants(remoteConfig.native.setCustomSignals(customSignals));
263
+ }
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- module.exports = '21.7.4';
2
+ module.exports = '21.8.0';
@@ -7,6 +7,7 @@ import {
7
7
  fetchConfig,
8
8
  getAll,
9
9
  makeIDBAvailable,
10
+ setCustomSignals,
10
11
  } from '@react-native-firebase/app/lib/internal/web/firebaseRemoteConfig';
11
12
  import { guard } from '@react-native-firebase/app/lib/internal/web/utils';
12
13
 
@@ -113,4 +114,11 @@ export default {
113
114
  return resultAndConstants(remoteConfig, null);
114
115
  });
115
116
  },
117
+ setCustomSignals(appName, customSignals) {
118
+ return guard(async () => {
119
+ const remoteConfig = getRemoteConfigInstanceForApp(appName);
120
+ await setCustomSignals(remoteConfig, customSignals);
121
+ return resultAndConstants(remoteConfig, null);
122
+ });
123
+ },
116
124
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-firebase/remote-config",
3
- "version": "21.7.4",
3
+ "version": "21.8.0",
4
4
  "author": "Invertase <oss@invertase.io> (http://invertase.io)",
5
5
  "description": "React Native Firebase - React Native Firebase provides native integration with Remote Config, allowing you to change the appearance and/or functionality of your app without requiring an app update.",
6
6
  "main": "lib/index.js",
@@ -24,11 +24,11 @@
24
24
  "remote-config"
25
25
  ],
26
26
  "peerDependencies": {
27
- "@react-native-firebase/analytics": "21.7.4",
28
- "@react-native-firebase/app": "21.7.4"
27
+ "@react-native-firebase/analytics": "21.8.0",
28
+ "@react-native-firebase/app": "21.8.0"
29
29
  },
30
30
  "publishConfig": {
31
31
  "access": "public"
32
32
  },
33
- "gitHead": "82c4c7391fee6597726e5363d78400f11a644e47"
33
+ "gitHead": "14ebd5c2d2e0f284397c331f909e533c47f2ec62"
34
34
  }
@@ -1,220 +0,0 @@
1
- /*
2
- * Copyright (c) 2016-present Invertase Limited & Contributors
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this library except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- *
16
- */
17
- import { describe, expect, it } from '@jest/globals';
18
-
19
- import {
20
- firebase,
21
- getRemoteConfig,
22
- activate,
23
- ensureInitialized,
24
- fetchAndActivate,
25
- fetchConfig,
26
- getAll,
27
- getBoolean,
28
- getNumber,
29
- getString,
30
- getValue,
31
- setLogLevel,
32
- isSupported,
33
- fetchTimeMillis,
34
- settings,
35
- lastFetchStatus,
36
- reset,
37
- setConfigSettings,
38
- fetch,
39
- setDefaults,
40
- setDefaultsFromResource,
41
- onConfigUpdated,
42
- } from '../lib';
43
-
44
- describe('remoteConfig()', function () {
45
- describe('namespace', function () {
46
- it('accessible from firebase.app()', function () {
47
- const app = firebase.app();
48
- expect(app.remoteConfig()).toBeDefined();
49
- expect(app.remoteConfig().app).toEqual(app);
50
- });
51
-
52
- it('supports multiple apps', async function () {
53
- expect(firebase.remoteConfig().app.name).toEqual('[DEFAULT]');
54
- expect(firebase.app('secondaryFromNative').remoteConfig().app.name).toEqual(
55
- 'secondaryFromNative',
56
- );
57
- });
58
- });
59
-
60
- describe('statics', function () {
61
- it('LastFetchStatus', function () {
62
- expect(firebase.remoteConfig.LastFetchStatus).toBeDefined();
63
- expect(firebase.remoteConfig.LastFetchStatus.FAILURE).toEqual('failure');
64
- expect(firebase.remoteConfig.LastFetchStatus.SUCCESS).toEqual('success');
65
- expect(firebase.remoteConfig.LastFetchStatus.NO_FETCH_YET).toEqual('no_fetch_yet');
66
- expect(firebase.remoteConfig.LastFetchStatus.THROTTLED).toEqual('throttled');
67
- });
68
-
69
- it('ValueSource', function () {
70
- expect(firebase.remoteConfig.ValueSource).toBeDefined();
71
- expect(firebase.remoteConfig.ValueSource.REMOTE).toEqual('remote');
72
- expect(firebase.remoteConfig.ValueSource.STATIC).toEqual('static');
73
- expect(firebase.remoteConfig.ValueSource.DEFAULT).toEqual('default');
74
- });
75
- });
76
-
77
- describe('fetch()', function () {
78
- it('it throws if expiration is not a number', function () {
79
- expect(() => {
80
- // @ts-ignore - incorrect argument on purpose to check validation
81
- firebase.remoteConfig().fetch('foo');
82
- }).toThrow('must be a number value');
83
- });
84
- });
85
-
86
- describe('setConfigSettings()', function () {
87
- it('it throws if arg is not an object', async function () {
88
- expect(() => {
89
- // @ts-ignore - incorrect argument on purpose to check validation
90
- firebase.remoteConfig().setConfigSettings('not an object');
91
- }).toThrow('must set an object');
92
- });
93
-
94
- it('throws if minimumFetchIntervalMillis is not a number', async function () {
95
- expect(() => {
96
- // @ts-ignore - incorrect argument on purpose to check validation
97
- firebase.remoteConfig().setConfigSettings({ minimumFetchIntervalMillis: 'potato' });
98
- }).toThrow('must be a number type in milliseconds.');
99
- });
100
-
101
- it('throws if fetchTimeMillis is not a number', function () {
102
- expect(() => {
103
- // @ts-ignore - incorrect argument on purpose to check validation
104
- firebase.remoteConfig().setConfigSettings({ fetchTimeMillis: 'potato' });
105
- }).toThrow('must be a number type in milliseconds.');
106
- });
107
- });
108
-
109
- describe('setDefaults()', function () {
110
- it('it throws if defaults object not provided', function () {
111
- expect(() => {
112
- // @ts-ignore - incorrect argument on purpose to check validation
113
- firebase.remoteConfig().setDefaults('not an object');
114
- }).toThrow('must be an object.');
115
- });
116
- });
117
-
118
- describe('setDefaultsFromResource()', function () {
119
- it('throws if resourceName is not a string', function () {
120
- expect(() => {
121
- // @ts-ignore - incorrect argument on purpose to check validation
122
- firebase.remoteConfig().setDefaultsFromResource(1337);
123
- }).toThrow('must be a string value');
124
- });
125
- });
126
-
127
- describe('getAll() should not crash', function () {
128
- it('should return an empty object pre-fetch, pre-defaults', function () {
129
- const config = firebase.remoteConfig().getAll();
130
- expect(config).toBeDefined();
131
- expect(config).toEqual({});
132
- });
133
- });
134
-
135
- describe('modular', function () {
136
- it('`getRemoteConfig` function is properly exposed to end user', function () {
137
- expect(getRemoteConfig).toBeDefined();
138
- });
139
-
140
- it('`activate` function is properly exposed to end user', function () {
141
- expect(activate).toBeDefined();
142
- });
143
-
144
- it('`ensureInitialized` function is properly exposed to end user', function () {
145
- expect(ensureInitialized).toBeDefined();
146
- });
147
-
148
- it('`fetchAndActivate` function is properly exposed to end user', function () {
149
- expect(fetchAndActivate).toBeDefined();
150
- });
151
-
152
- it('`fetchConfig` function is properly exposed to end user', function () {
153
- expect(fetchConfig).toBeDefined();
154
- });
155
-
156
- it('`getAll` function is properly exposed to end user', function () {
157
- expect(getAll).toBeDefined();
158
- });
159
-
160
- it('`getBoolean` function is properly exposed to end user', function () {
161
- expect(getBoolean).toBeDefined();
162
- });
163
-
164
- it('`getNumber` function is properly exposed to end user', function () {
165
- expect(getNumber).toBeDefined();
166
- });
167
-
168
- it('`getString` function is properly exposed to end user', function () {
169
- expect(getString).toBeDefined();
170
- });
171
-
172
- it('`getValue` function is properly exposed to end user', function () {
173
- expect(getValue).toBeDefined();
174
- });
175
-
176
- it('`setLogLevel` function is properly exposed to end user', function () {
177
- expect(setLogLevel).toBeDefined();
178
- });
179
-
180
- it('`isSupported` function is properly exposed to end user', function () {
181
- expect(isSupported).toBeDefined();
182
- });
183
-
184
- it('`fetchTimeMillis` function is properly exposed to end user', function () {
185
- expect(fetchTimeMillis).toBeDefined();
186
- });
187
-
188
- it('`settings` function is properly exposed to end user', function () {
189
- expect(settings).toBeDefined();
190
- });
191
-
192
- it('`lastFetchStatus` function is properly exposed to end user', function () {
193
- expect(lastFetchStatus).toBeDefined();
194
- });
195
-
196
- it('`reset` function is properly exposed to end user', function () {
197
- expect(reset).toBeDefined();
198
- });
199
-
200
- it('`setConfigSettings` function is properly exposed to end user', function () {
201
- expect(setConfigSettings).toBeDefined();
202
- });
203
-
204
- it('`fetch` function is properly exposed to end user', function () {
205
- expect(fetch).toBeDefined();
206
- });
207
-
208
- it('`setDefaults` function is properly exposed to end user', function () {
209
- expect(setDefaults).toBeDefined();
210
- });
211
-
212
- it('`setDefaultsFromResource` function is properly exposed to end user', function () {
213
- expect(setDefaultsFromResource).toBeDefined();
214
- });
215
-
216
- it('`onConfigUpdated` function is properly exposed to end user', function () {
217
- expect(onConfigUpdated).toBeDefined();
218
- });
219
- });
220
- });