@_nazmiforreal/flutter-ota 0.1.25 → 0.1.27

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 (256) hide show
  1. package/bin/flutter-ota-linux-x64 +0 -0
  2. package/bin/flutter-ota.js +12 -11
  3. package/dart-src/packages/cli-tools/lib/flutter_ota_kit_cli.dart +46 -13
  4. package/dart-src/packages/cli-tools/lib/src/backend.dart +6 -6
  5. package/dart-src/packages/cli-tools/lib/src/commands/build.dart +2 -0
  6. package/dart-src/packages/cli-tools/lib/src/commands/bundle.dart +7 -7
  7. package/dart-src/packages/cli-tools/lib/src/commands/deploy.dart +4 -1
  8. package/dart-src/packages/cli-tools/lib/src/commands/pocketbase.dart +1 -1
  9. package/dart-src/packages/cli-tools/lib/src/commands/rollback.dart +1 -1
  10. package/dart-src/packages/cli-tools/lib/src/config.dart +5 -5
  11. package/dart-src/packages/cli-tools/lib/src/operations.dart +2 -2
  12. package/dart-src/packages/cli-tools/pubspec.yaml +8 -21
  13. package/dart-src/packages/cli-tools/test/backends_test.dart +3 -3
  14. package/dart-src/packages/cli-tools/test/cli_test.dart +1 -1
  15. package/dart-src/packages/cli-tools/test/mocks/mock_aws_s3_client.dart +2 -2
  16. package/dart-src/packages/cli-tools/test/mocks/mock_d1_client.dart +2 -2
  17. package/dart-src/packages/cli-tools/test/mocks/mock_pocketbase_client.dart +4 -1
  18. package/dart-src/packages/cli-tools/test/mocks/mock_postgres_client.dart +2 -2
  19. package/dart-src/packages/cli-tools/test/pocketbase_smoke_test.dart +1 -1
  20. package/dart-src/root/README.md +394 -0
  21. package/dart-src/root/analysis_options.yaml +21 -0
  22. package/dart-src/root/android/build.gradle +116 -0
  23. package/dart-src/root/android/consumer-rules.pro +23 -0
  24. package/dart-src/root/android/settings.gradle +1 -0
  25. package/dart-src/root/android/src/main/AndroidManifest.xml +21 -0
  26. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/ApplyResult.kt +52 -0
  27. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/BlacklistStore.kt +154 -0
  28. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/BootDiagnosticStore.kt +150 -0
  29. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/CrashGuard.kt +271 -0
  30. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/FlutterPatcherApplication.kt +201 -0
  31. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/FlutterPatcherAutoInitProvider.kt +93 -0
  32. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/FlutterPatcherPlugin.kt +245 -0
  33. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/LoaderHook.kt +298 -0
  34. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/PatchManager.kt +1579 -0
  35. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/PatcherConfig.kt +173 -0
  36. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/SignatureVerifier.kt +177 -0
  37. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/CrashGuardTest.kt +61 -0
  38. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/LoaderHookTest.kt +25 -0
  39. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/PatchManagerTest.kt +401 -0
  40. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/PatcherConfigTest.kt +30 -0
  41. package/dart-src/root/bin/pack.dart +182 -0
  42. package/dart-src/root/lib/flutter_ota_kit.dart +1170 -0
  43. package/dart-src/root/lib/src/app_version_resolver.dart +36 -0
  44. package/dart-src/root/lib/src/aws_update_source.dart +97 -0
  45. package/dart-src/root/lib/src/blacklist.dart +54 -0
  46. package/dart-src/root/lib/src/boot_diagnostic.dart +138 -0
  47. package/dart-src/root/lib/src/cloudflare_update_source.dart +97 -0
  48. package/dart-src/root/lib/src/flutter_ota_app.dart +69 -0
  49. package/dart-src/root/lib/src/io.dart +48 -0
  50. package/dart-src/root/lib/src/io_stub.dart +19 -0
  51. package/dart-src/root/lib/src/ota_progress_overlay.dart +987 -0
  52. package/dart-src/root/lib/src/pack/pack.dart +434 -0
  53. package/dart-src/root/lib/src/patch_info.dart +12 -0
  54. package/dart-src/root/lib/src/patcher_channel.dart +160 -0
  55. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_database.dart +1 -1
  56. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_s3_client.dart +1 -1
  57. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_storage.dart +1 -1
  58. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_storage_profile.dart +1 -1
  59. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/with_cloudfront_signed_url.dart +1 -1
  60. package/dart-src/root/lib/src/pkg/client/flutter_ota_kit_client.dart +1 -0
  61. package/dart-src/root/lib/src/pkg/client/src/server_update_source.dart +46 -0
  62. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/cloudflare_worker_database.dart +1 -1
  63. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_build_where.dart +1 -1
  64. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_bundle_mapper.dart +3 -3
  65. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_database.dart +1 -1
  66. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_database_plugin.dart +2 -2
  67. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_s3_client.dart +1 -1
  68. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_storage.dart +1 -1
  69. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_storage_profile.dart +1 -1
  70. package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/status.dart +1 -1
  71. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/flutter_ota_kit_plugin_core.dart +1 -1
  72. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_blob_database_plugin.dart +1 -1
  73. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/filter_compatible_app_versions.dart +1 -1
  74. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/get_update_info.dart +1 -1
  75. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/request_update_bundle_state.dart +1 -1
  76. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/resolve_update_info_from_bundles.dart +1 -1
  77. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/types.dart +2 -2
  78. package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_bundle_mapper.dart +2 -2
  79. package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_database.dart +26 -15
  80. package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_storage.dart +1 -1
  81. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_bundle_mapper.dart +2 -2
  82. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_database.dart +2 -2
  83. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_get_update_info.dart +2 -2
  84. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_storage.dart +1 -1
  85. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_types.dart +1 -1
  86. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_bundle_mapper.dart +2 -2
  87. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_database.dart +2 -2
  88. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_edge_function_database.dart +1 -1
  89. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_edge_function_storage.dart +1 -1
  90. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_storage.dart +1 -1
  91. package/dart-src/root/lib/src/pocketbase_update_source.dart +107 -0
  92. package/dart-src/root/lib/src/postgres_update_source.dart +95 -0
  93. package/dart-src/root/lib/src/shared_update_check.dart +131 -0
  94. package/dart-src/root/lib/src/supabase_update_source.dart +93 -0
  95. package/dart-src/root/pubspec.yaml +54 -0
  96. package/package.json +2 -1
  97. package/scripts/postinstall.js +17 -13
  98. package/scripts/vendor.sh +22 -7
  99. package/dart-src/packages/core/CHANGELOG.md +0 -21
  100. package/dart-src/packages/core/README.md +0 -23
  101. package/dart-src/packages/core/example/lib/main.dart +0 -69
  102. package/dart-src/packages/core/pubspec.yaml +0 -13
  103. package/dart-src/packages/core/test/rollout_test.dart +0 -135
  104. package/dart-src/packages/core/test/semver_test.dart +0 -55
  105. package/dart-src/packages/core/test/semver_vectors.json +0 -1
  106. package/dart-src/packages/core/test/types_test.dart +0 -131
  107. package/dart-src/packages/core/test/uuid_test.dart +0 -40
  108. package/dart-src/packages/core/tool/dbg.dart +0 -7
  109. package/dart-src/plugins/aws/.gitkeep +0 -0
  110. package/dart-src/plugins/aws/CHANGELOG.md +0 -23
  111. package/dart-src/plugins/aws/LICENSE +0 -21
  112. package/dart-src/plugins/aws/README.md +0 -28
  113. package/dart-src/plugins/aws/example/lib/main.dart +0 -60
  114. package/dart-src/plugins/aws/pubspec.yaml +0 -30
  115. package/dart-src/plugins/aws/test/aws_database_test.dart +0 -161
  116. package/dart-src/plugins/aws/test/aws_storage_test.dart +0 -73
  117. package/dart-src/plugins/aws/test/mock_aws_s3_client.dart +0 -78
  118. package/dart-src/plugins/cloudflare/.gitkeep +0 -0
  119. package/dart-src/plugins/cloudflare/CHANGELOG.md +0 -23
  120. package/dart-src/plugins/cloudflare/LICENSE +0 -21
  121. package/dart-src/plugins/cloudflare/README.md +0 -25
  122. package/dart-src/plugins/cloudflare/example/lib/main.dart +0 -62
  123. package/dart-src/plugins/cloudflare/migrations/0001_hot-updater_init.sql +0 -16
  124. package/dart-src/plugins/cloudflare/migrations/0002_hot-updater_0.13.0.sql +0 -8
  125. package/dart-src/plugins/cloudflare/migrations/0003_hot-updater_0.18.0.sql +0 -38
  126. package/dart-src/plugins/cloudflare/migrations/0004_hot-updater_0.29.0.sql +0 -11
  127. package/dart-src/plugins/cloudflare/migrations/0005_hot-updater_0.31.0.sql +0 -24
  128. package/dart-src/plugins/cloudflare/pubspec.yaml +0 -28
  129. package/dart-src/plugins/cloudflare/sql/bundles.sql +0 -42
  130. package/dart-src/plugins/cloudflare/test/cloudflare_worker_database_test.dart +0 -126
  131. package/dart-src/plugins/cloudflare/test/d1_bundle_mapper_test.dart +0 -106
  132. package/dart-src/plugins/cloudflare/test/d1_database_test.dart +0 -200
  133. package/dart-src/plugins/cloudflare/test/mock_d1_client.dart +0 -261
  134. package/dart-src/plugins/cloudflare/test/mock_r2_client.dart +0 -78
  135. package/dart-src/plugins/cloudflare/test/r2_storage_test.dart +0 -74
  136. package/dart-src/plugins/plugin-core/CHANGELOG.md +0 -20
  137. package/dart-src/plugins/plugin-core/LICENSE +0 -21
  138. package/dart-src/plugins/plugin-core/README.md +0 -21
  139. package/dart-src/plugins/plugin-core/example/lib/main.dart +0 -61
  140. package/dart-src/plugins/plugin-core/pubspec.yaml +0 -23
  141. package/dart-src/plugins/plugin-core/test/asset_storage_layout_test.dart +0 -170
  142. package/dart-src/plugins/plugin-core/test/bundle_unit_of_work_store_test.dart +0 -74
  143. package/dart-src/plugins/plugin-core/test/bundle_unit_of_work_test.dart +0 -345
  144. package/dart-src/plugins/plugin-core/test/create_blob_database_plugin_test.dart +0 -843
  145. package/dart-src/plugins/plugin-core/test/create_database_plugin_test.dart +0 -298
  146. package/dart-src/plugins/plugin-core/test/create_storage_plugin_test.dart +0 -195
  147. package/dart-src/plugins/plugin-core/test/generate_min_bundle_id_test.dart +0 -56
  148. package/dart-src/plugins/plugin-core/test/get_update_info_test.dart +0 -1589
  149. package/dart-src/plugins/plugin-core/test/helpers_test.dart +0 -283
  150. package/dart-src/plugins/plugin-core/test/query_bundles_test.dart +0 -202
  151. package/dart-src/plugins/plugin-core/test/request_update_bundle_state_test.dart +0 -86
  152. package/dart-src/plugins/plugin-core/test/uuidv7_test.dart +0 -88
  153. package/dart-src/plugins/pocketbase/CHANGELOG.md +0 -23
  154. package/dart-src/plugins/pocketbase/LICENSE +0 -21
  155. package/dart-src/plugins/pocketbase/README.md +0 -54
  156. package/dart-src/plugins/pocketbase/example/lib/main.dart +0 -62
  157. package/dart-src/plugins/pocketbase/pubspec.yaml +0 -26
  158. package/dart-src/plugins/pocketbase/test/pb_uri_test.dart +0 -12
  159. package/dart-src/plugins/postgres/.gitkeep +0 -0
  160. package/dart-src/plugins/postgres/CHANGELOG.md +0 -23
  161. package/dart-src/plugins/postgres/LICENSE +0 -21
  162. package/dart-src/plugins/postgres/README.md +0 -29
  163. package/dart-src/plugins/postgres/example/lib/main.dart +0 -67
  164. package/dart-src/plugins/postgres/pubspec.yaml +0 -26
  165. package/dart-src/plugins/postgres/sql/bundles.sql +0 -45
  166. package/dart-src/plugins/postgres/sql/get_target_app_version_list.sql +0 -21
  167. package/dart-src/plugins/postgres/sql/get_update_info.spec.ts +0 -171
  168. package/dart-src/plugins/postgres/sql/get_update_info_by_app_version.sql +0 -126
  169. package/dart-src/plugins/postgres/sql/get_update_info_by_fingerprint_hash.sql +0 -125
  170. package/dart-src/plugins/postgres/sql/hash_user_id.sql +0 -30
  171. package/dart-src/plugins/postgres/sql/is_device_eligible.sql +0 -237
  172. package/dart-src/plugins/postgres/sql/prepareSql.ts +0 -11
  173. package/dart-src/plugins/postgres/test/mock_postgres_client.dart +0 -320
  174. package/dart-src/plugins/postgres/test/postgres_bundle_mapper_test.dart +0 -139
  175. package/dart-src/plugins/postgres/test/postgres_database_test.dart +0 -210
  176. package/dart-src/plugins/postgres/test/postgres_storage_runtime_test.dart +0 -60
  177. package/dart-src/plugins/supabase/CHANGELOG.md +0 -24
  178. package/dart-src/plugins/supabase/LICENSE +0 -21
  179. package/dart-src/plugins/supabase/README.md +0 -53
  180. package/dart-src/plugins/supabase/example/lib/main.dart +0 -63
  181. package/dart-src/plugins/supabase/pubspec.yaml +0 -27
  182. package/dart-src/plugins/supabase/supabase/edge-functions/index.ts +0 -44
  183. package/dart-src/plugins/supabase/supabase/edge-functions/runtime.docker.integration.spec.ts +0 -968
  184. package/dart-src/plugins/supabase/supabase/migrations/20250103114225_init.sql +0 -232
  185. package/dart-src/plugins/supabase/supabase/migrations/20250314000000_hot-updater_0.13.0.sql +0 -137
  186. package/dart-src/plugins/supabase/supabase/migrations/20250516000000_hot-updater_0.18.0.sql +0 -206
  187. package/dart-src/plugins/supabase/supabase/migrations/20251014000000_hot-updater_0.21.0.sql +0 -186
  188. package/dart-src/plugins/supabase/supabase/migrations/20260401000000_hot-updater_0.29.0.sql +0 -505
  189. package/dart-src/plugins/supabase/supabase/migrations/20260414000000_hot-updater_0.30.0.sql +0 -50
  190. package/dart-src/plugins/supabase/supabase/migrations/20260422000000_hot-updater_0.31.0.sql +0 -20
  191. package/dart-src/plugins/supabase/supabase/migrations/20260520014100_hot-updater_rls.sql +0 -75
  192. package/dart-src/plugins/supabase/test/mock_supabase_client.dart +0 -654
  193. package/dart-src/plugins/supabase/test/supabase_bundle_mapper_test.dart +0 -115
  194. package/dart-src/plugins/supabase/test/supabase_database_test.dart +0 -198
  195. package/dart-src/plugins/supabase/test/supabase_storage_test.dart +0 -168
  196. /package/dart-src/{packages/core → root}/LICENSE +0 -0
  197. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/flutter_ota_kit_aws.dart +0 -0
  198. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_cloudfront_client.dart +0 -0
  199. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_cloudfront_signer.dart +0 -0
  200. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_config.dart +0 -0
  201. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_ssm_client.dart +0 -0
  202. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/flutter_ota_kit_cloudflare.dart +0 -0
  203. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_client.dart +0 -0
  204. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_config.dart +0 -0
  205. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_config.dart +0 -0
  206. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/flutter_ota_kit_core.dart +0 -0
  207. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/app_update_info.dart +0 -0
  208. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/bundle.dart +0 -0
  209. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/bundle_artifacts.dart +0 -0
  210. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/bundle_patch_artifact.dart +0 -0
  211. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/changed_asset.dart +0 -0
  212. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/get_bundles_args.dart +0 -0
  213. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/metadata.dart +0 -0
  214. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/patch_info.dart +0 -0
  215. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/platform.dart +0 -0
  216. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/rollout.dart +0 -0
  217. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/semver.dart +0 -0
  218. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/semver_range.dart +0 -0
  219. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/semver_version.dart +0 -0
  220. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/strategy.dart +0 -0
  221. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/update_bundle_params.dart +0 -0
  222. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/uuid.dart +0 -0
  223. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/asset_storage_layout.dart +0 -0
  224. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_helpers.dart +0 -0
  225. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_storage_layout.dart +0 -0
  226. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_unit_of_work.dart +0 -0
  227. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_unit_of_work_store.dart +0 -0
  228. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/calculate_pagination.dart +0 -0
  229. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/compression_format.dart +0 -0
  230. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/content_addressed_assets.dart +0 -0
  231. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_database_plugin.dart +0 -0
  232. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_storage_key_builder.dart +0 -0
  233. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_storage_plugin.dart +0 -0
  234. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/generate_min_bundle_id.dart +0 -0
  235. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/is_object.dart +0 -0
  236. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/legacy_asset_storage_layout.dart +0 -0
  237. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/paginate_bundles.dart +0 -0
  238. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/parse_storage_uri.dart +0 -0
  239. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/query_bundles.dart +0 -0
  240. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/storage_helpers.dart +0 -0
  241. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/storage_profile.dart +0 -0
  242. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/uuidv7.dart +0 -0
  243. /package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/flutter_ota_kit_pocketbase.dart +0 -0
  244. /package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_client.dart +0 -0
  245. /package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_config.dart +0 -0
  246. /package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/flutter_ota_kit_postgres.dart +0 -0
  247. /package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_client.dart +0 -0
  248. /package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_config.dart +0 -0
  249. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/edge.dart +0 -0
  250. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/flutter_ota_kit_supabase.dart +0 -0
  251. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/error_message.dart +0 -0
  252. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_client_adapter.dart +0 -0
  253. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_client_http.dart +0 -0
  254. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_config.dart +0 -0
  255. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_signed_url_batcher.dart +0 -0
  256. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/types.dart +0 -0
@@ -0,0 +1,173 @@
1
+ package com.flutter_patcher.flutter_patcher
2
+
3
+ import android.content.Context
4
+ import android.content.SharedPreferences
5
+ import android.content.pm.PackageManager
6
+ import android.os.Build
7
+ import android.util.Log
8
+ import org.json.JSONArray
9
+
10
+ /**
11
+ * 热更新运行时配置读写,统一走 SharedPreferences。
12
+ *
13
+ * 所有键值由 Dart 侧在 FlutterPatcher.init() 时下发,**不在** 库里硬编码任何
14
+ * 业务相关默认值(服务端 URL、公钥、渠道等)。
15
+ */
16
+ internal object PatcherConfig {
17
+
18
+ const val PREFS_NAME = "flutter_patcher_prefs"
19
+
20
+ // ---- Config keys ----
21
+ private const val KEY_PUBLIC_KEY = "public_key_base64"
22
+ private const val KEY_MAX_CRASH = "max_crash_count"
23
+ private const val KEY_STRICT_SIG = "strict_signature"
24
+ private const val KEY_LOADER_FIELDS = "loader_field_candidates"
25
+ private const val KEY_LOADER_HEURISTIC = "loader_fallback_heuristic"
26
+ private const val KEY_MAX_PATCH_HISTORY = "max_patch_history"
27
+ private const val KEY_MAX_ASSET_HISTORY = "max_asset_history"
28
+
29
+ // ---- Runtime state keys (CrashGuard / PatchManager) ----
30
+ const val KEY_CRASH_COUNT = "crash_count"
31
+ const val KEY_PATCH_LOADING = "patch_loading"
32
+
33
+ /** PID written at [com.flutter_patcher.flutter_patcher.CrashGuard.markBooting]; consumed
34
+ * next cold start to look up `ActivityManager.getHistoricalProcessExitReasons` (API 30+).
35
+ * Unused on API < 30 — that path uses the naive "patch_loading=true ⇒ crash" rule. */
36
+ const val KEY_LAST_BOOTING_PID = "last_booting_pid"
37
+
38
+ /** Wall-clock time (epoch millis) when the patched process began booting, written together
39
+ * with [KEY_LAST_BOOTING_PID] at markBooting. Used on API 30+ to bound crash attribution:
40
+ * a crash is only treated as a *patch boot* failure when it occurred within
41
+ * [BOOT_CRASH_WINDOW_MS] of this timestamp. Prevents an unrelated runtime crash/ANR hours
42
+ * into a healthy session from tripping the circuit breaker and reverting the patch. */
43
+ const val KEY_BOOT_STARTED_AT = "boot_started_at"
44
+
45
+ // ---- File layout ----
46
+ const val PATCH_DIR = "flutter_patcher"
47
+ const val PATCH_FILENAME = "libapp_patch.so"
48
+ const val META_FILENAME = "patch_meta.json"
49
+
50
+ // ---- Meta JSON keys ----
51
+ const val META_KEY_TARGET_VERSION_CODE = "targetVersionCode"
52
+
53
+ // ---- Sentinels ----
54
+ const val INVALID_VERSION_CODE = -1L
55
+
56
+ // ---- Patch history limits ----
57
+ const val MAX_PATCH_HISTORY = 4
58
+ const val MAX_ASSET_HISTORY = 4
59
+
60
+ // ---- Defaults ----
61
+ /**
62
+ * 默认 1:补丁连续启动失败 1 次即立刻丢弃 + 入黑名单(fail-fast)。
63
+ *
64
+ * 设计依据:补丁加载后崩溃是明确"补丁有问题"信号,不应该再赌一次让用户多崩
65
+ * 一次。0.1 之前默认是 2,行为是"崩 2 次才回滚",已确认对用户体验更糟。
66
+ * 业务侧若想保留旧行为,显式传 `FlutterPatcher.init(maxCrashCount: 2)`。
67
+ */
68
+ const val DEFAULT_MAX_CRASH = 1
69
+ const val DEFAULT_STRICT_SIG = true
70
+ const val DEFAULT_LOADER_HEURISTIC = false
71
+
72
+ /**
73
+ * How long after boot start a process death still counts as a *patch boot*
74
+ * failure (API 30+ ExitInfo path). Deaths later than this are treated as
75
+ * ordinary runtime exits and NOT charged against the patch.
76
+ *
77
+ * Rationale: once the app has rendered its first frame and run for a while,
78
+ * a later crash/ANR/force-stop is not evidence that the patch is bad. Before
79
+ * this bound, any REASON_CRASH / REASON_ANR / REASON_CRASH_NATIVE recorded
80
+ * for the last booting pid — even hours into a healthy session — was counted,
81
+ * so the circuit breaker would delete the patch and the app would silently
82
+ * revert to the pre-OTA build. 30s comfortably covers real boot-time crashes
83
+ * while excluding steady-state failures.
84
+ */
85
+ const val BOOT_CRASH_WINDOW_MS = 30_000L
86
+
87
+ fun prefs(context: Context): SharedPreferences =
88
+ context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
89
+
90
+ internal fun encodeLoaderFieldCandidates(fields: List<String>): String {
91
+ val normalized = fields
92
+ .map { it.trim() }
93
+ .filter { it.isNotEmpty() }
94
+ .distinct()
95
+ return JSONArray(normalized).toString()
96
+ }
97
+
98
+ internal fun decodeLoaderFieldCandidates(raw: Any?): List<String> {
99
+ return when (raw) {
100
+ is String -> try {
101
+ val arr = JSONArray(raw)
102
+ List(arr.length()) { arr.optString(it) }
103
+ .map { it.trim() }
104
+ .filter { it.isNotEmpty() }
105
+ .distinct()
106
+ } catch (_: Exception) {
107
+ emptyList()
108
+ }
109
+ else -> emptyList()
110
+ }
111
+ }
112
+
113
+ fun saveConfig(
114
+ context: Context,
115
+ publicKeyBase64: String,
116
+ maxCrashCount: Int,
117
+ strictSignature: Boolean,
118
+ loaderFieldCandidates: List<String>,
119
+ loaderFallbackHeuristic: Boolean,
120
+ maxPatchHistory: Int = MAX_PATCH_HISTORY,
121
+ maxAssetHistory: Int = MAX_ASSET_HISTORY
122
+ ) {
123
+ prefs(context).edit()
124
+ .putString(KEY_PUBLIC_KEY, publicKeyBase64)
125
+ .putInt(KEY_MAX_CRASH, maxCrashCount.coerceAtLeast(1))
126
+ .putBoolean(KEY_STRICT_SIG, strictSignature)
127
+ .putString(KEY_LOADER_FIELDS, encodeLoaderFieldCandidates(loaderFieldCandidates))
128
+ .putBoolean(KEY_LOADER_HEURISTIC, loaderFallbackHeuristic)
129
+ .putInt(KEY_MAX_PATCH_HISTORY, maxPatchHistory.coerceAtLeast(0))
130
+ .putInt(KEY_MAX_ASSET_HISTORY, maxAssetHistory.coerceAtLeast(0))
131
+ .apply()
132
+ }
133
+
134
+ fun publicKey(context: Context): String =
135
+ prefs(context).getString(KEY_PUBLIC_KEY, "") ?: ""
136
+
137
+ fun maxCrashCount(context: Context): Int =
138
+ prefs(context).getInt(KEY_MAX_CRASH, DEFAULT_MAX_CRASH)
139
+
140
+ fun strictSignature(context: Context): Boolean =
141
+ prefs(context).getBoolean(KEY_STRICT_SIG, DEFAULT_STRICT_SIG)
142
+
143
+ fun loaderFieldCandidates(context: Context): List<String> =
144
+ decodeLoaderFieldCandidates(prefs(context).all[KEY_LOADER_FIELDS])
145
+
146
+ fun loaderFallbackHeuristic(context: Context): Boolean =
147
+ prefs(context).getBoolean(KEY_LOADER_HEURISTIC, DEFAULT_LOADER_HEURISTIC)
148
+
149
+ fun maxPatchHistory(context: Context): Int =
150
+ prefs(context).getInt(KEY_MAX_PATCH_HISTORY, MAX_PATCH_HISTORY)
151
+
152
+ fun maxAssetHistory(context: Context): Int =
153
+ prefs(context).getInt(KEY_MAX_ASSET_HISTORY, MAX_ASSET_HISTORY)
154
+
155
+ /**
156
+ * 读取当前宿主 APK 的 versionCode(API 28+ 用 longVersionCode,以下降级)。
157
+ * 查询自身包名不应失败,失败时返回 [INVALID_VERSION_CODE] 作为兜底。
158
+ */
159
+ fun currentVersionCode(context: Context): Long {
160
+ return try {
161
+ val pi = context.packageManager.getPackageInfo(context.packageName, 0)
162
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
163
+ pi.longVersionCode
164
+ } else {
165
+ @Suppress("DEPRECATION")
166
+ pi.versionCode.toLong()
167
+ }
168
+ } catch (e: PackageManager.NameNotFoundException) {
169
+ Log.e("FlutterPatcher/Config", "own package not found", e)
170
+ INVALID_VERSION_CODE
171
+ }
172
+ }
173
+ }
@@ -0,0 +1,177 @@
1
+ package com.flutter_patcher.flutter_patcher
2
+
3
+ import android.os.Build
4
+ import android.util.Base64
5
+ import android.util.Log
6
+ import java.io.File
7
+ import java.security.KeyFactory
8
+ import java.security.MessageDigest
9
+ import java.security.Signature
10
+ import java.security.spec.X509EncodedKeySpec
11
+
12
+ /**
13
+ * 补丁文件完整性与签名校验。
14
+ *
15
+ * 策略:
16
+ * - MD5 校验:始终执行(来自 [com.flutter_patcher.flutter_patcher.PatchInfo.md5])
17
+ * - Ed25519 签名:
18
+ * - signature 为空 → 跳过(仅靠 MD5 + 传输层防篡改)
19
+ * - signature 非空 且 API >= 33 → 使用 JDK 原生 Ed25519 验签
20
+ * - signature 非空 且 API < 33:
21
+ * - strictSignature=true(默认安全) → **拒绝加载**,防止攻击者通过降级到低
22
+ * 版本设备绕过签名校验
23
+ * - strictSignature=false → 跳过验签(调用方显式选择降级)
24
+ *
25
+ * 签名的消息体约定为 **MD5 小写 hex 字符串的 UTF-8 字节**,
26
+ * 与 Dart 侧 PatchInfo.signature 含义保持一致。
27
+ */
28
+ internal object SignatureVerifier {
29
+
30
+ private const val TAG = "FlutterPatcher/Sig"
31
+
32
+ /** 计算文件 MD5(小写 hex)。 */
33
+ fun md5(file: File): String {
34
+ val digest = MessageDigest.getInstance("MD5")
35
+ file.inputStream().use { input ->
36
+ val buf = ByteArray(8192)
37
+ while (true) {
38
+ val n = input.read(buf)
39
+ if (n <= 0) break
40
+ digest.update(buf, 0, n)
41
+ }
42
+ }
43
+ return digest.digest().joinToString("") { "%02x".format(it) }
44
+ }
45
+
46
+ /**
47
+ * 仅校验 Ed25519 签名(调用方已确认 MD5 匹配)。
48
+ *
49
+ * - signature 为空 → 跳过返回 true
50
+ * - signature 非空但 publicKey 未配置 → 拒绝
51
+ * - API < 33 且 strictSignature=true → 拒绝(防止降级攻击)
52
+ * - API < 33 且 strictSignature=false → 跳过返回 true
53
+ * - API >= 33 → 真实 Ed25519 验签
54
+ *
55
+ * @param md5HexLower 已匹配并**小写化**的 md5 hex 字符串(作为签名消息体)
56
+ */
57
+ fun verifySignatureOnly(
58
+ md5HexLower: String,
59
+ signatureBase64: String,
60
+ publicKeyBase64: String,
61
+ strictSignature: Boolean = true
62
+ ): Boolean {
63
+ val sig = signatureBase64.trim()
64
+ if (sig.isEmpty() || sig.equals("null", ignoreCase = true)) {
65
+ Log.d(TAG, "signature empty, skip Ed25519 check")
66
+ return true
67
+ }
68
+ if (publicKeyBase64.isEmpty()) {
69
+ Log.w(TAG, "signature present but no public key configured, reject")
70
+ return false
71
+ }
72
+
73
+ if (Build.VERSION.SDK_INT < 33) {
74
+ if (strictSignature) {
75
+ Log.e(
76
+ TAG,
77
+ "API ${Build.VERSION.SDK_INT} < 33, Ed25519 not supported; strict mode rejects. " +
78
+ "Pass strictSignature=false to FlutterPatcher.init to downgrade (NOT recommended)."
79
+ )
80
+ return false
81
+ }
82
+ Log.w(
83
+ TAG,
84
+ "API ${Build.VERSION.SDK_INT} < 33, Ed25519 not supported; strictSignature=false, skip"
85
+ )
86
+ return true
87
+ }
88
+
89
+ return try {
90
+ verifyEd25519(md5HexLower, sig, publicKeyBase64)
91
+ } catch (e: Exception) {
92
+ Log.e(TAG, "Ed25519 verify failed", e)
93
+ false
94
+ }
95
+ }
96
+
97
+ /**
98
+ * [verify] 的细粒度结果。调用方据此可区分"被丢弃的具体原因"用于诊断上报,
99
+ * 见 [BootDiagnosticStore.DROPPED_MD5_MISMATCH] / [BootDiagnosticStore.DROPPED_SIGNATURE_INVALID]。
100
+ */
101
+ enum class VerifyResult { OK, MD5_MISMATCH, SIGNATURE_INVALID }
102
+
103
+ /**
104
+ * 完整校验(细粒度版本):MD5 + 可选 Ed25519。返回失败原因分类。
105
+ *
106
+ * 注意:[expectedMd5] 为空时整体跳过 MD5 与签名校验,直接返回
107
+ * [VerifyResult.OK](调用方明确选择"不下发 md5",仅依赖 HTTPS)。
108
+ * 启动路径目前仍依赖 meta.effectiveMd5 非空,故启动期不会走到这条分支;
109
+ * 该分支主要服务于 [PatchManager.applyPatch] 期间的重复使用。
110
+ */
111
+ fun verifyDetailed(
112
+ file: File,
113
+ expectedMd5: String,
114
+ signatureBase64: String,
115
+ publicKeyBase64: String,
116
+ strictSignature: Boolean = true
117
+ ): VerifyResult {
118
+ if (expectedMd5.isEmpty()) {
119
+ Log.w(TAG, "expected md5 empty, skip md5 & signature verify")
120
+ return VerifyResult.OK
121
+ }
122
+ val actualMd5 = md5(file)
123
+ if (!actualMd5.equals(expectedMd5, ignoreCase = true)) {
124
+ Log.e(TAG, "md5 mismatch: expected=$expectedMd5, actual=$actualMd5")
125
+ return VerifyResult.MD5_MISMATCH
126
+ }
127
+ return if (verifySignatureOnly(
128
+ actualMd5.lowercase(),
129
+ signatureBase64,
130
+ publicKeyBase64,
131
+ strictSignature
132
+ )
133
+ ) {
134
+ VerifyResult.OK
135
+ } else {
136
+ VerifyResult.SIGNATURE_INVALID
137
+ }
138
+ }
139
+
140
+ /**
141
+ * 完整校验:MD5 + 可选 Ed25519。
142
+ *
143
+ * @param file 已下载的补丁文件
144
+ * @param expectedMd5 manifest 中的预期 MD5(小写 hex)
145
+ * @param signatureBase64 manifest 中的 Ed25519 签名(Base64,允许为空)
146
+ * @param publicKeyBase64 X.509 SubjectPublicKeyInfo 的 Base64 公钥(允许为空)
147
+ * @param strictSignature API < 33 是否拒绝签名校验(默认 true,安全)
148
+ * @return 是否通过校验
149
+ */
150
+ fun verify(
151
+ file: File,
152
+ expectedMd5: String,
153
+ signatureBase64: String,
154
+ publicKeyBase64: String,
155
+ strictSignature: Boolean = true
156
+ ): Boolean = verifyDetailed(
157
+ file, expectedMd5, signatureBase64, publicKeyBase64, strictSignature
158
+ ) == VerifyResult.OK
159
+
160
+ private fun verifyEd25519(
161
+ md5Hex: String,
162
+ signatureBase64: String,
163
+ publicKeyBase64: String
164
+ ): Boolean {
165
+ val pkBytes = Base64.decode(publicKeyBase64, Base64.NO_WRAP)
166
+ val keySpec = X509EncodedKeySpec(pkBytes)
167
+ val kf = KeyFactory.getInstance("Ed25519")
168
+ val pk = kf.generatePublic(keySpec)
169
+
170
+ val sig = Signature.getInstance("Ed25519")
171
+ sig.initVerify(pk)
172
+ sig.update(md5Hex.toByteArray(Charsets.UTF_8))
173
+
174
+ val sigBytes = Base64.decode(signatureBase64, Base64.NO_WRAP)
175
+ return sig.verify(sigBytes)
176
+ }
177
+ }
@@ -0,0 +1,61 @@
1
+ package com.flutter_patcher.flutter_patcher
2
+
3
+ import kotlin.test.Test
4
+ import kotlin.test.assertFalse
5
+ import kotlin.test.assertTrue
6
+
7
+ /**
8
+ * Unit tests for the boot-window crash attribution rule that prevents a
9
+ * healthy OTA patch from being reverted by an unrelated runtime crash/ANR
10
+ * hours into a session.
11
+ */
12
+ class CrashGuardTest {
13
+
14
+ private val window = PatcherConfig.BOOT_CRASH_WINDOW_MS
15
+
16
+ @Test
17
+ fun crashWithinWindowIsChargedToPatch() {
18
+ val bootAt = 1_000_000L
19
+ // Crash 5s after boot — clearly a boot failure.
20
+ assertTrue(CrashGuard.isWithinBootWindow(bootAt, bootAt + 5_000L))
21
+ }
22
+
23
+ @Test
24
+ fun crashAtExactWindowEdgeIsCharged() {
25
+ val bootAt = 1_000_000L
26
+ assertTrue(CrashGuard.isWithinBootWindow(bootAt, bootAt + window))
27
+ }
28
+
29
+ @Test
30
+ fun crashLongAfterBootIsNotChargedToPatch() {
31
+ val bootAt = 1_000_000L
32
+ // Crash 2 hours into a healthy session — must NOT revert the patch.
33
+ val twoHours = 2 * 60 * 60 * 1000L
34
+ assertFalse(CrashGuard.isWithinBootWindow(bootAt, bootAt + twoHours))
35
+ }
36
+
37
+ @Test
38
+ fun crashJustPastWindowIsNotCharged() {
39
+ val bootAt = 1_000_000L
40
+ assertFalse(CrashGuard.isWithinBootWindow(bootAt, bootAt + window + 1L))
41
+ }
42
+
43
+ @Test
44
+ fun unknownBootTimestampFallsBackToCharging() {
45
+ // No boot timestamp recorded (legacy state / upgrade) → conservative,
46
+ // preserve prior fail-fast behavior.
47
+ assertTrue(CrashGuard.isWithinBootWindow(0L, 5_000_000L))
48
+ }
49
+
50
+ @Test
51
+ fun unknownCrashTimestampFallsBackToCharging() {
52
+ assertTrue(CrashGuard.isWithinBootWindow(1_000_000L, 0L))
53
+ }
54
+
55
+ @Test
56
+ fun clockSkewNegativeElapsedTreatedAsInWindow() {
57
+ // ExitInfo timestamp earlier than recorded boot (device clock change) →
58
+ // treat as in-window rather than silently ignoring a genuine boot crash.
59
+ assertTrue(CrashGuard.isWithinBootWindow(2_000_000L, 1_000_000L))
60
+ }
61
+ }
@@ -0,0 +1,25 @@
1
+ package com.flutter_patcher.flutter_patcher
2
+
3
+ import kotlin.test.Test
4
+ import kotlin.test.assertEquals
5
+
6
+ class LoaderHookTest {
7
+ @Test
8
+ fun patchedAssetLookupKeysUseBundlePath() {
9
+ assertEquals(
10
+ "flutter_patcher_assets/images/hero.png",
11
+ patchedAssetLookupKey(
12
+ "flutter_patcher_assets",
13
+ "images/hero.png"
14
+ )
15
+ )
16
+ assertEquals(
17
+ "flutter_patcher_assets/packages/demo/images/hero.png",
18
+ patchedPackageAssetLookupKey(
19
+ "flutter_patcher_assets",
20
+ "images/hero.png",
21
+ "demo"
22
+ )
23
+ )
24
+ }
25
+ }