feat(block2): offline outbox — share now, publish when connected
Sender-side offline delivery hardening.
- OfferOutbox: a keystore-backed (no plaintext) queue of lot ids to publish
later. Stores ids, not offers, so on flush each offer is rebuilt from the
lot's CURRENT state — an offline edit is respected, a deleted lot drops out.
- flushOutbox(): on reconnect, republishes queued lots and clears them (no-op
offline; drops ids whose lot is gone).
- Market screen: sharing offline parks the lots ('we'll share these when you're
connected'); opening the market online auto-flushes the queue first.
- Wired via DI + TaneApp(outbox); i18n en/es/pt.
Tests: 4 outbox + 3 flush + market UI, 20 green. Analyzer clean for new code.
This commit is contained in:
parent
2a6b4b0947
commit
cf5d0243ee
15 changed files with 222 additions and 8 deletions
37
apps/app_seeds/lib/services/offer_outbox.dart
Normal file
37
apps/app_seeds/lib/services/offer_outbox.dart
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import '../security/secret_store.dart';
|
||||
|
||||
/// A durable "to publish when connected" queue of lot ids. When sharing is
|
||||
/// attempted offline, the lot ids are parked here (keystore-backed, so no
|
||||
/// plaintext at rest) and flushed once a relay is reachable — offline delivery
|
||||
/// for the sender side.
|
||||
///
|
||||
/// We store lot ids, not serialized offers: on flush the offer is rebuilt from
|
||||
/// the lot's current state, so an edit made while offline is respected and a
|
||||
/// since-deleted lot simply drops out.
|
||||
class OfferOutbox {
|
||||
OfferOutbox(this._store);
|
||||
|
||||
final SecretStore _store;
|
||||
static const _key = 'tane.social.outbox';
|
||||
|
||||
/// Lot ids waiting to be published.
|
||||
Future<Set<String>> pending() async {
|
||||
final raw = await _store.read(_key);
|
||||
if (raw == null || raw.isEmpty) return <String>{};
|
||||
return raw.split('\n').where((s) => s.isNotEmpty).toSet();
|
||||
}
|
||||
|
||||
Future<void> enqueue(Iterable<String> lotIds) async {
|
||||
final next = await pending()..addAll(lotIds);
|
||||
await _write(next);
|
||||
}
|
||||
|
||||
Future<void> remove(Iterable<String> lotIds) async {
|
||||
final next = await pending()..removeAll(lotIds.toSet());
|
||||
await _write(next);
|
||||
}
|
||||
|
||||
Future<void> clear() => _store.write(_key, '');
|
||||
|
||||
Future<void> _write(Set<String> ids) => _store.write(_key, ids.join('\n'));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue