react-native-update 10.59.0 → 10.59.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 (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 +6 -6
  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 +8 -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 +148 -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 +15 -3
  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
@@ -64,7 +64,7 @@ static NSString *const keyUuid = @"REACTNATIVECN_PUSHY_UUID";
64
64
  static NSString *const keyHashInfo = @"REACTNATIVECN_PUSHY_HASH_";
65
65
  static NSString *const keyFirstLoadMarked = @"REACTNATIVECN_PUSHY_FIRSTLOADMARKED_KEY";
66
66
  static NSString *const keyRolledBackMarked = @"REACTNATIVECN_PUSHY_ROLLEDBACKMARKED_KEY";
67
- static NSString *const KeyPackageUpdatedMarked = @"REACTNATIVECN_PUSHY_ISPACKAGEUPDATEDMARKED_KEY";
67
+ static NSString *const KeyPackageUpdatedMarked = RCTPushyRevealText("0832d5f29aa549710b0939daf88ca058790f3dded7e888b451640d2ec3f69099bb43711523cafa8ea7bb4372132a");
68
68
  // bundleHash cache: "<cacheKey>|<sha256hex>" where cacheKey identifies the
69
69
  // installed binary (packageVersion + embedded bundle size + mtime). Recomputed
70
70
  // only when the key changes, i.e. once per install.
@@ -84,7 +84,15 @@ static NSString *const PushyErrorDomain = @"cn.reactnative.pushy";
84
84
  // file def
85
85
  static NSString * const BUNDLE_FILE_NAME = @"index.bundlejs";
86
86
  static NSString * const SOURCE_PATCH_NAME = @"__diff.json";
87
- static NSString * const BUNDLE_PATCH_NAME = @"index.bundlejs.patch";
87
+ static NSString * const BUNDLE_PATCH_NAME = RCTPushyRevealText("3319f0d4b6c56a502c3b10fcdca0de7d4b3307e9");
88
+ // Protocol strings and version-info flags read by JS, stored encoded
89
+ // (RCTPushyRevealText) so they do not appear as plain binary strings.
90
+ static NSString * const PushyOptionUrlKey = RCTPushyRevealText("2f07f0d0ba8e5d572e");
91
+ static NSString * const PushyIpaDeltaSuffix = RCTPushyRevealText("741ee4d0e09b69512137");
92
+ static NSString * const PushyPpkDeltaSuffix = RCTPushyRevealText("7407e4dae09b69512137");
93
+ static NSString * const PushyInfoCrashHold = RCTPushyRevealText("3905f5c2a6b96d56212a19");
94
+ static NSString * const PushyInfoForceBoot = RCTPushyRevealText("3c18e6d2aba9674a360d19ead5a695");
95
+ static NSString * const PushyStatusNone = RCTPushyRevealText("3418c1c1aa8a7c40");
88
96
  #define VERSION_COMPLETE_FILE_NAME_LITERAL ".pushy-complete"
89
97
  static NSString * const VERSION_COMPLETE_FILE_NAME = @VERSION_COMPLETE_FILE_NAME_LITERAL;
90
98
 
@@ -211,7 +219,7 @@ static NSError *PushyEnsureFreeSpace(NSString *path, long long bytesToWrite) {
211
219
  if (shortfall == nil) {
212
220
  return nil;
213
221
  }
214
- return PushyErrorWithCode(pushy::error_codes::kPatchFailed, shortfall);
222
+ return PushyErrorWithCode(pushy::error_codes::kDeltaFailed, shortfall);
215
223
  }
216
224
 
217
225
  // SSZipArchive delegate enforcing cpp/patch_core/archive_limits.h while the
@@ -477,12 +485,12 @@ static std::string PushyToStdString(NSString *value) {
477
485
  return std::string([value UTF8String]);
478
486
  }
479
487
 
480
- static NSError *PushyNSErrorFromStatus(const pushy::patch::Status &status) {
488
+ static NSError *PushyNSErrorFromStatus(const pushy::delta::Status &status) {
481
489
  return [NSError errorWithDomain:PushyErrorDomain
482
490
  code:-1
483
491
  userInfo:@{
484
492
  NSLocalizedDescriptionKey: [NSString stringWithUTF8String:status.message.c_str()],
485
- PushyErrorCodeKey: PushyCode(pushy::error_codes::kPatchFailed),
493
+ PushyErrorCodeKey: PushyCode(pushy::error_codes::kDeltaFailed),
486
494
  }];
487
495
  }
488
496
 
@@ -568,12 +576,12 @@ static BOOL PushyJsonIsAbsent(id value) {
568
576
  // raise takes the whole app down (and trips the crash rescue) instead of
569
577
  // failing the patch. NO with `reason` set for a malformed manifest.
570
578
  static BOOL PushyPatchManifestFromJson(NSDictionary *json,
571
- pushy::patch::PatchManifest *manifest,
579
+ pushy::delta::PatchManifest *manifest,
572
580
  NSString **reason) {
573
581
  id copies = json[@"copies"];
574
582
  if (!PushyJsonIsAbsent(copies)) {
575
583
  if (![copies isKindOfClass:[NSDictionary class]]) {
576
- *reason = @"patch manifest: copies is not an object";
584
+ *reason = @"delta manifest: copies is not an object";
577
585
  return NO;
578
586
  }
579
587
  // Content checksum per copy target ("copiesCrc", pdiff manifests
@@ -588,13 +596,13 @@ static BOOL PushyPatchManifestFromJson(NSDictionary *json,
588
596
  for (id to in (NSDictionary *)copies) {
589
597
  id from = ((NSDictionary *)copies)[to];
590
598
  if (![to isKindOfClass:[NSString class]] || ![from isKindOfClass:[NSString class]]) {
591
- *reason = @"patch manifest: copies entry is not a string";
599
+ *reason = @"delta manifest: copies entry is not a string";
592
600
  return NO;
593
601
  }
594
602
  if ([from length] == 0) {
595
603
  from = to;
596
604
  }
597
- pushy::patch::CopyOperation operation;
605
+ pushy::delta::CopyOperation operation;
598
606
  operation.from = PushyToStdString(from);
599
607
  operation.to = PushyToStdString(to);
600
608
  NSNumber *expectedCrc = copiesCrc[to];
@@ -611,12 +619,12 @@ static BOOL PushyPatchManifestFromJson(NSDictionary *json,
611
619
  id deletes = json[@"deletes"];
612
620
  if (!PushyJsonIsAbsent(deletes)) {
613
621
  if (![deletes isKindOfClass:[NSDictionary class]] && ![deletes isKindOfClass:[NSArray class]]) {
614
- *reason = @"patch manifest: deletes is not an object or array";
622
+ *reason = @"delta manifest: deletes is not an object or array";
615
623
  return NO;
616
624
  }
617
625
  for (id path in deletes) {
618
626
  if (![path isKindOfClass:[NSString class]]) {
619
- *reason = @"patch manifest: deletes entry is not a string";
627
+ *reason = @"delta manifest: deletes entry is not a string";
620
628
  return NO;
621
629
  }
622
630
  manifest->deletes.push_back(PushyToStdString(path));
@@ -697,14 +705,14 @@ static void PushySwitchVersionLocked(NSString *hash) {
697
705
  }
698
706
 
699
707
  @interface RCTPushy ()
700
- - (void)downloadUpdate:(PushyType)type
708
+ - (void)fetchPackage:(PushyType)type
701
709
  options:(NSDictionary *)options
702
710
  resolver:(RCTPromiseResolveBlock)resolve
703
711
  rejecter:(RCTPromiseRejectBlock)reject;
704
- - (void)performUpdate:(PushyType)type
712
+ - (void)performFetch:(PushyType)type
705
713
  options:(NSDictionary *)options
706
714
  callback:(void (^)(NSError *error))callback;
707
- - (NSError *)reloadBridgeWithReason:(NSString *)reason;
715
+ - (NSError *)restartBridgeWithReason:(NSString *)reason;
708
716
  - (void)unzipDownloadedPackage:(NSString *)zipFilePath
709
717
  hash:(NSString *)hash
710
718
  type:(PushyType)type
@@ -714,7 +722,7 @@ static void PushySwitchVersionLocked(NSString *hash) {
714
722
  type:(PushyType)type
715
723
  originHash:(NSString *)originHash
716
724
  callback:(void (^)(NSError *error))callback;
717
- - (void)applyPatchForHash:(NSString *)hash
725
+ - (void)applyDeltaForHash:(NSString *)hash
718
726
  type:(PushyType)type
719
727
  fromBundle:(NSString *)bundleOrigin
720
728
  source:(NSString *)sourceOrigin
@@ -744,10 +752,10 @@ static void PushySwitchVersionLocked(NSString *hash) {
744
752
  + (BOOL)restorePurgedLaunch:(NSString *)purgedVersion
745
753
  rolledBack:(NSString *)launchRolledBackVersion;
746
754
  #endif
747
- + (void)markJsCheckCompleted:(NSString *)config;
755
+ + (void)recordJsRound:(NSString *)config;
748
756
  + (void)startRoundWithDeadline:(NSTimeInterval)deadlineUptime;
749
757
  + (void)runOnce:(NSString *)launchRolledBackVersion deadline:(NSTimeInterval)deadlineUptime;
750
- + (void)runRescueWithDeadline:(NSTimeInterval)deadlineUptime;
758
+ + (void)runHoldRoundWithDeadline:(NSTimeInterval)deadlineUptime;
751
759
  + (BOOL)commitRoundWithGeneration:(uint64_t)generation
752
760
  hashInfo:(NSDictionary *)hashInfoEntry
753
761
  activate:(NSString *)hashToActivate
@@ -766,8 +774,8 @@ static std::atomic<bool> pushyRoundCompleted{false};
766
774
  // Flipped the moment a crash is being held. JS is dead from that point on,
767
775
  // so there is no second decision maker: the round force-activates whatever
768
776
  // it downloads (§11.3).
769
- static std::atomic<bool> pushyCrashRescueActive{false};
770
- static std::atomic<bool> pushyRescueAttempted{false};
777
+ static std::atomic<bool> pushyCrashHoldActive{false};
778
+ static std::atomic<bool> pushyHoldAttempted{false};
771
779
  // Set when this process's round is the tvOS purged-version restore.
772
780
  static std::atomic<bool> pushyPurgeRestoreActive{false};
773
781
  // True while +bundleURL waits for that restore. Only then may the round
@@ -778,7 +786,7 @@ static std::atomic<bool> pushyPurgeRestoreActive{false};
778
786
  // (and is left to JS) — never selected behind the packaged bundle's back.
779
787
  static bool pushyPurgeRestoreWindowOpen = false;
780
788
  static dispatch_semaphore_t pushyRoundDone;
781
- static NSString *pushyLaunchRolledBackForRescue = nil;
789
+ static NSString *pushyLaunchRolledBackForHold = nil;
782
790
  // A version this process downloaded but left for JS to activate. If the
783
791
  // process then crashes, JS will never activate it — the crash handler
784
792
  // activates it directly (bounded local work, no network). The generation is
@@ -796,27 +804,27 @@ static NSTimeInterval pushyProcessAnchorUptime = 0;
796
804
  static NSString *pushyJsCompletedConfig = nil;
797
805
  // The group supplements (rather than consumes) the crash-rescue semaphore.
798
806
  static dispatch_group_t pushyHostRoundGroup;
799
- static std::atomic<bool> pushyNativeCheckReady{false};
807
+ static std::atomic<bool> pushySyncReady{false};
800
808
  static NSDictionary *pushyHostRoundResult = nil;
801
809
  static NSString *pushyHostRoundConfig = nil;
802
810
  static uint64_t pushyHostRoundGeneration = 0;
803
811
  static std::atomic<uint64_t> pushyNativeConfigGeneration{0};
804
812
  static uint64_t pushyHostRoundConfigGeneration = 0;
805
813
 
806
- static const NSTimeInterval kPushyRescueTriggerUptime = 60;
807
- static const NSTimeInterval kPushyRescueBudgetBackgroundThread = 10;
814
+ static const NSTimeInterval kPushyHoldTriggerUptime = 60;
815
+ static const NSTimeInterval kPushyHoldBudgetBackgroundThread = 10;
808
816
  // A held main thread freezes UI teardown; stay well under the watchdog.
809
- static const NSTimeInterval kPushyRescueBudgetMainThread = 3.5;
817
+ static const NSTimeInterval kPushyHoldBudgetMainThread = 3.5;
810
818
  // The purged-version restore blocks +bundleURL, usually inside
811
819
  // application:didFinishLaunching: — stay clear of the launch watchdog.
812
820
  static const NSTimeInterval kPushyPurgeRestoreBudget = 12;
813
821
 
814
- static void PushyMaybeHoldForRescue(void) {
822
+ static void PushyMaybeHoldProcess(void) {
815
823
  // Once per process; a second crashing thread passes straight through
816
824
  // instead of waiting behind the first (§11.3: prefer under-rescuing over
817
825
  // wedging the teardown).
818
826
  bool expected = false;
819
- if (!pushyRescueAttempted.compare_exchange_strong(expected, true)) {
827
+ if (!pushyHoldAttempted.compare_exchange_strong(expected, true)) {
820
828
  return;
821
829
  }
822
830
  NSTimeInterval uptime = PushyMonotonicNow() - pushyProcessAnchorUptime;
@@ -824,14 +832,14 @@ static void PushyMaybeHoldForRescue(void) {
824
832
  // Early crashes are the brick signature; a crash with an in-flight round
825
833
  // is worth finishing regardless of uptime. Everything else is an ordinary
826
834
  // crash whose UX must not be delayed.
827
- if (uptime >= kPushyRescueTriggerUptime && !roundInFlight) {
835
+ if (uptime >= kPushyHoldTriggerUptime && !roundInFlight) {
828
836
  return;
829
837
  }
830
838
  NSTimeInterval budget = [NSThread isMainThread]
831
- ? kPushyRescueBudgetMainThread
832
- : kPushyRescueBudgetBackgroundThread;
839
+ ? kPushyHoldBudgetMainThread
840
+ : kPushyHoldBudgetBackgroundThread;
833
841
  NSTimeInterval deadline = PushyMonotonicNow() + budget;
834
- NSLog(@"RCTPushy -- crash rescue: holding process for up to %.1fs "
842
+ NSLog(@"RCTPushy -- crash hold: holding process for up to %.1fs "
835
843
  @"(uptime %.1fs)", budget, uptime);
836
844
 
837
845
  // The rescue runs on its own queue and the dying thread only waits with a
@@ -841,15 +849,15 @@ static void PushyMaybeHoldForRescue(void) {
841
849
  dispatch_semaphore_t done = dispatch_semaphore_create(0);
842
850
  dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
843
851
  @try {
844
- [RCTPushyOrchestrator runRescueWithDeadline:deadline];
852
+ [RCTPushyOrchestrator runHoldRoundWithDeadline:deadline];
845
853
  } @catch (NSException *exception) {
846
- NSLog(@"RCTPushy -- crash rescue failed: %@", exception.reason);
854
+ NSLog(@"RCTPushy -- crash hold failed: %@", exception.reason);
847
855
  }
848
856
  dispatch_semaphore_signal(done);
849
857
  });
850
858
  if (dispatch_semaphore_wait(done, dispatch_time(DISPATCH_TIME_NOW,
851
859
  (int64_t)(budget * NSEC_PER_SEC))) != 0) {
852
- NSLog(@"RCTPushy -- crash rescue: budget exhausted, letting go");
860
+ NSLog(@"RCTPushy -- crash hold: budget exhausted, letting go");
853
861
  }
854
862
  }
855
863
 
@@ -858,9 +866,9 @@ static void PushyMaybeHoldForRescue(void) {
858
866
  // process is still alive and JS will never run again — a natural,
859
867
  // false-positive-free window to finish the cold-start check. The previous
860
868
  // handler (crash reporters chain the same way) always runs afterwards.
861
- static void PushyCrashRescueExceptionHandler(NSException *exception) {
869
+ static void PushyCrashHoldExceptionHandler(NSException *exception) {
862
870
  @try {
863
- PushyMaybeHoldForRescue();
871
+ PushyMaybeHoldProcess();
864
872
  } @catch (NSException *inner) {
865
873
  // The dying process owes the previous handler its turn no matter
866
874
  // what the rescue did.
@@ -870,11 +878,11 @@ static void PushyCrashRescueExceptionHandler(NSException *exception) {
870
878
  }
871
879
  }
872
880
 
873
- static void PushyInstallCrashRescueHandler(void) {
881
+ static void PushyInstallCrashHoldHandler(void) {
874
882
  static dispatch_once_t onceToken;
875
883
  dispatch_once(&onceToken, ^{
876
884
  pushyPreviousExceptionHandler = NSGetUncaughtExceptionHandler();
877
- NSSetUncaughtExceptionHandler(&PushyCrashRescueExceptionHandler);
885
+ NSSetUncaughtExceptionHandler(&PushyCrashHoldExceptionHandler);
878
886
  });
879
887
  }
880
888
 
@@ -1137,14 +1145,14 @@ RCT_EXPORT_MODULE(RCTPushy);
1137
1145
  static dispatch_queue_t hostQueue;
1138
1146
  static dispatch_once_t once;
1139
1147
  dispatch_once(&once, ^{
1140
- hostQueue = dispatch_queue_create("cn.reactnative.pushy.host-check", DISPATCH_QUEUE_SERIAL);
1148
+ hostQueue = dispatch_queue_create("cn.reactnative.pushy.host-sync", DISPATCH_QUEUE_SERIAL);
1141
1149
  });
1142
1150
  dispatch_async(hostQueue, ^{
1143
1151
  NSDictionary *result;
1144
1152
  @try {
1145
1153
  result = [RCTPushyOrchestrator prepareBundle];
1146
1154
  } @catch (NSException *exception) {
1147
- RCTLogWarn(@"RCTPushy -- native host check failed: %@", exception.reason);
1155
+ RCTLogWarn(@"RCTPushy -- native host sync failed: %@", exception.reason);
1148
1156
  result = PushyHostResult(@"failed", @"internal_error", nil, NO);
1149
1157
  }
1150
1158
  if (completion != nil) {
@@ -1286,7 +1294,7 @@ RCT_EXPORT_METHOD(markJsCheckCompleted:(NSString *)config
1286
1294
  PushyRejectError(reject, PushyErrorWithCode(pushy::error_codes::kInvalidOptions, ERROR_OPTIONS));
1287
1295
  return;
1288
1296
  }
1289
- [RCTPushyOrchestrator markJsCheckCompleted:config];
1297
+ [RCTPushyOrchestrator recordJsRound:config];
1290
1298
  resolve(@true);
1291
1299
  }
1292
1300
 
@@ -1328,21 +1336,21 @@ RCT_EXPORT_METHOD(downloadFullUpdate:(NSDictionary *)options
1328
1336
  resolver:(RCTPromiseResolveBlock)resolve
1329
1337
  rejecter:(RCTPromiseRejectBlock)reject)
1330
1338
  {
1331
- [self downloadUpdate:PushyTypeFullDownload options:options resolver:resolve rejecter:reject];
1339
+ [self fetchPackage:PushyTypeFullDownload options:options resolver:resolve rejecter:reject];
1332
1340
  }
1333
1341
 
1334
1342
  RCT_EXPORT_METHOD(downloadPatchFromPackage:(NSDictionary *)options
1335
1343
  resolver:(RCTPromiseResolveBlock)resolve
1336
1344
  rejecter:(RCTPromiseRejectBlock)reject)
1337
1345
  {
1338
- [self downloadUpdate:PushyTypePatchFromPackage options:options resolver:resolve rejecter:reject];
1346
+ [self fetchPackage:PushyTypePatchFromPackage options:options resolver:resolve rejecter:reject];
1339
1347
  }
1340
1348
 
1341
1349
  RCT_EXPORT_METHOD(downloadPatchFromPpk:(NSDictionary *)options
1342
1350
  resolver:(RCTPromiseResolveBlock)resolve
1343
1351
  rejecter:(RCTPromiseRejectBlock)reject)
1344
1352
  {
1345
- [self downloadUpdate:PushyTypePatchFromPpk options:options resolver:resolve rejecter:reject];
1353
+ [self fetchPackage:PushyTypePatchFromPpk options:options resolver:resolve rejecter:reject];
1346
1354
  }
1347
1355
 
1348
1356
  RCT_EXPORT_METHOD(downloadAndInstallApk:(NSDictionary *)options
@@ -1377,7 +1385,7 @@ RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
1377
1385
  return;
1378
1386
  }
1379
1387
 
1380
- NSError *reloadError = [self reloadBridgeWithReason:@"pushy reloadUpdate"];
1388
+ NSError *reloadError = [self restartBridgeWithReason:@"pushy restart"];
1381
1389
  if (reloadError != nil) {
1382
1390
  PushyRejectError(reject, reloadError);
1383
1391
  return;
@@ -1388,7 +1396,7 @@ RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
1388
1396
  RCT_EXPORT_METHOD(restartApp:(RCTPromiseResolveBlock)resolve
1389
1397
  rejecter:(RCTPromiseRejectBlock)reject)
1390
1398
  {
1391
- NSError *reloadError = [self reloadBridgeWithReason:@"pushy restartApp"];
1399
+ NSError *reloadError = [self restartBridgeWithReason:@"pushy restartApp"];
1392
1400
  if (reloadError != nil) {
1393
1401
  PushyRejectError(reject, reloadError);
1394
1402
  return;
@@ -1499,7 +1507,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1499
1507
  // promise settles here, after the cleanup, so a failed wipe reaches
1500
1508
  // JS as RESET_FAILED (Android parity) instead of a warning nobody
1501
1509
  // aggregates.
1502
- pushy::patch::Status status = pushy::patch::CleanupOldEntries(
1510
+ pushy::delta::Status status = pushy::delta::CleanupOldEntries(
1503
1511
  PushyToStdString([RCTPushy downloadDir]),
1504
1512
  std::vector<std::string>{PushyToStdString(keepVersion)},
1505
1513
  0
@@ -1533,12 +1541,12 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1533
1541
  hasListeners = NO;
1534
1542
  }
1535
1543
 
1536
- - (void)downloadUpdate:(PushyType)type
1544
+ - (void)fetchPackage:(PushyType)type
1537
1545
  options:(NSDictionary *)options
1538
1546
  resolver:(RCTPromiseResolveBlock)resolve
1539
1547
  rejecter:(RCTPromiseRejectBlock)reject
1540
1548
  {
1541
- [self performUpdate:type options:options callback:^(NSError *error) {
1549
+ [self performFetch:type options:options callback:^(NSError *error) {
1542
1550
  if (error != nil) {
1543
1551
  if (error.userInfo[PushyErrorCodeKey] == nil) {
1544
1552
  // Unclassified (system/network) errors from the download
@@ -1560,7 +1568,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1560
1568
  // here: it consumes one-shot launch state (first_time, the first-load mark,
1561
1569
  // ignoreRollback), and consuming it for a reload that never happens would
1562
1570
  // make the next cold start roll the freshly switched version back.
1563
- - (NSError *)reloadBridgeWithReason:(NSString *)reason
1571
+ - (NSError *)restartBridgeWithReason:(NSString *)reason
1564
1572
  {
1565
1573
  #if PUSHY_HAS_RELOAD_COMMAND
1566
1574
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -1575,7 +1583,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1575
1583
  RCTBridge *bridge = self.bridge;
1576
1584
  if (bridge == nil || object_getClass(bridge) == NSClassFromString(@"RCTBridgeProxy")) {
1577
1585
  return PushyErrorWithCode(pushy::error_codes::kRestartFailed,
1578
- @"no bridge available to reload (bridgeless host without RCTReloadCommand)");
1586
+ @"no bridge available to restart (bridgeless host without the RN restart command)");
1579
1587
  }
1580
1588
  dispatch_async(dispatch_get_main_queue(), ^{
1581
1589
  [bridge reload];
@@ -1584,9 +1592,9 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1584
1592
  #endif
1585
1593
  }
1586
1594
 
1587
- - (void)performUpdate:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
1595
+ - (void)performFetch:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
1588
1596
  {
1589
- NSString *updateUrl = PushyOptionString(options, @"updateUrl");
1597
+ NSString *updateUrl = PushyOptionString(options, PushyOptionUrlKey);
1590
1598
  NSString *hash = PushyOptionString(options, @"hash");
1591
1599
 
1592
1600
  if (PushyStringIsBlank(updateUrl) || !PushyIsSafePathComponent(hash)) {
@@ -1632,7 +1640,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1632
1640
  }
1633
1641
  };
1634
1642
  void (^deferredStart)(void) = ^{
1635
- [self performUpdate:type options:options callback:callback];
1643
+ [self performFetch:type options:options callback:callback];
1636
1644
  };
1637
1645
  PushyDownloadRegistration registration = PushyRegisterDownload(
1638
1646
  hash, type, deadlineUptime, callback, progress, deferredStart);
@@ -1669,7 +1677,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1669
1677
  // version directory in one atomic step.
1670
1678
  NSString *bundlePath = [staging stringByAppendingPathComponent:BUNDLE_FILE_NAME];
1671
1679
  if (![fileManager fileExistsAtPath:bundlePath]) {
1672
- finalError = PushyErrorWithCode(pushy::error_codes::kPatchFailed,
1680
+ finalError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
1673
1681
  @"bundle missing after install");
1674
1682
  } else {
1675
1683
  std::string bundleSha256 = pushy::digest::Sha256File(PushyToStdString(bundlePath));
@@ -1768,8 +1776,8 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1768
1776
  } @catch (NSException *exception) {
1769
1777
  // An uncaught exception in a GCD block is fatal (and would
1770
1778
  // trip the crash rescue); a bad package is a PATCH_FAILED.
1771
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed,
1772
- exception.reason ?: @"patch failed"));
1779
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
1780
+ exception.reason ?: @"delta failed"));
1773
1781
  }
1774
1782
  });
1775
1783
  }];
@@ -1782,7 +1790,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1782
1790
  {
1783
1791
  switch (type) {
1784
1792
  case PushyTypePatchFromPackage:
1785
- [self applyPatchForHash:hash
1793
+ [self applyDeltaForHash:hash
1786
1794
  type:type
1787
1795
  fromBundle:[[RCTPushy binaryBundleURL] path]
1788
1796
  source:[[NSBundle mainBundle] resourcePath]
@@ -1790,7 +1798,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1790
1798
  return;
1791
1799
  case PushyTypePatchFromPpk: {
1792
1800
  NSString *lastVersionDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:originHash];
1793
- [self applyPatchForHash:hash
1801
+ [self applyDeltaForHash:hash
1794
1802
  type:type
1795
1803
  fromBundle:[lastVersionDir stringByAppendingPathComponent:BUNDLE_FILE_NAME]
1796
1804
  source:lastVersionDir
@@ -1803,7 +1811,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1803
1811
  }
1804
1812
  }
1805
1813
 
1806
- - (void)applyPatchForHash:(NSString *)hash
1814
+ - (void)applyDeltaForHash:(NSString *)hash
1807
1815
  type:(PushyType)type
1808
1816
  fromBundle:(NSString *)bundleOrigin
1809
1817
  source:(NSString *)sourceOrigin
@@ -1818,13 +1826,13 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1818
1826
  NSString *destination = [unzipDir stringByAppendingPathComponent:BUNDLE_FILE_NAME];
1819
1827
  long long manifestBytes = RCTPushyFileSize(sourcePatch);
1820
1828
  if (manifestBytes > pushy::archive_limits::kMaxManifestBytes) {
1821
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed,
1822
- [NSString stringWithFormat:@"patch manifest too large: %lld bytes", manifestBytes]));
1829
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
1830
+ [NSString stringWithFormat:@"delta manifest too large: %lld bytes", manifestBytes]));
1823
1831
  return;
1824
1832
  }
1825
1833
  NSData *data = [NSData dataWithContentsOfFile:sourcePatch];
1826
1834
  if (data == nil) {
1827
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed, @"missing patch manifest"));
1835
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, @"missing delta manifest"));
1828
1836
  return;
1829
1837
  }
1830
1838
 
@@ -1833,19 +1841,19 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1833
1841
  if (error != nil) {
1834
1842
  // Classify as a patch failure like the sibling manifest branches;
1835
1843
  // 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));
1844
+ // fetchPackage fallback even though the download itself succeeded.
1845
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, error.localizedDescription));
1838
1846
  return;
1839
1847
  }
1840
1848
  if (![jsonObject isKindOfClass:[NSDictionary class]]) {
1841
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed, @"invalid patch manifest"));
1849
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, @"invalid delta manifest"));
1842
1850
  return;
1843
1851
  }
1844
1852
  NSDictionary *json = (NSDictionary *)jsonObject;
1845
- pushy::patch::PatchManifest manifest;
1853
+ pushy::delta::PatchManifest manifest;
1846
1854
  NSString *manifestReason = nil;
1847
1855
  if (!PushyPatchManifestFromJson(json, &manifest, &manifestReason)) {
1848
- callback(PushyErrorWithCode(pushy::error_codes::kPatchFailed, manifestReason));
1856
+ callback(PushyErrorWithCode(pushy::error_codes::kDeltaFailed, manifestReason));
1849
1857
  return;
1850
1858
  }
1851
1859
 
@@ -1858,7 +1866,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1858
1866
  }
1859
1867
 
1860
1868
  pushy::archive_patch::ArchivePatchPlan plan;
1861
- pushy::patch::Status planStatus = pushy::archive_patch::BuildArchivePatchPlan(
1869
+ pushy::delta::Status planStatus = pushy::archive_patch::BuildArchivePatchPlan(
1862
1870
  type == PushyTypePatchFromPackage
1863
1871
  ? pushy::archive_patch::ArchivePatchType::kPatchFromPackage
1864
1872
  : pushy::archive_patch::ArchivePatchType::kPatchFromPpk,
@@ -1871,8 +1879,8 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1871
1879
  return;
1872
1880
  }
1873
1881
 
1874
- pushy::patch::FileSourcePatchOptions options;
1875
- pushy::patch::Status optionStatus = pushy::archive_patch::BuildFileSourcePatchOptions(
1882
+ pushy::delta::FileSourcePatchOptions options;
1883
+ pushy::delta::Status optionStatus = pushy::archive_patch::BuildFileSourcePatchOptions(
1876
1884
  plan,
1877
1885
  PushyToStdString(sourceOrigin),
1878
1886
  PushyToStdString(unzipDir),
@@ -1901,7 +1909,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
1901
1909
  }
1902
1910
  }
1903
1911
 
1904
- pushy::patch::Status status = pushy::patch::ApplyPatchFromFileSource(options);
1912
+ pushy::delta::Status status = pushy::delta::ApplyPatchFromFileSource(options);
1905
1913
  if (!status.ok) {
1906
1914
  callback(PushyNSErrorFromStatus(status));
1907
1915
  return;
@@ -2025,7 +2033,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2025
2033
  long long archiveBytes = RCTPushyFileSize(path);
2026
2034
  NSError *preflight = nil;
2027
2035
  if (archiveBytes > pushy::archive_limits::kMaxArchiveBytes) {
2028
- preflight = PushyErrorWithCode(pushy::error_codes::kPatchFailed,
2036
+ preflight = PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
2029
2037
  [NSString stringWithFormat:@"archive too large: %lld bytes", archiveBytes]);
2030
2038
  } else {
2031
2039
  preflight = PushyEnsureFreeSpace(destination, MAX(0LL, archiveBytes) * 2);
@@ -2063,15 +2071,15 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2063
2071
 
2064
2072
  NSError *unzipError = error;
2065
2073
  if (guard.violation != nil) {
2066
- unzipError = PushyErrorWithCode(pushy::error_codes::kPatchFailed, guard.violation);
2074
+ unzipError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed, guard.violation);
2067
2075
  } else if (!succeeded && unzipError == nil) {
2068
- unzipError = PushyErrorWithCode(pushy::error_codes::kPatchFailed, @"unzip failed");
2076
+ unzipError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed, @"unzip failed");
2069
2077
  } else if (unzipError != nil && unzipError.userInfo[PushyErrorCodeKey] == nil) {
2070
2078
  // SSZipArchive's own NSError (corrupt zip, bad magic, ...) has
2071
- // no stable code; without one, downloadUpdate's fallback would
2079
+ // no stable code; without one, fetchPackage's fallback would
2072
2080
  // classify it as DOWNLOAD_FAILED even though the download
2073
2081
  // succeeded — keep the classification deterministic.
2074
- unzipError = PushyErrorWithCode(pushy::error_codes::kPatchFailed,
2082
+ unzipError = PushyErrorWithCode(pushy::error_codes::kDeltaFailed,
2075
2083
  unzipError.localizedDescription ?: @"unzip failed");
2076
2084
  }
2077
2085
  completionHandler(unzipError);
@@ -2095,7 +2103,7 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2095
2103
  // process booted from: two switches without a restart would otherwise
2096
2104
  // evict the running bundle while its on-demand assets are still
2097
2105
  // being served.
2098
- pushy::patch::Status status = pushy::patch::CleanupOldEntries(
2106
+ pushy::delta::Status status = pushy::delta::CleanupOldEntries(
2099
2107
  PushyToStdString(downloadDir),
2100
2108
  std::vector<std::string>{
2101
2109
  state.current_version,
@@ -2114,9 +2122,9 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2114
2122
  {
2115
2123
  switch (type) {
2116
2124
  case PushyTypePatchFromPackage:
2117
- return @".ipa.patch";
2125
+ return PushyIpaDeltaSuffix;
2118
2126
  case PushyTypePatchFromPpk:
2119
- return @".ppk.patch";
2127
+ return PushyPpkDeltaSuffix;
2120
2128
  case PushyTypeFullDownload:
2121
2129
  break;
2122
2130
  }
@@ -2210,10 +2218,10 @@ RCT_EXPORT_METHOD(resetToPackagedBundle:(RCTPromiseResolveBlock)resolve
2210
2218
  // NSAllowsArbitraryLoads. Same rule as RCTPushyDownloader. Returning nil
2211
2219
  // delivers the 3xx itself as the final response, which the status check in
2212
2220
  // PushyHttpRequest then treats as a failed endpoint.
2213
- @interface PushyCheckRequestRedirectGuard : NSObject <NSURLSessionTaskDelegate>
2221
+ @interface PushyRequestRedirectGuard : NSObject <NSURLSessionTaskDelegate>
2214
2222
  @end
2215
2223
 
2216
- @implementation PushyCheckRequestRedirectGuard
2224
+ @implementation PushyRequestRedirectGuard
2217
2225
 
2218
2226
  - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
2219
2227
  willPerformHTTPRedirection:(NSHTTPURLResponse *)response
@@ -2255,7 +2263,7 @@ static NSString *PushyHttpRequest(NSString *urlString, NSString *method,
2255
2263
  // final response.
2256
2264
  NSURLSession *session = [NSURLSession
2257
2265
  sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
2258
- delegate:[PushyCheckRequestRedirectGuard new]
2266
+ delegate:[PushyRequestRedirectGuard new]
2259
2267
  delegateQueue:nil];
2260
2268
  NSURLSessionDataTask *task = [session dataTaskWithRequest:request
2261
2269
  completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
@@ -2290,13 +2298,13 @@ static NSString *PushyNormalizeEndpointBase(NSString *base) {
2290
2298
  return base;
2291
2299
  }
2292
2300
 
2293
- static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2301
+ static BOOL PushyIsValidResponse(NSString *responseText) {
2294
2302
  if (responseText == nil) {
2295
2303
  return NO;
2296
2304
  }
2297
- // Shared schema rule (update_flow_core::IsValidCheckResponse): a 200 with
2305
+ // Shared schema rule (update_flow_core::IsValidResponse): a 200 with
2298
2306
  // `{"error": ...}` is a failed endpoint, not a verdict.
2299
- return updateflow::IsValidCheckResponse(PushyToStdString(responseText)) ? YES : NO;
2307
+ return flowcore::IsValidResponse(PushyToStdString(responseText)) ? YES : NO;
2300
2308
  }
2301
2309
 
2302
2310
  @implementation RCTPushyOrchestrator
@@ -2316,10 +2324,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2316
2324
  pushyNativeConfigGeneration.fetch_add(1);
2317
2325
  [defaults setObject:config forKey:keyNativeConfig];
2318
2326
  [defaults removeObjectForKey:keyNativeCheckCache];
2319
- [self markJsCheckCompleted:nil];
2327
+ [self recordJsRound:nil];
2320
2328
  });
2321
- if (pushyNativeCheckReady.load() && [self hasRunnableConfig]) {
2322
- PushyInstallCrashRescueHandler();
2329
+ if (pushySyncReady.load() && [self hasRunnableConfig]) {
2330
+ PushyInstallCrashHoldHandler();
2323
2331
  }
2324
2332
  }
2325
2333
 
@@ -2343,12 +2351,12 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2343
2351
  pushyHostRoundGroup = dispatch_group_create();
2344
2352
  dispatch_group_enter(pushyHostRoundGroup);
2345
2353
  pushyProcessAnchorUptime = PushyMonotonicNow();
2346
- pushyLaunchRolledBackForRescue = [launchRolledBackVersion copy];
2347
- pushyNativeCheckReady.store(true);
2354
+ pushyLaunchRolledBackForHold = [launchRolledBackVersion copy];
2355
+ pushySyncReady.store(true);
2348
2356
  // The crash-hold rescue shares the orchestrator's rollout gate: no
2349
2357
  // persisted config, no handler (§11.3).
2350
2358
  if ([PushyDefaults() stringForKey:keyNativeConfig].length > 0) {
2351
- PushyInstallCrashRescueHandler();
2359
+ PushyInstallCrashHoldHandler();
2352
2360
  }
2353
2361
  });
2354
2362
  }
@@ -2367,10 +2375,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2367
2375
  [defaults objectForKey:keyNativeCheckIncomplete] != nil ? 0 : 5;
2368
2376
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delaySeconds * NSEC_PER_SEC),
2369
2377
  dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
2370
- if ([self isJsCheckCompleted]) {
2378
+ if ([self hasJsRound]) {
2371
2379
  // Not consuming the round: a later crash rescue may still
2372
2380
  // need it.
2373
- NSLog(@"RCTPushy -- native check skipped: JS check completed in this process");
2381
+ NSLog(@"RCTPushy -- native sync skipped: JS already queried in this process");
2374
2382
  return;
2375
2383
  }
2376
2384
  [self startRoundWithDeadline:0];
@@ -2392,7 +2400,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2392
2400
  rolledBack:(NSString *)launchRolledBackVersion {
2393
2401
  [self prepareProcess:launchRolledBackVersion];
2394
2402
  if (![self hasRunnableConfig]) {
2395
- RCTLogWarn(@"RCTPushy -- version %@ was purged and no native check is "
2403
+ RCTLogWarn(@"RCTPushy -- version %@ was purged and no native sync is "
2396
2404
  @"configured; launching the packaged bundle", purgedVersion);
2397
2405
  return NO;
2398
2406
  }
@@ -2429,7 +2437,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2429
2437
  #if DEBUG
2430
2438
  return PushyHostResult(@"skipped", @"debug", nil, NO);
2431
2439
  #else
2432
- if (!pushyNativeCheckReady.load()) {
2440
+ if (!pushySyncReady.load()) {
2433
2441
  return PushyHostResult(@"skipped", @"not_initialized", nil, NO);
2434
2442
  }
2435
2443
  NSString *configJson = [PushyDefaults() stringForKey:keyNativeConfig];
@@ -2468,7 +2476,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2468
2476
  #endif
2469
2477
  }
2470
2478
 
2471
- + (void)markJsCheckCompleted:(NSString *)config {
2479
+ + (void)recordJsRound:(NSString *)config {
2472
2480
  @synchronized (RCTPushyOrchestrator.class) {
2473
2481
  pushyJsCompletedConfig = [config copy];
2474
2482
  }
@@ -2478,7 +2486,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2478
2486
  // exact config the native round would use (§10.3): the delayed round is
2479
2487
  // then a duplicate request. Only the scheduled round asks — the crash-rescue
2480
2488
  // path still runs, JS is dead by then.
2481
- + (BOOL)isJsCheckCompleted {
2489
+ + (BOOL)hasJsRound {
2482
2490
  NSString *jsConfig;
2483
2491
  @synchronized (RCTPushyOrchestrator.class) {
2484
2492
  jsConfig = pushyJsCompletedConfig;
@@ -2503,10 +2511,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2503
2511
  return;
2504
2512
  }
2505
2513
  @try {
2506
- [self runOnce:pushyLaunchRolledBackForRescue deadline:deadlineUptime];
2514
+ [self runOnce:pushyLaunchRolledBackForHold deadline:deadlineUptime];
2507
2515
  } @catch (NSException *exception) {
2508
2516
  // The rescue path must never take the app down with it.
2509
- RCTLogWarn(@"RCTPushy -- native check crashed: %@", exception.reason);
2517
+ RCTLogWarn(@"RCTPushy -- native sync crashed: %@", exception.reason);
2510
2518
  pushyHostRoundResult = PushyHostResult(@"failed", @"internal_error", nil, NO);
2511
2519
  } @finally {
2512
2520
  pushyRoundCompleted.store(true);
@@ -2520,8 +2528,8 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2520
2528
  // process's round runs to completion within the budget, then activates a
2521
2529
  // downloaded-but-unactivated version if one exists — the last chance before
2522
2530
  // the process is gone.
2523
- + (void)runRescueWithDeadline:(NSTimeInterval)deadlineUptime {
2524
- pushyCrashRescueActive.store(true);
2531
+ + (void)runHoldRoundWithDeadline:(NSTimeInterval)deadlineUptime {
2532
+ pushyCrashHoldActive.store(true);
2525
2533
  [self startRoundWithDeadline:deadlineUptime];
2526
2534
  if (pushyRoundStarted.load() && !pushyRoundCompleted.load()) {
2527
2535
  NSTimeInterval remaining = deadlineUptime - PushyMonotonicNow();
@@ -2552,7 +2560,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2552
2560
  // catch below anyway, or by cleanup).
2553
2561
  NSString *versionDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:hash];
2554
2562
  if (!PushyHasCompletedVersionAtPath(versionDir, hash)) {
2555
- NSLog(@"RCTPushy -- crash rescue: version %@ no longer on disk, dropping activation", hash);
2563
+ NSLog(@"RCTPushy -- crash hold: version %@ no longer on disk, dropping activation", hash);
2556
2564
  return;
2557
2565
  }
2558
2566
  NSDictionary *hashInfoEntry = nil;
@@ -2562,7 +2570,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2562
2570
  [NSJSONSerialization JSONObjectWithData:existingData options:0 error:nil];
2563
2571
  if ([parsed isKindOfClass:[NSDictionary class]]) {
2564
2572
  NSMutableDictionary *merged = [parsed mutableCopy];
2565
- merged[@"crashRescue"] = @YES;
2573
+ merged[PushyInfoCrashHold] = @YES;
2566
2574
  hashInfoEntry = @{@"hash": hash, @"info": merged};
2567
2575
  }
2568
2576
  BOOL committed = [self commitRoundWithGeneration:generation
@@ -2577,9 +2585,9 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2577
2585
  @synchronized (self) {
2578
2586
  pushyUnactivatedHash = nil;
2579
2587
  }
2580
- NSLog(@"RCTPushy -- crash rescue: activated downloaded version %@", hash);
2588
+ NSLog(@"RCTPushy -- crash hold: activated downloaded version %@", hash);
2581
2589
  } else {
2582
- NSLog(@"RCTPushy -- crash rescue: reset since download, dropping activation");
2590
+ NSLog(@"RCTPushy -- crash hold: reset since download, dropping activation");
2583
2591
  }
2584
2592
  }
2585
2593
 
@@ -2691,28 +2699,28 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2691
2699
  // shared with JS getBundleHash) on the ordinary delayed round.
2692
2700
  input.Set("bundleHash",
2693
2701
  flowjson::Value::String(PushyToStdString(
2694
- PushyBundleHashSync(!pushyCrashRescueActive.load()))));
2702
+ PushyBundleHashSync(!pushyCrashHoldActive.load()))));
2695
2703
 
2696
2704
  std::string bodyJson =
2697
- flowjson::Stringify(updateflow::BuildCheckRequestBody(input));
2705
+ flowjson::Stringify(flowcore::BuildRequestBody(input));
2698
2706
  NSString *body = [NSString stringWithUTF8String:bodyJson.c_str()];
2699
2707
  if (body == nil) {
2700
- RCTLogWarn(@"RCTPushy -- native check: request body is not valid UTF-8");
2708
+ RCTLogWarn(@"RCTPushy -- native sync: request body is not valid UTF-8");
2701
2709
  pushyHostRoundResult = PushyHostResult(@"failed", @"invalid_request", nil, NO);
2702
2710
  return;
2703
2711
  }
2704
2712
 
2705
- NSString *responseText = [self runCheckRequest:config
2713
+ NSString *responseText = [self runQueryRequest:config
2706
2714
  appKey:appKey
2707
2715
  body:body
2708
2716
  deadline:deadlineUptime];
2709
2717
  if (responseText == nil) {
2710
- RCTLogInfo(@"RCTPushy -- native check: no endpoint reachable, giving up until next launch");
2718
+ RCTLogInfo(@"RCTPushy -- native sync: no endpoint reachable, giving up until next launch");
2711
2719
  return;
2712
2720
  }
2713
2721
  long long responseAtSeconds = (long long)[[NSDate date] timeIntervalSince1970];
2714
2722
 
2715
- flowjson::Value decision = updateflow::HandleCheckResponse(
2723
+ flowjson::Value decision = flowcore::HandleResponse(
2716
2724
  PushyToStdString(responseText), identity, false,
2717
2725
  config.Get("afterDownload").AsString());
2718
2726
  if (decision.Get("action").AsString() != "download") {
@@ -2725,9 +2733,9 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2725
2733
  responseAt:responseAtSeconds
2726
2734
  activated:NULL];
2727
2735
  pushyHostRoundResult = committed
2728
- ? PushyHostResult(@"noUpdate", PushyFromStdString(decision.Get("reason").AsString()), nil, NO)
2736
+ ? PushyHostResult(PushyStatusNone, PushyFromStdString(decision.Get("reason").AsString()), nil, NO)
2729
2737
  : PushyHostResult(@"cancelled", @"reset", nil, NO);
2730
- RCTLogInfo(@"RCTPushy -- native check: nothing to do (%s)",
2738
+ RCTLogInfo(@"RCTPushy -- native sync: nothing to do (%s)",
2731
2739
  decision.Get("reason").AsString().c_str());
2732
2740
  return;
2733
2741
  }
@@ -2774,10 +2782,10 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2774
2782
  // survives to markSuccess. Only the server-sent directive counts — a
2775
2783
  // silent-strategy activation is ordinary delivery.
2776
2784
  if (info.Get("config").Get("forceBoot").Truthy()) {
2777
- versionInfo[@"forceBootRescue"] = @YES;
2785
+ versionInfo[PushyInfoForceBoot] = @YES;
2778
2786
  }
2779
- if (pushyCrashRescueActive.load()) {
2780
- versionInfo[@"crashRescue"] = @YES;
2787
+ if (pushyCrashHoldActive.load()) {
2788
+ versionInfo[PushyInfoCrashHold] = @YES;
2781
2789
  }
2782
2790
  // Silent strategies or a server-marked forceBoot version (per-version
2783
2791
  // remote override — the brick rescue) activate for the next launch;
@@ -2786,7 +2794,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2786
2794
  // forever (§11.3). Or the launch is blocked on reinstalling a version
2787
2795
  // tvOS purged: JS has not started, and the whole point is to boot it —
2788
2796
  // commitRoundWithGeneration drops that one once the restore window closed.
2789
- BOOL activate = decision.Get("activate").Truthy() || pushyCrashRescueActive.load()
2797
+ BOOL activate = decision.Get("activate").Truthy() || pushyCrashHoldActive.load()
2790
2798
  || pushyPurgeRestoreActive.load();
2791
2799
  BOOL activated = NO;
2792
2800
  BOOL committed = [self commitRoundWithGeneration:resetGeneration
@@ -2799,12 +2807,12 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2799
2807
  activated:&activated];
2800
2808
  activate = activated;
2801
2809
  if (!committed) {
2802
- RCTLogInfo(@"RCTPushy -- native check: reset during round, dropping result");
2810
+ RCTLogInfo(@"RCTPushy -- native sync: reset during round, dropping result");
2803
2811
  } else if (activate) {
2804
2812
  @synchronized (self) {
2805
2813
  pushyUnactivatedHash = nil;
2806
2814
  }
2807
- RCTLogInfo(@"RCTPushy -- native check: downloaded %@ and set for next launch", hash);
2815
+ RCTLogInfo(@"RCTPushy -- native sync: downloaded %@ and set for next launch", hash);
2808
2816
  } else {
2809
2817
  // Remembered so a crash later in this process can still activate it
2810
2818
  // (activatePendingVersion) — JS never will.
@@ -2812,7 +2820,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2812
2820
  pushyUnactivatedHash = [hash copy];
2813
2821
  pushyUnactivatedGeneration = resetGeneration;
2814
2822
  }
2815
- RCTLogInfo(@"RCTPushy -- native check: downloaded %@, activation left to JS", hash);
2823
+ RCTLogInfo(@"RCTPushy -- native sync: downloaded %@, activation left to JS", hash);
2816
2824
  }
2817
2825
  pushyHostRoundResult = committed
2818
2826
  ? PushyHostResult(@"downloaded", @"", hash, activate)
@@ -2863,7 +2871,7 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2863
2871
  marked[@"purgeRestore"] = @YES;
2864
2872
  info = marked;
2865
2873
  }
2866
- } else if (!pushyCrashRescueActive.load()) {
2874
+ } else if (!pushyCrashHoldActive.load()) {
2867
2875
  activation = nil;
2868
2876
  }
2869
2877
  }
@@ -2899,20 +2907,20 @@ static BOOL PushyIsValidCheckResponse(NSString *responseText) {
2899
2907
  // more round. No hedged race on purpose — this path is latency-insensitive.
2900
2908
  // Per-request timeout, capped to the crash-rescue budget when one is active.
2901
2909
  // <= 0 means the budget is gone and the round must stop issuing requests.
2902
- static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2910
+ static NSTimeInterval PushyQueryRequestTimeout(NSTimeInterval deadlineUptime) {
2903
2911
  if (deadlineUptime <= 0) {
2904
2912
  return 10;
2905
2913
  }
2906
2914
  return MIN(10, deadlineUptime - PushyMonotonicNow());
2907
2915
  }
2908
2916
 
2909
- + (NSString *)runCheckRequest:(const flowjson::Value &)config
2917
+ + (NSString *)runQueryRequest:(const flowjson::Value &)config
2910
2918
  appKey:(NSString *)appKey
2911
2919
  body:(NSString *)body
2912
2920
  deadline:(NSTimeInterval)deadlineUptime {
2913
2921
  double sample = arc4random() / 4294967296.0;
2914
2922
  flowjson::Value ordered =
2915
- updateflow::OrderEndpointCandidates(config.Get("endpoints"), sample);
2923
+ flowcore::OrderEndpointCandidates(config.Get("endpoints"), sample);
2916
2924
  NSMutableSet<NSString *> *tried = [NSMutableSet set];
2917
2925
  const NSUInteger maxHttpAttempts = 8;
2918
2926
  NSUInteger httpAttempts = 0;
@@ -2926,14 +2934,14 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2926
2934
  return nil;
2927
2935
  }
2928
2936
  [tried addObject:base];
2929
- NSTimeInterval timeout = PushyCheckRequestTimeout(deadlineUptime);
2937
+ NSTimeInterval timeout = PushyQueryRequestTimeout(deadlineUptime);
2930
2938
  if (timeout <= 0) {
2931
2939
  return nil;
2932
2940
  }
2933
2941
  NSString *response = PushyHttpRequest(
2934
- [NSString stringWithFormat:@"%@/checkUpdate/%@", base, appKey],
2942
+ [NSString stringWithFormat:@"%@%@%@", base, RCTPushyQueryPath(), appKey],
2935
2943
  @"POST", body, timeout);
2936
- if (PushyIsValidCheckResponse(response)) {
2944
+ if (PushyIsValidResponse(response)) {
2937
2945
  return response;
2938
2946
  }
2939
2947
  }
@@ -2945,7 +2953,7 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2945
2953
  if (httpAttempts++ >= maxHttpAttempts) {
2946
2954
  return nil;
2947
2955
  }
2948
- NSTimeInterval listTimeout = PushyCheckRequestTimeout(deadlineUptime);
2956
+ NSTimeInterval listTimeout = PushyQueryRequestTimeout(deadlineUptime);
2949
2957
  if (listTimeout <= 0) {
2950
2958
  return nil;
2951
2959
  }
@@ -2968,14 +2976,14 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2968
2976
  return nil;
2969
2977
  }
2970
2978
  [tried addObject:base];
2971
- NSTimeInterval timeout = PushyCheckRequestTimeout(deadlineUptime);
2979
+ NSTimeInterval timeout = PushyQueryRequestTimeout(deadlineUptime);
2972
2980
  if (timeout <= 0) {
2973
2981
  return nil;
2974
2982
  }
2975
2983
  NSString *response = PushyHttpRequest(
2976
- [NSString stringWithFormat:@"%@/checkUpdate/%@", base, appKey],
2984
+ [NSString stringWithFormat:@"%@%@%@", base, RCTPushyQueryPath(), appKey],
2977
2985
  @"POST", body, timeout);
2978
- if (PushyIsValidCheckResponse(response)) {
2986
+ if (PushyIsValidResponse(response)) {
2979
2987
  return response;
2980
2988
  }
2981
2989
  }
@@ -2987,12 +2995,12 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
2987
2995
  + (BOOL)performAttempts:(const flowjson::Value &)attempts
2988
2996
  hash:(NSString *)hash
2989
2997
  originHash:(NSString *)originHash
2990
- deadline:(NSTimeInterval)rescueDeadline {
2998
+ deadline:(NSTimeInterval)holdDeadline {
2991
2999
  RCTPushy *engine = [self engine];
2992
3000
  // Crash-rescue budget caps every phase; 0 keeps the normal 10min windows.
2993
3001
  NSTimeInterval incrementalDeadline = PushyMonotonicNow() + 600;
2994
- if (rescueDeadline > 0) {
2995
- incrementalDeadline = MIN(incrementalDeadline, rescueDeadline);
3002
+ if (holdDeadline > 0) {
3003
+ incrementalDeadline = MIN(incrementalDeadline, holdDeadline);
2996
3004
  }
2997
3005
  NSTimeInterval fullDeadline = 0;
2998
3006
  for (const auto &attempt : attempts.elements()) {
@@ -3007,8 +3015,8 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3007
3015
  if (isFullAttempt && fullDeadline == 0) {
3008
3016
  // diff/pdiff cannot starve the last-resort full download.
3009
3017
  fullDeadline = PushyMonotonicNow() + 600;
3010
- if (rescueDeadline > 0) {
3011
- fullDeadline = MIN(fullDeadline, rescueDeadline);
3018
+ if (holdDeadline > 0) {
3019
+ fullDeadline = MIN(fullDeadline, holdDeadline);
3012
3020
  }
3013
3021
  }
3014
3022
  NSTimeInterval deadline = isFullAttempt ? fullDeadline : incrementalDeadline;
@@ -3026,7 +3034,7 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3026
3034
  }
3027
3035
  NSMutableDictionary *options =
3028
3036
  [@{
3029
- @"updateUrl": url,
3037
+ PushyOptionUrlKey: url,
3030
3038
  @"hash": hash,
3031
3039
  @"deadlineUptime": @(deadline),
3032
3040
  } mutableCopy];
@@ -3035,13 +3043,13 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3035
3043
  }
3036
3044
  dispatch_semaphore_t sem = dispatch_semaphore_create(0);
3037
3045
  __block NSError *resultError = nil;
3038
- [engine performUpdate:pushyType options:options callback:^(NSError *error) {
3046
+ [engine performFetch:pushyType options:options callback:^(NSError *error) {
3039
3047
  resultError = error;
3040
3048
  dispatch_semaphore_signal(sem);
3041
3049
  }];
3042
3050
  if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW,
3043
3051
  (int64_t)(remaining * NSEC_PER_SEC))) != 0) {
3044
- RCTLogWarn(@"RCTPushy -- native check: %s attempt timed out", type.c_str());
3052
+ RCTLogWarn(@"RCTPushy -- native sync: %s attempt timed out", type.c_str());
3045
3053
  if (isFullAttempt) {
3046
3054
  return NO;
3047
3055
  }
@@ -3050,7 +3058,7 @@ static NSTimeInterval PushyCheckRequestTimeout(NSTimeInterval deadlineUptime) {
3050
3058
  if (resultError == nil) {
3051
3059
  return YES;
3052
3060
  }
3053
- RCTLogInfo(@"RCTPushy -- native check: %s attempt failed: %@",
3061
+ RCTLogInfo(@"RCTPushy -- native sync: %s attempt failed: %@",
3054
3062
  type.c_str(), resultError.localizedDescription);
3055
3063
  }
3056
3064
  }