diff --git a/.github/workflows/build-tc-helper.yml b/.github/workflows/build-tc-helper.yml
new file mode 100644
index 00000000..f8f7ced2
--- /dev/null
+++ b/.github/workflows/build-tc-helper.yml
@@ -0,0 +1,72 @@
+# Compiles the tc_helper Rust native library from source (instead of relying on
+# the pre-built .so committed under android/app/src/main/jniLibs/) and then
+# builds the production APK against the freshly-compiled library.
+#
+# This is the "proper" fix for stale committed binaries: the .so is regenerated
+# from rust/ on every run, so it can never drift from the Rust source. Once this
+# is green, the committed jniLibs/*.so can be git-ignored and purged from history.
+#
+# NOTE: This workflow has not yet been run on CI — action versions, the NDK
+# version, and the cargo-ndk invocation are transcribed from a verified LOCAL
+# build (macOS) and may need small adjustments on the first CI run.
+#
+# Both arm64-v8a and armeabi-v7a are built. taskchampion is configured with only
+# the server-sync backend (see rust/Cargo.toml), so there's no aws-lc-sys — hence
+# no cmake/ninja/bindgen/libclang toolchain needed; ring builds with just the
+# Rust + NDK toolchain.
+name: Build tc_helper (compile from source)
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches: [main, reports]
+ paths:
+ - "rust/**"
+ - "android/**"
+ - ".github/workflows/build-tc-helper.yml"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-java@v4
+ with:
+ distribution: "temurin"
+ java-version: "17"
+
+ # Android SDK + NDK. cargo-ndk reads ANDROID_NDK_HOME to find the toolchain.
+ - uses: android-actions/setup-android@v3
+ - name: Install NDK
+ run: |
+ sdkmanager "ndk;26.1.10909125"
+ echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/26.1.10909125" >> "$GITHUB_ENV"
+
+ - name: Install Rust + Android targets + cargo-ndk
+ run: |
+ rustup toolchain install stable --profile minimal
+ rustup target add aarch64-linux-android armv7-linux-androideabi
+ cargo install cargo-ndk --version ^4
+
+ - name: Compile tc_helper (arm64-v8a + armeabi-v7a) from source
+ working-directory: rust
+ run: |
+ cargo ndk -t arm64-v8a -t armeabi-v7a \
+ -o ../android/app/src/main/jniLibs \
+ build --release
+
+ - name: Show freshly-built libs
+ run: ls -lhR android/app/src/main/jniLibs/
+
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: "3.44.5"
+
+ - run: flutter pub get
+ - run: flutter build apk --release --flavor production
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: production-apk-from-source
+ path: build/app/outputs/flutter-apk/app-production-release.apk
diff --git a/android/app/src/main/jniLibs/arm64-v8a/libcrc_fast-b3182f249ae653b7.so b/android/app/src/main/jniLibs/arm64-v8a/libcrc_fast-b3182f249ae653b7.so
deleted file mode 100755
index 3a8b6827..00000000
Binary files a/android/app/src/main/jniLibs/arm64-v8a/libcrc_fast-b3182f249ae653b7.so and /dev/null differ
diff --git a/android/app/src/main/jniLibs/arm64-v8a/libtc_helper.so b/android/app/src/main/jniLibs/arm64-v8a/libtc_helper.so
index 2ed5d305..6eef8ac4 100755
Binary files a/android/app/src/main/jniLibs/arm64-v8a/libtc_helper.so and b/android/app/src/main/jniLibs/arm64-v8a/libtc_helper.so differ
diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libcrc_fast-c8bd19aec5c73f3a.so b/android/app/src/main/jniLibs/armeabi-v7a/libcrc_fast-c8bd19aec5c73f3a.so
deleted file mode 100755
index df205bcd..00000000
Binary files a/android/app/src/main/jniLibs/armeabi-v7a/libcrc_fast-c8bd19aec5c73f3a.so and /dev/null differ
diff --git a/android/app/src/main/jniLibs/armeabi-v7a/libtc_helper.so b/android/app/src/main/jniLibs/armeabi-v7a/libtc_helper.so
index 4fa2b74e..d89a4f66 100755
Binary files a/android/app/src/main/jniLibs/armeabi-v7a/libtc_helper.so and b/android/app/src/main/jniLibs/armeabi-v7a/libtc_helper.so differ
diff --git a/ios/tc_helper.xcframework/Info.plist b/ios/tc_helper.xcframework/Info.plist
index cf3e2802..560aabd5 100644
--- a/ios/tc_helper.xcframework/Info.plist
+++ b/ios/tc_helper.xcframework/Info.plist
@@ -8,32 +8,32 @@
BinaryPath
tc_helper.framework/tc_helper
LibraryIdentifier
- ios-arm64
+ ios-arm64_x86_64-simulator
LibraryPath
tc_helper.framework
SupportedArchitectures
arm64
+ x86_64
SupportedPlatform
ios
+ SupportedPlatformVariant
+ simulator
BinaryPath
tc_helper.framework/tc_helper
LibraryIdentifier
- ios-arm64_x86_64-simulator
+ ios-arm64
LibraryPath
tc_helper.framework
SupportedArchitectures
arm64
- x86_64
SupportedPlatform
ios
- SupportedPlatformVariant
- simulator
CFBundlePackageType
diff --git a/ios/tc_helper.xcframework/ios-arm64/tc_helper.framework/tc_helper b/ios/tc_helper.xcframework/ios-arm64/tc_helper.framework/tc_helper
index 458cab50..a19b4587 100755
Binary files a/ios/tc_helper.xcframework/ios-arm64/tc_helper.framework/tc_helper and b/ios/tc_helper.xcframework/ios-arm64/tc_helper.framework/tc_helper differ
diff --git a/ios/tc_helper.xcframework/ios-arm64_x86_64-simulator/tc_helper.framework/tc_helper b/ios/tc_helper.xcframework/ios-arm64_x86_64-simulator/tc_helper.framework/tc_helper
index cec5b500..a9f3dfc8 100755
Binary files a/ios/tc_helper.xcframework/ios-arm64_x86_64-simulator/tc_helper.framework/tc_helper and b/ios/tc_helper.xcframework/ios-arm64_x86_64-simulator/tc_helper.framework/tc_helper differ
diff --git a/lib/app/modules/home/controllers/home_controller.dart b/lib/app/modules/home/controllers/home_controller.dart
index 3cf342f8..be5a4bc4 100644
--- a/lib/app/modules/home/controllers/home_controller.dart
+++ b/lib/app/modules/home/controllers/home_controller.dart
@@ -51,6 +51,11 @@ class HomeController extends GetxController {
final RxSet selectedTags = {}.obs;
final RxList queriedTasks = [].obs;
final RxList searchedTasks = [].obs;
+ // Reactive mirror of the search box text. `searchedTasks` only drives the
+ // local-taskc list (TasksBuilder); the TaskChampion replica list reads
+ // `tasksFromReplica` directly, so it needs an observable query to rebuild and
+ // filter on each keystroke. Kept in sync by search()/toggleSearch().
+ final RxString searchQuery = ''.obs;
final RxList selectedDates = List.filled(4, null).obs;
final RxMap pendingTags = {}.obs;
final RxMap projects = {}.obs;
@@ -86,6 +91,12 @@ class HomeController extends GetxController {
taskdb = TaskDatabase();
taskdb.open();
getUniqueProjects();
+ // Initialize the pending/waiting filters from their persisted values.
+ // Without this the RxBool defaults to false, and the replica list view
+ // (which filters `status == pending` only when pendingFilter is true)
+ // shows completed tasks only — hiding every pending task on first load.
+ pendingFilter.value = Query(storage.tabs.tab()).getPendingFilter();
+ waitingFilter.value = Query(storage.tabs.tab()).getWaitingFilter();
_loadTaskChampion();
fetchTasksFromDB();
@@ -499,10 +510,12 @@ class HomeController extends GetxController {
if (!searchVisible.value) {
searchedTasks.assignAll(queriedTasks);
searchController.text = '';
+ searchQuery.value = '';
}
}
void search(String term) {
+ searchQuery.value = term;
searchedTasks.assignAll(
queriedTasks
.where(
diff --git a/lib/app/modules/home/views/home_page_body.dart b/lib/app/modules/home/views/home_page_body.dart
index 0e139462..179e7182 100644
--- a/lib/app/modules/home/views/home_page_body.dart
+++ b/lib/app/modules/home/views/home_page_body.dart
@@ -30,7 +30,25 @@ class HomePageBody extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Obx(
- () => Column(
+ () {
+ // Read the replica list reactively here so the whole view rebuilds
+ // when tasks arrive. On launch, taskReplica flips true (triggering a
+ // rebuild) *before* the async FFI fetch populates tasksFromReplica;
+ // without a reactive read of the list itself, the populated tasks
+ // would never appear (the view stays on its initial empty build).
+ var replicaTasks = controller.tasksFromReplica.toList();
+ // Apply the search text to the replica list. Unlike the local-taskc
+ // path (which reads the pre-filtered `searchedTasks`), this builder
+ // gets the raw list, so filter here. Reading `searchQuery`/
+ // `searchVisible` inside the Obx makes it rebuild on each keystroke.
+ final query = controller.searchQuery.value.trim().toLowerCase();
+ if (controller.searchVisible.value && query.isNotEmpty) {
+ replicaTasks = replicaTasks
+ .where((task) =>
+ (task.description ?? '').toLowerCase().contains(query))
+ .toList();
+ }
+ return Column(
children: [
if (controller.searchVisible.value)
Container(
@@ -134,14 +152,15 @@ class HomePageBody extends StatelessWidget {
child: Expanded(
child: Scrollbar(
child: TaskReplicaViewBuilder(
- replicaTasks: controller.tasksFromReplica,
+ replicaTasks: replicaTasks,
pendingFilter: controller.pendingFilter.value,
selectedSort: controller.selectedSort.value,
project: controller.projectFilter.value,
),
)))
],
- ),
+ );
+ },
),
),
),
diff --git a/lib/app/modules/home/views/show_tasks_replica.dart b/lib/app/modules/home/views/show_tasks_replica.dart
index 642fbdff..f6c46aac 100644
--- a/lib/app/modules/home/views/show_tasks_replica.dart
+++ b/lib/app/modules/home/views/show_tasks_replica.dart
@@ -31,9 +31,11 @@ class TaskReplicaViewBuilder extends StatelessWidget {
TaskwarriorColorTheme tColors =
Theme.of(context).extension()!;
- return Obx(() {
- List tasks = List.from(replicaTasks);
- if (project != null && project != 'All Projects') {
+ // Reactivity is handled by the parent Obx in home_page_body (which reads
+ // tasksFromReplica); this widget just renders the snapshot it's given, so
+ // it must NOT be an Obx (an Obx with no observable read throws ObxError).
+ List tasks = List.from(replicaTasks);
+ if (project != null && project!.isNotEmpty && project != 'All Projects') {
tasks = tasks.where((task) => task.project == project).toList();
}
tasks.sort((a, b) {
@@ -203,7 +205,6 @@ class TaskReplicaViewBuilder extends StatelessWidget {
},
),
);
- });
}
Color _getPriorityColor(String priority) {
diff --git a/lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart b/lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart
index 2fe75484..42d194a0 100644
--- a/lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart
+++ b/lib/app/modules/manageTaskServer/controllers/manage_task_server_controller.dart
@@ -9,6 +9,7 @@ import 'package:taskwarrior/app/models/storage/set_config.dart';
import 'package:taskwarrior/app/modules/home/controllers/home_controller.dart';
import 'package:taskwarrior/app/modules/splash/controllers/splash_controller.dart';
import 'package:taskwarrior/app/tour/manage_task_server_page_tour.dart';
+import 'package:taskwarrior/app/tour/safe_tour.dart';
import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart';
import 'package:taskwarrior/app/utils/home_path/home_path.dart' as rc;
import 'package:taskwarrior/app/utils/taskserver/taskserver.dart';
@@ -221,18 +222,20 @@ class ManageTaskServerController extends GetxController {
void showManageTaskServerPageTour(BuildContext context) {
Future.delayed(
const Duration(milliseconds: 500),
- () {
- SaveTourStatus.getManageTaskServerTourStatus().then((value) => {
- if (value == false)
- {
- tutorialCoachMark.show(context: context),
- }
- else
- {
- // ignore: avoid_print
- print('User has seen this page'),
- }
- });
+ () async {
+ final seen = await SaveTourStatus.getManageTaskServerTourStatus();
+ if (seen) return;
+ await safeShowTour(
+ tutorialCoachMark: tutorialCoachMark,
+ context: context,
+ targetKeys: [
+ configureTaskRC,
+ configureServerCertificate,
+ configureTaskServerKey,
+ configureYourCertificate,
+ ],
+ markSeen: () => SaveTourStatus.saveManageTaskServerTourStatus(true),
+ );
},
);
}
diff --git a/lib/app/modules/profile/controllers/profile_controller.dart b/lib/app/modules/profile/controllers/profile_controller.dart
index 50e6e5cd..0c0303a5 100644
--- a/lib/app/modules/profile/controllers/profile_controller.dart
+++ b/lib/app/modules/profile/controllers/profile_controller.dart
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:taskwarrior/app/modules/splash/controllers/splash_controller.dart';
import 'package:taskwarrior/app/tour/profile_page_tour.dart';
+import 'package:taskwarrior/app/tour/safe_tour.dart';
import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart';
import 'package:taskwarrior/app/utils/app_settings/app_settings.dart';
import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
@@ -45,18 +46,19 @@ class ProfileController extends GetxController {
void showProfilePageTour(BuildContext context) {
Future.delayed(
const Duration(milliseconds: 500),
- () {
- SaveTourStatus.getProfileTourStatus().then((value) => {
- if (value == false)
- {
- tutorialCoachMark.show(context: context),
- }
- else
- {
- // ignore: avoid_print
- print('User has seen this page'),
- }
- });
+ () async {
+ final seen = await SaveTourStatus.getProfileTourStatus();
+ if (seen) return;
+ await safeShowTour(
+ tutorialCoachMark: tutorialCoachMark,
+ context: context,
+ targetKeys: [
+ currentProfileKey,
+ addNewProfileKey,
+ manageSelectedProfileKey,
+ ],
+ markSeen: () => SaveTourStatus.saveProfileTourStatus(true),
+ );
},
);
}
diff --git a/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart b/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart
index 6116cf7e..b1bf1c8e 100644
--- a/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart
+++ b/lib/app/modules/taskc_details/controllers/taskc_details_controller.dart
@@ -35,6 +35,9 @@ class TaskcDetailsController extends GetxController {
late RxString rtype;
late RxString recur;
late RxList annotations;
+ // Blocking state surfaced by the Rust serializer (replica tasks only).
+ late RxBool isBlocked;
+ late RxBool isBlocking;
late RxList previousTags = [].obs;
@override
@@ -64,6 +67,8 @@ class TaskcDetailsController extends GetxController {
rtype = "".obs;
recur = "".obs;
annotations = [].obs;
+ isBlocked = false.obs;
+ isBlocking = false.obs;
} else if (task is TaskForReplica) {
description = (task.description ?? '').obs;
project = (task.project ?? 'None').obs;
@@ -81,10 +86,13 @@ class TaskcDetailsController extends GetxController {
? task.tags!.map((e) => e.toString()).toList().obs
: [].obs;
previousTags = tags.toList().obs;
- depends = "".split(",").obs;
+ // Attributes now surfaced by the Rust serializer.
+ depends = (task.depends ?? []).obs;
rtype = "".obs;
- recur = "".obs;
- annotations = [].obs;
+ recur = (task.recur ?? "").obs;
+ annotations = (task.annotations ?? []).obs;
+ isBlocked = (task.isBlocked ?? false).obs;
+ isBlocking = (task.isBlocking ?? false).obs;
} else {
// Fallback
description = ''.obs;
@@ -100,6 +108,8 @@ class TaskcDetailsController extends GetxController {
rtype = "".obs;
recur = "".obs;
annotations = [].obs;
+ isBlocked = false.obs;
+ isBlocking = false.obs;
}
}
diff --git a/lib/app/modules/taskc_details/views/taskc_details_view.dart b/lib/app/modules/taskc_details/views/taskc_details_view.dart
index 2203274f..ba2a12f3 100644
--- a/lib/app/modules/taskc_details/views/taskc_details_view.dart
+++ b/lib/app/modules/taskc_details/views/taskc_details_view.dart
@@ -111,6 +111,45 @@ class TaskcDetailsView extends GetView {
controller.tags.join(', '),
(value) => controller.updateListField(controller.tags, value),
),
+ // Attributes surfaced by the enriched Rust serializer (D2).
+ // Replica tasks only; read-only (the mobile UI cannot edit
+ // dependencies/annotations yet).
+ if (controller.isReplicaTask) ...[
+ _buildDetail(
+ context,
+ 'Blocked:',
+ controller.isBlocked.value ? 'Yes' : 'No',
+ ),
+ _buildDetail(
+ context,
+ 'Blocking:',
+ controller.isBlocking.value ? 'Yes' : 'No',
+ ),
+ _buildDetail(
+ context,
+ 'Depends:',
+ controller.depends.isEmpty
+ ? 'None'
+ : controller.depends.join(', '),
+ ),
+ _buildDetail(
+ context,
+ 'Recur:',
+ controller.recur.value.isEmpty
+ ? 'None'
+ : controller.recur.value,
+ ),
+ _buildDetail(
+ context,
+ 'Annotations:',
+ controller.annotations.isEmpty
+ ? 'None'
+ : controller.annotations
+ .map((a) =>
+ '• ${a.description ?? ''}${(a.entry != null && a.entry!.isNotEmpty) ? ' (${a.entry})' : ''}')
+ .join('\n'),
+ ),
+ ],
if (controller.isLocalTask) ...[
_buildDetail(
context,
diff --git a/lib/app/tour/safe_tour.dart b/lib/app/tour/safe_tour.dart
new file mode 100644
index 00000000..fa13c457
--- /dev/null
+++ b/lib/app/tour/safe_tour.dart
@@ -0,0 +1,36 @@
+import 'package:flutter/widgets.dart';
+import 'package:tutorial_coach_mark/tutorial_coach_mark.dart';
+
+/// Safely shows a coach-mark tour.
+///
+/// `tutorial_coach_mark` throws
+/// `FormatException: It was not possible to obtain target position (null)`
+/// when any target's [GlobalKey] is not currently laid out. This happens when
+/// the screen changes during the pre-show delay (e.g. the user navigates
+/// deeper before the tour fires): the target widgets are unmounted, so their
+/// render boxes are null.
+///
+/// This helper guards against that: it only calls `show()` when the context is
+/// still mounted and every target key has a live element. Otherwise — or if
+/// `show()` throws anyway — it marks the tour as seen via [markSeen] so a
+/// failed attempt never surfaces an exception or loops forever (the tour's own
+/// `onFinish` would never run to persist the flag).
+Future safeShowTour({
+ required TutorialCoachMark tutorialCoachMark,
+ required BuildContext context,
+ required List targetKeys,
+ Future Function()? markSeen,
+}) async {
+ final bool allMounted =
+ targetKeys.every((k) => k.currentContext != null);
+ if (!context.mounted || !allMounted) {
+ await markSeen?.call();
+ return;
+ }
+ try {
+ tutorialCoachMark.show(context: context);
+ } catch (_) {
+ // Defensive: never let a tour failure bubble up or repeat.
+ await markSeen?.call();
+ }
+}
diff --git a/lib/app/v3/champion/models/task_for_replica.dart b/lib/app/v3/champion/models/task_for_replica.dart
index c1e966c8..c112a53f 100644
--- a/lib/app/v3/champion/models/task_for_replica.dart
+++ b/lib/app/v3/champion/models/task_for_replica.dart
@@ -1,5 +1,7 @@
import 'dart:convert';
+import 'package:taskwarrior/app/v3/models/annotation.dart';
+
class TaskForReplica {
final int? modified;
final String? due;
@@ -13,6 +15,13 @@ class TaskForReplica {
final String? priority;
final String? project;
+ // Attributes surfaced from the TaskChampion Rust serializer.
+ final bool? isBlocked;
+ final bool? isBlocking;
+ final List? depends;
+ final String? recur;
+ final List? annotations;
+
TaskForReplica({
this.modified,
this.due,
@@ -24,8 +33,18 @@ class TaskForReplica {
required this.uuid,
this.priority,
this.project,
+ this.isBlocked,
+ this.isBlocking,
+ this.depends,
+ this.recur,
+ this.annotations,
});
+ static bool _parseBool(dynamic value) {
+ if (value is bool) return value;
+ return value?.toString().toLowerCase() == 'true';
+ }
+
factory TaskForReplica.fromJson(Map json) {
return TaskForReplica(
modified: json['modified'] is int
@@ -62,6 +81,21 @@ class TaskForReplica {
uuid: json['uuid']?.toString() ?? '',
priority: json['priority']?.toString(),
project: json['project']?.toString(),
+ isBlocked:
+ json['is_blocked'] != null ? _parseBool(json['is_blocked']) : null,
+ isBlocking:
+ json['is_blocking'] != null ? _parseBool(json['is_blocking']) : null,
+ depends: (json['depends'] is List)
+ ? (json['depends'] as List).map((e) => e.toString()).toList()
+ : null,
+ recur: (json['recur'] != null && json['recur'].toString().isNotEmpty)
+ ? json['recur'].toString()
+ : null,
+ annotations: (json['annotations'] is List)
+ ? (json['annotations'] as List)
+ .map((e) => Annotation.fromJson(Map.from(e)))
+ .toList()
+ : null,
);
}
@@ -77,6 +111,12 @@ class TaskForReplica {
'uuid': uuid,
if (priority != null) 'priority': priority,
if (project != null) 'project': project,
+ if (isBlocked != null) 'is_blocked': isBlocked,
+ if (isBlocking != null) 'is_blocking': isBlocking,
+ if (depends != null) 'depends': depends,
+ if (recur != null) 'recur': recur,
+ if (annotations != null)
+ 'annotations': annotations!.map((a) => a.toJson()).toList(),
};
}
@@ -90,6 +130,12 @@ class TaskForReplica {
List? tags,
String? uuid,
String? priority,
+ String? project,
+ bool? isBlocked,
+ bool? isBlocking,
+ List? depends,
+ String? recur,
+ List? annotations,
}) {
return TaskForReplica(
modified: modified ?? this.modified,
@@ -101,7 +147,12 @@ class TaskForReplica {
tags: tags ?? this.tags,
uuid: uuid ?? this.uuid,
priority: priority ?? this.priority,
- project: project ?? project,
+ project: project ?? this.project,
+ isBlocked: isBlocked ?? this.isBlocked,
+ isBlocking: isBlocking ?? this.isBlocking,
+ depends: depends ?? this.depends,
+ recur: recur ?? this.recur,
+ annotations: annotations ?? this.annotations,
);
}
@@ -120,7 +171,11 @@ class TaskForReplica {
other.description == description &&
_listEquals(other.tags, tags) &&
other.uuid == uuid &&
- other.priority == priority;
+ other.priority == priority &&
+ other.isBlocked == isBlocked &&
+ other.isBlocking == isBlocking &&
+ _listEquals(other.depends, depends) &&
+ other.recur == recur;
}
@override
diff --git a/lib/rust_bridge/api.dart b/lib/rust_bridge/api.dart
index 8788ef8b..429c6d9c 100644
--- a/lib/rust_bridge/api.dart
+++ b/lib/rust_bridge/api.dart
@@ -6,29 +6,35 @@
import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
-// These functions are ignored because they are not marked as `pub`: `get_all_tasks`, `parse_datetime`
+// These functions are ignored because they are not marked as `pub`: `add_task_impl`, `delete_task_impl`, `get_all_tasks_json_impl`, `parse_datetime`, `sync_impl`, `update_task_impl`
+/// Return every task in the replica as a JSON array string.
Future getAllTasksJson({required String taskdbDirPath}) =>
RustLib.instance.api.crateApiGetAllTasksJson(taskdbDirPath: taskdbDirPath);
-Future deleteTask(
+/// Delete the task with the given UUID. A no-op if the task does not exist.
+Future deleteTask(
{required String uuidSt, required String taskdbDirPath}) =>
RustLib.instance.api
.crateApiDeleteTask(uuidSt: uuidSt, taskdbDirPath: taskdbDirPath);
-Future updateTask(
+/// Update the mutable fields of an existing task from the supplied key/value map.
+Future updateTask(
{required String uuidSt,
required String taskdbDirPath,
required Map map}) =>
RustLib.instance.api.crateApiUpdateTask(
uuidSt: uuidSt, taskdbDirPath: taskdbDirPath, map: map);
-Future addTask(
+/// Create a new task from the supplied key/value map. The map must contain a
+/// `uuid` entry.
+Future addTask(
{required String taskdbDirPath, required Map map}) =>
RustLib.instance.api
.crateApiAddTask(taskdbDirPath: taskdbDirPath, map: map);
-Future sync_(
+/// Synchronise the local replica with a remote TaskChampion sync server.
+Future sync_(
{required String taskdbDirPath,
required String url,
required String clientId,
diff --git a/lib/rust_bridge/frb_generated.dart b/lib/rust_bridge/frb_generated.dart
index 2dbdeccc..1c4a7038 100644
--- a/lib/rust_bridge/frb_generated.dart
+++ b/lib/rust_bridge/frb_generated.dart
@@ -79,21 +79,21 @@ class RustLib extends BaseEntrypoint {
}
abstract class RustLibApi extends BaseApi {
- Future crateApiAddTask(
+ Future crateApiAddTask(
{required String taskdbDirPath, required Map map});
- Future crateApiDeleteTask(
+ Future crateApiDeleteTask(
{required String uuidSt, required String taskdbDirPath});
Future crateApiGetAllTasksJson({required String taskdbDirPath});
- Future crateApiSync(
+ Future crateApiSync(
{required String taskdbDirPath,
required String url,
required String clientId,
required String encryptionSecret});
- Future crateApiUpdateTask(
+ Future crateApiUpdateTask(
{required String uuidSt,
required String taskdbDirPath,
required Map map});
@@ -108,7 +108,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
});
@override
- Future crateApiAddTask(
+ Future crateApiAddTask(
{required String taskdbDirPath, required Map map}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
@@ -119,8 +119,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
funcId: 1, port: port_);
},
codec: SseCodec(
- decodeSuccessData: sse_decode_i_8,
- decodeErrorData: null,
+ decodeSuccessData: sse_decode_unit,
+ decodeErrorData: sse_decode_String,
),
constMeta: kCrateApiAddTaskConstMeta,
argValues: [taskdbDirPath, map],
@@ -134,7 +134,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
@override
- Future crateApiDeleteTask(
+ Future crateApiDeleteTask(
{required String uuidSt, required String taskdbDirPath}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
@@ -145,8 +145,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
funcId: 2, port: port_);
},
codec: SseCodec(
- decodeSuccessData: sse_decode_i_8,
- decodeErrorData: null,
+ decodeSuccessData: sse_decode_unit,
+ decodeErrorData: sse_decode_String,
),
constMeta: kCrateApiDeleteTaskConstMeta,
argValues: [uuidSt, taskdbDirPath],
@@ -170,7 +170,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
},
codec: SseCodec(
decodeSuccessData: sse_decode_String,
- decodeErrorData: sse_decode_AnyhowException,
+ decodeErrorData: sse_decode_String,
),
constMeta: kCrateApiGetAllTasksJsonConstMeta,
argValues: [taskdbDirPath],
@@ -184,7 +184,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
@override
- Future crateApiSync(
+ Future crateApiSync(
{required String taskdbDirPath,
required String url,
required String clientId,
@@ -200,8 +200,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
funcId: 4, port: port_);
},
codec: SseCodec(
- decodeSuccessData: sse_decode_i_8,
- decodeErrorData: null,
+ decodeSuccessData: sse_decode_unit,
+ decodeErrorData: sse_decode_String,
),
constMeta: kCrateApiSyncConstMeta,
argValues: [taskdbDirPath, url, clientId, encryptionSecret],
@@ -215,7 +215,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
@override
- Future crateApiUpdateTask(
+ Future crateApiUpdateTask(
{required String uuidSt,
required String taskdbDirPath,
required Map map}) {
@@ -229,8 +229,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
funcId: 5, port: port_);
},
codec: SseCodec(
- decodeSuccessData: sse_decode_i_8,
- decodeErrorData: null,
+ decodeSuccessData: sse_decode_unit,
+ decodeErrorData: sse_decode_String,
),
constMeta: kCrateApiUpdateTaskConstMeta,
argValues: [uuidSt, taskdbDirPath, map],
@@ -243,12 +243,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
argNames: ["uuidSt", "taskdbDirPath", "map"],
);
- @protected
- AnyhowException dco_decode_AnyhowException(dynamic raw) {
- // Codec=Dco (DartCObject based), see doc to use other codecs
- return AnyhowException(raw as String);
- }
-
@protected
Map dco_decode_Map_String_String_None(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -262,12 +256,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as String;
}
- @protected
- int dco_decode_i_8(dynamic raw) {
- // Codec=Dco (DartCObject based), see doc to use other codecs
- return raw as int;
- }
-
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -305,13 +293,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return;
}
- @protected
- AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer) {
- // Codec=Sse (Serialization based), see doc to use other codecs
- var inner = sse_decode_String(deserializer);
- return AnyhowException(inner);
- }
-
@protected
Map sse_decode_Map_String_String_None(
SseDeserializer deserializer) {
@@ -327,12 +308,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return utf8.decoder.convert(inner);
}
- @protected
- int sse_decode_i_8(SseDeserializer deserializer) {
- // Codec=Sse (Serialization based), see doc to use other codecs
- return deserializer.buffer.getInt8();
- }
-
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -385,13 +360,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getUint8() != 0;
}
- @protected
- void sse_encode_AnyhowException(
- AnyhowException self, SseSerializer serializer) {
- // Codec=Sse (Serialization based), see doc to use other codecs
- sse_encode_String(self.message, serializer);
- }
-
@protected
void sse_encode_Map_String_String_None(
Map self, SseSerializer serializer) {
@@ -406,12 +374,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer);
}
- @protected
- void sse_encode_i_8(int self, SseSerializer serializer) {
- // Codec=Sse (Serialization based), see doc to use other codecs
- serializer.buffer.putInt8(self);
- }
-
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer) {
diff --git a/lib/rust_bridge/frb_generated.io.dart b/lib/rust_bridge/frb_generated.io.dart
index 77034b1d..0877d754 100644
--- a/lib/rust_bridge/frb_generated.io.dart
+++ b/lib/rust_bridge/frb_generated.io.dart
@@ -18,18 +18,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl {
required super.portManager,
});
- @protected
- AnyhowException dco_decode_AnyhowException(dynamic raw);
-
@protected
Map dco_decode_Map_String_String_None(dynamic raw);
@protected
String dco_decode_String(dynamic raw);
- @protected
- int dco_decode_i_8(dynamic raw);
-
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@@ -45,9 +39,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl {
@protected
void dco_decode_unit(dynamic raw);
- @protected
- AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
-
@protected
Map sse_decode_Map_String_String_None(
SseDeserializer deserializer);
@@ -55,9 +46,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl {
@protected
String sse_decode_String(SseDeserializer deserializer);
- @protected
- int sse_decode_i_8(SseDeserializer deserializer);
-
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@@ -81,10 +69,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl {
@protected
bool sse_decode_bool(SseDeserializer deserializer);
- @protected
- void sse_encode_AnyhowException(
- AnyhowException self, SseSerializer serializer);
-
@protected
void sse_encode_Map_String_String_None(
Map self, SseSerializer serializer);
@@ -92,9 +76,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl {
@protected
void sse_encode_String(String self, SseSerializer serializer);
- @protected
- void sse_encode_i_8(int self, SseSerializer serializer);
-
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
diff --git a/lib/rust_bridge/frb_generated.web.dart b/lib/rust_bridge/frb_generated.web.dart
index 34fa9bca..7d7b51f6 100644
--- a/lib/rust_bridge/frb_generated.web.dart
+++ b/lib/rust_bridge/frb_generated.web.dart
@@ -26,14 +26,10 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
- @protected AnyhowException dco_decode_AnyhowException(dynamic raw);
-
-@protected Map dco_decode_Map_String_String_None(dynamic raw);
+ @protected Map dco_decode_Map_String_String_None(dynamic raw);
@protected String dco_decode_String(dynamic raw);
-@protected int dco_decode_i_8(dynamic raw);
-
@protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@protected List<(String,String)> dco_decode_list_record_string_string(dynamic raw);
@@ -44,14 +40,10 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
@protected void dco_decode_unit(dynamic raw);
-@protected AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
-
@protected Map sse_decode_Map_String_String_None(SseDeserializer deserializer);
@protected String sse_decode_String(SseDeserializer deserializer);
-@protected int sse_decode_i_8(SseDeserializer deserializer);
-
@protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@protected List<(String,String)> sse_decode_list_record_string_string(SseDeserializer deserializer);
@@ -66,14 +58,10 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart';
@protected bool sse_decode_bool(SseDeserializer deserializer);
-@protected void sse_encode_AnyhowException(AnyhowException self, SseSerializer serializer);
-
@protected void sse_encode_Map_String_String_None(Map self, SseSerializer serializer);
@protected void sse_encode_String(String self, SseSerializer serializer);
-@protected void sse_encode_i_8(int self, SseSerializer serializer);
-
@protected void sse_encode_list_prim_u_8_strict(Uint8List self, SseSerializer serializer);
@protected void sse_encode_list_record_string_string(List<(String,String)> self, SseSerializer serializer);
diff --git a/pubspec.yaml b/pubspec.yaml
index 12e80726..1a45a235 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -66,7 +66,7 @@ dependencies:
built_collection: ^5.1.1
textfield_tags: ^3.0.1
path_provider: ^2.1.5
- flutter_rust_bridge: ^2.11.1
+ flutter_rust_bridge: 2.11.1
ffi: any # Required for FFI
app_links: ^6.4.1
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index e77d3b10..560330a9 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -49,12 +49,6 @@ dependencies = [
"backtrace",
]
-[[package]]
-name = "allocator-api2"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
-
[[package]]
name = "android-tzdata"
version = "0.1.1"
@@ -146,487 +140,18 @@ dependencies = [
"backtrace",
]
-[[package]]
-name = "async-stream"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
-dependencies = [
- "async-stream-impl",
- "futures-core",
- "pin-project-lite",
-]
-
-[[package]]
-name = "async-stream-impl"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "async-trait"
-version = "0.1.89"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
[[package]]
name = "atomic"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
-[[package]]
-name = "atomic-waker"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
-
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-[[package]]
-name = "aws-config"
-version = "1.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bc1b40fb26027769f16960d2f4a6bc20c4bb755d403e552c8c1a73af433c246"
-dependencies = [
- "aws-credential-types",
- "aws-runtime",
- "aws-sdk-sso",
- "aws-sdk-ssooidc",
- "aws-sdk-sts",
- "aws-smithy-async",
- "aws-smithy-http",
- "aws-smithy-json",
- "aws-smithy-runtime",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "aws-types",
- "bytes",
- "fastrand",
- "hex",
- "http 1.3.1",
- "ring",
- "time",
- "tokio",
- "tracing",
- "url",
- "zeroize",
-]
-
-[[package]]
-name = "aws-credential-types"
-version = "1.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d025db5d9f52cbc413b167136afb3d8aeea708c0d8884783cf6253be5e22f6f2"
-dependencies = [
- "aws-smithy-async",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "zeroize",
-]
-
-[[package]]
-name = "aws-lc-rs"
-version = "1.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba"
-dependencies = [
- "aws-lc-sys",
- "zeroize",
-]
-
-[[package]]
-name = "aws-lc-sys"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff"
-dependencies = [
- "bindgen",
- "cc",
- "cmake",
- "dunce",
- "fs_extra",
-]
-
-[[package]]
-name = "aws-runtime"
-version = "1.5.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c034a1bc1d70e16e7f4e4caf7e9f7693e4c9c24cd91cf17c2a0b21abaebc7c8b"
-dependencies = [
- "aws-credential-types",
- "aws-sigv4",
- "aws-smithy-async",
- "aws-smithy-eventstream",
- "aws-smithy-http",
- "aws-smithy-runtime",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "aws-types",
- "bytes",
- "fastrand",
- "http 0.2.12",
- "http-body 0.4.6",
- "percent-encoding",
- "pin-project-lite",
- "tracing",
- "uuid",
-]
-
-[[package]]
-name = "aws-sdk-s3"
-version = "1.104.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38c488cd6abb0ec9811c401894191932e941c5f91dc226043edacd0afa1634bc"
-dependencies = [
- "aws-credential-types",
- "aws-runtime",
- "aws-sigv4",
- "aws-smithy-async",
- "aws-smithy-checksums",
- "aws-smithy-eventstream",
- "aws-smithy-http",
- "aws-smithy-json",
- "aws-smithy-runtime",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "aws-smithy-xml",
- "aws-types",
- "bytes",
- "fastrand",
- "hex",
- "hmac",
- "http 0.2.12",
- "http 1.3.1",
- "http-body 0.4.6",
- "lru",
- "percent-encoding",
- "regex-lite",
- "sha2",
- "tracing",
- "url",
-]
-
-[[package]]
-name = "aws-sdk-sso"
-version = "1.83.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "643cd43af212d2a1c4dedff6f044d7e1961e5d9e7cfe773d70f31d9842413886"
-dependencies = [
- "aws-credential-types",
- "aws-runtime",
- "aws-smithy-async",
- "aws-smithy-http",
- "aws-smithy-json",
- "aws-smithy-runtime",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "aws-types",
- "bytes",
- "fastrand",
- "http 0.2.12",
- "regex-lite",
- "tracing",
-]
-
-[[package]]
-name = "aws-sdk-ssooidc"
-version = "1.84.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20ec4a95bd48e0db7a424356a161f8d87bd6a4f0af37204775f0da03d9e39fc3"
-dependencies = [
- "aws-credential-types",
- "aws-runtime",
- "aws-smithy-async",
- "aws-smithy-http",
- "aws-smithy-json",
- "aws-smithy-runtime",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "aws-types",
- "bytes",
- "fastrand",
- "http 0.2.12",
- "regex-lite",
- "tracing",
-]
-
-[[package]]
-name = "aws-sdk-sts"
-version = "1.85.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "410309ad0df4606bc721aff0d89c3407682845453247213a0ccc5ff8801ee107"
-dependencies = [
- "aws-credential-types",
- "aws-runtime",
- "aws-smithy-async",
- "aws-smithy-http",
- "aws-smithy-json",
- "aws-smithy-query",
- "aws-smithy-runtime",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "aws-smithy-xml",
- "aws-types",
- "fastrand",
- "http 0.2.12",
- "regex-lite",
- "tracing",
-]
-
-[[package]]
-name = "aws-sigv4"
-version = "1.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "084c34162187d39e3740cb635acd73c4e3a551a36146ad6fe8883c929c9f876c"
-dependencies = [
- "aws-credential-types",
- "aws-smithy-eventstream",
- "aws-smithy-http",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "bytes",
- "crypto-bigint 0.5.5",
- "form_urlencoded",
- "hex",
- "hmac",
- "http 0.2.12",
- "http 1.3.1",
- "p256",
- "percent-encoding",
- "ring",
- "sha2",
- "subtle",
- "time",
- "tracing",
- "zeroize",
-]
-
-[[package]]
-name = "aws-smithy-async"
-version = "1.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c"
-dependencies = [
- "futures-util",
- "pin-project-lite",
- "tokio",
-]
-
-[[package]]
-name = "aws-smithy-checksums"
-version = "0.63.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56d2df0314b8e307995a3b86d44565dfe9de41f876901a7d71886c756a25979f"
-dependencies = [
- "aws-smithy-http",
- "aws-smithy-types",
- "bytes",
- "crc-fast",
- "hex",
- "http 0.2.12",
- "http-body 0.4.6",
- "md-5",
- "pin-project-lite",
- "sha1",
- "sha2",
- "tracing",
-]
-
-[[package]]
-name = "aws-smithy-eventstream"
-version = "0.60.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "182b03393e8c677347fb5705a04a9392695d47d20ef0a2f8cfe28c8e6b9b9778"
-dependencies = [
- "aws-smithy-types",
- "bytes",
- "crc32fast",
-]
-
-[[package]]
-name = "aws-smithy-http"
-version = "0.62.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c4dacf2d38996cf729f55e7a762b30918229917eca115de45dfa8dfb97796c9"
-dependencies = [
- "aws-smithy-eventstream",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "bytes",
- "bytes-utils",
- "futures-core",
- "http 0.2.12",
- "http 1.3.1",
- "http-body 0.4.6",
- "percent-encoding",
- "pin-project-lite",
- "pin-utils",
- "tracing",
-]
-
-[[package]]
-name = "aws-smithy-http-client"
-version = "1.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b"
-dependencies = [
- "aws-smithy-async",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "h2 0.3.27",
- "h2 0.4.12",
- "http 0.2.12",
- "http 1.3.1",
- "http-body 0.4.6",
- "hyper 0.14.32",
- "hyper 1.7.0",
- "hyper-rustls 0.24.2",
- "hyper-rustls 0.27.7",
- "hyper-util",
- "pin-project-lite",
- "rustls 0.21.12",
- "rustls 0.23.31",
- "rustls-native-certs 0.8.1",
- "rustls-pki-types",
- "tokio",
- "tokio-rustls 0.26.2",
- "tower",
- "tracing",
-]
-
-[[package]]
-name = "aws-smithy-json"
-version = "0.61.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaa31b350998e703e9826b2104dd6f63be0508666e1aba88137af060e8944047"
-dependencies = [
- "aws-smithy-types",
-]
-
-[[package]]
-name = "aws-smithy-observability"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9364d5989ac4dd918e5cc4c4bdcc61c9be17dcd2586ea7f69e348fc7c6cab393"
-dependencies = [
- "aws-smithy-runtime-api",
-]
-
-[[package]]
-name = "aws-smithy-query"
-version = "0.60.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb"
-dependencies = [
- "aws-smithy-types",
- "urlencoding",
-]
-
-[[package]]
-name = "aws-smithy-runtime"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3946acbe1ead1301ba6862e712c7903ca9bb230bdf1fbd1b5ac54158ef2ab1f"
-dependencies = [
- "aws-smithy-async",
- "aws-smithy-http",
- "aws-smithy-http-client",
- "aws-smithy-observability",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "bytes",
- "fastrand",
- "http 0.2.12",
- "http 1.3.1",
- "http-body 0.4.6",
- "http-body 1.0.1",
- "pin-project-lite",
- "pin-utils",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "aws-smithy-runtime-api"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07f5e0fc8a6b3f2303f331b94504bbf754d85488f402d6f1dd7a6080f99afe56"
-dependencies = [
- "aws-smithy-async",
- "aws-smithy-types",
- "bytes",
- "http 0.2.12",
- "http 1.3.1",
- "pin-project-lite",
- "tokio",
- "tracing",
- "zeroize",
-]
-
-[[package]]
-name = "aws-smithy-types"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8"
-dependencies = [
- "base64-simd",
- "bytes",
- "bytes-utils",
- "futures-core",
- "http 0.2.12",
- "http 1.3.1",
- "http-body 0.4.6",
- "http-body 1.0.1",
- "http-body-util",
- "itoa",
- "num-integer",
- "pin-project-lite",
- "pin-utils",
- "ryu",
- "serde",
- "time",
- "tokio",
- "tokio-util",
-]
-
-[[package]]
-name = "aws-smithy-xml"
-version = "0.60.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3db87b96cb1b16c024980f133968d52882ca0daaee3a086c6decc500f6c99728"
-dependencies = [
- "xmlparser",
-]
-
-[[package]]
-name = "aws-types"
-version = "1.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390"
-dependencies = [
- "aws-credential-types",
- "aws-smithy-async",
- "aws-smithy-runtime-api",
- "aws-smithy-types",
- "rustc_version",
- "tracing",
-]
-
[[package]]
name = "backtrace"
version = "0.3.75"
@@ -642,63 +167,12 @@ dependencies = [
"windows-targets 0.52.6",
]
-[[package]]
-name = "base16ct"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
-
-[[package]]
-name = "base64"
-version = "0.21.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
-
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-[[package]]
-name = "base64-simd"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195"
-dependencies = [
- "outref",
- "vsimd",
-]
-
-[[package]]
-name = "base64ct"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
-
-[[package]]
-name = "bindgen"
-version = "0.69.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
-dependencies = [
- "bitflags 2.9.4",
- "cexpr",
- "clang-sys",
- "itertools 0.12.1",
- "lazy_static",
- "lazycell",
- "log",
- "prettyplease",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash 1.1.0",
- "shlex",
- "syn 2.0.106",
- "which",
-]
-
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -750,16 +224,6 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
-[[package]]
-name = "bytes-utils"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35"
-dependencies = [
- "bytes",
- "either",
-]
-
[[package]]
name = "camino"
version = "1.1.12"
@@ -826,32 +290,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54"
dependencies = [
"find-msvc-tools",
- "jobserver",
- "libc",
"shlex",
]
-[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom",
-]
-
[[package]]
name = "cfg-if"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
-[[package]]
-name = "cfg_aliases"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
-
[[package]]
name = "chrono"
version = "0.4.41"
@@ -867,17 +314,6 @@ dependencies = [
"windows-link",
]
-[[package]]
-name = "clang-sys"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
-dependencies = [
- "glob",
- "libc",
- "libloading",
-]
-
[[package]]
name = "clap"
version = "4.5.47"
@@ -918,15 +354,6 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
-[[package]]
-name = "cmake"
-version = "0.1.54"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
-dependencies = [
- "cc",
-]
-
[[package]]
name = "colorchoice"
version = "1.0.4"
@@ -967,38 +394,12 @@ dependencies = [
"wasm-bindgen",
]
-[[package]]
-name = "const-oid"
-version = "0.9.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
-
[[package]]
name = "convert_case"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8"
-[[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "core-foundation"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -1014,34 +415,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "crc"
-version = "3.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
-dependencies = [
- "crc-catalog",
-]
-
-[[package]]
-name = "crc-catalog"
-version = "2.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
-
-[[package]]
-name = "crc-fast"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bf62af4cc77d8fe1c22dde4e721d87f2f54056139d8c412e1366b740305f56f"
-dependencies = [
- "crc",
- "digest",
- "libc",
- "rand",
- "regex",
-]
-
[[package]]
name = "crc32fast"
version = "1.5.0"
@@ -1066,28 +439,6 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
-[[package]]
-name = "crypto-bigint"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
-dependencies = [
- "generic-array",
- "rand_core 0.6.4",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "crypto-bigint"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
-dependencies = [
- "rand_core 0.6.4",
- "subtle",
-]
-
[[package]]
name = "crypto-common"
version = "0.1.6"
@@ -1131,37 +482,6 @@ dependencies = [
"syn 2.0.106",
]
-[[package]]
-name = "der"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
-dependencies = [
- "const-oid",
- "zeroize",
-]
-
-[[package]]
-name = "der"
-version = "0.7.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
-dependencies = [
- "const-oid",
- "pem-rfc7468",
- "zeroize",
-]
-
-[[package]]
-name = "deranged"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc"
-dependencies = [
- "powerfmt",
- "serde",
-]
-
[[package]]
name = "derivative"
version = "2.2.0"
@@ -1181,7 +501,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
- "subtle",
]
[[package]]
@@ -1195,64 +514,17 @@ dependencies = [
"syn 2.0.106",
]
-[[package]]
-name = "dunce"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
-
-[[package]]
-name = "ecdsa"
-version = "0.14.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
-dependencies = [
- "der 0.6.1",
- "elliptic-curve",
- "rfc6979",
- "signature",
-]
-
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
-[[package]]
-name = "elliptic-curve"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
-dependencies = [
- "base16ct",
- "crypto-bigint 0.4.9",
- "der 0.6.1",
- "digest",
- "ff",
- "generic-array",
- "group",
- "pkcs8 0.9.0",
- "rand_core 0.6.4",
- "sec1",
- "subtle",
- "zeroize",
-]
-
[[package]]
name = "encode_unicode"
version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
-
-[[package]]
-name = "encoding_rs"
-version = "0.8.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
-dependencies = [
- "cfg-if",
-]
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "enum-iterator"
@@ -1341,16 +613,6 @@ dependencies = [
"log",
]
-[[package]]
-name = "ff"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
-dependencies = [
- "rand_core 0.6.4",
- "subtle",
-]
-
[[package]]
name = "filetime"
version = "0.2.26"
@@ -1430,7 +692,7 @@ dependencies = [
"include_dir",
"indicatif",
"indicatif-log-bridge",
- "itertools 0.10.5",
+ "itertools",
"lazy_static",
"log",
"notify",
@@ -1466,18 +728,6 @@ dependencies = [
"syn 2.0.106",
]
-[[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "foldhash"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
-
[[package]]
name = "form_urlencoded"
version = "1.2.2"
@@ -1487,12 +737,6 @@ dependencies = [
"percent-encoding",
]
-[[package]]
-name = "fs_extra"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
-
[[package]]
name = "fsevent-sys"
version = "4.1.0"
@@ -1608,10 +852,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
- "js-sys",
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
- "wasm-bindgen",
]
[[package]]
@@ -1621,11 +863,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
- "js-sys",
"libc",
"r-efi",
"wasi 0.14.4+wasi-0.2.4",
- "wasm-bindgen",
]
[[package]]
@@ -1640,130 +880,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
-[[package]]
-name = "google-cloud-auth"
-version = "0.17.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e57a13fbacc5e9c41ded3ad8d0373175a6b7a6ad430d99e89d314ac121b7ab06"
-dependencies = [
- "async-trait",
- "base64 0.21.7",
- "google-cloud-metadata",
- "google-cloud-token",
- "home",
- "jsonwebtoken",
- "reqwest",
- "serde",
- "serde_json",
- "thiserror 1.0.69",
- "time",
- "tokio",
- "tracing",
- "urlencoding",
-]
-
-[[package]]
-name = "google-cloud-metadata"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d901aeb453fd80e51d64df4ee005014f6cf39f2d736dd64f7239c132d9d39a6a"
-dependencies = [
- "reqwest",
- "thiserror 1.0.69",
- "tokio",
-]
-
-[[package]]
-name = "google-cloud-storage"
-version = "0.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34a73d9e94d35665909050f02e035d8bdc82e419241b1b027ebf1ea51dc8a470"
-dependencies = [
- "anyhow",
- "async-stream",
- "async-trait",
- "base64 0.21.7",
- "bytes",
- "futures-util",
- "google-cloud-auth",
- "google-cloud-metadata",
- "google-cloud-token",
- "hex",
- "once_cell",
- "percent-encoding",
- "pkcs8 0.10.2",
- "regex",
- "reqwest",
- "reqwest-middleware",
- "ring",
- "serde",
- "serde_json",
- "sha2",
- "thiserror 1.0.69",
- "time",
- "tokio",
- "tracing",
- "url",
-]
-
-[[package]]
-name = "google-cloud-token"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f49c12ba8b21d128a2ce8585955246977fbce4415f680ebf9199b6f9d6d725f"
-dependencies = [
- "async-trait",
-]
-
-[[package]]
-name = "group"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
-dependencies = [
- "ff",
- "rand_core 0.6.4",
- "subtle",
-]
-
-[[package]]
-name = "h2"
-version = "0.3.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http 0.2.12",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
-name = "h2"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
-dependencies = [
- "atomic-waker",
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "http 1.3.1",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
[[package]]
name = "hashbrown"
version = "0.14.5"
@@ -1778,11 +894,6 @@ name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
-dependencies = [
- "allocator-api2",
- "equivalent",
- "foldhash",
-]
[[package]]
name = "hashlink"
@@ -1817,196 +928,6 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-[[package]]
-name = "hmac"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
-dependencies = [
- "digest",
-]
-
-[[package]]
-name = "home"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "http"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http-body"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
-dependencies = [
- "bytes",
- "http 0.2.12",
- "pin-project-lite",
-]
-
-[[package]]
-name = "http-body"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
-dependencies = [
- "bytes",
- "http 1.3.1",
-]
-
-[[package]]
-name = "http-body-util"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
-dependencies = [
- "bytes",
- "futures-core",
- "http 1.3.1",
- "http-body 1.0.1",
- "pin-project-lite",
-]
-
-[[package]]
-name = "httparse"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
-
-[[package]]
-name = "httpdate"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
-
-[[package]]
-name = "hyper"
-version = "0.14.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2 0.3.27",
- "http 0.2.12",
- "http-body 0.4.6",
- "httparse",
- "httpdate",
- "itoa",
- "pin-project-lite",
- "socket2 0.5.10",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "hyper"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
-dependencies = [
- "atomic-waker",
- "bytes",
- "futures-channel",
- "futures-core",
- "h2 0.4.12",
- "http 1.3.1",
- "http-body 1.0.1",
- "httparse",
- "itoa",
- "pin-project-lite",
- "pin-utils",
- "smallvec",
- "tokio",
- "want",
-]
-
-[[package]]
-name = "hyper-rustls"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
-dependencies = [
- "futures-util",
- "http 0.2.12",
- "hyper 0.14.32",
- "log",
- "rustls 0.21.12",
- "rustls-native-certs 0.6.3",
- "tokio",
- "tokio-rustls 0.24.1",
-]
-
-[[package]]
-name = "hyper-rustls"
-version = "0.27.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
-dependencies = [
- "http 1.3.1",
- "hyper 1.7.0",
- "hyper-util",
- "rustls 0.23.31",
- "rustls-native-certs 0.8.1",
- "rustls-pki-types",
- "tokio",
- "tokio-rustls 0.26.2",
- "tower-service",
- "webpki-roots 1.0.2",
-]
-
-[[package]]
-name = "hyper-util"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
-dependencies = [
- "base64 0.22.1",
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "http 1.3.1",
- "http-body 1.0.1",
- "hyper 1.7.0",
- "ipnet",
- "libc",
- "percent-encoding",
- "pin-project-lite",
- "socket2 0.6.0",
- "tokio",
- "tower-service",
- "tracing",
-]
-
[[package]]
name = "iana-time-zone"
version = "0.1.63"
@@ -2221,22 +1142,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "ipnet"
-version = "2.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
-
-[[package]]
-name = "iri-string"
-version = "0.7.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
-dependencies = [
- "memchr",
- "serde",
-]
-
[[package]]
name = "is-terminal"
version = "0.4.16"
@@ -2263,31 +1168,12 @@ dependencies = [
"either",
]
-[[package]]
-name = "itertools"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
-dependencies = [
- "either",
-]
-
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
-[[package]]
-name = "jobserver"
-version = "0.1.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
-dependencies = [
- "getrandom 0.3.3",
- "libc",
-]
-
[[package]]
name = "js-sys"
version = "0.3.78"
@@ -2298,21 +1184,6 @@ dependencies = [
"wasm-bindgen",
]
-[[package]]
-name = "jsonwebtoken"
-version = "9.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde"
-dependencies = [
- "base64 0.22.1",
- "js-sys",
- "pem",
- "ring",
- "serde",
- "serde_json",
- "simple_asn1",
-]
-
[[package]]
name = "kqueue"
version = "1.1.1"
@@ -2339,27 +1210,11 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
[[package]]
name = "libc"
-version = "0.2.175"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
-
-[[package]]
-name = "libloading"
-version = "0.8.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
-dependencies = [
- "cfg-if",
- "windows-targets 0.53.3",
-]
+version = "0.2.175"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libredox"
@@ -2383,12 +1238,6 @@ dependencies = [
"vcpkg",
]
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
-
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
@@ -2417,21 +1266,6 @@ version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
-[[package]]
-name = "lru"
-version = "0.12.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
-dependencies = [
- "hashbrown 0.15.5",
-]
-
-[[package]]
-name = "lru-slab"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
-
[[package]]
name = "md-5"
version = "0.10.6"
@@ -2448,28 +1282,6 @@ version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
-[[package]]
-name = "mime"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-
-[[package]]
-name = "mime_guess"
-version = "2.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
-dependencies = [
- "mime",
- "unicase",
-]
-
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@@ -2502,16 +1314,6 @@ dependencies = [
"windows-sys 0.59.0",
]
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
[[package]]
name = "notify"
version = "6.1.1"
@@ -2542,31 +1344,6 @@ dependencies = [
"notify",
]
-[[package]]
-name = "num-bigint"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
-dependencies = [
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-conv"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-
-[[package]]
-name = "num-integer"
-version = "0.1.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
-dependencies = [
- "num-traits",
-]
-
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -2607,12 +1384,6 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
-[[package]]
-name = "openssl-probe"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
-
[[package]]
name = "oslog"
version = "0.2.0"
@@ -2624,23 +1395,6 @@ dependencies = [
"log",
]
-[[package]]
-name = "outref"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
-
-[[package]]
-name = "p256"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594"
-dependencies = [
- "ecdsa",
- "elliptic-curve",
- "sha2",
-]
-
[[package]]
name = "parking_lot"
version = "0.12.4"
@@ -2676,25 +1430,6 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
-[[package]]
-name = "pem"
-version = "3.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3"
-dependencies = [
- "base64 0.22.1",
- "serde",
-]
-
-[[package]]
-name = "pem-rfc7468"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
-dependencies = [
- "base64ct",
-]
-
[[package]]
name = "percent-encoding"
version = "2.3.2"
@@ -2713,26 +1448,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-[[package]]
-name = "pkcs8"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
-dependencies = [
- "der 0.6.1",
- "spki 0.6.0",
-]
-
-[[package]]
-name = "pkcs8"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
-dependencies = [
- "der 0.7.10",
- "spki 0.7.3",
-]
-
[[package]]
name = "pkg-config"
version = "0.3.32"
@@ -2754,31 +1469,6 @@ dependencies = [
"zerovec",
]
-[[package]]
-name = "powerfmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
-dependencies = [
- "zerocopy",
-]
-
-[[package]]
-name = "prettyplease"
-version = "0.2.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
-dependencies = [
- "proc-macro2",
- "syn 2.0.106",
-]
-
[[package]]
name = "proc-macro2"
version = "1.0.101"
@@ -2788,61 +1478,6 @@ dependencies = [
"unicode-ident",
]
-[[package]]
-name = "quinn"
-version = "0.11.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
-dependencies = [
- "bytes",
- "cfg_aliases",
- "pin-project-lite",
- "quinn-proto",
- "quinn-udp",
- "rustc-hash 2.1.1",
- "rustls 0.23.31",
- "socket2 0.6.0",
- "thiserror 2.0.16",
- "tokio",
- "tracing",
- "web-time",
-]
-
-[[package]]
-name = "quinn-proto"
-version = "0.11.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
-dependencies = [
- "bytes",
- "getrandom 0.3.3",
- "lru-slab",
- "rand",
- "ring",
- "rustc-hash 2.1.1",
- "rustls 0.23.31",
- "rustls-pki-types",
- "slab",
- "thiserror 2.0.16",
- "tinyvec",
- "tracing",
- "web-time",
-]
-
-[[package]]
-name = "quinn-udp"
-version = "0.5.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
-dependencies = [
- "cfg_aliases",
- "libc",
- "once_cell",
- "socket2 0.6.0",
- "tracing",
- "windows-sys 0.60.2",
-]
-
[[package]]
name = "quote"
version = "1.0.40"
@@ -2858,44 +1493,6 @@ version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
-[[package]]
-name = "rand"
-version = "0.9.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
-dependencies = [
- "rand_chacha",
- "rand_core 0.9.3",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.9.3",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom 0.2.16",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
-dependencies = [
- "getrandom 0.3.3",
-]
-
[[package]]
name = "redox_syscall"
version = "0.5.17"
@@ -2928,88 +1525,12 @@ dependencies = [
"regex-syntax",
]
-[[package]]
-name = "regex-lite"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30"
-
[[package]]
name = "regex-syntax"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
-[[package]]
-name = "reqwest"
-version = "0.12.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb"
-dependencies = [
- "base64 0.22.1",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "http 1.3.1",
- "http-body 1.0.1",
- "http-body-util",
- "hyper 1.7.0",
- "hyper-rustls 0.27.7",
- "hyper-util",
- "js-sys",
- "log",
- "mime",
- "mime_guess",
- "percent-encoding",
- "pin-project-lite",
- "quinn",
- "rustls 0.23.31",
- "rustls-pki-types",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper",
- "tokio",
- "tokio-rustls 0.26.2",
- "tokio-util",
- "tower",
- "tower-http",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-streams",
- "web-sys",
- "webpki-roots 1.0.2",
-]
-
-[[package]]
-name = "reqwest-middleware"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e"
-dependencies = [
- "anyhow",
- "async-trait",
- "http 1.3.1",
- "reqwest",
- "serde",
- "thiserror 1.0.69",
- "tower-service",
-]
-
-[[package]]
-name = "rfc6979"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
-dependencies = [
- "crypto-bigint 0.4.9",
- "hmac",
- "zeroize",
-]
-
[[package]]
name = "ring"
version = "0.17.14"
@@ -3044,40 +1565,6 @@ version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
-[[package]]
-name = "rustc-hash"
-version = "2.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
-
-[[package]]
-name = "rustc_version"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
-dependencies = [
- "semver",
-]
-
-[[package]]
-name = "rustix"
-version = "0.38.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
-dependencies = [
- "bitflags 2.9.4",
- "errno",
- "libc",
- "linux-raw-sys 0.4.15",
- "windows-sys 0.59.0",
-]
-
[[package]]
name = "rustix"
version = "1.0.8"
@@ -3087,69 +1574,23 @@ dependencies = [
"bitflags 2.9.4",
"errno",
"libc",
- "linux-raw-sys 0.9.4",
+ "linux-raw-sys",
"windows-sys 0.60.2",
]
[[package]]
-name = "rustls"
-version = "0.21.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
-dependencies = [
- "log",
- "ring",
- "rustls-webpki 0.101.7",
- "sct",
-]
-
-[[package]]
-name = "rustls"
-version = "0.23.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
-dependencies = [
- "aws-lc-rs",
- "log",
- "once_cell",
- "ring",
- "rustls-pki-types",
- "rustls-webpki 0.103.4",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "rustls-native-certs"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
-dependencies = [
- "openssl-probe",
- "rustls-pemfile",
- "schannel",
- "security-framework 2.11.1",
-]
-
-[[package]]
-name = "rustls-native-certs"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
-dependencies = [
- "openssl-probe",
- "rustls-pki-types",
- "schannel",
- "security-framework 3.4.0",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "1.0.4"
+name = "rustls"
+version = "0.23.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
+checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
dependencies = [
- "base64 0.21.7",
+ "log",
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
]
[[package]]
@@ -3158,27 +1599,15 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
dependencies = [
- "web-time",
"zeroize",
]
-[[package]]
-name = "rustls-webpki"
-version = "0.101.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
-dependencies = [
- "ring",
- "untrusted",
-]
-
[[package]]
name = "rustls-webpki"
version = "0.103.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
dependencies = [
- "aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@@ -3205,81 +1634,12 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "schannel"
-version = "0.1.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-[[package]]
-name = "sct"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
-name = "sec1"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
-dependencies = [
- "base16ct",
- "der 0.6.1",
- "generic-array",
- "pkcs8 0.9.0",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "security-framework"
-version = "2.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
-dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.9.4",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework"
-version = "3.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640"
-dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.10.1",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
[[package]]
name = "semver"
version = "1.0.26"
@@ -3330,18 +1690,6 @@ dependencies = [
"serde",
]
-[[package]]
-name = "serde_urlencoded"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
-dependencies = [
- "form_urlencoded",
- "itoa",
- "ryu",
- "serde",
-]
-
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
@@ -3391,17 +1739,6 @@ dependencies = [
"digest",
]
-[[package]]
-name = "sha2"
-version = "0.10.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest",
-]
-
[[package]]
name = "shlex"
version = "1.3.0"
@@ -3417,28 +1754,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "signature"
-version = "1.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
-dependencies = [
- "digest",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "simple_asn1"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb"
-dependencies = [
- "num-bigint",
- "num-traits",
- "thiserror 2.0.16",
- "time",
-]
-
[[package]]
name = "slab"
version = "0.4.11"
@@ -3451,16 +1766,6 @@ version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
-[[package]]
-name = "socket2"
-version = "0.5.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
-dependencies = [
- "libc",
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "socket2"
version = "0.6.0"
@@ -3471,26 +1776,6 @@ dependencies = [
"windows-sys 0.59.0",
]
-[[package]]
-name = "spki"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
-dependencies = [
- "base64ct",
- "der 0.6.1",
-]
-
-[[package]]
-name = "spki"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
-dependencies = [
- "base64ct",
- "der 0.7.10",
-]
-
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
@@ -3568,15 +1853,6 @@ dependencies = [
"unicode-ident",
]
-[[package]]
-name = "sync_wrapper"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
-dependencies = [
- "futures-core",
-]
-
[[package]]
name = "synstructure"
version = "0.13.2"
@@ -3595,13 +1871,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b010f5ebe51e88ae490691ed2a43b699e3468c8e3838e244accd8526aca7751b"
dependencies = [
"anyhow",
- "aws-config",
- "aws-credential-types",
- "aws-sdk-s3",
"byteorder",
"chrono",
"flate2",
- "google-cloud-storage",
"log",
"ring",
"rusqlite",
@@ -3610,7 +1882,6 @@ dependencies = [
"strum 0.27.2",
"strum_macros 0.27.2",
"thiserror 2.0.16",
- "tokio",
"ureq",
"url",
"uuid",
@@ -3627,6 +1898,7 @@ dependencies = [
"serde",
"serde_json",
"taskchampion",
+ "thiserror 1.0.69",
"tokio",
"uuid",
]
@@ -3640,7 +1912,7 @@ dependencies = [
"fastrand",
"getrandom 0.3.3",
"once_cell",
- "rustix 1.0.8",
+ "rustix",
"windows-sys 0.60.2",
]
@@ -3693,36 +1965,6 @@ dependencies = [
"num_cpus",
]
-[[package]]
-name = "time"
-version = "0.3.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031"
-dependencies = [
- "deranged",
- "num-conv",
- "powerfmt",
- "serde",
- "time-core",
- "time-macros",
-]
-
-[[package]]
-name = "time-core"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
-
-[[package]]
-name = "time-macros"
-version = "0.2.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
-dependencies = [
- "num-conv",
- "time-core",
-]
-
[[package]]
name = "tinystr"
version = "0.8.1"
@@ -3733,21 +1975,6 @@ dependencies = [
"zerovec",
]
-[[package]]
-name = "tinyvec"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
-dependencies = [
- "tinyvec_macros",
-]
-
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-
[[package]]
name = "tokio"
version = "1.47.1"
@@ -3763,7 +1990,7 @@ dependencies = [
"pin-project-lite",
"signal-hook-registry",
"slab",
- "socket2 0.6.0",
+ "socket2",
"tokio-macros",
"windows-sys 0.59.0",
]
@@ -3779,39 +2006,6 @@ dependencies = [
"syn 2.0.106",
]
-[[package]]
-name = "tokio-rustls"
-version = "0.24.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
-dependencies = [
- "rustls 0.21.12",
- "tokio",
-]
-
-[[package]]
-name = "tokio-rustls"
-version = "0.26.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
-dependencies = [
- "rustls 0.23.31",
- "tokio",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
-]
-
[[package]]
name = "toml"
version = "0.5.11"
@@ -3868,100 +2062,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
-[[package]]
-name = "tower"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
-dependencies = [
- "futures-core",
- "futures-util",
- "pin-project-lite",
- "sync_wrapper",
- "tokio",
- "tower-layer",
- "tower-service",
-]
-
-[[package]]
-name = "tower-http"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
-dependencies = [
- "bitflags 2.9.4",
- "bytes",
- "futures-util",
- "http 1.3.1",
- "http-body 1.0.1",
- "iri-string",
- "pin-project-lite",
- "tower",
- "tower-layer",
- "tower-service",
-]
-
-[[package]]
-name = "tower-layer"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
-
-[[package]]
-name = "tower-service"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
-
-[[package]]
-name = "tracing"
-version = "0.1.41"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
-dependencies = [
- "pin-project-lite",
- "tracing-attributes",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-attributes"
-version = "0.1.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "tracing-core"
-version = "0.1.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
-dependencies = [
- "once_cell",
-]
-
-[[package]]
-name = "try-lock"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
-
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
-[[package]]
-name = "unicase"
-version = "2.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
-
[[package]]
name = "unicode-ident"
version = "1.0.18"
@@ -3998,11 +2104,11 @@ version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
dependencies = [
- "base64 0.22.1",
+ "base64",
"flate2",
"log",
"once_cell",
- "rustls 0.23.31",
+ "rustls",
"rustls-pki-types",
"url",
"webpki-roots 0.26.11",
@@ -4020,12 +2126,6 @@ dependencies = [
"serde",
]
-[[package]]
-name = "urlencoding"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
-
[[package]]
name = "utf8_iter"
version = "1.0.4"
@@ -4062,12 +2162,6 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
-[[package]]
-name = "vsimd"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
-
[[package]]
name = "walkdir"
version = "2.5.0"
@@ -4078,15 +2172,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "want"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
-dependencies = [
- "try-lock",
-]
-
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
@@ -4174,19 +2259,6 @@ dependencies = [
"unicode-ident",
]
-[[package]]
-name = "wasm-streams"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
-dependencies = [
- "futures-util",
- "js-sys",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
-]
-
[[package]]
name = "web-sys"
version = "0.3.78"
@@ -4225,18 +2297,6 @@ dependencies = [
"rustls-pki-types",
]
-[[package]]
-name = "which"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
-dependencies = [
- "either",
- "home",
- "once_cell",
- "rustix 0.38.44",
-]
-
[[package]]
name = "winapi"
version = "0.3.9"
@@ -4570,12 +2630,6 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
-[[package]]
-name = "xmlparser"
-version = "0.13.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
-
[[package]]
name = "yoke"
version = "0.8.0"
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index 934ed553..80228819 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -1,19 +1,26 @@
[package]
name = "tc_helper"
version = "0.1.0"
-edition = "2024"
+edition = "2021"
[lib]
name="tc_helper"
crate-type=["staticlib","cdylib"]
[dependencies]
-taskchampion = "2.0.3"
+# Only the "server-sync" backend (the remote TaskChampion sync server, used by
+# our sync_() via ServerConfig::Remote) — NOT server-aws / server-gcp. Those
+# cloud backends dragged in the AWS + Google-Cloud SDKs → aws-lc-rs/aws-lc-sys,
+# which (a) bloats the binary, (b) needs bindgen for 32-bit ARM, and (c) fails
+# to cross-compile for iOS. server-sync uses ureq + ring, which build cleanly
+# on every target. `bundled` keeps SQLite compiled in.
+taskchampion = { version = "2.0.3", default-features = false, features = ["server-sync", "bundled"] }
anyhow = "1.0"
tokio = { version = "1.40", features = ["full"] }
uuid = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
+thiserror = "1.0" # Structured, typed error handling
flutter_rust_bridge = "=2.11.1" # Rust runtime bridge
flutter_rust_bridge_macros = "2.11.1" # Procedural macros support
diff --git a/rust/build.rs b/rust/build.rs
new file mode 100644
index 00000000..a66a62ab
--- /dev/null
+++ b/rust/build.rs
@@ -0,0 +1,53 @@
+use std::env;
+use std::process::Command;
+
+/// Build script for `tc_helper`.
+///
+/// * Rebuilds whenever anything under `src/` changes so the FFI stays in sync.
+/// * Detects the target platform and exposes it as a build-time note.
+/// * Optionally regenerates the flutter_rust_bridge bindings when the
+/// `FRB_CODEGEN=1` environment variable is set, so contributors can refresh
+/// bindings from a plain `cargo build` without memorising the CLI flags.
+/// (It is opt-in so ordinary/CI builds never shell out to the codegen tool.)
+fn main() {
+ println!("cargo:rerun-if-changed=src/");
+ println!("cargo:rerun-if-env-changed=FRB_CODEGEN");
+
+ let target = env::var("TARGET").unwrap_or_default();
+ let platform = if target.contains("android") {
+ "android"
+ } else if target.contains("apple-ios") {
+ "ios"
+ } else if target.contains("apple-darwin") {
+ "macos"
+ } else if target.contains("linux") {
+ "linux"
+ } else if target.contains("windows") {
+ "windows"
+ } else {
+ "unknown"
+ };
+ // Expose the detected platform as a compile-time env var (readable via
+ // env!("TC_HELPER_PLATFORM")) instead of a per-build warning, so ordinary
+ // builds stay quiet.
+ println!("cargo:rustc-env=TC_HELPER_PLATFORM={platform}");
+
+ if env::var("FRB_CODEGEN").as_deref() == Ok("1") {
+ let status = Command::new("flutter_rust_bridge_codegen")
+ .args([
+ "generate",
+ "--rust-input",
+ "crate::api",
+ "--rust-root",
+ ".",
+ "--dart-output",
+ "../lib/rust_bridge",
+ ])
+ .status();
+ match status {
+ Ok(s) if s.success() => println!("cargo:warning=flutter_rust_bridge bindings regenerated"),
+ Ok(s) => println!("cargo:warning=flutter_rust_bridge_codegen exited with {s}"),
+ Err(e) => println!("cargo:warning=could not run flutter_rust_bridge_codegen: {e}"),
+ }
+ }
+}
diff --git a/rust/src/api.rs b/rust/src/api.rs
index 5ee13205..87a6dfe4 100644
--- a/rust/src/api.rs
+++ b/rust/src/api.rs
@@ -1,11 +1,14 @@
use flutter_rust_bridge::frb;
+use std::{collections::HashMap, str::FromStr};
use taskchampion::{
chrono::{DateTime, Utc},
- Operations, Replica, ServerConfig, StorageConfig, Tag,
+ Operations, Tag, ServerConfig,
};
use uuid::Uuid;
-use std::{collections::HashMap, path::PathBuf, str::FromStr};
-use serde_json;
+
+use crate::serialize::task_to_json;
+use crate::storage::open_replica;
+use crate::utils::error::TcHelperError;
fn parse_datetime(input: &str) -> Option> {
if input.trim().is_empty() {
@@ -14,90 +17,69 @@ fn parse_datetime(input: &str) -> Option> {
input.parse::>().ok()
}
+/// Return every task in the replica as a JSON array string.
#[frb]
-pub fn get_all_tasks_json(taskdb_dir_path: String) -> Result {
- let tasks = get_all_tasks(taskdb_dir_path); // your Vec>
- let json = serde_json::to_string(&tasks)
- .map_err(|e| taskchampion::Error::Other(anyhow::anyhow!(e)))?;
- Ok(json)
+pub fn get_all_tasks_json(taskdb_dir_path: String) -> Result {
+ get_all_tasks_json_impl(&taskdb_dir_path).map_err(|e| e.to_string())
}
-fn get_all_tasks(taskdb_dir_path: String) -> Vec> {
- let taskdb_dir = PathBuf::from(taskdb_dir_path);
- let storage = StorageConfig::OnDisk {
- taskdb_dir,
- create_if_missing: true,
- access_mode: taskchampion::storage::AccessMode::ReadWrite,
- }
- .into_storage()
- .unwrap();
-
- let mut replica = Replica::new(storage);
- let mut vector: Vec> = Vec::new();
+fn get_all_tasks_json_impl(taskdb_dir_path: &str) -> Result {
+ let mut replica = open_replica(taskdb_dir_path)?;
+ let tasks = replica
+ .all_tasks()
+ .map_err(|e| TcHelperError::Champion(e.to_string()))?;
- for (_, value) in replica.all_tasks().unwrap() {
- let mut map: HashMap = HashMap::new();
- let mut tags = "".to_string();
-
- for (k, v) in value.get_taskmap() {
- if k.contains("tag_") {
- if let Some(stripped) = k.strip_prefix("tag_") {
- tags.push_str(stripped);
- tags.push(' ');
- }
- } else {
- map.insert(k.into(), v.into());
- }
- }
- map.insert("tags".into(), tags.trim().into());
- map.insert("uuid".into(), value.get_uuid().to_string());
- vector.push(map);
- }
- vector
+ let json_tasks: Vec = tasks.values().map(task_to_json).collect();
+ Ok(serde_json::to_string(&json_tasks)?)
}
+/// Delete the task with the given UUID. A no-op if the task does not exist.
#[frb]
-pub fn delete_task(uuid_st: String, taskdb_dir_path: String) -> i8 {
- let taskdb_dir = PathBuf::from(taskdb_dir_path);
- let storage = StorageConfig::OnDisk {
- taskdb_dir,
- create_if_missing: true,
- access_mode: taskchampion::storage::AccessMode::ReadWrite,
- }
- .into_storage()
- .unwrap();
+pub fn delete_task(uuid_st: String, taskdb_dir_path: String) -> Result<(), String> {
+ delete_task_impl(&uuid_st, &taskdb_dir_path).map_err(|e| e.to_string())
+}
- let mut replica = Replica::new(storage);
+fn delete_task_impl(uuid_st: &str, taskdb_dir_path: &str) -> Result<(), TcHelperError> {
+ let mut replica = open_replica(taskdb_dir_path)?;
let mut ops = Operations::new();
- let uuid = Uuid::parse_str(&uuid_st).unwrap();
+ let uuid = Uuid::parse_str(uuid_st).map_err(|_| TcHelperError::InvalidUuid(uuid_st.to_string()))?;
- if let Some(mut t) = replica.get_task_data(uuid).unwrap() {
+ if let Some(mut t) = replica
+ .get_task_data(uuid)
+ .map_err(|e| TcHelperError::Champion(e.to_string()))?
+ {
t.delete(&mut ops);
}
- replica.commit_operations(ops).unwrap();
- 0
+ replica
+ .commit_operations(ops)
+ .map_err(|e| TcHelperError::Commit(e.to_string()))?;
+ Ok(())
}
+/// Update the mutable fields of an existing task from the supplied key/value map.
#[frb]
pub fn update_task(
uuid_st: String,
taskdb_dir_path: String,
map: HashMap,
-) -> i8 {
- let taskdb_dir = PathBuf::from(taskdb_dir_path);
- let storage = StorageConfig::OnDisk {
- taskdb_dir,
- create_if_missing: true,
- access_mode: taskchampion::storage::AccessMode::ReadWrite,
- }
- .into_storage()
- .unwrap();
+) -> Result<(), String> {
+ update_task_impl(&uuid_st, &taskdb_dir_path, map).map_err(|e| e.to_string())
+}
- let mut replica = Replica::new(storage);
+#[allow(deprecated)] // `get_taskmap` is deprecated upstream; used to enumerate existing tags.
+fn update_task_impl(
+ uuid_st: &str,
+ taskdb_dir_path: &str,
+ map: HashMap,
+) -> Result<(), TcHelperError> {
+ let mut replica = open_replica(taskdb_dir_path)?;
let mut ops = Operations::new();
- let uuid = Uuid::parse_str(&uuid_st).unwrap();
+ let uuid = Uuid::parse_str(uuid_st).map_err(|_| TcHelperError::InvalidUuid(uuid_st.to_string()))?;
- if let Some(mut t) = replica.get_task(uuid).unwrap() {
+ if let Some(mut t) = replica
+ .get_task(uuid)
+ .map_err(|e| TcHelperError::Champion(e.to_string()))?
+ {
let _ = t.set_status(taskchampion::Status::Pending, &mut ops);
for (key, value) in map {
match key.as_str() {
@@ -121,21 +103,20 @@ pub fn update_task(
let _ = t.set_priority(value, &mut ops);
}
"tags" => {
- let existing_tags: Vec = t
- .get_taskmap()
- .iter()
- .filter_map(|(k, _)| k.strip_prefix("tag_").map(|s| s.to_string()))
- .collect();
- for tag_name in existing_tags {
- println!("removing tag at rust side {}", tag_name);
- let mut tag = Tag::from_str(&tag_name).unwrap();
- let _ = t.remove_tag(&mut tag, &mut ops);
- }
-
- for part in value.split_whitespace() {
- println!("tag at rust side {}", part);
- let mut tag = Tag::from_str(part).unwrap();
- let _ = t.add_tag(&mut tag, &mut ops);
+ let existing_tags: Vec = t
+ .get_taskmap()
+ .iter()
+ .filter_map(|(k, _)| k.strip_prefix("tag_").map(|s| s.to_string()))
+ .collect();
+ for tag_name in existing_tags {
+ if let Ok(mut tag) = Tag::from_str(&tag_name) {
+ let _ = t.remove_tag(&mut tag, &mut ops);
+ }
+ }
+ for part in value.split_whitespace() {
+ if let Ok(mut tag) = Tag::from_str(part) {
+ let _ = t.add_tag(&mut tag, &mut ops);
+ }
}
}
"project" => {
@@ -148,35 +129,37 @@ pub fn update_task(
"deleted" => taskchampion::Status::Deleted,
_ => taskchampion::Status::Pending,
};
- // print!("status at rust side {}", value);
- println!("status at rust side {}", value);
let _ = t.set_status(status, &mut ops);
}
_ => {}
}
}
- replica.commit_operations(ops).unwrap();
+ replica
+ .commit_operations(ops)
+ .map_err(|e| TcHelperError::Commit(e.to_string()))?;
}
- 0
+ Ok(())
}
+/// Create a new task from the supplied key/value map. The map must contain a
+/// `uuid` entry.
#[frb]
-pub fn add_task(taskdb_dir_path: String, map: HashMap) -> i8 {
- let taskdb_dir = PathBuf::from(taskdb_dir_path);
- let storage = StorageConfig::OnDisk {
- taskdb_dir,
- create_if_missing: true,
- access_mode: taskchampion::storage::AccessMode::ReadWrite,
- }
- .into_storage()
- .unwrap();
+pub fn add_task(taskdb_dir_path: String, map: HashMap) -> Result<(), String> {
+ add_task_impl(&taskdb_dir_path, map).map_err(|e| e.to_string())
+}
- let mut replica = Replica::new(storage);
+fn add_task_impl(taskdb_dir_path: &str, map: HashMap) -> Result<(), TcHelperError> {
+ let mut replica = open_replica(taskdb_dir_path)?;
let mut ops = Operations::new();
- if let Some(uuid_str) = map.get("uuid") {
- let uuid = Uuid::parse_str(&uuid_str).unwrap();
- let mut t = replica.create_task(uuid, &mut ops).unwrap();
+ let uuid_str = map
+ .get("uuid")
+ .ok_or_else(|| TcHelperError::InvalidUuid("".to_string()))?;
+ let uuid = Uuid::parse_str(uuid_str).map_err(|_| TcHelperError::InvalidUuid(uuid_str.clone()))?;
+
+ let mut t = replica
+ .create_task(uuid, &mut ops)
+ .map_err(|e| TcHelperError::Champion(e.to_string()))?;
let _ = t.set_status(taskchampion::Status::Pending, &mut ops);
for (key, value) in map {
@@ -198,8 +181,9 @@ pub fn add_task(taskdb_dir_path: String, map: HashMap) -> i8 {
}
"tags" => {
for part in value.split_whitespace() {
- let mut tag = Tag::from_str(part).unwrap();
- let _ = t.add_tag(&mut tag, &mut ops);
+ if let Ok(mut tag) = Tag::from_str(part) {
+ let _ = t.add_tag(&mut tag, &mut ops);
+ }
}
}
"project" => {
@@ -208,43 +192,53 @@ pub fn add_task(taskdb_dir_path: String, map: HashMap) -> i8 {
_ => {}
}
}
- replica.commit_operations(ops).unwrap();
- return 0;
-}
- 1
+ replica
+ .commit_operations(ops)
+ .map_err(|e| TcHelperError::Commit(e.to_string()))?;
+ Ok(())
}
+/// Synchronise the local replica with a remote TaskChampion sync server.
#[frb]
pub async fn sync(
taskdb_dir_path: String,
url: String,
client_id: String,
encryption_secret: String,
-) -> i8 {
- let taskdb_dir = PathBuf::from(taskdb_dir_path);
- let storage = StorageConfig::OnDisk {
- taskdb_dir,
- create_if_missing: true,
- access_mode: taskchampion::storage::AccessMode::ReadWrite,
- }
- .into_storage()
- .unwrap();
+) -> Result<(), String> {
+ sync_impl(&taskdb_dir_path, url, &client_id, encryption_secret).map_err(|e| e.to_string())
+}
+
+fn sync_impl(
+ taskdb_dir_path: &str,
+ url: String,
+ client_id: &str,
+ encryption_secret: String,
+) -> Result<(), TcHelperError> {
+ let mut replica = open_replica(taskdb_dir_path)?;
+ let client_uuid =
+ Uuid::parse_str(client_id).map_err(|_| TcHelperError::InvalidUuid(client_id.to_string()))?;
- let mut replica = Replica::new(storage);
let config = ServerConfig::Remote {
url: url.into(),
- client_id: Uuid::parse_str(&client_id).unwrap(),
+ client_id: client_uuid,
encryption_secret: encryption_secret.into(),
};
- let mut server = config.into_server().unwrap();
- replica.sync(&mut server, false).unwrap();
- 0
+ let mut server = config
+ .into_server()
+ .map_err(|e| TcHelperError::Sync(e.to_string()))?;
+ replica
+ .sync(&mut server, false)
+ .map_err(|e| TcHelperError::Sync(e.to_string()))?;
+ Ok(())
}
#[test]
fn test_add_task_with_tags() {
use std::{collections::HashMap, env, fs};
+ use serde_json::Value;
+
// create unique temporary directory for taskdb
let tmp = env::temp_dir().join(format!("taskdb_test_{}", Uuid::new_v4()));
let taskdb_path = tmp.to_string_lossy().into_owned();
@@ -258,19 +252,96 @@ fn test_add_task_with_tags() {
map.insert("tags".to_string(), "tag1 tag2".to_string());
// add task
- let res = add_task(taskdb_path.clone(), map);
- assert_eq!(res, 0);
+ add_task(taskdb_path.clone(), map).expect("add_task");
- // read tasks as json and verify tags are present
+ // read tasks as json and verify the surfaced attributes
let json = get_all_tasks_json(taskdb_path.clone()).expect("get_all_tasks_json");
- let tasks: Vec> = serde_json::from_str(&json).expect("parse json");
- let found = tasks.into_iter().find(|m| m.get("uuid").map(|s| s == &uuid).unwrap_or(false));
- assert!(found.is_some(), "task with uuid not found");
- let task = found.unwrap();
- let tags = task.get("tags").map(|s| s.as_str()).unwrap_or("");
+ let tasks: Vec = serde_json::from_str(&json).expect("parse json");
+ let task = tasks
+ .into_iter()
+ .find(|t| t.get("uuid").and_then(|u| u.as_str()) == Some(uuid.as_str()))
+ .expect("task with uuid not found");
+
+ let tags = task.get("tags").and_then(|t| t.as_str()).unwrap_or("");
assert!(tags.contains("tag1"), "tag1 missing in tags: {}", tags);
assert!(tags.contains("tag2"), "tag2 missing in tags: {}", tags);
+ // newly surfaced attributes should be present with sensible defaults
+ assert!(task.get("annotations").map(|v| v.is_array()).unwrap_or(false));
+ assert!(task.get("depends").map(|v| v.is_array()).unwrap_or(false));
+ assert_eq!(task.get("is_blocked").and_then(|v| v.as_bool()), Some(false));
+ assert_eq!(task.get("is_blocking").and_then(|v| v.as_bool()), Some(false));
+
// cleanup
fs::remove_dir_all(&tmp).ok();
}
+
+#[test]
+fn test_dependencies_and_annotations_surface() {
+ // Exercises the POPULATED cases of the enriched serializer: a real
+ // dependency (A depends on B) must surface as depends[]/is_blocked/is_blocking,
+ // and an annotation must surface as {entry (RFC3339), description}.
+ use std::{env, fs};
+ use serde_json::Value;
+ use taskchampion::{chrono::{DateTime, Utc}, Annotation, Operations, Status};
+
+ let tmp = env::temp_dir().join(format!("taskdb_deptest_{}", Uuid::new_v4()));
+ let taskdb_path = tmp.to_string_lossy().into_owned();
+ fs::create_dir_all(&tmp).expect("create temp taskdb dir");
+
+ let uuid_a = Uuid::new_v4(); // dependent task
+ let uuid_b = Uuid::new_v4(); // blocker task
+
+ {
+ let mut replica = open_replica(&taskdb_path).expect("open replica");
+ let mut ops = Operations::new();
+
+ let mut b = replica.create_task(uuid_b, &mut ops).expect("create B");
+ let _ = b.set_status(Status::Pending, &mut ops);
+ let _ = b.set_description("blocker".to_string(), &mut ops);
+
+ let mut a = replica.create_task(uuid_a, &mut ops).expect("create A");
+ let _ = a.set_status(Status::Pending, &mut ops);
+ let _ = a.set_description("dependent".to_string(), &mut ops);
+ a.add_dependency(uuid_b, &mut ops).expect("add dependency A->B");
+ a.add_annotation(
+ Annotation { entry: Utc::now(), description: "note-one".to_string() },
+ &mut ops,
+ ).expect("add annotation");
+
+ replica.commit_operations(ops).expect("commit");
+ }
+
+ // Read back through the SAME path the app uses (fresh replica + all_tasks()).
+ let json = get_all_tasks_json(taskdb_path.clone()).expect("get_all_tasks_json");
+ let tasks: Vec = serde_json::from_str(&json).expect("parse json");
+ let find = |u: &Uuid| {
+ tasks
+ .iter()
+ .find(|t| t.get("uuid").and_then(|v| v.as_str()) == Some(u.to_string().as_str()))
+ .cloned()
+ .expect("task present")
+ };
+ let a = find(&uuid_a);
+ let b = find(&uuid_b);
+
+ // A depends on B → depends[] carries B, and A is blocked (unresolved dep).
+ let deps: Vec = a["depends"].as_array().unwrap()
+ .iter().map(|v| v.as_str().unwrap().to_string()).collect();
+ assert!(deps.contains(&uuid_b.to_string()), "A.depends must contain B: {:?}", deps);
+ assert_eq!(a["is_blocked"].as_bool(), Some(true), "A must be blocked");
+ assert_eq!(a["is_blocking"].as_bool(), Some(false), "A must not be blocking");
+
+ // A's annotation surfaces with description + RFC3339 entry.
+ let anns = a["annotations"].as_array().unwrap();
+ assert_eq!(anns.len(), 1, "A must have one annotation");
+ assert_eq!(anns[0]["description"].as_str(), Some("note-one"));
+ let entry = anns[0]["entry"].as_str().unwrap();
+ assert!(DateTime::parse_from_rfc3339(entry).is_ok(), "entry must be RFC3339: {}", entry);
+
+ // B is depended-upon → B is blocking, not blocked.
+ assert_eq!(b["is_blocking"].as_bool(), Some(true), "B must be blocking");
+ assert_eq!(b["is_blocked"].as_bool(), Some(false), "B must not be blocked");
+
+ fs::remove_dir_all(&tmp).ok();
+}
diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs
index 9f690200..8590af35 100644
--- a/rust/src/frb_generated.rs
+++ b/rust/src/frb_generated.rs
@@ -72,9 +72,8 @@ fn wire__crate__api__add_task_impl(
>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
- transform_result_sse::<_, ()>((move || {
- let output_ok =
- Result::<_, ()>::Ok(crate::api::add_task(api_taskdb_dir_path, api_map))?;
+ transform_result_sse::<_, String>((move || {
+ let output_ok = crate::api::add_task(api_taskdb_dir_path, api_map)?;
Ok(output_ok)
})())
}
@@ -107,11 +106,8 @@ fn wire__crate__api__delete_task_impl(
let api_taskdb_dir_path = ::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
- transform_result_sse::<_, ()>((move || {
- let output_ok = Result::<_, ()>::Ok(crate::api::delete_task(
- api_uuid_st,
- api_taskdb_dir_path,
- ))?;
+ transform_result_sse::<_, String>((move || {
+ let output_ok = crate::api::delete_task(api_uuid_st, api_taskdb_dir_path)?;
Ok(output_ok)
})())
}
@@ -143,12 +139,10 @@ fn wire__crate__api__get_all_tasks_json_impl(
let api_taskdb_dir_path = ::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
- transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
- (move || {
- let output_ok = crate::api::get_all_tasks_json(api_taskdb_dir_path)?;
- Ok(output_ok)
- })(),
- )
+ transform_result_sse::<_, String>((move || {
+ let output_ok = crate::api::get_all_tasks_json(api_taskdb_dir_path)?;
+ Ok(output_ok)
+ })())
}
},
)
@@ -181,17 +175,15 @@ fn wire__crate__api__sync_impl(
let api_encryption_secret = ::sse_decode(&mut deserializer);
deserializer.end();
move |context| async move {
- transform_result_sse::<_, ()>(
+ transform_result_sse::<_, String>(
(move || async move {
- let output_ok = Result::<_, ()>::Ok(
- crate::api::sync(
- api_taskdb_dir_path,
- api_url,
- api_client_id,
- api_encryption_secret,
- )
- .await,
- )?;
+ let output_ok = crate::api::sync(
+ api_taskdb_dir_path,
+ api_url,
+ api_client_id,
+ api_encryption_secret,
+ )
+ .await?;
Ok(output_ok)
})()
.await,
@@ -228,12 +220,9 @@ fn wire__crate__api__update_task_impl(
>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
- transform_result_sse::<_, ()>((move || {
- let output_ok = Result::<_, ()>::Ok(crate::api::update_task(
- api_uuid_st,
- api_taskdb_dir_path,
- api_map,
- ))?;
+ transform_result_sse::<_, String>((move || {
+ let output_ok =
+ crate::api::update_task(api_uuid_st, api_taskdb_dir_path, api_map)?;
Ok(output_ok)
})())
}
@@ -243,14 +232,6 @@ fn wire__crate__api__update_task_impl(
// Section: dart2rust
-impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error {
- // Codec=Sse (Serialization based), see doc to use other codecs
- fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
- let mut inner = ::sse_decode(deserializer);
- return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);
- }
-}
-
impl SseDecode for std::collections::HashMap {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -267,13 +248,6 @@ impl SseDecode for String {
}
}
-impl SseDecode for i8 {
- // Codec=Sse (Serialization based), see doc to use other codecs
- fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
- deserializer.cursor.read_i8().unwrap()
- }
-}
-
impl SseDecode for Vec {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -365,13 +339,6 @@ fn pde_ffi_dispatcher_sync_impl(
// Section: rust2dart
-impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error {
- // Codec=Sse (Serialization based), see doc to use other codecs
- fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
- ::sse_encode(format!("{:?}", self), serializer);
- }
-}
-
impl SseEncode for std::collections::HashMap {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
@@ -386,13 +353,6 @@ impl SseEncode for String {
}
}
-impl SseEncode for i8 {
- // Codec=Sse (Serialization based), see doc to use other codecs
- fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
- serializer.cursor.write_i8(self).unwrap();
- }
-}
-
impl SseEncode for Vec {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index b07ba846..a4db1e3d 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -1,2 +1,5 @@
mod frb_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */
-mod api;
\ No newline at end of file
+mod api;
+mod serialize;
+mod storage;
+mod utils;
\ No newline at end of file
diff --git a/rust/src/serialize.rs b/rust/src/serialize.rs
new file mode 100644
index 00000000..18b6b4f3
--- /dev/null
+++ b/rust/src/serialize.rs
@@ -0,0 +1,66 @@
+use serde_json::{json, Value};
+use taskchampion::Task;
+
+/// Serialise a TaskChampion [`Task`] into the JSON object the Flutter layer
+/// consumes.
+///
+/// Beyond the flat properties the previous serialiser emitted, this now
+/// surfaces attributes the Dart model already anticipated but never received:
+///
+/// * `tags` — space-joined user tags (synthetic tags are excluded)
+/// * `annotations` — array of `{ entry, description }` objects
+/// * `depends` — array of dependency UUID strings
+/// * `is_blocked` — whether the task has at least one unresolved dependency
+/// * `is_blocking` — whether at least one other task depends on this one
+/// * `recur` — recurrence rule, when present
+///
+/// `urgency` is intentionally omitted: TaskChampion 2.0.3 does not compute or
+/// store an urgency value on [`Task`], so there is nothing authoritative to
+/// surface here.
+#[allow(deprecated)] // `get_taskmap` is deprecated upstream; retained for the raw property view.
+pub fn task_to_json(task: &Task) -> Value {
+ let mut map = serde_json::Map::new();
+ let mut tags: Vec = Vec::new();
+
+ for (key, value) in task.get_taskmap() {
+ if let Some(tag) = key.strip_prefix("tag_") {
+ // User tags are stored as `tag_` properties.
+ tags.push(tag.to_string());
+ } else if key.starts_with("dep_") || key.starts_with("annotation_") {
+ // Raw dependency/annotation properties are surfaced below as
+ // structured arrays, so skip their flat representation here.
+ continue;
+ } else {
+ // Flat properties (description, status, due, priority, project,
+ // recur, ...) pass straight through as strings.
+ map.insert(key.clone(), Value::String(value.clone()));
+ }
+ }
+
+ let annotations: Vec = task
+ .get_annotations()
+ .map(|a| {
+ json!({
+ // RFC 3339 / ISO-8601 so consumers get an unambiguous,
+ // directly-parseable timestamp (not a bare epoch number).
+ "entry": a.entry.to_rfc3339(),
+ "description": a.description,
+ })
+ })
+ .collect();
+
+ let depends: Vec = task
+ .get_dependencies()
+ .map(|uuid| Value::String(uuid.to_string()))
+ .collect();
+
+ map.insert("uuid".into(), Value::String(task.get_uuid().to_string()));
+ map.insert("tags".into(), Value::String(tags.join(" ")));
+ map.insert("annotations".into(), Value::Array(annotations));
+ map.insert("depends".into(), Value::Array(depends));
+ map.insert("is_blocked".into(), Value::Bool(task.is_blocked()));
+ map.insert("is_blocking".into(), Value::Bool(task.is_blocking()));
+ // `recur` is already carried through the flat-property loop above.
+
+ Value::Object(map)
+}
diff --git a/rust/src/storage.rs b/rust/src/storage.rs
new file mode 100644
index 00000000..ecee1037
--- /dev/null
+++ b/rust/src/storage.rs
@@ -0,0 +1,25 @@
+use std::path::PathBuf;
+use taskchampion::{Replica, StorageConfig};
+
+use crate::utils::error::TcHelperError;
+
+/// Open (creating if necessary) the on-disk TaskChampion replica at
+/// `taskdb_dir_path` in read/write mode.
+///
+/// This centralises the storage-configuration boilerplate that was previously
+/// duplicated across every FFI entry point.
+pub fn open_replica(taskdb_dir_path: &str) -> Result {
+ let taskdb_dir = PathBuf::from(taskdb_dir_path);
+ let storage = StorageConfig::OnDisk {
+ taskdb_dir,
+ create_if_missing: true,
+ access_mode: taskchampion::storage::AccessMode::ReadWrite,
+ }
+ .into_storage()
+ .map_err(|e| TcHelperError::ReplicaOpen {
+ path: taskdb_dir_path.to_string(),
+ message: e.to_string(),
+ })?;
+
+ Ok(Replica::new(storage))
+}
diff --git a/rust/src/utils/error.rs b/rust/src/utils/error.rs
new file mode 100644
index 00000000..a032803b
--- /dev/null
+++ b/rust/src/utils/error.rs
@@ -0,0 +1,29 @@
+use thiserror::Error;
+
+/// Errors raised by the `tc_helper` FFI layer.
+///
+/// Each FFI entry point in [`crate::api`] converts one of these into a plain
+/// error string, which flutter_rust_bridge surfaces to the Dart side as a
+/// thrown exception. Modelling the failure modes as a typed enum keeps the
+/// Rust code free of `.unwrap()` panics and makes the source of a failure
+/// explicit at the call site.
+#[derive(Error, Debug)]
+pub enum TcHelperError {
+ #[error("cannot open replica at '{path}': {message}")]
+ ReplicaOpen { path: String, message: String },
+
+ #[error("invalid UUID '{0}'")]
+ InvalidUuid(String),
+
+ #[error("sync failed: {0}")]
+ Sync(String),
+
+ #[error("task operation failed: {0}")]
+ Commit(String),
+
+ #[error("taskchampion error: {0}")]
+ Champion(String),
+
+ #[error("JSON serialization error: {0}")]
+ Serialization(#[from] serde_json::Error),
+}
diff --git a/rust/src/utils/mod.rs b/rust/src/utils/mod.rs
new file mode 100644
index 00000000..a91e7351
--- /dev/null
+++ b/rust/src/utils/mod.rs
@@ -0,0 +1 @@
+pub mod error;