refactor(shopinbit): drop the single-flight ticket/invoice fetch wrappers
What changed, and why it matters
This commit removes a small performance optimization in the Stack Wallet app's ShopInBit service. Previously, if multiple parts of the app tried to fetch the same ticket list or car-research invoice list at the same time, they would share one network request. After this change, each call goes straight to the API independently. There is no security fix or vulnerability here—it's a straightforward code simplification that may slightly increase API traffic.
No security action required. Treat as a normal refactor; monitor for any user-reported performance regressions in ticket/invoice refresh behavior.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch deletes two single-flight/deduplication wrappers—_ticketsByCustomer and the wrapped version of getCurrentCarResearchInvoices—and replaces their call sites with direct calls to the underlying client.getTicketsByCustomer(key) and client.getCurrentCarResearchInvoices(). The remaining _inFlight map for other operations is untouched. This is a pure refactor with no change to authentication, authorization, input validation, cryptography, or data handling.
Changed components
lib/services/shopinbit/shopinbit_service.dartInspect captured patch +5 / −54
diff --git a/lib/services/shopinbit/shopinbit_service.dart b/lib/services/shopinbit/shopinbit_service.dart
index 107da76..4a7fe79 100644
--- a/lib/services/shopinbit/shopinbit_service.dart
+++ b/lib/services/shopinbit/shopinbit_service.dart
@@ -22,60 +22,9 @@ class ShopInBitService {
final Map<int, Completer<void>> _inFlight = {};
- // Combine concurrent list/invoice fetches the same way _refreshRef does, so
- // overlapping refreshes (e.g. tickets view refresh racing a post-action one)
- // share a single round-trip instead of each hitting the API.
- Completer<ApiResponse<List<TicketRef>>>? _ticketsInFlight;
- String? _ticketsInFlightKey;
- Completer<ApiResponse<List<CarResearchCurrentInvoice>>>? _carInvoicesInFlight;
-
- /// Combined by-customer ticket list fetch. Concurrent calls for the same
- /// key await the same in-flight request.
- Future<ApiResponse<List<TicketRef>>> _ticketsByCustomer(String key) {
- final Completer<ApiResponse<List<TicketRef>>>? pending = _ticketsInFlight;
- if (pending != null && _ticketsInFlightKey == key) {
- return pending.future;
- }
- final Completer<ApiResponse<List<TicketRef>>> completer = Completer();
- _ticketsInFlight = completer;
- _ticketsInFlightKey = key;
- unawaited(
- client
- .getTicketsByCustomer(key)
- .then(completer.complete, onError: completer.completeError)
- .whenComplete(() {
- if (_ticketsInFlight == completer) {
- _ticketsInFlight = null;
- _ticketsInFlightKey = null;
- }
- }),
- );
- return completer.future;
- }
-
- /// Combined wrapper around the current car research invoices fetch. The
- /// tickets view calls this on every refresh, so dedup keeps overlapping
- /// refreshes from each firing their own request.
+ /// Current still-payable car research invoices for the active customer key.
Future<ApiResponse<List<CarResearchCurrentInvoice>>>
- getCurrentCarResearchInvoices() {
- final Completer<ApiResponse<List<CarResearchCurrentInvoice>>>? pending =
- _carInvoicesInFlight;
- if (pending != null) return pending.future;
- final Completer<ApiResponse<List<CarResearchCurrentInvoice>>> completer =
- Completer();
- _carInvoicesInFlight = completer;
- unawaited(
- client
- .getCurrentCarResearchInvoices()
- .then(completer.complete, onError: completer.completeError)
- .whenComplete(() {
- if (_carInvoicesInFlight == completer) {
- _carInvoicesInFlight = null;
- }
- }),
- );
- return completer.future;
- }
+ getCurrentCarResearchInvoices() => client.getCurrentCarResearchInvoices();
// -- Customer key --
@@ -115,7 +64,9 @@ class ShopInBitService {
/// New tickets are hydrated and inserted; existing tickets are patched.
Future<void> refreshAll() async {
final String key = await ensureCustomerKey();
- final ApiResponse<List<TicketRef>> resp = await _ticketsByCustomer(key);
+ final ApiResponse<List<TicketRef>> resp = await client.getTicketsByCustomer(
+ key,
+ );
if (resp.hasError || resp.value == null) {
Logging.instance.w(
"ShopInBitService.refreshAll: failed to fetch ticket list",
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.