pulse-updates 1.0.0

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 (524) hide show
  1. package/README.md +333 -0
  2. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/results.bin +1 -0
  3. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/AssetModel.dex +0 -0
  4. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/BuildConfig.dex +0 -0
  5. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/BundleModel.dex +0 -0
  6. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/CheckResult.dex +0 -0
  7. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/FetchResult.dex +0 -0
  8. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/ManifestModel$Companion.dex +0 -0
  9. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/ManifestModel.dex +0 -0
  10. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseController$Companion.dex +0 -0
  11. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseController$Delegate.dex +0 -0
  12. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseController$errorRecoveryDelegate$1.dex +0 -0
  13. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseController.dex +0 -0
  14. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseControllerKt.dex +0 -0
  15. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseIntegrityCheck.dex +0 -0
  16. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseReactHostDelegate.dex +0 -0
  17. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseReactHostFactory.dex +0 -0
  18. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseReaper.dex +0 -0
  19. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseRemoteLoader.dex +0 -0
  20. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseUpdatesConfig.dex +0 -0
  21. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseUpdatesException.dex +0 -0
  22. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseUpdatesModule$Companion.dex +0 -0
  23. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseUpdatesModule.dex +0 -0
  24. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/PulseUpdatesPackage.dex +0 -0
  25. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/SignatureModel.dex +0 -0
  26. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/UiThreadUtil.dex +0 -0
  27. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/database/PulseAsset.dex +0 -0
  28. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/database/PulseDatabase.dex +0 -0
  29. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/database/PulseDatabaseSchema.dex +0 -0
  30. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/database/PulseUpdate.dex +0 -0
  31. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/database/PulseUpdateStatus$Companion.dex +0 -0
  32. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/database/PulseUpdateStatus.dex +0 -0
  33. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecovery$Companion.dex +0 -0
  34. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecovery.dex +0 -0
  35. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$LauncherCallback.dex +0 -0
  36. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$RemoteLoadStatus.dex +0 -0
  37. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate.dex +0 -0
  38. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Companion.dex +0 -0
  39. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$MessageType.dex +0 -0
  40. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Task.dex +0 -0
  41. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$WhenMappings.dex +0 -0
  42. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$tryRelaunchFromCache$1.dex +0 -0
  43. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler.dex +0 -0
  44. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/EmbeddedAsset$Companion.dex +0 -0
  45. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/EmbeddedAsset.dex +0 -0
  46. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/EmbeddedManifest$Companion.dex +0 -0
  47. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/EmbeddedManifest.dex +0 -0
  48. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/LauncherException.dex +0 -0
  49. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/PulseAppLauncher$Companion.dex +0 -0
  50. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/PulseAppLauncher.dex +0 -0
  51. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/PulseDefaultSelectionPolicy.dex +0 -0
  52. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/PulseSelectionPolicy.dex +0 -0
  53. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/app/pulse/updates/launcher/PulseUpdateInfo.dex +0 -0
  54. package/android/build/.transforms/051997ae5715069c07acae848c6dd9c5/transformed/bundleLibRuntimeToDirRelease/desugar_graph.bin +0 -0
  55. package/android/build/.transforms/1a2af57545c1657f87f3de30891a3470/results.bin +1 -0
  56. package/android/build/.transforms/1a2af57545c1657f87f3de30891a3470/transformed/classes/classes_dex/classes.dex +0 -0
  57. package/android/build/generated/source/buildConfig/debug/app/pulse/updates/BuildConfig.java +10 -0
  58. package/android/build/generated/source/buildConfig/release/app/pulse/updates/BuildConfig.java +10 -0
  59. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +9 -0
  60. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +18 -0
  61. package/android/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/AndroidManifest.xml +9 -0
  62. package/android/build/intermediates/aapt_friendly_merged_manifests/release/processReleaseManifest/aapt/output-metadata.json +18 -0
  63. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +6 -0
  64. package/android/build/intermediates/aar_metadata/release/writeReleaseAarMetadata/aar-metadata.properties +6 -0
  65. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +1 -0
  66. package/android/build/intermediates/annotation_processor_list/release/javaPreCompileRelease/annotationProcessors.json +1 -0
  67. package/android/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar +0 -0
  68. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  69. package/android/build/intermediates/compile_r_class_jar/release/generateReleaseRFile/R.jar +0 -0
  70. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
  71. package/android/build/intermediates/compile_symbol_list/release/generateReleaseRFile/R.txt +0 -0
  72. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
  73. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
  74. package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +2 -0
  75. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
  76. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
  77. package/android/build/intermediates/incremental/mergeReleaseAssets/merger.xml +2 -0
  78. package/android/build/intermediates/incremental/mergeReleaseJniLibFolders/merger.xml +2 -0
  79. package/android/build/intermediates/incremental/mergeReleaseShaders/merger.xml +2 -0
  80. package/android/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties +1 -0
  81. package/android/build/intermediates/incremental/release/packageReleaseResources/merger.xml +2 -0
  82. package/android/build/intermediates/java_res/release/processReleaseJavaRes/out/META-INF/pulse-updates_release.kotlin_module +0 -0
  83. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/app/pulse/updates/BuildConfig.class +0 -0
  84. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +2 -0
  85. package/android/build/intermediates/local_only_symbol_list/release/parseReleaseLocalResources/R-def.txt +2 -0
  86. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +11 -0
  87. package/android/build/intermediates/manifest_merge_blame_file/release/processReleaseManifest/manifest-merger-blame-release-report.txt +11 -0
  88. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +9 -0
  89. package/android/build/intermediates/merged_manifest/release/processReleaseManifest/AndroidManifest.xml +9 -0
  90. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +1 -0
  91. package/android/build/intermediates/navigation_json/release/extractDeepLinksRelease/navigation.json +1 -0
  92. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +1 -0
  93. package/android/build/intermediates/nested_resources_validation_report/release/generateReleaseResources/nestedResourcesValidationReport.txt +1 -0
  94. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/META-INF/pulse-updates_release.kotlin_module +0 -0
  95. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/AssetModel.class +0 -0
  96. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/BuildConfig.class +0 -0
  97. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/BundleModel.class +0 -0
  98. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/CheckResult.class +0 -0
  99. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/FetchResult.class +0 -0
  100. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/ManifestModel$Companion.class +0 -0
  101. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/ManifestModel.class +0 -0
  102. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseController$Companion.class +0 -0
  103. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseController$Delegate.class +0 -0
  104. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseController$errorRecoveryDelegate$1.class +0 -0
  105. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseController.class +0 -0
  106. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseControllerKt.class +0 -0
  107. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseIntegrityCheck.class +0 -0
  108. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseReactHostDelegate.class +0 -0
  109. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseReactHostFactory.class +0 -0
  110. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseReaper.class +0 -0
  111. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseRemoteLoader.class +0 -0
  112. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseUpdatesConfig.class +0 -0
  113. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseUpdatesException.class +0 -0
  114. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseUpdatesModule$Companion.class +0 -0
  115. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseUpdatesModule.class +0 -0
  116. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/PulseUpdatesPackage.class +0 -0
  117. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/SignatureModel.class +0 -0
  118. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/UiThreadUtil.class +0 -0
  119. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/database/PulseAsset.class +0 -0
  120. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/database/PulseDatabase.class +0 -0
  121. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/database/PulseDatabaseSchema.class +0 -0
  122. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/database/PulseUpdate.class +0 -0
  123. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/database/PulseUpdateStatus$Companion.class +0 -0
  124. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/database/PulseUpdateStatus.class +0 -0
  125. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecovery$Companion.class +0 -0
  126. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecovery.class +0 -0
  127. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$LauncherCallback.class +0 -0
  128. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$RemoteLoadStatus.class +0 -0
  129. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate.class +0 -0
  130. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Companion.class +0 -0
  131. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$MessageType.class +0 -0
  132. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Task.class +0 -0
  133. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$WhenMappings.class +0 -0
  134. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$tryRelaunchFromCache$1.class +0 -0
  135. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler.class +0 -0
  136. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/EmbeddedAsset$Companion.class +0 -0
  137. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/EmbeddedAsset.class +0 -0
  138. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/EmbeddedManifest$Companion.class +0 -0
  139. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/EmbeddedManifest.class +0 -0
  140. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/LauncherException.class +0 -0
  141. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/PulseAppLauncher$Companion.class +0 -0
  142. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/PulseAppLauncher.class +0 -0
  143. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/PulseDefaultSelectionPolicy.class +0 -0
  144. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/PulseSelectionPolicy.class +0 -0
  145. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/app/pulse/updates/launcher/PulseUpdateInfo.class +0 -0
  146. package/android/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar +0 -0
  147. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +1 -0
  148. package/android/build/intermediates/symbol_list_with_package_name/release/generateReleaseRFile/package-aware-r.txt +1 -0
  149. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  150. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  151. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  152. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  153. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  154. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  155. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
  156. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  157. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  158. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  159. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  160. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  161. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  162. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
  163. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  164. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  165. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  166. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  167. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  168. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  169. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
  170. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  171. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
  172. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
  173. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
  174. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  175. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
  176. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
  177. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  178. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  179. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  180. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  181. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  182. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  183. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
  184. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab +0 -0
  185. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream +0 -0
  186. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len +0 -0
  187. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len +0 -0
  188. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at +0 -0
  189. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i +0 -0
  190. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len +0 -0
  191. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  192. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  193. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  194. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  195. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values +0 -0
  196. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  197. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s +1 -0
  198. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  199. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
  200. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  201. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  202. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  203. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  204. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  205. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  206. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
  207. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  208. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  209. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  210. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  211. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  212. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  213. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
  214. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  215. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  216. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  217. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  218. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  219. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  220. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
  221. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +2 -0
  222. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  223. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  224. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  225. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  226. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  227. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  228. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
  229. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  230. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  231. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  232. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  233. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  234. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  235. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
  236. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  237. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  238. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  239. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  240. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  241. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  242. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
  243. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  244. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  245. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  246. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  247. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  248. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  249. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  250. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values +0 -0
  251. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  252. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.s +1 -0
  253. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  254. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
  255. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  256. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  257. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  258. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  259. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  260. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  261. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
  262. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  263. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  264. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  265. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  266. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values +0 -0
  267. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  268. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.s +4 -0
  269. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  270. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
  271. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
  272. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
  273. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
  274. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
  275. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
  276. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
  277. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
  278. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  279. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  280. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  281. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  282. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values +0 -0
  283. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  284. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.s +3 -0
  285. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  286. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
  287. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab +0 -0
  288. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream +0 -0
  289. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.keystream.len +0 -0
  290. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.len +0 -0
  291. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab.values.at +0 -0
  292. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i +0 -0
  293. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/package-parts.tab_i.len +0 -0
  294. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  295. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  296. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  297. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  298. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values +0 -0
  299. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  300. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s +1 -0
  301. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  302. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
  303. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  304. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  305. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  306. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  307. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  308. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  309. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
  310. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  311. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  312. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  313. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  314. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  315. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  316. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
  317. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  318. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  319. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  320. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  321. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  322. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  323. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
  324. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/counters.tab +2 -0
  325. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  326. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  327. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  328. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  329. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  330. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  331. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
  332. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  333. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  334. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  335. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  336. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  337. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  338. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
  339. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  340. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  341. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  342. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  343. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.values +0 -0
  344. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  345. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.s +1 -0
  346. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  347. package/android/build/kotlin/compileReleaseKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
  348. package/android/build/kotlin/compileReleaseKotlin/cacheable/last-build.bin +0 -0
  349. package/android/build/kotlin/compileReleaseKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  350. package/android/build/kotlin/compileReleaseKotlin/local-state/build-history.bin +0 -0
  351. package/android/build/outputs/logs/manifest-merger-debug-report.txt +20 -0
  352. package/android/build/outputs/logs/manifest-merger-release-report.txt +20 -0
  353. package/android/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin +0 -0
  354. package/android/build/tmp/kotlin-classes/debug/META-INF/pulse-updates_debug.kotlin_module +0 -0
  355. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/AssetModel.class +0 -0
  356. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/BundleModel.class +0 -0
  357. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/CheckResult.class +0 -0
  358. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/FetchResult.class +0 -0
  359. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/ManifestModel$Companion.class +0 -0
  360. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/ManifestModel.class +0 -0
  361. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseController$Companion.class +0 -0
  362. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseController$Delegate.class +0 -0
  363. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseController$errorRecoveryDelegate$1.class +0 -0
  364. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseController.class +0 -0
  365. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseControllerKt.class +0 -0
  366. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseIntegrityCheck.class +0 -0
  367. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseReaper.class +0 -0
  368. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseRemoteLoader.class +0 -0
  369. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseUpdatesConfig.class +0 -0
  370. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseUpdatesException.class +0 -0
  371. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseUpdatesModule$Companion.class +0 -0
  372. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseUpdatesModule.class +0 -0
  373. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/PulseUpdatesPackage.class +0 -0
  374. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/SignatureModel.class +0 -0
  375. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/UiThreadUtil.class +0 -0
  376. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/database/PulseAsset.class +0 -0
  377. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/database/PulseDatabase.class +0 -0
  378. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/database/PulseDatabaseSchema.class +0 -0
  379. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/database/PulseUpdate.class +0 -0
  380. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/database/PulseUpdateStatus$Companion.class +0 -0
  381. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/database/PulseUpdateStatus.class +0 -0
  382. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecovery$Companion.class +0 -0
  383. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecovery.class +0 -0
  384. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$LauncherCallback.class +0 -0
  385. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$RemoteLoadStatus.class +0 -0
  386. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate.class +0 -0
  387. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Companion.class +0 -0
  388. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$MessageType.class +0 -0
  389. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Task.class +0 -0
  390. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$WhenMappings.class +0 -0
  391. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$tryRelaunchFromCache$1.class +0 -0
  392. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler.class +0 -0
  393. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/EmbeddedAsset$Companion.class +0 -0
  394. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/EmbeddedAsset.class +0 -0
  395. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/EmbeddedManifest$Companion.class +0 -0
  396. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/EmbeddedManifest.class +0 -0
  397. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/LauncherException.class +0 -0
  398. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/PulseAppLauncher$Companion.class +0 -0
  399. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/PulseAppLauncher.class +0 -0
  400. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/PulseDefaultSelectionPolicy.class +0 -0
  401. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/PulseSelectionPolicy.class +0 -0
  402. package/android/build/tmp/kotlin-classes/debug/app/pulse/updates/launcher/PulseUpdateInfo.class +0 -0
  403. package/android/build/tmp/kotlin-classes/release/META-INF/pulse-updates_release.kotlin_module +0 -0
  404. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/AssetModel.class +0 -0
  405. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/BundleModel.class +0 -0
  406. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/CheckResult.class +0 -0
  407. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/FetchResult.class +0 -0
  408. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/ManifestModel$Companion.class +0 -0
  409. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/ManifestModel.class +0 -0
  410. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseController$Companion.class +0 -0
  411. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseController$Delegate.class +0 -0
  412. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseController$errorRecoveryDelegate$1.class +0 -0
  413. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseController.class +0 -0
  414. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseControllerKt.class +0 -0
  415. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseIntegrityCheck.class +0 -0
  416. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseReactHostDelegate.class +0 -0
  417. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseReactHostFactory.class +0 -0
  418. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseReaper.class +0 -0
  419. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseRemoteLoader.class +0 -0
  420. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseUpdatesConfig.class +0 -0
  421. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseUpdatesException.class +0 -0
  422. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseUpdatesModule$Companion.class +0 -0
  423. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseUpdatesModule.class +0 -0
  424. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/PulseUpdatesPackage.class +0 -0
  425. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/SignatureModel.class +0 -0
  426. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/UiThreadUtil.class +0 -0
  427. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/database/PulseAsset.class +0 -0
  428. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/database/PulseDatabase.class +0 -0
  429. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/database/PulseDatabaseSchema.class +0 -0
  430. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/database/PulseUpdate.class +0 -0
  431. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/database/PulseUpdateStatus$Companion.class +0 -0
  432. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/database/PulseUpdateStatus.class +0 -0
  433. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecovery$Companion.class +0 -0
  434. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecovery.class +0 -0
  435. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$LauncherCallback.class +0 -0
  436. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate$RemoteLoadStatus.class +0 -0
  437. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate.class +0 -0
  438. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Companion.class +0 -0
  439. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$MessageType.class +0 -0
  440. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$Task.class +0 -0
  441. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$WhenMappings.class +0 -0
  442. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler$tryRelaunchFromCache$1.class +0 -0
  443. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler.class +0 -0
  444. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/EmbeddedAsset$Companion.class +0 -0
  445. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/EmbeddedAsset.class +0 -0
  446. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/EmbeddedManifest$Companion.class +0 -0
  447. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/EmbeddedManifest.class +0 -0
  448. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/LauncherException.class +0 -0
  449. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/PulseAppLauncher$Companion.class +0 -0
  450. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/PulseAppLauncher.class +0 -0
  451. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/PulseDefaultSelectionPolicy.class +0 -0
  452. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/PulseSelectionPolicy.class +0 -0
  453. package/android/build/tmp/kotlin-classes/release/app/pulse/updates/launcher/PulseUpdateInfo.class +0 -0
  454. package/android/build.gradle +53 -0
  455. package/android/src/main/AndroidManifest.xml +3 -0
  456. package/android/src/main/java/app/pulse/updates/PulseController.kt +1419 -0
  457. package/android/src/main/java/app/pulse/updates/PulseReactHostFactory.kt +116 -0
  458. package/android/src/main/java/app/pulse/updates/PulseUpdatesModule.kt +314 -0
  459. package/android/src/main/java/app/pulse/updates/PulseUpdatesPackage.kt +16 -0
  460. package/android/src/main/java/app/pulse/updates/database/PulseDatabase.kt +400 -0
  461. package/android/src/main/java/app/pulse/updates/database/PulseDatabaseSchema.kt +90 -0
  462. package/android/src/main/java/app/pulse/updates/errorrecovery/PulseErrorRecovery.kt +89 -0
  463. package/android/src/main/java/app/pulse/updates/errorrecovery/PulseErrorRecoveryDelegate.kt +30 -0
  464. package/android/src/main/java/app/pulse/updates/errorrecovery/PulseErrorRecoveryHandler.kt +159 -0
  465. package/android/src/main/java/app/pulse/updates/launcher/PulseAppLauncher.kt +472 -0
  466. package/ios/PulseUpdates/AppLauncher/PulseAppLauncher.swift +551 -0
  467. package/ios/PulseUpdates/Database/PulseDatabase.swift +557 -0
  468. package/ios/PulseUpdates/Database/PulseDatabaseSchema.swift +229 -0
  469. package/ios/PulseUpdates/Database/PulseDatabaseUtils.swift +247 -0
  470. package/ios/PulseUpdates/ErrorRecovery/PulseErrorRecovery.swift +415 -0
  471. package/ios/PulseUpdates/PulseController.swift +1359 -0
  472. package/ios/PulseUpdates/PulseTypes.swift +289 -0
  473. package/ios/PulseUpdates/PulseUpdates.m +37 -0
  474. package/ios/PulseUpdates/PulseUpdates.swift +236 -0
  475. package/lib/commonjs/NativePulseUpdates.js +9 -0
  476. package/lib/commonjs/NativePulseUpdates.js.map +1 -0
  477. package/lib/commonjs/PulseUpdates.js +315 -0
  478. package/lib/commonjs/PulseUpdates.js.map +1 -0
  479. package/lib/commonjs/assetResolver.js +201 -0
  480. package/lib/commonjs/assetResolver.js.map +1 -0
  481. package/lib/commonjs/index.js +55 -0
  482. package/lib/commonjs/index.js.map +1 -0
  483. package/lib/commonjs/types.js +2 -0
  484. package/lib/commonjs/types.js.map +1 -0
  485. package/lib/commonjs/usePulseUpdates.js +115 -0
  486. package/lib/commonjs/usePulseUpdates.js.map +1 -0
  487. package/lib/module/NativePulseUpdates.js +3 -0
  488. package/lib/module/NativePulseUpdates.js.map +1 -0
  489. package/lib/module/PulseUpdates.js +291 -0
  490. package/lib/module/PulseUpdates.js.map +1 -0
  491. package/lib/module/assetResolver.js +193 -0
  492. package/lib/module/assetResolver.js.map +1 -0
  493. package/lib/module/index.js +5 -0
  494. package/lib/module/index.js.map +1 -0
  495. package/lib/module/types.js +2 -0
  496. package/lib/module/types.js.map +1 -0
  497. package/lib/module/usePulseUpdates.js +108 -0
  498. package/lib/module/usePulseUpdates.js.map +1 -0
  499. package/lib/typescript/NativePulseUpdates.d.ts +34 -0
  500. package/lib/typescript/NativePulseUpdates.d.ts.map +1 -0
  501. package/lib/typescript/PulseUpdates.d.ts +93 -0
  502. package/lib/typescript/PulseUpdates.d.ts.map +1 -0
  503. package/lib/typescript/assetResolver.d.ts +30 -0
  504. package/lib/typescript/assetResolver.d.ts.map +1 -0
  505. package/lib/typescript/index.d.ts +5 -0
  506. package/lib/typescript/index.d.ts.map +1 -0
  507. package/lib/typescript/types.d.ts +70 -0
  508. package/lib/typescript/types.d.ts.map +1 -0
  509. package/lib/typescript/usePulseUpdates.d.ts +21 -0
  510. package/lib/typescript/usePulseUpdates.d.ts.map +1 -0
  511. package/package.json +63 -0
  512. package/pulse-updates.podspec +23 -0
  513. package/react-native.config.js +18 -0
  514. package/scripts/create-pulse-resources-android.sh +93 -0
  515. package/scripts/create-pulse-resources-ios.sh +114 -0
  516. package/scripts/generate-embedded-manifest.mjs +307 -0
  517. package/scripts/manifest-check.js +67 -0
  518. package/scripts/publish.mjs +902 -0
  519. package/src/NativePulseUpdates.ts +52 -0
  520. package/src/PulseUpdates.ts +332 -0
  521. package/src/assetResolver.ts +193 -0
  522. package/src/index.ts +4 -0
  523. package/src/types.ts +78 -0
  524. package/src/usePulseUpdates.ts +135 -0
@@ -0,0 +1,1359 @@
1
+ // PulseUpdates Controller
2
+ // Based on expo-updates AppController
3
+ // Main controller that orchestrates update lifecycle
4
+
5
+ import Foundation
6
+ import Network
7
+
8
+ // MARK: - Controller Delegate
9
+
10
+ public protocol PulseControllerDelegate: AnyObject {
11
+ func pulseController(_ controller: PulseController, didStartWithSuccess success: Bool)
12
+ }
13
+
14
+ // MARK: - Main Controller
15
+
16
+ public final class PulseController {
17
+
18
+ // MARK: - Singleton
19
+
20
+ public static let shared = PulseController()
21
+
22
+ // MARK: - Public Properties
23
+
24
+ public weak var delegate: PulseControllerDelegate?
25
+
26
+ /// Whether the controller is active (updates are enabled)
27
+ public private(set) var isActive: Bool = false
28
+
29
+ /// Whether the controller has started
30
+ public private(set) var isStarted: Bool = false
31
+
32
+ /// Current configuration
33
+ public private(set) var config: PulseUpdatesConfig?
34
+
35
+ /// The currently launched update info
36
+ public private(set) var launchedUpdate: PulseUpdateInfo?
37
+
38
+ /// Whether we're running the embedded update
39
+ public private(set) var isEmbeddedLaunch: Bool = true
40
+
41
+ /// URL to the launch asset (JS bundle)
42
+ public private(set) var launchAssetUrl: URL?
43
+
44
+ /// Local assets map (asset key -> file URL)
45
+ public private(set) var localAssets: [String: String] = [:]
46
+
47
+ /// The manifest JSON for the launched update (for metadata like build number)
48
+ public private(set) var launchedManifestJson: String?
49
+
50
+ /// Error recovery handler
51
+ public private(set) var errorRecovery: PulseErrorRecovery?
52
+
53
+ /// Remote load status for error recovery
54
+ public private(set) var remoteLoadStatus: PulseRemoteLoadStatus = .idle
55
+
56
+ // MARK: - Private Properties
57
+
58
+ private var database: PulseDatabase?
59
+ private var launcher: PulseAppLauncher?
60
+ private let directory: URL
61
+ private let fileQueue = DispatchQueue(label: "app.pulse.files", qos: .userInitiated)
62
+
63
+ // Embedded manifest cache
64
+ private var embeddedManifest: PulseEmbeddedManifest?
65
+ private var embeddedAssetHashes: [String: URL] = [:]
66
+ private var embeddedBundleHash: String?
67
+
68
+ // MARK: - Native Config (from Info.plist, like expo-updates)
69
+
70
+ /// Load config from Info.plist (called before JS starts)
71
+ private func loadNativeConfig() -> PulseUpdatesConfig? {
72
+ let info = Bundle.main.infoDictionary
73
+
74
+ // Check if PulseUpdates is configured in Info.plist
75
+ guard let updateUrl = info?["PulseUpdatesURL"] as? String, !updateUrl.isEmpty else {
76
+ pulseLog("No PulseUpdatesURL in Info.plist, native config disabled")
77
+ return nil
78
+ }
79
+
80
+ let enabled = (info?["PulseUpdatesEnabled"] as? Bool) ?? true
81
+
82
+ // Runtime version: embedded manifest > CFBundleShortVersionString
83
+ let runtimeVersion: String
84
+ if let embedded = embeddedManifest {
85
+ runtimeVersion = embedded.runtimeVersion
86
+ } else {
87
+ runtimeVersion = (info?["CFBundleShortVersionString"] as? String)
88
+ ?? (info?["CFBundleVersion"] as? String)
89
+ ?? "unknown"
90
+ }
91
+
92
+ return PulseUpdatesConfig(
93
+ enabled: enabled,
94
+ updateUrl: updateUrl,
95
+ runtimeVersion: runtimeVersion,
96
+ checkOnLaunch: (info?["PulseUpdatesCheckOnLaunch"] as? String) ?? "ALWAYS",
97
+ launchWaitMs: (info?["PulseUpdatesLaunchWaitMs"] as? Int) ?? 0,
98
+ channel: info?["PulseUpdatesChannel"] as? String,
99
+ signingKeyId: info?["PulseUpdatesSigningKeyId"] as? String,
100
+ signingPublicKey: info?["PulseUpdatesSigningPublicKey"] as? String
101
+ )
102
+ }
103
+
104
+ /// Get the runtime version (from config or native sources)
105
+ private var nativeRuntimeVersion: String {
106
+ // Use config if available
107
+ if let configVersion = config?.runtimeVersion {
108
+ return configVersion
109
+ }
110
+
111
+ // Try embedded manifest
112
+ if let embedded = embeddedManifest {
113
+ return embedded.runtimeVersion
114
+ }
115
+
116
+ // Fall back to app version
117
+ let info = Bundle.main.infoDictionary
118
+ return (info?["CFBundleShortVersionString"] as? String)
119
+ ?? (info?["CFBundleVersion"] as? String)
120
+ ?? "unknown"
121
+ }
122
+
123
+ // MARK: - Initialization
124
+
125
+ private init() {
126
+ // Use Application Support directory
127
+ let appSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
128
+ self.directory = appSupport.appendingPathComponent("pulse", isDirectory: true)
129
+ }
130
+
131
+ // MARK: - Public API
132
+
133
+ /// Configure the controller (call before start)
134
+ public func configure(_ config: PulseUpdatesConfig) {
135
+ self.config = config
136
+ self.isActive = config.enabled
137
+ }
138
+
139
+ /// Initialize without starting (for custom initialization)
140
+ /// This is called synchronously by getBundleURL() before JS starts
141
+ public func initializeWithoutStarting() {
142
+ guard !isStarted else { return }
143
+
144
+ createDirectories()
145
+ initializeDatabase()
146
+ loadEmbeddedManifest()
147
+
148
+ // Load native config from Info.plist if not already configured by JS
149
+ if config == nil {
150
+ config = loadNativeConfig()
151
+ if let cfg = config {
152
+ isActive = cfg.enabled
153
+ pulseLog("Loaded native config: url=\(cfg.updateUrl) runtime=\(cfg.runtimeVersion)")
154
+ }
155
+ }
156
+
157
+ seedEmbeddedUpdateIfNeeded()
158
+ runIntegrityCheck()
159
+
160
+ // Synchronously select the best update for launch
161
+ selectBestUpdateSync()
162
+ }
163
+
164
+ /// Synchronously select the best update (used for initial launch)
165
+ private func selectBestUpdateSync() {
166
+ // Use config.runtimeVersion if available, otherwise fall back to native
167
+ let runtimeVersion = config?.runtimeVersion ?? nativeRuntimeVersion
168
+
169
+ pulseLog("selectBestUpdateSync: database=\(database != nil) runtimeVersion=\(runtimeVersion)")
170
+
171
+ guard let database = database else {
172
+ pulseLog("selectBestUpdateSync: no database")
173
+ return
174
+ }
175
+
176
+ do {
177
+ let updates = try database.launchableUpdates(forRuntimeVersion: runtimeVersion)
178
+ pulseLog("selectBestUpdateSync: found \(updates.count) updates, runtimeVersion=\(runtimeVersion)")
179
+
180
+ let policy = PulseDefaultSelectionPolicy()
181
+
182
+ guard let selectedUpdate = policy.selectUpdateToLaunch(from: updates) else {
183
+ pulseLog("selectBestUpdateSync: no update selected")
184
+ return
185
+ }
186
+
187
+ pulseLog("selectBestUpdateSync: selected \(selectedUpdate.updateId) status=\(selectedUpdate.status) bundleHash=\(selectedUpdate.bundleHash ?? "nil")")
188
+
189
+ // Set the launch URL based on selected update
190
+ if selectedUpdate.status == .embedded {
191
+ launchAssetUrl = Bundle.main.url(forResource: "main", withExtension: "jsbundle")
192
+ isEmbeddedLaunch = true
193
+ // For embedded, use only embedded assets
194
+ localAssets = buildEmbeddedLocalAssets()
195
+ pulseLog("selectBestUpdateSync: using embedded bundle, localAssets count=\(localAssets.count)")
196
+ } else if let bundleHash = selectedUpdate.bundleHash {
197
+ let bundlePath = directory.appendingPathComponent("assets/sha256/\(bundleHash.lowercased())")
198
+ let exists = FileManager.default.fileExists(atPath: bundlePath.path)
199
+ pulseLog("selectBestUpdateSync: bundlePath exists=\(exists)")
200
+
201
+ if exists {
202
+ launchAssetUrl = bundlePath
203
+ isEmbeddedLaunch = false
204
+
205
+ // Set launchedUpdate info
206
+ launchedUpdate = PulseUpdateInfo(
207
+ updateId: selectedUpdate.updateId,
208
+ runtimeVersion: selectedUpdate.runtimeVersion,
209
+ commitTime: selectedUpdate.commitTime,
210
+ status: selectedUpdate.status,
211
+ successfulLaunchCount: selectedUpdate.successfulLaunchCount,
212
+ failedLaunchCount: selectedUpdate.failedLaunchCount,
213
+ isEmbedded: selectedUpdate.isEmbedded,
214
+ bundleHash: selectedUpdate.bundleHash,
215
+ scopeKey: selectedUpdate.scopeKey
216
+ )
217
+
218
+ // Load manifest from database for metadata (build number, etc.)
219
+ if let manifest = selectedUpdate.manifest,
220
+ let data = try? JSONSerialization.data(withJSONObject: manifest, options: []),
221
+ let jsonString = String(data: data, encoding: .utf8) {
222
+ launchedManifestJson = jsonString
223
+ pulseLog("selectBestUpdateSync: loaded manifest json")
224
+ }
225
+
226
+ // Build localAssets: downloaded assets + embedded fallbacks
227
+ localAssets = buildLocalAssetsForUpdate(updateId: selectedUpdate.updateId, database: database)
228
+ pulseLog("selectBestUpdateSync: set launchAssetUrl to downloaded bundle, localAssets count=\(localAssets.count)")
229
+ }
230
+ }
231
+ } catch {
232
+ pulseLogError("selectBestUpdateSync error: \(error)")
233
+ }
234
+ }
235
+
236
+ /// Build localAssets map for an OTA update (downloaded + embedded fallbacks)
237
+ /// Store BOTH hash AND path-based keys for maximum compatibility:
238
+ /// - hash: for SHA256 hash lookup (how expo-asset looks up)
239
+ /// - path: for Metro path-based lookup (httpServerLocation/name.type)
240
+ private func buildLocalAssetsForUpdate(updateId: String, database: PulseDatabase) -> [String: String] {
241
+ // Start with embedded assets as base (fallback)
242
+ var assets = buildEmbeddedLocalAssets()
243
+ pulseLog("buildLocalAssetsForUpdate: embedded base count=\(assets.count)")
244
+
245
+ // Get downloaded assets for this update from database
246
+ do {
247
+ let updateAssets = try database.assets(forUpdateId: updateId)
248
+ pulseLog("buildLocalAssetsForUpdate: found \(updateAssets.count) assets in database for update \(updateId)")
249
+
250
+ for asset in updateAssets where !asset.isLaunchAsset {
251
+ // Check if downloaded asset exists (stored by SHA256 hash)
252
+ let downloadedPath = directory.appendingPathComponent("assets/sha256/\(asset.hash.lowercased())")
253
+ if FileManager.default.fileExists(atPath: downloadedPath.path) {
254
+ let localUri = downloadedPath.absoluteString
255
+
256
+ // Store by SHA256 hash (how expo-asset looks up assets)
257
+ assets[asset.hash] = localUri
258
+
259
+ // Also store by manifest key (MD5 hash) for expo-asset compatibility
260
+ if let key = asset.key {
261
+ // Normalize key: remove double "assets/assets/" prefix -> "assets/"
262
+ var normalizedKey = key
263
+ if normalizedKey.hasPrefix("assets/assets/") {
264
+ normalizedKey = String(normalizedKey.dropFirst("assets/".count))
265
+ }
266
+ assets[normalizedKey] = localUri
267
+ }
268
+ } else {
269
+ // Downloaded file doesn't exist - use embedded fallback
270
+ // BUT we still need to add the MD5 key from OTA manifest pointing to the embedded asset!
271
+ // The embedded map has SHA256 keys, but JS looks up by MD5 hash (asset.key)
272
+ if let embeddedUri = assets[asset.hash], let key = asset.key {
273
+ // Add MD5 key pointing to embedded asset
274
+ assets[key] = embeddedUri
275
+ pulseLog("buildLocalAssetsForUpdate: using embedded fallback for key=\(key.prefix(16))... hash=\(asset.hash.prefix(16))...")
276
+ } else {
277
+ pulseLogWarn("buildLocalAssetsForUpdate: file not found AND no embedded fallback for hash=\(asset.hash.prefix(16))...")
278
+ }
279
+ }
280
+ }
281
+ } catch {
282
+ pulseLogError("buildLocalAssetsForUpdate error: \(error)")
283
+ }
284
+
285
+ return assets
286
+ }
287
+
288
+ /// Build localAssets map from embedded manifest for fallback
289
+ /// Key is the manifest key (MD5 hash) which matches how expo-asset looks up assets
290
+ private func buildEmbeddedLocalAssets() -> [String: String] {
291
+ guard let manifest = embeddedManifest else { return [:] }
292
+
293
+ var assets: [String: String] = [:]
294
+
295
+ for asset in manifest.assets where !asset.isLaunchAsset {
296
+ guard let filename = asset.nsBundleFilename else {
297
+ continue
298
+ }
299
+
300
+ let bundlePath: String?
301
+ if let dir = asset.nsBundleDir, !dir.isEmpty {
302
+ bundlePath = Bundle.main.path(forResource: filename, ofType: nil, inDirectory: dir)
303
+ } else {
304
+ bundlePath = Bundle.main.path(forResource: filename, ofType: nil)
305
+ }
306
+
307
+ if let path = bundlePath {
308
+ let localUri = URL(fileURLWithPath: path).absoluteString
309
+
310
+ // Store by manifest key (MD5 hash - matches how expo-asset looks up)
311
+ if let key = asset.key {
312
+ assets[key] = localUri
313
+ }
314
+
315
+ // Also store by SHA256 hash for fallback
316
+ assets[asset.hash] = localUri
317
+ }
318
+ }
319
+
320
+ return assets
321
+ }
322
+
323
+ /// Start the controller (call after configure, or auto-starts with native config)
324
+ public func start() {
325
+ guard !isStarted else { return }
326
+ isStarted = true
327
+
328
+ pulseLog("Starting controller")
329
+
330
+ // Initialize
331
+ createDirectories()
332
+ initializeDatabase()
333
+ loadEmbeddedManifest()
334
+
335
+ // Load native config from Info.plist if not already configured by JS
336
+ if config == nil {
337
+ config = loadNativeConfig()
338
+ if let cfg = config {
339
+ isActive = cfg.enabled
340
+ pulseLog("Loaded native config: url=\(cfg.updateUrl) runtime=\(cfg.runtimeVersion)")
341
+ }
342
+ }
343
+
344
+ seedEmbeddedUpdateIfNeeded()
345
+ runIntegrityCheck()
346
+
347
+ // Create and start error recovery
348
+ errorRecovery = PulseErrorRecovery()
349
+ errorRecovery?.delegate = self
350
+ errorRecovery?.startMonitoring()
351
+
352
+ // Launch best available update
353
+ launchBestUpdate { [weak self] success in
354
+ guard let self = self else { return }
355
+
356
+ if success {
357
+ pulseLog("Started successfully with update: \(self.launchedUpdate?.updateId ?? "embedded")")
358
+ } else {
359
+ pulseLog("Failed to start, falling back to embedded")
360
+ self.launchEmbedded()
361
+ }
362
+
363
+ self.delegate?.pulseController(self, didStartWithSuccess: success || self.launchAssetUrl != nil)
364
+
365
+ // Check for updates on launch based on config
366
+ self.performCheckOnLaunchIfNeeded()
367
+ }
368
+ }
369
+
370
+ // MARK: - Check on Launch
371
+
372
+ private func performCheckOnLaunchIfNeeded() {
373
+ guard let config = config, config.enabled else { return }
374
+
375
+ switch config.checkOnLaunch.uppercased() {
376
+ case "NEVER":
377
+ pulseLog("checkOnLaunch is NEVER, skipping automatic check")
378
+ return
379
+ case "WIFI_ONLY":
380
+ guard isOnWifi() else {
381
+ pulseLog("checkOnLaunch is WIFI_ONLY but not on WiFi, skipping")
382
+ return
383
+ }
384
+ case "ALWAYS":
385
+ break
386
+ default:
387
+ break
388
+ }
389
+
390
+ // Wait for launchWaitMs before checking
391
+ let waitMs = config.launchWaitMs
392
+ if waitMs > 0 {
393
+ DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + .milliseconds(waitMs)) { [weak self] in
394
+ self?.performBackgroundUpdateCheck()
395
+ }
396
+ } else {
397
+ DispatchQueue.global(qos: .utility).async { [weak self] in
398
+ self?.performBackgroundUpdateCheck()
399
+ }
400
+ }
401
+ }
402
+
403
+ private func performBackgroundUpdateCheck() {
404
+ pulseLog("Performing background update check")
405
+
406
+ checkForUpdate { [weak self] result in
407
+ switch result {
408
+ case .success(let checkResult):
409
+ if checkResult.isAvailable {
410
+ pulseLog("Background check: update available, fetching...")
411
+ self?.fetchUpdate { fetchResult in
412
+ switch fetchResult {
413
+ case .success(let fetch):
414
+ if fetch.isNew {
415
+ pulseLog("Background check: update downloaded and ready")
416
+ // Notify via event emitter that update is available
417
+ NotificationCenter.default.post(
418
+ name: NSNotification.Name("PulseUpdatesAvailable"),
419
+ object: nil,
420
+ userInfo: ["manifest": fetch.manifest as Any]
421
+ )
422
+ }
423
+ case .failure(let error):
424
+ pulseLog("Background check: fetch failed - \(error)")
425
+ }
426
+ }
427
+ } else {
428
+ pulseLog("Background check: no update available")
429
+ }
430
+ case .failure(let error):
431
+ pulseLog("Background check failed: \(error)")
432
+ }
433
+ }
434
+ }
435
+
436
+ private func isOnWifi() -> Bool {
437
+ // Use Network framework for WiFi detection
438
+ let monitor = NWPathMonitor()
439
+ var isWifi = false
440
+ let semaphore = DispatchSemaphore(value: 0)
441
+
442
+ monitor.pathUpdateHandler = { path in
443
+ isWifi = path.usesInterfaceType(.wifi)
444
+ semaphore.signal()
445
+ }
446
+
447
+ let queue = DispatchQueue(label: "wifi.check")
448
+ monitor.start(queue: queue)
449
+ _ = semaphore.wait(timeout: .now() + 1)
450
+ monitor.cancel()
451
+
452
+ return isWifi
453
+ }
454
+
455
+ /// Get the bundle URL for React Native
456
+ public func launchAssetURL() -> URL? {
457
+ if launchAssetUrl != nil {
458
+ return launchAssetUrl
459
+ }
460
+
461
+ // Fall back to embedded bundle
462
+ return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
463
+ }
464
+
465
+ /// Check for updates
466
+ public func checkForUpdate(completion: @escaping (Result<PulseCheckResult, Error>) -> Void) {
467
+ guard let config = config else {
468
+ completion(.failure(PulseUpdatesError.notConfigured))
469
+ return
470
+ }
471
+
472
+ guard config.enabled else {
473
+ completion(.failure(PulseUpdatesError.notEnabled))
474
+ return
475
+ }
476
+
477
+ PulseRemoteLoader.checkForUpdate(
478
+ config: config,
479
+ currentUpdateId: launchedUpdate?.updateId,
480
+ completion: completion
481
+ )
482
+ }
483
+
484
+ /// Fetch and download an update
485
+ public func fetchUpdate(completion: @escaping (Result<PulseFetchResult, Error>) -> Void) {
486
+ guard let config = config else {
487
+ completion(.failure(PulseUpdatesError.notConfigured))
488
+ return
489
+ }
490
+
491
+ guard config.enabled else {
492
+ completion(.failure(PulseUpdatesError.notEnabled))
493
+ return
494
+ }
495
+
496
+ PulseRemoteLoader.fetchUpdate(
497
+ config: config,
498
+ database: database,
499
+ directory: directory,
500
+ completion: completion
501
+ )
502
+ }
503
+
504
+ /// Reload the app with the new update
505
+ public func reload(completion: ((Bool) -> Void)? = nil) {
506
+ // Re-select the best update before reloading
507
+ launchBestUpdate { success in
508
+ // Signal React Native to reload with the new bundle
509
+ NotificationCenter.default.post(name: NSNotification.Name("PulseUpdatesReload"), object: nil)
510
+ completion?(success)
511
+ }
512
+ }
513
+
514
+ /// Mark the app as ready (error recovery)
515
+ /// Note: With the new error recovery system, this is handled automatically
516
+ /// via RCTContentDidAppear notification. This method is kept for manual marking if needed.
517
+ public func markAppReady() {
518
+ if let updateId = launchedUpdate?.updateId {
519
+ try? database?.recordSuccessfulLaunch(updateId: updateId)
520
+ }
521
+
522
+ // Run reaper after successful launch
523
+ runReaper()
524
+ }
525
+
526
+ /// Report a fatal error for error recovery handling
527
+ public func reportError(_ error: NSError) {
528
+ errorRecovery?.handle(error: error)
529
+ }
530
+
531
+ /// Report a fatal exception for error recovery handling
532
+ public func reportException(_ exception: NSException) {
533
+ errorRecovery?.handle(exception: exception)
534
+ }
535
+
536
+ // MARK: - Private Methods
537
+
538
+ private func createDirectories() {
539
+ let dirs = [
540
+ directory,
541
+ directory.appendingPathComponent("updates"),
542
+ directory.appendingPathComponent("assets/sha256"),
543
+ directory.appendingPathComponent("bundles/sha256"),
544
+ directory.appendingPathComponent("staging")
545
+ ]
546
+
547
+ for dir in dirs {
548
+ try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
549
+ }
550
+ }
551
+
552
+ private func initializeDatabase() {
553
+ do {
554
+ database = PulseDatabase(directory: directory)
555
+ try database?.open()
556
+ pulseLog("Database initialized")
557
+ } catch {
558
+ pulseLog("Failed to initialize database: \(error)")
559
+ }
560
+ }
561
+
562
+ private func loadEmbeddedManifest() {
563
+ guard let url = Bundle.main.url(forResource: "embedded-manifest", withExtension: "json"),
564
+ let data = try? Data(contentsOf: url),
565
+ let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
566
+ pulseLog("No embedded manifest found")
567
+ return
568
+ }
569
+
570
+ embeddedManifest = PulseEmbeddedManifest(json: json)
571
+
572
+ // Cache embedded asset hashes
573
+ if let manifest = embeddedManifest {
574
+ for asset in manifest.assets {
575
+ if let filename = asset.nsBundleFilename {
576
+ let bundlePath: String?
577
+ if let dir = asset.nsBundleDir, !dir.isEmpty {
578
+ bundlePath = Bundle.main.path(forResource: filename, ofType: nil, inDirectory: dir)
579
+ } else {
580
+ bundlePath = Bundle.main.path(forResource: filename, ofType: nil)
581
+ }
582
+
583
+ if let path = bundlePath {
584
+ embeddedAssetHashes[asset.hash.lowercased()] = URL(fileURLWithPath: path)
585
+ }
586
+ }
587
+
588
+ if asset.isLaunchAsset {
589
+ embeddedBundleHash = asset.hash.lowercased()
590
+ }
591
+ }
592
+ }
593
+
594
+ pulseLog("Loaded embedded manifest: \(embeddedManifest?.updateId ?? "unknown")")
595
+ }
596
+
597
+ private func seedEmbeddedUpdateIfNeeded() {
598
+ guard let embedded = embeddedManifest,
599
+ let database = database else {
600
+ return
601
+ }
602
+
603
+ let embeddedId = "embedded:\(embedded.updateId)"
604
+
605
+ // Check if already seeded
606
+ if let _ = try? database.update(withId: embeddedId) {
607
+ return
608
+ }
609
+
610
+ // Create embedded update record
611
+ // scopeKey from config, or default to "default" if not configured yet
612
+ let update = PulseUpdate(
613
+ updateId: embeddedId,
614
+ scopeKey: config?.scopeKey ?? "default",
615
+ runtimeVersion: embedded.runtimeVersion,
616
+ commitTime: embedded.commitTime,
617
+ status: .embedded,
618
+ manifest: nil,
619
+ bundleHash: embeddedBundleHash,
620
+ lastAccessed: Date(),
621
+ successfulLaunchCount: 0,
622
+ failedLaunchCount: 0
623
+ )
624
+
625
+ do {
626
+ try database.addUpdate(update)
627
+ pulseLog("Seeded embedded update: \(embeddedId)")
628
+ } catch {
629
+ pulseLog("Failed to seed embedded update: \(error)")
630
+ }
631
+ }
632
+
633
+ private func runIntegrityCheck() {
634
+ guard let database = database else { return }
635
+
636
+ let currentEmbeddedId = embeddedManifest.map { "embedded:\($0.updateId)" }
637
+
638
+ PulseIntegrityCheck.run(
639
+ database: database,
640
+ directory: directory,
641
+ currentEmbeddedId: currentEmbeddedId
642
+ )
643
+ }
644
+
645
+ private func launchBestUpdate(completion: @escaping (Bool) -> Void) {
646
+ guard let database = database,
647
+ let config = config else {
648
+ completion(false)
649
+ return
650
+ }
651
+
652
+ let launcher = PulseAppLauncher(
653
+ database: database,
654
+ directory: directory,
655
+ selectionPolicy: PulseDefaultSelectionPolicy(),
656
+ runtimeVersion: config.runtimeVersion
657
+ )
658
+
659
+ self.launcher = launcher
660
+
661
+ launcher.launch { [weak self] success, error in
662
+ guard let self = self else {
663
+ completion(false)
664
+ return
665
+ }
666
+
667
+ if success {
668
+ self.launchAssetUrl = launcher.launchAssetUrl
669
+ self.localAssets = launcher.assetFilesMap
670
+ self.isEmbeddedLaunch = launcher.isUsingEmbeddedAssets
671
+
672
+ if let update = launcher.launchedUpdate {
673
+ self.launchedUpdate = PulseUpdateInfo(
674
+ updateId: update.updateId,
675
+ runtimeVersion: update.runtimeVersion,
676
+ commitTime: update.commitTime,
677
+ status: update.status,
678
+ successfulLaunchCount: update.successfulLaunchCount,
679
+ failedLaunchCount: update.failedLaunchCount,
680
+ isEmbedded: update.isEmbedded,
681
+ bundleHash: update.bundleHash,
682
+ scopeKey: update.scopeKey
683
+ )
684
+ }
685
+ }
686
+
687
+ if let error = error {
688
+ pulseLog("Launch error: \(error)")
689
+ }
690
+
691
+ completion(success)
692
+ }
693
+ }
694
+
695
+ private func launchEmbedded() {
696
+ launchAssetUrl = Bundle.main.url(forResource: "main", withExtension: "jsbundle")
697
+ isEmbeddedLaunch = true
698
+
699
+ // Build local assets from embedded manifest - use KEY for React Native compatibility
700
+ if let manifest = embeddedManifest {
701
+ for asset in manifest.assets where !asset.isLaunchAsset {
702
+ if let key = asset.key, let url = embeddedAssetHashes[asset.hash.lowercased()] {
703
+ // Use KEY as dictionary key - React Native asset resolver looks up by key
704
+ localAssets[key] = url.absoluteString
705
+ }
706
+ }
707
+ }
708
+ }
709
+
710
+ private func rollbackToPreviousUpdate() {
711
+ pulseLog("Rolling back to previous update")
712
+ // Implementation depends on error recovery strategy
713
+ }
714
+
715
+ private func runReaper() {
716
+ guard let database = database,
717
+ let launchedUpdate = launchedUpdate else {
718
+ return
719
+ }
720
+
721
+ PulseReaper.reap(
722
+ database: database,
723
+ directory: directory,
724
+ selectionPolicy: PulseDefaultSelectionPolicy(),
725
+ launchedUpdateId: launchedUpdate.updateId
726
+ )
727
+ }
728
+ }
729
+
730
+ // MARK: - Integrity Check
731
+
732
+ final class PulseIntegrityCheck {
733
+ static func run(database: PulseDatabase, directory: URL, currentEmbeddedId: String?) {
734
+ DispatchQueue.global(qos: .utility).async {
735
+ do {
736
+ // Delete old embedded updates
737
+ let embeddedUpdates = try database.embeddedUpdates()
738
+ let toDelete = embeddedUpdates.filter { update in
739
+ guard let currentId = currentEmbeddedId else { return true }
740
+ return update.updateId != currentId
741
+ }
742
+
743
+ if !toDelete.isEmpty {
744
+ try database.deleteUpdates(toDelete.map { $0.updateId })
745
+ pulseLog("IntegrityCheck: Deleted \(toDelete.count) old embedded updates")
746
+
747
+ // Clean up unused assets
748
+ _ = try database.deleteUnusedAssets()
749
+ }
750
+ } catch {
751
+ pulseLog("IntegrityCheck error: \(error)")
752
+ }
753
+ }
754
+ }
755
+ }
756
+
757
+ // MARK: - Reaper
758
+
759
+ final class PulseReaper {
760
+ /// Clean up old updates after successful launch
761
+ /// Based on Expo's UpdatesReaper
762
+ static func reap(
763
+ database: PulseDatabase,
764
+ directory: URL,
765
+ selectionPolicy: PulseSelectionPolicy,
766
+ launchedUpdateId: String
767
+ ) {
768
+ DispatchQueue.global(qos: .utility).async {
769
+ do {
770
+ let allUpdates = try database.allUpdates()
771
+
772
+ guard let launchedUpdate = allUpdates.first(where: { $0.updateId == launchedUpdateId }) else {
773
+ return
774
+ }
775
+
776
+ // Convert to PulseUpdateInfo for selection policy
777
+ let launchedInfo = PulseUpdateInfo(
778
+ updateId: launchedUpdate.updateId,
779
+ runtimeVersion: launchedUpdate.runtimeVersion,
780
+ commitTime: launchedUpdate.commitTime,
781
+ status: launchedUpdate.status,
782
+ successfulLaunchCount: launchedUpdate.successfulLaunchCount,
783
+ failedLaunchCount: launchedUpdate.failedLaunchCount,
784
+ isEmbedded: launchedUpdate.isEmbedded,
785
+ bundleHash: launchedUpdate.bundleHash,
786
+ scopeKey: launchedUpdate.scopeKey
787
+ )
788
+
789
+ let allInfos = allUpdates.map { update in
790
+ PulseUpdateInfo(
791
+ updateId: update.updateId,
792
+ runtimeVersion: update.runtimeVersion,
793
+ commitTime: update.commitTime,
794
+ status: update.status,
795
+ successfulLaunchCount: update.successfulLaunchCount,
796
+ failedLaunchCount: update.failedLaunchCount,
797
+ isEmbedded: update.isEmbedded,
798
+ bundleHash: update.bundleHash,
799
+ scopeKey: update.scopeKey
800
+ )
801
+ }
802
+
803
+ let toDeleteInfos = selectionPolicy.selectUpdatesToDelete(
804
+ launchedUpdate: launchedInfo,
805
+ allUpdates: allInfos
806
+ )
807
+
808
+ if toDeleteInfos.isEmpty {
809
+ return
810
+ }
811
+
812
+ let toDeleteIds = toDeleteInfos.map { $0.updateId }
813
+ try database.deleteUpdates(toDeleteIds)
814
+
815
+ // Delete unused assets from filesystem
816
+ let unusedAssets = try database.deleteUnusedAssets()
817
+ for asset in unusedAssets {
818
+ let assetPath = directory
819
+ .appendingPathComponent("assets/sha256")
820
+ .appendingPathComponent(asset.hash.lowercased())
821
+ try? FileManager.default.removeItem(at: assetPath)
822
+ }
823
+
824
+ // Also clean up unused bundles
825
+ cleanupUnusedBundles(database: database, directory: directory)
826
+
827
+ pulseLog("Reaper: Deleted \(toDeleteIds.count) updates, \(unusedAssets.count) assets")
828
+ } catch {
829
+ pulseLog("Reaper error: \(error)")
830
+ }
831
+ }
832
+ }
833
+
834
+ /// Clean up bundle files that are no longer referenced
835
+ private static func cleanupUnusedBundles(database: PulseDatabase, directory: URL) {
836
+ do {
837
+ let allUpdates = try database.allUpdates()
838
+ let referencedHashes = Set(allUpdates.compactMap { $0.bundleHash?.lowercased() })
839
+
840
+ let bundlesDir = directory.appendingPathComponent("bundles/sha256")
841
+ guard let items = try? FileManager.default.contentsOfDirectory(atPath: bundlesDir.path) else {
842
+ return
843
+ }
844
+
845
+ for item in items {
846
+ if !referencedHashes.contains(item.lowercased()) {
847
+ let bundlePath = bundlesDir.appendingPathComponent(item)
848
+ try? FileManager.default.removeItem(at: bundlePath)
849
+ pulseLog("Reaper: Deleted unused bundle \(item)")
850
+ }
851
+ }
852
+ } catch {
853
+ pulseLog("Reaper bundle cleanup error: \(error)")
854
+ }
855
+ }
856
+ }
857
+
858
+ // MARK: - Remote Loader
859
+
860
+ final class PulseRemoteLoader {
861
+
862
+ static func checkForUpdate(
863
+ config: PulseUpdatesConfig,
864
+ currentUpdateId: String?,
865
+ completion: @escaping (Result<PulseCheckResult, Error>) -> Void
866
+ ) {
867
+ guard let request = buildManifestRequest(config: config, currentUpdateId: currentUpdateId) else {
868
+ completion(.failure(PulseUpdatesError.invalidManifest(reason: "Invalid update URL")))
869
+ return
870
+ }
871
+
872
+ URLSession.shared.dataTask(with: request) { data, response, error in
873
+ if let error = error {
874
+ completion(.failure(PulseUpdatesError.networkError(underlying: error)))
875
+ return
876
+ }
877
+
878
+ guard let httpResponse = response as? HTTPURLResponse else {
879
+ completion(.success(PulseCheckResult(isAvailable: false)))
880
+ return
881
+ }
882
+
883
+ // 204 = no update available
884
+ if httpResponse.statusCode == 204 {
885
+ completion(.success(PulseCheckResult(isAvailable: false)))
886
+ return
887
+ }
888
+
889
+ guard httpResponse.statusCode == 200, let data = data else {
890
+ completion(.success(PulseCheckResult(isAvailable: false)))
891
+ return
892
+ }
893
+
894
+ do {
895
+ let manifest = try JSONDecoder().decode(PulseManifestModel.self, from: data)
896
+
897
+ // Check runtime version
898
+ if manifest.runtimeVersion != config.runtimeVersion {
899
+ pulseLog("Runtime version mismatch: manifest=\(manifest.runtimeVersion) expected=\(config.runtimeVersion)")
900
+ completion(.success(PulseCheckResult(isAvailable: false)))
901
+ return
902
+ }
903
+
904
+ // Verify signature if required
905
+ if config.signingPublicKey != nil {
906
+ guard verifyManifestSignature(manifest: manifest, manifestJson: data, config: config) else {
907
+ completion(.failure(PulseUpdatesError.signatureVerificationFailed))
908
+ return
909
+ }
910
+ }
911
+
912
+ // Check if this is the same update
913
+ if manifest.updateId == currentUpdateId {
914
+ completion(.success(PulseCheckResult(isAvailable: false)))
915
+ return
916
+ }
917
+
918
+ pulseLog("Update available: \(manifest.updateId)")
919
+ completion(.success(PulseCheckResult(isAvailable: true, manifest: manifest)))
920
+
921
+ } catch {
922
+ completion(.failure(PulseUpdatesError.invalidManifest(reason: error.localizedDescription)))
923
+ }
924
+ }.resume()
925
+ }
926
+
927
+ static func fetchUpdate(
928
+ config: PulseUpdatesConfig,
929
+ database: PulseDatabase?,
930
+ directory: URL,
931
+ completion: @escaping (Result<PulseFetchResult, Error>) -> Void
932
+ ) {
933
+ // First check for update
934
+ checkForUpdate(config: config, currentUpdateId: PulseController.shared.launchedUpdate?.updateId) { result in
935
+ switch result {
936
+ case .failure(let error):
937
+ completion(.failure(error))
938
+
939
+ case .success(let checkResult):
940
+ guard checkResult.isAvailable, let manifest = checkResult.manifest else {
941
+ completion(.success(PulseFetchResult(isNew: false)))
942
+ return
943
+ }
944
+
945
+ // Download the update
946
+ downloadUpdate(manifest: manifest, config: config, database: database, directory: directory) { downloadResult in
947
+ switch downloadResult {
948
+ case .failure(let error):
949
+ completion(.failure(error))
950
+ case .success:
951
+ completion(.success(PulseFetchResult(isNew: true, manifest: manifest)))
952
+ }
953
+ }
954
+ }
955
+ }
956
+ }
957
+
958
+ // MARK: - Private Methods
959
+
960
+ private static func buildManifestRequest(config: PulseUpdatesConfig, currentUpdateId: String?) -> URLRequest? {
961
+ guard let url = URL(string: config.updateUrl) else { return nil }
962
+
963
+ var request = URLRequest(url: url)
964
+ request.httpMethod = "GET"
965
+ request.setValue("application/json", forHTTPHeaderField: "Accept")
966
+ request.setValue("2", forHTTPHeaderField: "Pulse-Protocol-Version")
967
+ request.setValue("ios", forHTTPHeaderField: "X-Pulse-Platform")
968
+ request.setValue(config.runtimeVersion, forHTTPHeaderField: "X-Pulse-Runtime-Version")
969
+
970
+ if let channel = config.channel {
971
+ request.setValue(channel, forHTTPHeaderField: "X-Pulse-Channel-Name")
972
+ }
973
+
974
+ if let currentId = currentUpdateId {
975
+ request.setValue(currentId, forHTTPHeaderField: "X-Pulse-Current-Update-Id")
976
+ }
977
+
978
+ return request
979
+ }
980
+
981
+ private static func downloadUpdate(
982
+ manifest: PulseManifestModel,
983
+ config: PulseUpdatesConfig,
984
+ database: PulseDatabase?,
985
+ directory: URL,
986
+ completion: @escaping (Result<Void, Error>) -> Void
987
+ ) {
988
+ let updateId = manifest.updateId
989
+ let bundleHash = manifest.bundle.hash.lowercased()
990
+ let stagingDir = directory.appendingPathComponent("staging/\(updateId)")
991
+
992
+ // Create staging directory
993
+ try? FileManager.default.createDirectory(at: stagingDir, withIntermediateDirectories: true)
994
+
995
+ // Convert manifest to dictionary for storage
996
+ var manifestDict: [String: Any]?
997
+ if let data = try? JSONEncoder().encode(manifest),
998
+ let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
999
+ manifestDict = dict
1000
+ }
1001
+
1002
+ // Store update in database
1003
+ let update = PulseUpdate(
1004
+ updateId: updateId,
1005
+ scopeKey: config.scopeKey,
1006
+ runtimeVersion: manifest.runtimeVersion,
1007
+ commitTime: manifest.commitTime ?? Date(),
1008
+ status: .downloading,
1009
+ manifest: manifestDict,
1010
+ bundleHash: bundleHash,
1011
+ lastAccessed: Date(),
1012
+ successfulLaunchCount: 0,
1013
+ failedLaunchCount: 0
1014
+ )
1015
+
1016
+ try? database?.addUpdate(update)
1017
+
1018
+ // Download bundle
1019
+ downloadBundle(manifest: manifest, directory: directory, stagingDir: stagingDir, database: database, updateId: updateId) { bundleResult in
1020
+ switch bundleResult {
1021
+ case .failure(let error):
1022
+ try? database?.setStatus(.failed, forUpdateId: updateId)
1023
+ cleanupStaging(stagingDir)
1024
+ completion(.failure(error))
1025
+
1026
+ case .success:
1027
+ // Download assets
1028
+ downloadAssets(manifest: manifest, directory: directory, stagingDir: stagingDir, database: database, updateId: updateId) { assetsResult in
1029
+ switch assetsResult {
1030
+ case .failure(let error):
1031
+ try? database?.setStatus(.failed, forUpdateId: updateId)
1032
+ cleanupStaging(stagingDir)
1033
+ completion(.failure(error))
1034
+
1035
+ case .success:
1036
+ try? database?.setStatus(.ready, forUpdateId: updateId)
1037
+ cleanupStaging(stagingDir)
1038
+ pulseLog("Update \(updateId) downloaded and ready")
1039
+ completion(.success(()))
1040
+ }
1041
+ }
1042
+ }
1043
+ }
1044
+ }
1045
+
1046
+ private static func downloadBundle(
1047
+ manifest: PulseManifestModel,
1048
+ directory: URL,
1049
+ stagingDir: URL,
1050
+ database: PulseDatabase?,
1051
+ updateId: String,
1052
+ completion: @escaping (Result<Void, Error>) -> Void
1053
+ ) {
1054
+ let bundleHash = manifest.bundle.hash.lowercased()
1055
+ // Store bundle in assets directory (same as other assets) so launcher can find it
1056
+ let destination = directory.appendingPathComponent("assets/sha256/\(bundleHash)")
1057
+
1058
+ // Store bundle as launch asset in database
1059
+ func storeBundleInDatabase() {
1060
+ var dbAsset = PulseAsset(key: "bundle", hash: bundleHash)
1061
+ dbAsset.type = "application/javascript"
1062
+
1063
+ if let assetId = try? database?.addAsset(dbAsset) {
1064
+ try? database?.linkAsset(assetId: assetId, toUpdate: updateId, assetKey: "bundle", assetHash: bundleHash, isLaunchAsset: true)
1065
+ }
1066
+ }
1067
+
1068
+ // Already cached?
1069
+ if FileManager.default.fileExists(atPath: destination.path) {
1070
+ storeBundleInDatabase()
1071
+ completion(.success(()))
1072
+ return
1073
+ }
1074
+
1075
+ guard let url = URL(string: manifest.bundle.url) else {
1076
+ completion(.failure(PulseUpdatesError.downloadFailed(underlying: NSError(domain: "PulseUpdates", code: 1, userInfo: [NSLocalizedDescriptionKey: "Invalid bundle URL"]))))
1077
+ return
1078
+ }
1079
+
1080
+ let tempPath = stagingDir.appendingPathComponent("bundle.tmp")
1081
+
1082
+ downloadFile(from: url, to: tempPath) { result in
1083
+ switch result {
1084
+ case .failure(let error):
1085
+ completion(.failure(error))
1086
+ case .success:
1087
+ // Verify hash
1088
+ guard let fileHash = sha256Hex(fileUrl: tempPath), fileHash == bundleHash else {
1089
+ completion(.failure(PulseUpdatesError.hashMismatch(expected: bundleHash, actual: "unknown")))
1090
+ return
1091
+ }
1092
+
1093
+ // Move to final destination
1094
+ try? FileManager.default.createDirectory(at: destination.deletingLastPathComponent(), withIntermediateDirectories: true)
1095
+ try? FileManager.default.removeItem(at: destination)
1096
+ try? FileManager.default.moveItem(at: tempPath, to: destination)
1097
+
1098
+ // Store in database as launch asset
1099
+ storeBundleInDatabase()
1100
+
1101
+ completion(.success(()))
1102
+ }
1103
+ }
1104
+ }
1105
+
1106
+ private static func downloadAssets(
1107
+ manifest: PulseManifestModel,
1108
+ directory: URL,
1109
+ stagingDir: URL,
1110
+ database: PulseDatabase?,
1111
+ updateId: String,
1112
+ completion: @escaping (Result<Void, Error>) -> Void
1113
+ ) {
1114
+ let assets = manifest.assets
1115
+ guard !assets.isEmpty else {
1116
+ completion(.success(()))
1117
+ return
1118
+ }
1119
+
1120
+ let group = DispatchGroup()
1121
+ var downloadError: Error?
1122
+
1123
+ for asset in assets {
1124
+ group.enter()
1125
+
1126
+ let assetHash = asset.hash.lowercased()
1127
+ let destination = directory.appendingPathComponent("assets/sha256/\(assetHash)")
1128
+
1129
+ // Already cached?
1130
+ if FileManager.default.fileExists(atPath: destination.path) {
1131
+ // Link to update
1132
+ storeAssetInDatabase(asset: asset, hash: assetHash, database: database, updateId: updateId)
1133
+ group.leave()
1134
+ continue
1135
+ }
1136
+
1137
+ guard let url = URL(string: asset.url) else {
1138
+ group.leave()
1139
+ continue
1140
+ }
1141
+
1142
+ let tempPath = stagingDir.appendingPathComponent("asset-\(assetHash).tmp")
1143
+
1144
+ downloadFile(from: url, to: tempPath) { result in
1145
+ switch result {
1146
+ case .failure(let error):
1147
+ downloadError = error
1148
+ case .success:
1149
+ // Verify hash
1150
+ if let fileHash = sha256Hex(fileUrl: tempPath), fileHash == assetHash {
1151
+ try? FileManager.default.createDirectory(at: destination.deletingLastPathComponent(), withIntermediateDirectories: true)
1152
+ try? FileManager.default.removeItem(at: destination)
1153
+ try? FileManager.default.moveItem(at: tempPath, to: destination)
1154
+
1155
+ storeAssetInDatabase(asset: asset, hash: assetHash, database: database, updateId: updateId)
1156
+ } else {
1157
+ downloadError = PulseUpdatesError.hashMismatch(expected: assetHash, actual: "unknown")
1158
+ }
1159
+ }
1160
+ group.leave()
1161
+ }
1162
+ }
1163
+
1164
+ group.notify(queue: .global(qos: .userInitiated)) {
1165
+ if let error = downloadError {
1166
+ completion(.failure(error))
1167
+ } else {
1168
+ completion(.success(()))
1169
+ }
1170
+ }
1171
+ }
1172
+
1173
+ private static func storeAssetInDatabase(asset: PulseAssetModel, hash: String, database: PulseDatabase?, updateId: String) {
1174
+ var dbAsset = PulseAsset(key: asset.key, hash: hash)
1175
+ dbAsset.type = asset.contentType
1176
+ dbAsset.nsBundleDir = asset.nsBundleDir
1177
+ dbAsset.nsBundleFilename = asset.nsBundleFilename
1178
+
1179
+ if let assetId = try? database?.addAsset(dbAsset) {
1180
+ try? database?.linkAsset(assetId: assetId, toUpdate: updateId, assetKey: asset.key, assetHash: hash, isLaunchAsset: false)
1181
+ }
1182
+ }
1183
+
1184
+ private static func downloadFile(from url: URL, to destination: URL, completion: @escaping (Result<Void, Error>) -> Void) {
1185
+ URLSession.shared.downloadTask(with: url) { tempUrl, response, error in
1186
+ if let error = error {
1187
+ completion(.failure(PulseUpdatesError.downloadFailed(underlying: error)))
1188
+ return
1189
+ }
1190
+
1191
+ if let httpResponse = response as? HTTPURLResponse,
1192
+ httpResponse.statusCode < 200 || httpResponse.statusCode >= 300 {
1193
+ completion(.failure(PulseUpdatesError.downloadFailed(underlying: NSError(domain: "HTTP", code: httpResponse.statusCode, userInfo: nil))))
1194
+ return
1195
+ }
1196
+
1197
+ guard let tempUrl = tempUrl else {
1198
+ completion(.failure(PulseUpdatesError.downloadFailed(underlying: NSError(domain: "PulseUpdates", code: 0, userInfo: [NSLocalizedDescriptionKey: "No download file"]))))
1199
+ return
1200
+ }
1201
+
1202
+ do {
1203
+ try? FileManager.default.removeItem(at: destination)
1204
+ try? FileManager.default.createDirectory(at: destination.deletingLastPathComponent(), withIntermediateDirectories: true)
1205
+ try FileManager.default.moveItem(at: tempUrl, to: destination)
1206
+ completion(.success(()))
1207
+ } catch {
1208
+ completion(.failure(PulseUpdatesError.downloadFailed(underlying: error)))
1209
+ }
1210
+ }.resume()
1211
+ }
1212
+
1213
+ private static func cleanupStaging(_ dir: URL) {
1214
+ try? FileManager.default.removeItem(at: dir)
1215
+ }
1216
+
1217
+ private static func sha256Hex(fileUrl: URL) -> String? {
1218
+ guard let handle = try? FileHandle(forReadingFrom: fileUrl) else { return nil }
1219
+ defer { try? handle.close() }
1220
+
1221
+ var hasher = SHA256()
1222
+ while true {
1223
+ let data = try? handle.read(upToCount: 1024 * 1024)
1224
+ guard let chunk = data, !chunk.isEmpty else { break }
1225
+ hasher.update(data: chunk)
1226
+ }
1227
+ let digest = hasher.finalize()
1228
+ return digest.map { String(format: "%02x", $0) }.joined()
1229
+ }
1230
+
1231
+ private static func verifyManifestSignature(manifest: PulseManifestModel, manifestJson: Data, config: PulseUpdatesConfig) -> Bool {
1232
+ guard let signature = manifest.signature else { return false }
1233
+ guard signature.alg.lowercased() == "ed25519" else { return false }
1234
+ guard let keyId = config.signingKeyId, signature.keyId == keyId else { return false }
1235
+ guard let publicKeyBase64 = config.signingPublicKey,
1236
+ let publicKeyData = Data(base64Encoded: publicKeyBase64),
1237
+ let signatureData = Data(base64Encoded: signature.sig) else { return false }
1238
+
1239
+ let canonical = canonicalizeManifestJson(manifestJson)
1240
+
1241
+ guard let publicKey = try? Curve25519.Signing.PublicKey(rawRepresentation: publicKeyData) else { return false }
1242
+ return publicKey.isValidSignature(signatureData, for: canonical)
1243
+ }
1244
+
1245
+ private static func canonicalizeManifestJson(_ data: Data) -> Data {
1246
+ guard let json = try? JSONSerialization.jsonObject(with: data),
1247
+ var dict = json as? [String: Any] else { return data }
1248
+
1249
+ dict.removeValue(forKey: "signature")
1250
+ let canonical = canonicalizeJson(dict)
1251
+ return canonical.data(using: .utf8) ?? data
1252
+ }
1253
+
1254
+ private static func canonicalizeJson(_ value: Any) -> String {
1255
+ if let dict = value as? [String: Any] {
1256
+ let keys = dict.keys.sorted()
1257
+ let items = keys.compactMap { key -> String? in
1258
+ guard let val = dict[key] else { return nil }
1259
+ return "\"\(escapeJson(key))\":\(canonicalizeJson(val))"
1260
+ }
1261
+ return "{\(items.joined(separator: ","))}"
1262
+ }
1263
+
1264
+ if let array = value as? [Any] {
1265
+ return "[\(array.map { canonicalizeJson($0) }.joined(separator: ","))]"
1266
+ }
1267
+
1268
+ if value is NSNull { return "null" }
1269
+
1270
+ if let number = value as? NSNumber {
1271
+ if CFGetTypeID(number) == CFBooleanGetTypeID() {
1272
+ return number.boolValue ? "true" : "false"
1273
+ }
1274
+ return number.stringValue
1275
+ }
1276
+
1277
+ if let string = value as? String {
1278
+ return "\"\(escapeJson(string))\""
1279
+ }
1280
+
1281
+ return "null"
1282
+ }
1283
+
1284
+ private static func escapeJson(_ input: String) -> String {
1285
+ var result = ""
1286
+ for char in input {
1287
+ switch char {
1288
+ case "\"": result += "\\\""
1289
+ case "\\": result += "\\\\"
1290
+ case "\n": result += "\\n"
1291
+ case "\r": result += "\\r"
1292
+ case "\t": result += "\\t"
1293
+ default:
1294
+ if char.asciiValue ?? 0 < 32 {
1295
+ result += String(format: "\\u%04x", char.asciiValue ?? 0)
1296
+ } else {
1297
+ result.append(char)
1298
+ }
1299
+ }
1300
+ }
1301
+ return result
1302
+ }
1303
+ }
1304
+
1305
+ // MARK: - Error Recovery Delegate
1306
+
1307
+ extension PulseController: PulseErrorRecoveryDelegate {
1308
+
1309
+ func getLaunchedUpdate() -> PulseUpdateInfo? {
1310
+ return self.launchedUpdate
1311
+ }
1312
+
1313
+ var checkOnLaunch: String {
1314
+ return config?.checkOnLaunch ?? "ALWAYS"
1315
+ }
1316
+
1317
+ func relaunch(completion: @escaping (Error?, Bool) -> Void) {
1318
+ // Try to launch a different update from cache
1319
+ launchBestUpdate { success in
1320
+ if success {
1321
+ // Trigger a reload of React Native
1322
+ NotificationCenter.default.post(
1323
+ name: NSNotification.Name("PulseUpdatesReloadRequest"),
1324
+ object: nil
1325
+ )
1326
+ }
1327
+ completion(nil, success)
1328
+ }
1329
+ }
1330
+
1331
+ func loadRemoteUpdate() {
1332
+ remoteLoadStatus = .loading
1333
+ fetchUpdate { [weak self] result in
1334
+ switch result {
1335
+ case .success(let fetchResult):
1336
+ self?.remoteLoadStatus = fetchResult.isNew ? .newUpdateLoaded : .idle
1337
+ case .failure:
1338
+ self?.remoteLoadStatus = .idle
1339
+ }
1340
+ self?.errorRecovery?.notify(newRemoteLoadStatus: self?.remoteLoadStatus ?? .idle)
1341
+ }
1342
+ }
1343
+
1344
+ func markFailedLaunchForLaunchedUpdate() {
1345
+ guard let updateId = launchedUpdate?.updateId else { return }
1346
+ try? database?.recordFailedLaunch(updateId: updateId)
1347
+ }
1348
+
1349
+ func markSuccessfulLaunchForLaunchedUpdate() {
1350
+ guard let updateId = launchedUpdate?.updateId else { return }
1351
+ try? database?.recordSuccessfulLaunch(updateId: updateId)
1352
+ }
1353
+
1354
+ func throwException(_ exception: NSException) {
1355
+ exception.raise()
1356
+ }
1357
+ }
1358
+
1359
+ import CryptoKit