@_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
package/README.md CHANGED
@@ -1,37 +1,131 @@
1
- # flutter-ota (flutter-ota CLI)
1
+ # flutter-ota
2
2
 
3
- Command-line interface for [flutter_ota_kit](https://github.com/HYPER12755/flutter-ota-kit) — a multi-backend OTA ("code push") toolkit for Flutter Android, hot-updater compatible.
3
+ [![npm](https://img.shields.io/npm/v/@_nazmiforreal/flutter-ota.svg)](https://www.npmjs.com/package/@_nazmiforreal/flutter-ota)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/HYPER12755/flutter-ota-kit/blob/main/LICENSE)
5
+
6
+ ### The command line for [flutter_ota_kit](https://pub.dev/packages/flutter_ota_kit) — build patches, deploy them to your backend, and manage rollouts.
7
+
8
+ `flutter-ota` is the companion CLI for **flutter_ota_kit**, open-source OTA code
9
+ push for Flutter Android. Pack a release APK into a signed patch, upload it to
10
+ the backend **you** own (Supabase / Postgres / Cloudflare / AWS / PocketBase),
11
+ and manage channels, staged rollouts, and instant rollback — no store review, no
12
+ monthly bill.
13
+
14
+ > The runtime SDK your app depends on is the separate
15
+ > [`flutter_ota_kit`](https://pub.dev/packages/flutter_ota_kit) pub package.
16
+
17
+ ---
4
18
 
5
19
  ## Install
6
20
 
7
21
  ```bash
8
22
  npm i -g @_nazmiforreal/flutter-ota
23
+ flutter-ota --help
24
+ ```
25
+
26
+ A prebuilt `linux-x64` binary ships in the package. On other platforms the CLI
27
+ compiles from bundled Dart source on first install, which needs the
28
+ [**Flutter SDK**](https://flutter.dev) (the CLI shares the `flutter_ota_kit`
29
+ Flutter package). If Flutter isn't available, build a binary once yourself:
30
+
31
+ ```bash
32
+ cd $(npm root -g)/@_nazmiforreal/flutter-ota/dart-src/packages/cli-tools
33
+ flutter pub get && dart compile exe bin/flutter_ota_kit.dart -o ../../bin/flutter-ota-<os>-<arch>
9
34
  ```
10
35
 
11
- This installs the `flutter-ota` command. A prebuilt Linux binary ships with the package; on other platforms it falls back to `dart compile exe` (requires the [Dart SDK](https://dart.dev)).
36
+ ---
12
37
 
13
- ## Usage
38
+ ## The 60-second workflow
14
39
 
15
40
  ```bash
16
- flutter-ota --help
17
- flutter-ota keys # generate an Ed25519 keypair
18
- flutter-ota build -a app-release.apk \
19
- --version 1.0.0 --target-version-code 1 # -> dist/patch.zip (all ABIs)
20
- flutter-ota deploy --source dist \
21
- --channel production --backend supabase \
22
- --key <PRIVATE_KEY_BASE64> # upload + sign a bundle
41
+ # 1. Scaffold config + a setup helper for your backend
42
+ # (adds the latest flutter_ota_kit to your pubspec automatically)
43
+ flutter-ota init supabase # or: postgres | cloudflare | aws | pocketbase
44
+
45
+ # 2. Provision the backend (Supabase & PocketBase are fully automated)
46
+ flutter-ota migrate supabase
47
+
48
+ # 3. Build the release APK, then pack it into a device-ready patch
49
+ flutter build apk --release
50
+ flutter-ota build \
51
+ --apk build/app/outputs/flutter-apk/app-release.apk \
52
+ --version 1.0.1 \
53
+ --target-version-code 100
54
+
55
+ # 4. Sign + deploy it to a channel
56
+ flutter-ota deploy --source dist --channel production \
57
+ --target-app-version 1.0.0 --force -m "hotfix: crash on login"
58
+ ```
59
+
60
+ Devices pick up the patch on their next launch. Pull it back with:
61
+
62
+ ```bash
63
+ flutter-ota rollback --channel production
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Commands
69
+
70
+ | Command | What it does |
71
+ |---------|--------------|
72
+ | `init <backend>` | Scaffold config, `.env`, and `lib/flutter_ota_kit_setup.dart`; add the SDK dependency + `INTERNET` permission |
73
+ | `build` | Pack a release APK into `dist/patch.zip` (all ABIs by default) |
74
+ | `deploy` | Upload + register a bundle; sign it with `--key` |
75
+ | `bundle` | `list` / `show` / `delete` / `disable` / `enable` / `force` / `promote` / `update` |
76
+ | `channel` | `list` / `get` / `set` the live bundle per channel |
77
+ | `rollback` | Disable the latest enabled bundle (or roll back to a specific one) |
78
+ | `storage` | `list` / `delete` stored bundle objects |
79
+ | `migrate` | Provision the backend schema |
80
+ | `keys` | Generate an Ed25519 signing keypair |
81
+ | `fingerprint` | Compute a deterministic build fingerprint |
82
+ | `doctor` | Diagnose the environment + backend connectivity |
83
+ | `config` | `get` / `set` / `list` config values |
84
+ | `console` | Open the web console |
85
+ | `pocketbase` | Manage a local single-binary PocketBase backend |
86
+
87
+ Help works at every level, including nested subcommands:
88
+
89
+ ```bash
90
+ flutter-ota deploy --help
91
+ flutter-ota bundle list --help
92
+ flutter-ota pocketbase records list --help
23
93
  ```
24
94
 
25
- ### Backends
95
+ ---
96
+
97
+ ## Backends
98
+
99
+ Select one with `--backend supabase|postgres|cloudflare|aws|pocketbase` (or set
100
+ `provider` in `.flutter_ota_kit/config.json`). Settings resolve with a clear
101
+ precedence:
102
+
103
+ ```
104
+ explicit flag > environment variable > .flutter_ota_kit/config.json > default
105
+ ```
106
+
107
+ Config search order: `./.flutter_ota_kit/config.json`, then
108
+ `~/.flutter_ota_kit/config.json`. Secrets belong in your shell env or `.env`,
109
+ never in committed config.
110
+
111
+ | Backend | Provisioning |
112
+ |---------|--------------|
113
+ | **Supabase** | `migrate supabase` — SQL + storage bucket, fully automated |
114
+ | **PocketBase** | `pocketbase install` + `pocketbase serve` — single binary, schema auto-installed |
115
+ | **Postgres** | `migrate postgres` applies SQL migrations |
116
+ | **Cloudflare** | `migrate cloudflare` creates D1 + R2, runs SQL |
117
+ | **AWS** | No SQL — S3 bucket/prefix created on first `deploy` |
118
+
119
+ ---
26
120
 
27
- `--backend supabase|postgres|cloudflare|aws`.
28
- Each resolves its own env / `.flutter_ota_kit/config.json` (global: `~/.flutter_ota_kit/config.json`).
121
+ ## Documentation
29
122
 
30
- ### Commands
123
+ - [CLI Reference](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/cli-reference.md)
124
+ - [Getting Started](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/getting-started.md)
125
+ - [Backends](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/backends.md)
126
+ - [Production Playbook](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/production-playbook.md)
31
127
 
32
- `init`, `build`, `deploy`, `bundle` (list/show/delete/disable/enable/force/promote/update),
33
- `rollback`, `channel` (list/get/set), `fingerprint`, `doctor`, `migrate`, `config`
34
- (get/set/list), `keys`, `console`, `storage` (list/delete).
128
+ ---
35
129
 
36
130
  ## License
37
131
 
Binary file
@@ -55,31 +55,32 @@ if (fs.existsSync(binPath)) {
55
55
  chmodIfNeeded(binPath);
56
56
  run(binPath, process.argv.slice(2));
57
57
  } else if (
58
- spawnSync('dart', ['--version'], { stdio: 'ignore' }).status === 0 &&
58
+ spawnSync('flutter', ['--version'], { stdio: 'ignore' }).status === 0 &&
59
59
  fs.existsSync(sourceEntry)
60
60
  ) {
61
- // Ensure dependencies are resolved before running from source. We only run
62
- // `dart pub get` when the package config is missing, so repeated invocations
63
- // don't re-resolve dependencies on every command.
61
+ // Fallback for platforms/arches without a shipped prebuilt binary.
62
+ // Since v0.2.0 the CLI depends on the `flutter_ota_kit` Flutter package, so
63
+ // dependency resolution needs `flutter pub get` (not `dart pub get`). The CLI
64
+ // entrypoint itself only touches pure-Dart backend code, so `dart run` of the
65
+ // resolved package still works.
64
66
  const configPath = path.join(cliDir, '.dart_tool', 'package_config.json');
65
67
  if (!fs.existsSync(configPath)) {
66
- const getRes = spawnSync('dart', ['pub', 'get'], { stdio: 'inherit', cwd: cliDir });
68
+ const getRes = spawnSync('flutter', ['pub', 'get'], { stdio: 'inherit', cwd: cliDir });
67
69
  if (getRes.status !== 0) {
68
70
  console.error(
69
- 'flutter-ota: `dart pub get` failed. Install dependencies or build ' +
70
- `a prebuilt manually:\n cd ${cliDir} && dart compile exe ` +
71
- `bin/flutter_ota_kit.dart -o ${binPath}`,
71
+ 'flutter-ota: `flutter pub get` failed. Install the Flutter SDK or ' +
72
+ `build a prebuilt manually:\n cd ${cliDir} && flutter pub get && ` +
73
+ `dart compile exe bin/flutter_ota_kit.dart -o ${binPath}`,
72
74
  );
73
75
  process.exit(1);
74
76
  }
75
77
  }
76
- chmodIfNeeded(binPath);
77
78
  run('dart', [sourceEntry, ...process.argv.slice(2)]);
78
79
  } else {
79
80
  console.error(
80
81
  `flutter-ota: no prebuilt binary for ${platformName}-${archName} and ` +
81
- 'the Dart SDK was not found. Install Dart (https://dart.dev) or use a ' +
82
- 'platform/arch with a shipped prebuilt binary.',
82
+ 'the Flutter SDK was not found. Install Flutter (https://flutter.dev) or ' +
83
+ 'use a platform/arch with a shipped prebuilt binary.',
83
84
  );
84
85
  process.exit(1);
85
86
  }
@@ -1,5 +1,149 @@
1
1
  # flutter_ota_kit_cli
2
2
 
3
- Part of the [flutter_ota_kit](https://github.com/HYPER12755/flutter-ota-kit) OTA (over-the-air) update toolkit for Flutter Android.
3
+ [![npm](https://img.shields.io/npm/v/@_nazmiforreal/flutter-ota.svg)](https://www.npmjs.com/package/@_nazmiforreal/flutter-ota)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](../../LICENSE)
4
5
 
5
- See the project README for usage, backend setup, and the architecture overview.
6
+ ### The command line for [flutter_ota_kit](https://pub.dev/packages/flutter_ota_kit) — build patches, deploy them to your backend, and manage rollouts.
7
+
8
+ `flutter-ota` is the companion CLI for **flutter_ota_kit**, open-source OTA code
9
+ push for Flutter Android. It packs a release APK into a signed patch, uploads it
10
+ to the backend **you** own (Supabase / Postgres / Cloudflare / AWS / PocketBase),
11
+ and gives you first-class commands for channels, staged rollouts, and instant
12
+ rollback.
13
+
14
+ > This tool ships via npm as `@_nazmiforreal/flutter-ota`. The runtime SDK your
15
+ > app depends on is the separate [`flutter_ota_kit`](https://pub.dev/packages/flutter_ota_kit)
16
+ > pub package.
17
+
18
+ ---
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ npm i -g @_nazmiforreal/flutter-ota
24
+ flutter-ota --help
25
+ ```
26
+
27
+ A prebuilt `linux-x64` binary ships in the package. On other platforms the CLI
28
+ compiles from bundled Dart source on first install, which needs the
29
+ [**Flutter SDK**](https://flutter.dev) (the CLI shares the `flutter_ota_kit`
30
+ package). No Flutter? Point `flutter-ota` at a prebuilt binary you build once
31
+ with `dart compile exe`.
32
+
33
+ ---
34
+
35
+ ## The 60-second workflow
36
+
37
+ ```bash
38
+ # 1. Scaffold config + a setup helper for your backend (adds the latest
39
+ # flutter_ota_kit to your pubspec automatically)
40
+ flutter-ota init supabase # or: postgres | cloudflare | aws | pocketbase
41
+
42
+ # 2. Provision the backend (Supabase & PocketBase are fully automated)
43
+ flutter-ota migrate supabase
44
+
45
+ # 3. Build the release APK, then pack it into a device-ready patch
46
+ flutter build apk --release
47
+ flutter-ota build \
48
+ --apk build/app/outputs/flutter-apk/app-release.apk \
49
+ --version 1.0.1 \
50
+ --target-version-code 100
51
+
52
+ # 4. Sign + deploy it to a channel
53
+ flutter-ota deploy --source dist --channel production \
54
+ --target-app-version 1.0.0 --force -m "hotfix: crash on login"
55
+ ```
56
+
57
+ Devices pick up the patch on their next launch. To pull it back:
58
+
59
+ ```bash
60
+ flutter-ota rollback --channel production
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Commands
66
+
67
+ | Command | What it does |
68
+ |---------|--------------|
69
+ | `init <backend>` | Scaffold `.flutter_ota_kit/config.json`, `.env`, and `lib/flutter_ota_kit_setup.dart`; add the SDK dependency + `INTERNET` permission |
70
+ | `build` | Pack a release APK into a device-ready `dist/patch.zip` (all ABIs by default) |
71
+ | `deploy` | Upload + register a bundle; sign it with `--key` |
72
+ | `bundle` | `list` / `show` / `delete` / `disable` / `enable` / `force` / `promote` / `update` |
73
+ | `channel` | `list` / `get` / `set` the live bundle per channel |
74
+ | `rollback` | Disable the latest enabled bundle on a channel (or roll back to a specific one) |
75
+ | `storage` | `list` / `delete` stored bundle objects |
76
+ | `migrate` | Provision the backend schema (Supabase / Postgres / Cloudflare / AWS / PocketBase) |
77
+ | `keys` | Generate an Ed25519 signing keypair |
78
+ | `fingerprint` | Compute a deterministic build fingerprint for fingerprint-targeted rollouts |
79
+ | `doctor` | Diagnose the environment + backend connectivity |
80
+ | `config` | `get` / `set` / `list` config values |
81
+ | `console` | Open the web console |
82
+ | `pocketbase` | Manage a local single-binary PocketBase backend (install / serve / …) |
83
+
84
+ Every command has help, including nested subcommands:
85
+
86
+ ```bash
87
+ flutter-ota deploy --help
88
+ flutter-ota bundle list --help
89
+ flutter-ota pocketbase records list --help
90
+ ```
91
+
92
+ Meaningful short flags map to the option's own name — e.g. on `deploy`:
93
+ `-s`ource, `-c`hannel, `-m`essage, `-f`orce, `-t`arget-app-version,
94
+ `-k`ey, `-b`ackend.
95
+
96
+ ---
97
+
98
+ ## Backends
99
+
100
+ Select one with `--backend supabase|postgres|cloudflare|aws|pocketbase` (or set
101
+ `provider` in `.flutter_ota_kit/config.json`). Each resolves settings with a
102
+ clear precedence:
103
+
104
+ ```
105
+ explicit flag > environment variable > .flutter_ota_kit/config.json > default
106
+ ```
107
+
108
+ Config file search order: `./.flutter_ota_kit/config.json`, then the global
109
+ `~/.flutter_ota_kit/config.json`. Secrets (service-role keys, DB passwords,
110
+ tokens) belong in your shell environment or `.env` — never in committed config.
111
+
112
+ | Backend | Provisioning |
113
+ |---------|--------------|
114
+ | **Supabase** | `migrate supabase` runs SQL + creates the storage bucket — fully automated |
115
+ | **PocketBase** | `pocketbase install` + `pocketbase serve` — single binary, schema auto-installed |
116
+ | **Postgres** | `migrate postgres` applies the SQL migrations |
117
+ | **Cloudflare** | `migrate cloudflare` creates D1 + R2 and runs SQL |
118
+ | **AWS** | No SQL — the S3 bucket/prefix is created on first `deploy` |
119
+
120
+ See the [Backends guide](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/backends.md)
121
+ for per-backend env vars and setup.
122
+
123
+ ---
124
+
125
+ ## Signing
126
+
127
+ ```bash
128
+ flutter-ota keys --save # generate a keypair, save the public half
129
+ flutter-ota deploy --key <private-file> # sign the bundle (Ed25519 over the MD5)
130
+ ```
131
+
132
+ Put the public key in your app via `FlutterPatcher.init(publicKeyBase64: '…')`;
133
+ keep the private key on your CI/build machine, never in the app bundle.
134
+
135
+ ---
136
+
137
+ ## Documentation
138
+
139
+ - [CLI Reference](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/cli-reference.md) — every command + flag
140
+ - [Getting Started](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/getting-started.md)
141
+ - [Backends](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/backends.md)
142
+ - [Configuration](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/configuration.md)
143
+ - [Production Playbook](https://github.com/HYPER12755/flutter-ota-kit/blob/main/doc/production-playbook.md)
144
+
145
+ ---
146
+
147
+ ## License
148
+
149
+ MIT
@@ -22,7 +22,7 @@ export 'src/util.dart';
22
22
 
23
23
  // Re-export the PocketBase client so CLI commands can probe PB health
24
24
  // without pulling the plugin in separately.
25
- export 'package:flutter_ota_kit_pocketbase/flutter_ota_kit_pocketbase.dart'
25
+ export 'package:flutter_ota_kit/src/pkg/pocketbase/flutter_ota_kit_pocketbase.dart'
26
26
  show PocketBaseClient;
27
27
 
28
28
  export 'src/commands/init.dart';
@@ -85,13 +85,15 @@ Future<int> run(List<String> args) async {
85
85
  final msg = e.message;
86
86
 
87
87
  // Missing subcommand → show the command's own help + suggestions.
88
+ // Handles nested paths too (e.g. "flutter-ota pocketbase records"), not
89
+ // just single-word commands.
88
90
  if (msg.startsWith('Missing subcommand')) {
89
- final match = RegExp(r'"flutter-ota (\w+)"').firstMatch(msg);
91
+ final match = RegExp(r'"flutter-ota ([^"]+)"').firstMatch(msg);
90
92
  if (match != null) {
91
- final cmd = runner.commands[match.group(1)];
93
+ final cmd = _resolveCommandPath(runner, match.group(1)!.split(' '));
92
94
  if (cmd != null) {
93
95
  _printMissingSubcommand(cmd);
94
- return 0;
96
+ return 64;
95
97
  }
96
98
  }
97
99
  }
@@ -103,7 +105,7 @@ Future<int> run(List<String> args) async {
103
105
  }
104
106
 
105
107
  // Unknown command → fuzzy-match and suggest.
106
- final unknownMatch = RegExp(r'Could not find a command named "?(\w+)"?')
108
+ final unknownMatch = RegExp(r'Could not find a command named "?([\w-]+)"?')
107
109
  .firstMatch(msg);
108
110
  if (unknownMatch != null) {
109
111
  final typed = unknownMatch.group(1)!;
@@ -111,14 +113,15 @@ Future<int> run(List<String> args) async {
111
113
  return 64;
112
114
  }
113
115
 
114
- // Unknown subcommand → suggest closest subcommand.
116
+ // Unknown subcommand → suggest closest subcommand. Handles nested parents
117
+ // (e.g. "... named "nope" for "flutter-ota pocketbase records"").
115
118
  final subMatch = RegExp(
116
- r'Could not find a subcommand named "?(\w+)"? for "?flutter-ota (\w+)"?',
119
+ r'Could not find a subcommand named "?([\w-]+)"? for "?flutter-ota ([^"]+)"?',
117
120
  ).firstMatch(msg);
118
121
  if (subMatch != null) {
119
122
  final subTyped = subMatch.group(1)!;
120
- final parentName = subMatch.group(2)!;
121
- final parentCmd = runner.commands[parentName];
123
+ final parentPath = subMatch.group(2)!.trim().split(' ');
124
+ final parentCmd = _resolveCommandPath(runner, parentPath);
122
125
  if (parentCmd != null) {
123
126
  _printUnknownSubcommand(parentCmd, subTyped);
124
127
  return 64;
@@ -133,6 +136,22 @@ Future<int> run(List<String> args) async {
133
136
  }
134
137
  }
135
138
 
139
+ /// Walk a space-separated command path (e.g. `["pocketbase", "records"]`)
140
+ /// from the runner down through nested subcommands. Returns the resolved
141
+ /// [Command], or null if any segment is unknown.
142
+ Command<int>? _resolveCommandPath(
143
+ FlutterPatcherRunner runner,
144
+ List<String> path,
145
+ ) {
146
+ if (path.isEmpty) return null;
147
+ Command<int>? cmd = runner.commands[path.first];
148
+ for (final segment in path.skip(1)) {
149
+ if (cmd == null) return null;
150
+ cmd = cmd.subcommands[segment];
151
+ }
152
+ return cmd;
153
+ }
154
+
136
155
  /// Show a helpful "unknown command" message with fuzzy-match suggestions.
137
156
  void _printUnknownCommand(FlutterPatcherRunner runner, String typed) {
138
157
  final commands = runner.commands.keys.toList();
@@ -213,6 +232,7 @@ void _printUnknownCommand(FlutterPatcherRunner runner, String typed) {
213
232
  /// Show a helpful "unknown subcommand" message with suggestions.
214
233
  void _printUnknownSubcommand(Command<int> parent, String typed) {
215
234
  final subNames = parent.subcommands.keys.toList();
235
+ final parentPath = _commandPath(parent);
216
236
 
217
237
  // Find closest subcommands.
218
238
  final suggestions = subNames
@@ -221,14 +241,14 @@ void _printUnknownSubcommand(Command<int> parent, String typed) {
221
241
 
222
242
  stderr.writeln('');
223
243
  stderr.writeln(
224
- ' ${_red('✗')} Unknown subcommand: ${_red(typed)} for ${_cyan('flutter-ota ${parent.name}')}',
244
+ ' ${_red('✗')} Unknown subcommand: ${_red(typed)} for ${_cyan('flutter-ota $parentPath')}',
225
245
  );
226
246
  stderr.writeln('');
227
247
 
228
248
  if (suggestions.isNotEmpty) {
229
249
  stderr.writeln(' ${_cyan('Did you mean?')}');
230
250
  for (final s in suggestions.take(3)) {
231
- stderr.writeln(' ${_green(s)}');
251
+ stderr.writeln(' ${_green('$parentPath $s')}');
232
252
  }
233
253
  stderr.writeln('');
234
254
  }
@@ -239,17 +259,18 @@ void _printUnknownSubcommand(Command<int> parent, String typed) {
239
259
  /// Show a helpful "missing subcommand" message with all subcommand suggestions.
240
260
  void _printMissingSubcommand(Command<int> parent) {
241
261
  final subNames = parent.subcommands.keys.toList()..sort();
262
+ final parentPath = _commandPath(parent);
242
263
 
243
264
  stderr.writeln('');
244
265
  stderr.writeln(
245
- ' ${_red('✗')} Missing subcommand for ${_cyan('flutter-ota ${parent.name}')}',
266
+ ' ${_red('✗')} Missing subcommand for ${_cyan('flutter-ota $parentPath')}',
246
267
  );
247
268
  stderr.writeln('');
248
269
 
249
270
  if (subNames.isNotEmpty) {
250
271
  stderr.writeln(' ${_cyan('Available subcommands:')}');
251
272
  for (final s in subNames) {
252
- stderr.writeln(' ${_green('${parent.name} $s')}');
273
+ stderr.writeln(' ${_green('$parentPath $s')}');
253
274
  }
254
275
  stderr.writeln('');
255
276
  }
@@ -257,6 +278,18 @@ void _printMissingSubcommand(Command<int> parent) {
257
278
  parent.printUsage();
258
279
  }
259
280
 
281
+ /// Full space-separated path of a command (e.g. `pocketbase records`),
282
+ /// walking up the `parent` chain. The runner itself has no name in the chain.
283
+ String _commandPath(Command<int> command) {
284
+ final parts = <String>[command.name];
285
+ var p = command.parent;
286
+ while (p != null) {
287
+ parts.insert(0, p.name);
288
+ p = p.parent;
289
+ }
290
+ return parts.join(' ');
291
+ }
292
+
260
293
  // ── Minimal Levenshtein distance ──────────────────────────────────────────────
261
294
 
262
295
  int _levenshtein(String a, String b) {
@@ -1,9 +1,9 @@
1
- import 'package:flutter_ota_kit_aws/flutter_ota_kit_aws.dart';
2
- import 'package:flutter_ota_kit_cloudflare/flutter_ota_kit_cloudflare.dart';
3
- import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart';
4
- import 'package:flutter_ota_kit_pocketbase/flutter_ota_kit_pocketbase.dart';
5
- import 'package:flutter_ota_kit_postgres/flutter_ota_kit_postgres.dart';
6
- import 'package:flutter_ota_kit_supabase/flutter_ota_kit_supabase.dart';
1
+ import 'package:flutter_ota_kit/src/pkg/aws/flutter_ota_kit_aws.dart';
2
+ import 'package:flutter_ota_kit/src/pkg/cloudflare/flutter_ota_kit_cloudflare.dart';
3
+ import 'package:flutter_ota_kit/src/pkg/plugin_core/flutter_ota_kit_plugin_core.dart';
4
+ import 'package:flutter_ota_kit/src/pkg/pocketbase/flutter_ota_kit_pocketbase.dart';
5
+ import 'package:flutter_ota_kit/src/pkg/postgres/flutter_ota_kit_postgres.dart';
6
+ import 'package:flutter_ota_kit/src/pkg/supabase/flutter_ota_kit_supabase.dart';
7
7
 
8
8
  import 'config.dart';
9
9
 
@@ -17,10 +17,12 @@ class BuildCommand extends FlutterPatcherCommand {
17
17
  )
18
18
  ..addMultiOption(
19
19
  'assets',
20
+ abbr: 'A',
20
21
  help: 'Asset keys to include as overlay updates (repeatable).',
21
22
  )
22
23
  ..addOption(
23
24
  'version',
25
+ abbr: 'V',
24
26
  help: 'Patch version string (stored in manifest.version).',
25
27
  )
26
28
  ..addOption(
@@ -151,7 +151,7 @@ class BundleShowCommand extends FlutterPatcherCommand {
151
151
  ? 'Backend provider [detected: $detected].'
152
152
  : 'Backend provider.',
153
153
  );
154
- argParser.addOption('id', help: 'Bundle id.');
154
+ argParser.addOption('id', abbr: 'i', help: 'Bundle id.');
155
155
  }
156
156
 
157
157
  final FlutterPatcherConfig? config;
@@ -201,7 +201,7 @@ class BundleDeleteCommand extends FlutterPatcherCommand {
201
201
  ? 'Backend provider [detected: $detected].'
202
202
  : 'Backend provider.',
203
203
  );
204
- argParser.addOption('id', help: 'Bundle id.');
204
+ argParser.addOption('id', abbr: 'i', help: 'Bundle id.');
205
205
  argParser.addFlag(
206
206
  'keep-storage',
207
207
  help: 'Do not delete the storage object.',
@@ -252,7 +252,7 @@ class BundleDisableCommand extends FlutterPatcherCommand {
252
252
  ? 'Backend provider [detected: $detected].'
253
253
  : 'Backend provider.',
254
254
  );
255
- argParser.addOption('id', help: 'Bundle id.');
255
+ argParser.addOption('id', abbr: 'i', help: 'Bundle id.');
256
256
  }
257
257
 
258
258
  final FlutterPatcherConfig? config;
@@ -290,7 +290,7 @@ class BundleEnableCommand extends FlutterPatcherCommand {
290
290
  ? 'Backend provider [detected: $detected].'
291
291
  : 'Backend provider.',
292
292
  );
293
- argParser.addOption('id', help: 'Bundle id.');
293
+ argParser.addOption('id', abbr: 'i', help: 'Bundle id.');
294
294
  }
295
295
 
296
296
  final FlutterPatcherConfig? config;
@@ -328,7 +328,7 @@ class BundleForceCommand extends FlutterPatcherCommand {
328
328
  ? 'Backend provider [detected: $detected].'
329
329
  : 'Backend provider.',
330
330
  );
331
- argParser.addOption('id', help: 'Bundle id.');
331
+ argParser.addOption('id', abbr: 'i', help: 'Bundle id.');
332
332
  argParser.addFlag(
333
333
  'off',
334
334
  help: 'Clear the force-update flag instead of setting it.',
@@ -377,7 +377,7 @@ class BundlePromoteCommand extends FlutterPatcherCommand {
377
377
  ? 'Backend provider [detected: $detected].'
378
378
  : 'Backend provider.',
379
379
  );
380
- argParser.addOption('id', help: 'Bundle id.');
380
+ argParser.addOption('id', abbr: 'i', help: 'Bundle id.');
381
381
  argParser.addOption('channel', abbr: 'c', help: 'Target channel.');
382
382
  }
383
383
 
@@ -426,7 +426,7 @@ class BundleUpdateCommand extends FlutterPatcherCommand {
426
426
  ? 'Backend provider [detected: $detected].'
427
427
  : 'Backend provider.',
428
428
  );
429
- argParser.addOption('id', help: 'Bundle id.');
429
+ argParser.addOption('id', abbr: 'i', help: 'Bundle id.');
430
430
  argParser.addOption('message', abbr: 'm', help: 'New release message.');
431
431
  argParser.addOption(
432
432
  'target-version',
@@ -1,6 +1,6 @@
1
1
  import 'dart:io';
2
2
 
3
- import 'package:flutter_ota_kit_core/flutter_ota_kit_core.dart';
3
+ import 'package:flutter_ota_kit/src/pkg/core/flutter_ota_kit_core.dart';
4
4
 
5
5
  import '../backend.dart';
6
6
  import '../cli_base.dart';
@@ -37,10 +37,12 @@ class DeployCommand extends FlutterPatcherCommand {
37
37
  argParser.addFlag('force', abbr: 'f', help: 'Force the update on clients.');
38
38
  argParser.addOption(
39
39
  'target-app-version',
40
+ abbr: 't',
40
41
  help: 'Semver range target (XOR with fingerprint-hash).',
41
42
  );
42
43
  argParser.addOption(
43
44
  'fingerprint-hash',
45
+ abbr: 'F',
44
46
  help: 'Fingerprint hash target (XOR with target-app-version).',
45
47
  );
46
48
  argParser.addOption(
@@ -50,6 +52,7 @@ class DeployCommand extends FlutterPatcherCommand {
50
52
  );
51
53
  argParser.addOption(
52
54
  'git-commit-hash',
55
+ abbr: 'g',
53
56
  help: 'Git commit hash (auto-detected).',
54
57
  );
55
58
  argParser.addOption(