@_nazmiforreal/flutter-ota 0.1.21 → 0.1.22

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 (41) hide show
  1. package/bin/flutter-ota-linux-x64 +0 -0
  2. package/dart-src/packages/cli-tools/.dart_tool/package_config.json +460 -0
  3. package/dart-src/packages/cli-tools/.dart_tool/package_graph.json +707 -0
  4. package/dart-src/packages/cli-tools/lib/flutter_ota_kit_cli.dart +7 -4
  5. package/dart-src/packages/cli-tools/lib/src/commands/bundle.dart +95 -32
  6. package/dart-src/packages/cli-tools/lib/src/commands/channel.dart +28 -12
  7. package/dart-src/packages/cli-tools/lib/src/commands/config_command.dart +9 -4
  8. package/dart-src/packages/cli-tools/lib/src/commands/deploy.dart +29 -6
  9. package/dart-src/packages/cli-tools/lib/src/commands/doctor.dart +20 -32
  10. package/dart-src/packages/cli-tools/lib/src/commands/init.dart +40 -19
  11. package/dart-src/packages/cli-tools/lib/src/commands/keys.dart +7 -5
  12. package/dart-src/packages/cli-tools/lib/src/commands/migrate.dart +33 -22
  13. package/dart-src/packages/cli-tools/lib/src/commands/pocketbase.dart +256 -68
  14. package/dart-src/packages/cli-tools/lib/src/commands/rollback.dart +17 -11
  15. package/dart-src/packages/cli-tools/lib/src/commands/storage.dart +28 -12
  16. package/dart-src/packages/cli-tools/lib/src/config.dart +5 -6
  17. package/dart-src/packages/cli-tools/lib/src/operations.dart +1 -3
  18. package/dart-src/packages/cli-tools/lib/src/pocketbase/process_manager.dart +17 -16
  19. package/dart-src/packages/cli-tools/lib/src/runner.dart +3 -1
  20. package/dart-src/packages/cli-tools/lib/src/ui/ui.dart +8 -14
  21. package/dart-src/packages/cli-tools/pubspec.lock +590 -0
  22. package/dart-src/packages/cli-tools/test/mocks/mock_pocketbase_client.dart +7 -3
  23. package/dart-src/packages/cli-tools/test/pocketbase_schema_test.dart +13 -16
  24. package/dart-src/packages/core/CHANGELOG.md +15 -0
  25. package/dart-src/packages/core/lib/src/bundle.dart +3 -6
  26. package/dart-src/packages/core/pubspec.yaml +1 -1
  27. package/dart-src/plugins/aws/CHANGELOG.md +18 -0
  28. package/dart-src/plugins/aws/lib/src/aws_cloudfront_client.dart +1 -2
  29. package/dart-src/plugins/aws/pubspec.yaml +3 -3
  30. package/dart-src/plugins/cloudflare/CHANGELOG.md +18 -0
  31. package/dart-src/plugins/cloudflare/pubspec.yaml +3 -3
  32. package/dart-src/plugins/plugin-core/CHANGELOG.md +15 -0
  33. package/dart-src/plugins/plugin-core/pubspec.yaml +2 -2
  34. package/dart-src/plugins/pocketbase/CHANGELOG.md +18 -0
  35. package/dart-src/plugins/pocketbase/pubspec.yaml +3 -3
  36. package/dart-src/plugins/postgres/CHANGELOG.md +18 -0
  37. package/dart-src/plugins/postgres/pubspec.yaml +3 -3
  38. package/dart-src/plugins/supabase/CHANGELOG.md +18 -0
  39. package/dart-src/plugins/supabase/pubspec.yaml +3 -3
  40. package/package.json +2 -2
  41. package/scripts/postinstall.js +5 -1
@@ -7,16 +7,24 @@ import '../ui/ui.dart';
7
7
  class RollbackCommand extends FlutterPatcherCommand {
8
8
  RollbackCommand({this.config, this.backendOverride}) {
9
9
  final detected = config?.provider ?? loadConfig()?.provider;
10
- argParser.addOption('backend', abbr: 'b', help: detected != null
11
- ? 'Backend provider [detected: $detected].'
12
- : 'Backend provider.');
10
+ argParser.addOption(
11
+ 'backend',
12
+ abbr: 'b',
13
+ help: detected != null
14
+ ? 'Backend provider [detected: $detected].'
15
+ : 'Backend provider.',
16
+ );
13
17
  argParser.addOption('channel', abbr: 'c', help: 'Channel to roll back.');
14
18
  argParser.addOption(
15
19
  'bundle-id',
16
20
  abbr: 'i',
17
21
  help: 'Roll back to this specific bundle id.',
18
22
  );
19
- argParser.addOption('platform', abbr: 'p', help: 'Platform filter (e.g. android).');
23
+ argParser.addOption(
24
+ 'platform',
25
+ abbr: 'p',
26
+ help: 'Platform filter (e.g. android).',
27
+ );
20
28
  }
21
29
 
22
30
  final FlutterPatcherConfig? config;
@@ -49,14 +57,12 @@ class RollbackCommand extends FlutterPatcherCommand {
49
57
 
50
58
  banner('rollback');
51
59
  final steps = Steps('rollback');
52
- final (disabled, live) = await steps.run('Rolling back channel "$channel"', () async {
60
+ final (
61
+ disabled,
62
+ live,
63
+ ) = await steps.run('Rolling back channel "$channel"', () async {
53
64
  if (bundleId != null && bundleId.isNotEmpty) {
54
- return rollbackToBundle(
55
- backend,
56
- channel,
57
- bundleId,
58
- platform: platform,
59
- );
65
+ return rollbackToBundle(backend, channel, bundleId, platform: platform);
60
66
  }
61
67
  final id = await rollbackChannel(backend, channel);
62
68
  final nowLive = (await getChannel(backend, channel))?.id ?? '';
@@ -28,9 +28,13 @@ class StorageCommand extends FlutterPatcherCommand {
28
28
  class StorageListCommand extends FlutterPatcherCommand {
29
29
  StorageListCommand({this.config, this.backendOverride}) {
30
30
  final detected = config?.provider ?? loadConfig()?.provider;
31
- argParser.addOption('backend', abbr: 'b', help: detected != null
32
- ? 'Backend provider [detected: $detected].'
33
- : 'Backend provider.');
31
+ argParser.addOption(
32
+ 'backend',
33
+ abbr: 'b',
34
+ help: detected != null
35
+ ? 'Backend provider [detected: $detected].'
36
+ : 'Backend provider.',
37
+ );
34
38
  argParser.addOption('prefix', help: 'Key prefix filter (e.g. bundles).');
35
39
  }
36
40
 
@@ -50,9 +54,12 @@ class StorageListCommand extends FlutterPatcherCommand {
50
54
  final prefix = argResults!['prefix'] as String?;
51
55
  banner('storage · list');
52
56
  final steps = Steps('list');
53
- final objects = await steps.run('Listing storage objects', () =>
54
- backend.storage.listObjects(
55
- prefix == null || prefix.isEmpty ? null : prefix));
57
+ final objects = await steps.run(
58
+ 'Listing storage objects',
59
+ () => backend.storage.listObjects(
60
+ prefix == null || prefix.isEmpty ? null : prefix,
61
+ ),
62
+ );
56
63
  if (objects.isEmpty) {
57
64
  steps.skip('(no objects)');
58
65
  steps.summary();
@@ -70,10 +77,17 @@ class StorageListCommand extends FlutterPatcherCommand {
70
77
  class StorageDeleteCommand extends FlutterPatcherCommand {
71
78
  StorageDeleteCommand({this.config, this.backendOverride}) {
72
79
  final detected = config?.provider ?? loadConfig()?.provider;
73
- argParser.addOption('backend', abbr: 'b', help: detected != null
74
- ? 'Backend provider [detected: $detected].'
75
- : 'Backend provider.');
76
- argParser.addMultiOption('key', help: 'Storage key to delete (repeatable).');
80
+ argParser.addOption(
81
+ 'backend',
82
+ abbr: 'b',
83
+ help: detected != null
84
+ ? 'Backend provider [detected: $detected].'
85
+ : 'Backend provider.',
86
+ );
87
+ argParser.addMultiOption(
88
+ 'key',
89
+ help: 'Storage key to delete (repeatable).',
90
+ );
77
91
  argParser.addOption('uri', help: 'Full storage URI to delete.');
78
92
  }
79
93
 
@@ -102,8 +116,10 @@ class StorageDeleteCommand extends FlutterPatcherCommand {
102
116
  banner('storage · delete');
103
117
  final steps = Steps('delete');
104
118
  if (keys.isNotEmpty) {
105
- await steps.run('Deleting ${keys.length} object(s)',
106
- () => backend.storage.deleteObjects(keys));
119
+ await steps.run(
120
+ 'Deleting ${keys.length} object(s)',
121
+ () => backend.storage.deleteObjects(keys),
122
+ );
107
123
  } else {
108
124
  await steps.run('Deleting $uri', () => backend.storage.delete(uri!));
109
125
  }
@@ -170,9 +170,7 @@ FlutterPatcherConfig? loadConfig() {
170
170
  jsonDecode(raw) as Map<String, dynamic>,
171
171
  );
172
172
  } on FormatException {
173
- stderr.writeln(
174
- 'Warning: invalid config at ${file.path} — ignoring.',
175
- );
173
+ stderr.writeln('Warning: invalid config at ${file.path} — ignoring.');
176
174
  return null;
177
175
  }
178
176
  }
@@ -246,7 +244,7 @@ SupabaseServiceRoleConfig resolveSupabaseConfig(
246
244
  if (resolvedUrl == null || resolvedUrl.isEmpty) {
247
245
  throw StateError(
248
246
  'Supabase URL is required. Set it via SUPABASE_URL env var, '
249
- 'or `flutter-ota config set supabase.url <url>`.',
247
+ 'or `flutter-ota config set supabase.url <url>`.',
250
248
  );
251
249
  }
252
250
 
@@ -280,7 +278,8 @@ SupabaseStorageConfig resolveSupabaseStorageConfig(
280
278
  supabaseServiceRoleKey: db.supabaseServiceRoleKey,
281
279
  supabaseAnonKey: db.supabaseAnonKey,
282
280
  clientFactory: db.clientFactory,
283
- bucketName: bucket ??
281
+ bucketName:
282
+ bucket ??
284
283
  Platform.environment['SUPABASE_BUCKET'] ??
285
284
  config.supabase.bucket ??
286
285
  'bundles',
@@ -382,7 +381,7 @@ PostgresConfig resolvePostgresDatabaseConfig(
382
381
  if (resolvedHost == null || resolvedHost.isEmpty) {
383
382
  throw StateError(
384
383
  'Postgres host is required. Set POSTGRES_HOST env var, '
385
- 'or `flutter-ota config set postgres.host <host>`.',
384
+ 'or `flutter-ota config set postgres.host <host>`.',
386
385
  );
387
386
  }
388
387
 
@@ -61,9 +61,7 @@ class ListOptions {
61
61
  /// Build the zip, upload it, and register a [Bundle] via the backend.
62
62
  Future<Bundle> deployBundle(Backend backend, DeployOptions opts) async {
63
63
  if (opts.targetAppVersion != null && opts.fingerprintHash != null) {
64
- throw StateError(
65
- 'Use only one of target-app-version / fingerprint-hash.',
66
- );
64
+ throw StateError('Use only one of target-app-version / fingerprint-hash.');
67
65
  }
68
66
  if (opts.targetAppVersion == null && opts.fingerprintHash == null) {
69
67
  throw StateError(
@@ -17,7 +17,7 @@ import 'package:path/path.dart' as p;
17
17
 
18
18
  class PocketBaseProcess {
19
19
  PocketBaseProcess._(this.process, this.dataDir, this.binaryPath)
20
- : _exitCodeCompleted = false {
20
+ : _exitCodeCompleted = false {
21
21
  process.exitCode.then((_) => _exitCodeCompleted = true);
22
22
  }
23
23
 
@@ -92,12 +92,14 @@ class PocketBaseProcessManager {
92
92
  }
93
93
 
94
94
  void _writeConfigFile(int pid) {
95
- configFile.writeAsStringSync(jsonEncode({
96
- 'pid': pid,
97
- 'host': host,
98
- 'port': port,
99
- 'url': 'http://$host:$port',
100
- }));
95
+ configFile.writeAsStringSync(
96
+ jsonEncode({
97
+ 'pid': pid,
98
+ 'host': host,
99
+ 'port': port,
100
+ 'url': 'http://$host:$port',
101
+ }),
102
+ );
101
103
  }
102
104
 
103
105
  Map<String, dynamic>? readConfig() {
@@ -135,19 +137,18 @@ class PocketBaseProcessManager {
135
137
  final hooksDir = Directory(p.join(dataDir.path, 'pb_hooks'));
136
138
  await hooksDir.create(recursive: true);
137
139
 
138
- final mergedEnv = <String, String>{
139
- ...Platform.environment,
140
- ...?env,
141
- };
140
+ final mergedEnv = <String, String>{...Platform.environment, ...?env};
142
141
 
143
142
  // Create superuser if credentials provided (PB 0.40+ doesn't support
144
143
  // PB_ADMIN_EMAIL env var, so we use the CLI directly).
145
144
  if (adminEmail != null && adminPassword != null) {
146
- final result = await Process.run(
147
- binaryPath.path,
148
- ['superuser', 'upsert', '--dir=${dataDir.path}', adminEmail, adminPassword],
149
- environment: mergedEnv,
150
- );
145
+ final result = await Process.run(binaryPath.path, [
146
+ 'superuser',
147
+ 'upsert',
148
+ '--dir=${dataDir.path}',
149
+ adminEmail,
150
+ adminPassword,
151
+ ], environment: mergedEnv);
151
152
  if (result.exitCode != 0) {
152
153
  // Non-fatal; serve will continue but schema install may fail.
153
154
  }
@@ -24,7 +24,9 @@ class FlutterPatcherRunner extends CommandRunner<int> {
24
24
  // Intercept missing subcommand for parent commands so we show our
25
25
  // colored usage text instead of the args package's plain text.
26
26
  if (results.command == null && results.rest.isEmpty) {
27
- final cmdName = results.arguments.isNotEmpty ? results.arguments.first : null;
27
+ final cmdName = results.arguments.isNotEmpty
28
+ ? results.arguments.first
29
+ : null;
28
30
  if (cmdName != null) {
29
31
  final cmd = commands[cmdName];
30
32
  if (cmd != null && cmd.subcommands.isNotEmpty) {
@@ -127,7 +127,8 @@ Future<T> spinner<T>(
127
127
  final r = await task();
128
128
  // Keep spinner visible for at least 400ms so fast ops are readable.
129
129
  final elapsed = sw.elapsedMilliseconds;
130
- if (elapsed < 400) await Future.delayed(Duration(milliseconds: 400 - elapsed));
130
+ if (elapsed < 400)
131
+ await Future.delayed(Duration(milliseconds: 400 - elapsed));
131
132
  timer.cancel();
132
133
  sw.stop();
133
134
  stdout.write('\r\x1b[K ${green('✓')} ${done ?? label}\n');
@@ -296,9 +297,7 @@ class Steps {
296
297
  void summary() {
297
298
  _sw.stop();
298
299
  final ms = _sw.elapsedMilliseconds;
299
- final time = ms >= 1000
300
- ? '${(ms / 1000).toStringAsFixed(1)}s'
301
- : '${ms}ms';
300
+ final time = ms >= 1000 ? '${(ms / 1000).toStringAsFixed(1)}s' : '${ms}ms';
302
301
  final parts = <String>[];
303
302
  if (_done > 0) parts.add('${_done} completed');
304
303
  if (_skipped > 0) parts.add('${_skipped} skipped');
@@ -401,9 +400,7 @@ class Steps {
401
400
  _activeTimer = null;
402
401
  _activeLabel = null;
403
402
  if (_colorOn) {
404
- stdout.write(
405
- '\r\x1b[K ${success ? green('✓') : red('✗')} $label\n',
406
- );
403
+ stdout.write('\r\x1b[K ${success ? green('✓') : red('✗')} $label\n');
407
404
  }
408
405
  if (success) {
409
406
  _done++;
@@ -455,9 +452,7 @@ class ProgressBar {
455
452
  _spin = (_spin + 1) % _frames.length;
456
453
  final pctStr = '${(pct * 100).round()}%'.padLeft(4);
457
454
 
458
- stdout.write(
459
- '\r\x1b[K ${cyan(_frames[_spin])} $_label $bar $pctStr',
460
- );
455
+ stdout.write('\r\x1b[K ${cyan(_frames[_spin])} $_label $bar $pctStr');
461
456
  }
462
457
 
463
458
  /// Finish: print the final status line. This is intentionally async and
@@ -470,11 +465,10 @@ class ProgressBar {
470
465
  _sw.stop();
471
466
  // Keep bar visible for at least 500ms so fast ops are readable.
472
467
  final elapsed = _sw.elapsedMilliseconds;
473
- if (elapsed < 500) await Future.delayed(Duration(milliseconds: 500 - elapsed));
468
+ if (elapsed < 500)
469
+ await Future.delayed(Duration(milliseconds: 500 - elapsed));
474
470
  final ms = _sw.elapsedMilliseconds;
475
- final time = ms >= 1000
476
- ? '${(ms / 1000).toStringAsFixed(1)}s'
477
- : '${ms}ms';
471
+ final time = ms >= 1000 ? '${(ms / 1000).toStringAsFixed(1)}s' : '${ms}ms';
478
472
  if (_colorOn) {
479
473
  stdout.write('\r\x1b[K ${green('✓')} $_label in $time\n');
480
474
  } else {