@_nazmiforreal/flutter-ota 0.1.12 → 0.1.14

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 (177) hide show
  1. package/README.md +1 -1
  2. package/bin/flutter-ota-linux-x64 +0 -0
  3. package/dart-src/packages/cli-tools/.dart_tool/package_config.json +46 -76
  4. package/dart-src/packages/cli-tools/.dart_tool/package_graph.json +140 -166
  5. package/dart-src/packages/cli-tools/README.md +1 -1
  6. package/dart-src/packages/cli-tools/lib/flutter_ota_kit_cli.dart +30 -17
  7. package/dart-src/packages/cli-tools/lib/src/backend.dart +30 -31
  8. package/dart-src/packages/cli-tools/lib/src/cli_base.dart +3 -1
  9. package/dart-src/packages/cli-tools/lib/src/commands/build.dart +44 -43
  10. package/dart-src/packages/cli-tools/lib/src/commands/bundle.dart +265 -239
  11. package/dart-src/packages/cli-tools/lib/src/commands/channel.dart +75 -66
  12. package/dart-src/packages/cli-tools/lib/src/commands/config_command.dart +39 -35
  13. package/dart-src/packages/cli-tools/lib/src/commands/console.dart +30 -27
  14. package/dart-src/packages/cli-tools/lib/src/commands/deploy.dart +88 -72
  15. package/dart-src/packages/cli-tools/lib/src/commands/doctor.dart +66 -29
  16. package/dart-src/packages/cli-tools/lib/src/commands/fingerprint.dart +10 -6
  17. package/dart-src/packages/cli-tools/lib/src/commands/init.dart +290 -181
  18. package/dart-src/packages/cli-tools/lib/src/commands/keys.dart +24 -23
  19. package/dart-src/packages/cli-tools/lib/src/commands/migrate.dart +111 -97
  20. package/dart-src/packages/cli-tools/lib/src/commands/pocketbase.dart +237 -0
  21. package/dart-src/packages/cli-tools/lib/src/commands/rollback.dart +43 -34
  22. package/dart-src/packages/cli-tools/lib/src/commands/storage.dart +57 -53
  23. package/dart-src/packages/cli-tools/lib/src/config.dart +227 -93
  24. package/dart-src/packages/cli-tools/lib/src/operations.dart +9 -8
  25. package/dart-src/packages/cli-tools/lib/src/pack.dart +26 -25
  26. package/dart-src/packages/cli-tools/lib/src/pocketbase/data_bootstrap.dart +39 -0
  27. package/dart-src/packages/cli-tools/lib/src/pocketbase/hooks/bundles.pb.js +56 -0
  28. package/dart-src/packages/cli-tools/lib/src/pocketbase/installer.dart +189 -0
  29. package/dart-src/packages/cli-tools/lib/src/pocketbase/process_manager.dart +123 -0
  30. package/dart-src/packages/cli-tools/lib/src/pocketbase/schema_installer.dart +237 -0
  31. package/dart-src/packages/cli-tools/lib/src/runner.dart +36 -15
  32. package/dart-src/packages/cli-tools/lib/src/sign.dart +13 -5
  33. package/dart-src/packages/cli-tools/lib/src/ui/ui.dart +10 -13
  34. package/dart-src/packages/cli-tools/lib/src/util.dart +3 -1
  35. package/dart-src/packages/cli-tools/pubspec.lock +69 -116
  36. package/dart-src/packages/cli-tools/pubspec.yaml +25 -7
  37. package/dart-src/packages/cli-tools/test/backends_test.dart +62 -32
  38. package/dart-src/packages/cli-tools/test/build_pack_test.dart +4 -4
  39. package/dart-src/packages/cli-tools/test/cli_test.dart +89 -42
  40. package/dart-src/packages/cli-tools/test/mocks/mock_aws_s3_client.dart +8 -13
  41. package/dart-src/packages/cli-tools/test/mocks/mock_d1_client.dart +23 -18
  42. package/dart-src/packages/cli-tools/test/mocks/mock_pocketbase_client.dart +197 -0
  43. package/dart-src/packages/cli-tools/test/mocks/mock_postgres_client.dart +70 -46
  44. package/dart-src/packages/cli-tools/test/pocketbase_installer_test.dart +72 -0
  45. package/dart-src/packages/cli-tools/test/pocketbase_schema_test.dart +107 -0
  46. package/dart-src/packages/cli-tools/test/pocketbase_smoke_test.dart +59 -0
  47. package/dart-src/packages/core/CHANGELOG.md +9 -0
  48. package/dart-src/packages/core/README.md +2 -2
  49. package/dart-src/packages/core/example/lib/main.dart +69 -0
  50. package/dart-src/packages/core/lib/flutter_ota_kit_core.dart +1 -1
  51. package/dart-src/packages/core/lib/src/app_update_info.dart +17 -15
  52. package/dart-src/packages/core/lib/src/bundle.dart +102 -94
  53. package/dart-src/packages/core/lib/src/bundle_artifacts.dart +1 -2
  54. package/dart-src/packages/core/lib/src/bundle_patch_artifact.dart +15 -16
  55. package/dart-src/packages/core/lib/src/changed_asset.dart +24 -22
  56. package/dart-src/packages/core/lib/src/get_bundles_args.dart +13 -13
  57. package/dart-src/packages/core/lib/src/metadata.dart +9 -7
  58. package/dart-src/packages/core/lib/src/patch_info.dart +8 -7
  59. package/dart-src/packages/core/lib/src/platform.dart +4 -3
  60. package/dart-src/packages/core/lib/src/rollout.dart +14 -11
  61. package/dart-src/packages/core/lib/src/semver_range.dart +49 -39
  62. package/dart-src/packages/core/lib/src/semver_version.dart +8 -7
  63. package/dart-src/packages/core/lib/src/status.dart +4 -3
  64. package/dart-src/packages/core/lib/src/update_bundle_params.dart +7 -7
  65. package/dart-src/packages/core/lib/src/uuid.dart +1 -2
  66. package/dart-src/packages/core/pubspec.yaml +6 -7
  67. package/dart-src/packages/core/test/rollout_test.dart +15 -8
  68. package/dart-src/packages/core/test/semver_test.dart +5 -2
  69. package/dart-src/packages/core/test/types_test.dart +26 -24
  70. package/dart-src/packages/core/test/uuid_test.dart +3 -1
  71. package/dart-src/packages/core/tool/dbg.dart +1 -0
  72. package/dart-src/plugins/aws/CHANGELOG.md +15 -0
  73. package/dart-src/plugins/aws/example/lib/main.dart +60 -0
  74. package/dart-src/plugins/aws/lib/flutter_ota_kit_aws.dart +5 -1
  75. package/dart-src/plugins/aws/lib/src/aws_cloudfront_client.dart +11 -16
  76. package/dart-src/plugins/aws/lib/src/aws_cloudfront_signer.dart +7 -2
  77. package/dart-src/plugins/aws/lib/src/aws_database.dart +14 -18
  78. package/dart-src/plugins/aws/lib/src/aws_s3_client.dart +23 -18
  79. package/dart-src/plugins/aws/lib/src/aws_ssm_client.dart +5 -4
  80. package/dart-src/plugins/aws/lib/src/aws_storage.dart +2 -3
  81. package/dart-src/plugins/aws/lib/src/aws_storage_profile.dart +10 -16
  82. package/dart-src/plugins/aws/lib/src/with_cloudfront_signed_url.dart +6 -9
  83. package/dart-src/plugins/aws/pubspec.yaml +15 -10
  84. package/dart-src/plugins/aws/test/aws_database_test.dart +51 -57
  85. package/dart-src/plugins/aws/test/mock_aws_s3_client.dart +8 -13
  86. package/dart-src/plugins/cloudflare/CHANGELOG.md +15 -0
  87. package/dart-src/plugins/cloudflare/example/lib/main.dart +62 -0
  88. package/dart-src/plugins/cloudflare/lib/flutter_ota_kit_cloudflare.dart +4 -2
  89. package/dart-src/plugins/cloudflare/lib/src/cloudflare_worker_database.dart +3 -3
  90. package/dart-src/plugins/cloudflare/lib/src/d1_build_where.dart +3 -2
  91. package/dart-src/plugins/cloudflare/lib/src/d1_bundle_mapper.dart +24 -27
  92. package/dart-src/plugins/cloudflare/lib/src/d1_database_plugin.dart +22 -30
  93. package/dart-src/plugins/cloudflare/lib/src/r2_config.dart +1 -1
  94. package/dart-src/plugins/cloudflare/lib/src/r2_s3_client.dart +21 -29
  95. package/dart-src/plugins/cloudflare/lib/src/r2_storage.dart +7 -7
  96. package/dart-src/plugins/cloudflare/lib/src/r2_storage_profile.dart +7 -15
  97. package/dart-src/plugins/cloudflare/pubspec.yaml +14 -9
  98. package/dart-src/plugins/cloudflare/test/cloudflare_worker_database_test.dart +46 -42
  99. package/dart-src/plugins/cloudflare/test/d1_database_test.dart +100 -90
  100. package/dart-src/plugins/cloudflare/test/mock_d1_client.dart +23 -18
  101. package/dart-src/plugins/cloudflare/test/mock_r2_client.dart +8 -13
  102. package/dart-src/plugins/cloudflare/test/r2_storage_test.dart +1 -4
  103. package/dart-src/plugins/plugin-core/CHANGELOG.md +15 -1
  104. package/dart-src/plugins/plugin-core/example/lib/main.dart +61 -0
  105. package/dart-src/plugins/plugin-core/lib/flutter_ota_kit_plugin_core.dart +3 -7
  106. package/dart-src/plugins/plugin-core/lib/src/asset_storage_layout.dart +5 -5
  107. package/dart-src/plugins/plugin-core/lib/src/bundle_helpers.dart +23 -0
  108. package/dart-src/plugins/plugin-core/lib/src/bundle_storage_layout.dart +16 -10
  109. package/dart-src/plugins/plugin-core/lib/src/bundle_unit_of_work.dart +31 -26
  110. package/dart-src/plugins/plugin-core/lib/src/calculate_pagination.dart +5 -1
  111. package/dart-src/plugins/plugin-core/lib/src/content_addressed_assets.dart +1 -1
  112. package/dart-src/plugins/plugin-core/lib/src/create_blob_database_plugin.dart +78 -71
  113. package/dart-src/plugins/plugin-core/lib/src/create_database_plugin.dart +56 -35
  114. package/dart-src/plugins/plugin-core/lib/src/create_storage_plugin.dart +10 -13
  115. package/dart-src/plugins/plugin-core/lib/src/paginate_bundles.dart +30 -17
  116. package/dart-src/plugins/plugin-core/lib/src/parse_storage_uri.dart +3 -1
  117. package/dart-src/plugins/plugin-core/lib/src/query_bundles.dart +5 -3
  118. package/dart-src/plugins/plugin-core/lib/src/request_update_bundle_state.dart +2 -4
  119. package/dart-src/plugins/plugin-core/lib/src/storage_helpers.dart +18 -0
  120. package/dart-src/plugins/plugin-core/lib/src/types.dart +7 -6
  121. package/dart-src/plugins/plugin-core/pubspec.yaml +12 -9
  122. package/dart-src/plugins/plugin-core/test/asset_storage_layout_test.dart +13 -9
  123. package/dart-src/plugins/plugin-core/test/bundle_unit_of_work_test.dart +28 -15
  124. package/dart-src/plugins/plugin-core/test/create_blob_database_plugin_test.dart +254 -122
  125. package/dart-src/plugins/plugin-core/test/create_database_plugin_test.dart +36 -32
  126. package/dart-src/plugins/plugin-core/test/create_storage_plugin_test.dart +18 -15
  127. package/dart-src/plugins/plugin-core/test/generate_min_bundle_id_test.dart +8 -3
  128. package/dart-src/plugins/plugin-core/test/get_update_info_test.dart +682 -693
  129. package/dart-src/plugins/plugin-core/test/helpers_test.dart +45 -21
  130. package/dart-src/plugins/plugin-core/test/query_bundles_test.dart +76 -13
  131. package/dart-src/plugins/plugin-core/test/uuidv7_test.dart +20 -9
  132. package/dart-src/plugins/pocketbase/CHANGELOG.md +8 -0
  133. package/dart-src/plugins/pocketbase/LICENSE +21 -0
  134. package/dart-src/plugins/pocketbase/README.md +54 -0
  135. package/dart-src/plugins/pocketbase/example/lib/main.dart +62 -0
  136. package/dart-src/plugins/pocketbase/lib/flutter_ota_kit_pocketbase.dart +28 -0
  137. package/dart-src/plugins/pocketbase/lib/src/pocketbase_bundle_mapper.dart +121 -0
  138. package/dart-src/plugins/pocketbase/lib/src/pocketbase_client.dart +349 -0
  139. package/dart-src/plugins/pocketbase/lib/src/pocketbase_config.dart +61 -0
  140. package/dart-src/plugins/pocketbase/lib/src/pocketbase_database.dart +278 -0
  141. package/dart-src/plugins/pocketbase/lib/src/pocketbase_storage.dart +255 -0
  142. package/dart-src/plugins/pocketbase/pubspec.yaml +26 -0
  143. package/dart-src/plugins/pocketbase/test/pb_uri_test.dart +12 -0
  144. package/dart-src/plugins/postgres/CHANGELOG.md +16 -0
  145. package/dart-src/plugins/postgres/example/lib/main.dart +67 -0
  146. package/dart-src/plugins/postgres/lib/flutter_ota_kit_postgres.dart +3 -6
  147. package/dart-src/plugins/postgres/lib/src/postgres_bundle_mapper.dart +32 -52
  148. package/dart-src/plugins/postgres/lib/src/postgres_config.dart +3 -1
  149. package/dart-src/plugins/postgres/lib/src/postgres_database.dart +28 -38
  150. package/dart-src/plugins/postgres/lib/src/postgres_get_update_info.dart +16 -14
  151. package/dart-src/plugins/postgres/lib/src/postgres_storage.dart +26 -14
  152. package/dart-src/plugins/postgres/lib/src/postgres_types.dart +27 -28
  153. package/dart-src/plugins/postgres/pubspec.yaml +14 -9
  154. package/dart-src/plugins/postgres/test/mock_postgres_client.dart +62 -39
  155. package/dart-src/plugins/postgres/test/postgres_bundle_mapper_test.dart +3 -4
  156. package/dart-src/plugins/postgres/test/postgres_database_test.dart +102 -73
  157. package/dart-src/plugins/postgres/test/postgres_storage_runtime_test.dart +60 -0
  158. package/dart-src/plugins/supabase/CHANGELOG.md +20 -0
  159. package/dart-src/plugins/supabase/README.md +2 -2
  160. package/dart-src/plugins/supabase/example/lib/main.dart +63 -0
  161. package/dart-src/plugins/supabase/lib/flutter_ota_kit_supabase.dart +2 -0
  162. package/dart-src/plugins/supabase/lib/src/error_message.dart +11 -0
  163. package/dart-src/plugins/supabase/lib/src/supabase_bundle_mapper.dart +34 -58
  164. package/dart-src/plugins/supabase/lib/src/supabase_client_adapter.dart +3 -13
  165. package/dart-src/plugins/supabase/lib/src/supabase_client_http.dart +34 -52
  166. package/dart-src/plugins/supabase/lib/src/supabase_database.dart +38 -30
  167. package/dart-src/plugins/supabase/lib/src/supabase_edge_function_storage.dart +21 -29
  168. package/dart-src/plugins/supabase/lib/src/supabase_signed_url_batcher.dart +7 -19
  169. package/dart-src/plugins/supabase/lib/src/supabase_storage.dart +18 -29
  170. package/dart-src/plugins/supabase/lib/src/types.dart +26 -26
  171. package/dart-src/plugins/supabase/pubspec.yaml +14 -9
  172. package/dart-src/plugins/supabase/test/mock_supabase_client.dart +57 -57
  173. package/dart-src/plugins/supabase/test/supabase_bundle_mapper_test.dart +30 -27
  174. package/dart-src/plugins/supabase/test/supabase_database_test.dart +26 -35
  175. package/dart-src/plugins/supabase/test/supabase_storage_test.dart +27 -34
  176. package/package.json +3 -3
  177. package/scripts/vendor.sh +1 -1
@@ -7,14 +7,30 @@ import '../ui/ui.dart';
7
7
  /// DB access needed; the CLI talks to the backend through its plugins).
8
8
  class BundleCommand extends FlutterPatcherCommand {
9
9
  BundleCommand({this.config, this.backendOverride}) {
10
- addSubcommand(BundleListCommand(config: config, backendOverride: backendOverride));
11
- addSubcommand(BundleShowCommand(config: config, backendOverride: backendOverride));
12
- addSubcommand(BundleDeleteCommand(config: config, backendOverride: backendOverride));
13
- addSubcommand(BundleDisableCommand(config: config, backendOverride: backendOverride));
14
- addSubcommand(BundleEnableCommand(config: config, backendOverride: backendOverride));
15
- addSubcommand(BundleForceCommand(config: config, backendOverride: backendOverride));
16
- addSubcommand(BundlePromoteCommand(config: config, backendOverride: backendOverride));
17
- addSubcommand(BundleUpdateCommand(config: config, backendOverride: backendOverride));
10
+ addSubcommand(
11
+ BundleListCommand(config: config, backendOverride: backendOverride),
12
+ );
13
+ addSubcommand(
14
+ BundleShowCommand(config: config, backendOverride: backendOverride),
15
+ );
16
+ addSubcommand(
17
+ BundleDeleteCommand(config: config, backendOverride: backendOverride),
18
+ );
19
+ addSubcommand(
20
+ BundleDisableCommand(config: config, backendOverride: backendOverride),
21
+ );
22
+ addSubcommand(
23
+ BundleEnableCommand(config: config, backendOverride: backendOverride),
24
+ );
25
+ addSubcommand(
26
+ BundleForceCommand(config: config, backendOverride: backendOverride),
27
+ );
28
+ addSubcommand(
29
+ BundlePromoteCommand(config: config, backendOverride: backendOverride),
30
+ );
31
+ addSubcommand(
32
+ BundleUpdateCommand(config: config, backendOverride: backendOverride),
33
+ );
18
34
  }
19
35
 
20
36
  final FlutterPatcherConfig? config;
@@ -29,18 +45,24 @@ class BundleCommand extends FlutterPatcherCommand {
29
45
 
30
46
  @override
31
47
  Future<int> run() => runGuarded(() async {
32
- print(description);
33
- print('');
34
- print('Subcommands:');
35
- print(' list List bundles (filters: --channel/-c, --platform/-p, --enabled, --limit/-l)');
36
- print(' show --id <id> Show a single bundle\'s details');
37
- print(' delete --id <id> Delete a bundle');
38
- print(' disable --id <id> Disable a bundle (stop serving it)');
39
- print(' enable --id <id> Enable a bundle');
40
- print(' force --id <id> Force an update onto clients (--off to clear)');
41
- print(' promote --id <id> -c Promote a bundle to a channel');
42
- print(' update --id <id> ... Edit metadata (--message/--target-version/--enabled/--force)');
43
- });
48
+ print(description);
49
+ print('');
50
+ print('Subcommands:');
51
+ print(
52
+ ' list List bundles (filters: --channel/-c, --platform/-p, --enabled, --limit/-l)',
53
+ );
54
+ print(' show --id <id> Show a single bundle\'s details');
55
+ print(' delete --id <id> Delete a bundle');
56
+ print(' disable --id <id> Disable a bundle (stop serving it)');
57
+ print(' enable --id <id> Enable a bundle');
58
+ print(
59
+ ' force --id <id> Force an update onto clients (--off to clear)',
60
+ );
61
+ print(' promote --id <id> -c Promote a bundle to a channel');
62
+ print(
63
+ ' update --id <id> ... Edit metadata (--message/--target-version/--enabled/--force)',
64
+ );
65
+ });
44
66
  }
45
67
 
46
68
  class BundleListCommand extends FlutterPatcherCommand {
@@ -65,49 +87,46 @@ class BundleListCommand extends FlutterPatcherCommand {
65
87
 
66
88
  @override
67
89
  Future<int> run() => runGuarded(() async {
68
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
69
- final backend = requireBackend(cfg, override: backendOverride);
70
- final enabledRaw = argResults!['enabled'] as String?;
71
- final enabled = enabledRaw == null
72
- ? null
73
- : (enabledRaw == 'true' || enabledRaw == '1');
74
- final res = await listBundles(
75
- backend,
76
- ListOptions(
77
- channel: argResults!['channel'] as String?,
78
- platform: argResults!['platform'] as String?,
79
- enabled: enabled,
80
- limit: int.parse(argResults!['limit'] as String),
81
- ),
82
- );
83
- banner('bundle · list');
84
- if (res.data.isEmpty) {
85
- step('(no bundles)');
86
- return;
87
- }
88
- final lines = <String>[];
89
- for (var i = 0; i < res.data.length; i++) {
90
- final b = res.data[i];
91
- final target = b.targetAppVersion ?? b.fingerprintHash ?? dim('-');
92
- lines
93
- ..add(kv('#$i', cyan(b.id)))
94
- ..add(kv('channel', b.channel))
95
- ..add(kv(
96
- 'enabled',
97
- b.enabled ? green('yes') : yellow('no'),
98
- ))
99
- ..add(kv('platform', b.platform.value))
100
- ..add(kv('force', b.shouldForceUpdate ? green('yes') : yellow('no')))
101
- ..add(kv('target', target));
102
- if (b.message != null) lines.add(kv('message', b.message!));
103
- if (b.metadata?.signature != null) {
104
- lines.add(kv('signature', green('✓ signed')));
105
- }
106
- lines.add('');
107
- }
108
- box('${res.data.length} bundles', lines);
109
- step('total: ${res.pagination.total}');
110
- });
90
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
91
+ final backend = requireBackend(cfg, override: backendOverride);
92
+ final enabledRaw = argResults!['enabled'] as String?;
93
+ final enabled = enabledRaw == null
94
+ ? null
95
+ : (enabledRaw == 'true' || enabledRaw == '1');
96
+ final res = await listBundles(
97
+ backend,
98
+ ListOptions(
99
+ channel: argResults!['channel'] as String?,
100
+ platform: argResults!['platform'] as String?,
101
+ enabled: enabled,
102
+ limit: int.parse(argResults!['limit'] as String),
103
+ ),
104
+ );
105
+ banner('bundle · list');
106
+ if (res.data.isEmpty) {
107
+ step('(no bundles)');
108
+ return;
109
+ }
110
+ final lines = <String>[];
111
+ for (var i = 0; i < res.data.length; i++) {
112
+ final b = res.data[i];
113
+ final target = b.targetAppVersion ?? b.fingerprintHash ?? dim('-');
114
+ lines
115
+ ..add(kv('#$i', cyan(b.id)))
116
+ ..add(kv('channel', b.channel))
117
+ ..add(kv('enabled', b.enabled ? green('yes') : yellow('no')))
118
+ ..add(kv('platform', b.platform.value))
119
+ ..add(kv('force', b.shouldForceUpdate ? green('yes') : yellow('no')))
120
+ ..add(kv('target', target));
121
+ if (b.message != null) lines.add(kv('message', b.message!));
122
+ if (b.metadata?.signature != null) {
123
+ lines.add(kv('signature', green('✓ signed')));
124
+ }
125
+ lines.add('');
126
+ }
127
+ box('${res.data.length} bundles', lines);
128
+ step('total: ${res.pagination.total}');
129
+ });
111
130
  }
112
131
 
113
132
  class BundleShowCommand extends FlutterPatcherCommand {
@@ -129,32 +148,32 @@ class BundleShowCommand extends FlutterPatcherCommand {
129
148
 
130
149
  @override
131
150
  Future<int> run() => runGuarded(() async {
132
- final id = argResults!['id'] as String?;
133
- if (id == null || id.isEmpty) {
134
- throw PackException('Usage: flutter_ota_kit bundle show --id <id>', 64);
135
- }
136
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
137
- final backend = requireBackend(cfg, override: backendOverride);
138
- banner('bundle · show');
139
- final b = await backend.db.getBundleById(id);
140
- if (b == null) {
141
- step('(not found)');
142
- return;
143
- }
144
- final lines = <String>[
145
- kv('id', cyan(b.id)),
146
- kv('channel', b.channel),
147
- kv('enabled', b.enabled ? green('yes') : yellow('no')),
148
- kv('platform', b.platform.value),
149
- kv('force', b.shouldForceUpdate ? green('yes') : yellow('no')),
150
- kv('target', b.targetAppVersion ?? b.fingerprintHash ?? dim('-')),
151
- ];
152
- if (b.message != null) lines.add(kv('message', b.message!));
153
- if (b.metadata?.signature != null) {
154
- lines.add(kv('signature', green('✓ signed')));
155
- }
156
- box('bundle', lines);
157
- });
151
+ final id = argResults!['id'] as String?;
152
+ if (id == null || id.isEmpty) {
153
+ throw PackException('Usage: flutter_ota_kit bundle show --id <id>', 64);
154
+ }
155
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
156
+ final backend = requireBackend(cfg, override: backendOverride);
157
+ banner('bundle · show');
158
+ final b = await backend.db.getBundleById(id);
159
+ if (b == null) {
160
+ step('(not found)');
161
+ return;
162
+ }
163
+ final lines = <String>[
164
+ kv('id', cyan(b.id)),
165
+ kv('channel', b.channel),
166
+ kv('enabled', b.enabled ? green('yes') : yellow('no')),
167
+ kv('platform', b.platform.value),
168
+ kv('force', b.shouldForceUpdate ? green('yes') : yellow('no')),
169
+ kv('target', b.targetAppVersion ?? b.fingerprintHash ?? dim('-')),
170
+ ];
171
+ if (b.message != null) lines.add(kv('message', b.message!));
172
+ if (b.metadata?.signature != null) {
173
+ lines.add(kv('signature', green('✓ signed')));
174
+ }
175
+ box('bundle', lines);
176
+ });
158
177
  }
159
178
 
160
179
  class BundleDeleteCommand extends FlutterPatcherCommand {
@@ -173,35 +192,39 @@ class BundleDeleteCommand extends FlutterPatcherCommand {
173
192
  ArgParser get argParser => ArgParser()
174
193
  ..addOption('backend', abbr: 'b', help: 'Backend provider.')
175
194
  ..addOption('id', help: 'Bundle id.')
176
- ..addFlag('keep-storage', help: 'Do not delete the storage object.', negatable: false);
195
+ ..addFlag(
196
+ 'keep-storage',
197
+ help: 'Do not delete the storage object.',
198
+ negatable: false,
199
+ );
177
200
 
178
201
  @override
179
202
  Future<int> run() => runGuarded(() async {
180
- final id = argResults!['id'] as String?;
181
- if (id == null || id.isEmpty) {
182
- throw PackException('Usage: flutter_ota_kit bundle delete --id <id>', 64);
183
- }
184
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
185
- final backend = requireBackend(cfg, override: backendOverride);
186
- banner('bundle · delete');
187
- final existing = await backend.db.getBundleById(id);
188
- if (existing == null) {
189
- throw StateError('Bundle "$id" not found.');
190
- }
191
- final keepStorage = argResults!['keep-storage'] as bool;
192
- await spinner(
193
- () => deleteBundle(backend, id),
194
- 'Deleting bundle $id',
195
- done: 'Deleted',
196
- );
197
- if (!keepStorage && existing.storageUri.isNotEmpty) {
198
- await spinner(
199
- () => backend.storage.delete(existing.storageUri),
200
- 'Removing storage object',
201
- done: 'Storage removed',
202
- );
203
- }
204
- });
203
+ final id = argResults!['id'] as String?;
204
+ if (id == null || id.isEmpty) {
205
+ throw PackException('Usage: flutter_ota_kit bundle delete --id <id>', 64);
206
+ }
207
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
208
+ final backend = requireBackend(cfg, override: backendOverride);
209
+ banner('bundle · delete');
210
+ final existing = await backend.db.getBundleById(id);
211
+ if (existing == null) {
212
+ throw StateError('Bundle "$id" not found.');
213
+ }
214
+ final keepStorage = argResults!['keep-storage'] as bool;
215
+ await spinner(
216
+ () => deleteBundle(backend, id),
217
+ 'Deleting bundle $id',
218
+ done: 'Deleted',
219
+ );
220
+ if (!keepStorage && existing.storageUri.isNotEmpty) {
221
+ await spinner(
222
+ () => backend.storage.delete(existing.storageUri),
223
+ 'Removing storage object',
224
+ done: 'Storage removed',
225
+ );
226
+ }
227
+ });
205
228
  }
206
229
 
207
230
  class BundleDisableCommand extends FlutterPatcherCommand {
@@ -223,22 +246,25 @@ class BundleDisableCommand extends FlutterPatcherCommand {
223
246
 
224
247
  @override
225
248
  Future<int> run() => runGuarded(() async {
226
- final id = argResults!['id'] as String?;
227
- if (id == null || id.isEmpty) {
228
- throw PackException('Usage: flutter_ota_kit bundle disable --id <id>', 64);
229
- }
230
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
231
- final backend = requireBackend(cfg, override: backendOverride);
232
- banner('bundle · disable');
233
- await spinner(
234
- () async {
235
- await backend.db.updateBundle(id, {'enabled': false});
236
- await backend.db.commitBundle();
237
- },
238
- 'Disabling bundle $id',
239
- done: 'Disabled',
240
- );
241
- });
249
+ final id = argResults!['id'] as String?;
250
+ if (id == null || id.isEmpty) {
251
+ throw PackException(
252
+ 'Usage: flutter_ota_kit bundle disable --id <id>',
253
+ 64,
254
+ );
255
+ }
256
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
257
+ final backend = requireBackend(cfg, override: backendOverride);
258
+ banner('bundle · disable');
259
+ await spinner(
260
+ () async {
261
+ await backend.db.updateBundle(id, {'enabled': false});
262
+ await backend.db.commitBundle();
263
+ },
264
+ 'Disabling bundle $id',
265
+ done: 'Disabled',
266
+ );
267
+ });
242
268
  }
243
269
 
244
270
  class BundleEnableCommand extends FlutterPatcherCommand {
@@ -260,22 +286,22 @@ class BundleEnableCommand extends FlutterPatcherCommand {
260
286
 
261
287
  @override
262
288
  Future<int> run() => runGuarded(() async {
263
- final id = argResults!['id'] as String?;
264
- if (id == null || id.isEmpty) {
265
- throw PackException('Usage: flutter_ota_kit bundle enable --id <id>', 64);
266
- }
267
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
268
- final backend = requireBackend(cfg, override: backendOverride);
269
- banner('bundle · enable');
270
- await spinner(
271
- () async {
272
- await backend.db.updateBundle(id, {'enabled': true});
273
- await backend.db.commitBundle();
274
- },
275
- 'Enabling bundle $id',
276
- done: 'Enabled',
277
- );
278
- });
289
+ final id = argResults!['id'] as String?;
290
+ if (id == null || id.isEmpty) {
291
+ throw PackException('Usage: flutter_ota_kit bundle enable --id <id>', 64);
292
+ }
293
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
294
+ final backend = requireBackend(cfg, override: backendOverride);
295
+ banner('bundle · enable');
296
+ await spinner(
297
+ () async {
298
+ await backend.db.updateBundle(id, {'enabled': true});
299
+ await backend.db.commitBundle();
300
+ },
301
+ 'Enabling bundle $id',
302
+ done: 'Enabled',
303
+ );
304
+ });
279
305
  }
280
306
 
281
307
  class BundleForceCommand extends FlutterPatcherCommand {
@@ -294,33 +320,36 @@ class BundleForceCommand extends FlutterPatcherCommand {
294
320
  ArgParser get argParser => ArgParser()
295
321
  ..addOption('backend', abbr: 'b', help: 'Backend provider.')
296
322
  ..addOption('id', help: 'Bundle id.')
297
- ..addFlag('off', help: 'Clear the force-update flag instead of setting it.');
323
+ ..addFlag(
324
+ 'off',
325
+ help: 'Clear the force-update flag instead of setting it.',
326
+ );
298
327
 
299
328
  @override
300
329
  Future<int> run() => runGuarded(() async {
301
- final id = argResults!['id'] as String?;
302
- if (id == null || id.isEmpty) {
303
- throw PackException(
304
- 'Usage: flutter_ota_kit bundle force --id <id> [--off]',
305
- 64,
306
- );
307
- }
308
- final off = argResults!['off'] as bool;
309
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
310
- final backend = requireBackend(cfg, override: backendOverride);
311
- banner('bundle · force');
312
- await spinner(
313
- () async {
314
- await backend.db.updateBundle(id, {
315
- 'shouldForceUpdate': !off,
316
- if (!off) 'enabled': true,
317
- });
318
- await backend.db.commitBundle();
319
- },
320
- off ? 'Clearing force flag on $id' : 'Forcing update for $id',
321
- done: off ? 'Cleared' : 'Forced',
322
- );
323
- });
330
+ final id = argResults!['id'] as String?;
331
+ if (id == null || id.isEmpty) {
332
+ throw PackException(
333
+ 'Usage: flutter_ota_kit bundle force --id <id> [--off]',
334
+ 64,
335
+ );
336
+ }
337
+ final off = argResults!['off'] as bool;
338
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
339
+ final backend = requireBackend(cfg, override: backendOverride);
340
+ banner('bundle · force');
341
+ await spinner(
342
+ () async {
343
+ await backend.db.updateBundle(id, {
344
+ 'shouldForceUpdate': !off,
345
+ if (!off) 'enabled': true,
346
+ });
347
+ await backend.db.commitBundle();
348
+ },
349
+ off ? 'Clearing force flag on $id' : 'Forcing update for $id',
350
+ done: off ? 'Cleared' : 'Forced',
351
+ );
352
+ });
324
353
  }
325
354
 
326
355
  class BundlePromoteCommand extends FlutterPatcherCommand {
@@ -343,27 +372,24 @@ class BundlePromoteCommand extends FlutterPatcherCommand {
343
372
 
344
373
  @override
345
374
  Future<int> run() => runGuarded(() async {
346
- final id = argResults!['id'] as String?;
347
- final channel = argResults!['channel'] as String?;
348
- if (id == null || id.isEmpty || channel == null || channel.isEmpty) {
349
- throw PackException(
350
- 'Usage: flutter_ota_kit bundle promote --id <id> --channel <channel>',
351
- 64,
352
- );
353
- }
354
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
355
- final backend = requireBackend(cfg, override: backendOverride);
356
- banner('bundle · promote');
357
- await spinner(
358
- () => promoteBundle(backend, id, channel),
359
- 'Promoting $id to $channel',
360
- done: 'Promoted',
361
- );
362
- box('promote', [
363
- kv('bundle', cyan(id)),
364
- kv('channel', channel),
365
- ]);
366
- });
375
+ final id = argResults!['id'] as String?;
376
+ final channel = argResults!['channel'] as String?;
377
+ if (id == null || id.isEmpty || channel == null || channel.isEmpty) {
378
+ throw PackException(
379
+ 'Usage: flutter_ota_kit bundle promote --id <id> --channel <channel>',
380
+ 64,
381
+ );
382
+ }
383
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
384
+ final backend = requireBackend(cfg, override: backendOverride);
385
+ banner('bundle · promote');
386
+ await spinner(
387
+ () => promoteBundle(backend, id, channel),
388
+ 'Promoting $id to $channel',
389
+ done: 'Promoted',
390
+ );
391
+ box('promote', [kv('bundle', cyan(id)), kv('channel', channel)]);
392
+ });
367
393
  }
368
394
 
369
395
  class BundleUpdateCommand extends FlutterPatcherCommand {
@@ -390,51 +416,51 @@ class BundleUpdateCommand extends FlutterPatcherCommand {
390
416
 
391
417
  @override
392
418
  Future<int> run() => runGuarded(() async {
393
- final id = argResults!['id'] as String?;
394
- if (id == null || id.isEmpty) {
395
- throw PackException(
396
- 'Usage: flutter-ota bundle update --id <id> '
397
- '[--message <m>] [--target-version <v>] [--enabled true|false] '
398
- '[--force true|false]',
399
- 64,
400
- );
401
- }
402
- final patch = <String, Object?>{};
403
- final message = argResults!['message'] as String?;
404
- if (message != null) patch['message'] = message;
405
- final target = argResults!['target-version'] as String?;
406
- if (target != null) patch['targetAppVersion'] = target;
407
- final enabled = argResults!['enabled'] as String?;
408
- if (enabled != null) {
409
- patch['enabled'] = enabled == 'true' || enabled == '1';
410
- }
411
- final force = argResults!['force'] as String?;
412
- if (force != null) {
413
- patch['shouldForceUpdate'] = force == 'true' || force == '1';
414
- }
415
- if (patch.isEmpty) {
416
- throw PackException('Nothing to update — pass at least one flag.', 64);
417
- }
418
- final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
419
- final backend = requireBackend(cfg, override: backendOverride);
420
- banner('bundle · update');
421
- await spinner(
422
- () async {
423
- await backend.db.updateBundle(id, patch);
424
- await backend.db.commitBundle();
425
- },
426
- 'Updating $id',
427
- done: 'Updated',
428
- );
429
- final b = await backend.db.getBundleById(id);
430
- if (b != null) {
431
- box('bundle', [
432
- kv('id', cyan(b.id)),
433
- kv('enabled', b.enabled ? green('yes') : yellow('no')),
434
- kv('force', b.shouldForceUpdate ? green('yes') : yellow('no')),
435
- kv('target', b.targetAppVersion ?? dim('-')),
436
- if (b.message != null) kv('message', b.message!),
437
- ]);
438
- }
439
- });
419
+ final id = argResults!['id'] as String?;
420
+ if (id == null || id.isEmpty) {
421
+ throw PackException(
422
+ 'Usage: flutter-ota bundle update --id <id> '
423
+ '[--message <m>] [--target-version <v>] [--enabled true|false] '
424
+ '[--force true|false]',
425
+ 64,
426
+ );
427
+ }
428
+ final patch = <String, Object?>{};
429
+ final message = argResults!['message'] as String?;
430
+ if (message != null) patch['message'] = message;
431
+ final target = argResults!['target-version'] as String?;
432
+ if (target != null) patch['targetAppVersion'] = target;
433
+ final enabled = argResults!['enabled'] as String?;
434
+ if (enabled != null) {
435
+ patch['enabled'] = enabled == 'true' || enabled == '1';
436
+ }
437
+ final force = argResults!['force'] as String?;
438
+ if (force != null) {
439
+ patch['shouldForceUpdate'] = force == 'true' || force == '1';
440
+ }
441
+ if (patch.isEmpty) {
442
+ throw PackException('Nothing to update — pass at least one flag.', 64);
443
+ }
444
+ final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
445
+ final backend = requireBackend(cfg, override: backendOverride);
446
+ banner('bundle · update');
447
+ await spinner(
448
+ () async {
449
+ await backend.db.updateBundle(id, patch);
450
+ await backend.db.commitBundle();
451
+ },
452
+ 'Updating $id',
453
+ done: 'Updated',
454
+ );
455
+ final b = await backend.db.getBundleById(id);
456
+ if (b != null) {
457
+ box('bundle', [
458
+ kv('id', cyan(b.id)),
459
+ kv('enabled', b.enabled ? green('yes') : yellow('no')),
460
+ kv('force', b.shouldForceUpdate ? green('yes') : yellow('no')),
461
+ kv('target', b.targetAppVersion ?? dim('-')),
462
+ if (b.message != null) kv('message', b.message!),
463
+ ]);
464
+ }
465
+ });
440
466
  }