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,1419 @@
1
+ package app.pulse.updates
2
+
3
+ import android.content.Context
4
+ import app.pulse.updates.database.PulseAsset
5
+ import app.pulse.updates.database.PulseDatabase
6
+ import app.pulse.updates.database.PulseUpdate
7
+ import app.pulse.updates.database.PulseUpdateStatus
8
+ import app.pulse.updates.launcher.PulseAppLauncher
9
+ import app.pulse.updates.launcher.PulseDefaultSelectionPolicy
10
+ import app.pulse.updates.launcher.PulseSelectionPolicy
11
+ import app.pulse.updates.launcher.PulseUpdateInfo
12
+ import app.pulse.updates.launcher.EmbeddedManifest
13
+ import app.pulse.updates.errorrecovery.PulseErrorRecovery
14
+ import app.pulse.updates.errorrecovery.PulseErrorRecoveryDelegate
15
+ import org.json.JSONObject
16
+ import java.io.File
17
+ import java.net.URL
18
+ import java.security.MessageDigest
19
+ import java.util.Date
20
+ import java.util.concurrent.Executors
21
+
22
+ // Logging - always prints for debugging OTA issues
23
+ // Debug flag - set via PULSE_DEBUG environment variable or BuildConfig
24
+ internal var PULSE_DEBUG: Boolean = System.getenv("PULSE_DEBUG")?.toBoolean() ?: false
25
+
26
+ internal fun pulseLog(tag: String, message: String) {
27
+ if (PULSE_DEBUG) {
28
+ println("[$tag] $message")
29
+ }
30
+ }
31
+
32
+ internal fun pulseLogWarn(tag: String, message: String) {
33
+ if (PULSE_DEBUG) {
34
+ println("[$tag] WARN: $message")
35
+ }
36
+ }
37
+
38
+ internal fun pulseLogError(tag: String, message: String) {
39
+ // Always log errors
40
+ println("[$tag] ERROR: $message")
41
+ }
42
+
43
+ /**
44
+ * PulseUpdates Controller
45
+ * Based on expo-updates AppController
46
+ * Main controller that orchestrates update lifecycle
47
+ */
48
+ class PulseController private constructor() {
49
+
50
+ companion object {
51
+ private const val TAG = "PulseController"
52
+
53
+ @Volatile
54
+ private var instance: PulseController? = null
55
+
56
+ fun getInstance(): PulseController {
57
+ return instance ?: synchronized(this) {
58
+ instance ?: PulseController().also { instance = it }
59
+ }
60
+ }
61
+ }
62
+
63
+ interface Delegate {
64
+ fun onStarted(success: Boolean)
65
+ }
66
+
67
+ // Public properties
68
+ var delegate: Delegate? = null
69
+ var isActive: Boolean = false
70
+ private set
71
+ var isStarted: Boolean = false
72
+ private set
73
+ var config: PulseUpdatesConfig? = null
74
+ private set
75
+ var launchedUpdate: PulseUpdateInfo? = null
76
+ private set
77
+ var isEmbeddedLaunch: Boolean = true
78
+ private set
79
+ var launchAssetFile: File? = null
80
+ private set
81
+ var localAssets: Map<String, String> = emptyMap()
82
+ private set
83
+
84
+ // The manifest JSON for the launched update (for metadata like build number)
85
+ var launchedManifestJson: String? = null
86
+ private set
87
+
88
+ // Error recovery
89
+ var errorRecovery: PulseErrorRecovery? = null
90
+ private set
91
+ var remoteLoadStatus: PulseErrorRecoveryDelegate.RemoteLoadStatus = PulseErrorRecoveryDelegate.RemoteLoadStatus.IDLE
92
+ private set
93
+
94
+ // Private properties
95
+ private var context: Context? = null
96
+ private var database: PulseDatabase? = null
97
+ private var launcher: PulseAppLauncher? = null
98
+ private var directory: File? = null
99
+ private var embeddedManifest: EmbeddedManifest? = null
100
+ private val executor = Executors.newSingleThreadExecutor()
101
+
102
+ // Native runtime version (from config, embedded manifest, or app version)
103
+ private val nativeRuntimeVersion: String
104
+ get() {
105
+ // Use config if available
106
+ config?.runtimeVersion?.let { return it }
107
+
108
+ // Try embedded manifest
109
+ embeddedManifest?.runtimeVersion?.let { return it }
110
+
111
+ // Fall back to app version
112
+ return try {
113
+ val ctx = context ?: return "unknown"
114
+ val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
115
+ packageInfo.versionName ?: packageInfo.versionCode.toString()
116
+ } catch (e: Exception) {
117
+ "unknown"
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Load config from AndroidManifest.xml metadata (like expo-updates)
123
+ */
124
+ private fun loadNativeConfig(): PulseUpdatesConfig? {
125
+ val ctx = context ?: return null
126
+
127
+ try {
128
+ val appInfo = ctx.packageManager.getApplicationInfo(
129
+ ctx.packageName,
130
+ android.content.pm.PackageManager.GET_META_DATA
131
+ )
132
+ val metadata = appInfo.metaData ?: return null
133
+
134
+ // Check if PulseUpdates is configured
135
+ val updateUrl = metadata.getString("PulseUpdatesURL")
136
+ if (updateUrl.isNullOrEmpty()) {
137
+ pulseLog(TAG, "No PulseUpdatesURL in AndroidManifest.xml, native config disabled")
138
+ return null
139
+ }
140
+
141
+ val enabled = metadata.getBoolean("PulseUpdatesEnabled", true)
142
+
143
+ // Runtime version: embedded manifest > versionName
144
+ val runtimeVersion = embeddedManifest?.runtimeVersion
145
+ ?: try {
146
+ val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
147
+ packageInfo.versionName ?: packageInfo.versionCode.toString()
148
+ } catch (e: Exception) {
149
+ "unknown"
150
+ }
151
+
152
+ return PulseUpdatesConfig(
153
+ enabled = enabled,
154
+ updateUrl = updateUrl,
155
+ runtimeVersion = runtimeVersion,
156
+ checkOnLaunch = metadata.getString("PulseUpdatesCheckOnLaunch") ?: "ALWAYS",
157
+ launchWaitMs = metadata.getInt("PulseUpdatesLaunchWaitMs", 0),
158
+ channel = metadata.getString("PulseUpdatesChannel"),
159
+ signingKeyId = metadata.getString("PulseUpdatesSigningKeyId"),
160
+ signingPublicKey = metadata.getString("PulseUpdatesSigningPublicKey")
161
+ )
162
+ } catch (e: Exception) {
163
+ pulseLogWarn(TAG, "Failed to load native config: ${e.message}")
164
+ return null
165
+ }
166
+ }
167
+
168
+ // MARK: - Public API
169
+
170
+ /**
171
+ * Initialize context and directory without full config
172
+ * Called by getBundleFile before JS starts
173
+ */
174
+ fun initializeContext(context: Context) {
175
+ if (this.context == null) {
176
+ this.context = context.applicationContext
177
+ this.directory = File(context.filesDir, "pulse")
178
+ }
179
+ }
180
+
181
+ fun configure(context: Context, config: PulseUpdatesConfig) {
182
+ this.context = context.applicationContext
183
+ this.config = config
184
+ this.isActive = config.enabled
185
+ this.directory = File(context.filesDir, "pulse")
186
+ }
187
+
188
+ fun initializeWithoutStarting() {
189
+ if (isStarted) return
190
+
191
+ createDirectories()
192
+ initializeDatabase()
193
+ loadEmbeddedManifest()
194
+
195
+ // Load native config from AndroidManifest.xml if not already configured by JS
196
+ if (config == null) {
197
+ config = loadNativeConfig()
198
+ config?.let { cfg ->
199
+ isActive = cfg.enabled
200
+ pulseLog(TAG, "Loaded native config: url=${cfg.updateUrl} runtime=${cfg.runtimeVersion}")
201
+ }
202
+ }
203
+
204
+ seedEmbeddedUpdateIfNeeded()
205
+ runIntegrityCheck()
206
+
207
+ // Synchronously select the best update for launch
208
+ selectBestUpdateSync()
209
+ }
210
+
211
+ // Synchronously select the best update (used for initial launch before JS starts)
212
+ private fun selectBestUpdateSync() {
213
+ val db = database
214
+ // Use config.runtimeVersion if available, otherwise fall back to native
215
+ val runtimeVersion = config?.runtimeVersion ?: nativeRuntimeVersion
216
+
217
+ pulseLog(TAG, "selectBestUpdateSync: database=${db != null} runtimeVersion=$runtimeVersion")
218
+
219
+ if (db == null) {
220
+ pulseLog(TAG, "selectBestUpdateSync: no database")
221
+ return
222
+ }
223
+
224
+ try {
225
+ val updates = db.launchableUpdates(runtimeVersion)
226
+ pulseLog(TAG, "selectBestUpdateSync: found ${updates.size} updates")
227
+
228
+ val policy = PulseDefaultSelectionPolicy()
229
+ val selectedUpdate = policy.selectUpdateToLaunch(updates)
230
+
231
+ if (selectedUpdate == null) {
232
+ pulseLog(TAG, "selectBestUpdateSync: no update selected")
233
+ return
234
+ }
235
+
236
+ pulseLog(TAG, "selectBestUpdateSync: selected ${selectedUpdate.updateId} status=${selectedUpdate.status} bundleHash=${selectedUpdate.bundleHash}")
237
+
238
+ // Set the launch file based on selected update
239
+ if (selectedUpdate.status == PulseUpdateStatus.EMBEDDED) {
240
+ // For embedded bundles, DON'T set launchAssetFile
241
+ // Let React Native use its default bundle loading mechanism
242
+ // This ensures images from drawable folders are resolved correctly
243
+ launchAssetFile = null
244
+ isEmbeddedLaunch = true
245
+ // For embedded, localAssets can be empty - React Native handles it
246
+ localAssets = emptyMap()
247
+ pulseLog(TAG, "selectBestUpdateSync: using embedded bundle (default RN loading)")
248
+ } else if (selectedUpdate.bundleHash != null) {
249
+ val bundlePath = File(directory, "assets/sha256/${selectedUpdate.bundleHash.lowercase()}")
250
+ val exists = bundlePath.exists()
251
+ pulseLog(TAG, "selectBestUpdateSync: bundlePath exists=$exists")
252
+
253
+ if (exists) {
254
+ launchAssetFile = bundlePath
255
+ isEmbeddedLaunch = false
256
+
257
+ // Set launchedUpdate info
258
+ launchedUpdate = PulseUpdateInfo(
259
+ updateId = selectedUpdate.updateId,
260
+ runtimeVersion = selectedUpdate.runtimeVersion,
261
+ commitTime = selectedUpdate.commitTime.time,
262
+ status = selectedUpdate.status,
263
+ successfulLaunchCount = selectedUpdate.successfulLaunchCount,
264
+ failedLaunchCount = selectedUpdate.failedLaunchCount,
265
+ isEmbedded = selectedUpdate.isEmbedded,
266
+ bundleHash = selectedUpdate.bundleHash,
267
+ scopeKey = selectedUpdate.scopeKey
268
+ )
269
+
270
+ // Load manifest from database for metadata (build number, etc.)
271
+ selectedUpdate.manifest?.let { manifest ->
272
+ launchedManifestJson = manifest.toString()
273
+ pulseLog(TAG, "selectBestUpdateSync: loaded manifest json")
274
+ }
275
+
276
+ // Build localAssets: downloaded assets + embedded fallbacks
277
+ localAssets = buildLocalAssetsForUpdate(selectedUpdate.updateId, db)
278
+ pulseLog(TAG, "selectBestUpdateSync: set launchAssetFile to downloaded bundle, localAssets count=${localAssets.size}")
279
+ }
280
+ }
281
+ } catch (e: Exception) {
282
+ pulseLogError(TAG, "selectBestUpdateSync error: ${e.message}")
283
+ }
284
+ }
285
+
286
+ // Build localAssets map from embedded manifest for fallback
287
+ // Store BOTH hash AND path-based keys for maximum compatibility:
288
+ // - hash: for SHA256 hash lookup
289
+ // - path: for Metro path-based lookup (httpServerLocation/name.type)
290
+ private fun buildEmbeddedLocalAssets(): Map<String, String> {
291
+ val ctx = context ?: return emptyMap()
292
+ val manifest = embeddedManifest ?: return emptyMap()
293
+
294
+ val assets = mutableMapOf<String, String>()
295
+
296
+ for (asset in manifest.assets) {
297
+ if (asset.isLaunchAsset) continue
298
+
299
+ // Try to find the asset in the assets folder
300
+ val assetPath = asset.mainBundleFilename?.let { filename ->
301
+ val dir = asset.mainBundleDir
302
+ if (dir != null && dir.isNotEmpty()) {
303
+ "$dir/$filename"
304
+ } else {
305
+ filename
306
+ }
307
+ }
308
+
309
+ if (assetPath != null) {
310
+ try {
311
+ // Verify the asset exists
312
+ ctx.assets.open(assetPath).close()
313
+ val localUri = "asset:///$assetPath"
314
+
315
+ // Store by manifest key (MD5 hash - matches how expo-asset looks up)
316
+ asset.key?.let { key ->
317
+ assets[key] = localUri
318
+ }
319
+
320
+ // Also store by SHA256 hash for fallback
321
+ assets[asset.hash] = localUri
322
+ } catch (e: Exception) {
323
+ // Asset doesn't exist in bundle
324
+ }
325
+ }
326
+ }
327
+
328
+ pulseLog(TAG, "buildEmbeddedLocalAssets: found ${assets.size} entries")
329
+ return assets
330
+ }
331
+
332
+ // Build localAssets map for an OTA update (downloaded + embedded fallbacks)
333
+ // Store BOTH hash AND path-based keys for maximum compatibility
334
+ private fun buildLocalAssetsForUpdate(updateId: String, database: PulseDatabase): Map<String, String> {
335
+ // Start with embedded assets as base (fallback)
336
+ val assets = buildEmbeddedLocalAssets().toMutableMap()
337
+ pulseLog(TAG, "buildLocalAssetsForUpdate: embedded base count=${assets.size}")
338
+
339
+ val dir = directory ?: return assets
340
+
341
+ // Get downloaded assets for this update from database
342
+ try {
343
+ val updateAssets = database.assetsForUpdate(updateId)
344
+ pulseLog(TAG, "buildLocalAssetsForUpdate: found ${updateAssets.size} assets in database for update $updateId")
345
+
346
+ for (asset in updateAssets) {
347
+ if (asset.isLaunchAsset) continue
348
+
349
+ // Check if downloaded asset exists (stored by SHA256 hash)
350
+ val downloadedPath = File(dir, "assets/sha256/${asset.hash.lowercase()}")
351
+ if (downloadedPath.exists()) {
352
+ val localUri = "file://${downloadedPath.absolutePath}"
353
+
354
+ // Store by manifest key (MD5 hash - matches how expo-asset looks up)
355
+ asset.key?.let { key ->
356
+ assets[key] = localUri
357
+ }
358
+
359
+ // Also store by SHA256 hash for fallback
360
+ assets[asset.hash] = localUri
361
+ } else {
362
+ // Downloaded file doesn't exist - use embedded fallback
363
+ // BUT we still need to add the MD5 key from OTA manifest pointing to the embedded asset!
364
+ // The embedded map has path-based keys, but JS looks up by MD5 hash
365
+ val embeddedUri = assets[asset.hash] // Try SHA256 hash (embedded has both hash and path keys)
366
+ if (embeddedUri != null && asset.key != null) {
367
+ // Add MD5 key pointing to embedded asset
368
+ assets[asset.key!!] = embeddedUri
369
+ pulseLog(TAG, "buildLocalAssetsForUpdate: using embedded fallback for key=${asset.key?.take(16)}... hash=${asset.hash.take(16)}...")
370
+ } else {
371
+ pulseLogWarn(TAG, "buildLocalAssetsForUpdate: file not found AND no embedded fallback for hash=${asset.hash.take(16)}...")
372
+ }
373
+ }
374
+ }
375
+ } catch (e: Exception) {
376
+ pulseLogError(TAG, "buildLocalAssetsForUpdate error: ${e.message}")
377
+ }
378
+
379
+ return assets
380
+ }
381
+
382
+ fun start() {
383
+ if (isStarted) return
384
+ isStarted = true
385
+
386
+ pulseLog(TAG, "Starting controller")
387
+
388
+ createDirectories()
389
+ initializeDatabase()
390
+ loadEmbeddedManifest()
391
+
392
+ // Load native config from AndroidManifest.xml if not already configured by JS
393
+ if (config == null) {
394
+ config = loadNativeConfig()
395
+ config?.let { cfg ->
396
+ isActive = cfg.enabled
397
+ pulseLog(TAG, "Loaded native config: url=${cfg.updateUrl} runtime=${cfg.runtimeVersion}")
398
+ }
399
+ }
400
+
401
+ seedEmbeddedUpdateIfNeeded()
402
+ runIntegrityCheck()
403
+
404
+ // Initialize error recovery
405
+ errorRecovery = PulseErrorRecovery().also {
406
+ it.initialize(errorRecoveryDelegate)
407
+ it.startMonitoring()
408
+ }
409
+
410
+ // Launch best available update
411
+ launchBestUpdate { success ->
412
+ if (success) {
413
+ pulseLog(TAG, "Started successfully with update: ${launchedUpdate?.updateId ?: "embedded"}")
414
+ } else {
415
+ pulseLogWarn(TAG, "Failed to start, falling back to embedded")
416
+ launchEmbedded()
417
+ }
418
+
419
+ delegate?.onStarted(success || launchAssetFile != null)
420
+
421
+ // Check for updates on launch based on config
422
+ performCheckOnLaunchIfNeeded()
423
+ }
424
+ }
425
+
426
+ // MARK: - Check on Launch
427
+
428
+ private fun performCheckOnLaunchIfNeeded() {
429
+ val cfg = config ?: return
430
+ if (!cfg.enabled) return
431
+
432
+ when (cfg.checkOnLaunch.uppercase()) {
433
+ "NEVER" -> {
434
+ pulseLog(TAG, "checkOnLaunch is NEVER, skipping automatic check")
435
+ return
436
+ }
437
+ "WIFI_ONLY" -> {
438
+ if (!isOnWifi()) {
439
+ pulseLog(TAG, "checkOnLaunch is WIFI_ONLY but not on WiFi, skipping")
440
+ return
441
+ }
442
+ }
443
+ }
444
+
445
+ // Wait for launchWaitMs before checking
446
+ val waitMs = cfg.launchWaitMs.toLong()
447
+ executor.execute {
448
+ if (waitMs > 0) {
449
+ Thread.sleep(waitMs)
450
+ }
451
+ performBackgroundUpdateCheck()
452
+ }
453
+ }
454
+
455
+ private fun performBackgroundUpdateCheck() {
456
+ pulseLog(TAG, "Performing background update check")
457
+
458
+ checkForUpdate { result ->
459
+ result.fold(
460
+ onSuccess = { checkResult ->
461
+ if (checkResult.isAvailable) {
462
+ pulseLog(TAG, "Background check: update available, fetching...")
463
+ fetchUpdate { fetchResult ->
464
+ fetchResult.fold(
465
+ onSuccess = { fetch ->
466
+ if (fetch.isNew) {
467
+ pulseLog(TAG, "Background check: update downloaded and ready")
468
+ // Could emit event to JS here
469
+ }
470
+ },
471
+ onFailure = { error ->
472
+ pulseLogWarn(TAG, "Background check: fetch failed - ${error.message}")
473
+ }
474
+ )
475
+ }
476
+ } else {
477
+ pulseLog(TAG, "Background check: no update available")
478
+ }
479
+ },
480
+ onFailure = { error ->
481
+ pulseLogWarn(TAG, "Background check failed: ${error.message}")
482
+ }
483
+ )
484
+ }
485
+ }
486
+
487
+ private fun isOnWifi(): Boolean {
488
+ val ctx = context ?: return false
489
+ val connectivityManager = ctx.getSystemService(Context.CONNECTIVITY_SERVICE) as? android.net.ConnectivityManager
490
+ ?: return false
491
+
492
+ val network = connectivityManager.activeNetwork ?: return false
493
+ val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
494
+ return capabilities.hasTransport(android.net.NetworkCapabilities.TRANSPORT_WIFI)
495
+ }
496
+
497
+ fun getBundleFile(): File? {
498
+ // Only return a custom bundle path if we have a downloaded OTA update
499
+ // For embedded bundles, return null to let React Native use its default mechanism
500
+ // This ensures images from drawable folders work correctly
501
+ val launchFile = launchAssetFile
502
+ if (launchFile != null && launchFile.exists()) {
503
+ return launchFile
504
+ }
505
+ // Return null to use default bundle loading (from APK assets)
506
+ return null
507
+ }
508
+
509
+ fun checkForUpdate(callback: (Result<CheckResult>) -> Unit) {
510
+ val cfg = config
511
+ if (cfg == null) {
512
+ callback(Result.failure(PulseUpdatesException("Not configured")))
513
+ return
514
+ }
515
+
516
+ if (!cfg.enabled) {
517
+ callback(Result.failure(PulseUpdatesException("Updates not enabled")))
518
+ return
519
+ }
520
+
521
+ executor.execute {
522
+ PulseRemoteLoader.checkForUpdate(cfg, launchedUpdate?.updateId, callback)
523
+ }
524
+ }
525
+
526
+ fun fetchUpdate(callback: (Result<FetchResult>) -> Unit) {
527
+ val cfg = config
528
+ val ctx = context
529
+ val dir = directory
530
+
531
+ if (cfg == null || ctx == null || dir == null) {
532
+ callback(Result.failure(PulseUpdatesException("Not configured")))
533
+ return
534
+ }
535
+
536
+ if (!cfg.enabled) {
537
+ callback(Result.failure(PulseUpdatesException("Updates not enabled")))
538
+ return
539
+ }
540
+
541
+ executor.execute {
542
+ PulseRemoteLoader.fetchUpdate(cfg, database, dir, callback)
543
+ }
544
+ }
545
+
546
+ fun reload(callback: (Boolean) -> Unit) {
547
+ // Re-select the best update before reloading
548
+ launchBestUpdate { success ->
549
+ pulseLog(TAG, "Reload: launchBestUpdate success=$success")
550
+ callback(success)
551
+ }
552
+ }
553
+
554
+ fun markAppReady() {
555
+ launchedUpdate?.let { update ->
556
+ try {
557
+ database?.recordSuccessfulLaunch(update.updateId)
558
+ } catch (e: Exception) {
559
+ pulseLogWarn(TAG, "Failed to record successful launch: ${e.message}")
560
+ }
561
+ }
562
+
563
+ // Run reaper after successful launch
564
+ runReaper()
565
+ }
566
+
567
+ fun reportLaunchFailure(reason: String) {
568
+ launchedUpdate?.let { update ->
569
+ try {
570
+ database?.recordFailedLaunch(update.updateId)
571
+ } catch (e: Exception) {
572
+ pulseLogWarn(TAG, "Failed to record launch failure: ${e.message}")
573
+ }
574
+ }
575
+ }
576
+
577
+ // MARK: - Private Methods
578
+
579
+ private fun createDirectories() {
580
+ val dir = directory ?: return
581
+ listOf(
582
+ dir,
583
+ File(dir, "updates"),
584
+ File(dir, "assets/sha256"),
585
+ File(dir, "bundles/sha256"),
586
+ File(dir, "staging")
587
+ ).forEach { it.mkdirs() }
588
+ }
589
+
590
+ private fun initializeDatabase() {
591
+ val ctx = context ?: return
592
+ val dir = directory ?: return
593
+
594
+ try {
595
+ database = PulseDatabase(ctx, dir)
596
+ pulseLog(TAG, "Database initialized")
597
+ } catch (e: Exception) {
598
+ pulseLogError(TAG, "Failed to initialize database: ${e.message}")
599
+ }
600
+ }
601
+
602
+ private fun loadEmbeddedManifest() {
603
+ val ctx = context ?: return
604
+
605
+ try {
606
+ val json = ctx.assets.open("embedded-manifest.json").bufferedReader().use { it.readText() }
607
+ embeddedManifest = EmbeddedManifest.fromJson(json)
608
+ pulseLog(TAG, "Loaded embedded manifest: ${embeddedManifest?.updateId}")
609
+ } catch (e: Exception) {
610
+ pulseLog(TAG, "No embedded manifest found")
611
+ }
612
+ }
613
+
614
+ private fun seedEmbeddedUpdateIfNeeded() {
615
+ val embedded = embeddedManifest ?: return
616
+ val db = database ?: return
617
+
618
+ val embeddedId = "embedded:${embedded.updateId}"
619
+
620
+ // Check if already seeded
621
+ try {
622
+ if (db.getUpdate(embeddedId) != null) return
623
+ } catch (e: Exception) {
624
+ // Continue to seed
625
+ }
626
+
627
+ // Get embedded bundle hash
628
+ val bundleHash = embedded.assets.find { it.isLaunchAsset }?.hash?.lowercase()
629
+
630
+ // scopeKey from config is optional - may be nil before JS configures us
631
+ val update = PulseUpdate(
632
+ updateId = embeddedId,
633
+ scopeKey = config?.scopeKey ?: "default",
634
+ runtimeVersion = embedded.runtimeVersion,
635
+ commitTime = Date(embedded.commitTime),
636
+ status = PulseUpdateStatus.EMBEDDED,
637
+ manifest = null,
638
+ bundleHash = bundleHash,
639
+ lastAccessed = Date(),
640
+ successfulLaunchCount = 0,
641
+ failedLaunchCount = 0
642
+ )
643
+
644
+ try {
645
+ db.addUpdate(update)
646
+ pulseLog(TAG, "Seeded embedded update: $embeddedId")
647
+ } catch (e: Exception) {
648
+ pulseLogWarn(TAG, "Failed to seed embedded update: ${e.message}")
649
+ }
650
+ }
651
+
652
+ private fun runIntegrityCheck() {
653
+ val db = database ?: return
654
+ val currentEmbeddedId = embeddedManifest?.let { "embedded:${it.updateId}" }
655
+
656
+ executor.execute {
657
+ PulseIntegrityCheck.run(db, directory!!, currentEmbeddedId)
658
+ }
659
+ }
660
+
661
+ private fun launchBestUpdate(callback: (Boolean) -> Unit) {
662
+ val db = database ?: run {
663
+ callback(false)
664
+ return
665
+ }
666
+ val cfg = config ?: run {
667
+ callback(false)
668
+ return
669
+ }
670
+ val ctx = context ?: run {
671
+ callback(false)
672
+ return
673
+ }
674
+ val dir = directory ?: run {
675
+ callback(false)
676
+ return
677
+ }
678
+
679
+ val launcher = PulseAppLauncher(
680
+ context = ctx,
681
+ database = db,
682
+ directory = dir,
683
+ selectionPolicy = PulseDefaultSelectionPolicy(),
684
+ runtimeVersion = cfg.runtimeVersion
685
+ )
686
+
687
+ this.launcher = launcher
688
+
689
+ launcher.launch { success, error ->
690
+ if (success) {
691
+ launchAssetFile = launcher.launchAssetFile
692
+ localAssets = launcher.assetFilesMap
693
+ isEmbeddedLaunch = launcher.isUsingEmbeddedAssets
694
+
695
+ launcher.launchedUpdate?.let { update ->
696
+ launchedUpdate = PulseUpdateInfo(
697
+ updateId = update.updateId,
698
+ runtimeVersion = update.runtimeVersion,
699
+ commitTime = update.commitTime.time,
700
+ status = update.status,
701
+ successfulLaunchCount = update.successfulLaunchCount,
702
+ failedLaunchCount = update.failedLaunchCount,
703
+ isEmbedded = update.isEmbedded,
704
+ bundleHash = update.bundleHash,
705
+ scopeKey = update.scopeKey
706
+ )
707
+ }
708
+ }
709
+
710
+ error?.let { pulseLogWarn(TAG, "Launch error: ${it.message}") }
711
+ callback(success)
712
+ }
713
+ }
714
+
715
+ private fun launchEmbedded() {
716
+ // For embedded bundles, DON'T set launchAssetFile
717
+ // Let React Native use its default bundle loading mechanism
718
+ // This ensures images from drawable folders are resolved correctly
719
+ launchAssetFile = null
720
+ isEmbeddedLaunch = true
721
+ localAssets = emptyMap()
722
+ }
723
+
724
+ private fun runReaper() {
725
+ val db = database ?: return
726
+ val dir = directory ?: return
727
+ val launchedId = launchedUpdate?.updateId ?: return
728
+
729
+ executor.execute {
730
+ PulseReaper.reap(db, dir, PulseDefaultSelectionPolicy(), launchedId)
731
+ }
732
+ }
733
+
734
+ // MARK: - Error Recovery Delegate
735
+
736
+ private val errorRecoveryDelegate = object : PulseErrorRecoveryDelegate {
737
+
738
+ override fun loadRemoteUpdate() {
739
+ remoteLoadStatus = PulseErrorRecoveryDelegate.RemoteLoadStatus.NEW_UPDATE_LOADING
740
+ fetchUpdate { result ->
741
+ result.fold(
742
+ onSuccess = { fetchResult ->
743
+ remoteLoadStatus = if (fetchResult.isNew)
744
+ PulseErrorRecoveryDelegate.RemoteLoadStatus.NEW_UPDATE_LOADED
745
+ else
746
+ PulseErrorRecoveryDelegate.RemoteLoadStatus.IDLE
747
+ },
748
+ onFailure = {
749
+ remoteLoadStatus = PulseErrorRecoveryDelegate.RemoteLoadStatus.IDLE
750
+ }
751
+ )
752
+ errorRecovery?.notifyNewRemoteLoadStatus(remoteLoadStatus)
753
+ }
754
+ }
755
+
756
+ override fun relaunch(callback: PulseErrorRecoveryDelegate.LauncherCallback) {
757
+ launchBestUpdate { success ->
758
+ if (success) {
759
+ callback.onSuccess()
760
+ } else {
761
+ callback.onFailure(PulseUpdatesException("Failed to relaunch"))
762
+ }
763
+ }
764
+ }
765
+
766
+ override fun throwException(exception: Exception) {
767
+ throw exception
768
+ }
769
+
770
+ override fun markFailedLaunchForLaunchedUpdate() {
771
+ launchedUpdate?.updateId?.let { updateId ->
772
+ try {
773
+ database?.recordFailedLaunch(updateId)
774
+ } catch (e: Exception) {
775
+ pulseLogWarn(TAG, "Failed to record failed launch: ${e.message}")
776
+ }
777
+ }
778
+ }
779
+
780
+ override fun markSuccessfulLaunchForLaunchedUpdate() {
781
+ launchedUpdate?.updateId?.let { updateId ->
782
+ try {
783
+ database?.recordSuccessfulLaunch(updateId)
784
+ } catch (e: Exception) {
785
+ pulseLogWarn(TAG, "Failed to record successful launch: ${e.message}")
786
+ }
787
+ }
788
+ }
789
+
790
+ override fun getRemoteLoadStatus(): PulseErrorRecoveryDelegate.RemoteLoadStatus {
791
+ return remoteLoadStatus
792
+ }
793
+
794
+ override fun getCheckOnLaunchConfiguration(): String {
795
+ return config?.checkOnLaunch ?: "ALWAYS"
796
+ }
797
+
798
+ override fun getLaunchedUpdateSuccessfulLaunchCount(): Int {
799
+ return launchedUpdate?.successfulLaunchCount ?: 0
800
+ }
801
+ }
802
+ }
803
+
804
+ // MARK: - Config
805
+
806
+ data class PulseUpdatesConfig(
807
+ val enabled: Boolean,
808
+ val updateUrl: String,
809
+ val runtimeVersion: String,
810
+ val checkOnLaunch: String = "ALWAYS",
811
+ val launchWaitMs: Int = 0,
812
+ val channel: String? = null,
813
+ val signingKeyId: String? = null,
814
+ val signingPublicKey: String? = null
815
+ ) {
816
+ val scopeKey: String
817
+ get() = try {
818
+ URL(updateUrl).host
819
+ } catch (e: Exception) {
820
+ "default"
821
+ }
822
+ }
823
+
824
+ // MARK: - Results
825
+
826
+ data class CheckResult(
827
+ val isAvailable: Boolean,
828
+ val manifest: ManifestModel? = null,
829
+ val isRollback: Boolean = false,
830
+ val failedReason: String? = null
831
+ )
832
+
833
+ data class FetchResult(
834
+ val isNew: Boolean,
835
+ val manifest: ManifestModel? = null
836
+ )
837
+
838
+ data class ManifestModel(
839
+ val updateId: String,
840
+ val runtimeVersion: String,
841
+ val createdAt: String,
842
+ val bundle: BundleModel,
843
+ val assets: List<AssetModel>,
844
+ val metadata: Map<String, String>? = null,
845
+ val signature: SignatureModel? = null
846
+ ) {
847
+ val commitTime: Date?
848
+ get() = try {
849
+ java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", java.util.Locale.US).parse(createdAt)
850
+ } catch (e: Exception) {
851
+ try {
852
+ java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", java.util.Locale.US).parse(createdAt)
853
+ } catch (e2: Exception) {
854
+ null
855
+ }
856
+ }
857
+
858
+ companion object {
859
+ fun fromJson(json: String): ManifestModel? {
860
+ return try {
861
+ val obj = JSONObject(json)
862
+ ManifestModel(
863
+ updateId = obj.getString("updateId"),
864
+ runtimeVersion = obj.getString("runtimeVersion"),
865
+ createdAt = obj.getString("createdAt"),
866
+ bundle = BundleModel(
867
+ hash = obj.getJSONObject("bundle").getString("hash"),
868
+ url = obj.getJSONObject("bundle").getString("url"),
869
+ contentType = obj.getJSONObject("bundle").getString("contentType")
870
+ ),
871
+ assets = obj.optJSONArray("assets")?.let { arr ->
872
+ (0 until arr.length()).map { i ->
873
+ val asset = arr.getJSONObject(i)
874
+ AssetModel(
875
+ key = asset.optString("key", null),
876
+ hash = asset.getString("hash"),
877
+ url = asset.getString("url"),
878
+ contentType = asset.getString("contentType"),
879
+ name = asset.optString("name", null),
880
+ type = asset.optString("type", null),
881
+ scale = asset.optDouble("scale", 1.0),
882
+ mainBundleDir = asset.optString("mainBundleDir", null),
883
+ mainBundleFilename = asset.optString("mainBundleFilename", null)
884
+ )
885
+ }
886
+ } ?: emptyList(),
887
+ metadata = obj.optJSONObject("metadata")?.let { meta ->
888
+ val map = mutableMapOf<String, String>()
889
+ meta.keys().forEach { key ->
890
+ map[key] = meta.optString(key, "")
891
+ }
892
+ map
893
+ },
894
+ signature = obj.optJSONObject("signature")?.let { sig ->
895
+ SignatureModel(
896
+ alg = sig.getString("alg"),
897
+ keyId = sig.getString("keyId"),
898
+ sig = sig.getString("sig")
899
+ )
900
+ }
901
+ )
902
+ } catch (e: Exception) {
903
+ null
904
+ }
905
+ }
906
+ }
907
+ }
908
+
909
+ data class BundleModel(
910
+ val hash: String,
911
+ val url: String,
912
+ val contentType: String
913
+ )
914
+
915
+ data class AssetModel(
916
+ val key: String?,
917
+ val hash: String,
918
+ val url: String,
919
+ val contentType: String,
920
+ val name: String? = null,
921
+ val type: String? = null,
922
+ val scale: Double? = null,
923
+ val mainBundleDir: String? = null,
924
+ val mainBundleFilename: String? = null
925
+ )
926
+
927
+ data class SignatureModel(
928
+ val alg: String,
929
+ val keyId: String,
930
+ val sig: String
931
+ )
932
+
933
+ // MARK: - Exception
934
+
935
+ class PulseUpdatesException(message: String) : Exception(message)
936
+
937
+ // MARK: - Integrity Check
938
+
939
+ object PulseIntegrityCheck {
940
+ private const val TAG = "PulseIntegrityCheck"
941
+
942
+ fun run(database: PulseDatabase, directory: File, currentEmbeddedId: String?) {
943
+ try {
944
+ // Delete old embedded updates
945
+ val embeddedUpdates = database.embeddedUpdates()
946
+ val toDelete = embeddedUpdates.filter { update ->
947
+ currentEmbeddedId == null || update.updateId != currentEmbeddedId
948
+ }
949
+
950
+ if (toDelete.isNotEmpty()) {
951
+ database.deleteUpdates(toDelete.map { it.updateId })
952
+ pulseLog(TAG, "Deleted ${toDelete.size} old embedded updates")
953
+
954
+ // Clean up unused assets
955
+ database.deleteUnusedAssets()
956
+ }
957
+ } catch (e: Exception) {
958
+ pulseLogError(TAG, "IntegrityCheck error: ${e.message}")
959
+ }
960
+ }
961
+ }
962
+
963
+ // MARK: - Reaper
964
+
965
+ object PulseReaper {
966
+ private const val TAG = "PulseReaper"
967
+
968
+ fun reap(
969
+ database: PulseDatabase,
970
+ directory: File,
971
+ selectionPolicy: PulseSelectionPolicy,
972
+ launchedUpdateId: String
973
+ ) {
974
+ try {
975
+ val allUpdates = database.allUpdates()
976
+ val launchedUpdate = allUpdates.find { it.updateId == launchedUpdateId } ?: return
977
+
978
+ val launchedInfo = PulseUpdateInfo(
979
+ updateId = launchedUpdate.updateId,
980
+ runtimeVersion = launchedUpdate.runtimeVersion,
981
+ commitTime = launchedUpdate.commitTime.time,
982
+ status = launchedUpdate.status,
983
+ successfulLaunchCount = launchedUpdate.successfulLaunchCount,
984
+ failedLaunchCount = launchedUpdate.failedLaunchCount,
985
+ isEmbedded = launchedUpdate.isEmbedded,
986
+ bundleHash = launchedUpdate.bundleHash,
987
+ scopeKey = launchedUpdate.scopeKey
988
+ )
989
+
990
+ val allInfos = allUpdates.map { update ->
991
+ PulseUpdateInfo(
992
+ updateId = update.updateId,
993
+ runtimeVersion = update.runtimeVersion,
994
+ commitTime = update.commitTime.time,
995
+ status = update.status,
996
+ successfulLaunchCount = update.successfulLaunchCount,
997
+ failedLaunchCount = update.failedLaunchCount,
998
+ isEmbedded = update.isEmbedded,
999
+ bundleHash = update.bundleHash,
1000
+ scopeKey = update.scopeKey
1001
+ )
1002
+ }
1003
+
1004
+ val toDeleteInfos = selectionPolicy.selectUpdatesToDelete(launchedInfo, allInfos)
1005
+ if (toDeleteInfos.isEmpty()) return
1006
+
1007
+ val toDeleteIds = toDeleteInfos.map { it.updateId }
1008
+ database.deleteUpdates(toDeleteIds)
1009
+
1010
+ // Delete unused assets from filesystem
1011
+ val unusedAssets = database.deleteUnusedAssets()
1012
+ for (asset in unusedAssets) {
1013
+ val assetPath = File(directory, "assets/sha256/${asset.hash.lowercase()}")
1014
+ assetPath.delete()
1015
+ }
1016
+
1017
+ // Clean up unused bundles
1018
+ cleanupUnusedBundles(database, directory)
1019
+
1020
+ pulseLog(TAG, "Reaper: Deleted ${toDeleteIds.size} updates, ${unusedAssets.size} assets")
1021
+ } catch (e: Exception) {
1022
+ pulseLogError(TAG, "Reaper error: ${e.message}")
1023
+ }
1024
+ }
1025
+
1026
+ private fun cleanupUnusedBundles(database: PulseDatabase, directory: File) {
1027
+ // TODO: Implement proper cleanup based on database references
1028
+ }
1029
+ }
1030
+
1031
+ // MARK: - Remote Loader
1032
+
1033
+ object PulseRemoteLoader {
1034
+ private const val TAG = "PulseRemoteLoader"
1035
+
1036
+ fun checkForUpdate(
1037
+ config: PulseUpdatesConfig,
1038
+ currentUpdateId: String?,
1039
+ callback: (Result<CheckResult>) -> Unit
1040
+ ) {
1041
+ try {
1042
+ val url = URL(config.updateUrl)
1043
+ val connection = url.openConnection() as java.net.HttpURLConnection
1044
+
1045
+ connection.requestMethod = "GET"
1046
+ connection.setRequestProperty("Accept", "application/json")
1047
+ connection.setRequestProperty("Pulse-Protocol-Version", "2")
1048
+ connection.setRequestProperty("X-Pulse-Platform", "android")
1049
+ connection.setRequestProperty("X-Pulse-Runtime-Version", config.runtimeVersion)
1050
+
1051
+ pulseLog(TAG, "checkForUpdate: url=${config.updateUrl}")
1052
+ pulseLog(TAG, "checkForUpdate: runtimeVersion=${config.runtimeVersion}")
1053
+ pulseLog(TAG, "checkForUpdate: channel=${config.channel}")
1054
+ pulseLog(TAG, "checkForUpdate: currentUpdateId=$currentUpdateId")
1055
+
1056
+ config.channel?.let {
1057
+ connection.setRequestProperty("X-Pulse-Channel-Name", it)
1058
+ }
1059
+
1060
+ currentUpdateId?.let {
1061
+ connection.setRequestProperty("X-Pulse-Current-Update-Id", it)
1062
+ }
1063
+
1064
+ val responseCode = connection.responseCode
1065
+ pulseLog(TAG, "checkForUpdate: responseCode=$responseCode")
1066
+
1067
+ if (responseCode == 204) {
1068
+ pulseLog(TAG, "checkForUpdate: no update (204)")
1069
+ callback(Result.success(CheckResult(isAvailable = false)))
1070
+ return
1071
+ }
1072
+
1073
+ if (responseCode != 200) {
1074
+ val errorBody = try {
1075
+ connection.errorStream?.bufferedReader()?.use { it.readText() } ?: ""
1076
+ } catch (e: Exception) { "" }
1077
+ pulseLogWarn(TAG, "checkForUpdate: server error $responseCode: $errorBody")
1078
+ callback(Result.failure(PulseUpdatesException("Server error: $responseCode")))
1079
+ return
1080
+ }
1081
+
1082
+ val response = connection.inputStream.bufferedReader().use { it.readText() }
1083
+ pulseLog(TAG, "checkForUpdate: parsing manifest...")
1084
+ val manifest = ManifestModel.fromJson(response)
1085
+
1086
+ if (manifest == null) {
1087
+ pulseLogWarn(TAG, "checkForUpdate: failed to parse manifest")
1088
+ callback(Result.failure(PulseUpdatesException("Invalid manifest")))
1089
+ return
1090
+ }
1091
+
1092
+ pulseLog(TAG, "checkForUpdate: manifest updateId=${manifest.updateId} runtimeVersion=${manifest.runtimeVersion}")
1093
+
1094
+ // Check runtime version
1095
+ if (manifest.runtimeVersion != config.runtimeVersion) {
1096
+ pulseLogWarn(TAG, "checkForUpdate: runtime mismatch - manifest=${manifest.runtimeVersion} config=${config.runtimeVersion}")
1097
+ callback(Result.success(CheckResult(isAvailable = false)))
1098
+ return
1099
+ }
1100
+
1101
+ // Verify signature if required
1102
+ if (config.signingPublicKey != null) {
1103
+ pulseLog(TAG, "checkForUpdate: verifying signature...")
1104
+ if (!verifyManifestSignature(manifest, response, config)) {
1105
+ pulseLogWarn(TAG, "checkForUpdate: signature verification failed")
1106
+ callback(Result.failure(PulseUpdatesException("Signature verification failed")))
1107
+ return
1108
+ }
1109
+ pulseLog(TAG, "checkForUpdate: signature valid")
1110
+ }
1111
+
1112
+ // Check if same update
1113
+ if (manifest.updateId == currentUpdateId) {
1114
+ pulseLog(TAG, "checkForUpdate: same update already installed")
1115
+ callback(Result.success(CheckResult(isAvailable = false)))
1116
+ return
1117
+ }
1118
+
1119
+ pulseLog(TAG, "checkForUpdate: update available! updateId=${manifest.updateId}")
1120
+ callback(Result.success(CheckResult(isAvailable = true, manifest = manifest)))
1121
+
1122
+ } catch (e: Exception) {
1123
+ callback(Result.failure(PulseUpdatesException("Network error: ${e.message}")))
1124
+ }
1125
+ }
1126
+
1127
+ fun fetchUpdate(
1128
+ config: PulseUpdatesConfig,
1129
+ database: PulseDatabase?,
1130
+ directory: File,
1131
+ callback: (Result<FetchResult>) -> Unit
1132
+ ) {
1133
+ checkForUpdate(config, PulseController.getInstance().launchedUpdate?.updateId) { result ->
1134
+ result.fold(
1135
+ onSuccess = { checkResult ->
1136
+ if (!checkResult.isAvailable || checkResult.manifest == null) {
1137
+ callback(Result.success(FetchResult(isNew = false)))
1138
+ return@fold
1139
+ }
1140
+
1141
+ downloadUpdate(checkResult.manifest, config, database, directory) { downloadResult ->
1142
+ downloadResult.fold(
1143
+ onSuccess = { callback(Result.success(FetchResult(isNew = true, manifest = checkResult.manifest))) },
1144
+ onFailure = { callback(Result.failure(it)) }
1145
+ )
1146
+ }
1147
+ },
1148
+ onFailure = { callback(Result.failure(it)) }
1149
+ )
1150
+ }
1151
+ }
1152
+
1153
+ private fun downloadUpdate(
1154
+ manifest: ManifestModel,
1155
+ config: PulseUpdatesConfig,
1156
+ database: PulseDatabase?,
1157
+ directory: File,
1158
+ callback: (Result<Unit>) -> Unit
1159
+ ) {
1160
+ val updateId = manifest.updateId
1161
+ val bundleHash = manifest.bundle.hash.lowercase()
1162
+ val stagingDir = File(directory, "staging/$updateId")
1163
+ stagingDir.mkdirs()
1164
+
1165
+ // Store update in database
1166
+ // Convert manifest to JSONObject for storage
1167
+ val manifestJson = try {
1168
+ JSONObject().apply {
1169
+ put("updateId", manifest.updateId)
1170
+ put("runtimeVersion", manifest.runtimeVersion)
1171
+ put("createdAt", manifest.createdAt)
1172
+ put("bundle", JSONObject().apply {
1173
+ put("hash", manifest.bundle.hash)
1174
+ put("url", manifest.bundle.url)
1175
+ put("contentType", manifest.bundle.contentType)
1176
+ })
1177
+ put("assets", org.json.JSONArray(manifest.assets.map { asset ->
1178
+ JSONObject().apply {
1179
+ asset.key?.let { put("key", it) }
1180
+ put("hash", asset.hash)
1181
+ put("url", asset.url)
1182
+ put("contentType", asset.contentType)
1183
+ asset.name?.let { put("name", it) }
1184
+ asset.type?.let { put("type", it) }
1185
+ asset.scale?.let { put("scale", it) }
1186
+ asset.mainBundleDir?.let { put("mainBundleDir", it) }
1187
+ asset.mainBundleFilename?.let { put("mainBundleFilename", it) }
1188
+ }
1189
+ }))
1190
+ manifest.metadata?.let { meta ->
1191
+ put("metadata", JSONObject(meta))
1192
+ }
1193
+ }
1194
+ } catch (e: Exception) {
1195
+ pulseLogWarn(TAG, "Failed to convert manifest to JSON: ${e.message}")
1196
+ null
1197
+ }
1198
+
1199
+ val update = PulseUpdate(
1200
+ updateId = updateId,
1201
+ scopeKey = config.scopeKey,
1202
+ runtimeVersion = manifest.runtimeVersion,
1203
+ commitTime = manifest.commitTime ?: Date(),
1204
+ status = PulseUpdateStatus.DOWNLOADING,
1205
+ manifest = manifestJson,
1206
+ bundleHash = bundleHash,
1207
+ lastAccessed = Date()
1208
+ )
1209
+
1210
+ try {
1211
+ database?.addUpdate(update)
1212
+ } catch (e: Exception) {
1213
+ pulseLogWarn(TAG, "Failed to add update: ${e.message}")
1214
+ }
1215
+
1216
+ // Download bundle (store in assets directory, same as other assets)
1217
+ val bundleDest = File(directory, "assets/sha256/$bundleHash")
1218
+ if (!bundleDest.exists()) {
1219
+ try {
1220
+ downloadFile(manifest.bundle.url, bundleDest, stagingDir)
1221
+
1222
+ // Verify hash
1223
+ val actualHash = sha256Hex(bundleDest)
1224
+ if (actualHash != bundleHash) {
1225
+ bundleDest.delete()
1226
+ database?.setStatus(updateId, PulseUpdateStatus.FAILED)
1227
+ callback(Result.failure(PulseUpdatesException("Bundle hash mismatch")))
1228
+ return
1229
+ }
1230
+ } catch (e: Exception) {
1231
+ database?.setStatus(updateId, PulseUpdateStatus.FAILED)
1232
+ stagingDir.deleteRecursively()
1233
+ callback(Result.failure(e))
1234
+ return
1235
+ }
1236
+ }
1237
+
1238
+ // Store bundle as launch asset in database
1239
+ try {
1240
+ val bundleAsset = PulseAsset(
1241
+ key = "bundle",
1242
+ hash = bundleHash,
1243
+ type = "application/javascript"
1244
+ )
1245
+ val assetId = database?.addAsset(bundleAsset)
1246
+ if (assetId != null) {
1247
+ database?.linkAsset(assetId, updateId, "bundle", bundleHash, isLaunchAsset = true)
1248
+ }
1249
+ } catch (e: Exception) {
1250
+ pulseLogWarn(TAG, "Failed to store bundle asset: ${e.message}")
1251
+ }
1252
+
1253
+ // Download assets and link them to the update
1254
+ for (asset in manifest.assets) {
1255
+ val assetHash = asset.hash.lowercase()
1256
+ val assetDest = File(directory, "assets/sha256/$assetHash")
1257
+
1258
+ // Download if not exists
1259
+ if (!assetDest.exists()) {
1260
+ try {
1261
+ downloadFile(asset.url, assetDest, stagingDir)
1262
+
1263
+ val actualHash = sha256Hex(assetDest)
1264
+ if (actualHash != assetHash) {
1265
+ assetDest.delete()
1266
+ pulseLogWarn(TAG, "Asset hash mismatch for ${asset.key}")
1267
+ continue
1268
+ }
1269
+ } catch (e: Exception) {
1270
+ pulseLogWarn(TAG, "Failed to download asset: ${e.message}")
1271
+ continue
1272
+ }
1273
+ }
1274
+
1275
+ // Link asset to update in database (important for buildLocalAssetsForUpdate)
1276
+ try {
1277
+ val dbAsset = PulseAsset(
1278
+ key = asset.key,
1279
+ hash = assetHash,
1280
+ type = asset.contentType,
1281
+ url = asset.url,
1282
+ expectedHash = assetHash,
1283
+ mainBundleDir = asset.mainBundleDir,
1284
+ mainBundleFilename = asset.mainBundleFilename
1285
+ )
1286
+ val assetId = database?.addAsset(dbAsset)
1287
+ if (assetId != null) {
1288
+ database?.linkAsset(assetId, updateId, asset.key, assetHash, isLaunchAsset = false)
1289
+ }
1290
+ } catch (e: Exception) {
1291
+ pulseLogWarn(TAG, "Failed to link asset to update: ${e.message}")
1292
+ }
1293
+ }
1294
+
1295
+ // Mark as ready
1296
+ database?.setStatus(updateId, PulseUpdateStatus.READY)
1297
+ stagingDir.deleteRecursively()
1298
+
1299
+ pulseLog(TAG, "Update $updateId downloaded and ready")
1300
+ callback(Result.success(Unit))
1301
+ }
1302
+
1303
+ private fun downloadFile(url: String, destination: File, stagingDir: File) {
1304
+ destination.parentFile?.mkdirs()
1305
+ val tempFile = File(stagingDir, "temp_${System.currentTimeMillis()}")
1306
+
1307
+ URL(url).openStream().use { input ->
1308
+ tempFile.outputStream().use { output ->
1309
+ input.copyTo(output)
1310
+ }
1311
+ }
1312
+
1313
+ tempFile.renameTo(destination)
1314
+ }
1315
+
1316
+ private fun sha256Hex(file: File): String {
1317
+ val digest = MessageDigest.getInstance("SHA-256")
1318
+ file.inputStream().use { fis ->
1319
+ val buffer = ByteArray(8192)
1320
+ var bytesRead: Int
1321
+ while (fis.read(buffer).also { bytesRead = it } != -1) {
1322
+ digest.update(buffer, 0, bytesRead)
1323
+ }
1324
+ }
1325
+ return digest.digest().joinToString("") { "%02x".format(it) }
1326
+ }
1327
+
1328
+ // MARK: - Signature Verification
1329
+
1330
+ private fun verifyManifestSignature(
1331
+ manifest: ManifestModel,
1332
+ manifestJson: String,
1333
+ config: PulseUpdatesConfig
1334
+ ): Boolean {
1335
+ val signature = manifest.signature ?: return false
1336
+ if (signature.alg.lowercase() != "ed25519") return false
1337
+ if (config.signingKeyId != null && signature.keyId != config.signingKeyId) return false
1338
+
1339
+ val publicKeyBase64 = config.signingPublicKey ?: return false
1340
+ val publicKeyBytes = android.util.Base64.decode(publicKeyBase64, android.util.Base64.DEFAULT)
1341
+ val signatureBytes = android.util.Base64.decode(signature.sig, android.util.Base64.DEFAULT)
1342
+
1343
+ return try {
1344
+ val canonical = canonicalizeManifestJson(manifestJson)
1345
+ pulseLog(TAG, "verifySignature: canonical length=${canonical.length}")
1346
+ pulseLog(TAG, "verifySignature: canonical start=${canonical.take(200)}...")
1347
+ pulseLog(TAG, "verifySignature: canonical hash=${MessageDigest.getInstance("SHA-256").digest(canonical.toByteArray(Charsets.UTF_8)).joinToString("") { "%02x".format(it) }.take(16)}...")
1348
+ pulseLog(TAG, "verifySignature: signature=${signature.sig.take(20)}...")
1349
+
1350
+ val spec = net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable.getByName("Ed25519")
1351
+ val pubKeySpec = net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec(publicKeyBytes, spec)
1352
+ val publicKey = net.i2p.crypto.eddsa.EdDSAPublicKey(pubKeySpec)
1353
+
1354
+ val sgr = net.i2p.crypto.eddsa.EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm))
1355
+ sgr.initVerify(publicKey)
1356
+ sgr.update(canonical.toByteArray(Charsets.UTF_8))
1357
+ val result = sgr.verify(signatureBytes)
1358
+ pulseLog(TAG, "verifySignature: result=$result")
1359
+ result
1360
+ } catch (e: Exception) {
1361
+ pulseLogError(TAG, "Signature verification error: ${e.message}")
1362
+ e.printStackTrace()
1363
+ false
1364
+ }
1365
+ }
1366
+
1367
+ private fun canonicalizeManifestJson(json: String): String {
1368
+ return try {
1369
+ val obj = JSONObject(json)
1370
+ obj.remove("signature")
1371
+ canonicalizeJson(obj)
1372
+ } catch (e: Exception) {
1373
+ json
1374
+ }
1375
+ }
1376
+
1377
+ private fun canonicalizeJson(value: Any?): String {
1378
+ return when (value) {
1379
+ null, JSONObject.NULL -> "null"
1380
+ is JSONObject -> {
1381
+ val keys = value.keys().asSequence().toList().sorted()
1382
+ val items = keys.mapNotNull { key ->
1383
+ val v = value.opt(key) ?: return@mapNotNull null
1384
+ "\"${escapeJson(key)}\":${canonicalizeJson(v)}"
1385
+ }
1386
+ "{${items.joinToString(",")}}"
1387
+ }
1388
+ is org.json.JSONArray -> {
1389
+ val items = (0 until value.length()).map { canonicalizeJson(value.get(it)) }
1390
+ "[${items.joinToString(",")}]"
1391
+ }
1392
+ is Boolean -> if (value) "true" else "false"
1393
+ is Number -> value.toString()
1394
+ is String -> "\"${escapeJson(value)}\""
1395
+ else -> "null"
1396
+ }
1397
+ }
1398
+
1399
+ private fun escapeJson(input: String): String {
1400
+ val sb = StringBuilder()
1401
+ for (char in input) {
1402
+ when (char) {
1403
+ '"' -> sb.append("\\\"")
1404
+ '\\' -> sb.append("\\\\")
1405
+ '\n' -> sb.append("\\n")
1406
+ '\r' -> sb.append("\\r")
1407
+ '\t' -> sb.append("\\t")
1408
+ else -> {
1409
+ if (char.code < 32) {
1410
+ sb.append(String.format("\\u%04x", char.code))
1411
+ } else {
1412
+ sb.append(char)
1413
+ }
1414
+ }
1415
+ }
1416
+ }
1417
+ return sb.toString()
1418
+ }
1419
+ }