Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AgentforceSDK-ReactNative-Bridge/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ repositories {
dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.5"
implementation "com.facebook.react:react-android"
api "com.salesforce.android.agentforcesdk:agentforce-sdk:15.165.6"
api "com.salesforce.android.agentforcesdk:agentforce-sdk-voice:15.165.6"
api "com.salesforce.android.agentforcesdk:agentforce-sdk:15.195.3"
api "com.salesforce.android.agentforcesdk:agentforce-sdk-voice:15.195.3"
// compileOnly: host app adds this for Employee Agent. Bridge compiles; host provides at runtime.
compileOnly "com.salesforce.mobilesdk:SalesforceReact:13.1.1"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ Pod::Spec.new do |s|
"ServiceAgent/**/*.{h,m,swift}"
]
core.dependency "React-Core"
core.dependency "AgentforceSDK", "19.29.3"
core.dependency "AgentforceService", "6.17.3"
core.dependency "AgentforceVoice", "2.10.8"
# AgentforceSDK 17.31.6 (262.1) depends on SharedUI ('~> 1'); declare it so
# this target can resolve the design-system module.
core.dependency "SharedUI", "1.3.1"
core.dependency "AgentforceSDK", "264.0.0"
core.dependency "AgentforceService", "264.0.0"
core.dependency "AgentforceVoice", "264.0.0"
# AgentforceSDK 264.0.0 requires SharedUI >= 1.5.11; declare a compatible
# published binary so this target can resolve the design-system module.
core.dependency "SharedUI", "1.6.10"
end

# Optional: add for Employee Agent auth (OAuth via Salesforce Mobile SDK).
Expand Down
2 changes: 1 addition & 1 deletion AgentforceSDK-ReactNative-Bridge/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@salesforce/react-native-agentforce",
"version": "0.7.3-patch2",
"version": "0.8.0",
"description": "Agentforce React Native bridge: JS API and native module for Service Agent and Employee Agent (auth bridge included; host app adds Mobile SDK).",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
42 changes: 20 additions & 22 deletions ios/Podfile.common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,36 @@ def shared_pods
:app_path => "#{Pod::Config.instance.installation_root}/.."
)

pod 'AgentforceSDK', '19.29.3'
pod 'AgentforceSDK', '264.0.0'
# AgentforceSDK declares a broad `~> 6` service dependency; pin explicitly to
# the exact 262.3 service binary this SDK build was tested against.
pod 'AgentforceService', '6.17.3'
pod 'AgentforceVoice', '2.10.8'
pod 'Messaging-InApp-Core', '> 1.10.0'
# the exact 264.0 service binary selected for this release.
pod 'AgentforceService', '264.0.0'
pod 'AgentforceVoice', '264.0.0'
pod 'Messaging-InApp-Core', '~> 1.13.0'
# Messaging-Multimedia-Core vends SMIMultimediaCore.framework, which
# AgentforceVoice links at runtime (@rpath/SMIMultimediaCore.framework).
# Keep this explicit so the framework is embedded, and align it with the
# AgentforceVoice 2.10.8 podspec requirement.
pod 'Messaging-Multimedia-Core', '~> 1.12.0'
# The AgentforceVoice podspec resolved from this Specs source declares only
# AgentforceService/SalesforceLogging/SalesforceNetwork (not the Binary subspec
# that the iOS SDK uses), so this transitive multimedia dep isn't pulled in and
# the framework is never embedded — surfacing as a dyld "Library not loaded"
# crash once Service Agent voice is enabled. Declare it explicitly so it's
# installed and embedded.
# Keep the Messaging family on one patch line. Multimedia-Core 1.13.x consumes
# the prebuilt LiveKit 2.16.x XCFramework declared below.
pod 'Messaging-Multimedia-Core', '~> 1.13.0'

# JWTKit is required by AgentforceService but not resolved automatically
pod 'JWTKit'

# SharedUI provides the design-system module (Colors/Fonts/Dimensions) that
# AgentforceSDK 17.31.6 (262.1) depends on ('SharedUI', '~> 1'). Pin to the
# exact flat spec the iOS SDK ships with; SLDSIcons is held at 1.2.2 to avoid
# AgentforceSDK 264.0.0 requires SharedUI >= 1.5.11. Pin a compatible
# published binary; SLDSIcons is held at 1.2.2 to avoid
# the "Multiple commands produce SLDSIcons.framework" collision.
pod 'SharedUI', '1.3.1'
pod 'SharedUI', '1.6.10'
pod 'SLDSIcons', '1.2.2'

# LiveKit is needed for both Service and Employee agents.
# Messaging-Multimedia-Core 1.12.x requires the compatible 2.11.x line.
pod 'LiveKitClient', '2.11.0' # Required so CocoaPods looks in the correct source location
# LiveKit is needed for both Service and Employee agents. Use the same prebuilt
# pod and minor line required by Messaging-Multimedia-Core 1.13.x.
pod 'LiveKitClient-XCFramework', '~> 2.16.0'

# AgentforceService links to Crypto.framework at runtime; SwiftCrypto provides it (avoids dyld "Library not loaded: Crypto.framework").
pod 'SwiftCrypto', '~> 3.15'
Expand All @@ -66,13 +71,6 @@ def pod.build_type
Pod::BuildType.static_library
end
end

# AgentforceVoice.xcframework links against @rpath/LiveKit.framework/LiveKit,
# but CocoaPods builds LiveKitClient as LiveKitClient.framework by default.
# Override module_name so it produces LiveKit.framework instead.
if pod.name == 'LiveKitClient'
pod.root_spec.attributes_hash['module_name'] = 'LiveKit'
end
end
end

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

133 changes: 133 additions & 0 deletions patches/react-native+0.74.7.patch
Original file line number Diff line number Diff line change
@@ -1,3 +1,136 @@
diff --git a/node_modules/react-native/sdks/hermes-engine/hermes-utils.rb b/node_modules/react-native/sdks/hermes-engine/hermes-utils.rb
index c0c7613..eda20e9 100644
--- a/node_modules/react-native/sdks/hermes-engine/hermes-utils.rb
+++ b/node_modules/react-native/sdks/hermes-engine/hermes-utils.rb
@@ -5,6 +5,7 @@

require 'net/http'
require 'rexml/document'
+require 'fileutils'

HERMES_GITHUB_URL = "https://github.com/facebook/hermes.git"
ENV_BUILD_FROM_SOURCE = "RCT_BUILD_HERMES_FROM_SOURCE"
@@ -217,14 +218,49 @@ def download_hermes_tarball(react_native_path, tarball_url, version, configurati
"#{artifacts_dir()}/hermes-ios-#{version}.tar.gz" :
"#{artifacts_dir()}/hermes-ios-#{version}-#{configuration}.tar.gz"

- unless File.exist?(destination_path)
- # Download to a temporary file first so we don't cache incomplete downloads.
- tmp_file = "#{artifacts_dir()}/hermes-ios.download"
- `mkdir -p "#{artifacts_dir()}" && curl "#{tarball_url}" -Lo "#{tmp_file}" && mv "#{tmp_file}" "#{destination_path}"`
+ if File.exist?(destination_path)
+ return destination_path if valid_hermes_tarball?(destination_path)
+
+ hermes_log("Removing invalid cached artifact: #{destination_path}", :error)
+ FileUtils.rm_f(destination_path)
+ end
+
+ FileUtils.mkdir_p(artifacts_dir())
+ tmp_file = "#{destination_path}.download-#{Process.pid}"
+
+ begin
+ download_succeeded = system(
+ 'curl',
+ '--fail',
+ '--location',
+ '--http1.1',
+ '--retry', '5',
+ '--retry-all-errors',
+ '--retry-delay', '2',
+ '--connect-timeout', '30',
+ '--output', tmp_file,
+ tarball_url
+ )
+
+ unless download_succeeded && valid_hermes_tarball?(tmp_file)
+ raise "[Hermes] Failed to download a valid artifact from #{tarball_url}"
+ end
+
+ # Only expose the final path after the complete archive has been validated.
+ File.rename(tmp_file, destination_path)
+ ensure
+ FileUtils.rm_f(tmp_file)
end
+
return destination_path
end

+def valid_hermes_tarball?(tarball_path)
+ return false unless File.file?(tarball_path) && File.size?(tarball_path)
+
+ return system('tar', '-tzf', tarball_path, out: File::NULL, err: File::NULL)
+end
+
def nightly_tarball_url(version)
params = "r=snapshots\&g=com.facebook.react\&a=react-native-artifacts\&c=hermes-ios-debug\&e=tar.gz\&v=#{version}-SNAPSHOT"
return resolve_url_redirects("http://oss.sonatype.org/service/local/artifact/maven/redirect\?#{params}")
diff --git a/node_modules/react-native/sdks/hermes-engine/utils/replace_hermes_version.js b/node_modules/react-native/sdks/hermes-engine/utils/replace_hermes_version.js
index f727aeb..4720eed 100644
--- a/node_modules/react-native/sdks/hermes-engine/utils/replace_hermes_version.js
+++ b/node_modules/react-native/sdks/hermes-engine/utils/replace_hermes_version.js
@@ -9,7 +9,7 @@

'use strict';

-const {execSync} = require('child_process');
+const {execFileSync} = require('child_process');
const fs = require('fs');
const yargs = require('yargs');

@@ -55,13 +55,48 @@ function shouldReplaceHermesConfiguration(configuration) {
function replaceHermesConfiguration(configuration, version, podsRoot) {
const tarballURLPath = `${podsRoot}/hermes-engine-artifacts/hermes-ios-${version.toLowerCase()}-${configuration.toLowerCase()}.tar.gz`;

+ validateHermesTarball(tarballURLPath);
+
const finalLocation = 'hermes-engine';
- console.log('Preparing the final location');
- fs.rmSync(finalLocation, {force: true, recursive: true});
- fs.mkdirSync(finalLocation, {recursive: true});
+ const temporaryLocation = fs.mkdtempSync(`${finalLocation}.tmp-`);
+ const backupLocation = `${finalLocation}.backup-${process.pid}-${Date.now()}`;
+
+ try {
+ console.log('Extracting the tarball');
+ execFileSync('tar', ['-xf', tarballURLPath, '-C', temporaryLocation], {
+ stdio: 'inherit',
+ });
+
+ console.log('Preparing the final location');
+ if (fs.existsSync(finalLocation)) {
+ fs.renameSync(finalLocation, backupLocation);
+ }
+
+ try {
+ fs.renameSync(temporaryLocation, finalLocation);
+ } catch (error) {
+ if (fs.existsSync(backupLocation) && !fs.existsSync(finalLocation)) {
+ fs.renameSync(backupLocation, finalLocation);
+ }
+ throw error;
+ }
+
+ fs.rmSync(backupLocation, {force: true, recursive: true});
+ } finally {
+ fs.rmSync(temporaryLocation, {force: true, recursive: true});
+ }
+}

- console.log('Extracting the tarball');
- execSync(`tar -xf ${tarballURLPath} -C ${finalLocation}`);
+function validateHermesTarball(tarballPath) {
+ if (!fs.existsSync(tarballPath) || fs.statSync(tarballPath).size === 0) {
+ throw new Error(`Hermes archive is missing or empty: ${tarballPath}`);
+ }
+
+ try {
+ execFileSync('tar', ['-tzf', tarballPath], {stdio: 'ignore'});
+ } catch (_error) {
+ throw new Error(`Hermes archive is invalid: ${tarballPath}`);
+ }
}

function updateLastBuildConfiguration(configuration) {
diff --git a/node_modules/react-native/third-party-podspecs/boost.podspec b/node_modules/react-native/third-party-podspecs/boost.podspec
index 8e924af..edd3a44 100644
--- a/node_modules/react-native/third-party-podspecs/boost.podspec
Expand Down
Loading