react-native-update 10.59.0 → 10.59.2

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 (68) hide show
  1. package/android/build.gradle +46 -14
  2. package/android/jni/Android.mk +2 -1
  3. package/android/lib/arm64-v8a/librnpushy.so +0 -0
  4. package/android/lib/armeabi-v7a/librnpushy.so +0 -0
  5. package/android/lib/x86/librnpushy.so +0 -0
  6. package/android/lib/x86_64/librnpushy.so +0 -0
  7. package/android/src/main/java/cn/reactnative/modules/update/ApkInstaller.java +20 -16
  8. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +4 -4
  9. package/android/src/main/java/cn/reactnative/modules/update/{CrashRescue.java → CrashHold.java} +12 -12
  10. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +28 -24
  11. package/android/src/main/java/cn/reactnative/modules/update/ErrorCodes.java +2 -1
  12. package/android/src/main/java/cn/reactnative/modules/update/{NativeUpdateFlow.java → FlowBridge.java} +6 -6
  13. package/android/src/main/java/cn/reactnative/modules/update/HttpUtils.java +6 -3
  14. package/android/src/main/java/cn/reactnative/modules/update/{NativeUpdateCore.java → NativeCore.java} +4 -4
  15. package/android/src/main/java/cn/reactnative/modules/update/PushyConfiguration.java +10 -5
  16. package/android/src/main/java/cn/reactnative/modules/update/PushyRuntime.java +4 -4
  17. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +7 -7
  18. package/android/src/main/java/cn/reactnative/modules/update/StateSerialRunner.java +1 -1
  19. package/android/src/main/java/cn/reactnative/modules/update/{NativeCheckOrchestrator.java → SyncCoordinator.java} +79 -75
  20. package/android/src/main/java/cn/reactnative/modules/update/Texts.java +28 -0
  21. package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +1 -1
  22. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +28 -28
  23. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +12 -9
  24. package/cpp/patch_core/archive_limits.h +5 -0
  25. package/cpp/patch_core/archive_patch_core.cpp +26 -19
  26. package/cpp/patch_core/archive_patch_core.h +17 -8
  27. package/cpp/patch_core/digest.h +6 -1
  28. package/cpp/patch_core/error_codes.h +8 -1
  29. package/cpp/patch_core/hbc_transform.h +5 -0
  30. package/cpp/patch_core/hbc_transform_wire.h +5 -0
  31. package/cpp/patch_core/install_record.h +5 -0
  32. package/cpp/patch_core/jni_natives.h +27 -0
  33. package/cpp/patch_core/jni_registration.cpp +103 -0
  34. package/cpp/patch_core/obscured_text.h +44 -0
  35. package/cpp/patch_core/patch_core.cpp +13 -13
  36. package/cpp/patch_core/patch_core.h +11 -6
  37. package/cpp/patch_core/patch_core_android.cpp +10 -10
  38. package/cpp/patch_core/state_core.h +5 -0
  39. package/cpp/patch_core/state_ops.h +5 -0
  40. package/cpp/patch_core/update_core_android.cpp +23 -22
  41. package/cpp/update_flow_core/flow_json.h +6 -1
  42. package/cpp/update_flow_core/update_flow_core.cpp +35 -18
  43. package/cpp/update_flow_core/update_flow_core.h +13 -8
  44. package/cpp/update_flow_core/update_flow_jni.cpp +11 -13
  45. package/harmony/pushy/src/main/cpp/CMakeLists.txt +10 -8
  46. package/harmony/pushy/src/main/cpp/pushy.cpp +33 -33
  47. package/harmony/pushy/src/main/ets/ArchiveLimits.ts +15 -15
  48. package/harmony/pushy/src/main/ets/DownloadTask.ts +60 -60
  49. package/harmony/pushy/src/main/ets/ErrorCodes.ts +13 -11
  50. package/harmony/pushy/src/main/ets/InstallRecord.ts +4 -4
  51. package/harmony/pushy/src/main/ets/NativePatchCore.ts +9 -9
  52. package/harmony/pushy/src/main/ets/PathUtils.ts +2 -2
  53. package/harmony/pushy/src/main/ets/PushyConfiguration.ts +8 -6
  54. package/harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets +1 -1
  55. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +42 -41
  56. package/harmony/pushy/src/main/ets/{NativeCheckOrchestrator.ts → SyncCoordinator.ts} +33 -32
  57. package/harmony/pushy/src/main/ets/Texts.ts +28 -0
  58. package/harmony/pushy/src/main/ets/UpdateContext.ts +31 -30
  59. package/harmony/pushy.har +0 -0
  60. package/ios/RCTPushy/RCTPushy.mm +154 -140
  61. package/ios/RCTPushy/RCTPushyConfiguration.h +8 -0
  62. package/ios/RCTPushy/RCTPushyConfiguration.mm +32 -5
  63. package/package.json +1 -1
  64. package/react-native-update.podspec +16 -4
  65. package/android/lib/arm64-v8a/librnupdate.so +0 -0
  66. package/android/lib/armeabi-v7a/librnupdate.so +0 -0
  67. package/android/lib/x86/librnupdate.so +0 -0
  68. package/android/lib/x86_64/librnupdate.so +0 -0
@@ -31,6 +31,12 @@
31
31
 
32
32
  #import <React/RCTConvert.h>
33
33
  #import <React/RCTLog.h>
34
+ // RN's log macros pass __FILE__, which would embed this file's absolute build
35
+ // path in the binary; log with the bare file name instead.
36
+ #if RCTLOG_ENABLED
37
+ #undef _RCTLog
38
+ #define _RCTLog(lvl, ...) _RCTLogNativeInternal(lvl, __FILE_NAME__, __LINE__, __VA_ARGS__)
39
+ #endif
34
40
  #import <objc/runtime.h>
35
41
  #import <os/lock.h>
36
42
 
@@ -64,7 +70,7 @@ static NSString *const keyUuid = @"REACTNATIVECN_PUSHY_UUID";
64
70
  static NSString *const keyHashInfo = @"REACTNATIVECN_PUSHY_HASH_";
65
71
  static NSString *const keyFirstLoadMarked = @"REACTNATIVECN_PUSHY_FIRSTLOADMARKED_KEY";
66
72
  static NSString *const keyRolledBackMarked = @"REACTNATIVECN_PUSHY_ROLLEDBACKMARKED_KEY";
67
- static NSString *const KeyPackageUpdatedMarked = @"REACTNATIVECN_PUSHY_ISPACKAGEUPDATEDMARKED_KEY";
73
+ static NSString *const KeyPackageUpdatedMarked = RCTPushyRevealText("0832d5f29aa549710b0939daf88ca058790f3dded7e888b451640d2ec3f69099bb43711523cafa8ea7bb4372132a");
68
74
  // bundleHash cache: "<cacheKey>|<sha256hex>" where cacheKey identifies the
69
75
  // installed binary (packageVersion + embedded bundle size + mtime). Recomputed
70
76
  // only when the key changes, i.e. once per install.
@@ -84,7 +90,15 @@ static NSString *const PushyErrorDomain = @"cn.reactnative.pushy";
84
90
  // file def
85
91
  static NSString * const BUNDLE_FILE_NAME = @"index.bundlejs";
86
92
  static NSString * const SOURCE_PATCH_NAME = @"__diff.json";
87
- static NSString * const BUNDLE_PATCH_NAME = @"index.bundlejs.patch";
93
+ static NSString * const BUNDLE_PATCH_NAME = RCTPushyRevealText("3319f0d4b6c56a502c3b10fcdca0de7d4b3307e9");
94
+ // Protocol strings and version-info flags read by JS, stored encoded
95
+ // (RCTPushyRevealText) so they do not appear as plain binary strings.
96
+ static NSString * const PushyOptionUrlKey = RCTPushyRevealText("2f07f0d0ba8e5d572e");
97
+ static NSString * const PushyIpaDeltaSuffix = RCTPushyRevealText("741ee4d0e09b69512137");
98
+ static NSString * const PushyPpkDeltaSuffix = RCTPushyRevealText("7407e4dae09b69512137");
99
+ static NSString * const PushyInfoCrashHold = RCTPushyRevealText("3905f5c2a6b96d56212a19");
100
+ static NSString * const PushyInfoForceBoot = RCTPushyRevealText("3c18e6d2aba9674a360d19ead5a695");
101
+ static NSString * const PushyStatusNone = RCTPushyRevealText("3418c1c1aa8a7c40");
88
102
  #define VERSION_COMPLETE_FILE_NAME_LITERAL ".pushy-complete"
89
103
  static NSString * const VERSION_COMPLETE_FILE_NAME = @VERSION_COMPLETE_FILE_NAME_LITERAL;
90
104
 
@@ -211,7 +225,7 @@ static NSError *PushyEnsureFreeSpace(NSString *path, long long bytesToWrite) {
211
225
  if (shortfall == nil) {
212
226
  return nil;
213
227
  }
214
- return PushyErrorWithCode(pushy::error_codes::kPatchFailed, shortfall);
228
+ return PushyErrorWithCode(pushy::error_codes::kDeltaFailed, shortfall);
215
229
  }
216
230
 
217
231
  // SSZipArchive delegate enforcing cpp/patch_core/archive_limits.h while the
@@ -477,12 +491,12 @@ static std::string PushyToStdString(NSString *value) {
477
491
  return std::string([value UTF8String]);
478
492
  }
479
493
 
480
- static NSError *PushyNSErrorFromStatus(const pushy::patch::Status &status) {
494
+ static NSError *PushyNSErrorFromStatus(const pushy::delta::Status &status) {
481
495
  return [NSError errorWithDomain:PushyErrorDomain
482
496
  code:-1
483
497
  userInfo:@{
484
498
  NSLocalizedDescriptionKey: [NSString stringWithUTF8String:status.message.c_str()],
485
- PushyErrorCodeKey: PushyCode(pushy::error_codes::kPatchFailed),
499
+ PushyErrorCodeKey: PushyCode(pushy::error_codes::kDeltaFailed),
486
500
  }];
487
501
  }
488
502
 
@@ -568,12 +582,12 @@ static BOOL PushyJsonIsAbsent(id value) {
568
582
  // raise takes the whole app down (and trips the crash rescue) instead of
569
583
  // failing the patch. NO with `reason` set for a malformed manifest.
570
584
  static BOOL PushyPatchManifestFromJson(NSDictionary *json,
571
- pushy::patch::PatchManifest *manifest,
585
+ pushy::delta::PatchManifest *manifest,
572
586
  NSString **reason) {
573
587
  id copies = json[@"copies"];
574
588
  if (!PushyJsonIsAbsent(copies)) {
575
589
  if (![copies isKindOfClass:[NSDictionary class]]) {
576
- *reason = @"patch manifest: copies is not an object";
590
+ *reason = @"delta manifest: copies is not an object";
577
591
  return NO;
578
592
  }
579
593
  // Content checksum per copy target ("copiesCrc", pdiff manifests
@@ -588,13 +602,13 @@ static BOOL PushyPatchManifestFromJson(NSDictionary *json,
588
602
  for (id to in (NSDictionary *)copies) {
589
603
  id from = ((NSDictionary *)copies)[to];
590
604
  if (![to isKindOfClass:[NSString class]] || ![from isKindOfClass:[NSString class]]) {
591
- *reason = @"patch manifest: copies entry is not a string";
605
+ *reason = @"delta manifest: copies entry is not a string";
592
606
  return NO;
593
607
  }
594
608
  if ([from length] == 0) {
595
609
  from = to;
596
610
  }
597
- pushy::patch::CopyOperation operation;
611
+ pushy::delta::CopyOperation operation;
598
612
  operation.from = PushyToStdString(from);
599
613
  operation.to = PushyToStdString(to);
600
614
  NSNumber *expectedCrc = copiesCrc[to];
@@ -611,12 +625,12 @@ static BOOL PushyPatchManifestFromJson(NSDictionary *json,
611
625
  id deletes = json[@"deletes"];
612
626
  if (!PushyJsonIsAbsent(deletes)) {
613
627
  if (![deletes isKindOfClass:[NSDictionary class]] && ![deletes isKindOfClass:[NSArray class]]) {
614
- *reason = @"patch manifest: deletes is not an object or array";
628
+ *reason = @"delta manifest: deletes is not an object or array";
615
629
  return NO;
616
630
  }
617
631
  for (id path in deletes) {
618
632
  if (![path isKindOfClass:[NSString class]]) {
619
- *reason = @"patch manifest: deletes entry is not a string";
633
+ *reason = @"delta manifest: deletes entry is not a string";
620
634
  return NO;
621
635
  }
622
636
  manifest->deletes.push_back(PushyToStdString(path));
@@ -697,14 +711,14 @@ static void PushySwitchVersionLocked(NSString *hash) {
697
711
  }
698
712
 
699
713
  @interface RCTPushy ()
700
- - (void)downloadUpdate:(PushyType)type
714
+ - (void)fetchPackage:(PushyType)type
701
715
  options:(NSDictionary *)options
702
716
  resolver:(RCTPromiseResolveBlock)resolve
703
717
  rejecter:(RCTPromiseRejectBlock)reject;
704
- - (void)performUpdate:(PushyType)type
718
+ - (void)performFetch:(PushyType)type
705
719
  options:(NSDictionary *)options
706
720
  callback:(void (^)(NSError *error))callback;
707
- - (NSError *)reloadBridgeWithReason:(NSString *)reason;
721
+ - (NSError *)restartBridgeWithReason:(NSString *)reason;
708
722
  - (void)unzipDownloadedPackage:(NSString *)zipFilePath
709
723
  hash:(NSString *)hash
710
724
  type:(PushyType)type
@@ -714,7 +728,7 @@ static void PushySwitchVersionLocked(NSString *hash) {
714
728
  type:(PushyType)type
715
729
  originHash:(NSString *)originHash
716
730
  callback:(void (^)(NSError *error))callback;
717
- - (void)applyPatchForHash:(NSString *)hash
731
+ - (void)applyDeltaForHash:(NSString *)hash
718
732
  type:(PushyType)type
719
733
  fromBundle:(NSString *)bundleOrigin
720
734
  source:(NSString *)sourceOrigin
@@ -744,10 +758,10 @@ static void PushySwitchVersionLocked(NSString *hash) {
744
758
  + (BOOL)restorePurgedLaunch:(NSString *)purgedVersion
745
759
  rolledBack:(NSString *)launchRolledBackVersion;
746
760
  #endif
747
- + (void)markJsCheckCompleted:(NSString *)config;
761
+ + (void)recordJsRound:(NSString *)config;
748
762
  + (void)startRoundWithDeadline:(NSTimeInterval)deadlineUptime;
749
763
  + (void)runOnce:(NSString *)launchRolledBackVersion deadline:(NSTimeInterval)deadlineUptime;
750
- + (void)runRescueWithDeadline:(NSTimeInterval)deadlineUptime;
764
+ + (void)runHoldRoundWithDeadline:(NSTimeInterval)deadlineUptime;
751
765
  + (BOOL)commitRoundWithGeneration:(uint64_t)generation
752
766
  hashInfo:(NSDictionary *)hashInfoEntry
753
767
  activate:(NSString *)hashToActivate
@@ -766,8 +780,8 @@ static std::atomic<bool> pushyRoundCompleted{false};
766
780
  // Flipped the moment a crash is being held. JS is dead from that point on,
767
781
  // so there is no second decision maker: the round force-activates whatever
768
782
  // it downloads (§11.3).
769
- static std::atomic<bool> pushyCrashRescueActive{false};
770
- static std::atomic<bool> pushyRescueAttempted{false};
783
+ static std::atomic<bool> pushyCrashHoldActive{false};
784
+ static std::atomic<bool> pushyHoldAttempted{false};
771
785
  // Set when this process's round is the tvOS purged-version restore.
772
786
  static std::atomic<bool> pushyPurgeRestoreActive{false};
773
787
  // True while +bundleURL waits for that restore. Only then may the round
@@ -778,7 +792,7 @@ static std::atomic<bool> pushyPurgeRestoreActive{false};
778
792
  // (and is left to JS) — never selected behind the packaged bundle's back.
779
793
  static bool pushyPurgeRestoreWindowOpen = false;
780
794
  static dispatch_semaphore_t pushyRoundDone;
781
- static NSString *pushyLaunchRolledBackForRescue = nil;
795
+ static NSString *pushyLaunchRolledBackForHold = nil;
782
796
  // A version this process downloaded but left for JS to activate. If the
783
797
  // process then crashes, JS will never activate it — the crash handler
784
798
  // activates it directly (bounded local work, no network). The generation is
@@ -796,27 +810,27 @@ static NSTimeInterval pushyProcessAnchorUptime = 0;
796
810
  static NSString *pushyJsCompletedConfig = nil;
797
811
  // The group supplements (rather than consumes) the crash-rescue semaphore.
798
812
  static dispatch_group_t pushyHostRoundGroup;
799
- static std::atomic<bool> pushyNativeCheckReady{false};
813
+ static std::atomic<bool> pushySyncReady{false};
800
814
  static NSDictionary *pushyHostRoundResult = nil;
801
815
  static NSString *pushyHostRoundConfig = nil;
802
816
  static uint64_t pushyHostRoundGeneration = 0;
803
817
  static std::atomic<uint64_t> pushyNativeConfigGeneration{0};
804
818
  static uint64_t pushyHostRoundConfigGeneration = 0;
805
819
 
806
- static const NSTimeInterval kPushyRescueTriggerUptime = 60;
807
- static const NSTimeInterval kPushyRescueBudgetBackgroundThread = 10;
820
+ static const NSTimeInterval kPushyHoldTriggerUptime = 60;
821
+ static const NSTimeInterval kPushyHoldBudgetBackgroundThread = 10;
808
822
  // A held main thread freezes UI teardown; stay well under the watchdog.
809
- static const NSTimeInterval kPushyRescueBudgetMainThread = 3.5;
823
+ static const NSTimeInterval kPushyHoldBudgetMainThread = 3.5;
810
824
  // The purged-version restore blocks +bundleURL, usually inside
811
825
  // application:didFinishLaunching: — stay clear of the launch watchdog.
812
826
  static const NSTimeInterval kPushyPurgeRestoreBudget = 12;
813
827
 
814
- static void PushyMaybeHoldForRescue(void) {
828
+ static void PushyMaybeHoldProcess(void) {
815
829
  // Once per process; a second crashing thread passes straight through
816
830
  // instead of waiting behind the first (§11.3: prefer under-rescuing over
817
831
  // wedging the teardown).
818
832
  bool expected = false;
819
- if (!pushyRescueAttempted.compare_exchange_strong(expected, true)) {
833
+ if (!pushyHoldAttempted.compare_exchange_strong(expected, true)) {
820
834
  return;
821
835
  }
822
836
  NSTimeInterval uptime = PushyMonotonicNow() - pushyProcessAnchorUptime;
@@ -824,14 +838,14 @@ static void PushyMaybeHoldForRescue(void) {
824
838
  // Early crashes are the brick signature; a crash with an in-flight round
825
839
  // is worth finishing regardless of uptime. Everything else is an ordinary
826
840
  // crash whose UX must not be delayed.
827
- if (uptime >= kPushyRescueTriggerUptime && !roundInFlight) {
841
+ if (uptime >= kPushyHoldTriggerUptime && !roundInFlight) {
828
842
  return;
829
843
  }
830
844
  NSTimeInterval budget = [NSThread isMainThread]
831
- ? kPushyRescueBudgetMainThread
832
- : kPushyRescueBudgetBackgroundThread;
845
+ ? kPushyHoldBudgetMainThread
846
+ : kPushyHoldBudgetBackgroundThread;
833
847
  NSTimeInterval deadline = PushyMonotonicNow() + budget;
834
- NSLog(@"RCTPushy -- crash rescue: holding process for up to %.1fs "
848
+ NSLog(@"RCTPushy -- crash hold: holding process for up to %.1fs "
835
849
  @"(uptime %.1fs)", budget, uptime);
836
850
 
837
851
  // The rescue runs on its own queue and the dying thread only waits with a
@@ -841,15 +855,15 @@ static void PushyMaybeHoldForRescue(void) {
841
855
  dispatch_semaphore_t done = dispatch_semaphore_create(0);
842
856
  dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
843
857
  @try {
844
- [RCTPushyOrchestrator runRescueWithDeadline:deadline];
858
+ [RCTPushyOrchestrator runHoldRoundWithDeadline:deadline];
845
859
  } @catch (NSException *exception) {
846
- NSLog(@"RCTPushy -- crash rescue failed: %@", exception.reason);
860
+ NSLog(@"RCTPushy -- crash hold failed: %@", exception.reason);
847
861
  }
848
862
  dispatch_semaphore_signal(done);
849
863
  });
850
864
  if (dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW,
851
865
  (int64_t)(budget * NSEC_PER_SEC))) != 0) {
852
- NSLog(@"RCTPushy -- crash rescue: budget exhausted, letting go");
866
+ NSLog(@"RCTPushy -- crash hold: budget exhausted, letting go");
853
867
  }
854
868
  }
855
869
 
@@ -858,9 +872,9 @@ static void PushyMaybeHoldForRescue(void) {
858
872
  // process is still alive and JS will never run again — a natural,
859
873
  // false-positive-free window to finish the cold-start check. The previous
860
874
  // handler (crash reporters chain the same way) always runs afterwards.
861
- static void PushyCrashRescueExceptionHandler(NSException *exception) {
875
+ static void PushyCrashHoldExceptionHandler(NSException *exception) {
862
876
  @try {
863
- PushyMaybeHoldForRescue();
877
+ PushyMaybeHoldProcess();
864
878
  } @catch (NSException *inner) {
865
879
  // The dying process owes the previous handler its turn no matter
866
880
  // what the rescue did.
@@ -870,11 +884,11 @@ static void PushyCrashRescueExceptionHandler(NSException *exception) {
870
884
  }
871
885
  }
872
886
 
873
- static void PushyInstallCrashRescueHandler(void) {
887
+ static void PushyInstallCrashHoldHandler(void) {
874
888
  static dispatch_once_t onceToken;
875
889
  dispatch_once(&onceToken, ^{
876
890
  pushyPreviousExceptionHandler = NSGetUncaughtExceptionHandler();
877
- NSSetUncaughtExceptionHandler(&PushyCrashRescueExceptionHandler);
891
+ NSSetUncaughtExceptionHandler(&PushyCrashHoldExceptionHandler);
878
892
  });
879
893
  }
880
894
 
@@ -1137,14 +1151,14 @@ RCT_EXPORT_MODULE(RCTPushy);
1137
1151
  static dispatch_queue_t hostQueue;
1138
1152
  static dispatch_once_t once;
1139
1153
  dispatch_once(&once, ^{
1140
- hostQueue = dispatch_queue_create("cn.reactnative.pushy.host-check", DISPATCH_QUEUE_SERIAL);
1154
+ hostQueue = dispatch_queue_create("cn.reactnative.pushy.host-sync", DISPATCH_QUEUE_SERIAL);
1141
1155
  });
1142
1156
  dispatch_async(hostQueue, ^{
1143
1157
  NSDictionary *result;
1144
1158
  @try {
1145
1159
  result = [RCTPushyOrchestrator prepareBundle];
1146
1160
  } @catch (NSException *exception) {
1147
- RCTLogWarn(@"RCTPushy -- native host check failed: %@", exception.reason);
1161
+ RCTLogWarn(@"RCTPushy -- native host sync failed: %@", exception.reason);
1148
1162
  result = PushyHostResult(@"failed", @"internal_error", nil, NO);
1149
1163
  }
1150
1164
  if (completion != nil) {
@@ -1286,7 +1300,7 @@ RCT_EXPORT_METHOD(markJsCheckCompleted:(NSString *)config
1286
1300
  PushyRejectError(reject, PushyErrorWithCode(pushy::error_codes::kInvalidOptions, ERROR_OPTIONS));
1287
1301
  return;
1288
1302
  }
1289
- [RCTPushyOrchestrator markJsCheckCompleted:config];
1303
+ [RCTPushyOrchestrator recordJsRound:config];
1290
1304
  resolve(@true);
1291
1305
  }
1292
1306
 
@@ -1328,21 +1342,21 @@ RCT_EXPORT_METHOD(downloadFullUpdate:(NSDictionary *)options
1328
1342
  resolver:(RCTPromiseResolveBlock)resolve
1329
1343
  rejecter:(RCTPromiseRejectBlock)reject)
1330
1344
  {
1331
- [self downloadUpdate:PushyTypeFullDownload options:options resolver:resolve rejecter:reject];
1345
+ [self fetchPackage:PushyTypeFullDownload options:options resolver:resolve rejecter:reject];
1332
1346
  }
1333
1347
 
1334
1348
  RCT_EXPORT_METHOD(downloadPatchFromPackage:(NSDictionary *)options
1335
1349
  resolver:(RCTPromiseResolveBlock)resolve
1336
1350
  rejecter:(RCTPromiseRejectBlock)reject)
1337
1351
  {
1338
- [self downloadUpdate:PushyTypePatchFromPackage options:options resolver:resolve rejecter:reject];
1352
+ [self fetchPackage:PushyTypePatchFromPackage options:options resolver:resolve rejecter:reject];
1339
1353
  }
1340
1354
 
1341
1355
  RCT_EXPORT_METHOD(downloadPatchFromPpk:(NSDictionary *)options
1342
1356
  resolver:(RCTPromiseResolveBlock)resolve
1343
1357
  rejecter:(RCTPromiseRejectBlock)reject)
1344
1358
  {
1345
- [self downloadUpdate:PushyTypePatchFromPpk options:options resolver:resolve rejecter:reject];
1359
+ [self fetchPackage:PushyTypePatchFromPpk options:options resolver:resolve rejecter:reject];
1346
1360
  }
1347
1361
 
1348
1362
  RCT_EXPORT_METHOD(downloadAndInstallApk:(NSDictionary *)options
@@ -1377,7 +1391,7 @@ RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
1377
1391
  return;
1378
1392
  }
1379
1393
 
1380
- NSError *reloadError = [self reloadBridgeWithReason:@"pushy reloadUpdate"];
1394
+ NSError *reloadError = [self restartBridgeWithReason:@"pushy restart"];
1381
1395
  if (reloadError != nil) {
1382
1396
  PushyRejectError(reject, reloadError);
1383
1397
  return;
@@ -1388,7 +1402,7 @@ RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
1388
1402
  RCT_EXPORT_METHOD(restartApp:(RCTPromiseResolveBlock)resolve
1389
1403
  rejecter:(RCTPromiseRejectBlock)reject)
1390
1404
  {
1391
- NSError *reloadError = [self reloadBridgeWithReason:@"pushy restartApp"];
1405
+ NSError *reloadError = [self restartBridgeWithReason:@"pushy restartApp"];
1392
1406
  if (reloadError != nil) {
1393
1407
  PushyRejectError(reject, reloadError);
1394
1408
  return;
@@ -1499,7 +1513,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1499
1513
  // promise settles here, after the cleanup, so a failed wipe reaches
1500
1514
  // JS as RESET_FAILED (Android parity) instead of a warning nobody
1501
1515
  // aggregates.
1502
- pushy::patch::Status status = pushy::patch::CleanupOldEntries(
1516
+ pushy::delta::Status status = pushy::delta::CleanupOldEntries(
1503
1517
  PushyToStdString([RCTPushy downloadDir]),
1504
1518
  std::vector<std::string>{PushyToStdString(keepVersion)},
1505
1519
  0
@@ -1533,12 +1547,12 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1533
1547
  hasListeners = NO;
1534
1548
  }
1535
1549
 
1536
- - (void)downloadUpdate:(PushyType)type
1550
+ - (void)fetchPackage:(PushyType)type
1537
1551
  options:(NSDictionary *)options
1538
1552
  resolver:(RCTPromiseResolveBlock)resolve
1539
1553
  rejecter:(RCTPromiseRejectBlock)reject
1540
1554
  {
1541
- [self performUpdate:type options:options callback:^(NSError *error) {
1555
+ [self performFetch:type options:options callback:^(NSError *error) {
1542
1556
  if (error != nil) {
1543
1557
  if (error.userInfo[PushyErrorCodeKey] == nil) {
1544
1558
  // Unclassified (system/network) errors from the download
@@ -1560,7 +1574,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1560
1574
  // here: it consumes one-shot launch state (first_time, the first-load mark,
1561
1575
  // ignoreRollback), and consuming it for a reload that never happens would
1562
1576
  // make the next cold start roll the freshly switched version back.
1563
- - (NSError *)reloadBridgeWithReason:(NSString *)reason
1577
+ - (NSError *)restartBridgeWithReason:(NSString *)reason
1564
1578
  {
1565
1579
  #if PUSHY_HAS_RELOAD_COMMAND
1566
1580
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -1575,7 +1589,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1575
1589
  RCTBridge *bridge = self.bridge;
1576
1590
  if (bridge == nil || object_getClass(bridge) == NSClassFromString(@"RCTBridgeProxy")) {
1577
1591
  return PushyErrorWithCode(pushy::error_codes::kRestartFailed,
1578
- @"no bridge available to reload (bridgeless host without RCTReloadCommand)");
1592
+ @"no bridge available to restart (bridgeless host without the RN restart command)");
1579
1593
  }
1580
1594
  dispatch_async(dispatch_get_main_queue(), ^{
1581
1595
  [bridge reload];
@@ -1584,9 +1598,9 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1584
1598
  #endif
1585
1599
  }
1586
1600
 
1587
- - (void)performUpdate:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
1601
+ - (void)performFetch:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
1588
1602
  {
1589
- NSString *updateUrl = PushyOptionString(options, @"updateUrl");
1603
+ NSString *updateUrl = PushyOptionString(options, PushyOptionUrlKey);
1590
1604
  NSString *hash = PushyOptionString(options, @"hash");
1591
1605
 
1592
1606
  if (PushyStringIsBlank(updateUrl) || !PushyIsSafePathComponent(hash)) {
@@ -1632,7 +1646,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1632
1646
  }
1633
1647
  };
1634
1648
  void (^deferredStart)(void) = ^{
1635
- [self performUpdate:type options:options callback:callback];
1649
+ [self performFetch:type options:options callback:callback];
1636
1650
  };
1637
1651
  PushyDownloadRegistration registration = PushyRegisterDownload(
1638
1652
  hash, type, deadlineUptime, callback, progress, deferredStart);
@@ -1669,7 +1683,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1669
1683
  // version directory in one atomic step.
1670
1684
  NSString *bundlePath = [staging stringByAppendingPathComponent:BUNDLE_FILE_NAME];
1671
1685
  if (![fileManager fileExistsAtPath:bundlePath]) {
1672
- finalError = PushyErrorWithCode(pushy::error_codes::kPatchFailed,
1686
+ finalError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
1673
1687
  @"bundle missing after install");
1674
1688
  } else {
1675
1689
  std::string bundleSha256 = pushy::digest::Sha256File(PushyToStdString(bundlePath));
@@ -1768,8 +1782,8 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1768
1782
  } @catch (NSException *exception) {
1769
1783
  // An uncaught exception in a GCD block is fatal (and would
1770
1784
  // trip the crash rescue); a bad package is a PATCH_FAILED.
1771
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed,
1772
- exception.reason ?: @"patch failed"));
1785
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
1786
+ exception.reason ?: @"delta failed"));
1773
1787
  }
1774
1788
  });
1775
1789
  }];
@@ -1782,7 +1796,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1782
1796
  {
1783
1797
  switch (type) {
1784
1798
  case PushyTypePatchFromPackage:
1785
- [self applyPatchForHash:hash
1799
+ [self applyDeltaForHash:hash
1786
1800
  type:type
1787
1801
  fromBundle:[[RCTPushy binaryBundleURL] path]
1788
1802
  source:[[NSBundle mainBundle] resourcePath]
@@ -1790,7 +1804,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1790
1804
  return;
1791
1805
  case PushyTypePatchFromPpk: {
1792
1806
  NSString *lastVersionDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:originHash];
1793
- [self applyPatchForHash:hash
1807
+ [self applyDeltaForHash:hash
1794
1808
  type:type
1795
1809
  fromBundle:[lastVersionDir stringByAppendingPathComponent:BUNDLE_FILE_NAME]
1796
1810
  source:lastVersionDir
@@ -1803,7 +1817,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1803
1817
  }
1804
1818
  }
1805
1819
 
1806
- - (void)applyPatchForHash:(NSString *)hash
1820
+ - (void)applyDeltaForHash:(NSString *)hash
1807
1821
  type:(PushyType)type
1808
1822
  fromBundle:(NSString *)bundleOrigin
1809
1823
  source:(NSString *)sourceOrigin
@@ -1818,13 +1832,13 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1818
1832
  NSString *destination = [unzipDir stringByAppendingPathComponent:BUNDLE_FILE_NAME];
1819
1833
  long long manifestBytes = RCTPushyFileSize(sourcePatch);
1820
1834
  if (manifestBytes > pushy::archive_limits::kMaxManifestBytes) {
1821
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed,
1822
- [NSString stringWithFormat:@"patch manifest too large: %lld bytes", manifestBytes]));
1835
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
1836
+ [NSString stringWithFormat:@"delta manifest too large: %lld bytes", manifestBytes]));
1823
1837
  return;
1824
1838
  }
1825
1839
  NSData *data = [NSData dataWithContentsOfFile:sourcePatch];
1826
1840
  if (data == nil) {
1827
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed, @"missing patch manifest"));
1841
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, @"missing delta manifest"));
1828
1842
  return;
1829
1843
  }
1830
1844
 
@@ -1833,19 +1847,19 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1833
1847
  if (error != nil) {
1834
1848
  // Classify as a patch failure like the sibling manifest branches;
1835
1849
  // unclassified errors would otherwise be tagged DOWNLOAD_FAILED by the
1836
- // downloadUpdate fallback even though the download itself succeeded.
1837
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed, error.localizedDescription));
1850
+ // fetchPackage fallback even though the download itself succeeded.
1851
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, error.localizedDescription));
1838
1852
  return;
1839
1853
  }
1840
1854
  if (![jsonObject isKindOfClass:[NSDictionary class]]) {
1841
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed, @"invalid patch manifest"));
1855
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, @"invalid delta manifest"));
1842
1856
  return;
1843
1857
  }
1844
1858
  NSDictionary *json = (NSDictionary *)jsonObject;
1845
- pushy::patch::PatchManifest manifest;
1859
+ pushy::delta::PatchManifest manifest;
1846
1860
  NSString *manifestReason = nil;
1847
1861
  if (!PushyPatchManifestFromJson(json, &manifest, &manifestReason)) {
1848
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed, manifestReason));
1862
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, manifestReason));
1849
1863
  return;
1850
1864
  }
1851
1865
 
@@ -1858,7 +1872,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1858
1872
  }
1859
1873
 
1860
1874
  pushy::archive_patch::ArchivePatchPlan plan;
1861
- pushy::patch::Status planStatus = pushy::archive_patch::BuildArchivePatchPlan(
1875
+ pushy::delta::Status planStatus = pushy::archive_patch::BuildArchivePatchPlan(
1862
1876
  type == PushyTypePatchFromPackage
1863
1877
  ? pushy::archive_patch::ArchivePatchType::kPatchFromPackage
1864
1878
  : pushy::archive_patch::ArchivePatchType::kPatchFromPpk,
@@ -1871,8 +1885,8 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1871
1885
  return;
1872
1886
  }
1873
1887
 
1874
- pushy::patch::FileSourcePatchOptions options;
1875
- pushy::patch::Status optionStatus = pushy::archive_patch::BuildFileSourcePatchOptions(
1888
+ pushy::delta::FileSourcePatchOptions options;
1889
+ pushy::delta::Status optionStatus = pushy::archive_patch::BuildFileSourcePatchOptions(
1876
1890
  plan,
1877
1891
  PushyToStdString(sourceOrigin),
1878
1892
  PushyToStdString(unzipDir),
@@ -1901,7 +1915,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1901
1915
  }
1902
1916
  }
1903
1917
 
1904
- pushy::patch::Status status = pushy::patch::ApplyPatchFromFileSource(options);
1918
+ pushy::delta::Status status = pushy::delta::ApplyPatchFromFileSource(options);
1905
1919
  if (!status.ok) {
1906
1920
  callback(PushyNSErrorFromStatus(status));
1907
1921
  return;
@@ -2025,7 +2039,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2025
2039
  long long archiveBytes = RCTPushyFileSize(path);
2026
2040
  NSError *preflight = nil;
2027
2041
  if (archiveBytes > pushy::archive_limits::kMaxArchiveBytes) {
2028
- preflight = PushyErrorWithCode(pushy::error_codes::kPatchFailed,
2042
+ preflight = PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
2029
2043
  [NSString stringWithFormat:@"archive too large: %lld bytes", archiveBytes]);
2030
2044
  } else {
2031
2045
  preflight = PushyEnsureFreeSpace(destination, MAX(0LL, archiveBytes) * 2);
@@ -2063,15 +2077,15 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2063
2077
 
2064
2078
  NSError *unzipError = error;
2065
2079
  if (guard.violation != nil) {
2066
- unzipError = PushyErrorWithCode(pushy::error_codes::kPatchFailed, guard.violation);
2080
+ unzipError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed, guard.violation);
2067
2081
  } else if (!succeeded && unzipError == nil) {
2068
- unzipError = PushyErrorWithCode(pushy::error_codes::kPatchFailed, @"unzip failed");
2082
+ unzipError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed, @"unzip failed");
2069
2083
  } else if (unzipError != nil && unzipError.userInfo[PushyErrorCodeKey] == nil) {
2070
2084
  // SSZipArchive's own NSError (corrupt zip, bad magic, ...) has
2071
- // no stable code; without one, downloadUpdate's fallback would
2085
+ // no stable code; without one, fetchPackage's fallback would
2072
2086
  // classify it as DOWNLOAD_FAILED even though the download
2073
2087
  // succeeded — keep the classification deterministic.
2074
- unzipError = PushyErrorWithCode(pushy::error_codes::kPatchFailed,
2088
+ unzipError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
2075
2089
  unzipError.localizedDescription ?: @"unzip failed");
2076
2090
  }
2077
2091
  completionHandler(unzipError);
@@ -2095,7 +2109,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2095
2109
  // process booted from: two switches without a restart would otherwise
2096
2110
  // evict the running bundle while its on-demand assets are still
2097
2111
  // being served.
2098
- pushy::patch::Status status = pushy::patch::CleanupOldEntries(
2112
+ pushy::delta::Status status = pushy::delta::CleanupOldEntries(
2099
2113
  PushyToStdString(downloadDir),
2100
2114
  std::vector<std::string>{
2101
2115
  state.current_version,
@@ -2114,9 +2128,9 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2114
2128
  {
2115
2129
  switch (type) {
2116
2130
  case PushyTypePatchFromPackage:
2117
- return @".ipa.patch";
2131
+ return PushyIpaDeltaSuffix;
2118
2132
  case PushyTypePatchFromPpk:
2119
- return @".ppk.patch";
2133
+ return PushyPpkDeltaSuffix;
2120
2134
  case PushyTypeFullDownload:
2121
2135
  break;
2122
2136
  }
@@ -2210,10 +2224,10 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2210
2224
  // NSAllowsArbitraryLoads. Same rule as RCTPushyDownloader. Returning nil
2211
2225
  // delivers the 3xx itself as the final response, which the status check in
2212
2226
  // PushyHttpRequest then treats as a failed endpoint.
2213
- @interface PushyCheckRequestRedirectGuard : NSObject <NSURLSessionTaskDelegate>
2227
+ @interface PushyRequestRedirectGuard : NSObject <NSURLSessionTaskDelegate>
2214
2228
  @end
2215
2229
 
2216
- @implementation PushyCheckRequestRedirectGuard
2230
+ @implementation PushyRequestRedirectGuard
2217
2231
 
2218
2232
  - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
2219
2233
  willPerformHTTPRedirection:(NSHTTPURLResponse *)response
@@ -2255,7 +2269,7 @@ static NSString *PushyHttpRequest(NSString *urlString, NSString *method,
2255
2269
  // final response.
2256
2270
  NSURLSession *session = [NSURLSession
2257
2271
  sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
2258
- delegate:[PushyCheckRequestRedirectGuard new]
2272
+ delegate:[PushyRequestRedirectGuard new]
2259
2273
  delegateQueue:nil];
2260
2274
  NSURLSessionDataTask *task = [session dataTaskWithRequest:request
2261
2275
  completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
@@ -2290,13 +2304,13 @@ static NSString *PushyNormalizeEndpointBase(NSString *base) {
2290
2304
  return base;
2291
2305
  }
2292
2306
 
2293
- static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2307
+ static BOOL PushyIsValidResponse(NSString *responseText) {
2294
2308
  if (responseText == nil) {
2295
2309
  return NO;
2296
2310
  }
2297
- // Shared schema rule (update_flow_core::IsValidCheckResponse): a 200 with
2311
+ // Shared schema rule (update_flow_core::IsValidResponse): a 200 with
2298
2312
  // `{"error": ...}` is a failed endpoint, not a verdict.
2299
- return updateflow::IsValidCheckResponse(PushyToStdString(responseText)) ? YES : NO;
2313
+ return flowcore::IsValidResponse(PushyToStdString(responseText)) ? YES : NO;
2300
2314
  }
2301
2315
 
2302
2316
  @implementation RCTPushyOrchestrator
@@ -2316,10 +2330,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2316
2330
  pushyNativeConfigGeneration.fetch_add(1);
2317
2331
  [defaults setObject:config forKey:keyNativeConfig];
2318
2332
  [defaults removeObjectForKey:keyNativeCheckCache];
2319
- [self markJsCheckCompleted:nil];
2333
+ [self recordJsRound:nil];
2320
2334
  });
2321
- if (pushyNativeCheckReady.load() && [self hasRunnableConfig]) {
2322
- PushyInstallCrashRescueHandler();
2335
+ if (pushySyncReady.load() && [self hasRunnableConfig]) {
2336
+ PushyInstallCrashHoldHandler();
2323
2337
  }
2324
2338
  }
2325
2339
 
@@ -2343,12 +2357,12 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2343
2357
  pushyHostRoundGroup = dispatch_group_create();
2344
2358
  dispatch_group_enter(pushyHostRoundGroup);
2345
2359
  pushyProcessAnchorUptime = PushyMonotonicNow();
2346
- pushyLaunchRolledBackForRescue = [launchRolledBackVersion copy];
2347
- pushyNativeCheckReady.store(true);
2360
+ pushyLaunchRolledBackForHold = [launchRolledBackVersion copy];
2361
+ pushySyncReady.store(true);
2348
2362
  // The crash-hold rescue shares the orchestrator's rollout gate: no
2349
2363
  // persisted config, no handler (§11.3).
2350
2364
  if ([PushyDefaults() stringForKey:keyNativeConfig].length > 0) {
2351
- PushyInstallCrashRescueHandler();
2365
+ PushyInstallCrashHoldHandler();
2352
2366
  }
2353
2367
  });
2354
2368
  }
@@ -2367,10 +2381,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2367
2381
  [defaults objectForKey:keyNativeCheckIncomplete] != nil ? 0 : 5;
2368
2382
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delaySeconds * NSEC_PER_SEC),
2369
2383
  dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
2370
- if ([self isJsCheckCompleted]) {
2384
+ if ([self hasJsRound]) {
2371
2385
  // Not consuming the round: a later crash rescue may still
2372
2386
  // need it.
2373
- NSLog(@"RCTPushy -- native check skipped: JS check completed in this process");
2387
+ NSLog(@"RCTPushy -- native sync skipped: JS already queried in this process");
2374
2388
  return;
2375
2389
  }
2376
2390
  [self startRoundWithDeadline:0];
@@ -2392,7 +2406,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2392
2406
  rolledBack:(NSString *)launchRolledBackVersion {
2393
2407
  [self prepareProcess:launchRolledBackVersion];
2394
2408
  if (![self hasRunnableConfig]) {
2395
- RCTLogWarn(@"RCTPushy -- version %@ was purged and no native check is "
2409
+ RCTLogWarn(@"RCTPushy -- version %@ was purged and no native sync is "
2396
2410
  @"configured; launching the packaged bundle", purgedVersion);
2397
2411
  return NO;
2398
2412
  }
@@ -2429,7 +2443,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2429
2443
  #if DEBUG
2430
2444
  return PushyHostResult(@"skipped", @"debug", nil, NO);
2431
2445
  #else
2432
- if (!pushyNativeCheckReady.load()) {
2446
+ if (!pushySyncReady.load()) {
2433
2447
  return PushyHostResult(@"skipped", @"not_initialized", nil, NO);
2434
2448
  }
2435
2449
  NSString *configJson = [PushyDefaults() stringForKey:keyNativeConfig];
@@ -2468,7 +2482,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2468
2482
  #endif
2469
2483
  }
2470
2484
 
2471
- + (void)markJsCheckCompleted:(NSString *)config {
2485
+ + (void)recordJsRound:(NSString *)config {
2472
2486
  @synchronized (RCTPushyOrchestrator.class) {
2473
2487
  pushyJsCompletedConfig = [config copy];
2474
2488
  }
@@ -2478,7 +2492,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2478
2492
  // exact config the native round would use (§10.3): the delayed round is
2479
2493
  // then a duplicate request. Only the scheduled round asks — the crash-rescue
2480
2494
  // path still runs, JS is dead by then.
2481
- + (BOOL)isJsCheckCompleted {
2495
+ + (BOOL)hasJsRound {
2482
2496
  NSString *jsConfig;
2483
2497
  @synchronized (RCTPushyOrchestrator.class) {
2484
2498
  jsConfig = pushyJsCompletedConfig;
@@ -2503,10 +2517,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2503
2517
  return;
2504
2518
  }
2505
2519
  @try {
2506
- [self runOnce:pushyLaunchRolledBackForRescue deadline:deadlineUptime];
2520
+ [self runOnce:pushyLaunchRolledBackForHold deadline:deadlineUptime];
2507
2521
  } @catch (NSException *exception) {
2508
2522
  // The rescue path must never take the app down with it.
2509
- RCTLogWarn(@"RCTPushy -- native check crashed: %@", exception.reason);
2523
+ RCTLogWarn(@"RCTPushy -- native sync crashed: %@", exception.reason);
2510
2524
  pushyHostRoundResult = PushyHostResult(@"failed", @"internal_error", nil, NO);
2511
2525
  } @finally {
2512
2526
  pushyRoundCompleted.store(true);
@@ -2520,8 +2534,8 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2520
2534
  // process's round runs to completion within the budget, then activates a
2521
2535
  // downloaded-but-unactivated version if one exists — the last chance before
2522
2536
  // the process is gone.
2523
- + (void)runRescueWithDeadline:(NSTimeInterval)deadlineUptime {
2524
- pushyCrashRescueActive.store(true);
2537
+ + (void)runHoldRoundWithDeadline:(NSTimeInterval)deadlineUptime {
2538
+ pushyCrashHoldActive.store(true);
2525
2539
  [self startRoundWithDeadline:deadlineUptime];
2526
2540
  if (pushyRoundStarted.load() && !pushyRoundCompleted.load()) {
2527
2541
  NSTimeInterval remaining = deadlineUptime - PushyMonotonicNow();
@@ -2552,7 +2566,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2552
2566
  // catch below anyway, or by cleanup).
2553
2567
  NSString *versionDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:hash];
2554
2568
  if (!PushyHasCompletedVersionAtPath(versionDir, hash)) {
2555
- NSLog(@"RCTPushy -- crash rescue: version %@ no longer on disk, dropping activation", hash);
2569
+ NSLog(@"RCTPushy -- crash hold: version %@ no longer on disk, dropping activation", hash);
2556
2570
  return;
2557
2571
  }
2558
2572
  NSDictionary *hashInfoEntry = nil;
@@ -2562,7 +2576,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2562
2576
  [NSJSONSerialization JSONObjectWithData:existingData options:0 error:nil];
2563
2577
  if ([parsed isKindOfClass:[NSDictionary class]]) {
2564
2578
  NSMutableDictionary *merged = [parsed mutableCopy];
2565
- merged[@"crashRescue"] = @YES;
2579
+ merged[PushyInfoCrashHold] = @YES;
2566
2580
  hashInfoEntry = @{@"hash": hash, @"info": merged};
2567
2581
  }
2568
2582
  BOOL committed = [self commitRoundWithGeneration:generation
@@ -2577,9 +2591,9 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2577
2591
  @synchronized (self) {
2578
2592
  pushyUnactivatedHash = nil;
2579
2593
  }
2580
- NSLog(@"RCTPushy -- crash rescue: activated downloaded version %@", hash);
2594
+ NSLog(@"RCTPushy -- crash hold: activated downloaded version %@", hash);
2581
2595
  } else {
2582
- NSLog(@"RCTPushy -- crash rescue: reset since download, dropping activation");
2596
+ NSLog(@"RCTPushy -- crash hold: reset since download, dropping activation");
2583
2597
  }
2584
2598
  }
2585
2599
 
@@ -2691,28 +2705,28 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2691
2705
  // shared with JS getBundleHash) on the ordinary delayed round.
2692
2706
  input.Set("bundleHash",
2693
2707
  flowjson::Value::String(PushyToStdString(
2694
- PushyBundleHashSync(!pushyCrashRescueActive.load()))));
2708
+ PushyBundleHashSync(!pushyCrashHoldActive.load()))));
2695
2709
 
2696
2710
  std::string bodyJson =
2697
- flowjson::Stringify(updateflow::BuildCheckRequestBody(input));
2711
+ flowjson::Stringify(flowcore::BuildRequestBody(input));
2698
2712
  NSString *body = [NSString stringWithUTF8String:bodyJson.c_str()];
2699
2713
  if (body == nil) {
2700
- RCTLogWarn(@"RCTPushy -- native check: request body is not valid UTF-8");
2714
+ RCTLogWarn(@"RCTPushy -- native sync: request body is not valid UTF-8");
2701
2715
  pushyHostRoundResult = PushyHostResult(@"failed", @"invalid_request", nil, NO);
2702
2716
  return;
2703
2717
  }
2704
2718
 
2705
- NSString *responseText = [self runCheckRequest:config
2719
+ NSString *responseText = [self runQueryRequest:config
2706
2720
  appKey:appKey
2707
2721
  body:body
2708
2722
  deadline:deadlineUptime];
2709
2723
  if (responseText == nil) {
2710
- RCTLogInfo(@"RCTPushy -- native check: no endpoint reachable, giving up until next launch");
2724
+ RCTLogInfo(@"RCTPushy -- native sync: no endpoint reachable, giving up until next launch");
2711
2725
  return;
2712
2726
  }
2713
2727
  long long responseAtSeconds = (long long)[[NSDate date] timeIntervalSince1970];
2714
2728
 
2715
- flowjson::Value decision = updateflow::HandleCheckResponse(
2729
+ flowjson::Value decision = flowcore::HandleResponse(
2716
2730
  PushyToStdString(responseText), identity, false,
2717
2731
  config.Get("afterDownload").AsString());
2718
2732
  if (decision.Get("action").AsString() != "download") {
@@ -2725,9 +2739,9 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2725
2739
  responseAt:responseAtSeconds
2726
2740
  activated:NULL];
2727
2741
  pushyHostRoundResult = committed
2728
- ? PushyHostResult(@"noUpdate", PushyFromStdString(decision.Get("reason").AsString()), nil, NO)
2742
+ ? PushyHostResult(PushyStatusNone, PushyFromStdString(decision.Get("reason").AsString()), nil, NO)
2729
2743
  : PushyHostResult(@"cancelled", @"reset", nil, NO);
2730
- RCTLogInfo(@"RCTPushy -- native check: nothing to do (%s)",
2744
+ RCTLogInfo(@"RCTPushy -- native sync: nothing to do (%s)",
2731
2745
  decision.Get("reason").AsString().c_str());
2732
2746
  return;
2733
2747
  }
@@ -2774,10 +2788,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2774
2788
  // survives to markSuccess. Only the server-sent directive counts — a
2775
2789
  // silent-strategy activation is ordinary delivery.
2776
2790
  if (info.Get("config").Get("forceBoot").Truthy()) {
2777
- versionInfo[@"forceBootRescue"] = @YES;
2791
+ versionInfo[PushyInfoForceBoot] = @YES;
2778
2792
  }
2779
- if (pushyCrashRescueActive.load()) {
2780
- versionInfo[@"crashRescue"] = @YES;
2793
+ if (pushyCrashHoldActive.load()) {
2794
+ versionInfo[PushyInfoCrashHold] = @YES;
2781
2795
  }
2782
2796
  // Silent strategies or a server-marked forceBoot version (per-version
2783
2797
  // remote override — the brick rescue) activate for the next launch;
@@ -2786,7 +2800,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2786
2800
  // forever (§11.3). Or the launch is blocked on reinstalling a version
2787
2801
  // tvOS purged: JS has not started, and the whole point is to boot it —
2788
2802
  // commitRoundWithGeneration drops that one once the restore window closed.
2789
- BOOL activate = decision.Get("activate").Truthy() || pushyCrashRescueActive.load()
2803
+ BOOL activate = decision.Get("activate").Truthy() || pushyCrashHoldActive.load()
2790
2804
  || pushyPurgeRestoreActive.load();
2791
2805
  BOOL activated = NO;
2792
2806
  BOOL committed = [self commitRoundWithGeneration:resetGeneration
@@ -2799,12 +2813,12 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2799
2813
  activated:&activated];
2800
2814
  activate = activated;
2801
2815
  if (!committed) {
2802
- RCTLogInfo(@"RCTPushy -- native check: reset during round, dropping result");
2816
+ RCTLogInfo(@"RCTPushy -- native sync: reset during round, dropping result");
2803
2817
  } else if (activate) {
2804
2818
  @synchronized (self) {
2805
2819
  pushyUnactivatedHash = nil;
2806
2820
  }
2807
- RCTLogInfo(@"RCTPushy -- native check: downloaded %@ and set for next launch", hash);
2821
+ RCTLogInfo(@"RCTPushy -- native sync: downloaded %@ and set for next launch", hash);
2808
2822
  } else {
2809
2823
  // Remembered so a crash later in this process can still activate it
2810
2824
  // (activatePendingVersion) — JS never will.
@@ -2812,7 +2826,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2812
2826
  pushyUnactivatedHash = [hash copy];
2813
2827
  pushyUnactivatedGeneration = resetGeneration;
2814
2828
  }
2815
- RCTLogInfo(@"RCTPushy -- native check: downloaded %@, activation left to JS", hash);
2829
+ RCTLogInfo(@"RCTPushy -- native sync: downloaded %@, activation left to JS", hash);
2816
2830
  }
2817
2831
  pushyHostRoundResult = committed
2818
2832
  ? PushyHostResult(@"downloaded", @"", hash, activate)
@@ -2863,7 +2877,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2863
2877
  marked[@"purgeRestore"] = @YES;
2864
2878
  info = marked;
2865
2879
  }
2866
- } else if (!pushyCrashRescueActive.load()) {
2880
+ } else if (!pushyCrashHoldActive.load()) {
2867
2881
  activation = nil;
2868
2882
  }
2869
2883
  }
@@ -2899,20 +2913,20 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2899
2913
  // more round. No hedged race on purpose — this path is latency-insensitive.
2900
2914
  // Per-request timeout, capped to the crash-rescue budget when one is active.
2901
2915
  // <= 0 means the budget is gone and the round must stop issuing requests.
2902
- static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2916
+ static NSTimeInterval PushyQueryRequestTimeout(NSTimeInterval deadlineUptime) {
2903
2917
  if (deadlineUptime <= 0) {
2904
2918
  return 10;
2905
2919
  }
2906
2920
  return MIN(10, deadlineUptime - PushyMonotonicNow());
2907
2921
  }
2908
2922
 
2909
- + (NSString *)runCheckRequest:(const flowjson::Value &)config
2923
+ + (NSString *)runQueryRequest:(const flowjson::Value &)config
2910
2924
  appKey:(NSString *)appKey
2911
2925
  body:(NSString *)body
2912
2926
  deadline:(NSTimeInterval)deadlineUptime {
2913
2927
  double sample = arc4random() / 4294967296.0;
2914
2928
  flowjson::Value ordered =
2915
- updateflow::OrderEndpointCandidates(config.Get("endpoints"), sample);
2929
+ flowcore::OrderEndpointCandidates(config.Get("endpoints"), sample);
2916
2930
  NSMutableSet<NSString *> *tried = [NSMutableSet set];
2917
2931
  const NSUInteger maxHttpAttempts = 8;
2918
2932
  NSUInteger httpAttempts = 0;
@@ -2926,14 +2940,14 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2926
2940
  return nil;
2927
2941
  }
2928
2942
  [tried addObject:base];
2929
- NSTimeInterval timeout = PushyCheckRequestTimeout(deadlineUptime);
2943
+ NSTimeInterval timeout = PushyQueryRequestTimeout(deadlineUptime);
2930
2944
  if (timeout <= 0) {
2931
2945
  return nil;
2932
2946
  }
2933
2947
  NSString *response = PushyHttpRequest(
2934
- [NSString stringWithFormat:@"%@/checkUpdate/%@", base, appKey],
2948
+ [NSString stringWithFormat:@"%@%@%@", base, RCTPushyQueryPath(), appKey],
2935
2949
  @"POST", body, timeout);
2936
- if (PushyIsValidCheckResponse(response)) {
2950
+ if (PushyIsValidResponse(response)) {
2937
2951
  return response;
2938
2952
  }
2939
2953
  }
@@ -2945,7 +2959,7 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2945
2959
  if (httpAttempts++ >= maxHttpAttempts) {
2946
2960
  return nil;
2947
2961
  }
2948
- NSTimeInterval listTimeout = PushyCheckRequestTimeout(deadlineUptime);
2962
+ NSTimeInterval listTimeout = PushyQueryRequestTimeout(deadlineUptime);
2949
2963
  if (listTimeout <= 0) {
2950
2964
  return nil;
2951
2965
  }
@@ -2968,14 +2982,14 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2968
2982
  return nil;
2969
2983
  }
2970
2984
  [tried addObject:base];
2971
- NSTimeInterval timeout = PushyCheckRequestTimeout(deadlineUptime);
2985
+ NSTimeInterval timeout = PushyQueryRequestTimeout(deadlineUptime);
2972
2986
  if (timeout <= 0) {
2973
2987
  return nil;
2974
2988
  }
2975
2989
  NSString *response = PushyHttpRequest(
2976
- [NSString stringWithFormat:@"%@/checkUpdate/%@", base, appKey],
2990
+ [NSString stringWithFormat:@"%@%@%@", base, RCTPushyQueryPath(), appKey],
2977
2991
  @"POST", body, timeout);
2978
- if (PushyIsValidCheckResponse(response)) {
2992
+ if (PushyIsValidResponse(response)) {
2979
2993
  return response;
2980
2994
  }
2981
2995
  }
@@ -2987,12 +3001,12 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2987
3001
  + (BOOL)performAttempts:(const flowjson::Value &)attempts
2988
3002
  hash:(NSString *)hash
2989
3003
  originHash:(NSString *)originHash
2990
- deadline:(NSTimeInterval)rescueDeadline {
3004
+ deadline:(NSTimeInterval)holdDeadline {
2991
3005
  RCTPushy *engine = [self engine];
2992
3006
  // Crash-rescue budget caps every phase; 0 keeps the normal 10min windows.
2993
3007
  NSTimeInterval incrementalDeadline = PushyMonotonicNow() + 600;
2994
- if (rescueDeadline > 0) {
2995
- incrementalDeadline = MIN(incrementalDeadline, rescueDeadline);
3008
+ if (holdDeadline > 0) {
3009
+ incrementalDeadline = MIN(incrementalDeadline, holdDeadline);
2996
3010
  }
2997
3011
  NSTimeInterval fullDeadline = 0;
2998
3012
  for (const auto &attempt : attempts.elements()) {
@@ -3007,8 +3021,8 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3007
3021
  if (isFullAttempt && fullDeadline == 0) {
3008
3022
  // diff/pdiff cannot starve the last-resort full download.
3009
3023
  fullDeadline = PushyMonotonicNow() + 600;
3010
- if (rescueDeadline > 0) {
3011
- fullDeadline = MIN(fullDeadline, rescueDeadline);
3024
+ if (holdDeadline > 0) {
3025
+ fullDeadline = MIN(fullDeadline, holdDeadline);
3012
3026
  }
3013
3027
  }
3014
3028
  NSTimeInterval deadline = isFullAttempt ? fullDeadline : incrementalDeadline;
@@ -3026,7 +3040,7 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3026
3040
  }
3027
3041
  NSMutableDictionary *options =
3028
3042
  [@{
3029
- @"updateUrl": url,
3043
+ PushyOptionUrlKey: url,
3030
3044
  @"hash": hash,
3031
3045
  @"deadlineUptime": @(deadline),
3032
3046
  } mutableCopy];
@@ -3035,13 +3049,13 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3035
3049
  }
3036
3050
  dispatch_semaphore_t sem = dispatch_semaphore_create(0);
3037
3051
  __block NSError *resultError = nil;
3038
- [engine performUpdate:pushyType options:options callback:^(NSError *error) {
3052
+ [engine performFetch:pushyType options:options callback:^(NSError *error) {
3039
3053
  resultError = error;
3040
3054
  dispatch_semaphore_signal(sem);
3041
3055
  }];
3042
3056
  if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW,
3043
3057
  (int64_t)(remaining * NSEC_PER_SEC))) != 0) {
3044
- RCTLogWarn(@"RCTPushy -- native check: %s attempt timed out", type.c_str());
3058
+ RCTLogWarn(@"RCTPushy -- native sync: %s attempt timed out", type.c_str());
3045
3059
  if (isFullAttempt) {
3046
3060
  return NO;
3047
3061
  }
@@ -3050,7 +3064,7 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3050
3064
  if (resultError == nil) {
3051
3065
  return YES;
3052
3066
  }
3053
- RCTLogInfo(@"RCTPushy -- native check: %s attempt failed: %@",
3067
+ RCTLogInfo(@"RCTPushy -- native sync: %s attempt failed: %@",
3054
3068
  type.c_str(), resultError.localizedDescription);
3055
3069
  }
3056
3070
  }