diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 1edf34e..50b9799 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -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 diff --git a/.gitignore b/.gitignore index 0ad7f7d..3ca7ea2 100644 --- a/.gitignore +++ b/.gitignore @@ -71,4 +71,6 @@ lib/ .npmrc -sdk-package \ No newline at end of file +sdk-package + +ios/main/StallionVersion.h \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c9fd8f1..0dab2e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -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) diff --git a/android/build.gradle b/android/build.gradle index 6ce3b50..dfe5d69 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,3 +1,5 @@ +import groovy.json.JsonSlurper + buildscript { repositories { google() @@ -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 { @@ -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 { @@ -64,6 +83,12 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } + externalNativeBuild { + cmake { + path file("src/main/cpp/CMakeLists.txt") + } + } + } repositories { diff --git a/android/src/main/cpp/CMakeLists.txt b/android/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..a634828 --- /dev/null +++ b/android/src/main/cpp/CMakeLists.txt @@ -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} +) diff --git a/android/src/main/cpp/stallion_signal_handler.cpp b/android/src/main/cpp/stallion_signal_handler.cpp new file mode 100644 index 0000000..63d7fd4 --- /dev/null +++ b/android/src/main/cpp/stallion_signal_handler.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +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); + } +} diff --git a/android/src/main/java/com/stallion/Stallion.java b/android/src/main/java/com/stallion/Stallion.java index d613008..d8a3984 100644 --- a/android/src/main/java/com/stallion/Stallion.java +++ b/android/src/main/java/com/stallion/Stallion.java @@ -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(); diff --git a/android/src/main/java/com/stallion/StallionModule.java b/android/src/main/java/com/stallion/StallionModule.java index 8d84401..a0736e6 100644 --- a/android/src/main/java/com/stallion/StallionModule.java +++ b/android/src/main/java/com/stallion/StallionModule.java @@ -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; @@ -21,6 +22,7 @@ import org.json.JSONArray; import org.json.JSONException; +import org.json.JSONObject; import java.util.ArrayList; import java.util.List; @@ -34,7 +36,6 @@ public StallionModule(ReactApplicationContext reactContext) { super(reactContext); StallionStateManager.init(reactContext); this.stallionStateManager = StallionStateManager.getInstance(); - StallionEventManager.init(this.stallionStateManager); reactContext.addLifecycleEventListener(this); } @@ -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() { @@ -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(); + } + } } diff --git a/android/src/main/java/com/stallion/events/StallionEventConstants.java b/android/src/main/java/com/stallion/events/StallionEventConstants.java index 49c96ed..730fbde 100644 --- a/android/src/main/java/com/stallion/events/StallionEventConstants.java +++ b/android/src/main/java/com/stallion/events/StallionEventConstants.java @@ -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, @@ -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 { diff --git a/android/src/main/java/com/stallion/events/StallionEventManager.java b/android/src/main/java/com/stallion/events/StallionEventManager.java index ca3230e..060624a 100644 --- a/android/src/main/java/com/stallion/events/StallionEventManager.java +++ b/android/src/main/java/com/stallion/events/StallionEventManager.java @@ -1,6 +1,7 @@ package com.stallion.events; import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.stallion.BuildConfig; import com.stallion.storage.StallionConfig; import com.stallion.storage.StallionConfigConstants; import com.stallion.storage.StallionStateManager; @@ -18,20 +19,20 @@ public class StallionEventManager { public static final String STALLION_NATIVE_EVENT_NAME = "STALLION_NATIVE_EVENT"; private static final String EVENTS_KEY = "stored_events"; private static final int MAX_BATCH_COUNT_SIZE = 9; + private static final int MAX_EVENT_STORAGE_LIMIT = 60; private static StallionEventManager instance; - private final StallionStateManager stallionStateManager; private final AtomicReference eventEmitterRef = new AtomicReference<>(); // Private constructor for Singleton - private StallionEventManager(StallionStateManager stateManager) { - this.stallionStateManager = stateManager; + private StallionEventManager() { + } // Singleton initialization method - public static synchronized void init(StallionStateManager stateManager) { + public static synchronized void init() { if (instance == null) { - instance = new StallionEventManager(stateManager); + instance = new StallionEventManager(); } } @@ -56,7 +57,8 @@ public void sendEventWithoutCaching(String eventName, JSONObject eventPayload) { eventPayload.put("type", eventName); DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter = eventEmitterRef.get(); // Emit the event to React Native - if (eventEmitter != null && stallionStateManager.getIsMounted()) { + StallionStateManager stateManager = StallionStateManager.getInstance(); + if (eventEmitter != null && stateManager.getIsMounted()) { eventEmitter.emit(STALLION_NATIVE_EVENT_NAME, eventPayload.toString()); } @@ -68,7 +70,8 @@ public void sendEventWithoutCaching(String eventName, JSONObject eventPayload) { // Method to send an event public void sendEvent(String eventName, JSONObject eventPayload) { try { - StallionConfig stallionConfig = this.stallionStateManager.getStallionConfig(); + StallionStateManager stateManager = StallionStateManager.getInstance(); + StallionConfig stallionConfig = stateManager.getStallionConfig(); // Generate a unique ID for the event String uniqueId = UUID.randomUUID().toString(); @@ -76,10 +79,11 @@ public void sendEvent(String eventName, JSONObject eventPayload) { DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter = eventEmitterRef.get(); // Emit the event to React Native - if (eventEmitter != null && stallionStateManager.getIsMounted()) { + if (eventEmitter != null && stateManager.getIsMounted()) { eventEmitter.emit(STALLION_NATIVE_EVENT_NAME, eventPayload.toString()); } + // change type for sending to server eventPayload.remove("type"); eventPayload.put("eventType", eventName); @@ -91,6 +95,7 @@ public void sendEvent(String eventName, JSONObject eventPayload) { eventPayload.put("platform", StallionConfigConstants.PLATFORM); eventPayload.put("appVersion", stallionConfig.getAppVersion()); eventPayload.put("uid", stallionConfig.getUid()); + eventPayload.put("sdkVersion", BuildConfig.STALLION_SDK_VERSION); // Store the event locally storeEventLocally(uniqueId, eventPayload); @@ -103,10 +108,17 @@ public void sendEvent(String eventName, JSONObject eventPayload) { // Store the event locally in SharedPreferences private void storeEventLocally(String uniqueId, JSONObject eventPayload) { try { - String eventsString = stallionStateManager.getString(EVENTS_KEY, "{}"); + StallionStateManager stateManager = StallionStateManager.getInstance(); + String eventsString = stateManager.getString(EVENTS_KEY, "{}"); JSONObject eventsObject = new JSONObject(eventsString); + + // Flush all if limit reached + if (eventsObject.length() >= MAX_EVENT_STORAGE_LIMIT) { + eventsObject = new JSONObject(); // reset + } + eventsObject.put(uniqueId, eventPayload.toString()); - stallionStateManager.setString(EVENTS_KEY, eventsObject.toString()); + stateManager.setString(EVENTS_KEY, eventsObject.toString()); } catch (JSONException e) { cleanupEventStorage(); e.printStackTrace(); @@ -114,13 +126,15 @@ private void storeEventLocally(String uniqueId, JSONObject eventPayload) { } private void cleanupEventStorage() { - stallionStateManager.setString(EVENTS_KEY, "{}"); + StallionStateManager stateManager = StallionStateManager.getInstance(); + stateManager.setString(EVENTS_KEY, "{}"); } // Method to pop events as a batch public String popEvents() { try { - String eventsString = stallionStateManager.getString(EVENTS_KEY, "{}"); + StallionStateManager stateManager = StallionStateManager.getInstance(); + String eventsString = stateManager.getString(EVENTS_KEY, "{}"); JSONObject eventsObject = new JSONObject(eventsString); JSONArray batch = new JSONArray(); @@ -146,7 +160,8 @@ public String popEvents() { // Acknowledge events by deleting them from local storage public void acknowledgeEvents(List eventIds) { try { - String eventsString = stallionStateManager.getString(EVENTS_KEY, "{}"); + StallionStateManager stateManager = StallionStateManager.getInstance(); + String eventsString = stateManager.getString(EVENTS_KEY, "{}"); JSONObject eventsObject = new JSONObject(eventsString); // Remove each event by its unique ID @@ -157,7 +172,7 @@ public void acknowledgeEvents(List eventIds) { } // Update the SharedPreferences with the modified events - stallionStateManager.setString(EVENTS_KEY, eventsObject.toString()); + stateManager.setString(EVENTS_KEY, eventsObject.toString()); } catch (JSONException e) { e.printStackTrace(); diff --git a/android/src/main/java/com/stallion/networkmanager/StallionFileDownloader.java b/android/src/main/java/com/stallion/networkmanager/StallionFileDownloader.java index 6a7f8a7..1dc98a1 100644 --- a/android/src/main/java/com/stallion/networkmanager/StallionFileDownloader.java +++ b/android/src/main/java/com/stallion/networkmanager/StallionFileDownloader.java @@ -3,10 +3,8 @@ import android.os.StatFs; import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.net.HttpURLConnection; @@ -25,6 +23,7 @@ public class StallionFileDownloader { private static final String TAG = "StallionFileDownloader"; private static final ExecutorService executor = Executors.newSingleThreadExecutor(); + private static final long DEFAULT_PROGRESS_THROTTLE_INTERVAL_MS = 300L; public static void downloadBundle( String downloadUrl, @@ -125,7 +124,7 @@ private static void downloadFile( long totalBytes = connection.getContentLength() + alreadyDownloaded; long receivedBytes = alreadyDownloaded; int bytesRead; - double lastProgress = (double) receivedBytes / totalBytes; + long lastProgressEmitTimeMs = 0L; // Ensure totalBytes is valid if (totalBytes <= 0) { @@ -145,8 +144,8 @@ private static void downloadFile( return; } - if (progress - lastProgress >= 0.1) { - lastProgress = progress; + if (shouldEmitProgress(lastProgressEmitTimeMs, DEFAULT_PROGRESS_THROTTLE_INTERVAL_MS)) { + lastProgressEmitTimeMs = System.currentTimeMillis(); callback.onProgress(progress); } } @@ -194,6 +193,10 @@ private static HttpURLConnection setupConnection( return connection; } + private static boolean shouldEmitProgress(long lastEmitTimeMs, long intervalMs) { + return System.currentTimeMillis() - lastEmitTimeMs >= intervalMs; + } + private static void validateAndUnzip( File downloadedZip, String destDirectory, diff --git a/android/src/main/java/com/stallion/networkmanager/StallionSyncHandler.java b/android/src/main/java/com/stallion/networkmanager/StallionSyncHandler.java index de3236b..4ec70ad 100644 --- a/android/src/main/java/com/stallion/networkmanager/StallionSyncHandler.java +++ b/android/src/main/java/com/stallion/networkmanager/StallionSyncHandler.java @@ -1,14 +1,20 @@ package com.stallion.networkmanager; +import com.stallion.events.StallionEventConstants; import com.stallion.events.StallionEventManager; import com.stallion.storage.StallionConfigConstants; import com.stallion.storage.StallionMetaConstants; import com.stallion.storage.StallionStateManager; import com.stallion.storage.StallionConfig; +import com.stallion.utils.StallionDeviceInfo; +import com.stallion.utils.StallionFileManager; +import com.stallion.utils.StallionSignatureVerification; import com.stallion.utils.StallionSlotManager; import com.stallion.events.StallionEventConstants.NativeProdEventTypes; import org.json.JSONObject; + +import java.io.File; import java.util.concurrent.atomic.AtomicBoolean; public class StallionSyncHandler { @@ -39,6 +45,8 @@ public static void sync() { requestPayload.put("platform", "android"); requestPayload.put("projectId", projectId); requestPayload.put("appliedBundleHash", appliedBundleHash); + // Attach device metadata for analytics + requestPayload.put("deviceMeta", StallionDeviceInfo.getDeviceMetaJson(config)); // Make API call using StallionApiManager JSONObject releaseMeta = StallionApiManager.post( @@ -48,7 +56,7 @@ public static void sync() { // Process API response processReleaseMeta(releaseMeta, appVersion); - + stateManager.setIsSyncSuccessful(true); } catch (Exception e) { emitSyncError(e); } finally { @@ -85,11 +93,13 @@ private static void handleNewReleaseData(JSONObject newReleaseData) { StallionStateManager stateManager = StallionStateManager.getInstance(); String lastRolledBackHash = stateManager.stallionMeta.getLastRolledBackHash(); + String lastUnverifiedHash = stateManager.getStallionConfig().getLastUnverifiedHash(); if ( - !newReleaseHash.isEmpty() - && !newReleaseUrl.isEmpty() - && !newReleaseHash.equals(lastRolledBackHash) + !newReleaseHash.isEmpty() + && !newReleaseUrl.isEmpty() + && !newReleaseHash.equals(lastRolledBackHash) + && !newReleaseHash.equals(lastUnverifiedHash) ) { if(stateManager.getIsMounted()) { downloadNewRelease(newReleaseHash, newReleaseUrl); @@ -112,6 +122,7 @@ public static void downloadNewRelease(String newReleaseHash, String newReleaseUr + StallionConfigConstants.TEMP_FOLDER_SLOT; String projectId = config.getProjectId(); String downloadUrl = newReleaseUrl + "?projectId=" + projectId; + String publicSigningKey = config.getPublicSigningKey(); long alreadyDownloaded = StallionDownloadCacheManager.getDownloadCache(config, downloadUrl, downloadPath); @@ -131,6 +142,22 @@ public void onReject(String prefix, String error) { @Override public void onSuccess(String successPayload) { isDownloadInProgress.set(false); + StallionDownloadCacheManager.deleteDownloadCache(downloadPath); + + if(publicSigningKey != null && !publicSigningKey.isEmpty()) { + if( + !StallionSignatureVerification.verifyReleaseSignature( + downloadPath + StallionConfigConstants.UNZIP_FOLDER_NAME, + publicSigningKey) + ) { + // discard the downloaded release + config.setLastUnverifiedHash(newReleaseHash); + emitSignatureVerificationFailed(newReleaseHash); + StallionFileManager.deleteFileOrFolderSilently(new File(downloadPath)); + return; + } + } + stateManager.stallionMeta.setCurrentProdSlot(StallionMetaConstants.SlotStates.NEW_SLOT); stateManager.stallionMeta.setProdTempHash(newReleaseHash); String currentProdNewHash = stateManager.stallionMeta.getProdNewHash(); @@ -138,13 +165,13 @@ public void onSuccess(String successPayload) { StallionSlotManager.stabilizeProd(); } stateManager.syncStallionMeta(); - StallionDownloadCacheManager.deleteDownloadCache(downloadPath); emitDownloadSuccess(newReleaseHash); } @Override public void onProgress(double downloadFraction) { // Optional: Handle progress updates + emitDownloadProgressProd(newReleaseHash, downloadFraction); } } ); @@ -153,6 +180,18 @@ public void onProgress(double downloadFraction) { } } + private static void emitDownloadProgressProd(String releaseHash, double newProgress) { + JSONObject successPayload = new JSONObject(); + try { + successPayload.put("releaseHash", releaseHash); + successPayload.put("progress", String.valueOf(newProgress)); + } catch (Exception ignored) { } + StallionEventManager.getInstance().sendEventWithoutCaching( + StallionEventConstants.NativeProdEventTypes.DOWNLOAD_PROGRESS_PROD.toString(), + successPayload + ); + } + private static void emitSyncError(Exception e) { JSONObject syncErrorPayload = new JSONObject(); try { @@ -198,4 +237,14 @@ private static void emitDownloadStarted(String releaseHash, Boolean isResume) { successPayload ); } + private static void emitSignatureVerificationFailed(String releaseHash) { + JSONObject successPayload = new JSONObject(); + try { + successPayload.put("releaseHash", releaseHash); + } catch (Exception ignored) { } + StallionEventManager.getInstance().sendEvent( + NativeProdEventTypes.SIGNATURE_VERIFICATION_FAILED.toString(), + successPayload + ); + } } diff --git a/android/src/main/java/com/stallion/storage/StallionConfig.java b/android/src/main/java/com/stallion/storage/StallionConfig.java index 0b0d8e9..cc5d704 100644 --- a/android/src/main/java/com/stallion/storage/StallionConfig.java +++ b/android/src/main/java/com/stallion/storage/StallionConfig.java @@ -20,6 +20,9 @@ public class StallionConfig { private final SharedPreferences sharedPreferences; private final String filesDirectory; private String lastDownloadingUrl; + private String lastUnverifiedHash; + private final String publicSigningKey; + public StallionConfig(Context context, SharedPreferences sharedPreferences) { this.sharedPreferences = sharedPreferences; @@ -32,6 +35,7 @@ public StallionConfig(Context context, SharedPreferences sharedPreferences) { parentPackageName ); this.projectId = stallionProjectIdRes != 0 ?context.getString(stallionProjectIdRes) : ""; + int stallionAppTokenRes = res.getIdentifier( StallionConfigConstants.STALLION_APP_TOKEN_IDENTIFIER, "string", @@ -39,6 +43,13 @@ public StallionConfig(Context context, SharedPreferences sharedPreferences) { ); this.appToken = stallionAppTokenRes != 0 ? context.getString(stallionAppTokenRes) : ""; + int stallionPublicKeyRes = res.getIdentifier( + StallionConfigConstants.STALLION_PUBLIC_SIGNING_KEY_IDENTIFIER, + "string", + parentPackageName + ); + this.publicSigningKey = stallionPublicKeyRes != 0 ? context.getString(stallionPublicKeyRes) : ""; + // get or generate UID String cachedUniqueId = sharedPreferences.getString( StallionConfigConstants.UNIQUE_ID_IDENTIFIER, @@ -65,6 +76,7 @@ public StallionConfig(Context context, SharedPreferences sharedPreferences) { this.appVersion = fetchAppVersion(context); this.filesDirectory = context.getFilesDir().getAbsolutePath(); this.lastDownloadingUrl = sharedPreferences.getString(StallionConfigConstants.LAST_DOWNLOADING_URL_IDENTIFIER, ""); + this.lastUnverifiedHash = sharedPreferences.getString(StallionConfigConstants.LAST_UNVERIFIED_HASH, ""); } public String getLastDownloadingUrl() { @@ -78,6 +90,17 @@ public void setLastDownloadingUrl(String newUrl) { editor.apply(); } + public String getLastUnverifiedHash() { + return this.lastUnverifiedHash; + } + + public void setLastUnverifiedHash(String newUnverifiedHash) { + this.lastUnverifiedHash = newUnverifiedHash; + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(StallionConfigConstants.LAST_UNVERIFIED_HASH, newUnverifiedHash); + editor.apply(); + } + private String fetchAppVersion(Context context) { try { PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); @@ -96,12 +119,10 @@ public String getProjectId() { } public void updateSdkToken(String newApiKey) { - if(!newApiKey.isEmpty()) { this.sdkToken = newApiKey; SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(StallionConfigConstants.API_KEY_IDENTIFIER, this.sdkToken); editor.apply(); - } } public String getAppToken() { @@ -118,6 +139,10 @@ public String getUid() { public String getFilesDirectory() { return this.filesDirectory; } + public String getPublicSigningKey() { + return this.publicSigningKey; + } + public JSONObject toJSON() { JSONObject configJson = new JSONObject(); try { diff --git a/android/src/main/java/com/stallion/storage/StallionConfigConstants.java b/android/src/main/java/com/stallion/storage/StallionConfigConstants.java index e457828..839b921 100644 --- a/android/src/main/java/com/stallion/storage/StallionConfigConstants.java +++ b/android/src/main/java/com/stallion/storage/StallionConfigConstants.java @@ -7,9 +7,11 @@ public class StallionConfigConstants { public static final String STALLION_PROJECT_ID_IDENTIFIER = "StallionProjectId"; public static final String STALLION_APP_TOKEN_IDENTIFIER = "StallionAppToken"; + public static final String STALLION_PUBLIC_SIGNING_KEY_IDENTIFIER = "StallionPublicSigningKey"; public static final String UNIQUE_ID_IDENTIFIER = "stallionDeviceId"; public static final String API_KEY_IDENTIFIER = "x-sdk-access-token"; public static final String LAST_DOWNLOADING_URL_IDENTIFIER = "StallionLastDownloadingUrl"; + public static final String LAST_UNVERIFIED_HASH = "LastUnverifiedHash"; public static final String PROD_DIRECTORY = "/StallionProd"; public static final String STAGE_DIRECTORY = "/StallionStage"; diff --git a/android/src/main/java/com/stallion/storage/StallionMeta.java b/android/src/main/java/com/stallion/storage/StallionMeta.java index 914a7bf..24ee171 100644 --- a/android/src/main/java/com/stallion/storage/StallionMeta.java +++ b/android/src/main/java/com/stallion/storage/StallionMeta.java @@ -14,6 +14,12 @@ public class StallionMeta { private String prodNewHash; private String prodStableHash; private String lastRolledBackHash; + private long lastRolledBackAt; + private int successfulLaunchCount; + private String lastSuccessfulLaunchHash; + + public static final int MAX_SUCCESS_LAUNCH_THRESHOLD = 3; + public static final long LAST_ROLLED_BACK_TTL_MS = 6L * 60L * 60L * 1000L; // 6 hours public StallionMeta() { this.reset(); @@ -29,6 +35,9 @@ public void reset() { this.prodNewHash = ""; this.prodStableHash = ""; this.lastRolledBackHash = ""; + this.lastRolledBackAt = 0L; + this.successfulLaunchCount = 0; + this.lastSuccessfulLaunchHash = ""; } // Getters and Setters @@ -121,11 +130,13 @@ public void setProdStableHash(String prodStableHash) { } public String getLastRolledBackHash() { + enforceLastRolledBackExpiry(); return lastRolledBackHash; } public void setLastRolledBackHash(String lastRolledBackHash) { - this.lastRolledBackHash = lastRolledBackHash; + this.lastRolledBackHash = lastRolledBackHash == null ? "" : lastRolledBackHash; + this.lastRolledBackAt = this.lastRolledBackHash.isEmpty() ? 0L : System.currentTimeMillis(); } // Convert to JSON @@ -148,6 +159,9 @@ public JSONObject toJSON() { metaJson.put("prodSlot", prodJson); metaJson.put("lastRolledBackHash", lastRolledBackHash); + metaJson.put("lastRolledBackAt", lastRolledBackAt); + metaJson.put("successfulLaunchCount", successfulLaunchCount); + metaJson.put("lastSuccessfulLaunchHash", lastSuccessfulLaunchHash); } catch (JSONException e) { return new JSONObject(); @@ -169,6 +183,9 @@ public static StallionMeta fromJSON(JSONObject jsonObject) { ); stallionMeta.setLastRolledBackHash(jsonObject.optString("lastRolledBackHash", "")); + stallionMeta.lastRolledBackAt = jsonObject.optLong("lastRolledBackAt", 0L); + stallionMeta.successfulLaunchCount = jsonObject.optInt("successfulLaunchCount", 0); + stallionMeta.lastSuccessfulLaunchHash = jsonObject.optString("lastSuccessfulLaunchHash", ""); JSONObject stageJson = jsonObject.optJSONObject("stageSlot"); if(stageJson != null) { @@ -203,4 +220,38 @@ public static StallionMeta fromJSON(JSONObject jsonObject) { return stallionMeta; } } + + public void markSuccessfulLaunch(String releaseHash) { + if(releaseHash == null || releaseHash.isEmpty()) { + return; + } + if (!releaseHash.equals(this.lastSuccessfulLaunchHash)) { + this.successfulLaunchCount = 0; + this.lastSuccessfulLaunchHash = releaseHash; + } + if (this.successfulLaunchCount < MAX_SUCCESS_LAUNCH_THRESHOLD) { + this.successfulLaunchCount += 1; + } + } + + public int getSuccessfulLaunchCount(String releaseHash) { + String currentHash = releaseHash == null ? "" : releaseHash; + if (!currentHash.equals(this.lastSuccessfulLaunchHash)) { + return 0; + } else return this.successfulLaunchCount; + } + + private void enforceLastRolledBackExpiry() { + if (this.lastRolledBackHash == null || this.lastRolledBackHash.isEmpty()) { + return; + } + if (this.lastRolledBackAt <= 0L) { + return; + } + long now = System.currentTimeMillis(); + if (now - this.lastRolledBackAt >= LAST_ROLLED_BACK_TTL_MS) { + this.lastRolledBackHash = ""; + this.lastRolledBackAt = 0L; + } + } } diff --git a/android/src/main/java/com/stallion/storage/StallionStateManager.java b/android/src/main/java/com/stallion/storage/StallionStateManager.java index 81a7ae1..d1bacae 100644 --- a/android/src/main/java/com/stallion/storage/StallionStateManager.java +++ b/android/src/main/java/com/stallion/storage/StallionStateManager.java @@ -3,6 +3,7 @@ import android.content.Context; import android.content.SharedPreferences; +import com.stallion.events.StallionEventManager; import com.stallion.utils.StallionExceptionHandler; import org.json.JSONException; @@ -20,7 +21,7 @@ public class StallionStateManager { private boolean isMounted; private String pendingReleaseUrl; private String pendingReleaseHash; - + private boolean isSyncSuccessful; private StallionStateManager(Context context) { this.sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); @@ -29,11 +30,15 @@ private StallionStateManager(Context context) { this.isMounted = false; this.pendingReleaseUrl = ""; this.pendingReleaseHash = ""; + + // Reset mount state on initialization (ensures mount marker file is deleted for new session) + setIsMounted(false); } public static synchronized void init(Context context) { if (instance == null) { instance = new StallionStateManager(context); + StallionEventManager.init(); StallionExceptionHandler.initErrorBoundary(); } } @@ -78,6 +83,18 @@ public void clearStallionMeta() { public void setIsMounted(Boolean isMounted) { this.isMounted = isMounted; + // Write mount state to a simple file that C++ can read + String filesDir = getStallionConfig().getFilesDirectory(); + java.io.File mountMarker = new java.io.File(filesDir + "/stallion_mount.marker"); + if (isMounted) { + try { + // Create file to indicate mounted (file existence = mounted) + mountMarker.createNewFile(); + } catch (Exception ignored) {} + } else { + // Delete file to indicate not mounted (no file = not mounted) + mountMarker.delete(); + } } public boolean getIsMounted() { @@ -110,4 +127,8 @@ public String getPendingReleaseUrl() { public String getPendingReleaseHash() { return this.pendingReleaseHash; } + + public boolean getIsSyncSuccessful() { return this.isSyncSuccessful; } + + public void setIsSyncSuccessful(boolean isSyncSuccessful) { this.isSyncSuccessful = isSyncSuccessful; } } diff --git a/android/src/main/java/com/stallion/utils/StallionDeviceInfo.java b/android/src/main/java/com/stallion/utils/StallionDeviceInfo.java new file mode 100644 index 0000000..3699ab2 --- /dev/null +++ b/android/src/main/java/com/stallion/utils/StallionDeviceInfo.java @@ -0,0 +1,83 @@ +package com.stallion.utils; + +import android.os.Build; + +import com.stallion.storage.StallionConfig; + +import org.json.JSONObject; + +import java.util.Locale; +import java.util.TimeZone; + +public class StallionDeviceInfo { + + /** + * Sample JSON contract for deviceMeta + * { + * "osName": "Android", + * "osVersion": "14", + * "sdkInt": 34, + * "manufacturer": "Google", + * "brand": "google", + * "model": "Pixel 7", + * "device": "panther", + * "product": "panther", + * "hardware": "panther", + * "locale": "en-US", + * "localeLanguage": "en", + * "localeCountry": "US", + * "timezone": "America/Los_Angeles", + * "timezoneOffsetMinutes": -420, + * "isEmulator": false, + * "projectId": "", + * "uid": "", + * "appVersion": "1.2.3" + * } + */ + public static JSONObject getDeviceMetaJson(StallionConfig config) { + JSONObject json = new JSONObject(); + try { + json.put("osName", "Android"); + json.put("osVersion", Build.VERSION.RELEASE != null ? Build.VERSION.RELEASE : ""); + json.put("sdkInt", Build.VERSION.SDK_INT); + json.put("manufacturer", Build.MANUFACTURER != null ? Build.MANUFACTURER : ""); + json.put("brand", Build.BRAND != null ? Build.BRAND : ""); + json.put("model", Build.MODEL != null ? Build.MODEL : ""); + json.put("device", Build.DEVICE != null ? Build.DEVICE : ""); + json.put("product", Build.PRODUCT != null ? Build.PRODUCT : ""); + json.put("hardware", Build.HARDWARE != null ? Build.HARDWARE : ""); + Locale defaultLocale = Locale.getDefault(); + json.put("locale", defaultLocale != null ? defaultLocale.toLanguageTag() : ""); + json.put("localeLanguage", defaultLocale != null ? defaultLocale.getLanguage() : ""); + json.put("localeCountry", defaultLocale != null ? defaultLocale.getCountry() : ""); + TimeZone tz = TimeZone.getDefault(); + json.put("timezone", tz != null ? tz.getID() : ""); + json.put("timezoneOffsetMinutes", tz != null ? (tz.getOffset(System.currentTimeMillis()) / 60000) : 0); + json.put("isEmulator", isProbablyEmulator()); + if (config != null) { + json.put("projectId", config.getProjectId()); + json.put("uid", config.getUid()); + json.put("appVersion", config.getAppVersion()); + } + } catch (Exception ignored) { } + return json; + } + + private static boolean isProbablyEmulator() { + String fingerprint = Build.FINGERPRINT; + String model = Build.MODEL; + String manufacturer = Build.MANUFACTURER; + String brand = Build.BRAND; + String device = Build.DEVICE; + String product = Build.PRODUCT; + + if (fingerprint != null && (fingerprint.startsWith("generic") || fingerprint.startsWith("unknown"))) return true; + if (model != null && (model.contains("google_sdk") || model.contains("Emulator") || model.contains("Android SDK built for x86"))) return true; + if (manufacturer != null && manufacturer.contains("Genymotion")) return true; + if (brand != null && brand.startsWith("generic") && device != null && device.startsWith("generic")) return true; + if (product != null && product.equals("google_sdk")) return true; + return false; + } +} + + diff --git a/android/src/main/java/com/stallion/utils/StallionExceptionHandler.java b/android/src/main/java/com/stallion/utils/StallionExceptionHandler.java index 2265a99..55e6288 100644 --- a/android/src/main/java/com/stallion/utils/StallionExceptionHandler.java +++ b/android/src/main/java/com/stallion/utils/StallionExceptionHandler.java @@ -9,41 +9,64 @@ import org.json.JSONObject; +import java.util.concurrent.atomic.AtomicBoolean; + public class StallionExceptionHandler { private static Thread.UncaughtExceptionHandler _androidUncaughtExceptionHandler; private static Thread _exceptionThread; private static Throwable _exceptionThrowable; - private static boolean isErrorBoundaryInitialized = false; + private static final AtomicBoolean isErrorBoundaryInitialized = new AtomicBoolean(false); + private static final AtomicBoolean isNativeSignalsInitialized = new AtomicBoolean(false); + private static final AtomicBoolean hasProcessedNativeCrashMarker = new AtomicBoolean(false); + private static final AtomicBoolean isRollbackPerformed = new AtomicBoolean(false); public static void initErrorBoundary() { - if (isErrorBoundaryInitialized) { + // Use compareAndSet to atomically check and set initialization flag + if (!isErrorBoundaryInitialized.compareAndSet(false, true)) { return; // Prevent multiple initializations } - isErrorBoundaryInitialized = true; + + // Reset rollback flag when initializing exception handler + isRollbackPerformed.set(false); _androidUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { _exceptionThread = thread; _exceptionThrowable = throwable; - // Safely trim the stack trace string - String stackTraceString = Log.getStackTraceString(throwable); - stackTraceString = stackTraceString.length() > 900 - ? stackTraceString.substring(0, 900) + "..." - : stackTraceString; - - StallionStateManager stateManager = StallionStateManager.getInstance(); - StallionMetaConstants.SwitchState switchState = stateManager.stallionMeta.getSwitchState(); - - if (switchState == StallionMetaConstants.SwitchState.PROD) { - handleProdState(stackTraceString, stateManager); - } else if (switchState == StallionMetaConstants.SwitchState.STAGE) { - handleStageState(stackTraceString, stateManager); - } else { + try { + // Safely trim the stack trace string + String stackTraceString = Log.getStackTraceString(throwable); + stackTraceString = stackTraceString.length() > 900 + ? stackTraceString.substring(0, 900) + "..." + : stackTraceString; + + StallionStateManager stateManager = StallionStateManager.getInstance(); + StallionMetaConstants.SwitchState switchState = stateManager.stallionMeta.getSwitchState(); + + if (switchState == StallionMetaConstants.SwitchState.PROD) { + handleProdState(stackTraceString, stateManager); + } else if (switchState == StallionMetaConstants.SwitchState.STAGE) { + handleStageState(stackTraceString, stateManager); + } else { + continueExceptionFlow(); + } + } catch (Exception e) { + // If anything goes wrong in our handler, ensure we still chain to previous handler continueExceptionFlow(); } }); + + // Initialize native signal handler once and process any prior crash marker + try { + if (isNativeSignalsInitialized.compareAndSet(false, true)) { + System.loadLibrary("stallion-crash"); + String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory(); + initNativeSignalHandler(filesDir); + } + processNativeCrashMarkerIfPresent(); + } catch (Throwable ignored) {} } private static void emitException(String stackTraceString, String releaseHash, boolean isAutoRollback, boolean isProd) { @@ -52,27 +75,43 @@ private static void emitException(String stackTraceString, String releaseHash, b syncErrorPayload.put("meta", stackTraceString); syncErrorPayload.put("releaseHash", releaseHash); syncErrorPayload.put("isAutoRollback", Boolean.toString(isAutoRollback)); + StallionEventManager.getInstance().sendEvent( + isProd ? + StallionEventConstants.NativeProdEventTypes.EXCEPTION_PROD.toString() + : StallionEventConstants.NativeStageEventTypes.EXCEPTION_STAGE.toString(), + syncErrorPayload + ); } catch (Exception ignored) { } - StallionEventManager.getInstance().sendEvent( - isProd ? - StallionEventConstants.NativeProdEventTypes.EXCEPTION_PROD.toString() - : StallionEventConstants.NativeStageEventTypes.EXCEPTION_STAGE.toString(), - syncErrorPayload - ); } private static void handleProdState(String stackTraceString, StallionStateManager stateManager) { boolean isAutoRollback = !stateManager.getIsMounted(); String currentHash = stateManager.stallionMeta.getHashAtCurrentProdSlot(); - // Emit exception event - emitException(stackTraceString, currentHash, isAutoRollback, true); + // Only prevent multiple executions for auto rollback cases + // Launch crashes (when mounted) can continue to be registered + if (isAutoRollback) { + // Use compareAndSet to atomically check and set the flag + if (!isRollbackPerformed.compareAndSet(false, true)) { + // Flag was already true, skip duplicate rollback + continueExceptionFlow(); + return; + } + } + + // Emit exception event (wrap in try-catch to ensure chaining happens) + try { + emitException(stackTraceString, currentHash, isAutoRollback, true); + } catch (Exception ignored) { } // Perform rollback if auto-rollback is enabled if (isAutoRollback) { - StallionSlotManager.rollbackProd(true, stackTraceString); + try { + StallionSlotManager.rollbackProd(true, stackTraceString); + } catch (Exception ignored) { } } + // Always chain to previous handler, even if rollback or emit failed continueExceptionFlow(); } @@ -80,11 +119,29 @@ private static void handleStageState(String stackTraceString, StallionStateManag boolean isAutoRollback = !stateManager.getIsMounted(); String currentStageHash = stateManager.stallionMeta.getStageNewHash(); - // Emit exception event - emitException(stackTraceString, currentStageHash, isAutoRollback, false); + // Only prevent multiple executions for auto rollback cases + // Launch crashes (when mounted) can continue to be registered + if (isAutoRollback) { + // Use compareAndSet to atomically check and set the flag + if (!isRollbackPerformed.compareAndSet(false, true)) { + // Flag was already true, skip duplicate rollback + continueExceptionFlow(); + return; + } + } - StallionSlotManager.rollbackStage(); + // Emit exception event (wrap in try-catch to ensure chaining happens) + try { + emitException(stackTraceString, currentStageHash, isAutoRollback, false); + } catch (Exception ignored) { } + if(isAutoRollback) { + try { + StallionSlotManager.rollbackStage(); + } catch (Exception ignored) { } + } + + // Always chain to previous handler, even if rollback or emit failed continueExceptionFlow(); } @@ -93,4 +150,80 @@ public static void continueExceptionFlow() { _androidUncaughtExceptionHandler.uncaughtException(_exceptionThread, _exceptionThrowable); } } + + private static void processNativeCrashMarkerIfPresent() { + try { + if (hasProcessedNativeCrashMarker.get()) { return; } + String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory(); + java.io.File marker = new java.io.File(filesDir + "/stallion_crash.marker"); + if (marker.exists()) { + StringBuilder sb = new StringBuilder(); + try (java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader(marker))) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + } + } + + String jsonContent = sb.toString(); + String stackTraceString = ""; + boolean isAutoRollback = false; + + try { + // Parse JSON from previous crash + JSONObject crashMarker = new JSONObject(jsonContent); + stackTraceString = crashMarker.optString("crashLog", ""); + // Use the autoRollback flag that was determined at crash time (previous session) + isAutoRollback = crashMarker.optBoolean("isAutoRollback", false); + } catch (org.json.JSONException e) { + // Fallback for old format (non-JSON) + stackTraceString = jsonContent; + // Default to true for old format (conservative approach) + isAutoRollback = true; + } + + if (stackTraceString.length() > 900) { + stackTraceString = stackTraceString.substring(0, 900) + "..."; + } + + StallionStateManager stateManager = StallionStateManager.getInstance(); + StallionMetaConstants.SwitchState switchState = stateManager.stallionMeta.getSwitchState(); + if (switchState == StallionMetaConstants.SwitchState.PROD) { + String currentHash = stateManager.stallionMeta.getHashAtCurrentProdSlot(); + // Use isAutoRollback from previous crash, not current session state + try { + emitException(stackTraceString, currentHash, isAutoRollback, true); + } catch (Exception ignored) { } + if (isAutoRollback) { + // Only prevent multiple executions for auto rollback cases + if (isRollbackPerformed.compareAndSet(false, true)) { + try { + StallionSlotManager.rollbackProd(true, stackTraceString); + } catch (Exception ignored) { } + } + } + } else if (switchState == StallionMetaConstants.SwitchState.STAGE) { + String currentStageHash = stateManager.stallionMeta.getStageNewHash(); + // Use isAutoRollback from previous crash, not current session state + try { + emitException(stackTraceString, currentStageHash, isAutoRollback, false); + } catch (Exception ignored) { } + if (isAutoRollback) { + // Only prevent multiple executions for auto rollback cases + if (isRollbackPerformed.compareAndSet(false, true)) { + try { + StallionSlotManager.rollbackStage(); + } catch (Exception ignored) { } + } + } + } + + // delete marker + StallionFileManager.deleteFileOrFolderSilently(marker); + hasProcessedNativeCrashMarker.set(true); + } + } catch (Exception ignored) {} + } + + private static native void initNativeSignalHandler(String filesDir); } diff --git a/android/src/main/java/com/stallion/utils/StallionSignatureVerification.java b/android/src/main/java/com/stallion/utils/StallionSignatureVerification.java new file mode 100644 index 0000000..8b19825 --- /dev/null +++ b/android/src/main/java/com/stallion/utils/StallionSignatureVerification.java @@ -0,0 +1,129 @@ +package com.stallion.utils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.DigestInputStream; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Scanner; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class StallionSignatureVerification { + + public static final String SIGNATURE_FILE_NAME = ".stallionsigned"; + + public static boolean verifyReleaseSignature(String downloadedBundlePath, String publicKeyPem) { + try { + File folderPath = new File(downloadedBundlePath); + File signatureFile = new File(folderPath, SIGNATURE_FILE_NAME); + if (!signatureFile.exists()) return false; + + String jwt = readFileLegacy(signatureFile); + String[] jwtParts = jwt.split("\\."); + if (jwtParts.length != 3) return false; + + String header = jwtParts[0]; + String payload = jwtParts[1]; + String signature = jwtParts[2]; + + byte[] signatureBytes = base64UrlDecode(signature); + byte[] signedContent = (header + "." + payload).getBytes(StandardCharsets.UTF_8); + + String cleanedPem = publicKeyPem + .replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", "") + .replaceAll("\\s", ""); + + byte[] decodedKey = android.util.Base64.decode(cleanedPem, android.util.Base64.DEFAULT); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey pubKey = keyFactory.generatePublic(keySpec); + + Signature sig = Signature.getInstance("SHA256withRSA"); + sig.initVerify(pubKey); + sig.update(signedContent); + if (!sig.verify(signatureBytes)) return false; + + String jsonPayload = new String(base64UrlDecode(payload), StandardCharsets.UTF_8); + JSONObject payloadObj = new JSONObject(jsonPayload); + String expectedHash = payloadObj.optString("packageHash", ""); + + String actualHash = computeFolderHash(folderPath); + return expectedHash.equals(actualHash); + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private static String computeFolderHash(File folder) throws Exception { + ArrayList manifest = new ArrayList<>(); + addFolderContentsToManifest(folder, "", manifest); + Collections.sort(manifest); + JSONArray jsonArray = new JSONArray(); + for (String entry : manifest) { + jsonArray.put(entry); + } + String jsonString = jsonArray.toString().replace("\\/", "/"); + return computeHash(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8))); + } + + private static void addFolderContentsToManifest(File folder, String pathPrefix, ArrayList manifest) throws Exception { + File[] files = folder.listFiles(); + for (File file : files) { + String fileName = file.getName(); + String relativePath = pathPrefix.isEmpty() ? fileName : pathPrefix + "/" + fileName; + if (isIgnored(relativePath)) continue; + if (file.isDirectory()) { + addFolderContentsToManifest(file, relativePath, manifest); + } else { + manifest.add(relativePath + ":" + computeHash(new FileInputStream(file))); + } + } + } + + private static boolean isIgnored(String path) { + return path.equals(".DS_Store") || path.equals(SIGNATURE_FILE_NAME) || path.startsWith("__MACOSX/"); + } + + private static String computeHash(InputStream stream) throws Exception { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + DigestInputStream dis = new DigestInputStream(stream, digest); + byte[] buffer = new byte[8192]; + while (dis.read(buffer) != -1); + dis.close(); + byte[] hash = digest.digest(); + return String.format("%064x", new java.math.BigInteger(1, hash)); + } + + private static String readFileLegacy(File file) throws IOException { + Scanner scanner = new Scanner(file, "UTF-8"); + StringBuilder sb = new StringBuilder(); + while (scanner.hasNextLine()) { + sb.append(scanner.nextLine()); + } + scanner.close(); + return sb.toString(); + } + + private static byte[] base64UrlDecode(String input) { + String converted = input.replace('-', '+').replace('_', '/'); + switch (converted.length() % 4) { + case 2: converted += "=="; break; + case 3: converted += "="; break; + } + return android.util.Base64.decode(converted, android.util.Base64.NO_WRAP); + } +} diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml index 77588a9..1ae723b 100644 --- a/example/android/app/src/main/res/values/strings.xml +++ b/example/android/app/src/main/res/values/strings.xml @@ -1,5 +1,12 @@ StallionExample 67210b6f3e19d894c6a1a4fb - spb_qQnLqSy5ClKqtCP9lTt28wdfW4QUCUcrvXWgJIh4jA + spb_KLNEjOkETM48i3N1SffGDvEl-OsSiHZrhxER2kq3Ok + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApm9SgaDU9lXLi5OD6sd9 +WpNP8bWeGRzLYOReqH5yuu21kYTDaDt1/+vTpCBNuyX2ZjtKNvKujnAXuWf8Zfj4 +JcWb/r4clDQK0sNy8G7x7s+4Mup6W73lW5AtUnREQZX8IA00lp76r9ii6HYxXTpO +CgHpXyRyPLkMNc+HxaTmDHbldZtRCREcLldI7NnQkFMyZlHK2r1QxiQLpTIEK0vI +IJyXeHOeJUROebZn/UI7UDKiSCvlaHMsJ4pnIAyLrtqFQ8w9rf3aljmYX52m6Rbc +df8fwbWtBCH8OPW5SEDTMDzvE1siAvYwRNxbeXHMrAypPg/DaATdXoKMObjJWRm1 +owIDAQAB diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 094a013..998ea47 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -266,7 +266,7 @@ PODS: - React-jsinspector (0.71.10) - React-logger (0.71.10): - glog - - react-native-stallion (2.0.0): + - react-native-stallion (2.3.0-alpha.5): - React-Core - ZIPFoundation - React-perflogger (0.71.10) @@ -496,7 +496,7 @@ SPEC CHECKSUMS: React-jsiexecutor: 4bb480a183a354e4dbfb1012936b1a2bb9357de7 React-jsinspector: cdc854f8b13abd202afa54bc12578e5afb9cfae1 React-logger: ef2269b3afa6ba868da90496c3e17a4ec4f4cee0 - react-native-stallion: 84fae0abf4ae9bb8316f5cf8905e95b274d9f8b1 + react-native-stallion: 6d3ff7d3423e9f4c61d5ef87d5ba434b06ab45cb React-perflogger: 217095464d5c4bb70df0742fa86bf2a363693468 React-RCTActionSheet: 8deae9b85a4cbc6a2243618ea62a374880a2c614 React-RCTAnimation: 59c62353a8b59ce206044786c5d30e4754bffa64 diff --git a/example/ios/StallionExample/Info.plist b/example/ios/StallionExample/Info.plist index ecf3023..3af465a 100644 --- a/example/ios/StallionExample/Info.plist +++ b/example/ios/StallionExample/Info.plist @@ -3,7 +3,7 @@ StallionAppToken - spb_qQnLqSy5ClKqtCP9lTt28wdfW4QUCUcrvXWgJIh4jA + spb_qLFBKtdR9TBZtsKPDqMXvFD_ebcs-Tdjyc7F4-dX7q StallionProjectId 67210b6f3e19d894c6a1a4fb CFBundleDevelopmentRegion diff --git a/example/package-lock.json b/example/package-lock.json index 86309bd..7ecc498 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -16,7 +16,7 @@ "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "babel-plugin-module-resolver": "^5.0.0", - "stallion-cli": "^1.1.3" + "stallion-cli": "^2.1.0-alpha.1" } }, "node_modules/@ampproject/remapping": { @@ -2172,17 +2172,6 @@ "node": ">=6.9.0" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -2198,6 +2187,455 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@inquirer/checkbox": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.7.tgz", + "integrity": "sha512-VEr2vnI4TSM2Q50fAck98mzWJGAoxbF0rb48tcSEjkJ2kn3mM6c/YsJwnyu45PlXd6aNWObMGWmQVleL2BJy6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.11.tgz", + "integrity": "sha512-HgVha2B1lurfZ8u7cBWmu60HpkpnnIT/1IrreBx5g2oxQOVYU15WQDl6oZqjuXVbzteFKSpmMkLTMf2OmbUjaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.12", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.12.tgz", + "integrity": "sha512-uoaDadeJCYSVKYCMPwJi3AjCF9w+l9aWbHYA4iskKX84cVW/A2M6bJlWBoy3k81GpFp6EX3IElV1Z5xKw0g1QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.12.tgz", + "integrity": "sha512-YNOCY79iqI/ksWohdudGtnO02N/a2j82b6akK/+hy1/C6xoU07dsKFUBfQ36nLCxE98ICS74Uyandq7nBS31Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/type": "^3.0.7", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.14.tgz", + "integrity": "sha512-aon4yACMp4Qwc/2f6xafcC6jzAJ5vXBwL5+z4bS2y4YIOGF+QOe+Jzd5hLz1hOo+bhzVS7q07dNXTeBjaFAqRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/type": "^3.0.7", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", + "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.11.tgz", + "integrity": "sha512-gzcBWLWMiBaY507HFg4B1NJ18InnHhLjj4DTLfyoz9Rv7dSPpJ9JSj7Of8ea5QE2D+ms3ESTl/4MdzrC1//B0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.14.tgz", + "integrity": "sha512-8B4jX8ArK9zvb8/tB04jGLja4XoFfjvrTLJ5YeLlFnJh3jPa9VTQt2kxJZubGKc8YHX68e1XQxv4Nu/WZUnXIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.14.tgz", + "integrity": "sha512-/N/5PeI+QWE23dTn2D4erD9Y3yYeh0bUDkO9tt2d11mAVuCswiOKzoHrV9KYGQhoD6ae+Nff1G8TPqbfUUh8Ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.5.2.tgz", + "integrity": "sha512-+jsUm6G9X5PUD97HkcGojzwyPsz5oSB2FUbj+D+NOYFQUj0XqvhDcDfk9mhMxFG/RDIgT9Kq4x0rm5pC5zVHUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.1.7", + "@inquirer/confirm": "^5.1.11", + "@inquirer/editor": "^4.2.12", + "@inquirer/expand": "^4.0.14", + "@inquirer/input": "^4.1.11", + "@inquirer/number": "^3.0.14", + "@inquirer/password": "^4.0.14", + "@inquirer/rawlist": "^4.1.2", + "@inquirer/search": "^3.0.14", + "@inquirer/select": "^4.2.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.2.tgz", + "integrity": "sha512-VDuhV58w3FuKNl24GR9ygdbu3NkGfuaK7D2gyMWeY79Lr4GVbj7ySxw1isAnelSzU1ecZC/TwICa5rCy0za2OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/type": "^3.0.7", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.14.tgz", + "integrity": "sha512-+VdtRD5nVR50K5fEMq/qbtHGH08vfqm69NJtojavlMXj6fsYymQZrNqjxEISPs2PDvtsemTJVFGs0uI6Zti6Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.2.2.tgz", + "integrity": "sha512-3X8AAPE1WPUwY3IawT19BapD0kKpAUP7SVUu5mxmRjnl/f4q0MQz8CU8ToCC6Im0SzyOTWmSauE3GBgyOv1rBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.12", + "@inquirer/figures": "^1.0.12", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.7.tgz", + "integrity": "sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jest/create-cache-key-function": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.6.1.tgz", @@ -2344,6 +2782,17 @@ "semver": "bin/semver.js" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@react-native-community/cli": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.2.2.tgz", @@ -2786,6 +3235,13 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "license": "MIT" }, + "node_modules/@types/tinycolor2": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz", + "integrity": "sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", @@ -2955,59 +3411,247 @@ "license": "MIT" }, "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "dev": true, "license": "MIT", "dependencies": { - "archiver-utils": "^2.1.0", + "archiver-utils": "^5.0.2", "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" }, "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "dev": true, "license": "MIT", "dependencies": { - "glob": "^7.1.4", + "glob": "^10.0.0", "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", + "lodash": "^4.17.15", "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" + "readable-stream": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/archiver-utils/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/archiver/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/archiver/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/archiver/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, "node_modules/argparse": { @@ -3123,9 +3767,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", "dev": true, "license": "MIT", "dependencies": { @@ -3134,6 +3778,13 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/babel-core": { "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", @@ -3292,6 +3943,14 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, "node_modules/base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", @@ -3484,15 +4143,22 @@ } }, "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=8.0.0" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3528,6 +4194,20 @@ "node": ">=0.10.0" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", @@ -3655,16 +4335,6 @@ "node": ">=8" } }, - "node_modules/cli-spinner": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/cli-spinner/-/cli-spinner-0.2.10.tgz", - "integrity": "sha512-U0sSQ+JJvSLi1pAYuJykwiA8Dsr15uHEy85iCJ6A+0DjVxivr3d+N2Wjvodeg89uP5K6TswFkKBfAD7B3YSn/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/cli-spinners": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", @@ -3677,30 +4347,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-table3": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", - "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "license": "ISC", "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/cliui": { @@ -3817,35 +4471,107 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "license": "MIT" }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/compress-commons/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/compress-commons/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, "engines": { - "node": ">= 10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/compress-commons/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/compress-commons/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/compress-commons/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, "node_modules/compressible": { @@ -3962,32 +4688,90 @@ } }, "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "dev": true, "license": "MIT", "dependencies": { "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" + "readable-stream": "^4.0.0" }, "engines": { - "node": ">= 10" + "node": ">= 14" + } + }, + "node_modules/crc32-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/crc32-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/crc32-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/crc32-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, "node_modules/cross-spawn": { @@ -4198,32 +4982,36 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/duplexify": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", - "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.2" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "safe-buffer": "^5.0.1" } }, "node_modules/ee-first": { @@ -4305,6 +5093,55 @@ "node": ">= 0.8" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -4369,6 +5206,16 @@ "node": ">=6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -4463,6 +5310,13 @@ "node": ">=0.10.0" } }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-xml-parser": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", @@ -4494,20 +5348,17 @@ "bser": "2.1.1" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "node_modules/figlet": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.8.1.tgz", + "integrity": "sha512-kEC3Sme+YvA8Hkibv0NR1oClGcWia0VB2fC1SlMy027cwe795Xx40Xiv/nw/iFAwQLupymWh+uhAAErn/7hwPg==", "dev": true, "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" + "bin": { + "figlet": "bin/index.js" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4.0" } }, "node_modules/fill-range": { @@ -4601,54 +5452,149 @@ "node": ">=6" } }, - "node_modules/flow-parser": { - "version": "0.185.2", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.185.2.tgz", - "integrity": "sha512-2hJ5ACYeJCzNtiVULov6pljKOLygy0zddoqSI1fFetM+XRPpRshFdGEijtqlamA1XwyZ+7rhryI6FQFzvtLWUQ==", + "node_modules/flow-parser": { + "version": "0.185.2", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.185.2.tgz", + "integrity": "sha512-2hJ5ACYeJCzNtiVULov6pljKOLygy0zddoqSI1fFetM+XRPpRshFdGEijtqlamA1XwyZ+7rhryI6FQFzvtLWUQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/foreground-child/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=4.0" + "node": ">=14" }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "license": "MIT", + "node_modules/foreground-child/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" }, "engines": { @@ -4676,24 +5622,6 @@ "node": ">= 0.6" } }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -4728,10 +5656,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "license": "MIT" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -4751,6 +5682,45 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -4801,12 +5771,39 @@ "node": ">=4" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/gradient-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/gradient-string/-/gradient-string-2.0.2.tgz", + "integrity": "sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "tinygradient": "^1.1.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -4828,6 +5825,35 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -4867,6 +5893,19 @@ "node": ">=0.10.0" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hermes-estree": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.8.0.tgz", @@ -5003,29 +6042,30 @@ "license": "ISC" }, "node_modules/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.6.2.tgz", + "integrity": "sha512-bPQV0oGJTy3cKqgtY+PI8qpn1ig1yalY400I9fzg/YZcK1bpTZvpQJcPiJ0s+u0edOQlMv7NW/hguocx0/2CMg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.2.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "@inquirer/core": "^10.1.12", + "@inquirer/prompts": "^7.5.2", + "@inquirer/type": "^3.0.7", + "ansi-escapes": "^4.3.2", + "mute-stream": "^2.0.0", + "run-async": "^3.0.0", + "rxjs": "^7.8.2" }, "engines": { - "node": ">=8.0.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/invariant": { @@ -5237,6 +6277,22 @@ "node": ">=0.10.0" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest-environment-node": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.1.tgz", @@ -5720,6 +6776,72 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -5795,24 +6917,31 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", "dev": true, "license": "MIT" }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", "dev": true, "license": "MIT" }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", "dev": true, "license": "MIT" }, @@ -5823,19 +6952,26 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", "license": "MIT" }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "dev": true, - "license": "MIT" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -6042,6 +7178,16 @@ "node": ">=0.10.0" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -6636,6 +7782,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -6680,11 +7836,14 @@ "license": "MIT" }, "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, "node_modules/nanomatch": { "version": "1.2.13", @@ -7069,6 +8228,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -7133,6 +8299,30 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -7243,6 +8433,16 @@ "@types/yargs-parser": "*" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -7305,18 +8505,6 @@ "once": "^1.3.1" } }, - "node_modules/pumpify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "duplexify": "^4.1.1", - "inherits": "^2.0.3", - "pump": "^3.0.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7584,6 +8772,13 @@ "node": ">=0.10.0" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -7802,9 +8997,9 @@ } }, "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "dev": true, "license": "MIT", "engines": { @@ -7812,9 +9007,9 @@ } }, "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -8220,16 +9415,6 @@ "node": ">=0.10.0" } }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -8276,35 +9461,100 @@ } }, "node_modules/stallion-cli": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/stallion-cli/-/stallion-cli-1.1.3.tgz", - "integrity": "sha512-dpIFyCgmJyIUztxAGGLBCMTjTUJcWHA7tvf5JT9M+PsVS2G0B4VlJS2OZGtoelweNLI/3NNsJtGSmeYTONHXkQ==", + "version": "2.1.0-alpha.1", + "resolved": "https://registry.npmjs.org/stallion-cli/-/stallion-cli-2.1.0-alpha.1.tgz", + "integrity": "sha512-X16BU9ydIu9L29bevLGGwxYnBLle56zigOQom+ByobpA0RbtABpptvDXZeBU+xO5pPDRfh91gchhyEoq3KrPow==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "archiver": "^5.3.1", - "axios": "^1.4.0", - "chalk": "4.1.2", - "cli-spinner": "^0.2.10", - "cli-table3": "0.6.2", - "form-data": "^4.0.0", - "from2": "^2.3.0", - "inquirer": "8.2.0", + "archiver": "^7.0.1", + "axios": "^1.9.0", + "chalk": "^4.1.2", + "commander": "^13.1.0", + "figlet": "^1.7.0", + "gradient-string": "^2.0.2", + "inquirer": "^12.6.1", + "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", - "mime": "3.0.0", - "minimist": "^1.2.8", - "mkdirp": "^3.0.1", + "mime": "^3.0.0", "opener": "^1.5.2", - "pumpify": "^2.0.1", - "rimraf": "3.0.2", - "rxjs": "^7.8.1", - "semver": "^7.5.1", - "split2": "^4.2.0", - "through2": "^4.0.2", - "wordwrap": "^1.0.0" + "ora": "^5.4.1", + "reflect-metadata": "^0.2.2", + "rimraf": "^6.0.1", + "semver": "^7.7.2" + }, + "bin": { + "stallion": "index.js" + } + }, + "node_modules/stallion-cli/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/stallion-cli/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/stallion-cli/node_modules/glob": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", + "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" }, "bin": { - "stallion": "bin/stallion.js" + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stallion-cli/node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stallion-cli/node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" } }, "node_modules/stallion-cli/node_modules/mime": { @@ -8320,58 +9570,70 @@ "node": ">=10.0.0" } }, - "node_modules/stallion-cli/node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "node_modules/stallion-cli/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/stallion-cli/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/stallion-cli/node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">= 6" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/stallion-cli/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "node_modules/stallion-cli/node_modules/rimraf": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, "license": "ISC", + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, "bin": { - "semver": "bin/semver.js" + "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=10" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/stallion-cli/node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "node_modules/stallion-cli/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "3" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/static-extend": { @@ -8396,12 +9658,19 @@ "node": ">= 0.8" } }, - "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "node_modules/streamx": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", + "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } }, "node_modules/string_decoder": { "version": "1.1.1", @@ -8426,6 +9695,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -8438,6 +9723,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -8484,35 +9783,15 @@ } }, "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, "node_modules/temp": { @@ -8563,19 +9842,22 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", "license": "MIT" }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -8586,6 +9868,24 @@ "xtend": "~4.0.1" } }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinygradient": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tinygradient/-/tinygradient-1.1.5.tgz", + "integrity": "sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/tinycolor2": "^1.4.0", + "tinycolor2": "^1.0.0" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -9045,13 +10345,6 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "license": "ISC" }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true, - "license": "MIT" - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -9069,6 +10362,25 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -9170,56 +10482,105 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "dev": true, "license": "MIT", "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" }, "engines": { - "node": ">= 10" + "node": ">= 14" } }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "node_modules/zip-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/zip-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/zip-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/zip-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } } } diff --git a/example/package.json b/example/package.json index 02f19e9..ea29b16 100644 --- a/example/package.json +++ b/example/package.json @@ -17,6 +17,6 @@ "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "babel-plugin-module-resolver": "^5.0.0", - "stallion-cli": "^2.0.0" + "stallion-cli": "^2.1.0-alpha.1" } } diff --git a/example/src/App.tsx b/example/src/App.tsx index b21e151..da4b3e0 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -6,6 +6,7 @@ import { useStallionModal, useStallionUpdate, addEventListener, + restart, } from 'react-native-stallion'; const App: React.FC = () => { @@ -20,15 +21,22 @@ const App: React.FC = () => { React.useEffect(() => { if (isRestartRequired) { - Alert.alert('Restart the app', JSON.stringify(newReleaseBundle)); + Alert.alert('New Release installed', JSON.stringify(newReleaseBundle), [ + { + text: 'Restart', + onPress: restart, + }, + ]); } }, [isRestartRequired, newReleaseBundle]); React.useEffect(() => { - addEventListener((_) => { + addEventListener((event) => { + console.log('Stallion event:', event); // use data }); }, []); + return ( Hello world diff --git a/example/yarn.lock b/example/yarn.lock index 6349a87..af09806 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -1126,11 +1126,6 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" -"@colors/colors@1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" - integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== - "@hapi/hoek@^9.0.0": version "9.3.0" resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz" @@ -1143,6 +1138,162 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@inquirer/checkbox@^4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-4.1.8.tgz#eee11c7920e1ae07e57be038033c7905e9fc59d0" + integrity sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/figures" "^1.0.12" + "@inquirer/type" "^3.0.7" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/confirm@^5.1.12": + version "5.1.12" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.12.tgz#387037889a5a558ceefe52e978228630aa6e7d0e" + integrity sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/type" "^3.0.7" + +"@inquirer/core@^10.1.13": + version "10.1.13" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-10.1.13.tgz#8f1ecfaba288fd2d705c7ac0690371464cf687b0" + integrity sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA== + dependencies: + "@inquirer/figures" "^1.0.12" + "@inquirer/type" "^3.0.7" + ansi-escapes "^4.3.2" + cli-width "^4.1.0" + mute-stream "^2.0.0" + signal-exit "^4.1.0" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/editor@^4.2.13": + version "4.2.13" + resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-4.2.13.tgz#dc491ed01da4bab0de5e760501d76a81177dd7d0" + integrity sha512-WbicD9SUQt/K8O5Vyk9iC2ojq5RHoCLK6itpp2fHsWe44VxxcA9z3GTWlvjSTGmMQpZr+lbVmrxdHcumJoLbMA== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/type" "^3.0.7" + external-editor "^3.1.0" + +"@inquirer/expand@^4.0.15": + version "4.0.15" + resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-4.0.15.tgz#8b49f3503118bb977a13a9040fa84deb9b043ab6" + integrity sha512-4Y+pbr/U9Qcvf+N/goHzPEXiHH8680lM3Dr3Y9h9FFw4gHS+zVpbj8LfbKWIb/jayIB4aSO4pWiBTrBYWkvi5A== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/type" "^3.0.7" + yoctocolors-cjs "^2.1.2" + +"@inquirer/figures@^1.0.12": + version "1.0.12" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.12.tgz#667d6254cc7ba3b0c010a323d78024a1d30c6053" + integrity sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ== + +"@inquirer/input@^4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-4.1.12.tgz#8880b8520f0aad60ef39ea8e0769ce1eb97da713" + integrity sha512-xJ6PFZpDjC+tC1P8ImGprgcsrzQRsUh9aH3IZixm1lAZFK49UGHxM3ltFfuInN2kPYNfyoPRh+tU4ftsjPLKqQ== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/type" "^3.0.7" + +"@inquirer/number@^3.0.15": + version "3.0.15" + resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-3.0.15.tgz#13ac1300ab12d7f1dd1b32c693ac284cfcb04d95" + integrity sha512-xWg+iYfqdhRiM55MvqiTCleHzszpoigUpN5+t1OMcRkJrUrw7va3AzXaxvS+Ak7Gny0j2mFSTv2JJj8sMtbV2g== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/type" "^3.0.7" + +"@inquirer/password@^4.0.15": + version "4.0.15" + resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-4.0.15.tgz#1d48a5a163972dc3b08abe5819bc3c32243cb6e3" + integrity sha512-75CT2p43DGEnfGTaqFpbDC2p2EEMrq0S+IRrf9iJvYreMy5mAWj087+mdKyLHapUEPLjN10mNvABpGbk8Wdraw== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/type" "^3.0.7" + ansi-escapes "^4.3.2" + +"@inquirer/prompts@^7.5.3": + version "7.5.3" + resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-7.5.3.tgz#2b4c705a79658cf534fc5a5dba780a153f3cd83d" + integrity sha512-8YL0WiV7J86hVAxrh3fE5mDCzcTDe1670unmJRz6ArDgN+DBK1a0+rbnNWp4DUB5rPMwqD5ZP6YHl9KK1mbZRg== + dependencies: + "@inquirer/checkbox" "^4.1.8" + "@inquirer/confirm" "^5.1.12" + "@inquirer/editor" "^4.2.13" + "@inquirer/expand" "^4.0.15" + "@inquirer/input" "^4.1.12" + "@inquirer/number" "^3.0.15" + "@inquirer/password" "^4.0.15" + "@inquirer/rawlist" "^4.1.3" + "@inquirer/search" "^3.0.15" + "@inquirer/select" "^4.2.3" + +"@inquirer/rawlist@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-4.1.3.tgz#c97278a2bcd0c31ce846e7e448fb7a6a25bcd3b2" + integrity sha512-7XrV//6kwYumNDSsvJIPeAqa8+p7GJh7H5kRuxirct2cgOcSWwwNGoXDRgpNFbY/MG2vQ4ccIWCi8+IXXyFMZA== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/type" "^3.0.7" + yoctocolors-cjs "^2.1.2" + +"@inquirer/search@^3.0.15": + version "3.0.15" + resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-3.0.15.tgz#419ddff4254cf22018cdfbfc840fa3ef8a0721cb" + integrity sha512-YBMwPxYBrADqyvP4nNItpwkBnGGglAvCLVW8u4pRmmvOsHUtCAUIMbUrLX5B3tFL1/WsLGdQ2HNzkqswMs5Uaw== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/figures" "^1.0.12" + "@inquirer/type" "^3.0.7" + yoctocolors-cjs "^2.1.2" + +"@inquirer/select@^4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-4.2.3.tgz#3e31b56aff7bce9b46a0e2c8428118a25fe51c32" + integrity sha512-OAGhXU0Cvh0PhLz9xTF/kx6g6x+sP+PcyTiLvCrewI99P3BBeexD+VbuwkNDvqGkk3y2h5ZiWLeRP7BFlhkUDg== + dependencies: + "@inquirer/core" "^10.1.13" + "@inquirer/figures" "^1.0.12" + "@inquirer/type" "^3.0.7" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/type@^3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.7.tgz#b46bcf377b3172dbc768fdbd053e6492ad801a09" + integrity sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA== + +"@isaacs/balanced-match@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" + integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ== + +"@isaacs/brace-expansion@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3" + integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA== + dependencies: + "@isaacs/balanced-match" "^4.0.1" + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@jest/create-cache-key-function@^29.2.1": version "29.6.1" resolved "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.6.1.tgz" @@ -1263,6 +1414,11 @@ resolved "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz" integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@react-native-community/cli-clean@^10.1.1": version "10.1.1" resolved "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-10.1.1.tgz" @@ -1517,6 +1673,11 @@ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/tinycolor2@^1.4.0": + version "1.4.6" + resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.6.tgz#670cbc0caf4e58dd61d1e3a6f26386e473087f06" + integrity sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" @@ -1573,9 +1734,9 @@ anser@^1.4.9: resolved "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz" integrity sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww== -ansi-escapes@^4.2.1: +ansi-escapes@^4.3.2: version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" @@ -1599,6 +1760,11 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" @@ -1618,6 +1784,11 @@ ansi-styles@^5.0.0: resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + anymatch@^3.0.3: version "3.1.3" resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" @@ -1631,50 +1802,31 @@ appdirsjs@^1.2.4: resolved "https://registry.npmjs.org/appdirsjs/-/appdirsjs-1.2.7.tgz" integrity sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw== -archiver-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz" - integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== +archiver-utils@^5.0.0, archiver-utils@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-5.0.2.tgz#63bc719d951803efc72cf961a56ef810760dd14d" + integrity sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA== dependencies: - glob "^7.1.4" + glob "^10.0.0" graceful-fs "^4.2.0" + is-stream "^2.0.1" lazystream "^1.0.0" - lodash.defaults "^4.2.0" - lodash.difference "^4.5.0" - lodash.flatten "^4.4.0" - lodash.isplainobject "^4.0.6" - lodash.union "^4.6.0" + lodash "^4.17.15" normalize-path "^3.0.0" - readable-stream "^2.0.0" + readable-stream "^4.0.0" -archiver-utils@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz" - integrity sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw== - dependencies: - glob "^7.2.3" - graceful-fs "^4.2.0" - lazystream "^1.0.0" - lodash.defaults "^4.2.0" - lodash.difference "^4.5.0" - lodash.flatten "^4.4.0" - lodash.isplainobject "^4.0.6" - lodash.union "^4.6.0" - normalize-path "^3.0.0" - readable-stream "^3.6.0" - -archiver@^5.3.1: - version "5.3.2" - resolved "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz" - integrity sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw== +archiver@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-7.0.1.tgz#c9d91c350362040b8927379c7aa69c0655122f61" + integrity sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ== dependencies: - archiver-utils "^2.1.0" + archiver-utils "^5.0.2" async "^3.2.4" - buffer-crc32 "^0.2.1" - readable-stream "^3.6.0" + buffer-crc32 "^1.0.0" + readable-stream "^4.0.0" readdir-glob "^1.1.2" - tar-stream "^2.2.0" - zip-stream "^4.1.0" + tar-stream "^3.0.0" + zip-stream "^6.0.1" argparse@^1.0.7: version "1.0.10" @@ -1745,15 +1897,20 @@ atob@^2.1.2: resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -axios@^1.4.0: - version "1.7.7" - resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz" - integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== +axios@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.10.0.tgz#af320aee8632eaf2a400b6a1979fa75856f38d54" + integrity sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" +b4a@^1.6.4: + version "1.6.7" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4" + integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg== + babel-core@^7.0.0-bridge.0: version "7.0.0-bridge.0" resolved "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz" @@ -1837,6 +1994,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bare-events@^2.2.0: + version "2.5.4" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.4.tgz#16143d435e1ed9eafd1ab85f12b89b3357a41745" + integrity sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA== + base64-js@^1.1.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -1855,7 +2017,7 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -bl@^4.0.3, bl@^4.1.0: +bl@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -1919,10 +2081,15 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: - version "0.2.13" - resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" - integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== +buffer-crc32@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405" + integrity sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w== + +buffer-equal-constant-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== buffer-from@^1.0.0: version "1.1.2" @@ -1937,6 +2104,14 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + bytes@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" @@ -1991,14 +2166,6 @@ caniuse-lite@^1.0.30001503: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz" integrity sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g== -chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^2.0.0: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -2008,6 +2175,14 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" @@ -2040,29 +2215,15 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-spinner@^0.2.10: - version "0.2.10" - resolved "https://registry.npmjs.org/cli-spinner/-/cli-spinner-0.2.10.tgz" - integrity sha512-U0sSQ+JJvSLi1pAYuJykwiA8Dsr15uHEy85iCJ6A+0DjVxivr3d+N2Wjvodeg89uP5K6TswFkKBfAD7B3YSn/Q== - cli-spinners@^2.5.0: version "2.9.0" resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz" integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== -cli-table3@0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz" - integrity sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw== - dependencies: - string-width "^4.2.0" - optionalDependencies: - "@colors/colors" "1.5.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== cliui@^6.0.0: version "6.0.0" @@ -2145,6 +2306,11 @@ command-exists@^1.2.8: resolved "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz" integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== +commander@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46" + integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== + commander@^2.20.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" @@ -2170,15 +2336,16 @@ component-emitter@^1.2.1: resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -compress-commons@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz" - integrity sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg== +compress-commons@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e" + integrity sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg== dependencies: - buffer-crc32 "^0.2.13" - crc32-stream "^4.0.2" + crc-32 "^1.2.0" + crc32-stream "^6.0.0" + is-stream "^2.0.1" normalize-path "^3.0.0" - readable-stream "^3.6.0" + readable-stream "^4.0.0" compressible@~2.0.16: version "2.0.18" @@ -2252,13 +2419,13 @@ crc-32@^1.2.0: resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== -crc32-stream@^4.0.2: - version "4.0.3" - resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz" - integrity sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw== +crc32-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-6.0.0.tgz#8529a3868f8b27abb915f6c3617c0fadedbf9430" + integrity sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g== dependencies: crc-32 "^1.2.0" - readable-stream "^3.4.0" + readable-stream "^4.0.0" cross-spawn@^6.0.0: version "6.0.5" @@ -2271,6 +2438,15 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + dayjs@^1.8.15: version "1.11.9" resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz" @@ -2363,15 +2539,17 @@ destroy@1.2.0: resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -duplexify@^4.1.1: - version "4.1.3" - resolved "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz" - integrity sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== dependencies: - end-of-stream "^1.4.1" - inherits "^2.0.3" - readable-stream "^3.1.1" - stream-shift "^1.0.2" + safe-buffer "^5.0.1" ee-first@1.1.1: version "1.1.1" @@ -2388,12 +2566,17 @@ emoji-regex@^8.0.0: resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -end-of-stream@^1.1.0, end-of-stream@^1.4.1: +end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -2467,6 +2650,11 @@ event-target-shim@^5.0.0, event-target-shim@^5.0.1: resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + execa@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz" @@ -2508,9 +2696,9 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -external-editor@^3.0.3: +external-editor@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: chardet "^0.7.0" @@ -2531,6 +2719,11 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +fast-fifo@^1.2.0, fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + fast-xml-parser@^4.0.12: version "4.2.5" resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz" @@ -2545,12 +2738,10 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" +figlet@^1.7.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.8.1.tgz#e8e8a07e8c16be24c31086d7d5de8a9b9cf7f0fd" + integrity sha512-kEC3Sme+YvA8Hkibv0NR1oClGcWia0VB2fC1SlMy027cwe795Xx40Xiv/nw/iFAwQLupymWh+uhAAErn/7hwPg== fill-range@^4.0.0: version "4.0.0" @@ -2637,6 +2828,14 @@ for-in@^1.0.2: resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== +foreground-child@^3.1.0, foreground-child@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + form-data@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" @@ -2658,19 +2857,6 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -from2@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz" - integrity sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g== - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" @@ -2717,7 +2903,31 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== -glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: +glob@^10.0.0: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + +glob@^11.0.0: + version "11.0.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.3.tgz#9d8087e6d72ddb3c4707b1d2778f80ea3eaefcd6" + integrity sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA== + dependencies: + foreground-child "^3.3.1" + jackspeak "^4.1.1" + minimatch "^10.0.3" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" + +glob@^7.1.3: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2750,6 +2960,14 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +gradient-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/gradient-string/-/gradient-string-2.0.2.tgz#a90402618990ec993ecbb72a56bd7e6598f45c0e" + integrity sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw== + dependencies: + chalk "^4.1.2" + tinygradient "^1.1.5" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" @@ -2835,7 +3053,7 @@ iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -2866,30 +3084,23 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inquirer@8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz" - integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== +inquirer@^12.6.1: + version "12.6.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-12.6.3.tgz#2a61a0e7cbc70849df2c26812b108326319aa4fc" + integrity sha512-eX9beYAjr1MqYsIjx1vAheXsRk1jbZRvHLcBu5nA9wX0rXR1IfCZLnVLp4Ym4mrhqmh7AuANwcdtgQ291fZDfQ== dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.1" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.21" - mute-stream "0.0.8" - ora "^5.4.1" - run-async "^2.4.0" - rxjs "^7.2.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" + "@inquirer/core" "^10.1.13" + "@inquirer/prompts" "^7.5.3" + "@inquirer/type" "^3.0.7" + ansi-escapes "^4.3.2" + mute-stream "^2.0.0" + run-async "^3.0.0" + rxjs "^7.8.2" invariant@*, invariant@^2.2.4: version "2.2.4" @@ -3022,6 +3233,11 @@ is-stream@^1.1.0: resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== +is-stream@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" @@ -3059,6 +3275,22 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jackspeak@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.1.1.tgz#96876030f450502047fc7e8c7fcf8ce8124e43ae" + integrity sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + jest-environment-node@^29.2.1: version "29.6.1" resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.1.tgz" @@ -3244,6 +3476,39 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +jwa@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.2.tgz#16011ac6db48de7b102777e57897901520eec7b9" + integrity sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw== + dependencies: + buffer-equal-constant-time "^1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" @@ -3312,37 +3577,47 @@ lodash.debounce@^4.0.8: resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== -lodash.difference@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz" - integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz" integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== -lodash.union@^4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz" - integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== - -lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3371,6 +3646,16 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.1.0.tgz#afafb060607108132dbc1cf8ae661afb69486117" + integrity sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -3838,21 +4123,28 @@ mime@1.6.0: resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz" - integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== - mime@^2.4.1: version "2.6.0" resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +minimatch@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.3.tgz#cf7a0314a16c4d9ab73a7730a0e8e3c3502d47aa" + integrity sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw== + dependencies: + "@isaacs/brace-expansion" "^5.0.0" + minimatch@^3.0.2, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" @@ -3867,11 +4159,23 @@ minimatch@^5.0.1, minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.6, minimist@^1.2.8: +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz" @@ -3887,11 +4191,6 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.6" -mkdirp@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz" - integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" @@ -3902,15 +4201,15 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mute-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-2.0.0.tgz#a5446fc0c512b71c83c44d908d5c7b7b4c493b2b" + integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== nanomatch@^1.2.9: version "1.2.13" @@ -4143,6 +4442,11 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + parse-json@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" @@ -4181,11 +4485,32 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" @@ -4249,6 +4574,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + promise@^8.3.0: version "8.3.0" resolved "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz" @@ -4286,15 +4616,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz" - integrity sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw== - dependencies: - duplexify "^4.1.1" - inherits "^2.0.3" - pump "^3.0.0" - range-parser@~1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" @@ -4398,16 +4719,7 @@ react@18.2.0: dependencies: loose-envify "^1.1.0" -readable-stream@3, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@~2.3.6: +readable-stream@^2.0.5, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -4420,6 +4732,26 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^4.0.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.7.0.tgz#cedbd8a1146c13dfff8dab14068028d58c15ac91" + integrity sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + readdir-glob@^1.1.2: version "1.1.3" resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz" @@ -4442,6 +4774,11 @@ recast@^0.20.4: source-map "~0.6.1" tslib "^2.0.1" +reflect-metadata@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== + regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz" @@ -4550,13 +4887,21 @@ ret@~0.1.10: resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -rimraf@3.0.2, rimraf@^3.0.2: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" +rimraf@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-6.0.1.tgz#ffb8ad8844dd60332ab15f52bc104bc3ed71ea4e" + integrity sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A== + dependencies: + glob "^11.0.0" + package-json-from-dist "^1.0.0" + rimraf@~2.2.6: version "2.2.8" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" @@ -4569,15 +4914,15 @@ rimraf@~2.6.2: dependencies: glob "^7.1.3" -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-async@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad" + integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q== -rxjs@^7.2.0, rxjs@^7.8.1: - version "7.8.1" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz" - integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== +rxjs@^7.8.2: + version "7.8.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== dependencies: tslib "^2.1.0" @@ -4586,6 +4931,11 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@^5.0.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" @@ -4615,10 +4965,10 @@ semver@^6.3.0, semver@^6.3.1: resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.1: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.5.4, semver@^7.7.2: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== send@0.18.0: version "0.18.0" @@ -4688,11 +5038,23 @@ shebang-command@^1.2.0: dependencies: shebang-regex "^1.0.0" +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + shell-quote@^1.6.1, shell-quote@^1.7.3: version "1.8.1" resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz" @@ -4703,6 +5065,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" @@ -4798,11 +5165,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split2@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" - integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" @@ -4827,31 +5189,26 @@ stacktrace-parser@^0.1.3: dependencies: type-fest "^0.7.1" -stallion-cli@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/stallion-cli/-/stallion-cli-2.0.0.tgz#8ee6fda208c0f98a652f3cb647da6ec1074baf75" - integrity sha512-DS3X641quyLSf73bLiedTbrf7CTdyw3vaZsLGa+3FZs1eSurVpD7RMtuCGcXxdAEw3Qq4H+QZWsfBD5jHEVSvg== - dependencies: - archiver "^5.3.1" - axios "^1.4.0" - chalk "4.1.2" - cli-spinner "^0.2.10" - cli-table3 "0.6.2" - form-data "^4.0.0" - from2 "^2.3.0" - inquirer "8.2.0" +stallion-cli@^2.1.0-alpha.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/stallion-cli/-/stallion-cli-2.1.0.tgz#b7950a69787375f6fc7b4bc8e101b98253fa3e26" + integrity sha512-xAY3JaiA7SO6zbJgfZEJmokEJzIQyGiRoTTFPnVtEpNBiH+VHh7edknswAE6VxdyJVO9xZmF9Oh7VOxXGntXag== + dependencies: + archiver "^7.0.1" + axios "^1.9.0" + chalk "^4.1.2" + commander "^13.1.0" + figlet "^1.7.0" + gradient-string "^2.0.2" + inquirer "^12.6.1" + jsonwebtoken "^9.0.2" lodash "^4.17.21" - mime "3.0.0" - minimist "^1.2.8" - mkdirp "^3.0.1" + mime "^3.0.0" opener "^1.5.2" - pumpify "^2.0.1" - rimraf "3.0.2" - rxjs "^7.8.1" - semver "^7.5.1" - split2 "^4.2.0" - through2 "^4.0.2" - wordwrap "^1.0.0" + ora "^5.4.1" + reflect-metadata "^0.2.2" + rimraf "^6.0.1" + semver "^7.7.2" static-extend@^0.1.1: version "0.1.2" @@ -4871,10 +5228,24 @@ statuses@~1.5.0: resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -stream-shift@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz" - integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== +streamx@^2.15.0: + version "2.22.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.22.1.tgz#c97cbb0ce18da4f4db5a971dc9ab68ff5dc7f5a5" + integrity sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA== + dependencies: + fast-fifo "^1.3.2" + text-decoder "^1.1.0" + optionalDependencies: + bare-events "^2.2.0" + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" @@ -4885,6 +5256,15 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string_decoder@^1.1.1, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" @@ -4892,6 +5272,20 @@ string_decoder@^1.1.1, string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^5.0.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" @@ -4906,6 +5300,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz" @@ -4947,16 +5348,14 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -tar-stream@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== +tar-stream@^3.0.0: + version "3.1.7" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" temp@0.8.3: version "0.8.3" @@ -4983,6 +5382,13 @@ terser@^5.15.0: commander "^2.20.0" source-map-support "~0.5.20" +text-decoder@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.3.tgz#b19da364d981b2326d5f43099c310cc80d770c65" + integrity sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA== + dependencies: + b4a "^1.6.4" + throat@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz" @@ -4996,17 +5402,18 @@ through2@^2.0.1: readable-stream "~2.3.6" xtend "~4.0.1" -through2@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" +tinycolor2@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" + integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== -through@^2.3.6: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +tinygradient@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/tinygradient/-/tinygradient-1.1.5.tgz#0fb855ceb18d96b21ba780b51a8012033b2530ef" + integrity sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw== + dependencies: + "@types/tinycolor2" "^1.4.0" + tinycolor2 "^1.0.0" tmp@^0.0.33: version "0.0.33" @@ -5233,10 +5640,21 @@ which@^1.2.9: dependencies: isexe "^2.0.0" -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^6.2.0: version "6.2.0" @@ -5256,6 +5674,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" @@ -5350,11 +5777,16 @@ yocto-queue@^0.1.0: resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zip-stream@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz" - integrity sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ== +yoctocolors-cjs@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" + integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== + +zip-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb" + integrity sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA== dependencies: - archiver-utils "^3.0.4" - compress-commons "^4.1.2" - readable-stream "^3.6.0" + archiver-utils "^5.0.0" + compress-commons "^6.0.2" + readable-stream "^4.0.0" diff --git a/ios/Stallion.xcodeproj/project.pbxproj b/ios/Stallion.xcodeproj/project.pbxproj index 72dc3b8..97f80e7 100644 --- a/ios/Stallion.xcodeproj/project.pbxproj +++ b/ios/Stallion.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 5E555C0D2413F4C50049A1A2 /* Stallion.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* Stallion.m */; }; F4FF95D7245B92E800C19C63 /* Stallion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* Stallion.swift */; }; + F4FF95DA245B92EB00C19C63 /* StallionDeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D9245B92EB00C19C63 /* StallionDeviceInfo.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -28,6 +29,8 @@ B3E7B5891CC2AC0600A0062D /* Stallion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Stallion.m; sourceTree = ""; }; F4FF95D5245B92E700C19C63 /* Stallion-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Stallion-Bridging-Header.h"; sourceTree = ""; }; F4FF95D6245B92E800C19C63 /* Stallion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stallion.swift; sourceTree = ""; }; + F4FF95D7245B92E900C19C63 /* StallionVersion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StallionVersion.h"; sourceTree = ""; }; + F4FF95D9245B92EB00C19C63 /* StallionDeviceInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StallionDeviceInfo.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -53,8 +56,10 @@ isa = PBXGroup; children = ( F4FF95D6245B92E800C19C63 /* Stallion.swift */, + F4FF95D9245B92EB00C19C63 /* StallionDeviceInfo.swift */, B3E7B5891CC2AC0600A0062D /* Stallion.m */, F4FF95D5245B92E700C19C63 /* Stallion-Bridging-Header.h */, + F4FF95D7245B92E900C19C63 /* StallionVersion.h */, 134814211AA4EA7D00B7C361 /* Products */, ); sourceTree = ""; @@ -117,6 +122,7 @@ buildActionMask = 2147483647; files = ( F4FF95D7245B92E800C19C63 /* Stallion.swift in Sources */, + F4FF95DA245B92EB00C19C63 /* StallionDeviceInfo.swift in Sources */, B3E7B58A1CC2AC0600A0062D /* Stallion.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/main/Stallion.swift b/ios/main/Stallion.swift index aadbdbb..af3b1c6 100644 --- a/ios/main/Stallion.swift +++ b/ios/main/Stallion.swift @@ -30,6 +30,14 @@ class Stallion: RCTEventEmitter { @objc func onLaunch(_ launchData: String) { stallionStateManager.isMounted = true checkPendingDownloads() + let currentReleaseHash = stallionStateManager.stallionMeta.getHashAtCurrentProdSlot() + if let currentReleaseHash = currentReleaseHash { + if !currentReleaseHash.isEmpty && stallionStateManager.stallionMeta.getSuccessfulLaunchCount(currentReleaseHash) == 0 { + emitInstallEvent(currentReleaseHash) + } + stallionStateManager.stallionMeta.markSuccessfulLaunch(currentReleaseHash) + stallionStateManager.syncStallionMeta() + } } private func checkPendingDownloads() { @@ -149,8 +157,21 @@ class Stallion: RCTEventEmitter { @objc func restart() { DispatchQueue.main.async { + self.stallionStateManager.isMounted = false RCTTriggerReloadCommandListeners("Stallion: Restart") } } + + private func emitInstallEvent(_ releaseHash: String) { + let eventPayload: [String: Any] = [ + "releaseHash": releaseHash + ] + + Stallion.sendEventToRn( + eventName: StallionConstants.NativeEventTypesProd.INSTALLED_PROD, + eventBody: eventPayload as NSDictionary, + shouldCache: false + ) + } } diff --git a/ios/main/StallionConfig.h b/ios/main/StallionConfig.h index 6dcbd3c..46adde2 100644 --- a/ios/main/StallionConfig.h +++ b/ios/main/StallionConfig.h @@ -2,7 +2,7 @@ // StallionConfig.h // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import @@ -15,10 +15,13 @@ @property (nonatomic, copy) NSString *sdkToken; @property (nonatomic, copy, readonly) NSString *appVersion; @property (nonatomic, copy, readonly) NSString *filesDirectory; +@property (nonatomic, copy, readonly) NSString *publicSigningKey; +@property (nonatomic, copy) NSString *lastUnverifiedHash; - (instancetype)initWithDefaults:(NSUserDefaults *)defaults; - (void)updateSdkToken:(NSString *)newSdkToken; +- (void)updateLastUnverifiedHash:(NSString *)newUnverifiedHash; - (NSDictionary *)toDictionary; @end diff --git a/ios/main/StallionConfig.m b/ios/main/StallionConfig.m index 62c1be5..e75c9a0 100644 --- a/ios/main/StallionConfig.m +++ b/ios/main/StallionConfig.m @@ -2,7 +2,7 @@ // StallionConfig.m // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import "StallionConfig.h" @@ -17,8 +17,9 @@ - (instancetype)initWithDefaults:(NSUserDefaults *)defaults { _appToken = [[NSBundle mainBundle] objectForInfoDictionaryKey:STALLION_APP_TOKEN_IDENTIFIER] ?: @""; _sdkToken = [defaults stringForKey:API_KEY_IDENTIFIER] ?: @""; _appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:STALLION_APP_VERSION_IDENTIFIER] ?: @""; - _filesDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject ?: @""; + _publicSigningKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:STALLION_PUBLIC_SIGNING_KEY_IDENTIFIER] ?: @""; + _lastUnverifiedHash = [defaults stringForKey:LAST_UNVERIFIED_KEY_IDENTIFIER] ?: @""; NSString *cachedUid = [defaults stringForKey:UNIQUE_ID_IDENTIFIER]; if (cachedUid && ![cachedUid isEqualToString:@""]) { @@ -44,6 +45,12 @@ - (void)updateSdkToken:(NSString *)newSdkToken { [[NSUserDefaults standardUserDefaults] synchronize]; } +- (void)updateLastUnverifiedHash:(NSString *)newUnverifiedHash { + _lastUnverifiedHash = newUnverifiedHash ?: @""; + [[NSUserDefaults standardUserDefaults] setObject:_lastUnverifiedHash forKey:LAST_UNVERIFIED_KEY_IDENTIFIER]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + - (NSDictionary *)toDictionary { @try { return @{ diff --git a/ios/main/StallionConfigConstants.h b/ios/main/StallionConfigConstants.h index d4f010f..7c0d921 100644 --- a/ios/main/StallionConfigConstants.h +++ b/ios/main/StallionConfigConstants.h @@ -2,7 +2,7 @@ // StallionConfigConstants.h // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import @@ -29,4 +29,8 @@ extern NSString *const UNZIP_FOLDER_NAME; extern NSString *const STALLION_META_IDENTIFIER; +extern NSString *const STALLION_PUBLIC_SIGNING_KEY_IDENTIFIER; + +extern NSString *const LAST_UNVERIFIED_KEY_IDENTIFIER; + @end diff --git a/ios/main/StallionConfigConstants.m b/ios/main/StallionConfigConstants.m index f164d77..3ab91af 100644 --- a/ios/main/StallionConfigConstants.m +++ b/ios/main/StallionConfigConstants.m @@ -2,7 +2,7 @@ // StallionConfigConstants.m // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import "StallionConfigConstants.h" @@ -29,4 +29,8 @@ @implementation StallionConfigConstants NSString *const DEFAULT_JS_BUNDLE_LOCATION_BASE = @"assets:/"; NSString *const UNZIP_FOLDER_NAME = @"/build"; +NSString *const STALLION_PUBLIC_SIGNING_KEY_IDENTIFIER = @"StallionPublicSigningKey"; + +NSString *const LAST_UNVERIFIED_KEY_IDENTIFIER = @"LastUnverifiedHash"; + @end diff --git a/ios/main/StallionConstants.swift b/ios/main/StallionConstants.swift index 262b02b..4a736d0 100644 --- a/ios/main/StallionConstants.swift +++ b/ios/main/StallionConstants.swift @@ -34,6 +34,7 @@ class StallionConstants { static let SecretKey = "secretKey" } static let PROGRESS_EVENT_THRESHOLD: Float = 0.05; + static let PROGRESS_THROTTLE_INTERVAL_MS: TimeInterval = 0.3; // 300ms static let PROD_DIRECTORY = "StallionProd" static let STAGE_DIRECTORY = "StallionStage" @@ -78,6 +79,7 @@ class StallionConstants { static let INSTALLED_PROD = "INSTALLED_PROD" static let STABILIZED_PROD = "STABILIZED_PROD" static let EXCEPTION_PROD = "EXCEPTION_PROD" + static let SIGNATURE_VERIFICATION_FAILED = "SIGNATURE_VERIFICATION_FAILED" } public struct NativeEventTypesStage { static let DOWNLOAD_STARTED_STAGE = "DOWNLOAD_STARTED_STAGE" diff --git a/ios/main/StallionDeviceInfo.swift b/ios/main/StallionDeviceInfo.swift new file mode 100644 index 0000000..443ff09 --- /dev/null +++ b/ios/main/StallionDeviceInfo.swift @@ -0,0 +1,105 @@ +// +// StallionDeviceInfo.swift +// react-native-stallion +// +// Created by Thor963 on 29/01/25. +// + +import Foundation +import UIKit + +class StallionDeviceInfo { + + /** + * Sample JSON contract for deviceMeta + * { + * "osName": "iOS", + * "osVersion": "17.2", + * "sdkInt": 17, + * "manufacturer": "Apple", + * "brand": "Apple", + * "model": "iPhone 15 Pro", + * "device": "iPhone16,1", + * "product": "iPhone16,1", + * "hardware": "iPhone16,1", + * "locale": "en-US", + * "localeLanguage": "en", + * "localeCountry": "US", + * "timezone": "America/Los_Angeles", + * "timezoneOffsetMinutes": -420, + * "isEmulator": false, + * "projectId": "", + * "uid": "", + * "appVersion": "1.2.3" + * } + */ + static func getDeviceMetaJson(_ config: StallionConfig?) -> [String: Any] { + var json: [String: Any] = [:] + + // OS Information + json["osName"] = "iOS" + json["osVersion"] = UIDevice.current.systemVersion + json["sdkInt"] = Int(UIDevice.current.systemVersion.components(separatedBy: ".").first ?? "0") ?? 0 + + // Device Information + json["manufacturer"] = "Apple" + json["brand"] = "Apple" + json["model"] = getDeviceModel() + json["device"] = getDeviceIdentifier() + json["product"] = getDeviceIdentifier() + json["hardware"] = getDeviceIdentifier() + + // Locale Information + let locale = Locale.current + json["locale"] = locale.identifier + json["localeLanguage"] = locale.languageCode ?? "" + json["localeCountry"] = locale.regionCode ?? "" + + // Timezone Information + let timezone = TimeZone.current + json["timezone"] = timezone.identifier + json["timezoneOffsetMinutes"] = timezone.secondsFromGMT() / 60 + + // Emulator Detection + json["isEmulator"] = isProbablyEmulator() + + // Config Information + if let config = config { + json["projectId"] = config.projectId ?? "" + json["uid"] = config.uid ?? "" + json["appVersion"] = config.appVersion ?? "" + } + + return json + } + + private static func getDeviceModel() -> String { + var systemInfo = utsname() + uname(&systemInfo) + let modelCode = withUnsafePointer(to: &systemInfo.machine) { + $0.withMemoryRebound(to: CChar.self, capacity: 1) { + ptr in String.init(validatingUTF8: ptr) + } + } + return modelCode ?? "Unknown" + } + + private static func getDeviceIdentifier() -> String { + var systemInfo = utsname() + uname(&systemInfo) + let identifier = withUnsafePointer(to: &systemInfo.machine) { + $0.withMemoryRebound(to: CChar.self, capacity: 1) { + ptr in String.init(validatingUTF8: ptr) + } + } + return identifier ?? "Unknown" + } + + private static func isProbablyEmulator() -> Bool { + #if targetEnvironment(simulator) + return true + #else + return false + #endif + } +} diff --git a/ios/main/StallionEventHandler.h b/ios/main/StallionEventHandler.h index 83c2a45..07bfb76 100644 --- a/ios/main/StallionEventHandler.h +++ b/ios/main/StallionEventHandler.h @@ -2,7 +2,7 @@ // StallionEventHandler.h // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import diff --git a/ios/main/StallionEventHandler.m b/ios/main/StallionEventHandler.m index 13b391a..e3abe1e 100644 --- a/ios/main/StallionEventHandler.m +++ b/ios/main/StallionEventHandler.m @@ -2,11 +2,12 @@ // StallionEventHandler.m // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import "StallionEventHandler.h" #import "StallionStateManager.h" +#import "StallionVersion.h" #import #import @@ -15,6 +16,7 @@ static NSString *const STALLION_NATIVE_EVENT_NAME = @"STALLION_NATIVE_EVENT"; static NSString *const EVENTS_KEY = @"stored_events"; static NSInteger const MAX_BATCH_COUNT_SIZE = 9; +static NSInteger const MAX_EVENT_STORAGE_LIMIT = 60; @implementation StallionEventHandler @@ -30,11 +32,11 @@ + (instancetype)sharedInstance { // Emit event to React Native and store locally - (void)cacheEvent:(NSString *)eventName eventPayload:(NSDictionary *)eventPayload { StallionStateManager *stallionStateManager = [StallionStateManager sharedInstance]; - + NSString *projectId = stallionStateManager.stallionConfig.projectId ?: @""; NSString *appVersion = stallionStateManager.stallionConfig.appVersion ?: @""; NSString *uid = stallionStateManager.stallionConfig.uid ?: @""; - + NSMutableDictionary *mutablePayload = [eventPayload mutableCopy]; NSString *uniqueId = [[NSUUID UUID] UUIDString]; mutablePayload[@"eventId"] = uniqueId; @@ -44,6 +46,7 @@ - (void)cacheEvent:(NSString *)eventName eventPayload:(NSDictionary *)eventPaylo mutablePayload[@"platform"] = @"ios"; mutablePayload[@"appVersion"] = appVersion; mutablePayload[@"uid"] = uid; + mutablePayload[@"sdkVersion"] = STALLION_SDK_VERSION; // Store event locally [self storeEventLocally:uniqueId eventPayload:mutablePayload]; } @@ -62,6 +65,11 @@ - (void)storeEventLocally:(NSString *)uniqueId eventPayload:(NSDictionary *)even eventsObject = [NSMutableDictionary dictionary]; } + // Enforce max size + if (eventsObject.count >= MAX_EVENT_STORAGE_LIMIT) { + eventsObject = [NSMutableDictionary dictionary]; + } + eventsObject[uniqueId] = eventPayload; NSData *updatedData = [NSJSONSerialization dataWithJSONObject:eventsObject options:0 error:nil]; diff --git a/ios/main/StallionExceptionHandler.h b/ios/main/StallionExceptionHandler.h index 32a759d..8c0a067 100644 --- a/ios/main/StallionExceptionHandler.h +++ b/ios/main/StallionExceptionHandler.h @@ -2,7 +2,7 @@ // StallionExceptionHandler.h // react-native-stallion // -// Created by Jasbir Singh Shergill on 29/01/25. +// Created by Thor963 on 29/01/25. // #import @@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN @interface StallionExceptionHandler : NSObject + (void)initExceptionHandler; ++ (void)initJavaScriptExceptionHandler; @end diff --git a/ios/main/StallionExceptionHandler.m b/ios/main/StallionExceptionHandler.m deleted file mode 100644 index 64bb74f..0000000 --- a/ios/main/StallionExceptionHandler.m +++ /dev/null @@ -1,94 +0,0 @@ -// -// StallionExceptionHandler.m -// react-native-stallion -// -// Created by Jasbir Singh Shergill on 29/01/25. -// - -#import "StallionExceptionHandler.h" -#import "StallionStateManager.h" -#import "StallionEventHandler.h" -#import "StallionSlotManager.h" -#import "StallionMeta.h" -#import "StallionMetaConstants.h" -#import "StallionObjConstants.h" - -@implementation StallionExceptionHandler - -NSUncaughtExceptionHandler *_defaultExceptionHandler; - -+ (void)initExceptionHandler { - if (!_defaultExceptionHandler) { - _defaultExceptionHandler = NSGetUncaughtExceptionHandler(); - } - NSSetUncaughtExceptionHandler(&handleException); -} - -BOOL exceptionAlertDismissed = FALSE; - -void handleException(NSException *exception) { - StallionStateManager *stateManager = [StallionStateManager sharedInstance]; - StallionMeta *meta = stateManager.stallionMeta; - BOOL isAutoRollback = !stateManager.isMounted; - - NSString *readableError = [exception reason]; - - if (readableError.length > 900) { - readableError = [readableError substringToIndex:900]; - } - - if (meta.switchState == SwitchStateProd) { - NSString *currentHash = [meta getActiveReleaseHash] ?: @""; - - [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_prod_event - eventPayload:@{ - @"meta": readableError, - StallionObjConstants.release_hash_key: currentHash, - StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false" - }]; - if (isAutoRollback) { - [StallionSlotManager rollbackProdWithAutoRollback:YES errorString:readableError]; - } - - } else if (meta.switchState == SwitchStateStage) { - [StallionSlotManager rollbackStage]; - - [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_stage_event - eventPayload:@{ - @"meta": readableError, - StallionObjConstants.release_hash_key: meta.stageNewHash, - StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false" - }]; - - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Stallion Exception Handler" - message:[NSString stringWithFormat:@"%@\n%@", - @"A crash occurred in the app. Build was rolled back. Check crash report below. Continue crash to invoke other exception handlers. \n \n", - readableError] - preferredStyle:UIAlertControllerStyleAlert]; - - [alert addAction:[UIAlertAction actionWithTitle:@"Continue Crash" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) { - exceptionAlertDismissed = TRUE; - }]]; - - UIApplication *app = [UIApplication sharedApplication]; - UIViewController *rootViewController = app.delegate.window.rootViewController; - - dispatch_async(dispatch_get_main_queue(), ^{ - [rootViewController presentViewController:alert animated:YES completion:nil]; - }); - - while (exceptionAlertDismissed == FALSE) { - [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - } - } - - // Call default exception handler if available - if (_defaultExceptionHandler) { - _defaultExceptionHandler(exception); - } -} - -@end - diff --git a/ios/main/StallionExceptionHandler.mm b/ios/main/StallionExceptionHandler.mm new file mode 100644 index 0000000..e13cdd5 --- /dev/null +++ b/ios/main/StallionExceptionHandler.mm @@ -0,0 +1,379 @@ +// +// StallionExceptionHandler.mm +// react-native-stallion +// +// Created by Thor963 on 29/01/25. +// + +#import "StallionExceptionHandler.h" +#import "StallionStateManager.h" +#import "StallionEventHandler.h" +#import "StallionSlotManager.h" +#import "StallionMeta.h" +#import "StallionMetaConstants.h" +#import "StallionObjConstants.h" +#import "StallionFileManager.h" +#import +#import +#import +#import +#import +#include + +// Forward declarations +void handleException(NSException *exception); +void handleSignal(int signal, siginfo_t *info, void *context); +static void performStallionRollback(NSString *errorString); +static void setupSignalHandlers(void); +static void processNativeCrashMarkerIfPresent(void); + +// Async-signal-safe crash marker storage +static char g_marker_path[512]; +static char g_mount_marker_path[512]; + +@implementation StallionExceptionHandler + +NSUncaughtExceptionHandler *_defaultExceptionHandler; +static std::atomic exceptionAlertDismissed(false); +static std::atomic exceptionAlertShowing(false); +static std::atomic rollbackPerformed(false); +static std::atomic hasProcessedNativeCrashMarker(false); +static struct sigaction _previousHandlers[32]; // Store previous handlers for chaining + ++ (void)initExceptionHandler { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Reset rollback flag when initializing exception handler + [self resetRollbackFlag]; + + // Store and set Objective-C exception handler + if (!_defaultExceptionHandler) { + _defaultExceptionHandler = NSGetUncaughtExceptionHandler(); + } + NSSetUncaughtExceptionHandler(&handleException); + + // Setup signal handlers using sigaction with chaining + setupSignalHandlers(); + + // Initialize JavaScript exception handler + [self initJavaScriptExceptionHandler]; + + // Process any crash marker from previous session + processNativeCrashMarkerIfPresent(); + }); +} + ++ (void)initJavaScriptExceptionHandler { + // Handle fatal JavaScript errors that cause app crashes + RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + // Rollback only for fatal errors that crash the app + if (level >= RCTLogLevelFatal) { + NSString *errorString = [NSString stringWithFormat:@"Fatal JS Error in %@:%@ - %@", fileName, lineNumber, message]; + performStallionRollback(errorString); + } + }); +} + ++ (void)resetRollbackFlag { + rollbackPerformed.store(false); +} + +@end + +#pragma mark - Shared Rollback Logic + +static void performStallionRollback(NSString *errorString) { + + StallionStateManager *stateManager = [StallionStateManager sharedInstance]; + StallionMeta *meta = stateManager.stallionMeta; + BOOL isAutoRollback = !stateManager.isMounted; + + + // Only prevent multiple executions for auto rollback cases + // Launch crashes (when mounted) can continue to be registered + if (isAutoRollback) { + // Use compare-and-swap to atomically check and set the flag + bool expected = false; + if (!rollbackPerformed.compare_exchange_strong(expected, true)) { + // Flag was already true, skip duplicate rollback + return; + } + } + + if (errorString.length > 900) { + errorString = [errorString substringToIndex:900]; + } + + if (meta.switchState == SwitchStateProd) { + NSString *currentHash = [meta getActiveReleaseHash] ?: @""; + + [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_prod_event + eventPayload:@{ + @"meta": errorString, + StallionObjConstants.release_hash_key: currentHash, + StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false" + }]; + if (isAutoRollback) { + [StallionSlotManager rollbackProdWithAutoRollback:YES errorString:errorString]; + } + + } else if (meta.switchState == SwitchStateStage) { + NSString *currentStageHash = meta.stageNewHash ?: @""; + + // Emit exception event before rollback (consistent with PROD and Android) + [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_stage_event + eventPayload:@{ + @"meta": errorString, + StallionObjConstants.release_hash_key: currentStageHash, + StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false" + }]; + + if(isAutoRollback) { + [StallionSlotManager rollbackStage]; + } + + // Check if alert is already showing (atomic check to prevent duplicates) + bool expectedShowing = false; + if (exceptionAlertShowing.compare_exchange_strong(expectedShowing, true)) { + // We successfully claimed the right to show the alert + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Stallion Exception Handler" + message:[NSString stringWithFormat:@"%@\n%@", + @"A crash occurred in the app. Build was rolled back. Check crash report below. Continue crash to invoke other exception handlers. \n \n", + errorString] + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addAction:[UIAlertAction actionWithTitle:@"Continue Crash" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + // Set flag to true only when button is pressed + exceptionAlertDismissed.store(true); + }]]; + + UIApplication *app = [UIApplication sharedApplication]; + UIViewController *rootViewController = app.delegate.window.rootViewController; + + dispatch_async(dispatch_get_main_queue(), ^{ + [rootViewController presentViewController:alert animated:YES completion:nil]; + }); + + // Wait for user to press the button (exceptionAlertDismissed becomes true) + while (!exceptionAlertDismissed.load()) { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } + } + } +} + +#pragma mark - Signal Handler Setup + +// Async-signal-safe function to check if mount marker exists +static int is_mounted_safe(void) { + 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_safe(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 setupSignalHandlers(void) { + // Initialize marker paths from StallionStateManager + StallionStateManager *stateManager = [StallionStateManager sharedInstance]; + NSString *filesDir = stateManager.stallionConfig.filesDirectory; + if (filesDir) { + const char *path = [filesDir UTF8String]; + 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"); + } + + struct sigaction action; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = handleSignal; + + // List of signals to catch - comprehensive coverage + int signals[] = { + SIGABRT, // Abort signal + SIGILL, // Illegal instruction + SIGSEGV, // Segmentation violation + SIGFPE, // Floating point exception + SIGBUS, // Bus error + SIGTRAP, // Trace/breakpoint trap + SIGPIPE, // Broken pipe + SIGSYS, // Bad system call + }; + + 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, &_previousHandlers[sig]); + // Now install our handler + sigaction(sig, &action, NULL); + } +} + +void handleException(NSException *exception) { + NSString *readableError = [exception reason] ?: @"Unknown exception"; + NSString *name = [exception name] ?: @"Unknown"; + NSString *callStack = [[exception callStackSymbols] componentsJoinedByString:@"\n"]; + NSString *fullError = [NSString stringWithFormat:@"Exception: %@\nReason: %@\nStack:\n%@", name, readableError, callStack]; + + performStallionRollback(fullError); + + // Chain to default exception handler if available + if (_defaultExceptionHandler) { + _defaultExceptionHandler(exception); + } +} + +void handleSignal(int signalVal, siginfo_t *info, void *context) { + + if (!rollbackPerformed.load()) { + // Async-signal-safe operations only + // Read mount state at crash time (async-signal-safe) + int mounted = is_mounted_safe(); + // Write JSON marker with crash info and autoRollback flag + write_crash_marker_json_safe(signalVal, mounted); + } + + // Chain to previous handler if it exists and is valid (bubble up) + if (signalVal >= 0 && signalVal < 32) { + struct sigaction *prev = &_previousHandlers[signalVal]; + 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 != handleSignal) { + if (prev->sa_flags & SA_SIGINFO) { + prev->sa_sigaction(signalVal, info, context); + } else if (prev->sa_handler != SIG_DFL && prev->sa_handler != SIG_IGN) { + prev->sa_handler(signalVal); + } + } + } + } + + // Restore default and raise to proceed with crash + signal(signalVal, SIG_DFL); + raise(signalVal); +} + +#pragma mark - Crash Marker Processing + +static void processNativeCrashMarkerIfPresent(void) { + @try { + if (hasProcessedNativeCrashMarker.load()) { + return; + } + + StallionStateManager *stateManager = [StallionStateManager sharedInstance]; + NSString *filesDir = stateManager.stallionConfig.filesDirectory; + NSString *markerPath = [NSString stringWithFormat:@"%@/stallion_crash.marker", filesDir]; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:markerPath]) { + NSError *error = nil; + NSString *jsonContent = [NSString stringWithContentsOfFile:markerPath + encoding:NSUTF8StringEncoding + error:&error]; + + if (jsonContent && !error) { + NSString *stackTraceString = @""; + BOOL isAutoRollback = NO; + + @try { + // Parse JSON from previous crash + NSData *jsonData = [jsonContent dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *crashMarker = [NSJSONSerialization JSONObjectWithData:jsonData + options:0 + error:&error]; + if (crashMarker && !error) { + // Extract crash log and autoRollback flag from marker + stackTraceString = crashMarker[@"crashLog"] ?: @""; + // Use the autoRollback flag that was determined at crash time (previous session) + isAutoRollback = [crashMarker[@"isAutoRollback"] boolValue]; + } + } @catch (NSException *e) { + // Fallback for old format (non-JSON) + stackTraceString = jsonContent; + // Default to true for old format (conservative approach) + isAutoRollback = YES; + } + + if (stackTraceString.length > 900) { + stackTraceString = [stackTraceString substringToIndex:900]; + } + + StallionMeta *meta = stateManager.stallionMeta; + SwitchState switchState = meta.switchState; + + if (switchState == SwitchStateProd) { + NSString *currentHash = [meta getActiveReleaseHash] ?: @""; + // Use isAutoRollback from previous crash, not current session state + @try { + [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_prod_event + eventPayload:@{ + @"meta": stackTraceString, + StallionObjConstants.release_hash_key: currentHash, + StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false" + }]; + } @catch (NSException *e) { } + + if (isAutoRollback) { + // Only prevent multiple executions for auto rollback cases + bool expected = false; + if (rollbackPerformed.compare_exchange_strong(expected, true)) { + @try { + [StallionSlotManager rollbackProdWithAutoRollback:YES errorString:stackTraceString]; + } @catch (NSException *e) { } + } + } + } else if (switchState == SwitchStateStage) { + NSString *currentStageHash = meta.stageNewHash ?: @""; + // Use isAutoRollback from previous crash, not current session state + @try { + [[StallionEventHandler sharedInstance] cacheEvent:StallionObjConstants.exception_stage_event + eventPayload:@{ + @"meta": stackTraceString, + StallionObjConstants.release_hash_key: currentStageHash, + StallionObjConstants.is_auto_rollback_key: isAutoRollback ? @"true" : @"false" + }]; + } @catch (NSException *e) { } + + if (isAutoRollback) { + // Only prevent multiple executions for auto rollback cases + bool expected = false; + if (rollbackPerformed.compare_exchange_strong(expected, true)) { + @try { + [StallionSlotManager rollbackStage]; + } @catch (NSException *e) { } + } + } + } + + // Delete marker + [StallionFileManager deleteFileOrFolderSilently:markerPath]; + hasProcessedNativeCrashMarker.store(true); + } + } + } @catch (NSException *e) { } +} + diff --git a/ios/main/StallionFileDownloader.swift b/ios/main/StallionFileDownloader.swift index 619b256..1f45bdc 100644 --- a/ios/main/StallionFileDownloader.swift +++ b/ios/main/StallionFileDownloader.swift @@ -17,6 +17,7 @@ class StallionFileDownloader: NSObject { private var _reject: RCTPromiseRejectBlock? private var _onProgress: ((Float) -> Void)? private var lastSentProgress: Float = 0 + private var lastProgressEmitTime: TimeInterval = 0 private var _downloadDirectory: String? private let queue = DispatchQueue(label: "com.stallion.networkmanager", qos: .background) @@ -116,13 +117,20 @@ class StallionFileDownloader: NSObject { guard bytesRead == headerSize else { return false } return header == [0x50, 0x4B, 0x03, 0x04] // PKZIP magic number } + + private func shouldEmitProgress(currentTime: TimeInterval) -> Bool { + return currentTime - self.lastProgressEmitTime >= StallionConstants.PROGRESS_THROTTLE_INTERVAL_MS + } } extension StallionFileDownloader: URLSessionDownloadDelegate { func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) - if progress - self.lastSentProgress > StallionConstants.PROGRESS_EVENT_THRESHOLD { + let currentTime = Date().timeIntervalSince1970 + + if shouldEmitProgress(currentTime: currentTime) { self.lastSentProgress = progress + self.lastProgressEmitTime = currentTime self._onProgress?(progress) } } diff --git a/ios/main/StallionFileManager.h b/ios/main/StallionFileManager.h index cc63c28..55a0394 100644 --- a/ios/main/StallionFileManager.h +++ b/ios/main/StallionFileManager.h @@ -2,7 +2,7 @@ // StallionFileManager.h // react-native-stallion // -// Created by Jasbir Singh Shergill on 29/01/25. +// Created by Thor963 on 29/01/25. // #import diff --git a/ios/main/StallionFileManager.m b/ios/main/StallionFileManager.m index 6af03c2..71c3618 100644 --- a/ios/main/StallionFileManager.m +++ b/ios/main/StallionFileManager.m @@ -2,7 +2,7 @@ // StallionFileManager.m // react-native-stallion // -// Created by Jasbir Singh Shergill on 29/01/25. +// Created by Thor963 on 29/01/25. // #import "StallionFileManager.h" diff --git a/ios/main/StallionMeta.h b/ios/main/StallionMeta.h index 7c3caa0..2ea25e3 100644 --- a/ios/main/StallionMeta.h +++ b/ios/main/StallionMeta.h @@ -2,7 +2,7 @@ // StallionMeta.h // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import @@ -20,10 +20,21 @@ @property (nonatomic, copy) NSString *prodNewHash; @property (nonatomic, copy) NSString *prodStableHash; @property (nonatomic, copy) NSString *lastRolledBackHash; +@property (nonatomic, assign) NSTimeInterval lastRolledBackAt; +@property (nonatomic, assign) NSInteger successfulLaunchCount; +@property (nonatomic, copy) NSString *lastSuccessfulLaunchHash; + ++ (NSInteger)maxSuccessLaunchThreshold; ++ (NSTimeInterval)lastRolledBackTTL; - (void)reset; - (NSDictionary *)toDictionary; +- (NSString *)getHashAtCurrentProdSlot; - (NSString *)getActiveReleaseHash; +- (NSString *)getLastRolledBackHash; +- (void)setLastRolledBackHashWithTimestamp:(NSString *)lastRolledBackHash; +- (void)markSuccessfulLaunch:(NSString *)releaseHash; +- (NSInteger)getSuccessfulLaunchCount:(NSString *)releaseHash; + (instancetype)fromDictionary:(NSDictionary *)dict; @end diff --git a/ios/main/StallionMeta.m b/ios/main/StallionMeta.m index 3777c5d..e2ea27a 100644 --- a/ios/main/StallionMeta.m +++ b/ios/main/StallionMeta.m @@ -2,13 +2,21 @@ // StallionMeta.m // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import "StallionMeta.h" @implementation StallionMeta ++ (NSInteger)maxSuccessLaunchThreshold { + return 3; +} + ++ (NSTimeInterval)lastRolledBackTTL { + return 6 * 60 * 60; // 6 hours in seconds +} + - (instancetype)init { self = [super init]; if (self) [self reset]; @@ -26,6 +34,9 @@ - (void)reset { self.prodNewHash = @""; self.prodStableHash = @""; self.lastRolledBackHash = @""; + self.lastRolledBackAt = 0.0; + self.successfulLaunchCount = 0; + self.lastSuccessfulLaunchHash = @""; } - (NSDictionary *)toDictionary { @@ -43,7 +54,10 @@ - (NSDictionary *)toDictionary { @"stableHash": self.prodStableHash ?: @"", @"currentSlot": [StallionMetaConstants stringFromSlotState:self.currentProdSlot] ?: @"" }, - @"lastRolledBackHash": self.lastRolledBackHash ?: @"" + @"lastRolledBackHash": self.lastRolledBackHash ?: @"", + @"lastRolledBackAt": @(self.lastRolledBackAt), + @"successfulLaunchCount": @(self.successfulLaunchCount), + @"lastSuccessfulLaunchHash": self.lastSuccessfulLaunchHash ?: @"" }; } @catch (NSException *exception) { NSLog(@"Error in toDictionary: %@", exception.reason); @@ -87,6 +101,9 @@ + (instancetype)fromDictionary:(NSDictionary *)dict { meta.currentProdSlot = [StallionMetaConstants slotStateFromString:prodSlot[@"currentSlot"] ?: @"default_slot"]; meta.lastRolledBackHash = dict[@"lastRolledBackHash"] ?: @""; + meta.lastRolledBackAt = [dict[@"lastRolledBackAt"] doubleValue]; + meta.successfulLaunchCount = [dict[@"successfulLaunchCount"] integerValue]; + meta.lastSuccessfulLaunchHash = dict[@"lastSuccessfulLaunchHash"] ?: @""; return meta; } @catch (NSException *exception) { @@ -95,4 +112,62 @@ + (instancetype)fromDictionary:(NSDictionary *)dict { } } + - (NSString *)getHashAtCurrentProdSlot { + switch (self.currentProdSlot) { + case SlotStateNewSlot: + return self.prodNewHash; + case SlotStateStableSlot: + return self.prodStableHash; + default: + return @""; + } + } + + - (NSString *)getLastRolledBackHash { + [self enforceLastRolledBackExpiry]; + return self.lastRolledBackHash; + } + +- (void)setLastRolledBackHashWithTimestamp:(NSString *)lastRolledBackHash { + NSString *hashValue = lastRolledBackHash ?: @""; + self.lastRolledBackHash = hashValue; + self.lastRolledBackAt = [hashValue isEqualToString:@""] ? 0.0 : [[NSDate date] timeIntervalSince1970]; +} + + - (void)enforceLastRolledBackExpiry { + if (!self.lastRolledBackHash || [self.lastRolledBackHash isEqualToString:@""]) { + return; + } + if (self.lastRolledBackAt <= 0.0) { + return; + } + NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; + if (now - self.lastRolledBackAt >= [StallionMeta lastRolledBackTTL]) { + self.lastRolledBackHash = @""; + self.lastRolledBackAt = 0.0; + } + } + + - (void)markSuccessfulLaunch:(NSString *)releaseHash { + if (!releaseHash || [releaseHash isEqualToString:@""]) { + return; + } + if (![releaseHash isEqualToString:self.lastSuccessfulLaunchHash]) { + self.successfulLaunchCount = 0; + self.lastSuccessfulLaunchHash = releaseHash; + } + if (self.successfulLaunchCount < 3) { // MAX_SUCCESS_LAUNCH_THRESHOLD + self.successfulLaunchCount += 1; + } + } + + - (NSInteger)getSuccessfulLaunchCount:(NSString *)releaseHash { + NSString *currentHash = releaseHash ?: @""; + if (![currentHash isEqualToString:self.lastSuccessfulLaunchHash]) { + return 0; + } else { + return self.successfulLaunchCount; + } + } + @end diff --git a/ios/main/StallionMetaConstants.h b/ios/main/StallionMetaConstants.h index 9b820cc..db6b330 100644 --- a/ios/main/StallionMetaConstants.h +++ b/ios/main/StallionMetaConstants.h @@ -2,7 +2,7 @@ // StallionMetaConstants.h // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import diff --git a/ios/main/StallionMetaConstants.m b/ios/main/StallionMetaConstants.m index 47c62a2..817e808 100644 --- a/ios/main/StallionMetaConstants.m +++ b/ios/main/StallionMetaConstants.m @@ -2,7 +2,7 @@ // StallionMetaConstants.m // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import "StallionMetaConstants.h" diff --git a/ios/main/StallionSignatureVerification.swift b/ios/main/StallionSignatureVerification.swift new file mode 100644 index 0000000..f192d13 --- /dev/null +++ b/ios/main/StallionSignatureVerification.swift @@ -0,0 +1,135 @@ +import Foundation +import CommonCrypto +import Security + +class StallionSignatureVerification { + + static let signatureFileName = ".stallionsigned" + + static func verifyReleaseSignature(downloadedBundlePath: String, publicKeyPem: String) -> Bool { + do { + let signatureFilePath = (downloadedBundlePath as NSString).appendingPathComponent(signatureFileName) + guard FileManager.default.fileExists(atPath: signatureFilePath) else { return false } + + let jwt = try String(contentsOfFile: signatureFilePath, encoding: .utf8) + let parts = jwt.components(separatedBy: ".") + guard parts.count == 3 else { return false } + let header = parts[0] + let payload = parts[1] + let signatureB64 = parts[2] + + guard let signatureData = base64UrlDecode(signatureB64), + let signedData = (header + "." + payload).data(using: .utf8) else { return false } + + guard let pubKey = try? convertPemToPublicKey(pemString: publicKeyPem) else { return false } + + var error: Unmanaged? + let verified = SecKeyVerifySignature( + pubKey, + .rsaSignatureMessagePKCS1v15SHA256, + signedData as CFData, + signatureData as CFData, + &error + ) + + guard verified else { return false } + + guard let payloadData = base64UrlDecode(payload), + let payloadJson = try JSONSerialization.jsonObject(with: payloadData) as? [String: Any], + let expectedHash = payloadJson["packageHash"] as? String else { return false } + + let actualHash = try computeCodePushStyleHash(folderPath: downloadedBundlePath) + return expectedHash == actualHash + + } catch { + print("Signature verification error: \(error)") + return false + } + } + + private static func computeCodePushStyleHash(folderPath: String) throws -> String { + var manifest: [String] = [] + try addContentsOfFolder(to: &manifest, folderPath: folderPath, pathPrefix: "") + let sortedManifest = manifest.sorted() + let jsonData = try JSONSerialization.data(withJSONObject: sortedManifest, options: []) + var jsonString = String(data: jsonData, encoding: .utf8) ?? "" + jsonString = jsonString.replacingOccurrences(of: "\\/", with: "/") + return sha256Hex(jsonString) + } + + private static func addContentsOfFolder(to manifest: inout [String], folderPath: String, pathPrefix: String) throws { + let items = try FileManager.default.contentsOfDirectory(atPath: folderPath) + for item in items { + let fullPath = (folderPath as NSString).appendingPathComponent(item) + let relativePath = pathPrefix.isEmpty ? item : (pathPrefix as NSString).appendingPathComponent(item) + + if isIgnored(relativePath) { continue } + + var isDir: ObjCBool = false + FileManager.default.fileExists(atPath: fullPath, isDirectory: &isDir) + + if isDir.boolValue { + try addContentsOfFolder(to: &manifest, folderPath: fullPath, pathPrefix: relativePath) + } else { + let data = try Data(contentsOf: URL(fileURLWithPath: fullPath)) + let hash = sha256Hex(data) + manifest.append("\(relativePath):\(hash)") + } + } + } + + private static func isIgnored(_ path: String) -> Bool { + return path.hasPrefix("__MACOSX/") || + path == ".DS_Store" || + path.hasSuffix("/.DS_Store") || + path == signatureFileName || + path.hasSuffix("/\(signatureFileName)") + } + + private static func sha256Hex(_ input: String) -> String { + guard let data = input.data(using: .utf8) else { return "" } + return sha256Hex(data) + } + + private static func sha256Hex(_ data: Data) -> String { + var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) + data.withUnsafeBytes { + _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &digest) + } + return digest.map { String(format: "%02x", $0) }.joined() + } + + private static func base64UrlDecode(_ input: String) -> Data? { + var base64 = input.replacingOccurrences(of: "-", with: "+") + .replacingOccurrences(of: "_", with: "/") + let padding = base64.count % 4 + if padding > 0 { + base64 += String(repeating: "=", count: 4 - padding) + } + return Data(base64Encoded: base64) + } + + private static func convertPemToPublicKey(pemString: String) throws -> SecKey { + let cleaned = pemString + .replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----\n", with: "") + .replacingOccurrences(of: "-----END PUBLIC KEY-----", with: "") + .replacingOccurrences(of: "\n", with: "") + .replacingOccurrences(of: "\r", with: "") + + guard let keyData = Data(base64Encoded: cleaned, options: .ignoreUnknownCharacters) else { + throw NSError(domain: "Stallion", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid base64 key"]) + } + + let keyDict: [String: Any] = [ + kSecAttrKeyType as String: kSecAttrKeyTypeRSA, + kSecAttrKeyClass as String: kSecAttrKeyClassPublic, + kSecAttrKeySizeInBits as String: 2048 + ] + + var error: Unmanaged? + guard let secKey = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, &error) else { + throw error!.takeRetainedValue() as Error + } + return secKey + } +} diff --git a/ios/main/StallionSlotManager.h b/ios/main/StallionSlotManager.h index e19d366..b836db1 100644 --- a/ios/main/StallionSlotManager.h +++ b/ios/main/StallionSlotManager.h @@ -2,7 +2,7 @@ // StallionSlotManager.h // react-native-stallion // -// Created by Jasbir Singh Shergill on 29/01/25. +// Created by Thor963 on 29/01/25. // #import diff --git a/ios/main/StallionSlotManager.m b/ios/main/StallionSlotManager.m index 75723f2..bd15401 100644 --- a/ios/main/StallionSlotManager.m +++ b/ios/main/StallionSlotManager.m @@ -2,7 +2,7 @@ // StallionSlotManager.m // react-native-stallion // -// Created by Jasbir Singh Shergill on 29/01/25. +// Created by Thor963 on 29/01/25. // #import "StallionSlotManager.h" @@ -74,7 +74,7 @@ + (void)stabilizeProd { NSString *newSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.new_folder_slot]; NSString *stableSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.stable_folder_slot]; - [StallionFileManager copyFileOrDirectoryFrom:newSlotPath to:stableSlotPath]; + [StallionFileManager moveFileFrom:newSlotPath to:stableSlotPath]; NSString *newReleaseHash = stateManager.stallionMeta.prodNewHash; [stateManager.stallionMeta setProdStableHash:newReleaseHash]; @@ -96,7 +96,7 @@ + (void)emitRollbackEvent:(BOOL)isAutoRollback rolledBackReleaseHash:(NSString * if (isAutoRollback) { StallionStateManager *stateManager = [StallionStateManager sharedInstance]; - [stateManager.stallionMeta setLastRolledBackHash:rolledBackReleaseHash]; + [stateManager.stallionMeta setLastRolledBackHashWithTimestamp:rolledBackReleaseHash]; [stateManager syncStallionMeta]; } diff --git a/ios/main/StallionStageManager.swift b/ios/main/StallionStageManager.swift index 86da160..021dad8 100644 --- a/ios/main/StallionStageManager.swift +++ b/ios/main/StallionStageManager.swift @@ -2,7 +2,7 @@ // StallionStageManager.swift // react-native-stallion // -// Created by Jasbir Singh Shergill on 29/01/25. +// Created by Thor963 on 29/01/25. // import Foundation diff --git a/ios/main/StallionStateManager.h b/ios/main/StallionStateManager.h index 59e6fcc..9a298b1 100644 --- a/ios/main/StallionStateManager.h +++ b/ios/main/StallionStateManager.h @@ -2,7 +2,7 @@ // StallionStateManager.h // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import diff --git a/ios/main/StallionStateManager.m b/ios/main/StallionStateManager.m index c5fdf93..758b5c5 100644 --- a/ios/main/StallionStateManager.m +++ b/ios/main/StallionStateManager.m @@ -2,7 +2,7 @@ // StallionStateManager.m // DoubleConversion // -// Created by Jasbir Singh Shergill on 28/01/25. +// Created by Thor963 on 28/01/25. // #import "StallionStateManager.h" @@ -44,6 +44,9 @@ - (instancetype)init { _isMounted = NO; _pendingReleaseUrl = @""; _pendingReleaseHash = @""; + + // Reset mount state on initialization (ensures mount marker file is deleted for new session) + [self setIsMounted:NO]; } return self; } @@ -70,6 +73,32 @@ - (void)clearStallionMeta { [self syncStallionMeta]; } +- (void)setIsMounted:(BOOL)isMounted { + _isMounted = isMounted; + // Write mount state to a simple file that signal handler can read (async-signal-safe) + NSString *filesDir = self.stallionConfig.filesDirectory; + NSString *mountMarkerPath = [NSString stringWithFormat:@"%@/stallion_mount.marker", filesDir]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + if (isMounted) { + // Create file to indicate mounted (file existence = mounted) + @try { + [fileManager createFileAtPath:mountMarkerPath contents:nil attributes:nil]; + } @catch (NSException *e) { + // Silently ignore errors + } + } else { + // Delete file to indicate not mounted (no file = not mounted) + @try { + if ([fileManager fileExistsAtPath:mountMarkerPath]) { + [fileManager removeItemAtPath:mountMarkerPath error:nil]; + } + } @catch (NSException *e) { + // Silently ignore errors + } + } +} + #pragma mark - Local Storage Methods - (NSString *)getStringForKey:(NSString *)key defaultValue:(NSString *)defaultValue { diff --git a/ios/main/StallionSyncHandler.swift b/ios/main/StallionSyncHandler.swift index 93d6867..8136da0 100644 --- a/ios/main/StallionSyncHandler.swift +++ b/ios/main/StallionSyncHandler.swift @@ -2,7 +2,7 @@ // StallionSyncHandler.swift // react-native-stallion // -// Created by Jasbir Singh Shergill on 29/01/25. +// Created by Thor963 on 29/01/25. // import Foundation @@ -46,6 +46,7 @@ class StallionSyncHandler { "platform": StallionConstants.PlatformValue, "projectId": projectId, "appliedBundleHash": appliedBundleHash, + "deviceMeta": StallionDeviceInfo.getDeviceMetaJson(config) ] // Make API call using URLSession @@ -151,9 +152,10 @@ class StallionSyncHandler { !newReleaseHash.isEmpty else { return } let stateManager = StallionStateManager.sharedInstance() - let lastRolledBackHash = stateManager?.stallionMeta?.lastRolledBackHash ?? "" + let lastRolledBackHash = stateManager?.stallionMeta?.getLastRolledBackHash() ?? "" + let lastUnverifiedHash = stateManager?.stallionConfig?.lastUnverifiedHash ?? "" - if newReleaseHash != lastRolledBackHash { + if newReleaseHash != lastRolledBackHash && newReleaseHash != lastUnverifiedHash { if stateManager?.isMounted == true { downloadNewRelease(newReleaseHash: newReleaseHash, newReleaseUrl: newReleaseUrl) } else { @@ -179,29 +181,52 @@ class StallionSyncHandler { let downloadPath = config.filesDirectory + "/" + StallionConstants.PROD_DIRECTORY + "/" + StallionConstants.TEMP_FOLDER_SLOT let projectId = config.projectId ?? "" + let publicSigningKey = config.publicSigningKey ?? "" + guard let fromUrl = URL(string: newReleaseUrl + "?projectId=" + projectId) else { return } emitDownloadStarted(releaseHash: newReleaseHash) - StallionFileDownloader().downloadBundle(url: fromUrl, downloadDirectory: downloadPath, onProgress: { progress in - // Handle progress updates if necessary - }, resolve: { _ in - completeDownload() - stateManager.stallionMeta?.currentProdSlot = SlotStates.newSlot - stateManager.stallionMeta?.prodTempHash = newReleaseHash - if let currentProdNewHash = stateManager.stallionMeta?.prodNewHash, - !currentProdNewHash.isEmpty { - StallionSlotManager.stabilizeProd() - } - stateManager.syncStallionMeta() - emitDownloadSuccess(releaseHash: newReleaseHash) - }, reject: { code, prefix, error in - completeDownload() - emitDownloadError( - releaseHash: newReleaseHash, - error: "\(String(describing: prefix))\(String(describing: error))" + StallionFileDownloader().downloadBundle( + url: fromUrl, + downloadDirectory: downloadPath, + onProgress: { progress in + emitDownloadProgress(releaseHash: newReleaseHash, progress: progress) + }, + resolve: { _ in + completeDownload() + + if(publicSigningKey != nil && !publicSigningKey.isEmpty) { + if( + !StallionSignatureVerification.verifyReleaseSignature( + downloadedBundlePath: downloadPath + "/" + StallionConstants.FilePaths.ZipFolderName, + publicKeyPem: publicSigningKey + ) + ) { + // discard downloaded release + config.updateLastUnverifiedHash(newReleaseHash) + emitSignatureVerificationFailed(releaseHash: newReleaseHash) + StallionFileManager.deleteFileOrFolderSilently(downloadPath) + return; + } + } + stateManager.stallionMeta?.currentProdSlot = SlotStates.newSlot + stateManager.stallionMeta?.prodTempHash = newReleaseHash + if let currentProdNewHash = stateManager.stallionMeta?.prodNewHash, + !currentProdNewHash.isEmpty { + StallionSlotManager.stabilizeProd() + } + stateManager.syncStallionMeta() + emitDownloadSuccess(releaseHash: newReleaseHash) + }, + reject: { code, prefix, error in + completeDownload() + emitDownloadError( + releaseHash: newReleaseHash, + error: "\(String(describing: prefix))\(String(describing: error))" + ) + } ) - }) } private static func completeDownload() { @@ -246,5 +271,24 @@ class StallionSyncHandler { shouldCache: true ) } + + private static func emitSignatureVerificationFailed(releaseHash: String) { + let verificationFailurePayload: NSDictionary = ["releaseHash": releaseHash] + Stallion.sendEventToRn(eventName: StallionConstants.NativeEventTypesProd.SIGNATURE_VERIFICATION_FAILED, + eventBody: verificationFailurePayload, + shouldCache: true + ) + } + + private static func emitDownloadProgress(releaseHash: String, progress: Float) { + let progressPayload: NSDictionary = [ + "releaseHash": releaseHash, + "progress": "\(progress)" + ] + Stallion.sendEventToRn(eventName: StallionConstants.NativeEventTypesProd.DOWNLOAD_PROGRESS_PROD, + eventBody: progressPayload, + shouldCache: false + ) + } } diff --git a/package.json b/package.json index 7861a69..da0617d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-stallion", - "version": "2.2.0", + "version": "2.3.0", "description": "Offical React Native SDK for Stallion", "main": "index", "types": "types/index.d.ts", diff --git a/react-native-stallion.podspec b/react-native-stallion.podspec index 4da7d09..82a8fc2 100644 --- a/react-native-stallion.podspec +++ b/react-native-stallion.podspec @@ -3,6 +3,28 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' +# Generate StallionVersion.h during pod install +version_header_path = File.join(__dir__, "ios/main/StallionVersion.h") +version_header_content = <<~HEADER + // + // StallionVersion.h + // react-native-stallion + // + // Auto-generated from package.json during pod install + // Do not edit this file manually + // + + #ifndef StallionVersion_h + #define StallionVersion_h + + #define STALLION_SDK_VERSION @"#{package["version"]}" + + #endif /* StallionVersion_h */ +HEADER + +File.write(version_header_path, version_header_content) +puts "Stallion: Generated StallionVersion.h with version #{package["version"]}" + Pod::Spec.new do |s| s.name = "react-native-stallion" s.version = package["version"] diff --git a/src/index.tsx b/src/index.tsx index 4105626..3277e9b 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -29,3 +29,5 @@ export { sync, restart } from './main/utils/StallionNativeUtils'; export { useStallionUpdate } from './main/utils/useStallionUpdate'; export const addEventListener = stallionEventEmitter.addEventListener.bind(stallionEventEmitter); +export const removeEventListener = + stallionEventEmitter.removeEventListener.bind(stallionEventEmitter); diff --git a/src/main/components/modules/listing/components/BundleCardInfoSection.tsx b/src/main/components/modules/listing/components/BundleCardInfoSection.tsx index 6d121a9..d0ce37b 100644 --- a/src/main/components/modules/listing/components/BundleCardInfoSection.tsx +++ b/src/main/components/modules/listing/components/BundleCardInfoSection.tsx @@ -91,7 +91,7 @@ const BundleCardInfoSection: React.FC = ({ {description ? ( {BUNDLE_CARD_RELEASE_NOTE} - + {description} diff --git a/src/main/components/modules/listing/components/styles/index.ts b/src/main/components/modules/listing/components/styles/index.ts index 5b3d4b5..d9e7291 100644 --- a/src/main/components/modules/listing/components/styles/index.ts +++ b/src/main/components/modules/listing/components/styles/index.ts @@ -9,13 +9,14 @@ import { COLORS } from '../../../../../constants/colors'; const styles = StyleSheet.create({ cardContainer: { margin: STD_MARGIN, + marginBottom: STD_MARGIN * 1.5, backgroundColor: COLORS.white, - borderRadius: 8, + borderRadius: STD_MARGIN, shadowColor: COLORS.black, - shadowOffset: { height: 4, width: 4 }, - shadowOpacity: 0.1, - elevation: 2, - shadowRadius: 8, + shadowOffset: { height: 2, width: 0 }, + shadowOpacity: 0.08, + elevation: 3, + shadowRadius: 6, borderWidth: 0.5, borderColor: COLORS.black2, }, @@ -64,8 +65,9 @@ const styles = StyleSheet.create({ }, divider: { borderBottomWidth: 0.5, - opacity: 0.2, - marginBottom: STD_MARGIN, + borderColor: COLORS.black2, + marginVertical: STD_MARGIN, + marginHorizontal: STD_MARGIN, }, subText: { fontSize: HEADER_SLAB_HEIGHT / 3, @@ -86,9 +88,9 @@ const styles = StyleSheet.create({ fontWeight: 'bold', }, releaseNoteText: { - fontSize: 12, - fontWeight: '500', - color: COLORS.text_major, + fontSize: 14, + fontWeight: 'bold', + color: COLORS.black7, }, releaseNoteDescriptionText: { fontSize: 14, @@ -98,9 +100,12 @@ const styles = StyleSheet.create({ }, descContainer: { flexDirection: 'row', - alignItems: 'center', + alignItems: 'flex-start', padding: STD_MARGIN, + marginHorizontal: STD_MARGIN, + marginBottom: STD_MARGIN / 2, backgroundColor: COLORS.black1, + borderRadius: STD_MARGIN / 2, }, rightBorder: { borderRightWidth: 1, diff --git a/src/main/components/modules/listing/index.tsx b/src/main/components/modules/listing/index.tsx index 96f86cb..75ee11b 100644 --- a/src/main/components/modules/listing/index.tsx +++ b/src/main/components/modules/listing/index.tsx @@ -15,6 +15,28 @@ import FooterLoader from '../../common/FooterLoader'; import styles from './styles'; +interface IBucketOrBundle { + data: IBucketCard | IBundleCard; + setBucketSelection: (bucketId?: string | null | undefined) => void; +} + +const BucketOrBundle: React.FC = memo( + ({ data, setBucketSelection }) => { + return data?.type === CARD_TYPES.BUCKET ? ( + setBucketSelection(data.id)} + /> + ) : ( + (data?.type === CARD_TYPES.BUNDLE && ( + + )) || + null + ); + } +); + const Listing: React.FC = () => { const { listingData, @@ -65,25 +87,3 @@ const Listing: React.FC = () => { }; export default memo(Listing); - -interface IBucketOrBundle { - data: IBucketCard | IBundleCard; - setBucketSelection: (bucketId?: string | null | undefined) => void; -} - -const BucketOrBundle: React.FC = memo( - ({ data, setBucketSelection }) => { - return data?.type === CARD_TYPES.BUCKET ? ( - setBucketSelection(data.id)} - /> - ) : ( - (data?.type === CARD_TYPES.BUNDLE && ( - - )) || - null - ); - } -); diff --git a/src/main/components/modules/listing/styles.ts b/src/main/components/modules/listing/styles.ts index 0ec01ba..94eba5f 100644 --- a/src/main/components/modules/listing/styles.ts +++ b/src/main/components/modules/listing/styles.ts @@ -10,6 +10,7 @@ const styles = StyleSheet.create({ mainListContainer: { flexGrow: 1, backgroundColor: COLORS.background_grey, + paddingBottom: STD_MARGIN * 2, }, initalLoaderContainer: { width: '100%', diff --git a/src/main/components/modules/login/index.tsx b/src/main/components/modules/login/index.tsx index 7f85ea6..615c46e 100644 --- a/src/main/components/modules/login/index.tsx +++ b/src/main/components/modules/login/index.tsx @@ -47,12 +47,12 @@ const Login: React.FC = () => { }, [loginUser, pin]); return ( - + {Login_TITLE} { value={pin} onChange={handleNumberFormating} maxLength={PIN_LENGTH} - keyboardType={'numeric'} + keyboardType="numeric" + autoFocus={false} /> @@ -71,10 +72,14 @@ const Login: React.FC = () => { enabled={!userState.isLoading && pin?.length === PIN_LENGTH} /> - {userState.isLoading ? : null} - {userState.error ? ( + {userState.isLoading && ( + + + + )} + {userState.error && ( {userState.error} - ) : null} + )} ); }; diff --git a/src/main/components/modules/login/styles/index.ts b/src/main/components/modules/login/styles/index.ts index fb1277b..175c7d3 100644 --- a/src/main/components/modules/login/styles/index.ts +++ b/src/main/components/modules/login/styles/index.ts @@ -27,11 +27,16 @@ const styles = StyleSheet.create({ }, inputSection: { justifyContent: 'flex-start', + alignItems: 'center', + width: '100%', + paddingTop: STD_MARGIN, }, errorText: { fontSize: HEADER_SLAB_HEIGHT / 4, color: COLORS.red, - padding: HEADER_SLAB_HEIGHT / 2, + padding: STD_MARGIN, + paddingHorizontal: STD_MARGIN * 2, + textAlign: 'center', }, spinnerContainer: { margin: HEADER_SLAB_HEIGHT / 2, @@ -42,9 +47,10 @@ const styles = StyleSheet.create({ borderWidth: 1, borderColor: COLORS.black2, borderRadius: STD_MARGIN, - marginBottom: STD_MARGIN, + marginBottom: STD_MARGIN * 1.5, paddingHorizontal: STD_MARGIN * 2, color: COLORS.text_major, + fontSize: HEADER_SLAB_HEIGHT / 3, }, buttonContainer: { padding: HEADER_SLAB_HEIGHT / 2, diff --git a/src/main/components/modules/modal/StallionModal.tsx b/src/main/components/modules/modal/StallionModal.tsx index e5e5705..2445bdc 100644 --- a/src/main/components/modules/modal/StallionModal.tsx +++ b/src/main/components/modules/modal/StallionModal.tsx @@ -59,9 +59,9 @@ const Content: React.FC = () => { ) : ( )} - {isDownloading ? ( + {isDownloading && ( - ) : null} + )} {loginRequired ? null : (