@_nazmiforreal/flutter-ota 0.1.11 → 0.1.13
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 +299 -190
- 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/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 +6 -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 +7 -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 +16 -0
- 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 +6 -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 +17 -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 +2 -2
- package/scripts/vendor.sh +1 -1
|
@@ -46,12 +46,12 @@ class _Comparator {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
String _opStr(_Op o) => switch (o) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
_Op.lt => '<',
|
|
50
|
+
_Op.lte => '<=',
|
|
51
|
+
_Op.gt => '>',
|
|
52
|
+
_Op.gte => '>=',
|
|
53
|
+
_Op.eq => '=',
|
|
54
|
+
};
|
|
55
55
|
|
|
56
56
|
final RegExp _xRe = RegExp(r'^[xX*]$');
|
|
57
57
|
|
|
@@ -131,8 +131,7 @@ List<_Comparator> _parseToken(String raw) {
|
|
|
131
131
|
_Comparator(_Op.lt, ver(majS, '${int.parse(minS) + 1}', '0')),
|
|
132
132
|
];
|
|
133
133
|
}
|
|
134
|
-
final pre =
|
|
135
|
-
hasPre ? preRaw.split('.') : const <String>[];
|
|
134
|
+
final pre = hasPre ? preRaw.split('.') : const <String>[];
|
|
136
135
|
return [_Comparator(_Op.eq, ver(majS, minS!, patS!, pre))];
|
|
137
136
|
|
|
138
137
|
case '>':
|
|
@@ -141,7 +140,7 @@ List<_Comparator> _parseToken(String raw) {
|
|
|
141
140
|
}
|
|
142
141
|
if (!hasPatch) {
|
|
143
142
|
return [
|
|
144
|
-
_Comparator(_Op.gte, ver(majS, '${int.parse(minS!) + 1}', '0'))
|
|
143
|
+
_Comparator(_Op.gte, ver(majS, '${int.parse(minS!) + 1}', '0')),
|
|
145
144
|
];
|
|
146
145
|
}
|
|
147
146
|
return [_Comparator(_Op.gt, ver(majS, minS!, patS!))];
|
|
@@ -154,8 +153,10 @@ List<_Comparator> _parseToken(String raw) {
|
|
|
154
153
|
return [_Comparator(_Op.gte, ver(majS, minS!, '0'))];
|
|
155
154
|
}
|
|
156
155
|
return [
|
|
157
|
-
_Comparator(
|
|
158
|
-
|
|
156
|
+
_Comparator(
|
|
157
|
+
_Op.gte,
|
|
158
|
+
ver(majS, minS!, patS!, hasPre ? preRaw.split('.') : const []),
|
|
159
|
+
),
|
|
159
160
|
];
|
|
160
161
|
|
|
161
162
|
case '<':
|
|
@@ -167,9 +168,9 @@ List<_Comparator> _parseToken(String raw) {
|
|
|
167
168
|
}
|
|
168
169
|
return [
|
|
169
170
|
_Comparator(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
_Op.lt,
|
|
172
|
+
ver(majS, minS!, patS!, hasPre ? preRaw.split('.') : const []),
|
|
173
|
+
),
|
|
173
174
|
];
|
|
174
175
|
|
|
175
176
|
case '<=':
|
|
@@ -178,13 +179,13 @@ List<_Comparator> _parseToken(String raw) {
|
|
|
178
179
|
return [_Comparator(_Op.lt, ver('${int.parse(majS) + 1}', '0', '0'))];
|
|
179
180
|
}
|
|
180
181
|
if (!hasPatch) {
|
|
181
|
-
return [
|
|
182
|
-
_Comparator(_Op.lt, ver(majS, '${int.parse(minS!) + 1}', '0'))
|
|
183
|
-
];
|
|
182
|
+
return [_Comparator(_Op.lt, ver(majS, '${int.parse(minS!) + 1}', '0'))];
|
|
184
183
|
}
|
|
185
184
|
return [
|
|
186
|
-
_Comparator(
|
|
187
|
-
|
|
185
|
+
_Comparator(
|
|
186
|
+
_Op.lte,
|
|
187
|
+
ver(majS, minS!, patS!, hasPre ? preRaw.split('.') : const []),
|
|
188
|
+
),
|
|
188
189
|
];
|
|
189
190
|
|
|
190
191
|
case '~':
|
|
@@ -202,9 +203,9 @@ List<_Comparator> _parseToken(String raw) {
|
|
|
202
203
|
}
|
|
203
204
|
return [
|
|
204
205
|
_Comparator(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
_Op.gte,
|
|
207
|
+
ver(majS, minS!, patS!, hasPre ? preRaw.split('.') : const []),
|
|
208
|
+
),
|
|
208
209
|
_Comparator(_Op.lt, ver(majS, '${int.parse(minS) + 1}', '0')),
|
|
209
210
|
];
|
|
210
211
|
|
|
@@ -234,8 +235,10 @@ List<_Comparator> _parseToken(String raw) {
|
|
|
234
235
|
? SemVer(maj + 1, 0, 0)
|
|
235
236
|
: (min > 0 ? SemVer(0, min + 1, 0) : SemVer(0, 0, pat + 1));
|
|
236
237
|
return [
|
|
237
|
-
_Comparator(
|
|
238
|
-
|
|
238
|
+
_Comparator(
|
|
239
|
+
_Op.gte,
|
|
240
|
+
ver(majS, minS, patS, hasPre ? preRaw.split('.') : const []),
|
|
241
|
+
),
|
|
239
242
|
_Comparator(_Op.lt, upper),
|
|
240
243
|
];
|
|
241
244
|
}
|
|
@@ -263,12 +266,12 @@ List<List<_Comparator>> _parseRange(String range) {
|
|
|
263
266
|
for (var set in sets.map((s) => s.trim()).toList()) {
|
|
264
267
|
if (set.isEmpty) set = '*';
|
|
265
268
|
// Hyphen ranges first.
|
|
266
|
-
final hyphenMatch = RegExp(
|
|
267
|
-
r'^\s*(\S+)\s+-\s+(\S+)\s*$')
|
|
268
|
-
.firstMatch(set);
|
|
269
|
+
final hyphenMatch = RegExp(r'^\s*(\S+)\s+-\s+(\S+)\s*$').firstMatch(set);
|
|
269
270
|
if (hyphenMatch != null) {
|
|
270
|
-
final comps = _hyphenToComparators(
|
|
271
|
-
|
|
271
|
+
final comps = _hyphenToComparators(
|
|
272
|
+
hyphenMatch.group(1)!,
|
|
273
|
+
hyphenMatch.group(2)!,
|
|
274
|
+
);
|
|
272
275
|
result.add(comps);
|
|
273
276
|
continue;
|
|
274
277
|
}
|
|
@@ -299,11 +302,14 @@ List<_Comparator> _hyphenToComparators(String leftRaw, String rightRaw) {
|
|
|
299
302
|
if (_isX(min)) {
|
|
300
303
|
out.add(_Comparator(_Op.gte, SemVer(int.parse(maj), 0, 0)));
|
|
301
304
|
} else if (_isX(pat)) {
|
|
302
|
-
out.add(
|
|
303
|
-
_Comparator(_Op.gte, SemVer(int.parse(maj), int.parse(min!), 0)));
|
|
305
|
+
out.add(_Comparator(_Op.gte, SemVer(int.parse(maj), int.parse(min!), 0)));
|
|
304
306
|
} else {
|
|
305
|
-
out.add(
|
|
306
|
-
|
|
307
|
+
out.add(
|
|
308
|
+
_Comparator(
|
|
309
|
+
_Op.gte,
|
|
310
|
+
SemVer(int.parse(maj), int.parse(min!), int.parse(pat!), pre),
|
|
311
|
+
),
|
|
312
|
+
);
|
|
307
313
|
}
|
|
308
314
|
}
|
|
309
315
|
|
|
@@ -318,11 +324,16 @@ List<_Comparator> _hyphenToComparators(String leftRaw, String rightRaw) {
|
|
|
318
324
|
if (_isX(min)) {
|
|
319
325
|
out.add(_Comparator(_Op.lt, SemVer(int.parse(maj) + 1, 0, 0)));
|
|
320
326
|
} else if (_isX(pat)) {
|
|
321
|
-
out.add(
|
|
322
|
-
|
|
327
|
+
out.add(
|
|
328
|
+
_Comparator(_Op.lt, SemVer(int.parse(maj), int.parse(min!) + 1, 0)),
|
|
329
|
+
);
|
|
323
330
|
} else {
|
|
324
|
-
out.add(
|
|
325
|
-
|
|
331
|
+
out.add(
|
|
332
|
+
_Comparator(
|
|
333
|
+
_Op.lte,
|
|
334
|
+
SemVer(int.parse(maj), int.parse(min!), int.parse(pat!), pre),
|
|
335
|
+
),
|
|
336
|
+
);
|
|
326
337
|
}
|
|
327
338
|
}
|
|
328
339
|
return out;
|
|
@@ -348,8 +359,7 @@ bool satisfies(SemVer version, String range) {
|
|
|
348
359
|
}
|
|
349
360
|
if (!ok) continue;
|
|
350
361
|
if (version.isPrerelease) {
|
|
351
|
-
final allowed =
|
|
352
|
-
set.any((c) => c.allowsPrereleaseOf(version));
|
|
362
|
+
final allowed = set.any((c) => c.allowsPrereleaseOf(version));
|
|
353
363
|
if (!allowed) continue;
|
|
354
364
|
}
|
|
355
365
|
return true;
|
|
@@ -38,17 +38,18 @@ class SemVer implements Comparable<SemVer> {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
factory SemVer.fromJson(Map<String, dynamic> j) => SemVer(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
j['major'] as int,
|
|
42
|
+
j['minor'] as int,
|
|
43
|
+
j['patch'] as int,
|
|
44
|
+
(j['prerelease'] as List?)?.map((e) => '$e').toList() ?? const [],
|
|
45
|
+
j['build'] as String?,
|
|
46
|
+
);
|
|
47
47
|
|
|
48
48
|
bool get isPrerelease => prerelease.isNotEmpty;
|
|
49
49
|
|
|
50
50
|
@override
|
|
51
|
-
String toString() =>
|
|
51
|
+
String toString() =>
|
|
52
|
+
'$major.$minor.$patch'
|
|
52
53
|
'${prerelease.isEmpty ? '' : '-${prerelease.join('.')}'}'
|
|
53
54
|
'${build == null ? '' : '+$build'}';
|
|
54
55
|
|
|
@@ -8,9 +8,10 @@ enum UpdateStatus {
|
|
|
8
8
|
final String value;
|
|
9
9
|
const UpdateStatus(this.value);
|
|
10
10
|
|
|
11
|
-
static UpdateStatus fromValue(String v) => UpdateStatus.values
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
static UpdateStatus fromValue(String v) => UpdateStatus.values.firstWhere(
|
|
12
|
+
(s) => s.value == v,
|
|
13
|
+
orElse: () => throw ArgumentError('unknown status: $v'),
|
|
14
|
+
);
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/// What the client derives: UP_TO_DATE | ROLLBACK | UPDATE.
|
|
@@ -20,11 +20,11 @@ class UpdateBundleParams {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
Map<String, dynamic> toJson() => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
'platform': platform.value,
|
|
24
|
+
'bundleId': bundleId,
|
|
25
|
+
'minBundleId': minBundleId,
|
|
26
|
+
'channel': channel,
|
|
27
|
+
'appVersion': appVersion,
|
|
28
|
+
if (fingerprintHash != null) 'fingerprintHash': fingerprintHash,
|
|
29
|
+
};
|
|
30
30
|
}
|
|
@@ -28,8 +28,7 @@ String uuidV7({DateTime? now}) {
|
|
|
28
28
|
final rand = List.generate(10, (_) => _random.nextInt(256));
|
|
29
29
|
final tsHex = _hex(ts, 12);
|
|
30
30
|
final g3 = '${_hex(rand[0] & 0x0F, 1)}${_hex(rand[1], 2)}';
|
|
31
|
-
final g4 =
|
|
32
|
-
'${_hex((rand[2] & 0x3F) | 0x80, 2)}${_hex(rand[3], 2)}';
|
|
31
|
+
final g4 = '${_hex((rand[2] & 0x3F) | 0x80, 2)}${_hex(rand[3], 2)}';
|
|
33
32
|
final g5 = StringBuffer();
|
|
34
33
|
for (var i = 4; i < 10; i++) {
|
|
35
34
|
g5.write(_hex(rand[i], 2));
|
|
@@ -1,14 +1,13 @@
|
|
|
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.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
documentation: https://github.com/HYPER12755/flutter_ota_kit#readme
|
|
3
|
+
version: 0.1.1
|
|
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
|
dev_dependencies:
|
|
14
13
|
test: ^1.31.2
|
|
@@ -37,8 +37,10 @@ void main() {
|
|
|
37
37
|
for (final c in cohorts) {
|
|
38
38
|
expect(isCohortEligibleForUpdate('x-bundle', '$c', 137, null), isTrue);
|
|
39
39
|
}
|
|
40
|
-
final excluded = List.generate(
|
|
41
|
-
|
|
40
|
+
final excluded = List.generate(
|
|
41
|
+
1000,
|
|
42
|
+
(i) => i + 1,
|
|
43
|
+
).firstWhere((c) => !cohorts.contains(c));
|
|
42
44
|
expect(
|
|
43
45
|
isCohortEligibleForUpdate('x-bundle', '$excluded', 137, null),
|
|
44
46
|
isFalse,
|
|
@@ -64,8 +66,9 @@ void main() {
|
|
|
64
66
|
const bundleId = 'd-bundle';
|
|
65
67
|
final cohorts = getRolledOutNumericCohorts(bundleId, 137);
|
|
66
68
|
expect(
|
|
67
|
-
isCohortEligibleForUpdate(
|
|
68
|
-
|
|
69
|
+
isCohortEligibleForUpdate(bundleId, '${cohorts.first}', 137, [
|
|
70
|
+
'qa-group',
|
|
71
|
+
]),
|
|
69
72
|
isTrue,
|
|
70
73
|
);
|
|
71
74
|
});
|
|
@@ -80,8 +83,10 @@ void main() {
|
|
|
80
83
|
test('targeted numeric cohort wins even when excluded by rollout', () {
|
|
81
84
|
const bundleId = 'f-bundle';
|
|
82
85
|
final rolledOut = getRolledOutNumericCohorts(bundleId, 10).toSet();
|
|
83
|
-
final excluded = List.generate(
|
|
84
|
-
|
|
86
|
+
final excluded = List.generate(
|
|
87
|
+
1000,
|
|
88
|
+
(i) => i + 1,
|
|
89
|
+
).firstWhere((c) => !rolledOut.contains(c));
|
|
85
90
|
expect(
|
|
86
91
|
isCohortEligibleForUpdate(bundleId, '$excluded', 10, ['$excluded']),
|
|
87
92
|
isTrue,
|
|
@@ -95,8 +100,10 @@ void main() {
|
|
|
95
100
|
});
|
|
96
101
|
|
|
97
102
|
test('custom cohorts never match percentage rollouts', () {
|
|
98
|
-
expect(
|
|
99
|
-
|
|
103
|
+
expect(
|
|
104
|
+
isCohortEligibleForUpdate('h-bundle', 'qa-team', 999, null),
|
|
105
|
+
isFalse,
|
|
106
|
+
);
|
|
100
107
|
expect(
|
|
101
108
|
isCohortEligibleForUpdate('h-bundle', 'qa-team', 999, ['qa-team']),
|
|
102
109
|
isTrue,
|
|
@@ -31,8 +31,11 @@ void main() {
|
|
|
31
31
|
// verkit threw on invalid input; we treat as non-match.
|
|
32
32
|
expect(satisfies(parsed, range), isFalse);
|
|
33
33
|
} else {
|
|
34
|
-
expect(
|
|
35
|
-
|
|
34
|
+
expect(
|
|
35
|
+
satisfies(parsed, range),
|
|
36
|
+
expected,
|
|
37
|
+
reason: '$version vs range "$range"',
|
|
38
|
+
);
|
|
36
39
|
}
|
|
37
40
|
});
|
|
38
41
|
}
|
|
@@ -2,28 +2,28 @@ import 'package:flutter_ota_kit_core/flutter_ota_kit_core.dart';
|
|
|
2
2
|
import 'package:test/test.dart';
|
|
3
3
|
|
|
4
4
|
Bundle _sample() => Bundle(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
id: '019b76da-a800-7cc2-b5a5-c8f4a1e9d001',
|
|
6
|
+
platform: Platform.android,
|
|
7
|
+
shouldForceUpdate: false,
|
|
8
|
+
enabled: true,
|
|
9
|
+
fileHash: 'a' * 64,
|
|
10
|
+
storageUri: 'supabase-storage://flutter-ota-storage/bundles/x/bundle.zip',
|
|
11
|
+
gitCommitHash: 'deadbeef',
|
|
12
|
+
message: 'test bundle',
|
|
13
|
+
channel: 'production',
|
|
14
|
+
targetAppVersion: '^1.2.0',
|
|
15
|
+
metadata: const BundleMetadata(appVersion: '1.2.3'),
|
|
16
|
+
rolloutCohortCount: 137,
|
|
17
|
+
targetCohorts: ['qa-group'],
|
|
18
|
+
patches: [
|
|
19
|
+
BundlePatchArtifact(
|
|
20
|
+
baseBundleId: 'base-id',
|
|
21
|
+
baseFileHash: 'b' * 64,
|
|
22
|
+
patchFileHash: 'c' * 64,
|
|
23
|
+
patchStorageUri: 'supabase-storage://bucket/patches/p.bsdiff',
|
|
24
|
+
),
|
|
25
|
+
],
|
|
26
|
+
);
|
|
27
27
|
|
|
28
28
|
void main() {
|
|
29
29
|
group('Bundle JSON', () {
|
|
@@ -100,8 +100,10 @@ void main() {
|
|
|
100
100
|
},
|
|
101
101
|
}) as AppUpdateAvailableInfo;
|
|
102
102
|
expect(info.status, UpdateStatus.update);
|
|
103
|
-
expect(
|
|
104
|
-
|
|
103
|
+
expect(
|
|
104
|
+
info.changedAssets?['assets/logo.png']?.file?.url,
|
|
105
|
+
'https://cdn/logo.png',
|
|
106
|
+
);
|
|
105
107
|
});
|
|
106
108
|
|
|
107
109
|
test('available info serializes', () {
|
|
@@ -12,7 +12,9 @@ void main() {
|
|
|
12
12
|
test('encodes provided timestamp', () {
|
|
13
13
|
final ts = DateTime.utc(2026, 1, 1);
|
|
14
14
|
final id = uuidV7(now: ts);
|
|
15
|
-
final tsHex = ts.millisecondsSinceEpoch
|
|
15
|
+
final tsHex = ts.millisecondsSinceEpoch
|
|
16
|
+
.toRadixString(16)
|
|
17
|
+
.padLeft(12, '0');
|
|
16
18
|
expect(id.substring(0, 8), tsHex.substring(0, 8));
|
|
17
19
|
expect(id.substring(9, 13), tsHex.substring(8, 12));
|
|
18
20
|
expect(id[14], '7');
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## 0.1.1
|
|
2
|
+
|
|
3
|
+
- Add `withCloudFrontSignedUrl` helper for time-limited download URLs.
|
|
4
|
+
- Add `defaultAwsCloudFrontClientFactory` export.
|
|
5
|
+
- Repository moved to `https://github.com/HYPER12755/flutter-ota-kit`.
|
|
6
|
+
|
|
1
7
|
## 0.1.0
|
|
2
8
|
|
|
3
9
|
- Initial release of `flutter_ota_kit_aws` as part of the flutter_ota_kit OTA toolkit.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// flutter_ota_kit_aws example
|
|
2
|
+
//
|
|
3
|
+
// `flutter_ota_kit_aws` provides AWS S3 storage + S3/DynamoDB database
|
|
4
|
+
// plugins for `flutter_ota_kit`. The typical setup uses S3 for both
|
|
5
|
+
// (storing a `bundles.json` manifest plus patch blobs), with optional
|
|
6
|
+
// CloudFront for signed URLs and faster edge delivery.
|
|
7
|
+
//
|
|
8
|
+
// Most apps don't import this package directly; they wire it through
|
|
9
|
+
// `flutter_ota_kit.configureAws(...)` in their app boot path. This file
|
|
10
|
+
// shows the low-level config types in case you're writing a custom
|
|
11
|
+
// server or a CLI extension.
|
|
12
|
+
//
|
|
13
|
+
// Run: `dart run example/main.dart`
|
|
14
|
+
|
|
15
|
+
import 'package:flutter_ota_kit_aws/flutter_ota_kit_aws.dart';
|
|
16
|
+
|
|
17
|
+
void main() {
|
|
18
|
+
// ── 1. S3 storage config (for storing patch blobs). ──────────────
|
|
19
|
+
// `bucketName` + `region` are required. `accessKeyId` and
|
|
20
|
+
// `secretAccessKey` are read-write credentials; in production use an
|
|
21
|
+
// IAM role with the minimum required permissions.
|
|
22
|
+
final s3Config = AwsS3StorageConfig(
|
|
23
|
+
bucketName: 'flutter-ota-bundles',
|
|
24
|
+
region: 'us-east-1',
|
|
25
|
+
accessKeyId: 'AKIA...',
|
|
26
|
+
secretAccessKey: 'wJal...',
|
|
27
|
+
basePath: 'bundles',
|
|
28
|
+
);
|
|
29
|
+
print('S3 bucket: ${s3Config.bucketName} (${s3Config.region})');
|
|
30
|
+
print('Base path: ${s3Config.basePath}');
|
|
31
|
+
|
|
32
|
+
// ── 2. S3 database config (for storing the bundles manifest). ───
|
|
33
|
+
// The "database" plugin reads/writes a `bundles.json` manifest in
|
|
34
|
+
// the same S3 bucket. `cloudfrontDistributionId` enables signed URL
|
|
35
|
+
// serving for the patch downloads.
|
|
36
|
+
final dbConfig = S3DatabaseConfig(
|
|
37
|
+
bucketName: 'flutter-ota-bundles',
|
|
38
|
+
region: 'us-east-1',
|
|
39
|
+
accessKeyId: 'AKIA...',
|
|
40
|
+
secretAccessKey: 'wJal...',
|
|
41
|
+
cloudfrontDistributionId: 'E1ABC2DEF3GHIJ',
|
|
42
|
+
);
|
|
43
|
+
print('S3 DB bucket: ${dbConfig.bucketName}');
|
|
44
|
+
print('CloudFront distribution: ${dbConfig.cloudfrontDistributionId}');
|
|
45
|
+
|
|
46
|
+
// ── 3. CloudFront URL signing (for time-limited download URLs). ──
|
|
47
|
+
// `cloudfrontSignedUrl` produces a URL valid for `expiresInSeconds`
|
|
48
|
+
// (default 1 hour). The signing key is a private RSA key in PEM
|
|
49
|
+
// format — never ship it in a Flutter app.
|
|
50
|
+
// final key = parseRsaPrivateKeyPem(
|
|
51
|
+
// File('cloudfront-private-key.pem').readAsStringSync(),
|
|
52
|
+
// );
|
|
53
|
+
// final signedUrl = cloudfrontSignedUrl(
|
|
54
|
+
// url: 'https://d1abc2def3ghij.cloudfront.net/patch.zip',
|
|
55
|
+
// privateKey: key,
|
|
56
|
+
// keyPairId: 'APKA...',
|
|
57
|
+
// expiresInSeconds: 600,
|
|
58
|
+
// );
|
|
59
|
+
// print('Signed URL: $signedUrl');
|
|
60
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export 'src/aws_storage.dart' show s3Storage;
|
|
2
2
|
export 'src/aws_database.dart'
|
|
3
|
-
show
|
|
3
|
+
show
|
|
4
|
+
S3DatabaseConfig,
|
|
5
|
+
s3Database,
|
|
6
|
+
defaultAwsS3DatabaseClientFactory,
|
|
7
|
+
defaultAwsCloudFrontClientFactory;
|
|
4
8
|
export 'src/aws_config.dart' show AwsS3StorageConfig, defaultAwsS3ClientFactory;
|
|
5
9
|
export 'src/aws_s3_client.dart' show AwsS3ClientLike;
|
|
6
10
|
export 'src/aws_cloudfront_client.dart' show AwsCloudFrontClientLike;
|
|
@@ -118,11 +118,7 @@ class AwsCloudFrontClient implements AwsCloudFrontClientLike {
|
|
|
118
118
|
return m?.group(1);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
Map<String, String> _authHeaders(
|
|
122
|
-
String method,
|
|
123
|
-
Uri uri,
|
|
124
|
-
List<int>? body,
|
|
125
|
-
) {
|
|
121
|
+
Map<String, String> _authHeaders(String method, Uri uri, List<int>? body) {
|
|
126
122
|
final now = DateTime.now().toUtc();
|
|
127
123
|
final amzDate = _amzDate(now);
|
|
128
124
|
final dateStamp = amzDate.substring(0, 8);
|
|
@@ -130,7 +126,8 @@ class AwsCloudFrontClient implements AwsCloudFrontClientLike {
|
|
|
130
126
|
'$dateStamp/$_cloudfrontRegion/$_cloudfrontService/aws4_request';
|
|
131
127
|
final payloadHash = body == null ? _hashHex(const []) : _hashHex(body);
|
|
132
128
|
|
|
133
|
-
final canonicalHeaders =
|
|
129
|
+
final canonicalHeaders =
|
|
130
|
+
'host:${uri.host}\n'
|
|
134
131
|
'x-amz-content-sha256:$payloadHash\n'
|
|
135
132
|
'x-amz-date:$amzDate\n'
|
|
136
133
|
'${config.sessionToken != null ? 'x-amz-security-token:${config.sessionToken}\n' : ''}';
|
|
@@ -138,7 +135,8 @@ class AwsCloudFrontClient implements AwsCloudFrontClientLike {
|
|
|
138
135
|
? 'host;x-amz-content-sha256;x-amz-date;x-amz-security-token'
|
|
139
136
|
: 'host;x-amz-content-sha256;x-amz-date';
|
|
140
137
|
|
|
141
|
-
final canonicalRequest =
|
|
138
|
+
final canonicalRequest =
|
|
139
|
+
'$method\n${uri.path}\n'
|
|
142
140
|
'\n$canonicalHeaders$signedHeaders\n$payloadHash';
|
|
143
141
|
final stringToSign = _stringToSign(amzDate, scope, canonicalRequest);
|
|
144
142
|
final signingKey = _signingKey(dateStamp);
|
|
@@ -181,23 +179,20 @@ class AwsCloudFrontClient implements AwsCloudFrontClientLike {
|
|
|
181
179
|
static String _amzDate(DateTime utc) =>
|
|
182
180
|
'${utc.toIso8601String().replaceAll('-', '').replaceAll(':', '').split('.').first}Z';
|
|
183
181
|
|
|
184
|
-
static String _xmlEscape(String value) =>
|
|
185
|
-
|
|
182
|
+
static String _xmlEscape(String value) => value
|
|
183
|
+
.replaceAll('&', '&')
|
|
184
|
+
.replaceAll('<', '<')
|
|
185
|
+
.replaceAll('>', '>');
|
|
186
186
|
|
|
187
187
|
static Uint8List _hmac(List<int> key, String data) =>
|
|
188
188
|
Hmac(sha256, key).convert(utf8.encode(data)).bytes as Uint8List;
|
|
189
189
|
|
|
190
|
-
static String _hashHex(List<int> data) =>
|
|
191
|
-
_toHex(sha256.convert(data).bytes);
|
|
190
|
+
static String _hashHex(List<int> data) => _toHex(sha256.convert(data).bytes);
|
|
192
191
|
|
|
193
192
|
static String _toHex(List<int> bytes) =>
|
|
194
193
|
bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
|
195
194
|
|
|
196
|
-
static void _assertStatus(
|
|
197
|
-
Response response,
|
|
198
|
-
List<int> ok,
|
|
199
|
-
String operation,
|
|
200
|
-
) {
|
|
195
|
+
static void _assertStatus(Response response, List<int> ok, String operation) {
|
|
201
196
|
if (!ok.contains(response.statusCode)) {
|
|
202
197
|
throw Exception(
|
|
203
198
|
'CloudFront $operation failed (${response.statusCode}): ${response.body}',
|
|
@@ -16,7 +16,10 @@ import 'package:pointycastle/export.dart'
|
|
|
16
16
|
const String _sha1DigestIdentifierHex = '3021300906052b0e03021a05000414';
|
|
17
17
|
|
|
18
18
|
String _base64UrlNoPad(List<int> bytes) =>
|
|
19
|
-
base64Encode(bytes)
|
|
19
|
+
base64Encode(bytes)
|
|
20
|
+
.replaceAll('+', '-')
|
|
21
|
+
.replaceAll('/', '_')
|
|
22
|
+
.replaceAll('=', '');
|
|
20
23
|
|
|
21
24
|
/// Parse a PEM-encoded RSA private key (PKCS#1 `RSA PRIVATE KEY` or PKCS#8
|
|
22
25
|
/// `PRIVATE KEY`) into a [RSAPrivateKey].
|
|
@@ -84,7 +87,9 @@ String cloudfrontSignedUrl({
|
|
|
84
87
|
|
|
85
88
|
final signer = RSASigner(SHA1Digest(), _sha1DigestIdentifierHex);
|
|
86
89
|
signer.init(true, PrivateKeyParameter<RSAPrivateKey>(privateKey));
|
|
87
|
-
final signature = signer
|
|
90
|
+
final signature = signer
|
|
91
|
+
.generateSignature(Uint8List.fromList(policyBytes))
|
|
92
|
+
.bytes;
|
|
88
93
|
final signatureB64 = _base64UrlNoPad(signature);
|
|
89
94
|
|
|
90
95
|
return '$url?Policy=$policyB64&Signature=$signatureB64'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import 'dart:convert' show jsonDecode, jsonEncode, utf8;
|
|
2
2
|
|
|
3
3
|
import 'package:flutter_ota_kit_plugin_core/flutter_ota_kit_plugin_core.dart'
|
|
4
|
-
show BlobOperations, createBlobDatabasePlugin;
|
|
4
|
+
show BlobOperations, createBlobDatabasePlugin, updateJsonKeyRegex;
|
|
5
5
|
|
|
6
6
|
import 'aws_cloudfront_client.dart'
|
|
7
7
|
show AwsCloudFrontClient, AwsCloudFrontClientLike, AwsCloudFrontConfig;
|
|
@@ -70,7 +70,7 @@ class S3DatabaseConfig {
|
|
|
70
70
|
|
|
71
71
|
/// Test seam: override the concrete CloudFront client.
|
|
72
72
|
final AwsCloudFrontClientLike Function(S3DatabaseConfig config)
|
|
73
|
-
|
|
73
|
+
cloudfrontClientFactory;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/// Default factory producing a real [AwsS3Client] with runtime region applied.
|
|
@@ -92,25 +92,21 @@ AwsS3ClientLike defaultAwsS3DatabaseClientFactory(S3DatabaseConfig config) =>
|
|
|
92
92
|
/// Default factory producing a real [AwsCloudFrontClient].
|
|
93
93
|
AwsCloudFrontClientLike defaultAwsCloudFrontClientFactory(
|
|
94
94
|
S3DatabaseConfig config,
|
|
95
|
-
) =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
bool _isUpdateJsonKey(String key) =>
|
|
105
|
-
RegExp(r'^[^/]+/(?:ios|android)/[^/]+/update\.json$').hasMatch(key);
|
|
95
|
+
) => AwsCloudFrontClient(
|
|
96
|
+
AwsCloudFrontConfig(
|
|
97
|
+
accessKeyId: config.accessKeyId,
|
|
98
|
+
secretAccessKey: config.secretAccessKey,
|
|
99
|
+
sessionToken: config.sessionToken,
|
|
100
|
+
),
|
|
101
|
+
);
|
|
106
102
|
|
|
107
103
|
/// S3-backed [BlobOperations] for the AWS `s3Database` plugin.
|
|
108
104
|
class S3BlobOperations implements BlobOperations {
|
|
109
105
|
S3BlobOperations(this.config)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
: _client = config.clientFactory(config),
|
|
107
|
+
_cloudfront = config.cloudfrontDistributionId != null
|
|
108
|
+
? config.cloudfrontClientFactory(config)
|
|
109
|
+
: null {
|
|
114
110
|
final keyBuilder = createDatabaseKeyBuilder(config.basePath);
|
|
115
111
|
_toStorageKey = keyBuilder.$1;
|
|
116
112
|
_fromStorageKey = keyBuilder.$2;
|
|
@@ -130,7 +126,7 @@ class S3BlobOperations implements BlobOperations {
|
|
|
130
126
|
final objects = await _client.listObjects(_toStorageKey(prefix));
|
|
131
127
|
return objects
|
|
132
128
|
.map((o) => _fromStorageKey(o.key))
|
|
133
|
-
.where(
|
|
129
|
+
.where((key) => updateJsonKeyRegex.hasMatch(key))
|
|
134
130
|
.toList();
|
|
135
131
|
}
|
|
136
132
|
|