@_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.
- package/README.md +1 -1
- package/bin/flutter-ota-linux-x64 +0 -0
- package/dart-src/packages/cli-tools/.dart_tool/package_config.json +46 -76
- package/dart-src/packages/cli-tools/.dart_tool/package_graph.json +140 -166
- package/dart-src/packages/cli-tools/README.md +1 -1
- package/dart-src/packages/cli-tools/lib/flutter_ota_kit_cli.dart +30 -17
- package/dart-src/packages/cli-tools/lib/src/backend.dart +30 -31
- package/dart-src/packages/cli-tools/lib/src/cli_base.dart +3 -1
- package/dart-src/packages/cli-tools/lib/src/commands/build.dart +44 -43
- package/dart-src/packages/cli-tools/lib/src/commands/bundle.dart +265 -239
- package/dart-src/packages/cli-tools/lib/src/commands/channel.dart +75 -66
- package/dart-src/packages/cli-tools/lib/src/commands/config_command.dart +39 -35
- package/dart-src/packages/cli-tools/lib/src/commands/console.dart +30 -27
- package/dart-src/packages/cli-tools/lib/src/commands/deploy.dart +88 -72
- package/dart-src/packages/cli-tools/lib/src/commands/doctor.dart +66 -29
- package/dart-src/packages/cli-tools/lib/src/commands/fingerprint.dart +10 -6
- package/dart-src/packages/cli-tools/lib/src/commands/init.dart +290 -181
- package/dart-src/packages/cli-tools/lib/src/commands/keys.dart +24 -23
- package/dart-src/packages/cli-tools/lib/src/commands/migrate.dart +111 -97
- package/dart-src/packages/cli-tools/lib/src/commands/pocketbase.dart +237 -0
- package/dart-src/packages/cli-tools/lib/src/commands/rollback.dart +43 -34
- package/dart-src/packages/cli-tools/lib/src/commands/storage.dart +57 -53
- package/dart-src/packages/cli-tools/lib/src/config.dart +227 -93
- package/dart-src/packages/cli-tools/lib/src/operations.dart +9 -8
- package/dart-src/packages/cli-tools/lib/src/pack.dart +26 -25
- package/dart-src/packages/cli-tools/lib/src/pocketbase/data_bootstrap.dart +39 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/hooks/bundles.pb.js +56 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/installer.dart +189 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/process_manager.dart +123 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/schema_installer.dart +237 -0
- package/dart-src/packages/cli-tools/lib/src/runner.dart +36 -15
- package/dart-src/packages/cli-tools/lib/src/sign.dart +13 -5
- package/dart-src/packages/cli-tools/lib/src/ui/ui.dart +10 -13
- package/dart-src/packages/cli-tools/lib/src/util.dart +3 -1
- package/dart-src/packages/cli-tools/pubspec.lock +69 -116
- package/dart-src/packages/cli-tools/pubspec.yaml +25 -7
- package/dart-src/packages/cli-tools/test/backends_test.dart +62 -32
- package/dart-src/packages/cli-tools/test/build_pack_test.dart +4 -4
- package/dart-src/packages/cli-tools/test/cli_test.dart +89 -42
- package/dart-src/packages/cli-tools/test/mocks/mock_aws_s3_client.dart +8 -13
- package/dart-src/packages/cli-tools/test/mocks/mock_d1_client.dart +23 -18
- package/dart-src/packages/cli-tools/test/mocks/mock_pocketbase_client.dart +197 -0
- package/dart-src/packages/cli-tools/test/mocks/mock_postgres_client.dart +70 -46
- package/dart-src/packages/cli-tools/test/pocketbase_installer_test.dart +72 -0
- package/dart-src/packages/cli-tools/test/pocketbase_schema_test.dart +107 -0
- package/dart-src/packages/cli-tools/test/pocketbase_smoke_test.dart +59 -0
- package/dart-src/packages/core/CHANGELOG.md +9 -0
- package/dart-src/packages/core/README.md +2 -2
- package/dart-src/packages/core/example/lib/main.dart +69 -0
- package/dart-src/packages/core/lib/flutter_ota_kit_core.dart +1 -1
- package/dart-src/packages/core/lib/src/app_update_info.dart +17 -15
- package/dart-src/packages/core/lib/src/bundle.dart +102 -94
- package/dart-src/packages/core/lib/src/bundle_artifacts.dart +1 -2
- package/dart-src/packages/core/lib/src/bundle_patch_artifact.dart +15 -16
- package/dart-src/packages/core/lib/src/changed_asset.dart +24 -22
- package/dart-src/packages/core/lib/src/get_bundles_args.dart +13 -13
- package/dart-src/packages/core/lib/src/metadata.dart +9 -7
- package/dart-src/packages/core/lib/src/patch_info.dart +8 -7
- package/dart-src/packages/core/lib/src/platform.dart +4 -3
- package/dart-src/packages/core/lib/src/rollout.dart +14 -11
- package/dart-src/packages/core/lib/src/semver_range.dart +49 -39
- package/dart-src/packages/core/lib/src/semver_version.dart +8 -7
- package/dart-src/packages/core/lib/src/status.dart +4 -3
- package/dart-src/packages/core/lib/src/update_bundle_params.dart +7 -7
- package/dart-src/packages/core/lib/src/uuid.dart +1 -2
- package/dart-src/packages/core/pubspec.yaml +6 -7
- package/dart-src/packages/core/test/rollout_test.dart +15 -8
- package/dart-src/packages/core/test/semver_test.dart +5 -2
- package/dart-src/packages/core/test/types_test.dart +26 -24
- package/dart-src/packages/core/test/uuid_test.dart +3 -1
- package/dart-src/packages/core/tool/dbg.dart +1 -0
- package/dart-src/plugins/aws/CHANGELOG.md +15 -0
- package/dart-src/plugins/aws/example/lib/main.dart +60 -0
- package/dart-src/plugins/aws/lib/flutter_ota_kit_aws.dart +5 -1
- package/dart-src/plugins/aws/lib/src/aws_cloudfront_client.dart +11 -16
- package/dart-src/plugins/aws/lib/src/aws_cloudfront_signer.dart +7 -2
- package/dart-src/plugins/aws/lib/src/aws_database.dart +14 -18
- package/dart-src/plugins/aws/lib/src/aws_s3_client.dart +23 -18
- package/dart-src/plugins/aws/lib/src/aws_ssm_client.dart +5 -4
- package/dart-src/plugins/aws/lib/src/aws_storage.dart +2 -3
- package/dart-src/plugins/aws/lib/src/aws_storage_profile.dart +10 -16
- package/dart-src/plugins/aws/lib/src/with_cloudfront_signed_url.dart +6 -9
- package/dart-src/plugins/aws/pubspec.yaml +15 -10
- package/dart-src/plugins/aws/test/aws_database_test.dart +51 -57
- package/dart-src/plugins/aws/test/mock_aws_s3_client.dart +8 -13
- package/dart-src/plugins/cloudflare/CHANGELOG.md +15 -0
- package/dart-src/plugins/cloudflare/example/lib/main.dart +62 -0
- package/dart-src/plugins/cloudflare/lib/flutter_ota_kit_cloudflare.dart +4 -2
- package/dart-src/plugins/cloudflare/lib/src/cloudflare_worker_database.dart +3 -3
- package/dart-src/plugins/cloudflare/lib/src/d1_build_where.dart +3 -2
- package/dart-src/plugins/cloudflare/lib/src/d1_bundle_mapper.dart +24 -27
- package/dart-src/plugins/cloudflare/lib/src/d1_database_plugin.dart +22 -30
- package/dart-src/plugins/cloudflare/lib/src/r2_config.dart +1 -1
- package/dart-src/plugins/cloudflare/lib/src/r2_s3_client.dart +21 -29
- package/dart-src/plugins/cloudflare/lib/src/r2_storage.dart +7 -7
- package/dart-src/plugins/cloudflare/lib/src/r2_storage_profile.dart +7 -15
- package/dart-src/plugins/cloudflare/pubspec.yaml +14 -9
- package/dart-src/plugins/cloudflare/test/cloudflare_worker_database_test.dart +46 -42
- package/dart-src/plugins/cloudflare/test/d1_database_test.dart +100 -90
- package/dart-src/plugins/cloudflare/test/mock_d1_client.dart +23 -18
- package/dart-src/plugins/cloudflare/test/mock_r2_client.dart +8 -13
- package/dart-src/plugins/cloudflare/test/r2_storage_test.dart +1 -4
- package/dart-src/plugins/plugin-core/CHANGELOG.md +15 -1
- package/dart-src/plugins/plugin-core/example/lib/main.dart +61 -0
- package/dart-src/plugins/plugin-core/lib/flutter_ota_kit_plugin_core.dart +3 -7
- package/dart-src/plugins/plugin-core/lib/src/asset_storage_layout.dart +5 -5
- package/dart-src/plugins/plugin-core/lib/src/bundle_helpers.dart +23 -0
- package/dart-src/plugins/plugin-core/lib/src/bundle_storage_layout.dart +16 -10
- package/dart-src/plugins/plugin-core/lib/src/bundle_unit_of_work.dart +31 -26
- package/dart-src/plugins/plugin-core/lib/src/calculate_pagination.dart +5 -1
- package/dart-src/plugins/plugin-core/lib/src/content_addressed_assets.dart +1 -1
- package/dart-src/plugins/plugin-core/lib/src/create_blob_database_plugin.dart +78 -71
- package/dart-src/plugins/plugin-core/lib/src/create_database_plugin.dart +56 -35
- package/dart-src/plugins/plugin-core/lib/src/create_storage_plugin.dart +10 -13
- package/dart-src/plugins/plugin-core/lib/src/paginate_bundles.dart +30 -17
- package/dart-src/plugins/plugin-core/lib/src/parse_storage_uri.dart +3 -1
- package/dart-src/plugins/plugin-core/lib/src/query_bundles.dart +5 -3
- package/dart-src/plugins/plugin-core/lib/src/request_update_bundle_state.dart +2 -4
- package/dart-src/plugins/plugin-core/lib/src/storage_helpers.dart +18 -0
- package/dart-src/plugins/plugin-core/lib/src/types.dart +7 -6
- package/dart-src/plugins/plugin-core/pubspec.yaml +12 -9
- package/dart-src/plugins/plugin-core/test/asset_storage_layout_test.dart +13 -9
- package/dart-src/plugins/plugin-core/test/bundle_unit_of_work_test.dart +28 -15
- package/dart-src/plugins/plugin-core/test/create_blob_database_plugin_test.dart +254 -122
- package/dart-src/plugins/plugin-core/test/create_database_plugin_test.dart +36 -32
- package/dart-src/plugins/plugin-core/test/create_storage_plugin_test.dart +18 -15
- package/dart-src/plugins/plugin-core/test/generate_min_bundle_id_test.dart +8 -3
- package/dart-src/plugins/plugin-core/test/get_update_info_test.dart +682 -693
- package/dart-src/plugins/plugin-core/test/helpers_test.dart +45 -21
- package/dart-src/plugins/plugin-core/test/query_bundles_test.dart +76 -13
- package/dart-src/plugins/plugin-core/test/uuidv7_test.dart +20 -9
- package/dart-src/plugins/pocketbase/CHANGELOG.md +8 -0
- package/dart-src/plugins/pocketbase/LICENSE +21 -0
- package/dart-src/plugins/pocketbase/README.md +54 -0
- package/dart-src/plugins/pocketbase/example/lib/main.dart +62 -0
- package/dart-src/plugins/pocketbase/lib/flutter_ota_kit_pocketbase.dart +28 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_bundle_mapper.dart +121 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_client.dart +349 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_config.dart +61 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_database.dart +278 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_storage.dart +255 -0
- package/dart-src/plugins/pocketbase/pubspec.yaml +26 -0
- package/dart-src/plugins/pocketbase/test/pb_uri_test.dart +12 -0
- package/dart-src/plugins/postgres/CHANGELOG.md +16 -0
- package/dart-src/plugins/postgres/example/lib/main.dart +67 -0
- package/dart-src/plugins/postgres/lib/flutter_ota_kit_postgres.dart +3 -6
- package/dart-src/plugins/postgres/lib/src/postgres_bundle_mapper.dart +32 -52
- package/dart-src/plugins/postgres/lib/src/postgres_config.dart +3 -1
- package/dart-src/plugins/postgres/lib/src/postgres_database.dart +28 -38
- package/dart-src/plugins/postgres/lib/src/postgres_get_update_info.dart +16 -14
- package/dart-src/plugins/postgres/lib/src/postgres_storage.dart +26 -14
- package/dart-src/plugins/postgres/lib/src/postgres_types.dart +27 -28
- package/dart-src/plugins/postgres/pubspec.yaml +14 -9
- package/dart-src/plugins/postgres/test/mock_postgres_client.dart +62 -39
- package/dart-src/plugins/postgres/test/postgres_bundle_mapper_test.dart +3 -4
- package/dart-src/plugins/postgres/test/postgres_database_test.dart +102 -73
- package/dart-src/plugins/postgres/test/postgres_storage_runtime_test.dart +60 -0
- package/dart-src/plugins/supabase/CHANGELOG.md +20 -0
- package/dart-src/plugins/supabase/README.md +2 -2
- package/dart-src/plugins/supabase/example/lib/main.dart +63 -0
- package/dart-src/plugins/supabase/lib/flutter_ota_kit_supabase.dart +2 -0
- package/dart-src/plugins/supabase/lib/src/error_message.dart +11 -0
- package/dart-src/plugins/supabase/lib/src/supabase_bundle_mapper.dart +34 -58
- package/dart-src/plugins/supabase/lib/src/supabase_client_adapter.dart +3 -13
- package/dart-src/plugins/supabase/lib/src/supabase_client_http.dart +34 -52
- package/dart-src/plugins/supabase/lib/src/supabase_database.dart +38 -30
- package/dart-src/plugins/supabase/lib/src/supabase_edge_function_storage.dart +21 -29
- package/dart-src/plugins/supabase/lib/src/supabase_signed_url_batcher.dart +7 -19
- package/dart-src/plugins/supabase/lib/src/supabase_storage.dart +18 -29
- package/dart-src/plugins/supabase/lib/src/types.dart +26 -26
- package/dart-src/plugins/supabase/pubspec.yaml +14 -9
- package/dart-src/plugins/supabase/test/mock_supabase_client.dart +57 -57
- package/dart-src/plugins/supabase/test/supabase_bundle_mapper_test.dart +30 -27
- package/dart-src/plugins/supabase/test/supabase_database_test.dart +26 -35
- package/dart-src/plugins/supabase/test/supabase_storage_test.dart +27 -34
- package/package.json +3 -3
- package/scripts/vendor.sh +1 -1
|
@@ -33,7 +33,8 @@ import 'postgres_types.dart';
|
|
|
33
33
|
DatabasePlugin Function() Function(
|
|
34
34
|
PostgresConfig config, [
|
|
35
35
|
DatabasePluginHooks? hooks,
|
|
36
|
-
])
|
|
36
|
+
])
|
|
37
|
+
postgresDatabase = createDatabasePlugin<PostgresConfig>(
|
|
37
38
|
name: 'postgresDatabase',
|
|
38
39
|
factory: (config) {
|
|
39
40
|
final client = config.clientFactory != null
|
|
@@ -95,18 +96,10 @@ DatabasePlugin Function() Function(
|
|
|
95
96
|
add('enabled = ?', where.enabled);
|
|
96
97
|
}
|
|
97
98
|
if (where.fingerprintHash != null) {
|
|
98
|
-
|
|
99
|
-
conditions.add('fingerprint_hash IS NULL');
|
|
100
|
-
} else {
|
|
101
|
-
add('fingerprint_hash = ?', where.fingerprintHash);
|
|
102
|
-
}
|
|
99
|
+
add('fingerprint_hash = ?', where.fingerprintHash);
|
|
103
100
|
}
|
|
104
101
|
if (where.targetAppVersion != null) {
|
|
105
|
-
|
|
106
|
-
conditions.add('target_app_version IS NULL');
|
|
107
|
-
} else {
|
|
108
|
-
add('target_app_version = ?', where.targetAppVersion);
|
|
109
|
-
}
|
|
102
|
+
add('target_app_version = ?', where.targetAppVersion);
|
|
110
103
|
}
|
|
111
104
|
if (where.targetAppVersionIn != null) {
|
|
112
105
|
add('target_app_version = ANY(?)', where.targetAppVersionIn);
|
|
@@ -134,12 +127,10 @@ class _PostgresDatabasePlugin implements AbstractDatabasePlugin {
|
|
|
134
127
|
final PostgresClientLike client;
|
|
135
128
|
final Future<Map<String, List<PostgresBundlePatchRow>>> Function(
|
|
136
129
|
List<String> bundleIds,
|
|
137
|
-
)
|
|
130
|
+
)
|
|
131
|
+
fetchPatchMap;
|
|
138
132
|
|
|
139
|
-
_PostgresDatabasePlugin({
|
|
140
|
-
required this.client,
|
|
141
|
-
required this.fetchPatchMap,
|
|
142
|
-
});
|
|
133
|
+
_PostgresDatabasePlugin({required this.client, required this.fetchPatchMap});
|
|
143
134
|
|
|
144
135
|
@override
|
|
145
136
|
bool get supportsCursorPagination => false;
|
|
@@ -151,17 +142,16 @@ class _PostgresDatabasePlugin implements AbstractDatabasePlugin {
|
|
|
151
142
|
@override
|
|
152
143
|
Future<Bundle?> getBundleById(String bundleId) async {
|
|
153
144
|
final results = await Future.wait([
|
|
154
|
-
client.execute(
|
|
155
|
-
'SELECT * FROM bundles WHERE id = @p0',
|
|
156
|
-
{'p0': bundleId},
|
|
157
|
-
),
|
|
145
|
+
client.execute('SELECT * FROM bundles WHERE id = @p0', {'p0': bundleId}),
|
|
158
146
|
fetchPatchMap([bundleId]),
|
|
159
147
|
]);
|
|
160
148
|
|
|
161
149
|
final data = results[0] as List<Map<String, dynamic>>;
|
|
162
150
|
if (data.isEmpty) return null;
|
|
163
151
|
final row = PostgresBundleRow.fromJson(data.first);
|
|
164
|
-
final patches =
|
|
152
|
+
final patches =
|
|
153
|
+
(results[1] as Map<String, List<PostgresBundlePatchRow>>)[bundleId] ??
|
|
154
|
+
[];
|
|
165
155
|
return mapRowToBundle(row, patches);
|
|
166
156
|
}
|
|
167
157
|
|
|
@@ -174,9 +164,11 @@ class _PostgresDatabasePlugin implements AbstractDatabasePlugin {
|
|
|
174
164
|
final orderBy =
|
|
175
165
|
options.orderBy ?? const DatabaseBundleQueryOrder(direction: 'desc');
|
|
176
166
|
final offset =
|
|
177
|
-
options.offset ??
|
|
167
|
+
options.offset ??
|
|
168
|
+
(options.page != null ? (options.page! - 1) * limit : 0);
|
|
178
169
|
|
|
179
|
-
if ((where?.targetAppVersionIn != null &&
|
|
170
|
+
if ((where?.targetAppVersionIn != null &&
|
|
171
|
+
where!.targetAppVersionIn!.isEmpty) ||
|
|
180
172
|
(where?.id?.ins != null && where!.id!.ins!.isEmpty)) {
|
|
181
173
|
return Paginated(
|
|
182
174
|
data: const [],
|
|
@@ -230,18 +222,15 @@ class _PostgresDatabasePlugin implements AbstractDatabasePlugin {
|
|
|
230
222
|
}
|
|
231
223
|
|
|
232
224
|
@override
|
|
233
|
-
Future<void> commitBundle({
|
|
234
|
-
required List<BundleChange> changedSets,
|
|
235
|
-
}) async {
|
|
225
|
+
Future<void> commitBundle({required List<BundleChange> changedSets}) async {
|
|
236
226
|
if (changedSets.isEmpty) return;
|
|
237
227
|
|
|
238
228
|
await client.runTx((tx) async {
|
|
239
229
|
for (final op in changedSets) {
|
|
240
230
|
if (op.operation == BundleChangeOperation.delete) {
|
|
241
|
-
await tx.execute(
|
|
242
|
-
'
|
|
243
|
-
|
|
244
|
-
);
|
|
231
|
+
await tx.execute('DELETE FROM bundle_patches WHERE bundle_id = @p0', {
|
|
232
|
+
'p0': op.data.id,
|
|
233
|
+
});
|
|
245
234
|
await tx.execute(
|
|
246
235
|
'DELETE FROM bundle_patches WHERE base_bundle_id = @p0',
|
|
247
236
|
{'p0': op.data.id},
|
|
@@ -258,8 +247,9 @@ class _PostgresDatabasePlugin implements AbstractDatabasePlugin {
|
|
|
258
247
|
final values = bundleToRowValues(bundle);
|
|
259
248
|
final columns = values.keys.toList();
|
|
260
249
|
final insertCols = columns.join(', ');
|
|
261
|
-
final placeholders =
|
|
262
|
-
|
|
250
|
+
final placeholders = columns
|
|
251
|
+
.map((c) => '@${c.replaceAll('.', '_')}')
|
|
252
|
+
.join(', ');
|
|
263
253
|
final updateSets = columns
|
|
264
254
|
.where((c) => c != 'id')
|
|
265
255
|
.map((c) => '$c = EXCLUDED.$c')
|
|
@@ -270,17 +260,17 @@ class _PostgresDatabasePlugin implements AbstractDatabasePlugin {
|
|
|
270
260
|
{for (final c in columns) c.replaceAll('.', '_'): values[c]},
|
|
271
261
|
);
|
|
272
262
|
|
|
273
|
-
await tx.execute(
|
|
274
|
-
'
|
|
275
|
-
|
|
276
|
-
);
|
|
263
|
+
await tx.execute('DELETE FROM bundle_patches WHERE bundle_id = @p0', {
|
|
264
|
+
'p0': bundle.id,
|
|
265
|
+
});
|
|
277
266
|
final patchRows = bundleToPatchRows(bundle);
|
|
278
267
|
if (patchRows.isNotEmpty) {
|
|
279
268
|
for (final pr in patchRows) {
|
|
280
269
|
final patchCols = pr.keys.toList();
|
|
281
270
|
final patchInsert = patchCols.join(', ');
|
|
282
|
-
final patchPlaceholders =
|
|
283
|
-
|
|
271
|
+
final patchPlaceholders = patchCols
|
|
272
|
+
.map((c) => '@${c.replaceAll('.', '_')}')
|
|
273
|
+
.join(', ');
|
|
284
274
|
await tx.execute(
|
|
285
275
|
'INSERT INTO bundle_patches ($patchInsert) '
|
|
286
276
|
'VALUES ($patchPlaceholders) '
|
|
@@ -31,13 +31,13 @@ class _UpdateInfoRow {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
factory _UpdateInfoRow.fromJson(Map<String, dynamic> row) => _UpdateInfoRow(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
id: row['id'] as String,
|
|
35
|
+
shouldForceUpdate: row['should_force_update'] as bool,
|
|
36
|
+
message: row['message'] as String?,
|
|
37
|
+
status: row['status'] as String,
|
|
38
|
+
storageUri: row['storage_uri'] as String?,
|
|
39
|
+
fileHash: row['file_hash'] as String?,
|
|
40
|
+
);
|
|
41
41
|
|
|
42
42
|
final String id;
|
|
43
43
|
final bool shouldForceUpdate;
|
|
@@ -48,13 +48,15 @@ class _UpdateInfoRow {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
UpdateInfo mapUpdateInfoRow(_UpdateInfoRow row) => UpdateInfo(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
id: row.id,
|
|
52
|
+
shouldForceUpdate: row.shouldForceUpdate,
|
|
53
|
+
message: row.message,
|
|
54
|
+
status: row.status == 'ROLLBACK'
|
|
55
|
+
? UpdateStatus.rollback
|
|
56
|
+
: UpdateStatus.update,
|
|
57
|
+
storageUri: row.storageUri,
|
|
58
|
+
fileHash: row.fileHash,
|
|
59
|
+
);
|
|
58
60
|
|
|
59
61
|
/// Resolve update info via the Postgres RPCs.
|
|
60
62
|
Future<UpdateInfo?> getUpdateInfo(
|
|
@@ -29,7 +29,8 @@ class PostgresStorageConfig {
|
|
|
29
29
|
|
|
30
30
|
/// Resolves the storage client for a config (test seam via [PostgresConfig.clientFactory]).
|
|
31
31
|
PostgresClientLike resolvePostgresStorageClient(PostgresStorageConfig config) =>
|
|
32
|
-
config.db.clientFactory?.call(config.db) ??
|
|
32
|
+
config.db.clientFactory?.call(config.db) ??
|
|
33
|
+
PostgresClient.connect(config.db);
|
|
33
34
|
|
|
34
35
|
String _storageUri(String key, String? servingBaseUrl) {
|
|
35
36
|
if (servingBaseUrl != null && servingBaseUrl.isNotEmpty) {
|
|
@@ -52,8 +53,9 @@ String _strip(String storageUri, String? servingBaseUrl) {
|
|
|
52
53
|
return storageUri.substring('postgres://'.length);
|
|
53
54
|
}
|
|
54
55
|
if (servingBaseUrl != null && storageUri.startsWith(servingBaseUrl)) {
|
|
55
|
-
final base =
|
|
56
|
-
|
|
56
|
+
final base = servingBaseUrl.endsWith('/')
|
|
57
|
+
? servingBaseUrl
|
|
58
|
+
: '$servingBaseUrl/';
|
|
57
59
|
return storageUri.startsWith(base)
|
|
58
60
|
? storageUri.substring(base.length)
|
|
59
61
|
: storageUri;
|
|
@@ -71,8 +73,7 @@ NodeStorageProfile createPostgresNodeProfile(
|
|
|
71
73
|
PostgresClientLike client,
|
|
72
74
|
String? basePath,
|
|
73
75
|
String? servingBaseUrl,
|
|
74
|
-
) =>
|
|
75
|
-
_PostgresNodeProfile(client, basePath, servingBaseUrl);
|
|
76
|
+
) => _PostgresNodeProfile(client, basePath, servingBaseUrl);
|
|
76
77
|
|
|
77
78
|
class _PostgresNodeProfile implements NodeStorageProfile {
|
|
78
79
|
_PostgresNodeProfile(this._client, this._basePath, this._servingBaseUrl);
|
|
@@ -92,11 +93,7 @@ class _PostgresNodeProfile implements NodeStorageProfile {
|
|
|
92
93
|
'INSERT INTO flutter_ota_kit_storage (key, data, content_type) '
|
|
93
94
|
'VALUES (@key, @data, @ct) '
|
|
94
95
|
'ON CONFLICT (key) DO UPDATE SET data = EXCLUDED.data, content_type = EXCLUDED.content_type',
|
|
95
|
-
{
|
|
96
|
-
'@key': fullKey,
|
|
97
|
-
'@data': bytes,
|
|
98
|
-
'@ct': _contentType(fullKey),
|
|
99
|
-
},
|
|
96
|
+
{'@key': fullKey, '@data': bytes, '@ct': _contentType(fullKey)},
|
|
100
97
|
);
|
|
101
98
|
return {'storageUri': _storageUri(fullKey, _servingBaseUrl)};
|
|
102
99
|
}
|
|
@@ -164,8 +161,7 @@ class _PostgresNodeProfile implements NodeStorageProfile {
|
|
|
164
161
|
RuntimeStorageProfile createPostgresRuntimeProfile(
|
|
165
162
|
PostgresClientLike client,
|
|
166
163
|
String? servingBaseUrl,
|
|
167
|
-
) =>
|
|
168
|
-
_PostgresRuntimeProfile(client, servingBaseUrl);
|
|
164
|
+
) => _PostgresRuntimeProfile(client, servingBaseUrl);
|
|
169
165
|
|
|
170
166
|
class _PostgresRuntimeProfile implements RuntimeStorageProfile {
|
|
171
167
|
_PostgresRuntimeProfile(this._client, this._servingBaseUrl);
|
|
@@ -175,7 +171,19 @@ class _PostgresRuntimeProfile implements RuntimeStorageProfile {
|
|
|
175
171
|
|
|
176
172
|
@override
|
|
177
173
|
Future<Map<String, String>> getDownloadUrl(String storageUri) async {
|
|
178
|
-
|
|
174
|
+
if (_servingBaseUrl == null || _servingBaseUrl.isEmpty) {
|
|
175
|
+
throw StateError(
|
|
176
|
+
'Postgres storage requires a servingBaseUrl to expose bytes over HTTP. '
|
|
177
|
+
'Set `postgres.servingBaseUrl` in your config to a thin proxy that reads '
|
|
178
|
+
'from the `flutter_ota_kit_storage` table.',
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
'fileUrl': _storageUri(
|
|
183
|
+
_strip(storageUri, _servingBaseUrl),
|
|
184
|
+
_servingBaseUrl,
|
|
185
|
+
),
|
|
186
|
+
};
|
|
179
187
|
}
|
|
180
188
|
|
|
181
189
|
@override
|
|
@@ -198,7 +206,11 @@ StoragePlugin Function(PostgresStorageConfig) postgresStorage =
|
|
|
198
206
|
factory: (cfg) {
|
|
199
207
|
final client = resolvePostgresStorageClient(cfg);
|
|
200
208
|
return (
|
|
201
|
-
node: createPostgresNodeProfile(
|
|
209
|
+
node: createPostgresNodeProfile(
|
|
210
|
+
client,
|
|
211
|
+
cfg.basePath,
|
|
212
|
+
cfg.servingBaseUrl,
|
|
213
|
+
),
|
|
202
214
|
runtime: createPostgresRuntimeProfile(client, cfg.servingBaseUrl),
|
|
203
215
|
);
|
|
204
216
|
},
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import 'package:flutter_ota_kit_core/flutter_ota_kit_core.dart'
|
|
2
|
-
show Platform;
|
|
1
|
+
import 'package:flutter_ota_kit_core/flutter_ota_kit_core.dart' show Platform;
|
|
3
2
|
|
|
4
3
|
/// Database row for the `bundles` table (snake_case columns).
|
|
5
4
|
///
|
|
@@ -66,24 +65,24 @@ class PostgresBundleRow {
|
|
|
66
65
|
final List<String>? targetCohorts;
|
|
67
66
|
|
|
68
67
|
Map<String, dynamic> toJson() => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
68
|
+
'id': id,
|
|
69
|
+
'channel': channel,
|
|
70
|
+
'enabled': enabled,
|
|
71
|
+
'should_force_update': shouldForceUpdate,
|
|
72
|
+
'file_hash': fileHash,
|
|
73
|
+
'git_commit_hash': gitCommitHash,
|
|
74
|
+
'message': message,
|
|
75
|
+
'platform': platform.name,
|
|
76
|
+
'target_app_version': targetAppVersion,
|
|
77
|
+
'storage_uri': storageUri,
|
|
78
|
+
'fingerprint_hash': fingerprintHash,
|
|
79
|
+
'metadata': metadata ?? const {},
|
|
80
|
+
'manifest_storage_uri': manifestStorageUri,
|
|
81
|
+
'manifest_file_hash': manifestFileHash,
|
|
82
|
+
'asset_base_storage_uri': assetBaseStorageUri,
|
|
83
|
+
'rollout_cohort_count': rolloutCohortCount,
|
|
84
|
+
'target_cohorts': targetCohorts,
|
|
85
|
+
};
|
|
87
86
|
}
|
|
88
87
|
|
|
89
88
|
/// Database row for the `bundle_patches` table (snake_case columns).
|
|
@@ -121,12 +120,12 @@ class PostgresBundlePatchRow {
|
|
|
121
120
|
final int orderIndex;
|
|
122
121
|
|
|
123
122
|
Map<String, dynamic> toJson() => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
'id': id,
|
|
124
|
+
'bundle_id': bundleId,
|
|
125
|
+
'base_bundle_id': baseBundleId,
|
|
126
|
+
'base_file_hash': baseFileHash,
|
|
127
|
+
'patch_file_hash': patchFileHash,
|
|
128
|
+
'patch_storage_uri': patchStorageUri,
|
|
129
|
+
'order_index': orderIndex,
|
|
130
|
+
};
|
|
132
131
|
}
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
name: flutter_ota_kit_postgres
|
|
2
2
|
description: Postgres plugin for flutter_ota_kit — database backend.
|
|
3
|
-
version: 0.1.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
documentation: https://github.com/HYPER12755/flutter_ota_kit#readme
|
|
3
|
+
version: 0.1.3
|
|
4
|
+
homepage: https://github.com/HYPER12755/flutter-ota-kit
|
|
5
|
+
repository: https://github.com/HYPER12755/flutter-ota-kit
|
|
6
|
+
issue_tracker: https://github.com/HYPER12755/flutter-ota-kit/issues
|
|
7
|
+
documentation: https://github.com/HYPER12755/flutter-ota-kit#readme
|
|
9
8
|
license: MIT
|
|
10
9
|
|
|
11
10
|
environment:
|
|
12
|
-
sdk: ">=3.
|
|
11
|
+
sdk: ">=3.13.2 <4.0.0"
|
|
13
12
|
|
|
14
13
|
dependencies:
|
|
15
|
-
flutter_ota_kit_core: ^0.1.
|
|
16
|
-
flutter_ota_kit_plugin_core: ^0.0.
|
|
14
|
+
flutter_ota_kit_core: ^0.1.2
|
|
15
|
+
flutter_ota_kit_plugin_core: ^0.0.4
|
|
17
16
|
postgres: ^3.4.0
|
|
18
17
|
|
|
19
18
|
dev_dependencies:
|
|
20
19
|
test: ^1.25.0
|
|
21
20
|
lints: ^4.0.0
|
|
21
|
+
|
|
22
|
+
dependency_overrides:
|
|
23
|
+
flutter_ota_kit_core:
|
|
24
|
+
path: ../../packages/core
|
|
25
|
+
flutter_ota_kit_plugin_core:
|
|
26
|
+
path: ../plugin-core
|
|
@@ -51,10 +51,7 @@ class MockPostgresClient implements PostgresClientLike {
|
|
|
51
51
|
@override
|
|
52
52
|
Future<void> close() async {}
|
|
53
53
|
|
|
54
|
-
List<Map<String, dynamic>> _handle(
|
|
55
|
-
String sql,
|
|
56
|
-
Map<String, dynamic> params,
|
|
57
|
-
) {
|
|
54
|
+
List<Map<String, dynamic>> _handle(String sql, Map<String, dynamic> params) {
|
|
58
55
|
if (sql.contains('get_target_app_version_list')) {
|
|
59
56
|
return _targetAppVersionList(params);
|
|
60
57
|
}
|
|
@@ -126,7 +123,8 @@ class MockPostgresClient implements PostgresClientLike {
|
|
|
126
123
|
var rows = _filterBundles(sql, params);
|
|
127
124
|
|
|
128
125
|
if (sql.contains('ORDER BY id asc')) {
|
|
129
|
-
rows = rows.toList()
|
|
126
|
+
rows = rows.toList()
|
|
127
|
+
..sort((a, b) => (a['id'] as String).compareTo(b['id'] as String));
|
|
130
128
|
} else {
|
|
131
129
|
rows = rows.toList()
|
|
132
130
|
..sort((a, b) => (b['id'] as String).compareTo(a['id'] as String));
|
|
@@ -150,13 +148,18 @@ class MockPostgresClient implements PostgresClientLike {
|
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
List<Map<String, dynamic>> _channels() {
|
|
153
|
-
final channels = store.bundleRows
|
|
151
|
+
final channels = store.bundleRows
|
|
152
|
+
.map((r) => r['channel'] as String)
|
|
153
|
+
.toSet()
|
|
154
|
+
.toList();
|
|
154
155
|
return channels.map((c) => {'channel': c}).toList();
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
List<Map<String, dynamic>> _patchesForIds(Map<String, dynamic> params) {
|
|
158
159
|
final ids = (params['bundle_ids'] as List).cast<String>();
|
|
159
|
-
return store.bundlePatchRows
|
|
160
|
+
return store.bundlePatchRows
|
|
161
|
+
.where((p) => ids.contains(p['bundle_id']))
|
|
162
|
+
.toList();
|
|
160
163
|
}
|
|
161
164
|
|
|
162
165
|
void _upsertBundle(Map<String, dynamic> params) {
|
|
@@ -173,7 +176,9 @@ class MockPostgresClient implements PostgresClientLike {
|
|
|
173
176
|
void _upsertPatch(Map<String, dynamic> params) {
|
|
174
177
|
final row = <String, dynamic>{};
|
|
175
178
|
params.forEach((k, v) => row[k] = v);
|
|
176
|
-
final existing = store.bundlePatchRows.indexWhere(
|
|
179
|
+
final existing = store.bundlePatchRows.indexWhere(
|
|
180
|
+
(r) => r['id'] == row['id'],
|
|
181
|
+
);
|
|
177
182
|
if (existing >= 0) {
|
|
178
183
|
store.bundlePatchRows[existing] = row;
|
|
179
184
|
} else {
|
|
@@ -198,14 +203,24 @@ class MockPostgresClient implements PostgresClientLike {
|
|
|
198
203
|
final existed = store.bundleRows.any((r) => r['id'] == id);
|
|
199
204
|
store.bundleRows.removeWhere((r) => r['id'] == id);
|
|
200
205
|
store.bundlePatchRows.removeWhere((p) => p['bundle_id'] == id);
|
|
201
|
-
return existed
|
|
206
|
+
return existed
|
|
207
|
+
? [
|
|
208
|
+
{'id': id},
|
|
209
|
+
]
|
|
210
|
+
: [];
|
|
202
211
|
}
|
|
203
212
|
|
|
204
|
-
List<Map<String, dynamic>> _targetAppVersionList(
|
|
213
|
+
List<Map<String, dynamic>> _targetAppVersionList(
|
|
214
|
+
Map<String, dynamic> params,
|
|
215
|
+
) {
|
|
205
216
|
final platform = params['app_platform'];
|
|
206
217
|
final min = params['min_bundle_id'] as String? ?? '';
|
|
207
218
|
final versions = store.bundleRows
|
|
208
|
-
.where(
|
|
219
|
+
.where(
|
|
220
|
+
(r) =>
|
|
221
|
+
r['platform'] == platform &&
|
|
222
|
+
(r['id'] as String).compareTo(min) >= 0,
|
|
223
|
+
)
|
|
209
224
|
.map((r) => r['target_app_version'])
|
|
210
225
|
.where((v) => v != null)
|
|
211
226
|
.toSet()
|
|
@@ -222,44 +237,53 @@ class MockPostgresClient implements PostgresClientLike {
|
|
|
222
237
|
return matches.isEmpty ? null : matches.first;
|
|
223
238
|
}
|
|
224
239
|
|
|
225
|
-
List<Map<String, dynamic>> _updateInfoByAppVersion(
|
|
240
|
+
List<Map<String, dynamic>> _updateInfoByAppVersion(
|
|
241
|
+
Map<String, dynamic> params,
|
|
242
|
+
) {
|
|
226
243
|
final platform = params['app_platform'];
|
|
227
244
|
final channel = params['target_channel'];
|
|
228
245
|
final min = params['min_bundle_id'] as String? ?? '';
|
|
229
|
-
final list =
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
246
|
+
final list =
|
|
247
|
+
(params['target_app_version_list'] as List?)?.cast<String>() ?? [];
|
|
248
|
+
final row = _newestMatch(
|
|
249
|
+
(r) =>
|
|
250
|
+
r['platform'] == platform &&
|
|
251
|
+
r['enabled'] == true &&
|
|
252
|
+
r['channel'] == channel &&
|
|
253
|
+
(r['id'] as String).compareTo(min) >= 0 &&
|
|
254
|
+
list.contains(r['target_app_version']),
|
|
255
|
+
);
|
|
236
256
|
if (row == null) return [];
|
|
237
257
|
return [_infoRow(row)];
|
|
238
258
|
}
|
|
239
259
|
|
|
240
|
-
List<Map<String, dynamic>> _updateInfoByFingerprint(
|
|
260
|
+
List<Map<String, dynamic>> _updateInfoByFingerprint(
|
|
261
|
+
Map<String, dynamic> params,
|
|
262
|
+
) {
|
|
241
263
|
final platform = params['app_platform'];
|
|
242
264
|
final channel = params['target_channel'];
|
|
243
265
|
final min = params['min_bundle_id'] as String? ?? '';
|
|
244
266
|
final fp = params['target_fingerprint_hash'];
|
|
245
|
-
final row = _newestMatch(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
267
|
+
final row = _newestMatch(
|
|
268
|
+
(r) =>
|
|
269
|
+
r['platform'] == platform &&
|
|
270
|
+
r['enabled'] == true &&
|
|
271
|
+
r['channel'] == channel &&
|
|
272
|
+
(r['id'] as String).compareTo(min) >= 0 &&
|
|
273
|
+
r['fingerprint_hash'] == fp,
|
|
274
|
+
);
|
|
251
275
|
if (row == null) return [];
|
|
252
276
|
return [_infoRow(row)];
|
|
253
277
|
}
|
|
254
278
|
|
|
255
279
|
Map<String, dynamic> _infoRow(Map<String, dynamic> row) => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
280
|
+
'id': row['id'],
|
|
281
|
+
'should_force_update': row['should_force_update'],
|
|
282
|
+
'message': row['message'],
|
|
283
|
+
'status': 'UPDATE',
|
|
284
|
+
'storage_uri': row['storage_uri'],
|
|
285
|
+
'file_hash': row['file_hash'],
|
|
286
|
+
};
|
|
263
287
|
}
|
|
264
288
|
|
|
265
289
|
class _TxClient implements PostgresClientLike {
|
|
@@ -271,8 +295,7 @@ class _TxClient implements PostgresClientLike {
|
|
|
271
295
|
Future<List<Map<String, dynamic>>> execute(
|
|
272
296
|
String sql,
|
|
273
297
|
Map<String, dynamic> parameters,
|
|
274
|
-
) =>
|
|
275
|
-
_parent.execute(sql, parameters);
|
|
298
|
+
) => _parent.execute(sql, parameters);
|
|
276
299
|
|
|
277
300
|
@override
|
|
278
301
|
Future<T> runTx<T>(Future<T> Function(PostgresClientLike tx) fn) =>
|
|
@@ -284,10 +307,10 @@ class _TxClient implements PostgresClientLike {
|
|
|
284
307
|
|
|
285
308
|
/// Build a [PostgresConfig] wired to [MockPostgresClient].
|
|
286
309
|
PostgresConfig mockPostgresConfig(Store store) => PostgresConfig(
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
310
|
+
host: 'mock',
|
|
311
|
+
database: 'mock',
|
|
312
|
+
clientFactory: (_) => MockPostgresClient(store),
|
|
313
|
+
);
|
|
291
314
|
|
|
292
315
|
/// Create a [DatabasePlugin] backed by the mock store.
|
|
293
316
|
DatabasePlugin newPlugin({Store? store}) {
|
|
@@ -84,10 +84,9 @@ void main() {
|
|
|
84
84
|
|
|
85
85
|
final row = bundleToRowValues(bundle);
|
|
86
86
|
final patchRows = bundleToPatchRows(bundle);
|
|
87
|
-
final back = mapRowToBundle(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
87
|
+
final back = mapRowToBundle(PostgresBundleRow.fromJson(row), [
|
|
88
|
+
PostgresBundlePatchRow.fromJson(patchRows.first),
|
|
89
|
+
]);
|
|
91
90
|
|
|
92
91
|
expect(back.id, bundle.id);
|
|
93
92
|
expect(back.fileHash, 'hash-1');
|