@_nazmiforreal/flutter-ota 0.1.26 → 0.1.28

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 (259) hide show
  1. package/README.md +112 -18
  2. package/bin/flutter-ota-linux-x64 +0 -0
  3. package/bin/flutter-ota.js +12 -11
  4. package/dart-src/packages/cli-tools/README.md +146 -2
  5. package/dart-src/packages/cli-tools/lib/flutter_ota_kit_cli.dart +46 -13
  6. package/dart-src/packages/cli-tools/lib/src/backend.dart +6 -6
  7. package/dart-src/packages/cli-tools/lib/src/commands/build.dart +2 -0
  8. package/dart-src/packages/cli-tools/lib/src/commands/bundle.dart +7 -7
  9. package/dart-src/packages/cli-tools/lib/src/commands/deploy.dart +4 -1
  10. package/dart-src/packages/cli-tools/lib/src/commands/init.dart +36 -8
  11. package/dart-src/packages/cli-tools/lib/src/commands/pocketbase.dart +1 -1
  12. package/dart-src/packages/cli-tools/lib/src/commands/rollback.dart +1 -1
  13. package/dart-src/packages/cli-tools/lib/src/config.dart +5 -5
  14. package/dart-src/packages/cli-tools/lib/src/operations.dart +2 -2
  15. package/dart-src/packages/cli-tools/pubspec.yaml +8 -21
  16. package/dart-src/packages/cli-tools/test/backends_test.dart +3 -3
  17. package/dart-src/packages/cli-tools/test/cli_test.dart +1 -1
  18. package/dart-src/packages/cli-tools/test/mocks/mock_aws_s3_client.dart +2 -2
  19. package/dart-src/packages/cli-tools/test/mocks/mock_d1_client.dart +2 -2
  20. package/dart-src/packages/cli-tools/test/mocks/mock_pocketbase_client.dart +4 -1
  21. package/dart-src/packages/cli-tools/test/mocks/mock_postgres_client.dart +2 -2
  22. package/dart-src/packages/cli-tools/test/pocketbase_smoke_test.dart +1 -1
  23. package/dart-src/root/README.md +334 -0
  24. package/dart-src/root/analysis_options.yaml +21 -0
  25. package/dart-src/root/android/build.gradle +116 -0
  26. package/dart-src/root/android/consumer-rules.pro +23 -0
  27. package/dart-src/root/android/settings.gradle +1 -0
  28. package/dart-src/root/android/src/main/AndroidManifest.xml +21 -0
  29. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/ApplyResult.kt +52 -0
  30. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/BlacklistStore.kt +154 -0
  31. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/BootDiagnosticStore.kt +150 -0
  32. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/CrashGuard.kt +271 -0
  33. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/FlutterPatcherApplication.kt +201 -0
  34. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/FlutterPatcherAutoInitProvider.kt +93 -0
  35. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/FlutterPatcherPlugin.kt +245 -0
  36. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/LoaderHook.kt +298 -0
  37. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/PatchManager.kt +1579 -0
  38. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/PatcherConfig.kt +173 -0
  39. package/dart-src/root/android/src/main/kotlin/com/flutter_patcher/flutter_patcher/SignatureVerifier.kt +177 -0
  40. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/CrashGuardTest.kt +61 -0
  41. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/LoaderHookTest.kt +25 -0
  42. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/PatchManagerTest.kt +401 -0
  43. package/dart-src/root/android/src/test/kotlin/com/flutter_patcher/flutter_patcher/PatcherConfigTest.kt +30 -0
  44. package/dart-src/root/bin/pack.dart +182 -0
  45. package/dart-src/root/lib/flutter_ota_kit.dart +1170 -0
  46. package/dart-src/root/lib/src/app_version_resolver.dart +36 -0
  47. package/dart-src/root/lib/src/aws_update_source.dart +97 -0
  48. package/dart-src/root/lib/src/blacklist.dart +54 -0
  49. package/dart-src/root/lib/src/boot_diagnostic.dart +138 -0
  50. package/dart-src/root/lib/src/cloudflare_update_source.dart +97 -0
  51. package/dart-src/root/lib/src/flutter_ota_app.dart +69 -0
  52. package/dart-src/root/lib/src/io.dart +48 -0
  53. package/dart-src/root/lib/src/io_stub.dart +19 -0
  54. package/dart-src/root/lib/src/ota_progress_overlay.dart +1186 -0
  55. package/dart-src/root/lib/src/pack/pack.dart +434 -0
  56. package/dart-src/root/lib/src/patch_info.dart +12 -0
  57. package/dart-src/root/lib/src/patcher_channel.dart +160 -0
  58. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_database.dart +1 -1
  59. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_s3_client.dart +1 -1
  60. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_storage.dart +1 -1
  61. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_storage_profile.dart +1 -1
  62. package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/with_cloudfront_signed_url.dart +1 -1
  63. package/dart-src/root/lib/src/pkg/client/flutter_ota_kit_client.dart +1 -0
  64. package/dart-src/root/lib/src/pkg/client/src/server_update_source.dart +46 -0
  65. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/cloudflare_worker_database.dart +1 -1
  66. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_build_where.dart +1 -1
  67. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_bundle_mapper.dart +3 -3
  68. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_database.dart +1 -1
  69. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_database_plugin.dart +2 -2
  70. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_s3_client.dart +1 -1
  71. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_storage.dart +1 -1
  72. package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_storage_profile.dart +1 -1
  73. package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/status.dart +1 -1
  74. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/flutter_ota_kit_plugin_core.dart +1 -1
  75. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_blob_database_plugin.dart +1 -1
  76. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/filter_compatible_app_versions.dart +1 -1
  77. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/get_update_info.dart +1 -1
  78. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/request_update_bundle_state.dart +1 -1
  79. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/resolve_update_info_from_bundles.dart +1 -1
  80. package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/types.dart +2 -2
  81. package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_bundle_mapper.dart +2 -2
  82. package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_database.dart +26 -15
  83. package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_storage.dart +1 -1
  84. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_bundle_mapper.dart +2 -2
  85. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_database.dart +2 -2
  86. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_get_update_info.dart +2 -2
  87. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_storage.dart +1 -1
  88. package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_types.dart +1 -1
  89. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_bundle_mapper.dart +2 -2
  90. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_database.dart +2 -2
  91. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_edge_function_database.dart +1 -1
  92. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_edge_function_storage.dart +1 -1
  93. package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_storage.dart +1 -1
  94. package/dart-src/root/lib/src/pocketbase_update_source.dart +107 -0
  95. package/dart-src/root/lib/src/postgres_update_source.dart +95 -0
  96. package/dart-src/root/lib/src/shared_update_check.dart +131 -0
  97. package/dart-src/root/lib/src/supabase_update_source.dart +93 -0
  98. package/dart-src/root/pubspec.yaml +54 -0
  99. package/package.json +1 -1
  100. package/scripts/postinstall.js +17 -13
  101. package/scripts/vendor.sh +22 -7
  102. package/dart-src/packages/core/CHANGELOG.md +0 -21
  103. package/dart-src/packages/core/README.md +0 -23
  104. package/dart-src/packages/core/example/lib/main.dart +0 -69
  105. package/dart-src/packages/core/pubspec.yaml +0 -13
  106. package/dart-src/packages/core/test/rollout_test.dart +0 -135
  107. package/dart-src/packages/core/test/semver_test.dart +0 -55
  108. package/dart-src/packages/core/test/semver_vectors.json +0 -1
  109. package/dart-src/packages/core/test/types_test.dart +0 -131
  110. package/dart-src/packages/core/test/uuid_test.dart +0 -40
  111. package/dart-src/packages/core/tool/dbg.dart +0 -7
  112. package/dart-src/plugins/aws/.gitkeep +0 -0
  113. package/dart-src/plugins/aws/CHANGELOG.md +0 -23
  114. package/dart-src/plugins/aws/LICENSE +0 -21
  115. package/dart-src/plugins/aws/README.md +0 -28
  116. package/dart-src/plugins/aws/example/lib/main.dart +0 -60
  117. package/dart-src/plugins/aws/pubspec.yaml +0 -30
  118. package/dart-src/plugins/aws/test/aws_database_test.dart +0 -161
  119. package/dart-src/plugins/aws/test/aws_storage_test.dart +0 -73
  120. package/dart-src/plugins/aws/test/mock_aws_s3_client.dart +0 -78
  121. package/dart-src/plugins/cloudflare/.gitkeep +0 -0
  122. package/dart-src/plugins/cloudflare/CHANGELOG.md +0 -23
  123. package/dart-src/plugins/cloudflare/LICENSE +0 -21
  124. package/dart-src/plugins/cloudflare/README.md +0 -25
  125. package/dart-src/plugins/cloudflare/example/lib/main.dart +0 -62
  126. package/dart-src/plugins/cloudflare/migrations/0001_hot-updater_init.sql +0 -16
  127. package/dart-src/plugins/cloudflare/migrations/0002_hot-updater_0.13.0.sql +0 -8
  128. package/dart-src/plugins/cloudflare/migrations/0003_hot-updater_0.18.0.sql +0 -38
  129. package/dart-src/plugins/cloudflare/migrations/0004_hot-updater_0.29.0.sql +0 -11
  130. package/dart-src/plugins/cloudflare/migrations/0005_hot-updater_0.31.0.sql +0 -24
  131. package/dart-src/plugins/cloudflare/pubspec.yaml +0 -28
  132. package/dart-src/plugins/cloudflare/sql/bundles.sql +0 -42
  133. package/dart-src/plugins/cloudflare/test/cloudflare_worker_database_test.dart +0 -126
  134. package/dart-src/plugins/cloudflare/test/d1_bundle_mapper_test.dart +0 -106
  135. package/dart-src/plugins/cloudflare/test/d1_database_test.dart +0 -200
  136. package/dart-src/plugins/cloudflare/test/mock_d1_client.dart +0 -261
  137. package/dart-src/plugins/cloudflare/test/mock_r2_client.dart +0 -78
  138. package/dart-src/plugins/cloudflare/test/r2_storage_test.dart +0 -74
  139. package/dart-src/plugins/plugin-core/CHANGELOG.md +0 -20
  140. package/dart-src/plugins/plugin-core/LICENSE +0 -21
  141. package/dart-src/plugins/plugin-core/README.md +0 -21
  142. package/dart-src/plugins/plugin-core/example/lib/main.dart +0 -61
  143. package/dart-src/plugins/plugin-core/pubspec.yaml +0 -23
  144. package/dart-src/plugins/plugin-core/test/asset_storage_layout_test.dart +0 -170
  145. package/dart-src/plugins/plugin-core/test/bundle_unit_of_work_store_test.dart +0 -74
  146. package/dart-src/plugins/plugin-core/test/bundle_unit_of_work_test.dart +0 -345
  147. package/dart-src/plugins/plugin-core/test/create_blob_database_plugin_test.dart +0 -843
  148. package/dart-src/plugins/plugin-core/test/create_database_plugin_test.dart +0 -298
  149. package/dart-src/plugins/plugin-core/test/create_storage_plugin_test.dart +0 -195
  150. package/dart-src/plugins/plugin-core/test/generate_min_bundle_id_test.dart +0 -56
  151. package/dart-src/plugins/plugin-core/test/get_update_info_test.dart +0 -1589
  152. package/dart-src/plugins/plugin-core/test/helpers_test.dart +0 -283
  153. package/dart-src/plugins/plugin-core/test/query_bundles_test.dart +0 -202
  154. package/dart-src/plugins/plugin-core/test/request_update_bundle_state_test.dart +0 -86
  155. package/dart-src/plugins/plugin-core/test/uuidv7_test.dart +0 -88
  156. package/dart-src/plugins/pocketbase/CHANGELOG.md +0 -23
  157. package/dart-src/plugins/pocketbase/LICENSE +0 -21
  158. package/dart-src/plugins/pocketbase/README.md +0 -54
  159. package/dart-src/plugins/pocketbase/example/lib/main.dart +0 -62
  160. package/dart-src/plugins/pocketbase/pubspec.yaml +0 -26
  161. package/dart-src/plugins/pocketbase/test/pb_uri_test.dart +0 -12
  162. package/dart-src/plugins/postgres/.gitkeep +0 -0
  163. package/dart-src/plugins/postgres/CHANGELOG.md +0 -23
  164. package/dart-src/plugins/postgres/LICENSE +0 -21
  165. package/dart-src/plugins/postgres/README.md +0 -29
  166. package/dart-src/plugins/postgres/example/lib/main.dart +0 -67
  167. package/dart-src/plugins/postgres/pubspec.yaml +0 -26
  168. package/dart-src/plugins/postgres/sql/bundles.sql +0 -45
  169. package/dart-src/plugins/postgres/sql/get_target_app_version_list.sql +0 -21
  170. package/dart-src/plugins/postgres/sql/get_update_info.spec.ts +0 -171
  171. package/dart-src/plugins/postgres/sql/get_update_info_by_app_version.sql +0 -126
  172. package/dart-src/plugins/postgres/sql/get_update_info_by_fingerprint_hash.sql +0 -125
  173. package/dart-src/plugins/postgres/sql/hash_user_id.sql +0 -30
  174. package/dart-src/plugins/postgres/sql/is_device_eligible.sql +0 -237
  175. package/dart-src/plugins/postgres/sql/prepareSql.ts +0 -11
  176. package/dart-src/plugins/postgres/test/mock_postgres_client.dart +0 -320
  177. package/dart-src/plugins/postgres/test/postgres_bundle_mapper_test.dart +0 -139
  178. package/dart-src/plugins/postgres/test/postgres_database_test.dart +0 -210
  179. package/dart-src/plugins/postgres/test/postgres_storage_runtime_test.dart +0 -60
  180. package/dart-src/plugins/supabase/CHANGELOG.md +0 -24
  181. package/dart-src/plugins/supabase/LICENSE +0 -21
  182. package/dart-src/plugins/supabase/README.md +0 -53
  183. package/dart-src/plugins/supabase/example/lib/main.dart +0 -63
  184. package/dart-src/plugins/supabase/pubspec.yaml +0 -27
  185. package/dart-src/plugins/supabase/supabase/edge-functions/index.ts +0 -44
  186. package/dart-src/plugins/supabase/supabase/edge-functions/runtime.docker.integration.spec.ts +0 -968
  187. package/dart-src/plugins/supabase/supabase/migrations/20250103114225_init.sql +0 -232
  188. package/dart-src/plugins/supabase/supabase/migrations/20250314000000_hot-updater_0.13.0.sql +0 -137
  189. package/dart-src/plugins/supabase/supabase/migrations/20250516000000_hot-updater_0.18.0.sql +0 -206
  190. package/dart-src/plugins/supabase/supabase/migrations/20251014000000_hot-updater_0.21.0.sql +0 -186
  191. package/dart-src/plugins/supabase/supabase/migrations/20260401000000_hot-updater_0.29.0.sql +0 -505
  192. package/dart-src/plugins/supabase/supabase/migrations/20260414000000_hot-updater_0.30.0.sql +0 -50
  193. package/dart-src/plugins/supabase/supabase/migrations/20260422000000_hot-updater_0.31.0.sql +0 -20
  194. package/dart-src/plugins/supabase/supabase/migrations/20260520014100_hot-updater_rls.sql +0 -75
  195. package/dart-src/plugins/supabase/test/mock_supabase_client.dart +0 -654
  196. package/dart-src/plugins/supabase/test/supabase_bundle_mapper_test.dart +0 -115
  197. package/dart-src/plugins/supabase/test/supabase_database_test.dart +0 -198
  198. package/dart-src/plugins/supabase/test/supabase_storage_test.dart +0 -168
  199. /package/dart-src/{packages/core → root}/LICENSE +0 -0
  200. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/flutter_ota_kit_aws.dart +0 -0
  201. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_cloudfront_client.dart +0 -0
  202. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_cloudfront_signer.dart +0 -0
  203. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_config.dart +0 -0
  204. /package/dart-src/{plugins/aws/lib → root/lib/src/pkg/aws}/src/aws_ssm_client.dart +0 -0
  205. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/flutter_ota_kit_cloudflare.dart +0 -0
  206. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_client.dart +0 -0
  207. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/d1_config.dart +0 -0
  208. /package/dart-src/{plugins/cloudflare/lib → root/lib/src/pkg/cloudflare}/src/r2_config.dart +0 -0
  209. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/flutter_ota_kit_core.dart +0 -0
  210. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/app_update_info.dart +0 -0
  211. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/bundle.dart +0 -0
  212. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/bundle_artifacts.dart +0 -0
  213. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/bundle_patch_artifact.dart +0 -0
  214. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/changed_asset.dart +0 -0
  215. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/get_bundles_args.dart +0 -0
  216. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/metadata.dart +0 -0
  217. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/patch_info.dart +0 -0
  218. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/platform.dart +0 -0
  219. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/rollout.dart +0 -0
  220. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/semver.dart +0 -0
  221. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/semver_range.dart +0 -0
  222. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/semver_version.dart +0 -0
  223. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/strategy.dart +0 -0
  224. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/update_bundle_params.dart +0 -0
  225. /package/dart-src/{packages/core/lib → root/lib/src/pkg/core}/src/uuid.dart +0 -0
  226. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/asset_storage_layout.dart +0 -0
  227. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_helpers.dart +0 -0
  228. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_storage_layout.dart +0 -0
  229. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_unit_of_work.dart +0 -0
  230. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/bundle_unit_of_work_store.dart +0 -0
  231. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/calculate_pagination.dart +0 -0
  232. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/compression_format.dart +0 -0
  233. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/content_addressed_assets.dart +0 -0
  234. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_database_plugin.dart +0 -0
  235. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_storage_key_builder.dart +0 -0
  236. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/create_storage_plugin.dart +0 -0
  237. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/generate_min_bundle_id.dart +0 -0
  238. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/is_object.dart +0 -0
  239. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/legacy_asset_storage_layout.dart +0 -0
  240. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/paginate_bundles.dart +0 -0
  241. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/parse_storage_uri.dart +0 -0
  242. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/query_bundles.dart +0 -0
  243. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/storage_helpers.dart +0 -0
  244. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/storage_profile.dart +0 -0
  245. /package/dart-src/{plugins/plugin-core/lib → root/lib/src/pkg/plugin_core}/src/uuidv7.dart +0 -0
  246. /package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/flutter_ota_kit_pocketbase.dart +0 -0
  247. /package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_client.dart +0 -0
  248. /package/dart-src/{plugins/pocketbase/lib → root/lib/src/pkg/pocketbase}/src/pocketbase_config.dart +0 -0
  249. /package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/flutter_ota_kit_postgres.dart +0 -0
  250. /package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_client.dart +0 -0
  251. /package/dart-src/{plugins/postgres/lib → root/lib/src/pkg/postgres}/src/postgres_config.dart +0 -0
  252. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/edge.dart +0 -0
  253. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/flutter_ota_kit_supabase.dart +0 -0
  254. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/error_message.dart +0 -0
  255. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_client_adapter.dart +0 -0
  256. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_client_http.dart +0 -0
  257. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_config.dart +0 -0
  258. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/supabase_signed_url_batcher.dart +0 -0
  259. /package/dart-src/{plugins/supabase/lib → root/lib/src/pkg/supabase}/src/types.dart +0 -0
@@ -0,0 +1,434 @@
1
+ import 'dart:convert';
2
+ import 'dart:io';
3
+ import 'dart:typed_data';
4
+
5
+ import 'package:archive/archive.dart';
6
+ import 'package:crypto/crypto.dart';
7
+
8
+ const List<String> abiPriority = <String>['arm64-v8a', 'armeabi-v7a', 'x86_64'];
9
+ const String flutterAssetsPrefix = 'assets/flutter_assets/';
10
+ const String assetManifestPath = '${flutterAssetsPrefix}AssetManifest.bin';
11
+
12
+ /// Result of a successful [packPatch] run.
13
+ class PackResult {
14
+ const PackResult({
15
+ required this.payloadPath,
16
+ required this.manifestPath,
17
+ required this.abis,
18
+ required this.md5,
19
+ required this.version,
20
+ required this.targetVersionCode,
21
+ required this.assetCount,
22
+ });
23
+
24
+ final String payloadPath;
25
+ final String manifestPath;
26
+ final List<String> abis;
27
+ final String md5;
28
+ final String version;
29
+ final int targetVersionCode;
30
+ final int assetCount;
31
+ }
32
+
33
+ /// Pack a release APK into a device-compatible OTA patch (`patch.zip`).
34
+ ///
35
+ /// Mirrors the standalone `bin/pack.dart` CLI, but as a library usable by the
36
+ /// `flutter_ota_kit build` command. Includes **every** ABI found in the APK so
37
+ /// a single bundle serves all device ABIs (the device SDK picks its ABI).
38
+ Future<PackResult> packPatch({
39
+ required String apkPath,
40
+ required String version,
41
+ required int targetVersionCode,
42
+ String? abi,
43
+ List<String> requestedAssets = const [],
44
+ required String out,
45
+ void Function(int done, int total, String label)? onProgress,
46
+ }) async {
47
+ final apkFile = File(apkPath);
48
+ if (!apkFile.existsSync()) {
49
+ throw PackException('APK not found: $apkPath');
50
+ }
51
+
52
+ final apkBytes = apkFile.readAsBytesSync();
53
+ final archive = ZipDecoder().decodeBytes(apkBytes);
54
+
55
+ final libs = _collectLibapps(archive);
56
+ if (libs.isEmpty) {
57
+ throw PackException(
58
+ 'libapp.so not found in APK for any of $abiPriority '
59
+ '(or requested --abi $abi).',
60
+ );
61
+ }
62
+
63
+ if (abi != null && !libs.any((e) => e.$1 == abi)) {
64
+ throw PackException('requested --abi $abi not present in APK.');
65
+ }
66
+
67
+ final outDir = Directory(out);
68
+ outDir.createSync(recursive: true);
69
+ final result = _writePatchPackage(
70
+ outDir: outDir,
71
+ archive: archive,
72
+ libs: libs,
73
+ version: version,
74
+ targetVersionCode: targetVersionCode,
75
+ requestedAssets: requestedAssets,
76
+ abi: abi,
77
+ onProgress: onProgress,
78
+ );
79
+ return result;
80
+ }
81
+
82
+ PackResult _writePatchPackage({
83
+ required Directory outDir,
84
+ required Archive archive,
85
+ required List<(String, List<int>)> libs,
86
+ required String version,
87
+ required int targetVersionCode,
88
+ required List<String> requestedAssets,
89
+ String? abi,
90
+ void Function(int done, int total, String label)? onProgress,
91
+ }) {
92
+ // When an ABI is requested, restrict the patch to only that ABI instead of
93
+ // shipping every architecture found in the APK.
94
+ final effectiveLibs = abi == null
95
+ ? libs
96
+ : libs.where((e) => e.$1 == abi).toList();
97
+ final patchFiles = <String, _PatchAssetFile>{};
98
+ final operations = <Map<String, dynamic>>[];
99
+ var baseManifestSize = 0;
100
+
101
+ if (requestedAssets.isNotEmpty) {
102
+ final manifestEntry = _findFile(archive, assetManifestPath);
103
+ if (manifestEntry == null) {
104
+ throw PackException(
105
+ 'AssetManifest.bin not found in APK: $assetManifestPath',
106
+ );
107
+ }
108
+ final manifestBytes = _archiveFileBytes(manifestEntry);
109
+ baseManifestSize = manifestBytes.length;
110
+ final decoded = _FlutterStandardMessageCodec().decode(manifestBytes);
111
+ if (decoded is! Map) {
112
+ throw PackException('AssetManifest.bin must decode to a map.');
113
+ }
114
+ final assetManifest = Map<String, dynamic>.from(decoded);
115
+
116
+ for (final key in requestedAssets) {
117
+ final variantsRaw = assetManifest[key];
118
+ if (variantsRaw is! List) {
119
+ throw PackException('asset key not found in AssetManifest.bin: $key');
120
+ }
121
+ final variants = variantsRaw
122
+ .map((variant) => Map<String, dynamic>.from(variant as Map))
123
+ .toList(growable: false);
124
+ operations.add({'op': 'upsert', 'key': key, 'variants': variants});
125
+ for (final variant in variants) {
126
+ final assetPath = variant['asset'];
127
+ if (assetPath is! String || assetPath.isEmpty) {
128
+ throw PackException('invalid variant asset for key $key');
129
+ }
130
+ _validateArchiveRelativePath(assetPath, 'asset path');
131
+ final apkPath = '$flutterAssetsPrefix$assetPath';
132
+ final entry = _findFile(archive, apkPath);
133
+ if (entry == null) {
134
+ throw PackException(
135
+ 'variant file for $key not found in APK: $apkPath',
136
+ );
137
+ }
138
+ final bytes = _archiveFileBytes(entry);
139
+ patchFiles[assetPath] = _PatchAssetFile(
140
+ path: assetPath,
141
+ bytes: bytes,
142
+ md5Hex: md5.convert(bytes).toString(),
143
+ );
144
+ }
145
+ }
146
+ }
147
+
148
+ final libManifest = <String, dynamic>{
149
+ for (final (currentAbi, soBytes) in effectiveLibs)
150
+ currentAbi: {
151
+ 'path': 'lib/$currentAbi/libapp.so',
152
+ 'md5': md5.convert(soBytes).toString(),
153
+ },
154
+ };
155
+
156
+ final zipManifest = <String, dynamic>{
157
+ 'schemaVersion': 2,
158
+ 'version': version,
159
+ 'targetVersionCode': targetVersionCode,
160
+ 'lib': libManifest,
161
+ if (requestedAssets.isNotEmpty)
162
+ 'assets': {
163
+ 'mode': 'overlay',
164
+ 'manifestPatch': 'manifest_patch.json',
165
+ 'prefix': 'assets/',
166
+ 'files': patchFiles.values
167
+ .map(
168
+ (file) => {
169
+ 'path': file.path,
170
+ 'md5': file.md5Hex,
171
+ 'size': file.bytes.length,
172
+ },
173
+ )
174
+ .toList(),
175
+ },
176
+ };
177
+
178
+ final package = Archive()
179
+ ..addFile(_jsonArchiveFile('manifest.json', zipManifest));
180
+ final progressTotal = effectiveLibs.length + 1;
181
+ onProgress?.call(0, progressTotal, 'libapp.so');
182
+ var progressDone = 0;
183
+ for (final (currentAbi, soBytes) in effectiveLibs) {
184
+ package.addFile(
185
+ ArchiveFile('lib/$currentAbi/libapp.so', soBytes.length, soBytes),
186
+ );
187
+ progressDone++;
188
+ onProgress?.call(progressDone, progressTotal, 'lib/$currentAbi/libapp.so');
189
+ }
190
+
191
+ if (requestedAssets.isNotEmpty) {
192
+ final manifestPatch = <String, dynamic>{
193
+ 'schemaVersion': 1,
194
+ 'manifestFormat': 'bin',
195
+ 'baseManifestSize': baseManifestSize,
196
+ 'operations': operations,
197
+ };
198
+ package.addFile(_jsonArchiveFile('manifest_patch.json', manifestPatch));
199
+ for (final file in patchFiles.values) {
200
+ package.addFile(
201
+ ArchiveFile('assets/${file.path}', file.bytes.length, file.bytes),
202
+ );
203
+ }
204
+ }
205
+
206
+ // archive 3.x returns List<int>?, 4.x returns List<int>; drop the null-coalesce
207
+ // because we resolve archive >= 4 in the lockfile (and the constraint below).
208
+ final List<int> packageBytes = ZipEncoder().encode(package);
209
+ final outZip = File('${outDir.path}/patch.zip');
210
+ outZip.writeAsBytesSync(packageBytes);
211
+ onProgress?.call(progressTotal, progressTotal, 'patch.zip');
212
+
213
+ final payloadMd5 = md5.convert(packageBytes).toString();
214
+ final outerManifest = <String, dynamic>{
215
+ 'schemaVersion': 2,
216
+ 'version': version,
217
+ 'md5': payloadMd5,
218
+ 'targetVersionCode': targetVersionCode,
219
+ 'abis': effectiveLibs.map((e) => e.$1).toList(),
220
+ 'payload': 'patch.zip',
221
+ };
222
+ _writeJson(File('${outDir.path}/manifest.json'), outerManifest);
223
+
224
+ return PackResult(
225
+ payloadPath: outZip.path,
226
+ manifestPath: '${outDir.path}/manifest.json',
227
+ abis: effectiveLibs.map((e) => e.$1).toList(),
228
+ md5: payloadMd5,
229
+ version: version,
230
+ targetVersionCode: targetVersionCode,
231
+ assetCount: patchFiles.length,
232
+ );
233
+ }
234
+
235
+ ArchiveFile _jsonArchiveFile(String name, Map<String, dynamic> json) {
236
+ final bytes = utf8.encode(
237
+ '${const JsonEncoder.withIndent(' ').convert(json)}\n',
238
+ );
239
+ return ArchiveFile(name, bytes.length, bytes);
240
+ }
241
+
242
+ /// Collect every `lib/<abi>/libapp.so` present in the APK.
243
+ List<(String, List<int>)> _collectLibapps(Archive archive) {
244
+ final found = <(String, List<int>)>[];
245
+ final seen = <String>{};
246
+ final regex = RegExp(r'^lib/([^/]+)/libapp\.so$');
247
+ for (final file in archive.files) {
248
+ final m = regex.firstMatch(file.name);
249
+ if (m != null && seen.add(m.group(1)!)) {
250
+ found.add((m.group(1)!, _archiveFileBytes(file)));
251
+ }
252
+ }
253
+ found.sort((a, b) {
254
+ final ia = abiPriority.indexOf(a.$1);
255
+ final ib = abiPriority.indexOf(b.$1);
256
+ final ra = ia < 0 ? _nonPriorityRank(a.$1) : ia;
257
+ final rb = ib < 0 ? _nonPriorityRank(b.$1) : ib;
258
+ return ra.compareTo(rb);
259
+ });
260
+ return found;
261
+ }
262
+
263
+ int _nonPriorityRank(String abi) => abiPriority.length;
264
+
265
+ ArchiveFile? _findFile(Archive archive, String name) {
266
+ for (final file in archive.files) {
267
+ if (!file.isFile) continue;
268
+ if (file.name == name) return file;
269
+ }
270
+ return null;
271
+ }
272
+
273
+ void _writeJson(File file, Map<String, dynamic> json) {
274
+ file.writeAsStringSync(
275
+ '${const JsonEncoder.withIndent(' ').convert(json)}\n',
276
+ );
277
+ }
278
+
279
+ void _validateArchiveRelativePath(String path, String label) {
280
+ if (path.isEmpty ||
281
+ path.startsWith('/') ||
282
+ path.startsWith('\\') ||
283
+ path.contains('\u0000') ||
284
+ path.split('/').contains('..')) {
285
+ throw PackException('invalid $label: $path');
286
+ }
287
+ }
288
+
289
+ List<int> _archiveFileBytes(ArchiveFile file) {
290
+ final dynamic dynamicFile = file;
291
+ try {
292
+ return List<int>.from(dynamicFile.readBytes() as List<int>);
293
+ } on NoSuchMethodError {
294
+ return List<int>.from(dynamicFile.content as List<int>);
295
+ }
296
+ }
297
+
298
+ class _PatchAssetFile {
299
+ const _PatchAssetFile({
300
+ required this.path,
301
+ required this.bytes,
302
+ required this.md5Hex,
303
+ });
304
+
305
+ final String path;
306
+ final List<int> bytes;
307
+ final String md5Hex;
308
+ }
309
+
310
+ /// Error carrying a stable CLI exit code.
311
+ class PackException implements Exception {
312
+ const PackException(this.message, [this.exitCode = 1]);
313
+
314
+ final String message;
315
+ final int exitCode;
316
+ }
317
+
318
+ class _FlutterStandardMessageCodec {
319
+ late ByteData _data;
320
+ late int _offset;
321
+
322
+ Object? decode(List<int> bytes) {
323
+ final list = Uint8List.fromList(bytes);
324
+ _data = ByteData.sublistView(list);
325
+ _offset = 0;
326
+ final value = _readValue();
327
+ if (_offset != _data.lengthInBytes) {
328
+ throw PackException('AssetManifest.bin has trailing bytes.');
329
+ }
330
+ return value;
331
+ }
332
+
333
+ Object? _readValue() {
334
+ final type = _readUint8();
335
+ switch (type) {
336
+ case 0:
337
+ return null;
338
+ case 1:
339
+ return true;
340
+ case 2:
341
+ return false;
342
+ case 3:
343
+ return _readInt32();
344
+ case 4:
345
+ return _readInt64();
346
+ case 6:
347
+ _alignTo(8);
348
+ return _readFloat64();
349
+ case 7:
350
+ final len = _readSize();
351
+ final bytes = _readBytes(len);
352
+ return utf8.decode(bytes);
353
+ case 12:
354
+ final len = _readSize();
355
+ return List<Object?>.generate(len, (_) => _readValue());
356
+ case 13:
357
+ final len = _readSize();
358
+ final map = <Object?, Object?>{};
359
+ for (var i = 0; i < len; i++) {
360
+ map[_readValue()] = _readValue();
361
+ }
362
+ return map;
363
+ default:
364
+ throw PackException(
365
+ 'unsupported StandardMessageCodec type in AssetManifest.bin: $type',
366
+ );
367
+ }
368
+ }
369
+
370
+ int _readSize() {
371
+ final first = _readUint8();
372
+ if (first < 254) return first;
373
+ if (first == 254) return _readUint16();
374
+ return _readUint32();
375
+ }
376
+
377
+ int _readUint8() {
378
+ _ensure(1);
379
+ return _data.getUint8(_offset++);
380
+ }
381
+
382
+ int _readUint16() {
383
+ _ensure(2);
384
+ final value = _data.getUint16(_offset, Endian.little);
385
+ _offset += 2;
386
+ return value;
387
+ }
388
+
389
+ int _readUint32() {
390
+ _ensure(4);
391
+ final value = _data.getUint32(_offset, Endian.little);
392
+ _offset += 4;
393
+ return value;
394
+ }
395
+
396
+ int _readInt32() {
397
+ _ensure(4);
398
+ final value = _data.getInt32(_offset, Endian.little);
399
+ _offset += 4;
400
+ return value;
401
+ }
402
+
403
+ int _readInt64() {
404
+ _ensure(8);
405
+ final value = _data.getInt64(_offset, Endian.little);
406
+ _offset += 8;
407
+ return value;
408
+ }
409
+
410
+ double _readFloat64() {
411
+ _ensure(8);
412
+ final value = _data.getFloat64(_offset, Endian.little);
413
+ _offset += 8;
414
+ return value;
415
+ }
416
+
417
+ Uint8List _readBytes(int length) {
418
+ _ensure(length);
419
+ final start = _offset;
420
+ _offset += length;
421
+ return _data.buffer.asUint8List(start, length);
422
+ }
423
+
424
+ void _alignTo(int alignment) {
425
+ final mod = _offset % alignment;
426
+ if (mod != 0) _offset += alignment - mod;
427
+ }
428
+
429
+ void _ensure(int length) {
430
+ if (_offset + length > _data.lengthInBytes) {
431
+ throw PackException('truncated AssetManifest.bin');
432
+ }
433
+ }
434
+ }
@@ -0,0 +1,12 @@
1
+ // Re-exported from `flutter_ota_kit_core` (the canonical, framework-agnostic
2
+ // home for the data model). The device SDK previously defined these here; they
3
+ // now live in core so the server client can produce `PatchInfo` without pulling
4
+ // in the Flutter plugin.
5
+ export 'package:flutter_ota_kit/src/pkg/core/flutter_ota_kit_core.dart'
6
+ show
7
+ PatchApplyError,
8
+ PatchApplyPhase,
9
+ PatchApplyProgress,
10
+ PatchApplyResult,
11
+ PatchCheckResult,
12
+ PatchInfo;
@@ -0,0 +1,160 @@
1
+ import 'package:flutter/services.dart';
2
+ import 'package:restart_app/restart_app.dart';
3
+
4
+ /// MethodChannel constants and thin wrappers for talking to the Android native layer.
5
+ class PatcherChannel {
6
+ PatcherChannel._();
7
+
8
+ static const MethodChannel channel = MethodChannel('flutter_ota_kit');
9
+
10
+ /// Persists the Dart-side config to native (SharedPreferences). On the next cold
11
+ /// start the native side reads this config during `Application.attachBaseContext`
12
+ /// to verify signatures and load the patch.
13
+ static Future<void> saveConfig({
14
+ required String publicKeyBase64,
15
+ required int maxCrashCount,
16
+ required bool strictSignature,
17
+ required List<String> loaderFieldCandidates,
18
+ required bool loaderFallbackHeuristic,
19
+ int maxPatchHistory = 4,
20
+ int maxAssetHistory = 4,
21
+ }) async {
22
+ await channel.invokeMethod<void>('saveConfig', {
23
+ 'publicKeyBase64': publicKeyBase64,
24
+ 'maxCrashCount': maxCrashCount,
25
+ 'strictSignature': strictSignature,
26
+ 'loaderFieldCandidates': loaderFieldCandidates,
27
+ 'loaderFallbackHeuristic': loaderFallbackHeuristic,
28
+ 'maxPatchHistory': maxPatchHistory,
29
+ 'maxAssetHistory': maxAssetHistory,
30
+ });
31
+ }
32
+
33
+ /// Called at the very start of Dart `init`: marks "booting" (it cross-checks the
34
+ /// native `attachBaseContext` marker as a safety net).
35
+ static Future<void> markBooting() async {
36
+ await channel.invokeMethod<void>('markBooting');
37
+ }
38
+
39
+ /// Called after the first Dart frame renders -> resets the circuit-breaker counter.
40
+ static Future<void> reportBootSuccess() async {
41
+ await channel.invokeMethod<void>('reportBootSuccess');
42
+ }
43
+
44
+ /// Reports an uncaught Dart exception during the boot phase. The native side treats
45
+ /// it like an `ApplicationExitInfo` REASON_CRASH: `crash_count += 1`, and once the
46
+ /// threshold is reached it trips the circuit breaker, deletes the patch, and
47
+ /// blacklists it.
48
+ ///
49
+ /// When called: only inside the "verifyAfter window" (between the first frame
50
+ /// rendering and `verifyAfter` seconds later), triggered by the
51
+ /// `PlatformDispatcher.onError` / `FlutterError.onError` hooks installed by
52
+ /// `FlutterPatcher.init`. Business exceptions after the window closes do not call
53
+ /// this method.
54
+ static Future<void> reportDartBootError(String message) async {
55
+ await channel.invokeMethod<void>('reportDartBootError', {
56
+ 'message': message,
57
+ });
58
+ }
59
+
60
+ /// Download + verify signature + write atomically (atomic swap). Takes effect on
61
+ /// the next cold start.
62
+ ///
63
+ /// The native side returns `Map{ok, error, message}`, deserialized by the caller
64
+ /// via `PatchApplyResult.fromNative`.
65
+ static Future<Object?> applyPatch(Map<String, dynamic> patch) async {
66
+ return channel.invokeMethod<Object?>('applyPatch', patch);
67
+ }
68
+
69
+ /// Deletes the current patch + resets the circuit-breaker flag.
70
+ static Future<void> rollback() async {
71
+ await channel.invokeMethod<void>('rollback');
72
+ }
73
+
74
+ /// Rolls back to the immediately previous patch in local history.
75
+ /// Returns the RollbackOutcome enum name as string.
76
+ static Future<String> rollbackToPrevious() async {
77
+ final result = await channel.invokeMethod<String>('rollbackToPrevious');
78
+ return result ?? 'FALLBACK_TO_BASE';
79
+ }
80
+
81
+ /// The currently installed patch version (null / empty when none installed).
82
+ static Future<String?> currentVersion() async {
83
+ return channel.invokeMethod<String>('currentVersion');
84
+ }
85
+
86
+ /// Diagnostics from the last cold-start patch load.
87
+ ///
88
+ /// The native side returns `Map?` (see `BootDiagnosticStore`), deserialized by the
89
+ /// caller via `PatchBootDiagnostic.fromNative`; `null` means it was never recorded.
90
+ static Future<Map<dynamic, dynamic>?> lastBootDiagnostic() async {
91
+ return channel.invokeMethod<Map<dynamic, dynamic>?>('lastBootDiagnostic');
92
+ }
93
+
94
+ /// Absolute path to a plugin-writable cache directory, used for internal staging by
95
+ /// `applyPatchBytes`. Isolated from the existing `PatchManager.patchDir` (one is
96
+ /// temporary staging, the other is the final patch).
97
+ static Future<String?> cacheDir() async {
98
+ return channel.invokeMethod<String>('cacheDir');
99
+ }
100
+
101
+ /// The host APK's versionCode (uses `longVersionCode` on API 28+). The native side
102
+ /// returns -1 (INVALID_VERSION_CODE) on failure.
103
+ static Future<int?> appVersionCode() async {
104
+ final v = await channel.invokeMethod<int>('appVersionCode');
105
+ if (v == null || v < 0) return null;
106
+ return v;
107
+ }
108
+
109
+ /// The device's preferred ABI, so the server can serve ABI-specific patches.
110
+ static Future<String?> deviceAbi() async {
111
+ return channel.invokeMethod<String>('deviceAbi');
112
+ }
113
+
114
+ /// The local blacklist of patches known to "crash on install". The native side
115
+ /// returns `List<Map>`, deserialized by the caller via `BlacklistEntry.fromNative`.
116
+ static Future<List<dynamic>?> blacklist() async {
117
+ return channel.invokeMethod<List<dynamic>>('blacklist');
118
+ }
119
+
120
+ /// Clears the blacklist. Use with care: normally only called during debugging.
121
+ static Future<void> clearBlacklist() async {
122
+ await channel.invokeMethod<void>('clearBlacklist');
123
+ }
124
+
125
+ /// Reports a failed patch apply to the native blacklist. The patch will be
126
+ /// skipped on future attempts.
127
+ static Future<void> reportApplyFailure({
128
+ required String version,
129
+ required String md5,
130
+ String reason = 'APPLY_FAILED',
131
+ }) async {
132
+ await channel.invokeMethod<void>('reportApplyFailure', {
133
+ 'version': version,
134
+ 'md5': md5,
135
+ 'reason': reason,
136
+ });
137
+ }
138
+
139
+ /// Checks whether a patch version (optionally with md5) is blacklisted.
140
+ static Future<bool> isVersionBlacklisted(String version, {String md5 = ''}) async {
141
+ final found = await channel.invokeMethod<bool>('isVersionBlacklisted', {
142
+ 'version': version,
143
+ 'md5': md5,
144
+ });
145
+ return found ?? false;
146
+ }
147
+
148
+ /// Immediately restarts the whole App process (so a forced update takes effect).
149
+ ///
150
+ /// Uses the `restart_app` package with [RestartMode.process], which on Android
151
+ /// starts a fresh launch activity and then terminates the current process
152
+ /// (`exit(0)`). This true cold restart is required so the patched `libapp.so`
153
+ /// and assets are reloaded on the next launch. Without the process kill, only
154
+ /// the Flutter engine would be recreated with the old, already-mapped library.
155
+ ///
156
+ /// On non-Android this is a no-op handled upstream by `FlutterPatcher.restart`.
157
+ static Future<void> restartApp() async {
158
+ await Restart.restartApp(mode: RestartMode.process);
159
+ }
160
+ }
@@ -1,6 +1,6 @@
1
1
  import 'dart:convert' show jsonDecode, jsonEncode, utf8;
2
2
 
3
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart'
3
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart'
4
4
  show BlobOperations, createBlobDatabasePlugin, updateJsonKeyRegex;
5
5
 
6
6
  import 'aws_cloudfront_client.dart'
@@ -3,7 +3,7 @@ import 'dart:io' show File;
3
3
  import 'dart:typed_data' show Uint8List;
4
4
 
5
5
  import 'package:crypto/crypto.dart' show Hmac, sha256;
6
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart'
6
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart'
7
7
  show StorageObject;
8
8
  import 'package:http/http.dart' show Client, Request, Response;
9
9
 
@@ -1,4 +1,4 @@
1
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart'
1
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart'
2
2
  show createUniversalStoragePlugin;
3
3
 
4
4
  import 'aws_config.dart' show AwsS3StorageConfig;
@@ -1,6 +1,6 @@
1
1
  import 'package:path/path.dart' show basename;
2
2
 
3
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart'
3
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart'
4
4
  show
5
5
  NodeStorageProfile,
6
6
  RuntimeStorageProfile,
@@ -1,4 +1,4 @@
1
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart'
1
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart'
2
2
  show RuntimeStorageProfile, StoragePlugin, StoragePluginProfiles;
3
3
 
4
4
  import 'aws_cloudfront_signer.dart' show cloudfrontSignedUrl;
@@ -0,0 +1 @@
1
+ export 'src/server_update_source.dart';