react-native-stallion 2.0.1 → 2.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/android/src/main/AndroidManifest.xml +7 -1
  2. package/android/src/main/java/com/stallion/Stallion.java +16 -1
  3. package/android/src/main/java/com/stallion/StallionModule.java +8 -6
  4. package/android/src/main/java/com/stallion/events/StallionEventConstants.java +4 -1
  5. package/android/src/main/java/com/stallion/networkmanager/StallionStageManager.java +26 -1
  6. package/android/src/main/java/com/stallion/storage/StallionConfig.java +3 -2
  7. package/android/src/main/java/com/stallion/utils/ProcessPhoenix.java +100 -0
  8. package/ios/main/Stallion-Bridging-Header.h +1 -0
  9. package/ios/main/Stallion.m +2 -0
  10. package/ios/main/Stallion.swift +7 -1
  11. package/ios/main/StallionConstants.swift +3 -0
  12. package/ios/main/StallionModule.m +7 -1
  13. package/ios/main/StallionObjConstants.h +2 -0
  14. package/ios/main/StallionObjConstants.m +4 -0
  15. package/ios/main/StallionSlotManager.m +2 -2
  16. package/ios/main/StallionStageManager.swift +22 -1
  17. package/ios/main/StallionSyncHandler.swift +44 -19
  18. package/package.json +1 -1
  19. package/src/index.js +1 -1
  20. package/src/index.js.map +1 -1
  21. package/src/main/components/common/BackButton/index.js +54 -0
  22. package/src/main/components/common/BackButton/index.js.map +1 -0
  23. package/src/main/components/common/CrossButton/index.js +45 -0
  24. package/src/main/components/common/CrossButton/index.js.map +1 -0
  25. package/src/main/components/common/Footer/index.js +13 -5
  26. package/src/main/components/common/Footer/index.js.map +1 -1
  27. package/src/main/components/common/Footer/styles.js +16 -5
  28. package/src/main/components/common/Footer/styles.js.map +1 -1
  29. package/src/main/components/common/Header/index.js +9 -13
  30. package/src/main/components/common/Header/index.js.map +1 -1
  31. package/src/main/components/common/Header/styles.js +5 -5
  32. package/src/main/components/common/Header/styles.js.map +1 -1
  33. package/src/main/components/modules/listing/components/ConfigView.js +14 -4
  34. package/src/main/components/modules/listing/components/ConfigView.js.map +1 -1
  35. package/src/main/components/modules/listing/components/MetaCard.js +5 -4
  36. package/src/main/components/modules/listing/components/MetaCard.js.map +1 -1
  37. package/src/main/components/modules/listing/components/SlotView.js +47 -51
  38. package/src/main/components/modules/listing/components/SlotView.js.map +1 -1
  39. package/src/main/components/modules/listing/components/styles/index.js +27 -0
  40. package/src/main/components/modules/listing/components/styles/index.js.map +1 -1
  41. package/src/main/components/modules/listing/index.js +5 -6
  42. package/src/main/components/modules/listing/index.js.map +1 -1
  43. package/src/main/components/modules/listing/styles.js +5 -1
  44. package/src/main/components/modules/listing/styles.js.map +1 -1
  45. package/src/main/components/modules/modal/StallionModal.js +3 -3
  46. package/src/main/components/modules/modal/StallionModal.js.map +1 -1
  47. package/src/main/components/modules/modal/hooks/useStallionModal.js +6 -1
  48. package/src/main/components/modules/modal/hooks/useStallionModal.js.map +1 -1
  49. package/src/main/components/modules/prod/prod.js +1 -7
  50. package/src/main/components/modules/prod/prod.js.map +1 -1
  51. package/src/main/components/modules/prod/styles/index.js +4 -1
  52. package/src/main/components/modules/prod/styles/index.js.map +1 -1
  53. package/src/main/constants/appConstants.js +7 -3
  54. package/src/main/constants/appConstants.js.map +1 -1
  55. package/src/main/constants/colors.js +1 -0
  56. package/src/main/constants/colors.js.map +1 -1
  57. package/src/main/state/useStallionEvents.js +4 -1
  58. package/src/main/state/useStallionEvents.js.map +1 -1
  59. package/src/main/utils/StallionNativeUtils.js +1 -0
  60. package/src/main/utils/StallionNativeUtils.js.map +1 -1
  61. package/src/main/utils/getSize.js +11 -0
  62. package/src/main/utils/getSize.js.map +1 -0
  63. package/src/main/utils/useStallionUpdate.js +4 -2
  64. package/src/main/utils/useStallionUpdate.js.map +1 -1
  65. package/types/index.d.ts +1 -1
  66. package/types/index.d.ts.map +1 -1
  67. package/types/main/components/common/BackButton/index.d.ts +9 -0
  68. package/types/main/components/common/BackButton/index.d.ts.map +1 -0
  69. package/types/main/components/common/CrossButton/index.d.ts +9 -0
  70. package/types/main/components/common/CrossButton/index.d.ts.map +1 -0
  71. package/types/main/components/common/Footer/index.d.ts.map +1 -1
  72. package/types/main/components/common/Footer/styles.d.ts +12 -1
  73. package/types/main/components/common/Footer/styles.d.ts.map +1 -1
  74. package/types/main/components/common/Header/index.d.ts.map +1 -1
  75. package/types/main/components/common/Header/styles.d.ts +1 -1
  76. package/types/main/components/modules/listing/components/ConfigView.d.ts.map +1 -1
  77. package/types/main/components/modules/listing/components/MetaCard.d.ts.map +1 -1
  78. package/types/main/components/modules/listing/components/SlotView.d.ts.map +1 -1
  79. package/types/main/components/modules/listing/components/styles/index.d.ts +27 -0
  80. package/types/main/components/modules/listing/components/styles/index.d.ts.map +1 -1
  81. package/types/main/components/modules/listing/index.d.ts.map +1 -1
  82. package/types/main/components/modules/listing/styles.d.ts +4 -0
  83. package/types/main/components/modules/listing/styles.d.ts.map +1 -1
  84. package/types/main/components/modules/modal/StallionModal.d.ts.map +1 -1
  85. package/types/main/components/modules/modal/hooks/useStallionModal.d.ts +1 -0
  86. package/types/main/components/modules/modal/hooks/useStallionModal.d.ts.map +1 -1
  87. package/types/main/components/modules/prod/prod.d.ts.map +1 -1
  88. package/types/main/components/modules/prod/styles/index.d.ts +3 -0
  89. package/types/main/components/modules/prod/styles/index.d.ts.map +1 -1
  90. package/types/main/constants/appConstants.d.ts +7 -4
  91. package/types/main/constants/appConstants.d.ts.map +1 -1
  92. package/types/main/constants/colors.d.ts +1 -0
  93. package/types/main/constants/colors.d.ts.map +1 -1
  94. package/types/main/state/useStallionEvents.d.ts.map +1 -1
  95. package/types/main/utils/StallionNativeUtils.d.ts +1 -0
  96. package/types/main/utils/StallionNativeUtils.d.ts.map +1 -1
  97. package/types/main/utils/getSize.d.ts +2 -0
  98. package/types/main/utils/getSize.d.ts.map +1 -0
  99. package/types/main/utils/useStallionUpdate.d.ts.map +1 -1
@@ -2,7 +2,13 @@
2
2
  package="com.stallion">
3
3
  <application>
4
4
  <activity
5
- android:name="com.stallion.StallionDefaultErrorActivity">
5
+ android:name="com.stallion.utils.StallionErrorActivity">
6
+ </activity>
7
+ <activity
8
+ android:name="com.stallion.utils.ProcessPhoenix"
9
+ android:exported="false"
10
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
11
+ android:noHistory="true">
6
12
  </activity>
7
13
  </application>
8
14
  </manifest>
@@ -88,6 +88,7 @@ public class Stallion {
88
88
  stallionMeta.setStageNewHash(stageTempHash);
89
89
  stallionMeta.setStageTempHash("");
90
90
  stateManager.syncStallionMeta();
91
+ sendInstallEventStage(stageTempHash);
91
92
  } catch (Exception ignored) {}
92
93
  }
93
94
  }
@@ -134,6 +135,20 @@ public class Stallion {
134
135
  }
135
136
  }
136
137
 
138
+ private static void sendInstallEventStage(String releaseHash) {
139
+ try {
140
+ JSONObject eventPayload = new JSONObject();
141
+ eventPayload.put("releaseHash", releaseHash);
142
+
143
+ StallionEventManager.getInstance().sendEvent(
144
+ StallionEventConstants.NativeStageEventTypes.INSTALLED_STAGE.toString(),
145
+ eventPayload
146
+ );
147
+ } catch (Exception e) {
148
+ e.printStackTrace();
149
+ }
150
+ }
151
+
137
152
  private static void sendCorruptionEvent(String releaseHash, String folderPath) {
138
153
  try {
139
154
  JSONObject eventPayload = new JSONObject();
@@ -170,7 +185,7 @@ public class Stallion {
170
185
  return bundlePath;
171
186
  } else {
172
187
  if(isProd) {
173
- StallionSlotManager.rollbackProd(true, "Corruped file not found" + folderPath);
188
+ StallionSlotManager.rollbackProd(false, "Corruped file not found" + folderPath);
174
189
  sendCorruptionEvent(releaseHash, folderPath);
175
190
  } else {
176
191
  StallionSlotManager.rollbackStage();
@@ -1,7 +1,7 @@
1
1
  package com.stallion;
2
2
 
3
- import androidx.annotation.NonNull;
4
3
 
4
+ import androidx.annotation.NonNull;
5
5
  import com.facebook.react.bridge.LifecycleEventListener;
6
6
  import com.facebook.react.bridge.Promise;
7
7
  import com.facebook.react.bridge.ReactApplicationContext;
@@ -17,6 +17,7 @@ import com.stallion.storage.StallionConfigConstants;
17
17
 
18
18
  import com.stallion.storage.StallionMetaConstants;
19
19
  import com.stallion.storage.StallionStateManager;
20
+ import com.stallion.utils.ProcessPhoenix;
20
21
 
21
22
  import org.json.JSONArray;
22
23
  import org.json.JSONException;
@@ -46,11 +47,7 @@ public class StallionModule extends ReactContextBaseJavaModule implements Lifecy
46
47
  public void onHostPause() {}
47
48
 
48
49
  @Override
49
- public void onHostDestroy() {}
50
-
51
- @Override
52
- public void onCatalystInstanceDestroy() {
53
- super.onCatalystInstanceDestroy();
50
+ public void onHostDestroy() {
54
51
  stallionStateManager.setIsMounted(false);
55
52
  getReactApplicationContext().removeLifecycleEventListener(this);
56
53
  }
@@ -165,4 +162,9 @@ public class StallionModule extends ReactContextBaseJavaModule implements Lifecy
165
162
  promise.reject("ACKNOWLEDGE_EVENTS_ERROR", "Failed to acknowledge events: " + e.getMessage(), e);
166
163
  }
167
164
  }
165
+
166
+ @ReactMethod
167
+ public void restart() {
168
+ ProcessPhoenix.triggerRebirth(getReactApplicationContext());
169
+ }
168
170
  }
@@ -18,6 +18,9 @@ public class StallionEventConstants {
18
18
  public enum NativeStageEventTypes {
19
19
  DOWNLOAD_PROGRESS_STAGE,
20
20
  DOWNLOAD_COMPLETE_STAGE,
21
- EXCEPTION_STAGE
21
+ EXCEPTION_STAGE,
22
+ DOWNLOAD_STARTED_STAGE,
23
+ DOWNLOAD_ERROR_STAGE,
24
+ INSTALLED_STAGE,
22
25
  }
23
26
  }
@@ -25,6 +25,7 @@ public class StallionStageManager {
25
25
  + StallionConfigConstants.STAGE_DIRECTORY
26
26
  + StallionConfigConstants.TEMP_FOLDER_SLOT;
27
27
 
28
+ emitDownloadStartedStage(receivedHash);
28
29
  StallionFileDownloader.downloadBundle(
29
30
  receivedDownloadUrl,
30
31
  downloadPath,
@@ -32,6 +33,7 @@ public class StallionStageManager {
32
33
  @Override
33
34
  public void onReject(String prefix, String error) {
34
35
  promise.reject(prefix, error);
36
+ emitDownloadErrorStage(receivedHash, error);
35
37
  }
36
38
 
37
39
  @Override
@@ -57,7 +59,7 @@ public class StallionStageManager {
57
59
  try {
58
60
  successPayload.put("releaseHash", releaseHash);
59
61
  } catch (Exception ignored) { }
60
- StallionEventManager.getInstance().sendEventWithoutCaching(
62
+ StallionEventManager.getInstance().sendEvent(
61
63
  StallionEventConstants.NativeStageEventTypes.DOWNLOAD_COMPLETE_STAGE.toString(),
62
64
  successPayload
63
65
  );
@@ -74,4 +76,27 @@ public class StallionStageManager {
74
76
  successPayload
75
77
  );
76
78
  }
79
+
80
+ private static void emitDownloadStartedStage(String releaseHash) {
81
+ JSONObject startedPayload = new JSONObject();
82
+ try {
83
+ startedPayload.put("releaseHash", releaseHash);
84
+ } catch (Exception ignored) { }
85
+ StallionEventManager.getInstance().sendEvent(
86
+ StallionEventConstants.NativeStageEventTypes.DOWNLOAD_STARTED_STAGE.toString(),
87
+ startedPayload
88
+ );
89
+ }
90
+
91
+ private static void emitDownloadErrorStage(String releaseHash, String error) {
92
+ JSONObject errorPayload = new JSONObject();
93
+ try {
94
+ errorPayload.put("releaseHash", releaseHash);
95
+ errorPayload.put("meta", error);
96
+ } catch (Exception ignored) { }
97
+ StallionEventManager.getInstance().sendEvent(
98
+ StallionEventConstants.NativeStageEventTypes.DOWNLOAD_ERROR_STAGE.toString(),
99
+ errorPayload
100
+ );
101
+ }
77
102
  }
@@ -24,18 +24,19 @@ public class StallionConfig {
24
24
  this.sharedPreferences = sharedPreferences;
25
25
  Resources res = context.getResources();
26
26
  String parentPackageName= context.getPackageName();
27
+
27
28
  int stallionProjectIdRes = res.getIdentifier(
28
29
  StallionConfigConstants.STALLION_PROJECT_ID_IDENTIFIER,
29
30
  "string",
30
31
  parentPackageName
31
32
  );
32
- this.projectId = context.getString(stallionProjectIdRes);
33
+ this.projectId = stallionProjectIdRes != 0 ?context.getString(stallionProjectIdRes) : "";
33
34
  int stallionAppTokenRes = res.getIdentifier(
34
35
  StallionConfigConstants.STALLION_APP_TOKEN_IDENTIFIER,
35
36
  "string",
36
37
  parentPackageName
37
38
  );
38
- this.appToken = context.getString(stallionAppTokenRes);
39
+ this.appToken = stallionAppTokenRes != 0 ? context.getString(stallionAppTokenRes) : "";
39
40
 
40
41
  // get or generate UID
41
42
  String cachedUniqueId = sharedPreferences.getString(
@@ -0,0 +1,100 @@
1
+ package com.stallion.utils;
2
+
3
+ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
4
+ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
5
+
6
+ import android.app.Activity;
7
+ import android.app.ActivityManager;
8
+ import android.content.Context;
9
+ import android.content.Intent;
10
+ import android.os.Bundle;
11
+ import android.os.Process;
12
+
13
+ import java.util.ArrayList;
14
+ import java.util.Arrays;
15
+ import java.util.List;
16
+
17
+ /**
18
+ * Process Phoenix facilitates restarting your application process. This should only be used for
19
+ * things like fundamental state changes in your debug builds (e.g., changing from staging to
20
+ * production).
21
+ * <p>
22
+ * Trigger process recreation by calling {@link #triggerRebirth} with a {@link Context} instance.
23
+ */
24
+ public final class ProcessPhoenix extends Activity {
25
+ private static final String KEY_RESTART_INTENTS = "phoenix_restart_intents";
26
+ private static final String KEY_MAIN_PROCESS_PID = "phoenix_main_process_pid";
27
+
28
+ /**
29
+ * Call to restart the application process using the {@linkplain Intent#CATEGORY_DEFAULT default}
30
+ * activity as an intent.
31
+ * <p>
32
+ * Behavior of the current process after invoking this method is undefined.
33
+ */
34
+ public static void triggerRebirth(Context context) {
35
+ triggerRebirth(context, getRestartIntent(context));
36
+ }
37
+
38
+ /**
39
+ * Call to restart the application process using the specified intents.
40
+ * <p>
41
+ * Behavior of the current process after invoking this method is undefined.
42
+ */
43
+ public static void triggerRebirth(Context context, Intent... nextIntents) {
44
+ if (nextIntents.length < 1) {
45
+ throw new IllegalArgumentException("intents cannot be empty");
46
+ }
47
+ // create a new task for the first activity.
48
+ nextIntents[0].addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
49
+
50
+ Intent intent = new Intent(context, ProcessPhoenix.class);
51
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK); // In case we are called with non-Activity context.
52
+ intent.putParcelableArrayListExtra(KEY_RESTART_INTENTS, new ArrayList<>(Arrays.asList(nextIntents)));
53
+ intent.putExtra(KEY_MAIN_PROCESS_PID, Process.myPid());
54
+ context.startActivity(intent);
55
+ }
56
+
57
+ private static Intent getRestartIntent(Context context) {
58
+ String packageName = context.getPackageName();
59
+ Intent defaultIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
60
+ if (defaultIntent != null) {
61
+ return defaultIntent;
62
+ }
63
+
64
+ throw new IllegalStateException("Unable to determine default activity for "
65
+ + packageName
66
+ + ". Does an activity specify the DEFAULT category in its intent filter?");
67
+ }
68
+
69
+ @Override protected void onCreate(Bundle savedInstanceState) {
70
+ super.onCreate(savedInstanceState);
71
+
72
+ Process.killProcess(getIntent().getIntExtra(KEY_MAIN_PROCESS_PID, -1)); // Kill original main process
73
+
74
+ ArrayList<Intent> intents = getIntent().getParcelableArrayListExtra(KEY_RESTART_INTENTS);
75
+ startActivities(intents.toArray(new Intent[intents.size()]));
76
+ finish();
77
+ Runtime.getRuntime().exit(0); // Kill kill kill!
78
+ }
79
+
80
+ /**
81
+ * Checks if the current process is a temporary Phoenix Process.
82
+ * This can be used to avoid initialisation of unused resources or to prevent running code that
83
+ * is not multi-process ready.
84
+ *
85
+ * @return true if the current process is a temporary Phoenix Process
86
+ */
87
+ public static boolean isPhoenixProcess(Context context) {
88
+ int currentPid = Process.myPid();
89
+ ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
90
+ List<ActivityManager.RunningAppProcessInfo> runningProcesses = manager.getRunningAppProcesses();
91
+ if (runningProcesses != null) {
92
+ for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
93
+ if (processInfo.pid == currentPid && processInfo.processName.endsWith(":phoenix")) {
94
+ return true;
95
+ }
96
+ }
97
+ }
98
+ return false;
99
+ }
100
+ }
@@ -1,6 +1,7 @@
1
1
  #import <React/RCTBridgeModule.h>
2
2
  #import <React/RCTViewManager.h>
3
3
  #import <React/RCTEventEmitter.h>
4
+ #import <React/RCTReloadCommand.h>
4
5
  #import <StallionObjConstants.h>
5
6
  #import <StallionStateManager.h>
6
7
  #import <StallionEventHandler.h>
@@ -32,6 +32,8 @@ RCT_EXTERN_METHOD(acknowledgeEvents: (NSString *)eventIdsJson
32
32
  resolver:(RCTPromiseResolveBlock)resolver
33
33
  rejecter:(RCTPromiseRejectBlock)rejecter)
34
34
 
35
+ RCT_EXTERN_METHOD(restart)
36
+
35
37
  + (BOOL)requiresMainQueueSetup
36
38
  {
37
39
  return NO;
@@ -145,6 +145,12 @@ class Stallion: RCTEventEmitter {
145
145
  }
146
146
  } catch {};
147
147
  }
148
- }
148
+ }
149
+
150
+ @objc func restart() {
151
+ DispatchQueue.main.async {
152
+ RCTTriggerReloadCommandListeners("Stallion: Restart")
153
+ }
154
+ }
149
155
  }
150
156
 
@@ -80,8 +80,11 @@ class StallionConstants {
80
80
  static let EXCEPTION_PROD = "EXCEPTION_PROD"
81
81
  }
82
82
  public struct NativeEventTypesStage {
83
+ static let DOWNLOAD_STARTED_STAGE = "DOWNLOAD_STARTED_STAGE"
83
84
  static let DOWNLOAD_ERROR_STAGE = "DOWNLOAD_ERROR_STAGE"
84
85
  static let DOWNLOAD_PROGRESS_STAGE = "DOWNLOAD_PROGRESS_STAGE"
85
86
  static let DOWNLOAD_COMPLETE_STAGE = "DOWNLOAD_COMPLETE_STAGE"
87
+ static let INSTALLED_STAGE = "INSTALLED_STAGE"
88
+ static let EXCEPTION_STAGE = "EXCEPTION_STAGE"
86
89
  }
87
90
  }
@@ -114,6 +114,7 @@
114
114
  stallionMeta.stageNewHash = stageTempHash;
115
115
  stallionMeta.stageTempHash = @"";
116
116
  [stateManager syncStallionMeta];
117
+ [self sendInstallEventStage:stageTempHash];
117
118
  } @catch (NSException *exception) {
118
119
  NSLog(@"Error mounting new stage bundle: %@", exception.reason);
119
120
  }
@@ -127,7 +128,7 @@
127
128
  } else {
128
129
  [self sendCorruptionEvent:releaseHash folderPath:folderPath];
129
130
  if(isProd) {
130
- [StallionSlotManager rollbackProdWithAutoRollback:true errorString:@"Corruped File not found"];
131
+ [StallionSlotManager rollbackProdWithAutoRollback:false errorString:@"Corruped File not found"];
131
132
  } else {
132
133
  [StallionSlotManager rollbackStage];
133
134
  }
@@ -140,6 +141,11 @@
140
141
  [[StallionEventHandler sharedInstance] cacheEvent:[StallionObjConstants installed_prod_event] eventPayload:eventPayload];
141
142
  }
142
143
 
144
+ + (void)sendInstallEventStage:(NSString *)releaseHash {
145
+ NSDictionary *eventPayload = @{[StallionObjConstants release_hash_key]: releaseHash};
146
+ [[StallionEventHandler sharedInstance] cacheEvent:[StallionObjConstants installed_stage_event] eventPayload:eventPayload];
147
+ }
148
+
143
149
  + (void)sendCorruptionEvent:(NSString *)releaseHash folderPath:(NSString *)folderPath {
144
150
  NSDictionary *eventPayload = @{
145
151
  [StallionObjConstants release_hash_key]: releaseHash,
@@ -33,6 +33,8 @@
33
33
  @property (class, nonatomic, readonly) NSString *exception_stage_event;
34
34
  @property (class, nonatomic, readonly) NSString *stabilized_prod_event;
35
35
 
36
+ @property (class, nonatomic, readonly) NSString *installed_stage_event;
37
+
36
38
  @property (class, nonatomic, readonly) NSString *release_hash_key;
37
39
 
38
40
  @property (class, nonatomic, readonly) NSString *app_version_cache_key;
@@ -85,6 +85,10 @@
85
85
  return @"INSTALLED_PROD";
86
86
  }
87
87
 
88
+ + (NSString *)installed_stage_event {
89
+ return @"INSTALLED_STAGE";
90
+ }
91
+
88
92
  + (NSString *)exception_prod_event {
89
93
  return @"EXCEPTION_PROD";
90
94
  }
@@ -71,8 +71,8 @@
71
71
  StallionStateManager *stateManager = [StallionStateManager sharedInstance];
72
72
  NSString *baseFolderPath = stateManager.stallionConfig.filesDirectory;
73
73
 
74
- NSString *newSlotPath = [NSString stringWithFormat:@"%@%@%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.new_folder_slot];
75
- NSString *stableSlotPath = [NSString stringWithFormat:@"%@%@%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.stable_folder_slot];
74
+ NSString *newSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.new_folder_slot];
75
+ NSString *stableSlotPath = [NSString stringWithFormat:@"%@/%@/%@", baseFolderPath, StallionObjConstants.prod_directory, StallionObjConstants.stable_folder_slot];
76
76
 
77
77
  [StallionFileManager copyFileOrDirectoryFrom:newSlotPath to:stableSlotPath];
78
78
 
@@ -42,6 +42,8 @@ class StallionStageManager: NSObject {
42
42
  }
43
43
  }
44
44
 
45
+ emitDownloadStartedStage(releaseHash: receivedHash)
46
+
45
47
  // Start bundle download
46
48
  StallionFileDownloader().downloadBundle(
47
49
  url: URL(string: receivedDownloadUrl)!,
@@ -58,17 +60,29 @@ class StallionStageManager: NSObject {
58
60
  },
59
61
  reject: { code, prefix, error in
60
62
  let errorMessage = "\(prefix ?? "") \(error?.localizedDescription ?? "Unknown error")"
63
+ emitDownloadErrorStage(releaseHash: receivedHash, error: errorMessage)
61
64
  rejectClosure(code, errorMessage, error)
62
65
  }
63
66
  )
64
67
  }
65
68
 
66
69
  // MARK: - Event Emitters
70
+
71
+ private static func emitDownloadErrorStage(releaseHash: String, error: String) {
72
+ let errorPayload: NSDictionary = [
73
+ "releaseHash": releaseHash,
74
+ "meta": error
75
+ ]
76
+ Stallion.sendEventToRn(eventName: StallionConstants.NativeEventTypesStage.DOWNOAD_ERROR_STAGE,
77
+ eventBody: errorPayload,
78
+ shouldCache: true
79
+ )
80
+ }
67
81
 
68
82
  private static func emitDownloadSuccessStage(releaseHash: String) {
69
83
  let successPayload: NSDictionary = ["releaseHash": releaseHash]
70
84
  Stallion.sendEventToRn(eventName: StallionConstants.NativeEventTypesStage.DOWNLOAD_COMPLETE_STAGE,eventBody: successPayload,
71
- shouldCache: false
85
+ shouldCache: true
72
86
  )
73
87
  }
74
88
 
@@ -81,4 +95,11 @@ class StallionStageManager: NSObject {
81
95
  shouldCache: false
82
96
  )
83
97
  }
98
+ private static func emitDownloadStartedStage(releaseHash: String) {
99
+ let startedPayload: NSDictionary = ["releaseHash": releaseHash]
100
+ Stallion.sendEventToRn(eventName: StallionConstants.NativeEventTypesStage.DOWNLOAD_STARTED_STAGE,
101
+ eventBody: startedPayload,
102
+ shouldCache: true
103
+ )
104
+ }
84
105
  }
@@ -14,16 +14,25 @@ class StallionSyncHandler {
14
14
  private static let syncQueue = DispatchQueue(label: "com.stallion.syncQueue")
15
15
 
16
16
  static func sync() {
17
- syncQueue.async {
18
- guard !isSyncInProgress else { return }
19
- isSyncInProgress = true
20
- }
17
+ var shouldProceed = false
18
+
19
+ syncQueue.sync {
20
+ if !isSyncInProgress {
21
+ isSyncInProgress = true
22
+ shouldProceed = true
23
+ }
24
+ }
25
+
26
+ guard shouldProceed else { return }
21
27
 
22
28
  DispatchQueue.global().async {
23
29
  do {
24
30
  // Fetch StallionStateManager and StallionConfig
25
31
  let stateManager = StallionStateManager.sharedInstance()
26
- guard let config = stateManager?.stallionConfig else { return }
32
+ guard let config = stateManager?.stallionConfig else {
33
+ completeSync()
34
+ return
35
+ }
27
36
 
28
37
  // Use appVersion directly from StallionConfig
29
38
  let appVersion = config.appVersion ?? ""
@@ -43,7 +52,7 @@ class StallionSyncHandler {
43
52
  makeApiCall(payload: requestPayload, appVersion: appVersion)
44
53
 
45
54
  } catch {
46
- defer { isSyncInProgress = false }
55
+ completeSync()
47
56
  emitSyncError(error)
48
57
  }
49
58
  }
@@ -62,27 +71,27 @@ class StallionSyncHandler {
62
71
  // Add tokens
63
72
  request.setValue(StallionStateManager.sharedInstance()?.stallionConfig?.appToken, forHTTPHeaderField: StallionConstants.STALLION_APP_TOKEN_KEY)
64
73
  request.setValue(StallionStateManager.sharedInstance()?.stallionConfig?.sdkToken, forHTTPHeaderField: StallionConstants.STALLION_SDK_TOKEN_KEY)
65
- request.setValue(StallionStateManager.sharedInstance()?.stallionConfig?.uid, forHTTPHeaderField: StallionConstants.STALLION_UID_KEY)
74
+ request.setValue(StallionStateManager.sharedInstance()?.stallionConfig?.uid, forHTTPHeaderField: StallionConstants.STALLION_UID_KEY)
66
75
 
67
76
  // Convert payload to JSON
68
77
  do {
69
78
  let jsonData = try JSONSerialization.data(withJSONObject: payload, options: [])
70
79
  request.httpBody = jsonData
71
80
  } catch {
72
- defer { isSyncInProgress = false }
81
+ completeSync()
73
82
  emitSyncError(error)
74
83
  return
75
84
  }
76
85
 
77
86
  let task = URLSession.shared.dataTask(with: request) { data, response, error in
78
87
  if let error = error {
79
- defer { isSyncInProgress = false }
88
+ completeSync()
80
89
  emitSyncError(error)
81
90
  return
82
91
  }
83
92
 
84
93
  guard let data = data, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
85
- defer { isSyncInProgress = false }
94
+ completeSync()
86
95
  let responseError = NSError(domain: "Invalid response from server", code: -2)
87
96
  emitSyncError(responseError)
88
97
  return
@@ -91,21 +100,27 @@ class StallionSyncHandler {
91
100
  // Parse the JSON response
92
101
  do {
93
102
  if let releaseMeta = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
94
- defer { isSyncInProgress = false }
103
+ completeSync()
95
104
  processReleaseMeta(releaseMeta, appVersion: appVersion)
96
105
  } else {
97
- defer { isSyncInProgress = false }
106
+ completeSync()
98
107
  let parsingError = NSError(domain: "Invalid JSON format", code: -3)
99
108
  emitSyncError(parsingError)
100
109
  }
101
110
  } catch {
102
- defer { isSyncInProgress = false }
111
+ completeSync()
103
112
  emitSyncError(error)
104
113
  }
105
114
  }
106
115
 
107
116
  task.resume()
108
117
  }
118
+
119
+ private static func completeSync() {
120
+ syncQueue.sync {
121
+ isSyncInProgress = false
122
+ }
123
+ }
109
124
 
110
125
  private static func processReleaseMeta(_ releaseMeta: [String: Any], appVersion: String) {
111
126
  guard let success = releaseMeta["success"] as? Bool, success else { return }
@@ -152,10 +167,14 @@ class StallionSyncHandler {
152
167
  guard let stateManager = StallionStateManager.sharedInstance(),
153
168
  let config = stateManager.stallionConfig else { return }
154
169
 
155
- syncQueue.async {
156
- guard !isDownloadInProgress else { return }
157
- isDownloadInProgress = true
158
- }
170
+ var shouldDownload = false
171
+ syncQueue.sync {
172
+ if !isDownloadInProgress {
173
+ isDownloadInProgress = true
174
+ shouldDownload = true
175
+ }
176
+ }
177
+ guard shouldDownload else { return }
159
178
 
160
179
  let downloadPath = config.filesDirectory + "/" + StallionConstants.PROD_DIRECTORY + "/" + StallionConstants.TEMP_FOLDER_SLOT
161
180
  let projectId = config.projectId ?? ""
@@ -167,7 +186,7 @@ class StallionSyncHandler {
167
186
  StallionFileDownloader().downloadBundle(url: fromUrl, downloadDirectory: downloadPath, onProgress: { progress in
168
187
  // Handle progress updates if necessary
169
188
  }, resolve: { _ in
170
- defer { isDownloadInProgress = false }
189
+ completeDownload()
171
190
  stateManager.stallionMeta?.currentProdSlot = SlotStates.newSlot
172
191
  stateManager.stallionMeta?.prodTempHash = newReleaseHash
173
192
  if let currentProdNewHash = stateManager.stallionMeta?.prodNewHash,
@@ -177,13 +196,19 @@ class StallionSyncHandler {
177
196
  stateManager.syncStallionMeta()
178
197
  emitDownloadSuccess(releaseHash: newReleaseHash)
179
198
  }, reject: { code, prefix, error in
180
- defer { isDownloadInProgress = false }
199
+ completeDownload()
181
200
  emitDownloadError(
182
201
  releaseHash: newReleaseHash,
183
202
  error: "\(String(describing: prefix))\(String(describing: error))"
184
203
  )
185
204
  })
186
205
  }
206
+
207
+ private static func completeDownload() {
208
+ syncQueue.sync {
209
+ isDownloadInProgress = false
210
+ }
211
+ }
187
212
 
188
213
  // MARK: - Event Emission
189
214
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-stallion",
3
- "version": "2.0.1",
3
+ "version": "2.1.0-alpha.1",
4
4
  "description": "Offical React Native SDK for Stallion",
5
5
  "main": "index",
6
6
  "types": "types/index.d.ts",
package/src/index.js CHANGED
@@ -18,7 +18,7 @@ if (StallionNativeModule !== null && StallionNativeModule !== void 0 && Stallion
18
18
  withStallion = withStallionNoop;
19
19
  useStallionModal = useStallionModalNoop;
20
20
  }
21
- export { sync } from './main/utils/StallionNativeUtils';
21
+ export { sync, restart } from './main/utils/StallionNativeUtils';
22
22
  export { useStallionUpdate } from './main/utils/useStallionUpdate';
23
23
  export const addEventListener = stallionEventEmitter.addEventListener.bind(stallionEventEmitter);
24
24
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"names":["StallionNativeModule","STALLION_DISABLED_ERROR","withStallionNoop","useStallionModalNoop","withStallionMain","useStallionModalMain","stallionEventEmitter","withStallion","useStallionModal","getStallionConfig","console","warn","sync","useStallionUpdate","addEventListener","bind"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,OAAOA,oBAAoB,IACzBC,uBAAuB,QAClB,wBAAwB;;AAE/B;AACA,OAAOC,gBAAgB,MAAM,qBAAqB;AAClD,OAAOC,oBAAoB,MAAM,yBAAyB;;AAE1D;AACA,OAAOC,gBAAgB,MAAM,2BAA2B;AACxD,OAAOC,oBAAoB,MAAM,+BAA+B;AAGhE,SAASC,oBAAoB,QAAQ,mCAAmC;AAExE,OAAO,IAAIC,YAA2B;AACtC,OAAO,IAAIC,gBAAyC;AAEpD,IAAIR,oBAAoB,aAApBA,oBAAoB,eAApBA,oBAAoB,CAAES,iBAAiB,EAAE;EAC3CF,YAAY,GAAGH,gBAAgB;EAC/BI,gBAAgB,GAAGH,oBAAoB;AACzC,CAAC,MAAM;EACLK,OAAO,CAACC,IAAI,CAACV,uBAAuB,CAAC;EACrCM,YAAY,GAAGL,gBAAgB;EAC/BM,gBAAgB,GAAGL,oBAAoB;AACzC;AAEA,SAASS,IAAI,QAAQ,kCAAkC;AACvD,SAASC,iBAAiB,QAAQ,gCAAgC;AAClE,OAAO,MAAMC,gBAAgB,GAC3BR,oBAAoB,CAACQ,gBAAgB,CAACC,IAAI,CAACT,oBAAoB,CAAC"}
1
+ {"version":3,"names":["StallionNativeModule","STALLION_DISABLED_ERROR","withStallionNoop","useStallionModalNoop","withStallionMain","useStallionModalMain","stallionEventEmitter","withStallion","useStallionModal","getStallionConfig","console","warn","sync","restart","useStallionUpdate","addEventListener","bind"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,OAAOA,oBAAoB,IACzBC,uBAAuB,QAClB,wBAAwB;;AAE/B;AACA,OAAOC,gBAAgB,MAAM,qBAAqB;AAClD,OAAOC,oBAAoB,MAAM,yBAAyB;;AAE1D;AACA,OAAOC,gBAAgB,MAAM,2BAA2B;AACxD,OAAOC,oBAAoB,MAAM,+BAA+B;AAGhE,SAASC,oBAAoB,QAAQ,mCAAmC;AAExE,OAAO,IAAIC,YAA2B;AACtC,OAAO,IAAIC,gBAAyC;AAEpD,IAAIR,oBAAoB,aAApBA,oBAAoB,eAApBA,oBAAoB,CAAES,iBAAiB,EAAE;EAC3CF,YAAY,GAAGH,gBAAgB;EAC/BI,gBAAgB,GAAGH,oBAAoB;AACzC,CAAC,MAAM;EACLK,OAAO,CAACC,IAAI,CAACV,uBAAuB,CAAC;EACrCM,YAAY,GAAGL,gBAAgB;EAC/BM,gBAAgB,GAAGL,oBAAoB;AACzC;AAEA,SAASS,IAAI,EAAEC,OAAO,QAAQ,kCAAkC;AAChE,SAASC,iBAAiB,QAAQ,gCAAgC;AAClE,OAAO,MAAMC,gBAAgB,GAC3BT,oBAAoB,CAACS,gBAAgB,CAACC,IAAI,CAACV,oBAAoB,CAAC"}