ec0c10f312
ApiClient.buildDio takes on401; the library's dioProvider wires it to the auth controller's clearSession. The router redirect already handles navigation away from authed screens once the session goes null. HomeScreen surfaces the banner on connection_refused with Retry + Change URL.
42 lines
1.3 KiB
Dart
42 lines
1.3 KiB
Dart
import 'package:dio/dio.dart';
|
|
|
|
typedef TokenResolver = Future<String?> Function();
|
|
typedef OnUnauthenticated = Future<void> Function();
|
|
|
|
class ApiClient {
|
|
/// Builds a dio instance pinned to [baseUrl] with a Bearer-auth
|
|
/// interceptor that pulls the current token from [tokenResolver]
|
|
/// on every request. Server already supports cookie OR bearer
|
|
/// (internal/auth/session.go); we use bearer to skip cookie-jar.
|
|
///
|
|
/// [on401] fires when any response comes back 401. Use it to clear
|
|
/// stored credentials so the router redirect can route back to login.
|
|
static Dio buildDio({
|
|
required String baseUrl,
|
|
required TokenResolver tokenResolver,
|
|
OnUnauthenticated? on401,
|
|
}) {
|
|
final d = Dio(BaseOptions(
|
|
baseUrl: baseUrl,
|
|
connectTimeout: const Duration(seconds: 8),
|
|
receiveTimeout: const Duration(seconds: 30),
|
|
contentType: Headers.jsonContentType,
|
|
responseType: ResponseType.json,
|
|
));
|
|
d.interceptors.add(InterceptorsWrapper(
|
|
onRequest: (opts, h) async {
|
|
final t = await tokenResolver();
|
|
if (t != null && t.isNotEmpty) opts.headers['Authorization'] = 'Bearer $t';
|
|
h.next(opts);
|
|
},
|
|
onError: (e, h) async {
|
|
if (e.response?.statusCode == 401 && on401 != null) {
|
|
await on401();
|
|
}
|
|
h.next(e);
|
|
},
|
|
));
|
|
return d;
|
|
}
|
|
}
|