Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
77f440b
chore: stallion production release
Thor963 Mar 15, 2025
29a8aae
chore: base merged changelog
Thor963 Mar 15, 2025
f888820
fix: modifed event emitter init, added fallback for mounting prod bun…
Thor963 Mar 17, 2025
63a4527
chore(release): 2.0.1-alpha.1
Mar 17, 2025
ab3f0d4
fix: removed stallion enabled script reading logic from native, enabl…
Thor963 Mar 26, 2025
9a2197c
chore(release): 2.0.1-alpha.2
Mar 26, 2025
62cadf0
Alpha: Sync[iOS] & Restart + UI Changes (#38)
Thor963 Apr 22, 2025
c1a0316
chore: back merged main
Thor963 Apr 22, 2025
70b8067
feat: restart logic, ui revamp v0, ios sync and other bugfixes
Thor963 Apr 22, 2025
9cc9656
chore(release): 2.1.0-alpha.1
Apr 22, 2025
0620f85
chore: ios typo fix (#41)
Apr 29, 2025
c0c9bdb
fix: ios stage event typo
Thor963 Apr 29, 2025
bf9b787
chore(release): 2.1.0-alpha.2
Apr 29, 2025
3636acd
feat: added stream downloading for android (#42)
Thor963 May 11, 2025
df0d0d8
chore(release): 2.1.0-alpha.3
May 11, 2025
1471b57
feat: resume download android
Thor963 May 11, 2025
628eaca
chore(release): 2.2.0-alpha.1
May 11, 2025
d4d8433
feat: bundle signing (#44)
Thor963 Jun 6, 2025
1110e51
chore(release): 2.2.0-alpha.2
Jun 6, 2025
b16b74d
feat: bundle signing 2.3.0, back merge
Thor963 Jun 6, 2025
9e1117f
chore(release): 2.3.0-alpha.1
Jun 6, 2025
f0d454f
fix: exception handling ios newarch (#53)
Thor963 Jun 18, 2025
f36e6cd
chore: lockfile update
Thor963 Jun 18, 2025
f02c4f7
chore: node upgrade
Thor963 Jun 18, 2025
225085e
chore: node upgrade 20
Thor963 Jun 18, 2025
00bb17c
chore(release): 2.3.0-alpha.2
Jun 18, 2025
979640a
fix: removeEventListener exported
Thor963 Jun 18, 2025
c96c438
Merge branch 'alpha' of github.com-Thor963:stallion-tech/react-native…
Thor963 Jun 18, 2025
0f50efb
chore(release): 2.3.0-alpha.3
Jun 18, 2025
6c8202f
fix: android sdk token expriy logic fixed (#66)
Thor963 Jun 25, 2025
aebbe3e
chore(release): 2.3.0-alpha.4
Jun 25, 2025
044a5ad
fix: release v2.3.0-alpha.5 (#75)
Thor963 Nov 26, 2025
1093587
chore(release): 2.3.0-alpha.5
Nov 26, 2025
e7b9443
fix: js error boundary, exception handler safety checks (#86)
Thor963 Dec 16, 2025
3269c88
chore(release): 2.3.0-alpha.6
Dec 16, 2025
03cf350
chore: package stable update
Dec 17, 2025
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
2 changes: 1 addition & 1 deletion .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ runs:
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "16.x"
node-version: '20.x'
- name: Cache dependencies
id: yarn-cache
uses: actions/cache@v3
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,6 @@ lib/

.npmrc

sdk-package
sdk-package

ios/main/StallionVersion.h
61 changes: 57 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
# [2.2.0](https://github.com/stallion-tech/react-native-stallion/compare/v2.1.0...v2.2.0) (2025-06-06)
# [2.3.0-alpha.6](https://github.com/stallion-tech/react-native-stallion/compare/v2.3.0-alpha.5...v2.3.0-alpha.6) (2025-12-16)


### Features
### Bug Fixes

* resume download Android (v2.2.0) ([647a69f](https://github.com/stallion-tech/react-native-stallion/commit/647a69fdc70b913e7838a6c995c8d103e15b1c92)), closes [#32](https://github.com/stallion-tech/react-native-stallion/issues/32) [#38](https://github.com/stallion-tech/react-native-stallion/issues/38) [#41](https://github.com/stallion-tech/react-native-stallion/issues/41) [#42](https://github.com/stallion-tech/react-native-stallion/issues/42)
* js error boundary, exception handler safety checks ([#86](https://github.com/stallion-tech/react-native-stallion/issues/86)) ([e7b9443](https://github.com/stallion-tech/react-native-stallion/commit/e7b94434f280f0160630b30890aced8ea36c3410))

# [2.2.0-alpha.1](https://github.com/stallion-tech/react-native-stallion/compare/v2.1.0...v2.2.0-alpha.1) (2025-05-11)
# [2.3.0-alpha.5](https://github.com/stallion-tech/react-native-stallion/compare/v2.3.0-alpha.4...v2.3.0-alpha.5) (2025-11-26)


### Bug Fixes

* release v2.3.0-alpha.5 ([#75](https://github.com/stallion-tech/react-native-stallion/issues/75)) ([044a5ad](https://github.com/stallion-tech/react-native-stallion/commit/044a5addc9b36c153946e847ac9b34c59e5c5be5))

# [2.3.0-alpha.4](https://github.com/stallion-tech/react-native-stallion/compare/v2.3.0-alpha.3...v2.3.0-alpha.4) (2025-06-25)


### Bug Fixes

* android sdk token expriy logic fixed ([#66](https://github.com/stallion-tech/react-native-stallion/issues/66)) ([6c8202f](https://github.com/stallion-tech/react-native-stallion/commit/6c8202fff4a46c9eaf066d793b402e9d9084bed3))

# [2.3.0-alpha.3](https://github.com/stallion-tech/react-native-stallion/compare/v2.3.0-alpha.2...v2.3.0-alpha.3) (2025-06-18)


### Bug Fixes

* removeEventListener exported ([979640a](https://github.com/stallion-tech/react-native-stallion/commit/979640a8b485d8ab0bb03b5799fc176289429228))

# [2.3.0-alpha.2](https://github.com/stallion-tech/react-native-stallion/compare/v2.3.0-alpha.1...v2.3.0-alpha.2) (2025-06-18)


### Bug Fixes

* exception handling ios newarch ([#53](https://github.com/stallion-tech/react-native-stallion/issues/53)) ([f0d454f](https://github.com/stallion-tech/react-native-stallion/commit/f0d454fe9ebf83bcbc2b09fd96bb17dd5b2a8a82)), closes [#49](https://github.com/stallion-tech/react-native-stallion/issues/49)

# [2.3.0-alpha.1](https://github.com/stallion-tech/react-native-stallion/compare/v2.2.0...v2.3.0-alpha.1) (2025-06-06)


### Bug Fixes
Expand All @@ -18,9 +46,34 @@
### Features

* added stream downloading for android ([#42](https://github.com/stallion-tech/react-native-stallion/issues/42)) ([3636acd](https://github.com/stallion-tech/react-native-stallion/commit/3636acd4d48c4ae2e5f5659e4f0a31239f745d4b))
* bundle signing ([#44](https://github.com/stallion-tech/react-native-stallion/issues/44)) ([d4d8433](https://github.com/stallion-tech/react-native-stallion/commit/d4d84335409ef9b8b4eb5c223ef5217f4d0cd54f)), closes [#49](https://github.com/stallion-tech/react-native-stallion/issues/49)
* bundle signing 2.3.0, back merge ([b16b74d](https://github.com/stallion-tech/react-native-stallion/commit/b16b74d7bba4a07aa52af6a1864e2c971cea46ab))
* restart logic, ui revamp v0, ios sync and other bugfixes ([70b8067](https://github.com/stallion-tech/react-native-stallion/commit/70b806753d2a3784686b93ebe15eef802d2665e8))
* resume download android ([1471b57](https://github.com/stallion-tech/react-native-stallion/commit/1471b5780608df29437fbe8048205fb3537d2859))

# [2.2.0-alpha.2](https://github.com/stallion-tech/react-native-stallion/compare/v2.2.0-alpha.1...v2.2.0-alpha.2) (2025-06-06)

# [2.2.0](https://github.com/stallion-tech/react-native-stallion/compare/v2.1.0...v2.2.0) (2025-06-06)

### Features

- bundle signing ([#44](https://github.com/stallion-tech/react-native-stallion/issues/44)) ([d4d8433](https://github.com/stallion-tech/react-native-stallion/commit/d4d84335409ef9b8b4eb5c223ef5217f4d0cd54f)), closes [#49](https://github.com/stallion-tech/react-native-stallion/issues/49)
- resume download Android (v2.2.0) ([647a69f](https://github.com/stallion-tech/react-native-stallion/commit/647a69fdc70b913e7838a6c995c8d103e15b1c92)), closes [#32](https://github.com/stallion-tech/react-native-stallion/issues/32) [#38](https://github.com/stallion-tech/react-native-stallion/issues/38) [#41](https://github.com/stallion-tech/react-native-stallion/issues/41) [#42](https://github.com/stallion-tech/react-native-stallion/issues/42)

# [2.2.0-alpha.1](https://github.com/stallion-tech/react-native-stallion/compare/v2.1.0...v2.2.0-alpha.1) (2025-05-11)

### Bug Fixes

- ios stage event typo ([c0c9bdb](https://github.com/stallion-tech/react-native-stallion/commit/c0c9bdbc4d15cad7934559fbef6a397dde4a6c50))
- modifed event emitter init, added fallback for mounting prod bundle ([#32](https://github.com/stallion-tech/react-native-stallion/issues/32)) ([f888820](https://github.com/stallion-tech/react-native-stallion/commit/f888820305f57bc76649673d289ff15949558ab8))
- removed stallion enabled script reading logic from native, enabled by default ([ab3f0d4](https://github.com/stallion-tech/react-native-stallion/commit/ab3f0d4ba6d20f4277b0611c9a6783d49e44cb3f))

### Features

- added stream downloading for android ([#42](https://github.com/stallion-tech/react-native-stallion/issues/42)) ([3636acd](https://github.com/stallion-tech/react-native-stallion/commit/3636acd4d48c4ae2e5f5659e4f0a31239f745d4b))
- restart logic, ui revamp v0, ios sync and other bugfixes ([70b8067](https://github.com/stallion-tech/react-native-stallion/commit/70b806753d2a3784686b93ebe15eef802d2665e8))
- resume download android ([1471b57](https://github.com/stallion-tech/react-native-stallion/commit/1471b5780608df29437fbe8048205fb3537d2859))

# [2.1.0-alpha.3](https://github.com/stallion-tech/react-native-stallion/compare/v2.1.0-alpha.2...v2.1.0-alpha.3) (2025-05-11)

# [2.1.0](https://github.com/stallion-tech/react-native-stallion/compare/v2.0.1...v2.1.0) (2025-05-05)
Expand Down
25 changes: 25 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import groovy.json.JsonSlurper

buildscript {
repositories {
google()
Expand Down Expand Up @@ -30,6 +32,22 @@ def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Stallion_" + name]).toInteger()
}

def getSdkVersionFromPackageJson() {
try {
def pkgFile = new File(projectDir.parentFile, "package.json")
if (!pkgFile.exists()) {
logger.lifecycle("Stallion: package.json not found at ${pkgFile.absolutePath}, defaulting to 0.0.0")
return "0.0.0"
}
def json = new JsonSlurper().parseText(pkgFile.text)
def version = (json?.version ?: "0.0.0").toString()
logger.lifecycle("Stallion: Resolved SDK version ${version} from ${pkgFile.absolutePath}")
return version
} catch (Throwable ignored) {
return "0.0.0"
}
}

def stallionEnabled = true

android {
Expand All @@ -48,6 +66,7 @@ android {
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
buildConfigField "String", "STALLION_SDK_VERSION", "\"${getSdkVersionFromPackageJson()}\""
}
buildTypes {
release {
Expand All @@ -64,6 +83,12 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}

externalNativeBuild {
cmake {
path file("src/main/cpp/CMakeLists.txt")
}
}

}

repositories {
Expand Down
19 changes: 19 additions & 0 deletions android/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.10.2)

project(stallion_crash)

add_library(
stallion-crash
SHARED
stallion_signal_handler.cpp
)

find_library(
log-lib
log
)

target_link_libraries(
stallion-crash
${log-lib}
)
91 changes: 91 additions & 0 deletions android/src/main/cpp/stallion_signal_handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <jni.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>

static char g_marker_path[512];
static char g_mount_marker_path[512];
static struct sigaction g_previous_handlers[32]; // Store previous handlers for chaining

// Async-signal-safe function to check if mount marker exists
static int is_mounted() {
int fd = open(g_mount_marker_path, O_RDONLY);
if (fd >= 0) {
close(fd);
return 1; // Mounted
}
return 0; // Not mounted
}

// Async-signal-safe JSON writing (minimal JSON for crash marker)
static void write_crash_marker_json(int signal, int mounted) {
int fd = open(g_marker_path, O_CREAT | O_WRONLY | O_TRUNC, 0600);
if (fd >= 0) {
// Write JSON: {"signal":X,"isAutoRollback":true/false,"crashLog":"signal=X\n"}
// isAutoRollback = !mounted (auto rollback if not mounted)
int autoRollback = !mounted;
char json[512];
int len = snprintf(json, sizeof(json),
"{\"signal\":%d,\"isAutoRollback\":%s,\"crashLog\":\"signal=%d\\n\"}",
signal, autoRollback ? "true" : "false", signal);
if (len > 0 && len < (int)sizeof(json)) {
(void)write(fd, json, len);
}
close(fd);
}
}

static void stallion_signal_handler(int sig, siginfo_t *info, void *context) {
// Read mount state at crash time (async-signal-safe)
int mounted = is_mounted();
// Write JSON marker with crash info and autoRollback flag
write_crash_marker_json(sig, mounted);

// Chain to previous handler if it exists and is valid (bubble up)
if (sig >= 0 && sig < 32) {
struct sigaction *prev = &g_previous_handlers[sig];
if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN && prev->sa_handler != NULL) {
// Prevent infinite loop - don't call ourselves
if (prev->sa_sigaction != stallion_signal_handler) {
if (prev->sa_flags & SA_SIGINFO) {
prev->sa_sigaction(sig, info, context);
} else if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN) {
prev->sa_handler(sig);
}
}
}
}

// Restore default and raise to proceed with crash
signal(sig, SIG_DFL);
raise(sig);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_stallion_utils_StallionExceptionHandler_initNativeSignalHandler(
JNIEnv* env, jclass, jstring filesDir) {
const char* path = env->GetStringUTFChars(filesDir, nullptr);
snprintf(g_marker_path, sizeof(g_marker_path), "%s/%s", path, "stallion_crash.marker");
snprintf(g_mount_marker_path, sizeof(g_mount_marker_path), "%s/%s", path, "stallion_mount.marker");
env->ReleaseStringUTFChars(filesDir, path);

// Use sigaction instead of signal for better handler chaining
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = stallion_signal_handler;

int signals[] = {SIGABRT, SIGSEGV, SIGILL, SIGBUS, SIGFPE};
int signalCount = sizeof(signals) / sizeof(signals[0]);

for (int i = 0; i < signalCount; i++) {
int sig = signals[i];
// Store previous handler before installing ours (for chaining)
sigaction(sig, NULL, &g_previous_handlers[sig]);
// Now install our handler
sigaction(sig, &action, NULL);
}
}
2 changes: 0 additions & 2 deletions android/src/main/java/com/stallion/Stallion.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ public static String getJSBundleFile(Context applicationContext, String defaultB

validateAppVersion(stateManager.getStallionConfig().getAppVersion());

StallionEventManager.init(stateManager);

String baseFolderPath = stateManager.getStallionConfig().getFilesDirectory();
StallionMeta stallionMeta = stateManager.stallionMeta;
StallionMetaConstants.SwitchState switchState = stallionMeta.getSwitchState();
Expand Down
38 changes: 37 additions & 1 deletion android/src/main/java/com/stallion/StallionModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.stallion.events.StallionEventConstants;
import com.stallion.events.StallionEventManager;
import com.stallion.networkmanager.StallionStageManager;
import com.stallion.networkmanager.StallionSyncHandler;
Expand All @@ -21,6 +22,7 @@

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -34,7 +36,6 @@ public StallionModule(ReactApplicationContext reactContext) {
super(reactContext);
StallionStateManager.init(reactContext);
this.stallionStateManager = StallionStateManager.getInstance();
StallionEventManager.init(this.stallionStateManager);
reactContext.addLifecycleEventListener(this);
}

Expand All @@ -60,12 +61,23 @@ public String getName() {

@ReactMethod
public void onLaunch(String launchData) {
// try {
// JSONObject launchDataJson = new JSONObject(launchData);
// } catch (Exception e) {
// e.printStackTrace();
// }
stallionStateManager.setIsMounted(true);
DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter = getReactApplicationContext().getJSModule(
DeviceEventManagerModule.RCTDeviceEventEmitter.class
);
StallionEventManager.getInstance().setEmitter(eventEmitter);
checkPendingDownloads();
String currentReleaseHash = stallionStateManager.stallionMeta.getHashAtCurrentProdSlot();
if(!currentReleaseHash.isEmpty() && stallionStateManager.stallionMeta.getSuccessfulLaunchCount(currentReleaseHash) == 0) {
emitInstallEvent(currentReleaseHash);
}
stallionStateManager.stallionMeta.markSuccessfulLaunch(currentReleaseHash);
stallionStateManager.syncStallionMeta();
}

private void checkPendingDownloads() {
Expand Down Expand Up @@ -167,4 +179,28 @@ public void acknowledgeEvents(String eventIdsJson, Promise promise) {
public void restart() {
ProcessPhoenix.triggerRebirth(getReactApplicationContext());
}

@ReactMethod
public void addListener(String eventName) {
// No-op: required for RN event emitter contract
}

@ReactMethod
public void removeListeners(double count) {
// No-op: required for RN event emitter contract
}

private void emitInstallEvent(String releaseHash) {
try {
JSONObject eventPayload = new JSONObject();
eventPayload.put("releaseHash", releaseHash);

StallionEventManager.getInstance().sendEventWithoutCaching(
StallionEventConstants.NativeProdEventTypes.INSTALLED_PROD.toString(),
eventPayload
);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public class StallionEventConstants {
public enum NativeProdEventTypes {
DOWNLOAD_STARTED_PROD,
DOWNLOAD_PROGRESS_PROD,
DOWNLOAD_RESUME_PROD,
DOWNLOAD_ERROR_PROD,
DOWNLOAD_COMPLETE_PROD,
Expand All @@ -13,7 +14,8 @@ public enum NativeProdEventTypes {
EXCEPTION_PROD,
AUTO_ROLLED_BACK_PROD,
CORRUPTED_FILE_ERROR,
FILE_MOUNTING_ERROR
FILE_MOUNTING_ERROR,
SIGNATURE_VERIFICATION_FAILED
}

public enum NativeStageEventTypes {
Expand Down
Loading