@_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
@@ -314,24 +314,52 @@ class InitCommand extends FlutterPatcherCommand {
314
314
  warn('pubspec.yaml not found; skipping dependency injection.');
315
315
  return;
316
316
  }
317
- var content = pubspec.readAsStringSync();
317
+ final content = pubspec.readAsStringSync();
318
318
  if (content.contains(RegExp(r'^\s*flutter_ota_kit\s*:', multiLine: true))) {
319
319
  step('pubspec.yaml already references flutter_ota_kit');
320
320
  return;
321
321
  }
322
- const dep = ' flutter_ota_kit: ^0.1.4\n';
322
+ // Prefer `flutter pub add`, which resolves the LATEST published version and
323
+ // writes a proper caret constraint — so the CLI never hardcodes (and never
324
+ // goes stale on) a version number.
325
+ final exe = _flutterOrDart();
326
+ if (exe != null) {
327
+ final res = Process.runSync(exe, ['pub', 'add', 'flutter_ota_kit']);
328
+ if (res.exitCode == 0) {
329
+ step('Added `flutter_ota_kit` (latest) via `$exe pub add`');
330
+ return;
331
+ }
332
+ warn('`$exe pub add flutter_ota_kit` failed; falling back to a manual '
333
+ 'edit. Run it yourself if the constraint looks wrong.');
334
+ }
335
+ // Fallback: append an unpinned dependency so `pub get` picks the latest
336
+ // compatible release. Still no hardcoded version.
323
337
  final marker = '\ndependencies:';
324
338
  final idx = content.indexOf(marker);
325
339
  if (idx == -1) {
326
- warn(
327
- 'Could not find a `dependencies:` block; add `flutter_ota_kit` manually.',
328
- );
340
+ warn('Could not find a `dependencies:` block; add `flutter_ota_kit` '
341
+ 'manually (run `flutter pub add flutter_ota_kit`).');
329
342
  return;
330
343
  }
331
344
  final insertAt = idx + marker.length;
332
- content = content.replaceRange(insertAt, insertAt, '\n$dep');
333
- pubspec.writeAsStringSync(content);
334
- step('Added `flutter_ota_kit` dependency to pubspec.yaml');
345
+ final updated =
346
+ content.replaceRange(insertAt, insertAt, '\n flutter_ota_kit: any\n');
347
+ pubspec.writeAsStringSync(updated);
348
+ step('Added `flutter_ota_kit` dependency to pubspec.yaml '
349
+ '(run `flutter pub get` to resolve the latest version)');
350
+ }
351
+
352
+ /// Resolve the `flutter` executable (preferred) or `dart` for `pub add`.
353
+ String? _flutterOrDart() {
354
+ for (final exe in const ['flutter', 'dart']) {
355
+ try {
356
+ final r = Process.runSync(exe, ['--version']);
357
+ if (r.exitCode == 0) return exe;
358
+ } catch (_) {
359
+ // not on PATH; try next
360
+ }
361
+ }
362
+ return null;
335
363
  }
336
364
 
337
365
  void _addInternetPermission() {
@@ -6,7 +6,7 @@ import 'dart:convert';
6
6
  import 'dart:io';
7
7
 
8
8
  import 'package:args/args.dart';
9
- import 'package:flutter_ota_kit_pocketbase/flutter_ota_kit_pocketbase.dart';
9
+ import 'package:flutter_ota_kit/src/pkg/pocketbase/flutter_ota_kit_pocketbase.dart';
10
10
  import 'package:path/path.dart' as p;
11
11
 
12
12
  import '../cli_base.dart';
@@ -1,5 +1,5 @@
1
1
  import 'package:flutter_ota_kit_cli/flutter_ota_kit_cli.dart';
2
- import 'package:flutter_ota_kit_core/flutter_ota_kit_core.dart';
2
+ import 'package:flutter_ota_kit/src/pkg/core/flutter_ota_kit_core.dart';
3
3
 
4
4
  import '../ui/ui.dart';
5
5
 
@@ -1,13 +1,13 @@
1
1
  import 'dart:convert';
2
2
  import 'dart:io';
3
3
 
4
- import 'package:flutter_ota_kit_aws/flutter_ota_kit_aws.dart';
4
+ import 'package:flutter_ota_kit/src/pkg/aws/flutter_ota_kit_aws.dart';
5
5
  import 'package:postgres/postgres.dart';
6
- import 'package:flutter_ota_kit_cloudflare/flutter_ota_kit_cloudflare.dart';
7
- import 'package:flutter_ota_kit_pocketbase/flutter_ota_kit_pocketbase.dart';
8
- import 'package:flutter_ota_kit_postgres/flutter_ota_kit_postgres.dart';
6
+ import 'package:flutter_ota_kit/src/pkg/cloudflare/flutter_ota_kit_cloudflare.dart';
7
+ import 'package:flutter_ota_kit/src/pkg/pocketbase/flutter_ota_kit_pocketbase.dart';
8
+ import 'package:flutter_ota_kit/src/pkg/postgres/flutter_ota_kit_postgres.dart';
9
9
 
10
- import 'package:flutter_ota_kit_supabase/flutter_ota_kit_supabase.dart';
10
+ import 'package:flutter_ota_kit/src/pkg/supabase/flutter_ota_kit_supabase.dart';
11
11
  import 'package:path/path.dart' as p;
12
12
 
13
13
  /// Resolved configuration for the flutter_ota_kit CLI.
@@ -2,8 +2,8 @@ import 'dart:convert';
2
2
  import 'dart:io';
3
3
 
4
4
  import 'package:crypto/crypto.dart';
5
- import 'package:flutter_ota_kit_core/flutter_ota_kit_core.dart';
6
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart';
5
+ import 'package:flutter_ota_kit/src/pkg/core/flutter_ota_kit_core.dart';
6
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart';
7
7
 
8
8
  import 'backend.dart';
9
9
  import 'sign.dart';
@@ -8,6 +8,7 @@ publish_to: none
8
8
 
9
9
  environment:
10
10
  sdk: '>=3.13.2 <4.0.0'
11
+ flutter: '>=3.47.2'
11
12
 
12
13
  dependencies:
13
14
  args: '>=2.4.0 <3.0.0'
@@ -17,13 +18,11 @@ dependencies:
17
18
  collection: ^1.18.0
18
19
  cryptography: ^2.7.0
19
20
  postgres: ^3.4.0
20
- flutter_ota_kit_core: ^0.1.6
21
- flutter_ota_kit_plugin_core: ^0.0.8
22
- flutter_ota_kit_supabase: ^0.1.8
23
- flutter_ota_kit_postgres: ^0.1.7
24
- flutter_ota_kit_cloudflare: ^0.1.7
25
- flutter_ota_kit_aws: ^0.1.7
26
- flutter_ota_kit_pocketbase: ^0.1.4
21
+ # All former sub-packages (core, plugin-core, backends) now live inside the
22
+ # merged `flutter_ota_kit` package under lib/src/pkg/. The CLI depends on the
23
+ # single package instead of eight. NOTE: `flutter_ota_kit` is a Flutter plugin,
24
+ # so building the CLI now requires the Flutter SDK (not just the Dart SDK).
25
+ flutter_ota_kit: ^0.2.1
27
26
  http: ^1.2.0
28
27
  shelf: ^1.4.0
29
28
 
@@ -31,17 +30,5 @@ dev_dependencies:
31
30
  test: ^1.25.0
32
31
 
33
32
  dependency_overrides:
34
- flutter_ota_kit_core:
35
- path: ../core
36
- flutter_ota_kit_plugin_core:
37
- path: ../../plugins/plugin-core
38
- flutter_ota_kit_supabase:
39
- path: ../../plugins/supabase
40
- flutter_ota_kit_postgres:
41
- path: ../../plugins/postgres
42
- flutter_ota_kit_cloudflare:
43
- path: ../../plugins/cloudflare
44
- flutter_ota_kit_aws:
45
- path: ../../plugins/aws
46
- flutter_ota_kit_pocketbase:
47
- path: ../../plugins/pocketbase
33
+ flutter_ota_kit:
34
+ path: ../../root
@@ -1,9 +1,9 @@
1
1
  import 'dart:io';
2
2
 
3
- import 'package:flutter_ota_kit_aws/flutter_ota_kit_aws.dart';
3
+ import 'package:flutter_ota_kit/src/pkg/aws/flutter_ota_kit_aws.dart';
4
4
  import 'package:flutter_ota_kit_cli/flutter_ota_kit_cli.dart';
5
- import 'package:flutter_ota_kit_cloudflare/flutter_ota_kit_cloudflare.dart';
6
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart';
5
+ import 'package:flutter_ota_kit/src/pkg/cloudflare/flutter_ota_kit_cloudflare.dart';
6
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart';
7
7
  import 'package:test/test.dart';
8
8
 
9
9
  import 'mocks/mock_aws_s3_client.dart' as aws;
@@ -2,7 +2,7 @@ import 'dart:io';
2
2
  import 'dart:typed_data';
3
3
 
4
4
  import 'package:flutter_ota_kit_cli/flutter_ota_kit_cli.dart';
5
- import 'package:flutter_ota_kit_supabase/src/supabase_client_adapter.dart';
5
+ import 'package:flutter_ota_kit/src/pkg/supabase/src/supabase_client_adapter.dart';
6
6
  import 'package:path/path.dart' as p;
7
7
  import 'package:test/test.dart';
8
8
 
@@ -1,9 +1,9 @@
1
1
  import 'dart:convert' show 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 StorageObject;
5
5
 
6
- import 'package:flutter_ota_kit_aws/flutter_ota_kit_aws.dart'
6
+ import 'package:flutter_ota_kit/src/pkg/aws/flutter_ota_kit_aws.dart'
7
7
  show AwsS3ClientLike, AwsS3StorageConfig;
8
8
 
9
9
  /// In-memory store backing [MockAwsS3Client].
@@ -1,13 +1,13 @@
1
1
  import 'dart:convert' show jsonDecode;
2
2
 
3
- import 'package:flutter_ota_kit_cloudflare/flutter_ota_kit_cloudflare.dart'
3
+ import 'package:flutter_ota_kit/src/pkg/cloudflare/flutter_ota_kit_cloudflare.dart'
4
4
  show
5
5
  CloudflareWorkerDatabaseConfig,
6
6
  D1ClientLike,
7
7
  D1DatabaseConfig,
8
8
  cloudflareWorkerDatabase,
9
9
  d1Database;
10
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart'
10
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart'
11
11
  show DatabasePlugin;
12
12
 
13
13
  /// In-memory store backing [MockD1Client], mirroring the D1 tables.
@@ -5,7 +5,7 @@
5
5
  /// `backends_test.dart`.
6
6
  library;
7
7
 
8
- import 'package:flutter_ota_kit_pocketbase/flutter_ota_kit_pocketbase.dart';
8
+ import 'package:flutter_ota_kit/src/pkg/pocketbase/flutter_ota_kit_pocketbase.dart';
9
9
  import 'package:http/http.dart' as http;
10
10
 
11
11
  class MockPocketBaseClient implements PocketBaseClient {
@@ -18,6 +18,9 @@ class MockPocketBaseClient implements PocketBaseClient {
18
18
  String? _email;
19
19
  String? _password;
20
20
 
21
+ @override
22
+ String get authToken => (_email != null && _password != null) ? 'mock-token' : '';
23
+
21
24
  @override
22
25
  void adminCredentials(String email, String password) {
23
26
  _email = email;
@@ -1,8 +1,8 @@
1
1
  import 'dart:typed_data';
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
 
5
- import 'package:flutter_ota_kit_postgres/flutter_ota_kit_postgres.dart';
5
+ import 'package:flutter_ota_kit/src/pkg/postgres/flutter_ota_kit_postgres.dart';
6
6
 
7
7
  /// In-memory store backing [MockPostgresClient]. Mirrors the `bundles` and
8
8
  /// `bundle_patches` tables (snake_case row maps).
@@ -1,4 +1,4 @@
1
- import 'package:flutter_ota_kit_pocketbase/flutter_ota_kit_pocketbase.dart';
1
+ import 'package:flutter_ota_kit/src/pkg/pocketbase/flutter_ota_kit_pocketbase.dart';
2
2
  import 'package:test/test.dart';
3
3
 
4
4
  import 'mocks/mock_pocketbase_client.dart' as pb;
@@ -0,0 +1,334 @@
1
+ # flutter_ota_kit
2
+
3
+ [![pub package](https://img.shields.io/pub/v/flutter_ota_kit.svg)](https://pub.dev/packages/flutter_ota_kit)
4
+ [![Platform](https://img.shields.io/badge/platform-Android-brightgreen)](https://flutter.dev)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ ### Ship Dart & asset hotfixes over the air. Your backend. No store review. No monthly bill.
8
+
9
+ **flutter_ota_kit** is open-source code push for **Flutter Android**. Push a bug
10
+ fix or a new screen, and your users get it on the next cold start — no Play
11
+ Store round-trip, no vendor lock-in, no per-seat pricing. The patch lives on
12
+ **your** infrastructure (Supabase, Postgres, Cloudflare, AWS S3, PocketBase, or
13
+ your own CDN), signed and integrity-checked, with automatic crash rollback if
14
+ anything goes wrong.
15
+
16
+ If you've used [Shorebird](https://shorebird.dev/),
17
+ [CodePush](https://learn.microsoft.com/en-us/appcenter/distribution/codepush/),
18
+ or [Expo EAS Update](https://docs.expo.dev/eas-update/introduction/), this is the
19
+ same idea for Flutter Android — MIT-licensed, self-hosted, and yours to keep.
20
+
21
+ ![Feature demo: apply a patch, cold restart, and rollback](doc/feature-presentation.gif)
22
+
23
+ ```yaml
24
+ dependencies:
25
+ flutter_ota_kit: ^0.2.0 # one package — every backend included
26
+ ```
27
+
28
+ > **v0.2.0 is a single package.** Everything — the device SDK plus all five
29
+ > backends — now ships inside `flutter_ota_kit`. There are no more
30
+ > `flutter_ota_kit_supabase` / `_postgres` / `_cloudflare` / `_aws` /
31
+ > `_pocketbase` packages to add. One import, one dependency.
32
+
33
+ ---
34
+
35
+ ## Why teams pick it
36
+
37
+ - **You own the pipeline.** Patches sit in your Supabase project, your S3
38
+ bucket, your Cloudflare account — not someone else's cloud. No third party
39
+ sees your code or your users.
40
+ - **Zero recurring cost.** MIT-licensed. The only bill is your own storage,
41
+ which for OTA payloads is pennies.
42
+ - **Ships in one dependency.** Add `flutter_ota_kit`, run `flutter-ota init`,
43
+ deploy. Five backends are built in; you configure the one you use.
44
+ - **Safe by default.** MD5 + Ed25519 verification, automatic crash rollback,
45
+ a bad-patch blacklist, and staged rollouts — all on by default.
46
+ - **Zero-code forced-update UI.** Opt in and the SDK renders a polished
47
+ full-screen install progress screen for you. Write no UI.
48
+
49
+ ---
50
+
51
+ ## How it compares
52
+
53
+ | | flutter_ota_kit | Shorebird | CodePush (React Native) |
54
+ |--------------------------|----------------------------------------------------------|-------------------------------|------------------------------|
55
+ | **Framework** | Flutter | Flutter | React Native |
56
+ | **Platforms** | Android | Android + iOS | Android + iOS (retired 2025) |
57
+ | **Hosting** | Your backend / your CDN — see [Backends](doc/backends.md) | Shorebird cloud (managed) | AppCenter cloud (deprecated) |
58
+ | **Update scope** | Dart AOT + Flutter assets | Dart code (engine-level diff) | JS bundle |
59
+ | **Takes effect** | Next cold start | Next restart | Next restart |
60
+ | **Cost** | Free (MIT) — you pay only your own storage | Free tier + paid plans | — |
61
+ | **Backend flexibility** | Supabase / Postgres / Cloudflare / AWS / PocketBase / BYO CDN | Cloud-managed only | — |
62
+ | **Forced updates** | Yes — built-in progress UI | Yes | Yes |
63
+ | **Crash rollback** | Automatic + bad-patch blacklist | Yes | Yes |
64
+ | **Signing** | Ed25519 (Android 13+) + MD5 | Yes | — |
65
+
66
+ **Choose Shorebird** if you need iOS today or want a fully managed cloud.
67
+
68
+ **Choose flutter_ota_kit** if you want OTA on infrastructure you control —
69
+ enterprise apps, regional distribution, air-gapped deployments, or non-Play
70
+ channels. Bring your own backend, CDN, and auth.
71
+
72
+ > Google Play and some stores restrict downloading executable code at runtime.
73
+ > flutter_ota_kit targets self-controlled, enterprise, or permissive
74
+ > distribution channels. Verify your channel's policy before shipping.
75
+
76
+ ---
77
+
78
+ ## Features
79
+
80
+ - **OTA code push** — replaces the Dart AOT `libapp.so` and Flutter assets on
81
+ the next cold start, with MD5 + Ed25519 integrity checks.
82
+ - **Five backends, built in** — Supabase (fully automated), Postgres,
83
+ Cloudflare (D1 + R2), AWS (S3 + optional CloudFront), and **PocketBase**
84
+ (single-binary, self-hosted). Or point at your own CDN.
85
+ - **Automatic crash rollback** — a patch that fails to boot is rolled back and
86
+ blacklisted so it's never retried. Tunable via `maxCrashCount` /
87
+ `verifyAfter`. A runtime crash *hours* after a healthy boot no longer reverts
88
+ a good patch (bounded crash-attribution window).
89
+ - **Forced updates with a built-in UI** — set `autoApplyUpdates: true` and wrap
90
+ your app in `FlutterOtaApp`; the SDK shows a full-screen terminal-style
91
+ install screen (steps, live progress bar, speed/ETA, server message) and
92
+ cold-restarts into the new build. You write no UI.
93
+ - **Staged rollout** — server-side cohort math (per-mille + target cohorts) lets
94
+ you ship 1% → 5% → 20% → 50% → 100% safely.
95
+ - **Batteries-included tooling** — the `flutter-ota` CLI (`init`, `build`,
96
+ `deploy`, `bundle`, `channel`, `rollback`, `migrate`, `doctor`, and a bundled
97
+ PocketBase manager), plus runtime diagnostics and a sample app.
98
+
99
+ ---
100
+
101
+ ## Try it in 5 minutes (no server needed)
102
+
103
+ ```bash
104
+ git clone https://github.com/HYPER12755/flutter-ota-kit.git
105
+ cd flutter-ota-kit/example
106
+ flutter pub get
107
+ flutter build apk --release
108
+ flutter install
109
+ ```
110
+
111
+ 1. Launch the app — it shows the **original** demo screen.
112
+ 2. Tap **Apply patch**.
113
+ 3. Swipe the app away from recents and reopen.
114
+ 4. The screen has changed — the patch took effect.
115
+ 5. Tap **Rollback** → restart → the original is back.
116
+
117
+ The example bundles a precompiled patch; everything runs offline on the device.
118
+ For a full backend walkthrough, see the [Beginner Guide](doc/beginner-guide.md)
119
+ or [Getting Started](doc/getting-started.md).
120
+
121
+ ---
122
+
123
+ ## Requirements
124
+
125
+ | Item | Requirement |
126
+ |--------------------------|----------------------------------------------------------|
127
+ | **Platform** | Android only (iOS / macOS / Windows / Linux / Web are no-ops) |
128
+ | **Dart SDK** | `>=3.13.2 <4.0.0` |
129
+ | **Flutter** | `>=3.47.2` |
130
+ | **Android `minSdk`** | 24 |
131
+ | **Android `compileSdk`** | 36 |
132
+ | **ABI** | `armeabi-v7a` / `arm64-v8a` / `x86_64` |
133
+ | **NDK** | 27.0.12077973+ |
134
+ | **Java / JVM** | 17 |
135
+
136
+ On non-Android platforms every API is safe to call but is a **no-op** — the
137
+ plugin logs a one-time warning and returns safe defaults, so you can ship
138
+ `flutter_ota_kit` in cross-platform code without guarding every call site.
139
+
140
+ ---
141
+
142
+ ## Quick start
143
+
144
+ ### 1. Install
145
+
146
+ ```yaml
147
+ dependencies:
148
+ flutter_ota_kit: ^0.2.0
149
+ ```
150
+
151
+ ### 2. Scaffold your backend (CLI)
152
+
153
+ ```bash
154
+ # installs the flutter-ota CLI globally
155
+ npm i -g @_nazmiforreal/flutter-ota
156
+
157
+ # scaffold config + a generated setup file for your backend
158
+ flutter-ota init supabase # or: postgres | cloudflare | aws | pocketbase
159
+ ```
160
+
161
+ `init` writes a `.flutter_ota_kit/config.json`, an `.env` template for secrets,
162
+ and a `lib/flutter_ota_kit_setup.dart` helper you call from `main()`.
163
+
164
+ ### 3. Initialize in your app
165
+
166
+ Call the generated `setupFlutterOta()` (or wire it by hand) before `runApp`:
167
+
168
+ ```dart
169
+ import 'package:flutter/material.dart';
170
+ import 'package:flutter_ota_kit/flutter_ota_kit.dart';
171
+ import 'flutter_ota_kit_setup.dart'; // generated by `flutter-ota init`
172
+
173
+ Future<void> main() async {
174
+ WidgetsFlutterBinding.ensureInitialized();
175
+ await setupFlutterOta(); // configures the backend + forced updates
176
+ runApp(const FlutterOtaApp(child: MyApp()));
177
+ }
178
+ ```
179
+
180
+ `FlutterOtaApp` is the zero-code wrapper that lets the SDK render its built-in
181
+ forced-update screen. Disable it app-wide with
182
+ `FlutterPatcher.showUpdateUi = false` (or `FlutterOtaApp(showUpdateUi: false)`),
183
+ or host it yourself by setting `MaterialApp.navigatorKey =
184
+ FlutterPatcher.navigatorKey`.
185
+
186
+ Prefer wiring the backend directly? Every backend has a `configureX` helper:
187
+
188
+ ```dart
189
+ FlutterPatcher.configureSupabase(SupabaseUpdateConfig(
190
+ supabaseUrl: 'https://<ref>.supabase.co',
191
+ anonKey: '<anon-key>', // public, RLS-protected reads
192
+ bucket: 'bundles',
193
+ channel: 'production',
194
+ platform: Platform.android,
195
+ updateStrategy: UpdateStrategy.appVersion,
196
+ appVersion: '1.0.0', // or omit — auto-detected from versionName
197
+ ));
198
+ await FlutterPatcher.init(autoApplyUpdates: true);
199
+ ```
200
+
201
+ ### 4. Build a patch
202
+
203
+ Rebuild the release APK, then pack it into a device-ready `patch.zip`:
204
+
205
+ ```bash
206
+ flutter build apk --release
207
+ flutter-ota build \
208
+ --apk build/app/outputs/flutter-apk/app-release.apk \
209
+ --version 1.0.1 \
210
+ --target-version-code 100
211
+ ```
212
+
213
+ Every ABI in the APK is included, so one bundle serves all devices. Add
214
+ `--assets assets/hero.png,assets/strings/zh.json` to overlay updated assets.
215
+
216
+ ### 5. Deploy
217
+
218
+ ```bash
219
+ flutter-ota deploy \
220
+ --source dist \
221
+ --channel production \
222
+ --target-app-version 1.0.0 \
223
+ --force
224
+ ```
225
+
226
+ That's it — devices pick up the patch on their next check.
227
+
228
+ ### 6. Roll back (server side)
229
+
230
+ ```bash
231
+ flutter-ota rollback --channel production
232
+ ```
233
+
234
+ Or on the device, `FlutterPatcher.rollback()` deletes the local patch and
235
+ reverts to the APK's built-in version on the next cold start.
236
+
237
+ ---
238
+
239
+ ## How it works
240
+
241
+ ```text
242
+ ┌─────────────────┐ Supabase / Postgres / Cloudflare / AWS / PocketBase / CDN
243
+ │ Your backend │ stores: patch.zip (the diff) + manifest.json (metadata)
244
+ └────────▲────────┘
245
+ │ 1. check-for-update on launch
246
+ │ 2. backend returns PatchInfo (url, md5, signature, force flag)
247
+ ┌────────┴────────┐
248
+ │ The app │ 3. download patch.zip
249
+ │ │ 4. verify MD5 + Ed25519 signature
250
+ │ │ 5. write to local patch dir (atomic rename)
251
+ │ │ 6. cold-restart (forced) OR next cold start (staged)
252
+ │ │ 7. loader hook reads patched libapp.so + asset overlays
253
+ │ │ 8. boot ok → keep · boot fails → auto-rollback + blacklist
254
+ └─────────────────┘
255
+ ```
256
+
257
+ A patch is a byte-for-byte diff of the new APK's `libapp.so` against the
258
+ version the user has installed; asset patches overlay `flutter_assets/` by path.
259
+ Nothing is swapped into the running process — it loads on the next cold start.
260
+
261
+ Full internals: [Architecture](doc/architecture.md).
262
+
263
+ ---
264
+
265
+ ## What can and can't be patched
266
+
267
+ | ✅ Hot-patchable | ❌ Not hot-patchable |
268
+ |------------------------------------------------------|----------------------------------------------------------|
269
+ | Anything in `lib/` — widgets, logic, routes, constants | Native code (Kotlin / Java / C++ in `android/src/main/`) |
270
+ | Pure-Dart package upgrades (same native side) | `AndroidManifest.xml` changes |
271
+ | Flutter asset files registered in `pubspec.yaml` | APK `res/` (icons, layouts, strings.xml) |
272
+ | New `Image.asset()` / `rootBundle.load()` calls | Flutter Engine upgrades |
273
+ | | Adding or removing native plugins |
274
+ | | Removing assets that exist in the base APK |
275
+
276
+ See [API Reference → What can be patched](doc/api-reference.md#what-can-and-cannot-be-patched)
277
+ for edge cases (ProGuard/R8, multi-ABI/flavors, state migrations).
278
+
279
+ ---
280
+
281
+ ## Safety
282
+
283
+ - **Crash protection (on by default).** If a patch fails to boot, the SDK
284
+ auto-rolls back and blacklists the offending version. Tune with
285
+ `maxCrashCount` (default 1) and `verifyAfter` (default 5s). Crash attribution
286
+ is bounded to a boot window, so an unrelated crash long after a healthy boot
287
+ won't revert a working patch. See [Crash Protection](doc/crash-protection.md).
288
+ - **Integrity & signing.** MD5 is strongly recommended; Ed25519 signature
289
+ verification is available on Android 13+ (falls back to MD5-only below, with a
290
+ warning). Patches are bound to the host APK's `versionCode`, so stale patches
291
+ expire after an app upgrade. Keep private signing keys on your server, never
292
+ in the app bundle.
293
+ - **Staged rollout.** Ship 1% → 5% → 20% → 50% → 100% and watch crash rate at
294
+ each stage. The SDK records `lastBootDiagnostic` per device.
295
+
296
+ Full release workflow: [Production Playbook](doc/production-playbook.md).
297
+
298
+ ---
299
+
300
+ ## Documentation
301
+
302
+ **Guides**
303
+
304
+ - [Beginner Guide](doc/beginner-guide.md) — zero to first OTA, narrated
305
+ - [Getting Started](doc/getting-started.md) — scaffold → build → deploy
306
+ - [Developer Guide](doc/developer-guide.md) — full workflow reference
307
+ - [Configuration](doc/configuration.md) — env vars, `.env`, resolution order
308
+ - [Backends](doc/backends.md) — Supabase / Postgres / Cloudflare / AWS / PocketBase setup
309
+ - [Production Playbook](doc/production-playbook.md) — staged rollout, diagnostics, rollback
310
+
311
+ **Reference**
312
+
313
+ - [API Reference](doc/api-reference.md) — `FlutterPatcher`, configs, overlay, error codes
314
+ - [Architecture](doc/architecture.md) — internals, protocol, signing
315
+ - [CLI Reference](doc/cli-reference.md) — every command and flag
316
+ - [Crash Protection](doc/crash-protection.md) — rollback, blacklist, Android differences
317
+ - [FAQ](doc/faq.md) — versioning, cold start, store policy
318
+
319
+ ---
320
+
321
+ ## Contributing
322
+
323
+ Issues and PRs welcome. Before submitting:
324
+
325
+ - `flutter analyze` reports no issues
326
+ - `flutter test` is fully green
327
+ - If you touched native code, run a real-device patch / rollback end-to-end
328
+ - Document new public APIs (they surface on pub.dev)
329
+
330
+ ---
331
+
332
+ ## License
333
+
334
+ MIT
@@ -0,0 +1,21 @@
1
+ # Root analysis options for the flutter_ota_kit monorepo.
2
+ #
3
+ # The repo is a monorepo: `packages/*`, `plugins/*`, and `example/` are each
4
+ # standalone Dart/Flutter packages that are analyzed (and lint-configured)
5
+ # independently. Excluding them here keeps `dart analyze .` focused on the root
6
+ # device-SDK package (`lib/` + `test/`), which is the only thing the root
7
+ # package owns. Each sub-package is analyzed on its own and is already clean.
8
+ analyzer:
9
+ exclude:
10
+ - packages/**
11
+ - plugins/**
12
+ - example/**
13
+ - node_modules/**
14
+ - npm/**
15
+ - build/**
16
+ - android/**
17
+ - ios/**
18
+ - web/**
19
+ - windows/**
20
+ - macos/**
21
+ - linux/**