@_nazmiforreal/flutter-ota 0.1.13 → 0.1.15

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 (54) hide show
  1. package/bin/flutter-ota-linux-x64 +0 -0
  2. package/bin/flutter-ota.js +23 -72
  3. package/dart-src/packages/cli-tools/.dart_tool/package_config.json +0 -2
  4. package/dart-src/packages/cli-tools/.dart_tool/package_graph.json +6 -6
  5. package/dart-src/packages/cli-tools/lib/flutter_ota_kit_cli.dart +2 -2
  6. package/dart-src/packages/cli-tools/lib/src/commands/build.dart +1 -1
  7. package/dart-src/packages/cli-tools/lib/src/commands/bundle.dart +112 -124
  8. package/dart-src/packages/cli-tools/lib/src/commands/channel.dart +20 -28
  9. package/dart-src/packages/cli-tools/lib/src/commands/config_command.dart +40 -18
  10. package/dart-src/packages/cli-tools/lib/src/commands/console.dart +10 -11
  11. package/dart-src/packages/cli-tools/lib/src/commands/deploy.dart +30 -33
  12. package/dart-src/packages/cli-tools/lib/src/commands/doctor.dart +43 -41
  13. package/dart-src/packages/cli-tools/lib/src/commands/fingerprint.dart +9 -10
  14. package/dart-src/packages/cli-tools/lib/src/commands/init.dart +32 -35
  15. package/dart-src/packages/cli-tools/lib/src/commands/keys.dart +3 -6
  16. package/dart-src/packages/cli-tools/lib/src/commands/migrate.dart +59 -50
  17. package/dart-src/packages/cli-tools/lib/src/commands/pocketbase.dart +32 -37
  18. package/dart-src/packages/cli-tools/lib/src/commands/rollback.dart +13 -16
  19. package/dart-src/packages/cli-tools/lib/src/commands/storage.dart +12 -20
  20. package/dart-src/packages/cli-tools/lib/src/config.dart +10 -3
  21. package/dart-src/packages/cli-tools/lib/src/operations.dart +5 -0
  22. package/dart-src/packages/cli-tools/lib/src/ui/ui.dart +225 -31
  23. package/dart-src/packages/cli-tools/lib/src/util.dart +7 -3
  24. package/dart-src/packages/cli-tools/pubspec.lock +6 -6
  25. package/dart-src/packages/cli-tools/test/cli_test.dart +6 -0
  26. package/dart-src/packages/core/CHANGELOG.md +9 -0
  27. package/dart-src/packages/core/pubspec.yaml +1 -1
  28. package/dart-src/plugins/aws/CHANGELOG.md +10 -1
  29. package/dart-src/plugins/aws/pubspec.yaml +3 -3
  30. package/dart-src/plugins/cloudflare/CHANGELOG.md +9 -1
  31. package/dart-src/plugins/cloudflare/pubspec.yaml +3 -3
  32. package/dart-src/plugins/plugin-core/CHANGELOG.md +12 -14
  33. package/dart-src/plugins/plugin-core/pubspec.yaml +2 -2
  34. package/dart-src/plugins/pocketbase/pubspec.yaml +2 -2
  35. package/dart-src/plugins/postgres/CHANGELOG.md +13 -3
  36. package/dart-src/plugins/postgres/pubspec.yaml +3 -3
  37. package/dart-src/plugins/supabase/CHANGELOG.md +14 -11
  38. package/dart-src/plugins/supabase/pubspec.yaml +3 -3
  39. package/dart-src/plugins/supabase/supabase/migrations/20250103114225_init.sql +7 -3
  40. package/dart-src/plugins/supabase/supabase/migrations/20250314000000_hot-updater_0.13.0.sql +7 -4
  41. package/dart-src/plugins/supabase/supabase/migrations/20250516000000_hot-updater_0.18.0.sql +18 -6
  42. package/dart-src/plugins/supabase/supabase/migrations/20251014000000_hot-updater_0.21.0.sql +4 -2
  43. package/dart-src/plugins/supabase/supabase/migrations/20260401000000_hot-updater_0.29.0.sql +4 -2
  44. package/dart-src/plugins/supabase/supabase/migrations/20260520014100_hot-updater_rls.sql +22 -6
  45. package/migrations/supabase/20250103114225_init.sql +7 -3
  46. package/migrations/supabase/20250314000000_hot-updater_0.13.0.sql +7 -4
  47. package/migrations/supabase/20250516000000_hot-updater_0.18.0.sql +18 -6
  48. package/migrations/supabase/20251014000000_hot-updater_0.21.0.sql +4 -2
  49. package/migrations/supabase/20260401000000_hot-updater_0.29.0.sql +4 -2
  50. package/migrations/supabase/20260520014100_hot-updater_rls.sql +22 -6
  51. package/package.json +1 -1
  52. package/scripts/vendor.sh +32 -0
  53. package/migrations/aws/README.md +0 -7
  54. package/migrations/cloudflare/bundles.sql +0 -42
@@ -4,12 +4,15 @@ import 'dart:async';
4
4
  import 'dart:io';
5
5
  import 'dart:math' as math;
6
6
 
7
- /// Terminal UI toolkit for the flutter_ota_kit CLI: colored text, banners,
8
- /// bordered boxes, step logs, dynamic spinners and progress bars.
7
+ /// Terminal UI toolkit for the flutter-ota CLI.
9
8
  ///
10
- /// Everything degrades gracefully to plain text when stdout is not a TTY or the
11
- /// `NO_COLOR` env var is set, so pipes/CI/tests stay clean. Boxes auto-size to
12
- /// the terminal width and wrap long content so they never render broken.
9
+ /// Provides colored text, banners, bordered boxes, step logs, spinners,
10
+ /// thin progress bars, and column-aligned tables.
11
+ ///
12
+ /// Everything degrades gracefully to plain text when stdout is not a TTY
13
+ /// or the `NO_COLOR` env var is set.
14
+
15
+ // ── ANSI codes ───────────────────────────────────────────────────────────────
13
16
 
14
17
  const _kReset = '\x1b[0m';
15
18
  const _kRed = '\x1b[31m';
@@ -23,6 +26,8 @@ const _kBold = '\x1b[1m';
23
26
 
24
27
  const List<String> _frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
25
28
 
29
+ // ── TTY detection ────────────────────────────────────────────────────────────
30
+
26
31
  bool get _noColor {
27
32
  final v = Platform.environment['NO_COLOR'];
28
33
  return v != null && v.isNotEmpty;
@@ -31,6 +36,8 @@ bool get _noColor {
31
36
  bool get _colorOn =>
32
37
  !_noColor && stdout.hasTerminal && stdout.supportsAnsiEscapes;
33
38
 
39
+ // ── Color helpers ────────────────────────────────────────────────────────────
40
+
34
41
  String _c(String code, String s) => _colorOn ? '$code$s$_kReset' : s;
35
42
 
36
43
  String red(String s) => _c(_kRed, s);
@@ -43,7 +50,19 @@ String gray(String s) => _c(_kGray, s);
43
50
  String dim(String s) => _c(_kGray, s);
44
51
  String bold(String s) => _c(_kBold, s);
45
52
 
46
- int get _cols => stdout.hasTerminal ? stdout.terminalColumns : 80;
53
+ // ── Terminal width ───────────────────────────────────────────────────────────
54
+
55
+ int get _cols {
56
+ if (stdout.hasTerminal) return stdout.terminalColumns;
57
+ final envCols = Platform.environment['COLUMNS'];
58
+ if (envCols != null) {
59
+ final parsed = int.tryParse(envCols);
60
+ if (parsed != null && parsed > 0) return parsed;
61
+ }
62
+ return 80;
63
+ }
64
+
65
+ // ── Visible width (ANSI-aware) ──────────────────────────────────────────────
47
66
 
48
67
  final _ansi = RegExp('\x1b\\[[0-9;]*m');
49
68
 
@@ -51,26 +70,38 @@ int _dispWidth(String s) => s.replaceAll(_ansi, '').length;
51
70
 
52
71
  void _echo(String s) => stdout.writeln(s);
53
72
 
73
+ // ── Key-value pair ───────────────────────────────────────────────────────────
74
+
54
75
  /// `key value` laid out in a fixed 18-char column (visible-width aware).
76
+ /// Long values are truncated with `…` to prevent box overflow.
55
77
  String kv(String k, String v) {
56
78
  final pad = math.max(0, 18 - _dispWidth(k));
57
- return '${dim(k)}${' ' * pad} $v';
79
+ final maxVal = math.max(0, _cols - 24 - _dispWidth(k));
80
+ final display = maxVal > 0 && _dispWidth(v) > maxVal
81
+ ? '${_cut(v, maxVal - 1)}…'
82
+ : v;
83
+ return '${dim(k)}${' ' * pad} $display';
58
84
  }
59
85
 
86
+ // ── Banner ───────────────────────────────────────────────────────────────────
87
+
60
88
  void banner(String name) {
61
89
  _echo('');
62
90
  _echo(
63
- ' ${cyan('▶')} ${cyan(bold('flutter_ota_kit'))} ${dim('·')} ${bold(name)}',
91
+ ' ${cyan('▶')} ${cyan(bold('flutter-ota'))} ${dim('·')} ${bold(name)}',
64
92
  );
65
- _echo(' ${dim('─' * math.min(_cols - 4, 60))}');
93
+ final sepLen = math.max(20, math.min(_cols - 4, 72));
94
+ _echo(' ${dim('─' * sepLen)}');
66
95
  }
67
96
 
68
- void step(String msg) => _echo(' ${green('✓')} $msg');
69
-
70
- void warn(String msg) => _echo(' ${yellow('!')} ${yellow(msg)}');
97
+ // ── Single-line status ──────────────────────────────────────────────────────
71
98
 
99
+ void step(String msg) => _echo(' ${green('✓')} $msg');
100
+ void warn(String msg) => _echo(' ${yellow('⚠')} ${yellow(msg)}');
72
101
  void err(String msg) => _echo(' ${red('✗')} ${red(msg)}');
73
102
 
103
+ // ── Spinner ──────────────────────────────────────────────────────────────────
104
+
74
105
  /// Run [task] while showing a live spinner; replaces the line with a
75
106
  /// `${green('✓')} done` summary when finished (or `✗` on error).
76
107
  Future<T> spinner<T>(
@@ -101,6 +132,8 @@ Future<T> spinner<T>(
101
132
  }
102
133
  }
103
134
 
135
+ // ── Word wrap ────────────────────────────────────────────────────────────────
136
+
104
137
  List<String> _wrap(String text, int inner) {
105
138
  if (text.isEmpty) return [''];
106
139
  final result = <String>[];
@@ -148,6 +181,11 @@ String _cut(String s, int inner) {
148
181
  String _splitLong(String word, int inner, List<String> out) {
149
182
  var rem = word;
150
183
  while (_dispWidth(rem) > inner) {
184
+ if (_dispWidth(rem) <= inner + 2) {
185
+ // Truncate with … instead of hard-breaking mid-word.
186
+ out.add('${_cut(rem, inner - 1)}…');
187
+ return '';
188
+ }
151
189
  final cut = _cut(rem, inner);
152
190
  out.add(cut);
153
191
  rem = rem.substring(cut.length);
@@ -155,14 +193,19 @@ String _splitLong(String word, int inner, List<String> out) {
155
193
  return rem;
156
194
  }
157
195
 
196
+ // ── Box ──────────────────────────────────────────────────────────────────────
197
+
198
+ /// Mathematically precise box width: single formula for both title and content.
158
199
  int _boxWidth(List<String> lines, String title) {
159
- var longest = _dispWidth(title) + 4;
200
+ var longest = 0;
160
201
  for (final l in lines) {
161
202
  for (final w in l.split('\n')) {
162
203
  longest = math.max(longest, _dispWidth(w));
163
204
  }
164
205
  }
165
- final target = math.max(longest + 4, 40);
206
+ final titleNeeded = _dispWidth(title) + 4;
207
+ final contentNeeded = longest + 4;
208
+ final target = math.max(titleNeeded, math.max(contentNeeded, 40));
166
209
  return math.max(math.min(_cols - 1, target), 20);
167
210
  }
168
211
 
@@ -171,18 +214,25 @@ int _boxWidth(List<String> lines, String title) {
171
214
  void box(String title, List<String> lines) {
172
215
  final width = _boxWidth(lines, title);
173
216
  final inner = width - 4;
217
+
218
+ // Wrap content to fit inner width.
174
219
  final wrapped = <String>[];
175
220
  for (final l in lines) {
176
- wrapped.addAll(_wrap(l, inner));
221
+ if (l.isEmpty) {
222
+ wrapped.add('');
223
+ } else {
224
+ wrapped.addAll(_wrap(l, inner));
225
+ }
177
226
  }
178
227
 
228
+ // Title centered in top border.
179
229
  final titleText = ' $title ';
180
230
  final tVisible = _dispWidth(titleText);
181
- var dashes = math.max(2, width - 2 - tVisible);
182
- final left = math.max(1, dashes ~/ 2);
183
- final right = dashes - left;
184
- final top = '╭${'─' * left}$titleText${'─' * right}╮';
185
- _echo(top);
231
+ final totalDashes = width - 2 - tVisible;
232
+ final leftDashes = math.max(1, totalDashes ~/ 2);
233
+ final rightDashes = totalDashes - leftDashes;
234
+
235
+ _echo('╭${'─' * leftDashes}$titleText${'─' * rightDashes}╮');
186
236
  for (final l in wrapped) {
187
237
  final pad = math.max(0, inner - _dispWidth(l));
188
238
  _echo('│ $l${' ' * pad} │');
@@ -190,44 +240,188 @@ void box(String title, List<String> lines) {
190
240
  _echo('╰${'─' * (width - 2)}╯');
191
241
  }
192
242
 
193
- /// Live progress bar with an animated spinner prefix. Call [update] as work
194
- /// progresses; it renders a `[████░░] 45%` bar that overwrites the same line.
243
+ // ── Steps ────────────────────────────────────────────────────────────────────
244
+
245
+ /// Multi-step progress tracker with uv-style clean output.
246
+ ///
247
+ /// Each step prints a single line: `✓ label` (done), `✗ label` (failed),
248
+ /// or `· label` (skipped). After all steps, call [summary] to print a
249
+ /// boxed summary with counts and elapsed time.
250
+ ///
251
+ /// Example:
252
+ /// ```dart
253
+ /// final s = Steps('migrate · supabase');
254
+ /// s.success('Applied 20250103_init.sql');
255
+ /// s.skip('Skipped 20251014_0.21.0.sql');
256
+ /// s.summary(); // prints "2 applied · 1 skipped · 0 errors · 245ms"
257
+ /// ```
258
+ class Steps {
259
+ Steps(this.title) : _sw = Stopwatch()..start();
260
+
261
+ final String title;
262
+ final Stopwatch _sw;
263
+ int _done = 0;
264
+ int _failed = 0;
265
+ int _skipped = 0;
266
+
267
+ /// Whether any step has failed.
268
+ bool get hasErrors => _failed > 0;
269
+
270
+ /// Step completed successfully.
271
+ void success(String label) {
272
+ _done++;
273
+ _echo(' ${green('✓')} $label');
274
+ }
275
+
276
+ /// Step failed.
277
+ void fail(String label) {
278
+ _failed++;
279
+ _echo(' ${red('✗')} $label');
280
+ }
281
+
282
+ /// Step skipped (e.g. already applied).
283
+ void skip(String label) {
284
+ _skipped++;
285
+ _echo(' ${dim('·')} $label');
286
+ }
287
+
288
+ /// Print boxed summary: "N applied · N skipped · N errors · TIME"
289
+ void summary() {
290
+ _sw.stop();
291
+ final ms = _sw.elapsedMilliseconds;
292
+ final time = ms >= 1000
293
+ ? '${(ms / 1000).toStringAsFixed(1)}s'
294
+ : '${ms}ms';
295
+ final parts = <String>[];
296
+ if (_done > 0) parts.add('${_done} completed');
297
+ if (_skipped > 0) parts.add('${_skipped} skipped');
298
+ if (_failed > 0) parts.add('${red('${_failed} error${_failed > 1 ? 's' : ''}')}');
299
+ if (parts.isEmpty) parts.add('no steps');
300
+ parts.add(time);
301
+ box('summary', [parts.join(' · ')]);
302
+ }
303
+ }
304
+
305
+ // ── Progress Bar (thin, single-line) ────────────────────────────────────────
306
+
307
+ /// Thin single-line progress bar with spinner, label, bar, percent, and time.
308
+ ///
309
+ /// Renders as: `⠹ Label ████░░░░ 50% 1.3s`
310
+ /// On finish: `✓ Label in 1.3s`
195
311
  class ProgressBar {
196
312
  ProgressBar(this.total, this.label);
197
313
 
198
314
  int total;
199
- final String label;
315
+ String label;
200
316
  int _current = 0;
201
317
  int _spin = 0;
202
318
  bool _closed = false;
319
+ final Stopwatch _sw = Stopwatch()..start();
320
+ late String _label = label;
203
321
 
204
- void update(int current, [String? label]) {
322
+ void update(int current, [String? newLabel]) {
205
323
  _current = current;
206
- if (label != null) _label = label;
324
+ if (newLabel != null) _label = newLabel;
207
325
  _draw();
208
326
  if (total > 0 && _current >= total) _finish();
209
327
  }
210
328
 
211
- late String _label = label;
212
-
213
329
  void _draw() {
214
330
  if (_closed) return;
215
331
  if (!_colorOn) {
216
332
  _echo(' $_label: $_current/$total');
217
333
  return;
218
334
  }
219
- const barW = 28;
335
+
220
336
  final pct = total > 0 ? (_current / total).clamp(0.0, 1.0) : 1.0;
337
+
338
+ // Thin bar: width scales to terminal, max 20 chars.
339
+ final barW = math.min(20, math.max(8, _cols - 40));
221
340
  final filled = (barW * pct).round();
222
- final bar = '${green('█' * filled)}${gray('·' * (barW - filled))}';
341
+ final empty = barW - filled;
342
+ final bar = '${yellow('█' * filled)}${gray('░' * empty)}';
343
+
223
344
  _spin = (_spin + 1) % _frames.length;
224
345
  final pctStr = '${(pct * 100).round()}%'.padLeft(4);
225
- stdout.write('\r\x1b[K ${cyan(_frames[_spin])} $_label [$bar] $pctStr');
346
+
347
+ stdout.write(
348
+ '\r\x1b[K ${cyan(_frames[_spin])} $_label $bar $pctStr',
349
+ );
226
350
  }
227
351
 
228
352
  void _finish() {
229
353
  if (_closed) return;
230
354
  _closed = true;
231
- if (_colorOn) stdout.write('\n');
355
+ _sw.stop();
356
+ final ms = _sw.elapsedMilliseconds;
357
+ final time = ms >= 1000
358
+ ? '${(ms / 1000).toStringAsFixed(1)}s'
359
+ : '${ms}ms';
360
+ if (_colorOn) {
361
+ stdout.write('\r\x1b[K ${green('✓')} $_label in $time\n');
362
+ } else {
363
+ _echo(' ✓ $_label in $time');
364
+ }
365
+ }
366
+
367
+ /// Force finish (for when total is not reached).
368
+ void close() {
369
+ if (!_closed) _finish();
370
+ }
371
+ }
372
+
373
+ // ── Table ────────────────────────────────────────────────────────────────────
374
+
375
+ /// Column-aligned table inside a bordered box.
376
+ ///
377
+ /// Example:
378
+ /// ```dart
379
+ /// table('3 bundles', ['#', 'ID', 'CHANNEL', 'ON'], [
380
+ /// ['0', 'abc-123', 'production', '✓'],
381
+ /// ['1', 'def-456', 'staging', '✗'],
382
+ /// ]);
383
+ /// ```
384
+ void table(String title, List<String> headers, List<List<String>> rows) {
385
+ if (headers.isEmpty) return;
386
+
387
+ // Calculate column widths from content.
388
+ final colCount = headers.length;
389
+ final colWidths = List<int>.filled(colCount, 0);
390
+ for (var i = 0; i < colCount; i++) {
391
+ colWidths[i] = _dispWidth(headers[i]);
392
+ }
393
+ for (final row in rows) {
394
+ for (var i = 0; i < colCount && i < row.length; i++) {
395
+ colWidths[i] = math.max(colWidths[i], _dispWidth(row[i]));
396
+ }
397
+ }
398
+
399
+ // Build formatted lines.
400
+ final formatted = <String>[];
401
+
402
+ // Header line.
403
+ final headerParts = <String>[];
404
+ for (var i = 0; i < colCount; i++) {
405
+ headerParts.add(headers[i].padRight(colWidths[i]));
406
+ }
407
+ formatted.add(bold(headerParts.join(' ')));
408
+
409
+ // Separator line.
410
+ final sepParts = <String>[];
411
+ for (var i = 0; i < colCount; i++) {
412
+ sepParts.add('─' * colWidths[i]);
232
413
  }
414
+ formatted.add(dim(sepParts.join(' ')));
415
+
416
+ // Data rows.
417
+ for (final row in rows) {
418
+ final parts = <String>[];
419
+ for (var i = 0; i < colCount; i++) {
420
+ final cell = i < row.length ? row[i] : '';
421
+ parts.add(cell.padRight(colWidths[i]));
422
+ }
423
+ formatted.add(parts.join(' '));
424
+ }
425
+
426
+ box(title, formatted);
233
427
  }
@@ -51,9 +51,13 @@ String generateFingerprint(String directory) {
51
51
  for (final entity in dir.listSync(recursive: true)) {
52
52
  if (entity is! File) continue;
53
53
  final relative = p.relative(entity.path, from: dir.path);
54
- final content = File(entity.path).readAsBytesSync();
55
- final hash = sha256Hex(content);
56
- entries.add('$relative:$hash');
54
+ try {
55
+ final content = File(entity.path).readAsBytesSync();
56
+ final hash = sha256Hex(content);
57
+ entries.add('$relative:$hash');
58
+ } on FileSystemException {
59
+ // Skip unreadable files (sockets, pipes, broken symlinks).
60
+ }
57
61
  }
58
62
  entries.sort();
59
63
  return sha256Hex(utf8.encode(entries.join('\n')));
@@ -159,28 +159,28 @@ packages:
159
159
  path: "../../plugins/aws"
160
160
  relative: true
161
161
  source: path
162
- version: "0.1.2"
162
+ version: "0.1.3"
163
163
  flutter_ota_kit_cloudflare:
164
164
  dependency: "direct main"
165
165
  description:
166
166
  path: "../../plugins/cloudflare"
167
167
  relative: true
168
168
  source: path
169
- version: "0.1.2"
169
+ version: "0.1.3"
170
170
  flutter_ota_kit_core:
171
171
  dependency: "direct main"
172
172
  description:
173
173
  path: "../core"
174
174
  relative: true
175
175
  source: path
176
- version: "0.1.1"
176
+ version: "0.1.2"
177
177
  flutter_ota_kit_plugin_core:
178
178
  dependency: "direct main"
179
179
  description:
180
180
  path: "../../plugins/plugin-core"
181
181
  relative: true
182
182
  source: path
183
- version: "0.0.3"
183
+ version: "0.0.4"
184
184
  flutter_ota_kit_pocketbase:
185
185
  dependency: "direct main"
186
186
  description:
@@ -194,14 +194,14 @@ packages:
194
194
  path: "../../plugins/postgres"
195
195
  relative: true
196
196
  source: path
197
- version: "0.1.2"
197
+ version: "0.1.3"
198
198
  flutter_ota_kit_supabase:
199
199
  dependency: "direct main"
200
200
  description:
201
201
  path: "../../plugins/supabase"
202
202
  relative: true
203
203
  source: path
204
- version: "0.1.3"
204
+ version: "0.1.4"
205
205
  frontend_server_client:
206
206
  dependency: transitive
207
207
  description:
@@ -381,6 +381,7 @@ void main() {
381
381
  source: dir.path,
382
382
  channel: 'production',
383
383
  platform: 'android',
384
+ targetAppVersion: '1.0.0',
384
385
  ),
385
386
  );
386
387
  expect(bundle.enabled, isTrue);
@@ -402,6 +403,7 @@ void main() {
402
403
  source: dir.path,
403
404
  channel: 'production',
404
405
  platform: 'android',
406
+ targetAppVersion: '1.0.0',
405
407
  ),
406
408
  );
407
409
  final res = await listBundles(
@@ -429,6 +431,7 @@ void main() {
429
431
  source: dir.path,
430
432
  channel: 'production',
431
433
  platform: 'android',
434
+ targetAppVersion: '1.0.0',
432
435
  ),
433
436
  );
434
437
  await deleteBundle(backend, deployed.id);
@@ -448,6 +451,7 @@ void main() {
448
451
  source: dir.path,
449
452
  channel: 'production',
450
453
  platform: 'android',
454
+ targetAppVersion: '1.0.0',
451
455
  ),
452
456
  );
453
457
  final second = await deployBundle(
@@ -456,6 +460,7 @@ void main() {
456
460
  source: dir.path,
457
461
  channel: 'production',
458
462
  platform: 'android',
463
+ targetAppVersion: '2.0.0',
459
464
  ),
460
465
  );
461
466
  final disabled = await rollbackChannel(backend, 'production');
@@ -477,6 +482,7 @@ void main() {
477
482
  source: dir.path,
478
483
  channel: 'production',
479
484
  platform: 'android',
485
+ targetAppVersion: '1.0.0',
480
486
  ),
481
487
  );
482
488
  await promoteBundle(backend, b.id, 'staging');
@@ -1,3 +1,12 @@
1
+ ## 0.1.2
2
+
3
+ - Add dartdoc on internal API surfaces (10/10 pana dartdoc coverage).
4
+
5
+ ## 0.1.1
6
+
7
+ - Fix `<id>` angle bracket in dartdoc (`bundle.dart:23`) being interpreted as HTML by Markdown renderers.
8
+ - Repository moved to `https://github.com/HYPER12755/flutter-ota-kit`.
9
+
1
10
  ## 0.1.0
2
11
 
3
12
  - Initial release of `flutter_ota_kit_core` as part of the flutter_ota_kit OTA toolkit.
@@ -1,6 +1,6 @@
1
1
  name: flutter_ota_kit_core
2
2
  description: Core data model, rollout cohorts, and shared utilities for flutter_ota_kit — Dart translation of hot-updater's packages/core.
3
- version: 0.1.1
3
+ version: 0.1.2
4
4
  homepage: https://github.com/HYPER12755/flutter-ota-kit
5
5
  repository: https://github.com/HYPER12755/flutter-ota-kit
6
6
  issue_tracker: https://github.com/HYPER12755/flutter-ota-kit/issues
@@ -1,9 +1,18 @@
1
- ## 0.1.1
1
+ ## 0.1.3
2
+
3
+ - Add dartdoc on internal API surfaces (10/10 pana dartdoc coverage).
4
+
5
+ ## 0.1.2
2
6
 
7
+ - Bump `pointycastle` to `^4.0.0` (API-compatible, security update).
3
8
  - Add `withCloudFrontSignedUrl` helper for time-limited download URLs.
4
9
  - Add `defaultAwsCloudFrontClientFactory` export.
5
10
  - Repository moved to `https://github.com/HYPER12755/flutter-ota-kit`.
6
11
 
12
+ ## 0.1.1
13
+
14
+ - Initial test release of the AWS S3 + CloudFront storage plugin.
15
+
7
16
  ## 0.1.0
8
17
 
9
18
  - Initial release of `flutter_ota_kit_aws` as part of the flutter_ota_kit OTA toolkit.
@@ -1,6 +1,6 @@
1
1
  name: flutter_ota_kit_aws
2
2
  description: AWS S3 storage + S3/DynamoDB database plugins for flutter_ota_kit (faithful port of hot-updater plugins/aws).
3
- version: 0.1.2
3
+ version: 0.1.3
4
4
  homepage: https://github.com/HYPER12755/flutter-ota-kit
5
5
  repository: https://github.com/HYPER12755/flutter-ota-kit
6
6
  issue_tracker: https://github.com/HYPER12755/flutter-ota-kit/issues
@@ -11,8 +11,8 @@ environment:
11
11
  sdk: ">=3.13.2 <4.0.0"
12
12
 
13
13
  dependencies:
14
- flutter_ota_kit_core: ^0.1.1
15
- flutter_ota_kit_plugin_core: ^0.0.3
14
+ flutter_ota_kit_core: ^0.1.2
15
+ flutter_ota_kit_plugin_core: ^0.0.4
16
16
  crypto: ^3.0.0
17
17
  http: ^1.2.0
18
18
  path: ^1.9.0
@@ -1,10 +1,18 @@
1
- ## 0.1.1
1
+ ## 0.1.3
2
+
3
+ - Add dartdoc on internal API surfaces (10/10 pana dartdoc coverage).
4
+
5
+ ## 0.1.2
2
6
 
3
7
  - Add `parseMetadata` / `parseTargetCohorts` exports from the D1 bundle
4
8
  mapper for writing custom Cloudflare Worker logic.
5
9
  - Add `defaultRolloutCohortCount` export.
6
10
  - Repository moved to `https://github.com/HYPER12755/flutter-ota-kit`.
7
11
 
12
+ ## 0.1.1
13
+
14
+ - Initial test release of the Cloudflare D1 + R2 storage plugin.
15
+
8
16
  ## 0.1.0
9
17
 
10
18
  - Initial release of `flutter_ota_kit_cloudflare` as part of the flutter_ota_kit OTA toolkit.
@@ -1,6 +1,6 @@
1
1
  name: flutter_ota_kit_cloudflare
2
2
  description: Cloudflare D1 + R2 storage plugins for flutter_ota_kit (faithful port of hot-updater plugins/cloudflare).
3
- version: 0.1.2
3
+ version: 0.1.3
4
4
  homepage: https://github.com/HYPER12755/flutter-ota-kit
5
5
  repository: https://github.com/HYPER12755/flutter-ota-kit
6
6
  issue_tracker: https://github.com/HYPER12755/flutter-ota-kit/issues
@@ -11,8 +11,8 @@ environment:
11
11
  sdk: ">=3.13.2 <4.0.0"
12
12
 
13
13
  dependencies:
14
- flutter_ota_kit_core: ^0.1.1
15
- flutter_ota_kit_plugin_core: ^0.0.3
14
+ flutter_ota_kit_core: ^0.1.2
15
+ flutter_ota_kit_plugin_core: ^0.0.4
16
16
  crypto: ^3.0.0
17
17
  http: ^1.2.0
18
18
  path: ^1.9.0
@@ -1,19 +1,17 @@
1
- ## 0.0.2
1
+ ## 0.0.4
2
2
 
3
- ### Changed
3
+ - Add dartdoc on internal API surfaces (10/10 pana dartdoc coverage).
4
4
 
5
- - **Shared previously-duplicated backend helpers in one place.** Extracted
6
- `ensureExpectedBucket` (the S3/R2 bucket-mismatch guard, formerly copied
7
- byte-for-byte in the cloudflare + aws storage profiles), `normalizeMetadata`
8
- (bundle `metadata` JSON-string/object normalization, formerly in the supabase +
9
- postgres mappers and cloudflare's `parseMetadata`), `buildBundlePatchId`
10
- (the `${bundleId}:${baseBundleId}` patch primary key, formerly in three mappers),
11
- and `updateJsonKeyRegex` (the `update.json` key matcher, formerly duplicated in
12
- the aws blob database + `createBlobDatabasePlugin`). The four backend plugins
13
- now import these from `plugin-core` instead of maintaining their own copies.
14
- Public API of the backend packages is unchanged (cloudflare still re-exports
15
- `buildBundlePatchId` / `parseMetadata` as aliases of the shared helpers).
5
+ ## 0.0.3
16
6
 
17
- ## 0.0.1
7
+ - Bump `mime` constraint to `^2.0.0` (now used for asset content-type detection).
8
+ - Add `parseStorageUri` + `ParsedStorageUri` exports for the storage URI helpers.
9
+ - Repository moved to `https://github.com/HYPER12755/flutter-ota-kit`.
10
+
11
+ ## 0.0.2
18
12
 
19
13
  - Initial release of `flutter_ota_kit_plugin_core` as part of the flutter_ota_kit OTA toolkit.
14
+
15
+ ## 0.0.1
16
+
17
+ - Pre-release of the plugin core abstractions.
@@ -1,6 +1,6 @@
1
1
  name: flutter_ota_kit_plugin_core
2
2
  description: Plugin core abstractions for flutter_ota_kit — database, storage, and build interfaces.
3
- version: 0.0.3
3
+ version: 0.0.4
4
4
  homepage: https://github.com/HYPER12755/flutter-ota-kit
5
5
  repository: https://github.com/HYPER12755/flutter-ota-kit
6
6
  issue_tracker: https://github.com/HYPER12755/flutter-ota-kit/issues
@@ -11,7 +11,7 @@ environment:
11
11
  sdk: ">=3.13.2 <4.0.0"
12
12
 
13
13
  dependencies:
14
- flutter_ota_kit_core: ^0.1.1
14
+ flutter_ota_kit_core: ^0.1.2
15
15
  mime: ^2.0.0
16
16
 
17
17
  dev_dependencies:
@@ -11,8 +11,8 @@ environment:
11
11
  sdk: ">=3.13.2 <4.0.0"
12
12
 
13
13
  dependencies:
14
- flutter_ota_kit_core: ^0.1.1
15
- flutter_ota_kit_plugin_core: ^0.0.3
14
+ flutter_ota_kit_core: ^0.1.2
15
+ flutter_ota_kit_plugin_core: ^0.0.4
16
16
  http: ^1.2.0
17
17
 
18
18
  dev_dependencies: