import 'dart:convert'; import 'dart:io'; import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; import '../cors_headers.dart'; import '../firebase_auth.dart'; import '../trading/trading_dev_actions.dart'; const String tradingDevBasePath = '/v1/me/trading/dev'; /// Dev-only HTTP endpoints to exercise the trading flow without waiting for /// real market conditions. Mounted only when `TRADING_DEV_ENDPOINTS_ENABLED=true`. /// /// Endpoints: /// * `POST /v1/me/trading/dev/force-fire` — seeds dipped snapshots for the /// caller and runs one [TradingPipeline.evaluate] cycle. The next worker /// tick (or an immediate SignalR push from `createAndDeliverQuestion`) /// surfaces the question in the Flutter UI. Handler tradingDevHandler({ required FirebaseAuthVerifier auth, required TradingDevActions devActions, }) { final Router router = Router(); router.post('$tradingDevBasePath/force-fire', (Request request) async { final String? firebaseUid = await _verify(auth, request); if (firebaseUid == null) { return _jsonResponse(401, {'error': 'Unauthorized'}); } try { final ForceFireResult result = await devActions.forceFireDip(firebaseUid); return _jsonResponse(200, result.toJson()); } catch (e, st) { stderr.writeln('trading dev force-fire failed for $firebaseUid: $e\n$st'); return _jsonResponse(500, {'error': 'Internal error'}); } }); return (Request request) async { if (request.method == 'OPTIONS') { return Response.ok('', headers: apiCorsHeaders()); } return router.call(request); }; } Future _verify(FirebaseAuthVerifier auth, Request request) { return auth.verifyBearerToken( request.headers['Authorization'] ?? request.headers['authorization'], ); } Response _jsonResponse(int status, Map body) { return Response( status, body: jsonEncode(body), headers: { ...apiCorsHeaders(), 'Content-Type': 'application/json', }, ); }