diff --git a/eslint.config.mjs b/eslint.config.mjs index e0df72a64f..2280ff3b87 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -38,7 +38,7 @@ export default [ '**/type-test.ts', 'packages/**/modular/dist/**/*', 'packages/vertexai/__tests__/test-utils', - 'packages/vertexai/dist', + 'packages/**/dist', ], }, ...compat diff --git a/package.json b/package.json index 00756f8d9f..73ab85e9a6 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "lerna:clean": "lerna clean", "build:all:clean": "lerna run build:clean", "build:all:build": "lerna run build", + "codegen:all": "lerna run codegen", "lint": "yarn lint:js && yarn lint:android && yarn lint:ios:check", "lint:js": "eslint packages/* --max-warnings=0", "lint:android": "(google-java-format --set-exit-if-changed --replace --glob=\"packages/*/android/src/**/*.java\" || (echo \"\n\nandroid formatting error - please re-run\n\n\" && exit 1)) && (git diff --exit-code packages/*/android/src || (echo \"\n\nandroid files changed from linting, please examine and commit result\n\n\" && exit 1))", @@ -69,6 +70,7 @@ "@firebase/rules-unit-testing": "^4.0.1", "@inquirer/prompts": "^7.4.1", "@octokit/core": "^6.1.5", + "@react-native-community/cli": "latest", "@tsconfig/node-lts": "^22.0.1", "@types/react": "^19.0.0", "@types/react-native": "^0.73.0", diff --git a/packages/app/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java b/packages/app/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java index bcb4274a9e..740f119e34 100644 --- a/packages/app/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java +++ b/packages/app/android/src/main/java/io/invertase/firebase/common/UniversalFirebaseModule.java @@ -29,7 +29,7 @@ public class UniversalFirebaseModule { private final Context context; private final String serviceName; - protected UniversalFirebaseModule(Context context, String serviceName) { + public UniversalFirebaseModule(Context context, String serviceName) { this.context = context; this.serviceName = serviceName; this.executorService = new TaskExecutorService(getName()); @@ -43,7 +43,7 @@ public Context getApplicationContext() { return getContext().getApplicationContext(); } - protected ExecutorService getExecutor() { + public ExecutorService getExecutor() { return executorService.getExecutor(); } diff --git a/packages/app/lib/internal/nativeModuleAndroidIos.js b/packages/app/lib/internal/nativeModuleAndroidIos.js index 31a6a2e281..8254e4a91a 100644 --- a/packages/app/lib/internal/nativeModuleAndroidIos.js +++ b/packages/app/lib/internal/nativeModuleAndroidIos.js @@ -1,5 +1,6 @@ /* eslint-disable no-console */ import { NativeModules } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; /** * This is used by Android and iOS to get a native module. @@ -8,7 +9,7 @@ import { NativeModules } from 'react-native'; * @param moduleName */ export function getReactNativeModule(moduleName) { - const nativeModule = NativeModules[moduleName]; + const nativeModule = NativeModules[moduleName] || TurboModuleRegistry.get(moduleName); if (!globalThis.RNFBDebug) { return nativeModule; } diff --git a/packages/app/lib/internal/registry/nativeModule.js b/packages/app/lib/internal/registry/nativeModule.js index 2778b2dd75..ede8e5bc54 100644 --- a/packages/app/lib/internal/registry/nativeModule.js +++ b/packages/app/lib/internal/registry/nativeModule.js @@ -40,7 +40,8 @@ function nativeModuleKey(module) { */ function nativeModuleMethodWrapped(namespace, method, argToPrepend) { return (...args) => { - const possiblePromise = method(...[...argToPrepend, ...args]); + const allArgs = [...argToPrepend, ...args]; + const possiblePromise = method(...allArgs); if (possiblePromise && possiblePromise.then) { const jsStack = new Error().stack; diff --git a/packages/app/lib/modular/index.d.ts b/packages/app/lib/modular/index.d.ts index ec90f4f3d2..ff08406956 100644 --- a/packages/app/lib/modular/index.d.ts +++ b/packages/app/lib/modular/index.d.ts @@ -1,6 +1,8 @@ import { ReactNativeFirebase } from '..'; -import FirebaseApp = ReactNativeFirebase.FirebaseApp; +type FirebaseApp = ReactNativeFirebase.FirebaseApp & { + functions(regionOrCustomDomain?: string): Functions; +}; import FirebaseAppOptions = ReactNativeFirebase.FirebaseAppOptions; import LogLevelString = ReactNativeFirebase.LogLevelString; diff --git a/packages/functions/RNFBFunctions.podspec b/packages/functions/RNFBFunctions.podspec index 16c4118ffc..cb04cec6cb 100644 --- a/packages/functions/RNFBFunctions.podspec +++ b/packages/functions/RNFBFunctions.podspec @@ -27,11 +27,20 @@ Pod::Spec.new do |s| s.ios.deployment_target = firebase_ios_target s.macos.deployment_target = firebase_macos_target s.tvos.deployment_target = firebase_tvos_target - s.source_files = 'ios/**/*.{h,m}' + s.source_files = 'ios/**/*.{h,m,mm,cpp}' + s.exclude_files = 'ios/generated/RCTThirdPartyComponentsProvider.*', 'ios/generated/RCTAppDependencyProvider.*', 'ios/generated/RCTModuleProviders.*', 'ios/generated/RCTModulesConformingToProtocolsProvider.*', 'ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.*' + # Turbo modules require these compiler flags + s.compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1' # React Native dependencies s.dependency 'React-Core' s.dependency 'RNFBApp' + # Turbo module code generated podspecs + s.dependency 'ReactCodegen' + s.dependency 'ReactAppDependencyProvider' + # Turbo modules requires these dependencies + s.dependency 'RCT-Folly' + s.dependency 'React-Fabric' if defined?($FirebaseSDKVersion) Pod::UI.puts "#{s.name}: Using user specified Firebase SDK version '#{$FirebaseSDKVersion}'" diff --git a/packages/functions/__tests__/functions.test.ts b/packages/functions/__tests__/functions.test.ts index 708204b1f7..787ac9a005 100644 --- a/packages/functions/__tests__/functions.test.ts +++ b/packages/functions/__tests__/functions.test.ts @@ -1,6 +1,6 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it, jest } from '@jest/globals'; -import functions, { +import { firebase, getFunctions, connectFunctionsEmulator, @@ -9,12 +9,13 @@ import functions, { HttpsErrorCode, } from '../lib'; +import functions from '../lib/namespaced'; import { createCheckV9Deprecation, - CheckV9DeprecationFunction, + type CheckV9DeprecationFunction, } from '../../app/lib/common/unitTestUtils'; -import { getApp } from '../../app'; +import { getApp } from '@react-native-firebase/app'; // @ts-ignore test import FirebaseModule from '../../app/lib/internal/FirebaseModule'; diff --git a/packages/functions/android/build.gradle b/packages/functions/android/build.gradle index 0c2678a39c..96dd252292 100644 --- a/packages/functions/android/build.gradle +++ b/packages/functions/android/build.gradle @@ -80,9 +80,11 @@ android { } } - sourceSets { + sourceSets { main { java.srcDirs = ['src/main/java', 'src/reactnative/java'] + // Exclude generated JNI files from compilation + java.excludes = ['**/generated/jni/**'] } } } diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/NativeFunctionsModule.java b/packages/functions/android/src/main/java/io/invertase/firebase/functions/NativeFunctionsModule.java new file mode 100644 index 0000000000..6b212f84f6 --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/NativeFunctionsModule.java @@ -0,0 +1,138 @@ +package io.invertase.firebase.functions; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import static io.invertase.firebase.functions.UniversalFirebaseFunctionsModule.CODE_KEY; +import static io.invertase.firebase.functions.UniversalFirebaseFunctionsModule.DATA_KEY; +import static io.invertase.firebase.functions.UniversalFirebaseFunctionsModule.DETAILS_KEY; +import static io.invertase.firebase.functions.UniversalFirebaseFunctionsModule.MSG_KEY; + +import com.facebook.fbreact.specs.NativeFunctionsModuleSpec; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; +import com.google.android.gms.tasks.Task; +import com.google.firebase.functions.FirebaseFunctionsException; +import io.invertase.firebase.common.RCTConvertFirebase; +import io.invertase.firebase.common.UniversalFirebaseModule; +import java.io.IOException; + +public class NativeFunctionsModule extends NativeFunctionsModuleSpec { + private static final String SERVICE_NAME = "Functions"; + private final UniversalFirebaseFunctionsModule module; + private final UniversalFirebaseModule universalFirebaseModule; + + public NativeFunctionsModule(ReactApplicationContext reactContext) { + super(reactContext); + // cannot have multiple inheritance so we make this a property rather than extending it + universalFirebaseModule = new UniversalFirebaseModule(reactContext, SERVICE_NAME); + this.module = new UniversalFirebaseFunctionsModule(reactContext, SERVICE_NAME); + } + + @Override + public void httpsCallable( + String appName, + String region, + String emulatorHost, + double emulatorPort, + String name, + ReadableMap data, + ReadableMap options, + Promise promise) { + + Object callableData = data.toHashMap().get(DATA_KEY); + + // Convert emulatorPort to Integer (null if not using emulator) + Integer port = emulatorHost != null ? (int) emulatorPort : null; + + Task callMethodTask = module.httpsCallable( + appName, region, emulatorHost, port, name, callableData, options); + + // resolve + callMethodTask.addOnSuccessListener( + universalFirebaseModule.getExecutor(), + result -> { + promise.resolve(RCTConvertFirebase.mapPutValue(DATA_KEY, result, Arguments.createMap())); + }); + + // reject + callMethodTask.addOnFailureListener( + universalFirebaseModule.getExecutor(), + exception -> handleFunctionsException(exception, promise)); + } + + @Override + public void httpsCallableFromUrl( + String appName, + String region, + String emulatorHost, + double emulatorPort, + String url, + ReadableMap data, + ReadableMap options, + Promise promise) { + + Object callableData = data.toHashMap().get(DATA_KEY); + + // Convert emulatorPort to Integer (null if not using emulator) + Integer port = emulatorHost != null ? (int) emulatorPort : null; + + Task callMethodTask = module.httpsCallableFromUrl( + appName, region, emulatorHost, port, url, callableData, options); + + callMethodTask.addOnSuccessListener( + universalFirebaseModule.getExecutor(), + result -> { + promise.resolve(RCTConvertFirebase.mapPutValue(DATA_KEY, result, Arguments.createMap())); + }); + + callMethodTask.addOnFailureListener( + universalFirebaseModule.getExecutor(), + exception -> handleFunctionsException(exception, promise)); + } + + private void handleFunctionsException(Exception exception, Promise promise) { + Object details = null; + String code = "UNKNOWN"; + String message = exception.getMessage(); + WritableMap userInfo = Arguments.createMap(); + + if (exception.getCause() != null) { + FirebaseFunctionsException functionsException = + (FirebaseFunctionsException) exception.getCause(); + details = functionsException.getDetails(); + code = functionsException.getCode().name(); + message = functionsException.getMessage(); + String timeout = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); + Boolean isTimeout = code.contains(timeout); + + if (functionsException.getCause() instanceof IOException && !isTimeout) { + // return UNAVAILABLE for network io errors, to match iOS + code = FirebaseFunctionsException.Code.UNAVAILABLE.name(); + message = FirebaseFunctionsException.Code.UNAVAILABLE.name(); + } + } + + RCTConvertFirebase.mapPutValue(CODE_KEY, code, userInfo); + RCTConvertFirebase.mapPutValue(MSG_KEY, message, userInfo); + RCTConvertFirebase.mapPutValue(DETAILS_KEY, details, userInfo); + promise.reject(code, message, exception, userInfo); + } +} diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/NativeFunctionsPackage.java b/packages/functions/android/src/main/java/io/invertase/firebase/functions/NativeFunctionsPackage.java new file mode 100644 index 0000000000..0ee75ec8d5 --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/NativeFunctionsPackage.java @@ -0,0 +1,44 @@ +package io.invertase.firebase.functions; + +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; + +@SuppressWarnings("unused") +public class NativeFunctionsPackage implements ReactPackage { + @Nonnull + @Override + public List createNativeModules(@Nonnull ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + modules.add(new NativeFunctionsModule(reactContext)); + return modules; + } + + @Nonnull + @Override + public List createViewManagers(@Nonnull ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/java/com/facebook/fbreact/specs/NativeFunctionsModuleSpec.java b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/java/com/facebook/fbreact/specs/NativeFunctionsModuleSpec.java new file mode 100644 index 0000000000..96c22330d9 --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/java/com/facebook/fbreact/specs/NativeFunctionsModuleSpec.java @@ -0,0 +1,44 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeFunctionsModuleSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "NativeFunctionsModule"; + + public NativeFunctionsModuleSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void httpsCallable(String appName, String region, @Nullable String emulatorHost, double emulatorPort, String name, ReadableMap data, ReadableMap options, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void httpsCallableFromUrl(String appName, String region, @Nullable String emulatorHost, double emulatorPort, String url, ReadableMap data, ReadableMap options, Promise promise); +} diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt new file mode 100644 index 0000000000..9e890825d5 --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/NativeFunctionsModule/*.cpp) + +add_library( + react_codegen_NativeFunctionsModule + OBJECT + ${react_codegen_SRCS} +) + +target_include_directories(react_codegen_NativeFunctionsModule PUBLIC . react/renderer/components/NativeFunctionsModule) + +target_link_libraries( + react_codegen_NativeFunctionsModule + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_NativeFunctionsModule + PRIVATE + -DLOG_TAG=\"ReactNative\" + -fexceptions + -frtti + -std=c++20 + -Wall +) diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeFunctionsModule-generated.cpp b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeFunctionsModule-generated.cpp new file mode 100644 index 0000000000..777a2b140f --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeFunctionsModule-generated.cpp @@ -0,0 +1,38 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include "NativeFunctionsModule.h" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallable(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "httpsCallable", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +static facebook::jsi::Value __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallableFromUrl(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, PromiseKind, "httpsCallableFromUrl", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId); +} + +NativeFunctionsModuleSpecJSI::NativeFunctionsModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_["httpsCallable"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallable}; + methodMap_["httpsCallableFromUrl"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallableFromUrl}; +} + +std::shared_ptr NativeFunctionsModule_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == "NativeFunctionsModule") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeFunctionsModule.h b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeFunctionsModule.h new file mode 100644 index 0000000000..ba653a7b29 --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/NativeFunctionsModule.h @@ -0,0 +1,31 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeFunctionsModule' + */ +class JSI_EXPORT NativeFunctionsModuleSpecJSI : public JavaTurboModule { +public: + NativeFunctionsModuleSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr NativeFunctionsModule_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeFunctionsModule/NativeFunctionsModuleJSI-generated.cpp b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeFunctionsModule/NativeFunctionsModuleJSI-generated.cpp new file mode 100644 index 0000000000..25ff4262a3 --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeFunctionsModule/NativeFunctionsModuleJSI-generated.cpp @@ -0,0 +1,46 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "NativeFunctionsModuleJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallable(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->httpsCallable( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asString(rt)), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber(), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asString(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallableFromUrl(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->httpsCallableFromUrl( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asString(rt)), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber(), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asString(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt) + ); +} + +NativeFunctionsModuleCxxSpecJSI::NativeFunctionsModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeFunctionsModule", jsInvoker) { + methodMap_["httpsCallable"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallable}; + methodMap_["httpsCallableFromUrl"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallableFromUrl}; +} + + +} // namespace facebook::react diff --git a/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeFunctionsModule/NativeFunctionsModuleJSI.h b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeFunctionsModule/NativeFunctionsModuleJSI.h new file mode 100644 index 0000000000..980da558ac --- /dev/null +++ b/packages/functions/android/src/main/java/io/invertase/firebase/functions/generated/jni/react/renderer/components/NativeFunctionsModule/NativeFunctionsModuleJSI.h @@ -0,0 +1,80 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeFunctionsModuleCxxSpecJSI : public TurboModule { +protected: + NativeFunctionsModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value httpsCallable(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String name, jsi::Object data, jsi::Object options) = 0; + virtual jsi::Value httpsCallableFromUrl(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String url, jsi::Object data, jsi::Object options) = 0; + +}; + +template +class JSI_EXPORT NativeFunctionsModuleCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeFunctionsModule"; + +protected: + NativeFunctionsModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeFunctionsModuleCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeFunctionsModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeFunctionsModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Value httpsCallable(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String name, jsi::Object data, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::httpsCallable) == 8, + "Expected httpsCallable(...) to have 8 parameters"); + + return bridging::callFromJs( + rt, &T::httpsCallable, jsInvoker_, instance_, std::move(appName), std::move(region), std::move(emulatorHost), std::move(emulatorPort), std::move(name), std::move(data), std::move(options)); + } + jsi::Value httpsCallableFromUrl(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String url, jsi::Object data, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::httpsCallableFromUrl) == 8, + "Expected httpsCallableFromUrl(...) to have 8 parameters"); + + return bridging::callFromJs( + rt, &T::httpsCallableFromUrl, jsInvoker_, instance_, std::move(appName), std::move(region), std::move(emulatorHost), std::move(emulatorPort), std::move(url), std::move(data), std::move(options)); + } + + private: + friend class NativeFunctionsModuleCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h index b608e558e3..9fe450c8a9 100644 --- a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h +++ b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.h @@ -16,9 +16,8 @@ */ #import +#import "NativeFunctionsModule.h" -#import - -@interface RNFBFunctionsModule : NSObject +@interface RNFBFunctionsModule : NSObject @end diff --git a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.m b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.mm similarity index 69% rename from packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.m rename to packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.mm index 1f4be2b3dc..5f157e46c6 100644 --- a/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.m +++ b/packages/functions/ios/RNFBFunctions/RNFBFunctionsModule.mm @@ -19,54 +19,67 @@ #import #import "RNFBApp/RNFBSharedUtils.h" +#import "RNFBApp/RCTConvert+FIRApp.h" #import "RNFBFunctionsModule.h" +#import "NativeFunctionsModule.h" + +@interface RNFBFunctionsModule () +@end @implementation RNFBFunctionsModule #pragma mark - #pragma mark Module Setup -RCT_EXPORT_MODULE(); - +RCT_EXPORT_MODULE(NativeFunctionsModule) #pragma mark - #pragma mark Firebase Functions Methods -RCT_EXPORT_METHOD(httpsCallable - : (FIRApp *)firebaseApp customUrlOrRegion - : (NSString *)customUrlOrRegion host - : (NSString *)host port - : (NSNumber *_Nonnull)port name - : (NSString *)name wrapper - : (NSDictionary *)wrapper options - : (NSDictionary *)options resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { + +- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params { + return std::make_shared(params); +} + +- (void)httpsCallable:(NSString *)appName + region:(NSString *)customUrlOrRegion + emulatorHost:(NSString * _Nullable)emulatorHost + emulatorPort:(double)emulatorPort + name:(NSString *)name + data:(JS::NativeFunctionsModule::SpecHttpsCallableData &)data + options:(JS::NativeFunctionsModule::SpecHttpsCallableOptions &)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { NSURL *url = [NSURL URLWithString:customUrlOrRegion]; - FIRFunctions *functions = - (url && url.scheme && url.host) - ? [FIRFunctions functionsForApp:firebaseApp customDomain:customUrlOrRegion] - : [FIRFunctions functionsForApp:firebaseApp region:customUrlOrRegion]; + FIRApp *firebaseApp = [RCTConvert firAppFromString: appName]; - if (host != nil) { - [functions useEmulatorWithHost:host port:[port intValue]]; - } + FIRFunctions *functions = + (url && url.scheme && url.host) + ? [FIRFunctions functionsForApp:firebaseApp customDomain:customUrlOrRegion] + : [FIRFunctions functionsForApp:firebaseApp region:customUrlOrRegion]; - FIRHTTPSCallable *callable = [functions HTTPSCallableWithName:name]; - if (options[@"timeout"]) { - callable.timeoutInterval = [options[@"timeout"] doubleValue]; - } + id callableData = data.data(); // In reality, this value is always null, because we always call it with null data // on the javascript side for some reason. Check for that case (which should be 100% of the time) // and set it to an `NSNull` (versus the `Optional` Swift will see from `valueForKey` so that // FirebaseFunctions serializer won't have a validation failure for an unknown type. - id data = [wrapper valueForKey:@"data"]; - NSLog(@"RNFBFUNCTIONS pulled data from 'wrapper', has type %@", [data class]); - if (data == nil) { - data = [NSNull null]; + if (callableData == nil) { + callableData = [NSNull null]; + } + + std::optional timeout = options.timeout(); + + if (emulatorHost != nil) { + [functions useEmulatorWithHost:emulatorHost port:(int)emulatorPort]; + } + + FIRHTTPSCallable *callable = [functions HTTPSCallableWithName:name]; + + if (timeout.has_value()) { + callable.timeoutInterval = timeout.value(); } - [callable callWithObject:data + [callable callWithObject:callableData completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) { if (error) { NSObject *details = [NSNull null]; @@ -90,44 +103,50 @@ @implementation RNFBFunctionsModule }]; } -RCT_EXPORT_METHOD(httpsCallableFromUrl - : (FIRApp *)firebaseApp customUrlOrRegion - : (NSString *)customUrlOrRegion host - : (NSString *)host port - : (NSNumber *_Nonnull)port url - : (NSString *)url wrapper - : (NSDictionary *)wrapper options - : (NSDictionary *)options resolver - : (RCTPromiseResolveBlock)resolve rejecter - : (RCTPromiseRejectBlock)reject) { +- (void)httpsCallableFromUrl:(NSString *)appName + region:(NSString *)customUrlOrRegion + emulatorHost:(NSString * _Nullable)emulatorHost + emulatorPort:(double)emulatorPort + url:(NSString *)url + data:(JS::NativeFunctionsModule::SpecHttpsCallableFromUrlData &)data + options:(JS::NativeFunctionsModule::SpecHttpsCallableFromUrlOptions &)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + NSURL *customUrl = [NSURL URLWithString:customUrlOrRegion]; + FIRApp *firebaseApp = [RCTConvert firAppFromString: appName]; + FIRFunctions *functions = - (customUrl && customUrl.scheme && customUrl.host) - ? [FIRFunctions functionsForApp:firebaseApp customDomain:customUrlOrRegion] - : [FIRFunctions functionsForApp:firebaseApp region:customUrlOrRegion]; + (customUrl && customUrl.scheme && customUrl.host) + ? [FIRFunctions functionsForApp:firebaseApp customDomain:customUrlOrRegion] + : [FIRFunctions functionsForApp:firebaseApp region:customUrlOrRegion]; + + id callableData = data.data(); - if (host != nil) { - [functions useEmulatorWithHost:host port:[port intValue]]; + // In reality, this value is always null, because we always call it with null data + // on the javascript side for some reason. Check for that case (which should be 100% of the time) + // and set it to an `NSNull` (versus the `Optional` Swift will see from `valueForKey` so that + // FirebaseFunctions serializer won't have a validation failure for an unknown type. + if (callableData == nil) { + callableData = [NSNull null]; } - NSURL *functionUrl = [NSURL URLWithString:url]; + std::optional timeout = options.timeout(); - FIRHTTPSCallable *callable = [functions HTTPSCallableWithURL:functionUrl]; - if (options[@"timeout"]) { - callable.timeoutInterval = [options[@"timeout"] doubleValue]; + if (emulatorHost != nil) { + [functions useEmulatorWithHost:emulatorHost port:(int)emulatorPort]; } - // In reality, this value is always null, because we always call it with null data - // on the javascript side for some reason. Check for that case (which should be 100% of the time) - // and set it to an `NSNull` (versus the `Optional` Swift will see from `valueForKey` so that - // FirebaseFunctions serializer won't have a validation failure for an unknown type. - id data = [wrapper valueForKey:@"data"]; - if (data == nil) { - data = [NSNull null]; + NSURL *functionUrl = [NSURL URLWithString:url]; + + FIRHTTPSCallable *callable = [functions HTTPSCallableWithURL:functionUrl]; + + if (timeout.has_value()) { + callable.timeoutInterval = timeout.value(); } - [callable callWithObject:data + [callable callWithObject:callableData completion:^(FIRHTTPSCallableResult *_Nullable result, NSError *_Nullable error) { if (error) { NSObject *details = [NSNull null]; diff --git a/packages/functions/ios/generated/NativeFunctionsModule/NativeFunctionsModule-generated.mm b/packages/functions/ios/generated/NativeFunctionsModule/NativeFunctionsModule-generated.mm new file mode 100644 index 0000000000..b2e980128e --- /dev/null +++ b/packages/functions/ios/generated/NativeFunctionsModule/NativeFunctionsModule-generated.mm @@ -0,0 +1,71 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import "NativeFunctionsModule.h" + + +@implementation NativeFunctionsModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + +@implementation RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableData) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableData:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableOptions) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableOptions:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableFromUrlData) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableFromUrlData:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +@implementation RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableFromUrlOptions) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableFromUrlOptions:(id)json +{ + return facebook::react::managedPointer(json); +} +@end +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallable(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "httpsCallable", @selector(httpsCallable:region:emulatorHost:emulatorPort:name:data:options:resolve:reject:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallableFromUrl(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, PromiseKind, "httpsCallableFromUrl", @selector(httpsCallableFromUrl:region:emulatorHost:emulatorPort:url:data:options:resolve:reject:), args, count); + } + + NativeFunctionsModuleSpecJSI::NativeFunctionsModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_["httpsCallable"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallable}; + setMethodArgConversionSelector(@"httpsCallable", 5, @"JS_NativeFunctionsModule_SpecHttpsCallableData:"); + setMethodArgConversionSelector(@"httpsCallable", 6, @"JS_NativeFunctionsModule_SpecHttpsCallableOptions:"); + + methodMap_["httpsCallableFromUrl"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleSpecJSI_httpsCallableFromUrl}; + setMethodArgConversionSelector(@"httpsCallableFromUrl", 5, @"JS_NativeFunctionsModule_SpecHttpsCallableFromUrlData:"); + setMethodArgConversionSelector(@"httpsCallableFromUrl", 6, @"JS_NativeFunctionsModule_SpecHttpsCallableFromUrlOptions:"); + } +} // namespace facebook::react diff --git a/packages/functions/ios/generated/NativeFunctionsModule/NativeFunctionsModule.h b/packages/functions/ios/generated/NativeFunctionsModule/NativeFunctionsModule.h new file mode 100644 index 0000000000..9173dd8735 --- /dev/null +++ b/packages/functions/ios/generated/NativeFunctionsModule/NativeFunctionsModule.h @@ -0,0 +1,157 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of NativeFunctionsModule symbols +#ifndef NativeFunctionsModule_H +#define NativeFunctionsModule_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +NS_ASSUME_NONNULL_BEGIN +namespace JS { + namespace NativeFunctionsModule { + struct SpecHttpsCallableData { + id data() const; + + SpecHttpsCallableData(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableData) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableData:(id)json; +@end +namespace JS { + namespace NativeFunctionsModule { + struct SpecHttpsCallableOptions { + std::optional timeout() const; + + SpecHttpsCallableOptions(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableOptions) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableOptions:(id)json; +@end +namespace JS { + namespace NativeFunctionsModule { + struct SpecHttpsCallableFromUrlData { + id data() const; + + SpecHttpsCallableFromUrlData(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableFromUrlData) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableFromUrlData:(id)json; +@end +namespace JS { + namespace NativeFunctionsModule { + struct SpecHttpsCallableFromUrlOptions { + std::optional timeout() const; + + SpecHttpsCallableFromUrlOptions(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeFunctionsModule_SpecHttpsCallableFromUrlOptions) ++ (RCTManagedPointer *)JS_NativeFunctionsModule_SpecHttpsCallableFromUrlOptions:(id)json; +@end +@protocol NativeFunctionsModuleSpec + +- (void)httpsCallable:(NSString *)appName + region:(NSString *)region + emulatorHost:(NSString * _Nullable)emulatorHost + emulatorPort:(double)emulatorPort + name:(NSString *)name + data:(JS::NativeFunctionsModule::SpecHttpsCallableData &)data + options:(JS::NativeFunctionsModule::SpecHttpsCallableOptions &)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; +- (void)httpsCallableFromUrl:(NSString *)appName + region:(NSString *)region + emulatorHost:(NSString * _Nullable)emulatorHost + emulatorPort:(double)emulatorPort + url:(NSString *)url + data:(JS::NativeFunctionsModule::SpecHttpsCallableFromUrlData &)data + options:(JS::NativeFunctionsModule::SpecHttpsCallableFromUrlOptions &)options + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + +@end + +@interface NativeFunctionsModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeFunctionsModule' + */ + class JSI_EXPORT NativeFunctionsModuleSpecJSI : public ObjCTurboModule { + public: + NativeFunctionsModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react +inline id JS::NativeFunctionsModule::SpecHttpsCallableData::data() const +{ + id const p = _v[@"data"]; + return p; +} +inline std::optional JS::NativeFunctionsModule::SpecHttpsCallableOptions::timeout() const +{ + id const p = _v[@"timeout"]; + return RCTBridgingToOptionalDouble(p); +} +inline id JS::NativeFunctionsModule::SpecHttpsCallableFromUrlData::data() const +{ + id const p = _v[@"data"]; + return p; +} +inline std::optional JS::NativeFunctionsModule::SpecHttpsCallableFromUrlOptions::timeout() const +{ + id const p = _v[@"timeout"]; + return RCTBridgingToOptionalDouble(p); +} +NS_ASSUME_NONNULL_END +#endif // NativeFunctionsModule_H diff --git a/packages/functions/ios/generated/NativeFunctionsModuleJSI-generated.cpp b/packages/functions/ios/generated/NativeFunctionsModuleJSI-generated.cpp new file mode 100644 index 0000000000..25ff4262a3 --- /dev/null +++ b/packages/functions/ios/generated/NativeFunctionsModuleJSI-generated.cpp @@ -0,0 +1,46 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include "NativeFunctionsModuleJSI.h" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallable(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->httpsCallable( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asString(rt)), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber(), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asString(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt) + ); +} +static jsi::Value __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallableFromUrl(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->httpsCallableFromUrl( + rt, + count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt), + count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt), + count <= 2 || args[2].isNull() || args[2].isUndefined() ? std::nullopt : std::make_optional(args[2].asString(rt)), + count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asNumber(), + count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asString(rt), + count <= 5 ? throw jsi::JSError(rt, "Expected argument in position 5 to be passed") : args[5].asObject(rt), + count <= 6 ? throw jsi::JSError(rt, "Expected argument in position 6 to be passed") : args[6].asObject(rt) + ); +} + +NativeFunctionsModuleCxxSpecJSI::NativeFunctionsModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule("NativeFunctionsModule", jsInvoker) { + methodMap_["httpsCallable"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallable}; + methodMap_["httpsCallableFromUrl"] = MethodMetadata {7, __hostFunction_NativeFunctionsModuleCxxSpecJSI_httpsCallableFromUrl}; +} + + +} // namespace facebook::react diff --git a/packages/functions/ios/generated/NativeFunctionsModuleJSI.h b/packages/functions/ios/generated/NativeFunctionsModuleJSI.h new file mode 100644 index 0000000000..980da558ac --- /dev/null +++ b/packages/functions/ios/generated/NativeFunctionsModuleJSI.h @@ -0,0 +1,80 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + class JSI_EXPORT NativeFunctionsModuleCxxSpecJSI : public TurboModule { +protected: + NativeFunctionsModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value httpsCallable(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String name, jsi::Object data, jsi::Object options) = 0; + virtual jsi::Value httpsCallableFromUrl(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String url, jsi::Object data, jsi::Object options) = 0; + +}; + +template +class JSI_EXPORT NativeFunctionsModuleCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = "NativeFunctionsModule"; + +protected: + NativeFunctionsModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeFunctionsModuleCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeFunctionsModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeFunctionsModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Value httpsCallable(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String name, jsi::Object data, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::httpsCallable) == 8, + "Expected httpsCallable(...) to have 8 parameters"); + + return bridging::callFromJs( + rt, &T::httpsCallable, jsInvoker_, instance_, std::move(appName), std::move(region), std::move(emulatorHost), std::move(emulatorPort), std::move(name), std::move(data), std::move(options)); + } + jsi::Value httpsCallableFromUrl(jsi::Runtime &rt, jsi::String appName, jsi::String region, std::optional emulatorHost, double emulatorPort, jsi::String url, jsi::Object data, jsi::Object options) override { + static_assert( + bridging::getParameterCount(&T::httpsCallableFromUrl) == 8, + "Expected httpsCallableFromUrl(...) to have 8 parameters"); + + return bridging::callFromJs( + rt, &T::httpsCallableFromUrl, jsInvoker_, instance_, std::move(appName), std::move(region), std::move(emulatorHost), std::move(emulatorPort), std::move(url), std::move(data), std::move(options)); + } + + private: + friend class NativeFunctionsModuleCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react diff --git a/packages/functions/ios/generated/RCTAppDependencyProvider.h b/packages/functions/ios/generated/RCTAppDependencyProvider.h new file mode 100644 index 0000000000..5a1502d16f --- /dev/null +++ b/packages/functions/ios/generated/RCTAppDependencyProvider.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + +#import + +#if __has_include() +#import +#elif __has_include() +#import +#else +#import "RCTDependencyProvider.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTAppDependencyProvider : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/functions/ios/generated/RCTAppDependencyProvider.mm b/packages/functions/ios/generated/RCTAppDependencyProvider.mm new file mode 100644 index 0000000000..b76c468c8a --- /dev/null +++ b/packages/functions/ios/generated/RCTAppDependencyProvider.mm @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTAppDependencyProvider.h" +#import +#import +#import +#import + +@implementation RCTAppDependencyProvider + +- (nonnull NSArray *)URLRequestHandlerClassNames { + return RCTModulesConformingToProtocolsProvider.URLRequestHandlerClassNames; +} + +- (nonnull NSArray *)imageDataDecoderClassNames { + return RCTModulesConformingToProtocolsProvider.imageDataDecoderClassNames; +} + +- (nonnull NSArray *)imageURLLoaderClassNames { + return RCTModulesConformingToProtocolsProvider.imageURLLoaderClassNames; +} + +- (nonnull NSArray *)unstableModulesRequiringMainQueueSetup { + return RCTUnstableModulesRequiringMainQueueSetupProvider.modules; +} + +- (nonnull NSDictionary> *)thirdPartyFabricComponents { + return RCTThirdPartyComponentsProvider.thirdPartyFabricComponents; +} + +- (nonnull NSDictionary> *)moduleProviders { + return RCTModuleProviders.moduleProviders; +} + +@end diff --git a/packages/functions/ios/generated/RCTModuleProviders.h b/packages/functions/ios/generated/RCTModuleProviders.h new file mode 100644 index 0000000000..aff637c692 --- /dev/null +++ b/packages/functions/ios/generated/RCTModuleProviders.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@protocol RCTModuleProvider; + +@interface RCTModuleProviders: NSObject + ++ (NSDictionary> *)moduleProviders; + +@end diff --git a/packages/functions/ios/generated/RCTModuleProviders.mm b/packages/functions/ios/generated/RCTModuleProviders.mm new file mode 100644 index 0000000000..aeaf17cbe1 --- /dev/null +++ b/packages/functions/ios/generated/RCTModuleProviders.mm @@ -0,0 +1,51 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "RCTModuleProviders.h" +#import +#import + +@implementation RCTModuleProviders + ++ (NSDictionary> *)moduleProviders +{ + static NSDictionary> *providers = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + NSDictionary * moduleMapping = @{ + @"NativeFunctionsModule": @"RNFBFunctionsModule", // @react-native-firebase/functions + }; + + NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:moduleMapping.count]; + + for (NSString *key in moduleMapping) { + NSString * moduleProviderName = moduleMapping[key]; + Class klass = NSClassFromString(moduleProviderName); + if (!klass) { + RCTLogError(@"Module provider %@ cannot be found in the runtime", moduleProviderName); + continue; + } + + id instance = [klass new]; + if (![instance respondsToSelector:@selector(getTurboModule:)]) { + RCTLogError(@"Module provider %@ does not conform to RCTModuleProvider", moduleProviderName); + continue; + } + + [dict setObject:instance forKey:key]; + } + + providers = dict; + }); + + return providers; +} + +@end diff --git a/packages/functions/ios/generated/RCTModulesConformingToProtocolsProvider.h b/packages/functions/ios/generated/RCTModulesConformingToProtocolsProvider.h new file mode 100644 index 0000000000..10eb848917 --- /dev/null +++ b/packages/functions/ios/generated/RCTModulesConformingToProtocolsProvider.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface RCTModulesConformingToProtocolsProvider: NSObject + ++(NSArray *)imageURLLoaderClassNames; + ++(NSArray *)imageDataDecoderClassNames; + ++(NSArray *)URLRequestHandlerClassNames; + +@end diff --git a/packages/functions/ios/generated/RCTModulesConformingToProtocolsProvider.mm b/packages/functions/ios/generated/RCTModulesConformingToProtocolsProvider.mm new file mode 100644 index 0000000000..a5ff82810e --- /dev/null +++ b/packages/functions/ios/generated/RCTModulesConformingToProtocolsProvider.mm @@ -0,0 +1,54 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTModulesConformingToProtocolsProvider.h" + +@implementation RCTModulesConformingToProtocolsProvider + ++(NSArray *)imageURLLoaderClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + + ]; + }); + + return classNames; +} + ++(NSArray *)imageDataDecoderClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + + ]; + }); + + return classNames; +} + ++(NSArray *)URLRequestHandlerClassNames +{ + static NSArray *classNames = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + classNames = @[ + + ]; + }); + + return classNames; +} + +@end diff --git a/packages/functions/ios/generated/RCTThirdPartyComponentsProvider.h b/packages/functions/ios/generated/RCTThirdPartyComponentsProvider.h new file mode 100644 index 0000000000..ab1a249de3 --- /dev/null +++ b/packages/functions/ios/generated/RCTThirdPartyComponentsProvider.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@protocol RCTComponentViewProtocol; + +@interface RCTThirdPartyComponentsProvider: NSObject + ++ (NSDictionary> *)thirdPartyFabricComponents; + +@end diff --git a/packages/functions/ios/generated/RCTThirdPartyComponentsProvider.mm b/packages/functions/ios/generated/RCTThirdPartyComponentsProvider.mm new file mode 100644 index 0000000000..4e05532c39 --- /dev/null +++ b/packages/functions/ios/generated/RCTThirdPartyComponentsProvider.mm @@ -0,0 +1,30 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + +#import + +#import "RCTThirdPartyComponentsProvider.h" +#import + +@implementation RCTThirdPartyComponentsProvider + ++ (NSDictionary> *)thirdPartyFabricComponents +{ + static NSDictionary> *thirdPartyComponents = nil; + static dispatch_once_t nativeComponentsToken; + + dispatch_once(&nativeComponentsToken, ^{ + thirdPartyComponents = @{ + + }; + }); + + return thirdPartyComponents; +} + +@end diff --git a/packages/functions/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.h b/packages/functions/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.h new file mode 100644 index 0000000000..114d32253a --- /dev/null +++ b/packages/functions/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface RCTUnstableModulesRequiringMainQueueSetupProvider: NSObject + ++(NSArray *)modules; + +@end diff --git a/packages/functions/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.mm b/packages/functions/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.mm new file mode 100644 index 0000000000..9cc59ed7e3 --- /dev/null +++ b/packages/functions/ios/generated/RCTUnstableModulesRequiringMainQueueSetupProvider.mm @@ -0,0 +1,19 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTUnstableModulesRequiringMainQueueSetupProvider.h" + +@implementation RCTUnstableModulesRequiringMainQueueSetupProvider + ++(NSArray *)modules +{ + return @[ + + ]; +} + +@end diff --git a/packages/functions/ios/generated/ReactAppDependencyProvider.podspec b/packages/functions/ios/generated/ReactAppDependencyProvider.podspec new file mode 100644 index 0000000000..c80e01dae7 --- /dev/null +++ b/packages/functions/ios/generated/ReactAppDependencyProvider.podspec @@ -0,0 +1,34 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +version = "0.80.1" +source = { :git => 'https://github.com/facebook/react-native.git' } +if version == '1000.0.0' + # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. + source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") +else + source[:tag] = "v#{version}" +end + +Pod::Spec.new do |s| + s.name = "ReactAppDependencyProvider" + s.version = version + s.summary = "The third party dependency provider for the app" + s.homepage = "https://reactnative.dev/" + s.documentation_url = "https://reactnative.dev/" + s.license = "MIT" + s.author = "Meta Platforms, Inc. and its affiliates" + s.platforms = min_supported_versions + s.source = source + s.source_files = "**/RCTAppDependencyProvider.{h,mm}" + + # This guard prevent to install the dependencies when we run `pod install` in the old architecture. + s.pod_target_xcconfig = { + "CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(), + "DEFINES_MODULE" => "YES" + } + + s.dependency "ReactCodegen" +end diff --git a/packages/functions/ios/generated/ReactCodegen.podspec b/packages/functions/ios/generated/ReactCodegen.podspec new file mode 100644 index 0000000000..226793691e --- /dev/null +++ b/packages/functions/ios/generated/ReactCodegen.podspec @@ -0,0 +1,106 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +version = "0.80.1" +source = { :git => 'https://github.com/facebook/react-native.git' } +if version == '1000.0.0' + # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. + source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") +else + source[:tag] = "v#{version}" +end + +use_frameworks = ENV['USE_FRAMEWORKS'] != nil +folly_compiler_flags = Helpers::Constants.folly_config[:compiler_flags] +boost_compiler_flags = Helpers::Constants.boost_config[:compiler_flags] + +header_search_paths = [ + "\"$(PODS_ROOT)/ReactNativeDependencies\"", + "\"${PODS_ROOT}/Headers/Public/ReactCodegen/react/renderer/components\"", + "\"$(PODS_ROOT)/Headers/Private/React-Fabric\"", + "\"$(PODS_ROOT)/Headers/Private/React-RCTFabric\"", + "\"$(PODS_ROOT)/Headers/Private/Yoga\"", + "\"$(PODS_TARGET_SRCROOT)\"", +] +framework_search_paths = [] + +if use_frameworks + ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-Fabric", "React_Fabric", ["react/renderer/components/view/platform/cxx"]) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-FabricImage", "React_FabricImage", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-graphics", "React_graphics", ["react/renderer/graphics/platform/ios"])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "ReactCommon", "ReactCommon", ["react/nativemodule/core"])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-NativeModulesApple", "React_NativeModulesApple", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-RCTFabric", "RCTFabric", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-debug", "React_debug", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-rendererdebug", "React_rendererdebug", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-utils", "React_utils", [])) + .concat(ReactNativePodsUtils.create_header_search_path_for_frameworks("PODS_CONFIGURATION_BUILD_DIR", "React-featureflags", "React_featureflags", [])) + .each { |search_path| + header_search_paths << "\"#{search_path}\"" + } +end + +Pod::Spec.new do |s| + s.name = "ReactCodegen" + s.version = version + s.summary = 'Temp pod for generated files for React Native' + s.homepage = 'https://facebook.com/' + s.license = 'Unlicense' + s.authors = 'Facebook' + s.compiler_flags = "#{folly_compiler_flags} #{boost_compiler_flags} -Wno-nullability-completeness -std=c++20" + s.source = { :git => '' } + s.header_mappings_dir = './' + s.platforms = min_supported_versions + s.source_files = "**/*.{h,mm,cpp}" + s.exclude_files = "RCTAppDependencyProvider.{h,mm}" # these files are generated in the same codegen path but needs to belong to a different pod + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => header_search_paths.join(' '), + "FRAMEWORK_SEARCH_PATHS" => framework_search_paths, + "OTHER_CPLUSPLUSFLAGS" => "$(inherited) #{folly_compiler_flags} #{boost_compiler_flags}" + } + + s.dependency "React-jsiexecutor" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "React-Core" + s.dependency "React-jsi" + s.dependency "ReactCommon/turbomodule/bridging" + s.dependency "ReactCommon/turbomodule/core" + s.dependency "React-NativeModulesApple" + s.dependency 'React-graphics' + s.dependency 'React-rendererdebug' + s.dependency 'React-Fabric' + s.dependency 'React-FabricImage' + s.dependency 'React-debug' + s.dependency 'React-utils' + s.dependency 'React-featureflags' + s.dependency 'React-RCTAppDelegate' + + depend_on_js_engine(s) + add_rn_third_party_dependencies(s) + + s.script_phases = { + 'name' => 'Generate Specs', + 'execution_position' => :before_compile, + 'input_files' => ["${PODS_ROOT}/../../specs/NativeFunctionsModule.ts"], + 'show_env_vars_in_log' => true, + 'output_files' => ["${DERIVED_FILE_DIR}/react-codegen.log"], + 'script': <<-SCRIPT +pushd "$PODS_ROOT/../" > /dev/null +RCT_SCRIPT_POD_INSTALLATION_ROOT=$(pwd) +popd >/dev/null + +export RCT_SCRIPT_RN_DIR="$RCT_SCRIPT_POD_INSTALLATION_ROOT/../../node_modules/react-native" +export RCT_SCRIPT_APP_PATH="$RCT_SCRIPT_POD_INSTALLATION_ROOT/../.." +export RCT_SCRIPT_OUTPUT_DIR="$RCT_SCRIPT_POD_INSTALLATION_ROOT" +export RCT_SCRIPT_TYPE="withCodegenDiscovery" + +SCRIPT_PHASES_SCRIPT="$RCT_SCRIPT_RN_DIR/scripts/react_native_pods_utils/script_phases.sh" +WITH_ENVIRONMENT="$RCT_SCRIPT_RN_DIR/scripts/xcode/with-environment.sh" +/bin/sh -c "$WITH_ENVIRONMENT $SCRIPT_PHASES_SCRIPT" +SCRIPT + } + +end diff --git a/packages/functions/lib/HttpsError.js b/packages/functions/lib/HttpsError.ts similarity index 67% rename from packages/functions/lib/HttpsError.js rename to packages/functions/lib/HttpsError.ts index 3c4a6e59d0..5f5cd392dd 100644 --- a/packages/functions/lib/HttpsError.js +++ b/packages/functions/lib/HttpsError.ts @@ -17,8 +17,26 @@ import { NativeFirebaseError } from '@react-native-firebase/app/lib/internal'; -export default class HttpsError extends Error { - constructor(code, message, details, nativeErrorInstance) { +export interface NativeError { + userInfo?: { + code?: string; + message?: string; + details?: Record; + }; + jsStack?: string; + message?: string; +} +export class HttpsError extends Error { + readonly code!: string; + readonly details!: Record | null; + readonly message!: string; + + constructor( + code: string, + message?: string, + details?: Record | null, + nativeErrorInstance?: NativeError, + ) { super(message); Object.defineProperty(this, 'code', { @@ -37,8 +55,8 @@ export default class HttpsError extends Error { }); this.stack = NativeFirebaseError.getStackWithMessage( - `Error: ${this.message}`, - nativeErrorInstance.jsStack, + `Error: ${message}`, + nativeErrorInstance?.jsStack, ); } } diff --git a/packages/functions/lib/index.d.ts b/packages/functions/lib/index.d.ts deleted file mode 100644 index cfa7323fba..0000000000 --- a/packages/functions/lib/index.d.ts +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2016-present Invertase Limited & Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this library except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { ReactNativeFirebase } from '@react-native-firebase/app'; - -/** - * Firebase Cloud Functions package for React Native. - * - * #### Example 1 - * - * Access the firebase export from the `functions` package: - * - * ```js - * import { firebase } from '@react-native-firebase/functions'; - * - * // firebase.functions().X - * ``` - * - * #### Example 2 - * - * Using the default export from the `functions` package: - * - * ```js - * import functions from '@react-native-firebase/functions'; - * - * // functions().X - * ``` - * - * #### Example 3 - * - * Using the default export from the `app` package: - * - * ```js - * import firebase from '@react-native-firebase/app'; - * import '@react-native-firebase/functions'; - * - * // firebase.functions().X - * ``` - * - * @firebase functions - */ -export namespace FirebaseFunctionsTypes { - /** - * The set of Firebase Functions status codes. - * - * The codes are the same at the ones exposed by [gRPC](https://github.com/grpc/grpc/blob/master/doc/statuscodes.md). - * - * Possible values: - * - `cancelled`: The operation was cancelled (typically by the caller). - * - `unknown`: Unknown error or an error from a different error domain. - * - `invalid-argument`: Client specified an invalid argument. Note that this - * differs from `failed-precondition`. `invalid-argument` indicates - * arguments that are problematic regardless of the state of the system - * (e.g. an invalid field name). - * - `deadline-exceeded`: Deadline expired before operation could complete. - * For operations that change the state of the system, this error may be - * returned even if the operation has completed successfully. For example, - * a successful response from a server could have been delayed long enough - * for the deadline to expire. - * - `not-found`: Some requested document was not found. - * - `already-exists`: Some document that we attempted to create already - * exists. - * - `permission-denied`: The caller does not have permission to execute the - * specified operation. - * - `resource-exhausted`: Some resource has been exhausted, perhaps a - * per-user quota, or perhaps the entire file system is out of space. - * - `failed-precondition`: Operation was rejected because the system is not - * in a state required for the operation's execution. - * - `aborted`: The operation was aborted, typically due to a concurrency - * issue like transaction aborts, etc. - * - `out-of-range`: Operation was attempted past the valid range. - * - `unimplemented`: Operation is not implemented or not supported/enabled. - * - `internal`: Internal errors. Means some invariants expected by - * underlying system has been broken. If you see one of these errors, - * something is very broken. - * - `unavailable`: The service is currently unavailable. This is most likely - * a transient condition and may be corrected by retrying with a backoff. - * - `data-loss`: Unrecoverable data loss or corruption. - * - `unauthenticated`: The request does not have valid authentication - * credentials for the operation. - */ - import FirebaseModule = ReactNativeFirebase.FirebaseModule; - - export type FunctionsErrorCode = - | 'ok' - | 'cancelled' - | 'unknown' - | 'invalid-argument' - | 'deadline-exceeded' - | 'not-found' - | 'already-exists' - | 'permission-denied' - | 'resource-exhausted' - | 'failed-precondition' - | 'aborted' - | 'out-of-range' - | 'unimplemented' - | 'internal' - | 'unavailable' - | 'data-loss' - | 'unauthenticated'; - - /** - * An HttpsCallableResult wraps a single result from a function call. - */ - export interface HttpsCallableResult { - readonly data: ResponseData; - } - - /** - * An HttpsCallable is a reference to a "callable" http trigger in - * Google Cloud Functions. - * - * #### Example - * - * ```js - * // Create an HttpsCallable reference - * const reference = firebase.functions().httpsCallable('order'); - * - * try { - * const response = await reference({ - * id: '12345', - * }); - * } catch (e) { - * console.error(e); - * } - * ``` - */ - export interface HttpsCallable { - (data?: RequestData | null): Promise>; - } - - /** - * An interface for metadata about how calls should be executed. An instance of HttpsCallableOptions can be passed as the second argument to `firebase.functions().httpsCallable(name, httpsCallableOptions)`. - **/ - export interface HttpsCallableOptions { - /** - * The timeout property is the time in milliseconds after which to cancel if there is no response. Default is 70000. - * - * #### Example - * - *```js - * // The below will wait 7 seconds for a response from the cloud function before an error is thrown. - * try { - * const instance = firebase.functions().httpsCallable('order', { timeout: 7000 }); - * const response = await instance({ - * id: '12345', - * }); - * } catch (e) { - * console.log(e); - * } - * ``` - */ - timeout?: number; - } - - /** - * An HttpsError wraps a single error from a function call. - * - * #### Example - * - * ```js - * try { - * await firebase.functions().httpsCallable('order')(); - * } catch (httpsError) { - * console.log('Message', httpsError.message); - * - * // Check code - * if (httpsError.code === firebase.functions.HttpsErrorCode.NOT_FOUND) { - * console.error('Functions endpoint "order" not found'); - * } - * } - * ``` - */ - export interface HttpsError extends Error { - /** - * A standard error code that will be returned to the client. This also - * determines the HTTP status code of the response, as defined in code.proto. - * - * #### Example - * - * ```js - * try { - * await firebase.functions().httpsCallable('order')(); - * } catch (httpsError) { - * console.error(httpsError.code); - * } - * ``` - */ - readonly code: FunctionsErrorCode; - /** - * Extra data to be converted to JSON and included in the error response. - * - * ```js - * try { - * await firebase.functions().httpsCallable('order')(); - * } catch (httpsError) { - * if (httpsError.details) { - * console.error(httpsError.details); - * } - * } - * ``` - */ - readonly details?: any; - } - - /** - * The HttpsErrorCode interface provides access to all FunctionsErrorCode - * type aliases. - * - * #### Example - * - * ```js - * try { - * await firebase.functions().httpsCallable('order')(); - * } catch (httpsError) { - * switch(httpsError.code) { - * case firebase.functions.HttpsErrorCode.NOT_FOUND: - * console.error('Functions endpoint not found'); - * break; - * case firebase.functions.HttpsErrorCode.CANCELLED: - * console.error('The operation was cancelled'); - * break; - * default: - * console.error('An error occurred'); - * break; - * } - * } - * ``` - */ - export interface HttpsErrorCode { - OK: 'ok'; - CANCELLED: 'cancelled'; - UNKNOWN: 'unknown'; - INVALID_ARGUMENT: 'invalid-argument'; - DEADLINE_EXCEEDED: 'deadline-exceeded'; - NOT_FOUND: 'not-found'; - ALREADY_EXISTS: 'already-exists'; - PERMISSION_DENIED: 'permission-denied'; - UNAUTHENTICATED: 'unauthenticated'; - RESOURCE_EXHAUSTED: 'resource-exhausted'; - FAILED_PRECONDITION: 'failed-precondition'; - ABORTED: 'aborted'; - OUT_OF_RANGE: 'out-of-range'; - UNIMPLEMENTED: 'unimplemented'; - INTERNAL: 'internal'; - UNAVAILABLE: 'unavailable'; - DATA_LOSS: 'data-loss'; - } - - /** - * firebase.functions.X - */ - export interface Statics { - /** - * Uppercase + underscored variables of {@link functions.FunctionsErrorCode} - * - * #### Example - * - * ```js - * firebase.functions.HttpsErrorCode.OK; - * firebase.functions.HttpsErrorCode.NOT_FOUND; - * ``` - */ - HttpsErrorCode: HttpsErrorCode; - } - - /** - * The Firebase Cloud Functions service is available for the default app, a given app or a specified region. - * - * > The default functions region for all apps is `us-central1`. - * - * #### Example 1 - * - * Get the functions instance for the **default app**: - * - * ```js - * const functionsForDefaultApp = firebase.functions(); - * ``` - * - * #### Example 2 - * - * Get the functions instance for a **secondary app**: - * - * ```js - * const otherApp = firebase.app('otherApp'); - * const functionsForOtherApp = firebase.functions(otherApp); - * ``` - * - * #### Example 3 - * - * Get the functions instance for a **specific functions region**: - * - * ```js - * const defaultApp = firebase.app(); - * const functionsForRegion = defaultApp.functions('europe-west1'); - * - * const otherApp = firebase.app('otherApp'); - * const functionsForOtherAppRegion = otherApp.functions('europe-west1'); - * ``` - * - */ - export class Module extends FirebaseModule { - /** - * Returns a reference to the callable HTTPS trigger with the given name. - * - * #### Example - * - * ```js - * const reference = firebase.functions().httpsCallable('order'); - * - * try { - * const response = await reference({ - * id: '12345', - * }); - * } catch (e) { - * console.error(e); - * } - * ``` - * - * @param name The name of the https callable function. - * @return The `HttpsCallable` reference. - */ - httpsCallable( - name: string, - options?: HttpsCallableOptions, - ): HttpsCallable; - - /** - * Returns a reference to the callable HTTPS trigger with the specified url. - * - * #### Example - * - * ```js - * const reference = firebase.functions().httpsCallable('order'); - * - * try { - * const response = await reference({ - * id: '12345', - * }); - * } catch (e) { - * console.error(e); - * } - * ``` - * - * @param name The name of the https callable function. - * @return The `HttpsCallable` reference. - */ - httpsCallableFromUrl( - url: string, - options?: HttpsCallableOptions, - ): HttpsCallable; - - /** - * Changes this instance to point to a Cloud Functions emulator running locally. - * - * See https://firebase.google.com/docs/functions/local-emulator - * - * #### Example - * - * ```js - * if (__DEV__) { - * firebase.functions().useFunctionsEmulator('http://localhost:5001'); - * } - * ``` - * - * Note: on android, hosts 'localhost' and '127.0.0.1' are automatically remapped to '10.0.2.2' (the - * "host" computer IP address for android emulators) to make the standard development experience easy. - * If you want to use the emulator on a real android device, you will need to specify the actual host - * computer IP address. - * - * @deprecated prefer useEmulator instead - * @param origin url of the local emulator started via firebase tools "http://localhost:5001" - */ - useFunctionsEmulator(origin: string): void; - - /** - * Changes this instance to point to a Cloud Functions emulator running locally. - * - * See https://firebase.google.com/docs/functions/local-emulator - * - * #### Example - * - * ```js - * if (__DEV__) { - * firebase.functions().useEmulator('localhost', 5001); - * } - * ``` - * - * Note: on android, hosts 'localhost' and '127.0.0.1' are automatically remapped to '10.0.2.2' (the - * "host" computer IP address for android emulators) to make the standard development experience easy. - * If you want to use the emulator on a real android device, you will need to specify the actual host - * computer IP address. - * - * @param host hostname of the local emulator started via firebase tools, ex. "localhost" - * @param port port of the local emulator started via firebase tools, ex. 5001 - */ - useEmulator(host: string, port: number): void; - } -} - -declare const defaultExport: ReactNativeFirebase.FirebaseModuleWithStaticsAndApp< - FirebaseFunctionsTypes.Module, - FirebaseFunctionsTypes.Statics ->; - -export const firebase: ReactNativeFirebase.Module & { - functions: typeof defaultExport; - app( - name?: string, - ): ReactNativeFirebase.FirebaseApp & { functions(): FirebaseFunctionsTypes.Module }; -}; - -export default defaultExport; - -export * from './modular'; - -/** - * Attach namespace to `firebase.` and `FirebaseApp.`. - */ -declare module '@react-native-firebase/app' { - namespace ReactNativeFirebase { - import FirebaseModuleWithStaticsAndApp = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp; - interface Module { - functions: FirebaseModuleWithStaticsAndApp< - FirebaseFunctionsTypes.Module, - FirebaseFunctionsTypes.Statics - >; - } - interface FirebaseApp { - functions(customUrlOrRegion?: string): FirebaseFunctionsTypes.Module; - } - } -} diff --git a/packages/functions/lib/index.ts b/packages/functions/lib/index.ts new file mode 100644 index 0000000000..055640ce64 --- /dev/null +++ b/packages/functions/lib/index.ts @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { getApp, type ReactNativeFirebase } from '@react-native-firebase/app'; +import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/lib/common'; + +type Functions = FunctionsModule; +type FirebaseApp = ReactNativeFirebase.FirebaseApp & { + functions(regionOrCustomDomain?: string): Functions; +}; + +interface HttpsCallableOptions { + timeout?: number; +} + +// Export types for use in modular API +export type { HttpsCallableOptions }; + +export interface HttpsCallable { + (data?: RequestData | null): Promise<{ data: ResponseData }>; +} + +export interface FunctionsModule { + httpsCallable( + name: string, + options?: HttpsCallableOptions, + ): HttpsCallable; + httpsCallableFromUrl( + url: string, + options?: HttpsCallableOptions, + ): HttpsCallable; + useFunctionsEmulator(origin: string): void; + useEmulator(host: string, port: number): void; +} + +/** + * Returns a Functions instance for the given app. + * @param app - The FirebaseApp to use. Optional. + * @param regionOrCustomDomain - One of: a) The region the callable functions are located in (ex: us-central1) b) A custom domain hosting the callable functions (ex: https://mydomain.com). Optional. + * @returns Functions instance for the given app. + */ +export function getFunctions(app?: FirebaseApp, regionOrCustomDomain?: string): Functions { + if (app) { + return getApp(app.name).functions(regionOrCustomDomain) as Functions; + } + + return getApp().functions(regionOrCustomDomain) as Functions; +} + +/** + * Modify this instance to communicate with the Cloud Functions emulator. + * Note: this must be called before this instance has been used to do any operations. + * @param functionsInstance A functions instance. + * @param host The emulator host. (ex: localhost) + * @param port The emulator port. (ex: 5001) + */ +export function connectFunctionsEmulator( + functionsInstance: Functions, + host: string, + port: number, +): void { + // @ts-ignore + return functionsInstance.useEmulator.call(functionsInstance, host, port, MODULAR_DEPRECATION_ARG); +} + +/** + * Returns a reference to the callable HTTPS trigger with the given name. + * @param functionsInstance A functions instance. + * @param name The name of the trigger. + * @param options An interface for metadata about how calls should be executed. + * @returns HttpsCallable instance + */ +export function httpsCallable( + functionsInstance: Functions, + name: string, + options?: HttpsCallableOptions, +): HttpsCallable { + return functionsInstance.httpsCallable.call( + functionsInstance, + name, + options, + // @ts-ignore + MODULAR_DEPRECATION_ARG, + ) as HttpsCallable; +} + +/** + * Returns a reference to the callable HTTPS trigger with the specified url. + * @param functionsInstance A functions instance. + * @param url The url of the trigger. + * @param options An instance of HttpsCallableOptions containing metadata about how calls should be executed. + * @returns HttpsCallable instance + */ +export function httpsCallableFromUrl( + functionsInstance: Functions, + url: string, + options?: HttpsCallableOptions, +): HttpsCallable { + return functionsInstance.httpsCallableFromUrl.call( + functionsInstance, + url, + options, + // @ts-ignore + MODULAR_DEPRECATION_ARG, + ) as HttpsCallable; +} + +// Define HttpsErrorCode locally to avoid circular imports +export const HttpsErrorCode = { + OK: 'ok', + CANCELLED: 'cancelled', + UNKNOWN: 'unknown', + INVALID_ARGUMENT: 'invalid-argument', + DEADLINE_EXCEEDED: 'deadline-exceeded', + NOT_FOUND: 'not-found', + ALREADY_EXISTS: 'already-exists', + PERMISSION_DENIED: 'permission-denied', + UNAUTHENTICATED: 'unauthenticated', + RESOURCE_EXHAUSTED: 'resource-exhausted', + FAILED_PRECONDITION: 'failed-precondition', + ABORTED: 'aborted', + OUT_OF_RANGE: 'out-of-range', + UNIMPLEMENTED: 'unimplemented', + INTERNAL: 'internal', + UNAVAILABLE: 'unavailable', + DATA_LOSS: 'data-loss', + // Web codes are lowercase dasherized. + ok: 'ok', + cancelled: 'cancelled', + unknown: 'unknown', + 'invalid-argument': 'invalid-argument', + 'deadline-exceeded': 'deadline-exceeded', + 'not-found': 'not-found', + 'already-exists': 'already-exists', + 'permission-denied': 'permission-denied', + unauthenticated: 'unauthenticated', + 'resource-exhausted': 'resource-exhausted', + 'failed-precondition': 'failed-precondition', + aborted: 'aborted', + 'out-of-range': 'out-of-range', + unimplemented: 'unimplemented', + internal: 'internal', + unavailable: 'unavailable', + 'data-loss': 'data-loss', +} as const; + +export * from './namespaced'; diff --git a/packages/functions/lib/modular/index.d.ts b/packages/functions/lib/modular/index.d.ts deleted file mode 100644 index cee948f95f..0000000000 --- a/packages/functions/lib/modular/index.d.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { ReactNativeFirebase } from '@react-native-firebase/app'; -import { FirebaseFunctionsTypes } from '..'; - -import FirebaseApp = ReactNativeFirebase.FirebaseApp; -import Functions = FirebaseFunctionsTypes.Module; -import HttpsCallable = FirebaseFunctionsTypes.HttpsCallable; -import HttpsCallableOptions = FirebaseFunctionsTypes.HttpsCallableOptions; -import HttpsErrorCodeType = FirebaseFunctionsTypes.HttpsErrorCode; - -export const HttpsErrorCode: HttpsErrorCodeType; - -/** - * Get a {@link Functions} instance for the given app. - * @param {FirebaseApp | undefined} app - The FirebaseApp to use. Optional. - * @param {string | undefined} regionOrCustomDomain - One of: a) The region the callable functions are located in (ex: us-central1) b) A custom domain hosting the callable functions (ex: https://mydomain.com). optional - * @returns {Functions} Returns a {@link Functions} instance for the given app. - */ -export declare function getFunctions(app?: FirebaseApp, regionOrCustomDomain?: string): Functions; - -/** - * Modify this instance to communicate with the Cloud Functions emulator. - * Note: this must be called before this instance has been used to do any operations. - * @param {Functions} functionsInstance - * @param {string} host The emulator host. (ex: localhost) - * @param {number} port The emulator port. (ex: 5001) - */ -export declare function connectFunctionsEmulator( - functionsInstance: Functions, - host: string, - port: number, -): void; - -/** - * Returns a reference to the {@link HttpsCallable} trigger with the given name. - * @param {Functions} functionsInstance A functions instance. - * @param {string} name The name of the trigger. - * @param {HttpsCallableOptions | undefined} options An instance of {@link HttpsCallableOptions} containing metadata about how calls should be executed. - * @returns {HttpsCallable} - */ -export declare function httpsCallable( - functionsInstance: Functions, - name: string, - options?: HttpsCallableOptions, -): HttpsCallable; - -/** - * Returns a reference to the {@link HttpsCallable} trigger with the specified url. - * @param {Functions} functionsInstance A functions instance. - * @param {string} url The url of the trigger. - * @param {HttpsCallableOptions | undefined} options An instance of {@link HttpsCallableOptions} containing metadata about how calls should be executed. - * @returns {HttpsCallable} - */ -export declare function httpsCallableFromUrl( - functionsInstance: Functions, - url: string, - options?: HttpsCallableOptions, -): HttpsCallable; diff --git a/packages/functions/lib/modular/index.js b/packages/functions/lib/modular/index.js deleted file mode 100644 index 96a076a28b..0000000000 --- a/packages/functions/lib/modular/index.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2016-present Invertase Limited & Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this library except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -/** - * @typedef {import("..").FirebaseFunctionsTypes.Module} Functions - * @typedef {import("..").FirebaseFunctionsTypes.HttpsCallable} HttpsCallable - * @typedef {import("..").FirebaseFunctionsTypes.HttpsCallableOptions} HttpsCallableOptions - * @typedef {import("@firebase/app").FirebaseApp} FirebaseApp - */ - -import { getApp } from '@react-native-firebase/app'; -import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/lib/common'; - -/** - * Returns a Functions instance for the given app. - * @param {FirebaseApp | undefined} app - The FirebaseApp to use. Optional. - * @param {string | undefined} regionOrCustomDomain - One of: a) The region the callable functions are located in (ex: us-central1) b) A custom domain hosting the callable functions (ex: https://mydomain.com). Optional. - * @returns {Functions} - */ -export function getFunctions(app, regionOrCustomDomain) { - if (app) { - return getApp(app.name).functions(regionOrCustomDomain); - } - - return getApp().functions(regionOrCustomDomain); -} - -/** - * Modify this instance to communicate with the Cloud Functions emulator. - * Note: this must be called before this instance has been used to do any operations. - * @param {Functions} functionsInstance A functions instance. - * @param {string} host The emulator host. (ex: localhost) - * @param {number} port The emulator port. (ex: 5001) - * @returns {void} - */ -export function connectFunctionsEmulator(functionsInstance, host, port) { - return functionsInstance.useEmulator.call(functionsInstance, host, port, MODULAR_DEPRECATION_ARG); -} - -/** - * Returns a reference to the callable HTTPS trigger with the given name. - * @param {Functions} functionsInstance A functions instance. - * @param {string} name The name of the trigger. - * @param {HttpsCallableOptions | undefined} options An interface for metadata about how calls should be executed. - * @returns {HttpsCallable} - */ -export function httpsCallable(functionsInstance, name, options) { - return functionsInstance.httpsCallable.call( - functionsInstance, - name, - options, - MODULAR_DEPRECATION_ARG, - ); -} - -/** - * Returns a reference to the callable HTTPS trigger with the specified url. - * @param {Functions} functionsInstance A functions instance. - * @param {string} url The url of the trigger. - * @param {HttpsCallableOptions | undefined} options An instance of {@link HttpsCallableOptions} containing metadata about how calls should be executed. - * @returns {HttpsCallable} - */ -export function httpsCallableFromUrl(functionsInstance, url, options) { - return functionsInstance.httpsCallableFromUrl.call( - functionsInstance, - url, - options, - MODULAR_DEPRECATION_ARG, - ); -} - -export { HttpsErrorCode } from '../index'; diff --git a/packages/functions/lib/index.js b/packages/functions/lib/namespaced.ts similarity index 61% rename from packages/functions/lib/index.js rename to packages/functions/lib/namespaced.ts index cc038403c0..95f789042f 100644 --- a/packages/functions/lib/index.js +++ b/packages/functions/lib/namespaced.ts @@ -21,13 +21,15 @@ import { FirebaseModule, getFirebaseRoot, } from '@react-native-firebase/app/lib/internal'; -import HttpsError from './HttpsError'; -import version from './version'; +import { HttpsError, type NativeError } from './HttpsError'; +import { version } from './version'; import { setReactNativeModule } from '@react-native-firebase/app/lib/internal/nativeModule'; import fallBackModule from './web/RNFBFunctionsModule'; - +import type { HttpsCallableOptions } from '.'; +import type { FirebaseApp } from '@react-native-firebase/app'; const namespace = 'functions'; -const nativeModuleName = 'RNFBFunctionsModule'; + +const nativeModuleName = 'NativeFunctionsModule'; export const HttpsErrorCode = { OK: 'ok', @@ -67,21 +69,102 @@ export const HttpsErrorCode = { internal: 'internal', unavailable: 'unavailable', 'data-loss': 'data-loss', -}; +} as const; const statics = { HttpsErrorCode, }; +// Export the complete FirebaseFunctionsTypes namespace +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace FirebaseFunctionsTypes { + export type FunctionsErrorCode = + | 'ok' + | 'cancelled' + | 'unknown' + | 'invalid-argument' + | 'deadline-exceeded' + | 'not-found' + | 'already-exists' + | 'permission-denied' + | 'resource-exhausted' + | 'failed-precondition' + | 'aborted' + | 'out-of-range' + | 'unimplemented' + | 'internal' + | 'unavailable' + | 'data-loss' + | 'unauthenticated'; + + export interface HttpsCallableResult { + readonly data: ResponseData; + } + + export interface HttpsCallable { + (data?: RequestData | null): Promise>; + } + + export interface HttpsCallableOptions { + timeout?: number; + } + + export interface HttpsError extends Error { + readonly code: FunctionsErrorCode; + readonly details?: any; + } + + export interface HttpsErrorCode { + OK: 'ok'; + CANCELLED: 'cancelled'; + UNKNOWN: 'unknown'; + INVALID_ARGUMENT: 'invalid-argument'; + DEADLINE_EXCEEDED: 'deadline-exceeded'; + NOT_FOUND: 'not-found'; + ALREADY_EXISTS: 'already-exists'; + PERMISSION_DENIED: 'permission-denied'; + UNAUTHENTICATED: 'unauthenticated'; + RESOURCE_EXHAUSTED: 'resource-exhausted'; + FAILED_PRECONDITION: 'failed-precondition'; + ABORTED: 'aborted'; + OUT_OF_RANGE: 'out-of-range'; + UNIMPLEMENTED: 'unimplemented'; + INTERNAL: 'internal'; + UNAVAILABLE: 'unavailable'; + DATA_LOSS: 'data-loss'; + } + + export interface Statics { + HttpsErrorCode: HttpsErrorCode; + } + + export interface Module { + httpsCallable( + name: string, + options?: HttpsCallableOptions, + ): HttpsCallable; + httpsCallableFromUrl( + url: string, + options?: HttpsCallableOptions, + ): HttpsCallable; + useFunctionsEmulator(origin: string): void; + useEmulator(host: string, port: number): void; + } +} + class FirebaseFunctionsModule extends FirebaseModule { - constructor(...args) { - super(...args); - this._customUrlOrRegion = this._customUrlOrRegion || 'us-central1'; + _customUrlOrRegion: string; + private _useFunctionsEmulatorHost: string | null; + private _useFunctionsEmulatorPort: number; + // TODO: config is app package (FirebaseModule) object to be typed in the future + constructor(app: FirebaseApp, config: any, customUrlOrRegion: string | null) { + super(app, config, customUrlOrRegion); + this._customUrlOrRegion = customUrlOrRegion || 'us-central1'; this._useFunctionsEmulatorHost = null; this._useFunctionsEmulatorPort = -1; } - httpsCallable(name, options = {}) { + httpsCallable(name: string, options: HttpsCallableOptions = {}) { if (options.timeout) { if (isNumber(options.timeout)) { options.timeout = options.timeout / 1000; @@ -90,7 +173,7 @@ class FirebaseFunctionsModule extends FirebaseModule { } } - return data => { + return (data?: any) => { const nativePromise = this.native.httpsCallable( this._useFunctionsEmulatorHost, this._useFunctionsEmulatorPort, @@ -100,11 +183,11 @@ class FirebaseFunctionsModule extends FirebaseModule { }, options, ); - return nativePromise.catch(nativeError => { + return nativePromise.catch((nativeError: NativeError) => { const { code, message, details } = nativeError.userInfo || {}; return Promise.reject( new HttpsError( - HttpsErrorCode[code] || HttpsErrorCode.UNKNOWN, + HttpsErrorCode[code as keyof typeof HttpsErrorCode] || HttpsErrorCode.UNKNOWN, message || nativeError.message, details || null, nativeError, @@ -114,7 +197,7 @@ class FirebaseFunctionsModule extends FirebaseModule { }; } - httpsCallableFromUrl(url, options = {}) { + httpsCallableFromUrl(url: string, options: HttpsCallableOptions = {}) { if (options.timeout) { if (isNumber(options.timeout)) { options.timeout = options.timeout / 1000; @@ -123,7 +206,7 @@ class FirebaseFunctionsModule extends FirebaseModule { } } - return data => { + return (data?: any) => { const nativePromise = this.native.httpsCallableFromUrl( this._useFunctionsEmulatorHost, this._useFunctionsEmulatorPort, @@ -133,11 +216,11 @@ class FirebaseFunctionsModule extends FirebaseModule { }, options, ); - return nativePromise.catch(nativeError => { + return nativePromise.catch((nativeError: NativeError) => { const { code, message, details } = nativeError.userInfo || {}; return Promise.reject( new HttpsError( - HttpsErrorCode[code] || HttpsErrorCode.UNKNOWN, + HttpsErrorCode[code as keyof typeof HttpsErrorCode] || HttpsErrorCode.UNKNOWN, message || nativeError.message, details || null, nativeError, @@ -147,15 +230,17 @@ class FirebaseFunctionsModule extends FirebaseModule { }; } - useFunctionsEmulator(origin) { - [_, host, port] = /https?\:.*\/\/([^:]+):?(\d+)?/.exec(origin); - if (!port) { - port = 5001; + useFunctionsEmulator(origin: string): void { + const match = /https?\:.*\/\/([^:]+):?(\d+)?/.exec(origin); + if (!match) { + throw new Error('Invalid emulator origin format'); } - this.useEmulator(host, parseInt(port)); + const [, host, portStr] = match; + const port = portStr ? parseInt(portStr) : 5001; + this.useEmulator(host as string, port); } - useEmulator(host, port) { + useEmulator(host: string, port: number): void { if (!isNumber(port)) { throw new Error('useEmulator port parameter must be a number'); } @@ -202,8 +287,6 @@ export default createModuleNamespace({ ModuleClass: FirebaseFunctionsModule, }); -export * from './modular'; - // import functions, { firebase } from '@react-native-firebase/functions'; // functions().logEvent(...); // firebase.functions().logEvent(...); diff --git a/packages/functions/lib/types.d.ts b/packages/functions/lib/types.d.ts new file mode 100644 index 0000000000..7e6520ecfc --- /dev/null +++ b/packages/functions/lib/types.d.ts @@ -0,0 +1,58 @@ +declare module '@react-native-firebase/app/lib/common' { + export const MODULAR_DEPRECATION_ARG: string; + export const isAndroid: boolean; + export const isNumber: (value: any) => value is number; +} + +declare module '@react-native-firebase/app/lib/internal' { + export function createModuleNamespace(config: any): any; + export class FirebaseModule { + constructor(...args: any[]); + native: any; + firebaseJson: any; + _customUrlOrRegion: string | null; + } + export function getFirebaseRoot(): any; + export class NativeFirebaseError { + static getStackWithMessage(message: string, jsStack?: string): string; + } +} + +declare module '@react-native-firebase/app/lib/internal/nativeModule' { + export function setReactNativeModule(moduleName: string, module: any): void; +} + +declare module '@react-native-firebase/app/lib' { + namespace ReactNativeFirebase { + import FirebaseModuleWithStaticsAndApp = ReactNativeFirebase.FirebaseModuleWithStaticsAndApp; + interface Module { + functions: FirebaseModuleWithStaticsAndApp; + } + interface FirebaseApp { + functions(customUrlOrRegion?: string): any; + readonly name: string; + } + } +} + +declare module '@react-native-firebase/app/lib/internal/web/firebaseFunctions' { + export function getApp(appName: string): any; + export function getFunctions(app: any, regionOrCustomDomain?: string): any; + export function httpsCallable(functionsInstance: any, name: string, options?: any): any; + export function httpsCallableFromURL(functionsInstance: any, url: string, options?: any): any; + export function connectFunctionsEmulator( + functionsInstance: any, + host: string, + port: number, + ): void; +} + +declare module './version' { + const version: string; + export default version; +} + +declare module './web/RNFBFunctionsModule' { + const fallBackModule: any; + export default fallBackModule; +} diff --git a/packages/functions/lib/web/RNFBFunctionsModule.android.js b/packages/functions/lib/web/RNFBFunctionsModule.android.ts similarity index 100% rename from packages/functions/lib/web/RNFBFunctionsModule.android.js rename to packages/functions/lib/web/RNFBFunctionsModule.android.ts diff --git a/packages/functions/lib/web/RNFBFunctionsModule.ios.js b/packages/functions/lib/web/RNFBFunctionsModule.ios.ts similarity index 100% rename from packages/functions/lib/web/RNFBFunctionsModule.ios.js rename to packages/functions/lib/web/RNFBFunctionsModule.ios.ts diff --git a/packages/functions/lib/web/RNFBFunctionsModule.js b/packages/functions/lib/web/RNFBFunctionsModule.ts similarity index 63% rename from packages/functions/lib/web/RNFBFunctionsModule.js rename to packages/functions/lib/web/RNFBFunctionsModule.ts index cfb29c2281..7d4b7b397d 100644 --- a/packages/functions/lib/web/RNFBFunctionsModule.js +++ b/packages/functions/lib/web/RNFBFunctionsModule.ts @@ -5,6 +5,12 @@ import { httpsCallableFromURL, connectFunctionsEmulator, } from '@react-native-firebase/app/lib/internal/web/firebaseFunctions'; +import type { HttpsCallableOptions } from '../index'; +import type { NativeError } from '../HttpsError'; + +interface WrapperData { + data?: any; +} /** * This is a 'NativeModule' for the web platform. @@ -15,16 +21,24 @@ import { export default { /** * Get and execute a Firebase Functions callable. - * @param {string} appName - The name of the app to get the functions instance for. - * @param {string} regionOrCustomDomain - The region or custom domain to use for the functions instance. - * @param {string} host - The host to use for the functions emulator. - * @param {number} port - The port to use for the functions emulator. - * @param {string} name - The name of the functions callable. - * @param {object} wrapper - The wrapper object to use for the functions callable. - * @param {object} options - The options to use for the functions callable. - * @returns {object} - The result of the functions callable. + * @param appName - The name of the app to get the functions instance for. + * @param regionOrCustomDomain - The region or custom domain to use for the functions instance. + * @param host - The host to use for the functions emulator. + * @param port - The port to use for the functions emulator. + * @param name - The name of the functions callable. + * @param wrapper - The wrapper object to use for the functions callable. + * @param options - The options to use for the functions callable. + * @returns The result of the functions callable. */ - async httpsCallable(appName, regionOrCustomDomain, host, port, name, wrapper, options) { + async httpsCallable( + appName: string, + regionOrCustomDomain: string | null, + host: string | null, + port: number, + name: string, + wrapper: WrapperData, + options: HttpsCallableOptions, + ): Promise { try { const app = getApp(appName); let functionsInstance; @@ -58,10 +72,9 @@ export default { const data = wrapper['data'] ?? null; const result = await callable(data); return result; - } catch (error) { + } catch (error: any) { const { code, message, details } = error; - const nativeError = { - code, + const nativeError: NativeError = { message, userInfo: { code: code ? code.replace('functions/', '') : 'unknown', @@ -75,22 +88,30 @@ export default { /** * Get and execute a Firebase Functions callable from a URL. - * @param {string} appName - The name of the app to get the functions instance for. - * @param {string} regionOrCustomDomain - The region or custom domain to use for the functions instance. - * @param {string} host - The host to use for the functions emulator. - * @param {number} port - The port to use for the functions emulator. - * @param {string} url - The URL to use for the functions callable. - * @param {object} wrapper - The wrapper object to use for the functions callable. - * @param {object} options - The options to use for the functions callable. - * @returns {object} - The result of the functions callable. + * @param appName - The name of the app to get the functions instance for. + * @param regionOrCustomDomain - The region or custom domain to use for the functions instance. + * @param host - The host to use for the functions emulator. + * @param port - The port to use for the functions emulator. + * @param url - The URL to use for the functions callable. + * @param wrapper - The wrapper object to use for the functions callable. + * @param options - The options to use for the functions callable. + * @returns The result of the functions callable. */ - async httpsCallableFromUrl(appName, regionOrCustomDomain, host, port, url, wrapper, options) { + async httpsCallableFromUrl( + appName: string, + regionOrCustomDomain: string | null, + host: string | null, + port: number, + url: string, + wrapper: WrapperData, + options: HttpsCallableOptions, + ): Promise { try { const app = getApp(appName); let functionsInstance; if (regionOrCustomDomain) { functionsInstance = getFunctions(app, regionOrCustomDomain); - // Hack to work around custom domain and` region not being set on the instance. + // Hack to work around custom domain and region not being set on the instance. if (regionOrCustomDomain.startsWith('http')) { functionsInstance.customDomain = regionOrCustomDomain; } else { @@ -109,10 +130,9 @@ export default { const callable = httpsCallableFromURL(functionsInstance, url, options); const result = await callable(wrapper['data']); return result; - } catch (error) { + } catch (error: any) { const { code, message, details } = error; - const nativeError = { - code, + const nativeError: NativeError = { message, userInfo: { code: code ? code.replace('functions/', '') : 'unknown', diff --git a/packages/functions/package.json b/packages/functions/package.json index df98d358ee..2f4e74bc93 100644 --- a/packages/functions/package.json +++ b/packages/functions/package.json @@ -3,12 +3,31 @@ "version": "22.4.0", "author": "Invertase (http://invertase.io)", "description": "React Native Firebase - Cloud Functions for Firebase lets you automatically run backend code in response to events triggered by Firebase features and HTTPS requests. React Native Firebase supports integration with production and locally emulated Cloud Functions with a simple API interface.\n\n", - "main": "lib/index.js", - "types": "lib/index.d.ts", + "main": "./dist/commonjs/index.js", + "module": "./dist/module/index.js", + "types": "./dist/typescript/commonjs/functions/lib/index.d.ts", + "codegenConfig": { + "name": "NativeFunctionsModule", + "type": "modules", + "jsSrcsDir": "specs", + "includesGeneratedCode": true, + "android": { + "javaPackageName": "io.invertase.firebase.functions" + }, + "ios": { + "modulesProvider": { + "NativeFunctionsModule": "RNFBFunctionsModule" + } + } + }, "scripts": { - "build": "genversion --semi lib/version.js", + "build": "genversion --esm --semi lib/version.ts", "build:clean": "rimraf android/build && rimraf ios/build", - "prepare": "yarn run build" + "compile": "bob build", + "prepare": "yarn run build && yarn compile", + "codegen": "yarn android:codegen && yarn ios:codegen", + "android:codegen": "npx @react-native-community/cli codegen --platform android --outputPath=./android/src/main/java/io/invertase/firebase/functions/generated", + "ios:codegen": "npx @react-native-community/cli codegen --platform ios --outputPath=./ios/generated" }, "repository": { "type": "git", @@ -27,10 +46,57 @@ "@react-native-firebase/app": "22.4.0" }, "devDependencies": { - "@react-native-firebase/private-tests-firebase-functions": "^0.0.1" + "@react-native-firebase/private-tests-firebase-functions": "^0.0.1", + "react-native": "^0.80.1", + "react-native-builder-bob": "^0.40.12", + "typescript": "^5.8.3" }, "publishConfig": { "access": "public", "provenance": true - } + }, + "exports": { + ".": { + "source": "./lib/index.ts", + "import": { + "types": "./dist/typescript/module/functions/lib/index.d.ts", + "default": "./dist/module/index.js" + }, + "require": { + "types": "./dist/typescript/commonjs/functions/lib/index.d.ts", + "default": "./dist/commonjs/index.js" + } + }, + "./package.json": "./package.json" + }, + "files": [ + "lib/modular", + "dist", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__" + ], + "react-native-builder-bob": { + "source": "lib", + "output": "dist", + "targets": [ + [ + "module", + { + "esm": true + } + ], + [ + "commonjs", + { + "esm": true + } + ], + "typescript" + ] + }, + "eslintIgnore": [ + "node_modules/", + "dist/" + ] } diff --git a/packages/functions/react-native.config.js b/packages/functions/react-native.config.js new file mode 100644 index 0000000000..d1b6f36785 --- /dev/null +++ b/packages/functions/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependency: { + platforms: { + android: { + cmakeListsPath: + './src/main/java/io/invertase/firebase/functions/generated/jni/CMakeLists.txt', + }, + }, + }, +}; diff --git a/packages/functions/specs/NativeFunctionsModule.ts b/packages/functions/specs/NativeFunctionsModule.ts new file mode 100644 index 0000000000..a927107ec1 --- /dev/null +++ b/packages/functions/specs/NativeFunctionsModule.ts @@ -0,0 +1,50 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +// Define generic types outside the interface +export type RequestData = unknown; +export type ResponseData = unknown; + +export interface Spec extends TurboModule { + /** + * Calls a Cloud Function with the given name and data. + * + * @param emulatorHost - The emulator host (can be null) + * @param emulatorPort - The emulator port (can be -1 for no emulator) + * @param name - The name of the Cloud Function to call + * @param data - The data to pass to the function + * @param options - Additional options for the call + * @returns Promise that resolves with the function result + */ + httpsCallable( + appName: string, + region: string, + emulatorHost: string | null, + emulatorPort: number, + name: string, + data: { data: RequestData }, + options: { timeout?: number }, + ): Promise<{ data: ResponseData }>; + + /** + * Calls a Cloud Function using a full URL instead of just the function name. + * + * @param emulatorHost - The emulator host (can be null) + * @param emulatorPort - The emulator port (can be -1 for no emulator) + * @param url - The full URL of the Cloud Function + * @param data - The data to pass to the function + * @param options - Additional options for the call + * @returns Promise that resolves with the function result + */ + httpsCallableFromUrl( + appName: string, + region: string, + emulatorHost: string | null, + emulatorPort: number, + url: string, + data: { data: RequestData }, + options: { timeout?: number }, + ): Promise<{ data: ResponseData }>; +} + +export default TurboModuleRegistry.getEnforcing('NativeFunctionsModule'); diff --git a/packages/functions/tsconfig.json b/packages/functions/tsconfig.json new file mode 100644 index 0000000000..d74e371450 --- /dev/null +++ b/packages/functions/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "lib": [ + "ESNext" + ], + "module": "ESNext", + "moduleResolution": "bundler", + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "verbatimModuleSyntax": true, + "baseUrl": ".", + "paths": { + "@react-native-firebase/app": ["../app/lib"] + } + } +} diff --git a/packages/functions/type-test.ts b/packages/functions/type-test.ts deleted file mode 100644 index 44a1b399d0..0000000000 --- a/packages/functions/type-test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import firebase, { FirebaseFunctionsTypes } from '.'; - -console.log(firebase().app); - -// checks module exists at root -console.log(firebase.functions().app.name); - -// checks module exists at app level -console.log(firebase.app().functions().app.name); - -// app level module accepts string arg -console.log(firebase.app().functions('some-string').app.name); -console.log(firebase.app().functions('some-string').httpsCallable('foo')); - -// checks statics exist -console.log(firebase.functions.SDK_VERSION); - -// checks statics exist on defaultExport -console.log(firebase.firebase.SDK_VERSION); - -// checks root exists -console.log(firebase.SDK_VERSION); - -// checks multi-app support exists -console.log(firebase.functions(firebase.app()).app.name); - -// checks default export supports app arg -console.log(firebase.functions(firebase.app('foo')).app.name); - -console.log(firebase.functions.HttpsErrorCode.ABORTED); - -firebase - .functions() - .httpsCallable('foo')(123) - .then((result: FirebaseFunctionsTypes.HttpsCallableResult) => { - console.log(result.data); - }) - .catch((error: { code: any; details: any }) => { - console.log(error.code); - console.log(error.details); - }); - -firebase.functions().useFunctionsEmulator('123'); diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock index d179f5a4e0..b32b05cf18 100644 --- a/tests/ios/Podfile.lock +++ b/tests/ios/Podfile.lock @@ -1808,74 +1808,78 @@ PODS: - Yoga - RNDeviceInfo (14.0.4): - React-Core - - RNFBAnalytics (22.3.0): + - RNFBAnalytics (22.4.0): - FirebaseAnalytics/Core (= 11.15.0) - FirebaseAnalytics/IdentitySupport (= 11.15.0) - GoogleAdsOnDeviceConversion - React-Core - RNFBApp - - RNFBApp (22.3.0): + - RNFBApp (22.4.0): - Firebase/CoreOnly (= 11.15.0) - React-Core - - RNFBAppCheck (22.3.0): + - RNFBAppCheck (22.4.0): - Firebase/AppCheck (= 11.15.0) - React-Core - RNFBApp - - RNFBAppDistribution (22.3.0): + - RNFBAppDistribution (22.4.0): - Firebase/AppDistribution (= 11.15.0) - React-Core - RNFBApp - - RNFBAuth (22.3.0): + - RNFBAuth (22.4.0): - Firebase/Auth (= 11.15.0) - React-Core - RNFBApp - - RNFBCrashlytics (22.3.0): + - RNFBCrashlytics (22.4.0): - Firebase/Crashlytics (= 11.15.0) - FirebaseCoreExtension - React-Core - RNFBApp - - RNFBDatabase (22.3.0): + - RNFBDatabase (22.4.0): - Firebase/Database (= 11.15.0) - React-Core - RNFBApp - - RNFBDynamicLinks (22.3.0): + - RNFBDynamicLinks (22.4.0): - Firebase/DynamicLinks (= 11.15.0) - GoogleUtilities/AppDelegateSwizzler - React-Core - RNFBApp - - RNFBFirestore (22.3.0): + - RNFBFirestore (22.4.0): - Firebase/Firestore (= 11.15.0) - React-Core - RNFBApp - - RNFBFunctions (22.3.0): + - RNFBFunctions (22.4.0): - Firebase/Functions (= 11.15.0) + - RCT-Folly - React-Core + - React-Fabric + - ReactAppDependencyProvider + - ReactCodegen - RNFBApp - - RNFBInAppMessaging (22.3.0): + - RNFBInAppMessaging (22.4.0): - Firebase/InAppMessaging (= 11.15.0) - React-Core - RNFBApp - - RNFBInstallations (22.3.0): + - RNFBInstallations (22.4.0): - Firebase/Installations (= 11.15.0) - React-Core - RNFBApp - - RNFBMessaging (22.3.0): + - RNFBMessaging (22.4.0): - Firebase/Messaging (= 11.15.0) - FirebaseCoreExtension - React-Core - RNFBApp - - RNFBML (22.3.0): + - RNFBML (22.4.0): - React-Core - RNFBApp - - RNFBPerf (22.3.0): + - RNFBPerf (22.4.0): - Firebase/Performance (= 11.15.0) - React-Core - RNFBApp - - RNFBRemoteConfig (22.3.0): + - RNFBRemoteConfig (22.4.0): - Firebase/RemoteConfig (= 11.15.0) - React-Core - RNFBApp - - RNFBStorage (22.3.0): + - RNFBStorage (22.4.0): - Firebase/Storage (= 11.15.0) - React-Core - RNFBApp @@ -2249,87 +2253,87 @@ SPEC CHECKSUMS: nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 - RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 + RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809 RCTDeprecation: be794de7dc6ed8f9f7fbf525f86e7651b8b68746 RCTRequired: a83787b092ec554c2eb6019ff3f5b8d125472b3b RCTTypeSafety: 48ad3c858926b1c46f46a81a58822b476e178e2c React: 3b5754191f1b65f1dbc52fbea7959c3d2d9e39c9 React-callinvoker: 6beeaf4c7db11b6cc953fac45f2c76e3fb125013 - React-Core: 8a10ac9de53373a3ecb5dfcbcf56df1d3dad0861 - React-CoreModules: af6999b35c7c01b0e12b59d27f3e054e13da43b1 - React-cxxreact: 833f00155ce8c2fda17f6d286f8eaeff2ececc69 + React-Core: 88e817c42de035378cc71e009193b9a044d3f595 + React-CoreModules: dcf764d71efb4f75d38fcae8d4513b6729f49360 + React-cxxreact: 8cdcc937c5fbc406fe843a381102fd69440ca78a React-debug: 0a9fb34ecb645333d905645dabdcfdc945626078 - React-defaultsnativemodule: e3129434d3fc44832b7121bcbdffbe86c29ef34d - React-domnativemodule: 0dd52f92aae48f433ae5fa56876b4d10ab543faf - React-Fabric: 413d5fbb4b5df36df2d63520d529118884c9410e - React-FabricComponents: faa9035cdd551de0eaf2752afaf0b0327932696a - React-FabricImage: d43f0147c170c73cc7b546f95b7b7da82a6f34fc + React-defaultsnativemodule: b5b92d4b4716825afa8c848b793fc7efdf8aeb5a + React-domnativemodule: 073b3161e1b49dfe9045884369ae1ec2b987de26 + React-Fabric: f62d9ce5c158ae40c2a7b2805b7c055297c9dad7 + React-FabricComponents: 4c48b1052f8f6c3b03c3c3e2a231f1abd6d89703 + React-FabricImage: 5ad03b0081353e1e047ae3471bb129c521bf02b1 React-featureflags: 1bfa283a0e6f26eac629e8cef2add1b2670b6f4e - React-featureflagsnativemodule: 82733d2214096feaf44c411de375749ee1cd564f - React-graphics: 87a183c58b6a5bd5c57ae8c9a8105955f07f3947 - React-hermes: 63df5ac5a944889c8758a6213b39ed825863adb7 - React-idlecallbacksnativemodule: 6eac06a2d491a4b081ac45ab03a5ecf8b12404fa - React-ImageManager: f30c60d98a0a41eb116bf7e22a0258c821747ad2 - React-jserrorhandler: d68cef591c019bd8cd93169d253d6fe860b17844 - React-jsi: 99d6207ec802ad73473a0dad3c9ad48cd98463f6 - React-jsiexecutor: 8c8097b4ba7e7f480582d6e6238b01be5dcc01c0 - React-jsinspector: 434f39b00a5850b5479c7c0f0d06b480482d51a1 - React-jsinspectortracing: d43a8b9f953510ecebe3b5ec7e9676bef2d2c7f0 - React-jsitracing: 1df3b12bab22b3bc9078f54eefa53f82ba981dee - React-logger: 763728cf4eebc9c5dc9bfc3649e22295784f69f3 - React-Mapbuffer: 86e068fae064bbd3f24781d6ae5445b0266b2a10 - React-microtasksnativemodule: fd98e3e44af51599576705ec7a85a36e35978913 - React-NativeModulesApple: 5c61cef9e7f0e1d6216ff0af41a3b882806a5cec - React-perflogger: 5f8fa36a8e168fb355efe72099efe77213bc2ac6 - React-performancetimeline: 4f3521ee6238c9caf1b0969da2c4f610ff72b922 + React-featureflagsnativemodule: 7dc781f04bbd4b394fccb85e187bdda954362bca + React-graphics: 7eefc878da8a522942358f53abd6a7170d757bf3 + React-hermes: 08ad9fb832d1b9faef391be17309aa6a69fad23b + React-idlecallbacksnativemodule: 4a5d5ee0f8d7a9fa94ebd1426d349e866c223979 + React-ImageManager: ce227ed251701b3f37e25a2beede459078fcd82c + React-jserrorhandler: 6e5ffaef9b3364351ef6ef58d6665beabf615a0e + React-jsi: afa286d7e0c102c2478dc420d4f8935e13c973fc + React-jsiexecutor: 08f5b512b4db9e2f147416d60a0a797576b9cfef + React-jsinspector: ebe0817345b1c0194ed5c64185269b9668fadf9a + React-jsinspectortracing: 6f251cb68796f3496698127deabe5b0bbbb89b52 + React-jsitracing: 4c3fd6a14f560c52c167254a07029bcf9b60f3d8 + React-logger: 304814ae37503c8eb54359851cc55bd4f936b39c + React-Mapbuffer: 8ba61e036d346d363ad208cfb1dea6c7fce0dce0 + React-microtasksnativemodule: feb934d19767f38faf9f9f0efb7cc1dcdf2d11b7 + React-NativeModulesApple: 55d6d890aa60200292a90cc1ca6c53409650f48f + React-perflogger: 0ea25c109dba33d47dec36b2634bf7ea67c1a555 + React-performancetimeline: 21656d07aede48ca0c8c3ca7d0e755eaa17f697c React-RCTActionSheet: 2ef95837e89b9b154f13cd8401f9054fc3076aff - React-RCTAnimation: 46abefd5acfda7e6629f9e153646deecc70babd2 - React-RCTAppDelegate: 7e58e0299e304cceee3f7019fa77bc6990f66b22 - React-RCTBlob: f68c63a801ef1d27e83c4011e3b083cc86a200d7 - React-RCTFabric: ee035e3c73729b95da4ee0959b6e0d68cd512368 - React-RCTFBReactNativeSpec: 3240b9b8d792aa4be0fb85c9898fc183125ba8de - React-RCTImage: 34e0bba1507e55f1c614bd759eb91d9be48c8c5b - React-RCTLinking: a0b6c9f4871c18b0b81ea952f43e752718bd5f1d - React-RCTNetwork: bdafd661ac2b20d23b779e45bf7ac3e4c8bd1b60 - React-RCTSettings: 98aa5163796f43789314787b584a84eba47787a9 - React-RCTText: 424a274fc9015b29de89cf3cbcdf4dd85dd69f83 - React-RCTVibration: 92d9875a955b0adb34b4b773528fdbbbc5addd6c + React-RCTAnimation: 33d960d7f58a81779eea6dea47ad0364c67e1517 + React-RCTAppDelegate: 85c13403fd6f6b6cc630428d52bd8bd76a670dc9 + React-RCTBlob: 74c986a02d951931d2f6ed0e07ed5a7eb385bfc0 + React-RCTFabric: 384a6e22644799f66f545bf0de4618f4652c791f + React-RCTFBReactNativeSpec: eb1c3ec5149f76133593a516ff9d5efe32ebcecd + React-RCTImage: 2c58b5ddeb3c65e52f942bbe13ff9c59bd649b09 + React-RCTLinking: b6b14f8a3e62c02fc627ac4f3fb0c7bd941f907c + React-RCTNetwork: 1d050f2466c1541b339587d46f78d5eee218d626 + React-RCTSettings: 8148f6be0ccc0cfe6e313417ebf8a479caaa2146 + React-RCTText: 64114531ad1359e4e02a4a8af60df606dbbabc25 + React-RCTVibration: f4859417a7dd859b6bf18b1aba897e52beb72ef6 React-rendererconsistency: 80ffb3fc9635edb785c19f06eb1ba9e1d3b85ea6 - React-rendererdebug: ae050d2e1ad48d69fa20a7060766c9f132416ffa + React-rendererdebug: ea9b0383484ade00d675582d7848be6a86c3feb5 React-rncore: 7c0b895671632ea5eb84edb85f48e180816e9e33 - React-RuntimeApple: c85771bc5430980a8469ad3b28a3c8dd07f95979 - React-RuntimeCore: 45cbbed881ce89605c779b3f4111664664b63897 + React-RuntimeApple: 8e0654961ab947d3febc60f77a4d9fe97e135d0a + React-RuntimeCore: b194b603daafd68b140ab4c871f1556efc2c69bc React-runtimeexecutor: 876dfc1d8daa819dfd039c40f78f277c5a3e66a6 - React-RuntimeHermes: eb7f7ad2ad9d0bbe5e4e2521aae96de55bd4096a - React-runtimescheduler: 9957105c1d7f068a1c00760a9c332167634f945a + React-RuntimeHermes: f337612527ff2ca8bb86a861be4636f177bc3bbb + React-runtimescheduler: 307946600cf701b3ffe38b454d1d1a710e8e74e7 React-timing: 96e060d0d0bf18522d363716623ed2c61f7107c7 - React-utils: 93529ff7b4baa71aea1f42a48e9d3d06db398618 - ReactAppDependencyProvider: 4893bde33952f997a323eb1a1ee87a72764018ff - ReactCodegen: 31f8d982d351eb4dbf3af220f363c7398ae667c8 - ReactCommon: 0adf8f24a3415b6815613bad362d390726b33fc7 + React-utils: 8adf5864fc96ef51957fee06a3e43ed26559d8a7 + ReactAppDependencyProvider: b48473fe434569ff8f6cb6ed4421217ebcbda878 + ReactCodegen: dbfd0fb94c71add45b06cd6c96ccc7545489c1e6 + ReactCommon: 8fdc2d8511f4099f25d5929f7fa4284c14a7e509 RecaptchaInterop: 11e0b637842dfb48308d242afc3f448062325aba - RNCAsyncStorage: 5321442ed26760d7581b26effab82399ea5ff18b - RNDeviceInfo: d863506092aef7e7af3a1c350c913d867d795047 - RNFBAnalytics: 5cfe8c05a01dad18f089af3df0a4af5057330761 - RNFBApp: f4375dd56d5cca3c47af4cff25e9a801a7405729 - RNFBAppCheck: 8ec4e9283afb3d7828c6e26843a080d0c9dea39f - RNFBAppDistribution: 7e6cdc3d05f1549b68d039f253f33d70661dc96e - RNFBAuth: 4107c9889a628967fddd394c02cfca0410bb9218 - RNFBCrashlytics: b101c80707727d0044a0b55fad0b8b952a200855 - RNFBDatabase: f76d9006c51ad211efe36c6d79e2908dd547934d - RNFBDynamicLinks: d461e99c1905d17d1d528da745f0f2cbad253a06 - RNFBFirestore: 942e343c06e3cefcb08742fc14991674e565882c - RNFBFunctions: 3ba97516c05e96ea4cedee384896d0aa954fb4d7 - RNFBInAppMessaging: d96c7ab07c94917d04837d8d6ac26386f7c2bc0c - RNFBInstallations: 01a8a5d9f9197be5c09d5da276d5e8a82c09609f - RNFBMessaging: d7a9b3652402d9a210bcf8bb535834874a676e6f - RNFBML: f9d89ae71931ded81fdc9996a77b80eea708c6a4 - RNFBPerf: e18283b6a2fc29105d2d044c097aa32d134808cd - RNFBRemoteConfig: ef8a9a28dc18e48467d6a323f06a9b4c52ba3790 - RNFBStorage: b8c0715145a453bb2aeb110e1b134ae3627babdd + RNCAsyncStorage: 320c8b9217695928a64d8ae993653425c8605368 + RNDeviceInfo: feea80a690d2bde1fe51461cf548039258bd03f2 + RNFBAnalytics: c73197fda198806e6573e94180c7a802522efebc + RNFBApp: d15dab17b5639fb7f95712d07c204912a534b8c6 + RNFBAppCheck: 6141154680a4ba8b75369d9347b16ae2c98bbbe7 + RNFBAppDistribution: 565426a3a3bf97bc2790c1e37728bc05d8bfb164 + RNFBAuth: d671a6c27eac871a90c7fbc000e5236b070af055 + RNFBCrashlytics: 6ada8cdbb9778a55eb45bf86f75cef1b08c5d064 + RNFBDatabase: 8047d7f35f9d182b4a1961249c55c8d157877de6 + RNFBDynamicLinks: 537639507cb59e328ecf94fc7db2d0e120610226 + RNFBFirestore: 1361e2bc9fc45d91d609807cd0539d812cfd5af1 + RNFBFunctions: e6bca1448f71b88529a00352eee78474c2b4a370 + RNFBInAppMessaging: ea0e1f75fe693dee9380b806843818d32e7e5563 + RNFBInstallations: e9af9d3c4962b083c2770d96f0b806428044b07f + RNFBMessaging: d01e0013a9dc69e2deb747b991818f7d6dd296ca + RNFBML: 80f0689813f0add9bea2154bcb1d703ded6ca365 + RNFBPerf: f3b63dbeeb29e7d81415ffdcce9762d881fc7acf + RNFBRemoteConfig: 75d3335600b9d7c31522d92f72b87dde08ad7256 + RNFBStorage: 59b481153863edd47a709fd27a23d70aeb763587 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Yoga: 6eb60fc2c0eef63e7d2ef4a56e0a3353534143a2 + Yoga: 0c521d2eddeeff54ba1126068140b6e970a77fc0 PODFILE CHECKSUM: 3abe8cfe7b06f24b788e90bea320d8ae6ea6d11a -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/tests/react-native.config.js b/tests/react-native.config.js index f72909b853..9590aa70bf 100644 --- a/tests/react-native.config.js +++ b/tests/react-native.config.js @@ -3,6 +3,8 @@ module.exports = { project: { ios: { sourceDir: './ios', + // Required for using test app with turbo-modules + // automaticPodsInstallation: false, }, macos: { sourceDir: './macos', diff --git a/tests/test-app/examples/functions/index.js b/tests/test-app/examples/functions/index.js new file mode 100644 index 0000000000..d65a8ee5ae --- /dev/null +++ b/tests/test-app/examples/functions/index.js @@ -0,0 +1,38 @@ +import React from 'react'; +import { AppRegistry, Button, Text, View } from 'react-native'; + +import { getApp } from '@react-native-firebase/app'; +import { + getFunctions, + connectFunctionsEmulator, + httpsCallable, +} from '@react-native-firebase/functions'; + +const functions = getFunctions(); +connectFunctionsEmulator(functions, 'localhost', 5001); +function App() { + return ( + + React Native Firebase + Functions API + Ensure Emulator is running!! +