initialize static method

Future<void> initialize({
  1. required String url,
  2. Dio? dio,
  3. StorageInterface? store,
  4. String? scheme,
  5. bool refreshSessionOnAppResume = true,
  6. bool refreshSessionOnReconnect = true,
})

Implementation

static Future<void> initialize({
  required String url,
  Dio? dio,
  StorageInterface? store,

  /// Native deep-link scheme, for example `myapp`.
  ///
  /// Required for native social authentication. It is sent to Better Auth as
  /// `expo-origin` and used as the default OAuth callback scheme.
  String? scheme,

  /// Refresh the auth stream whenever the app returns to the foreground.
  bool refreshSessionOnAppResume = true,

  /// Refresh the auth stream whenever the device regains network
  /// connectivity (offline -> online transition). Mirrors the Expo
  /// online-manager behavior.
  bool refreshSessionOnReconnect = true,
}) async {
  if (_initialized) return;
  baseUrl = url;
  appScheme = scheme;
  if (store == null && !kIsWeb) {
    // Encrypted, chunked cookie persistence by default on native platforms.
    storage = SecureStorage();
  } else {
    storage = store;
  }
  dioClient =
      dio ??
      Dio(
        BaseOptions(
          headers: {
            'content-type': 'application/json',
            if (!kIsWeb) 'user-agent': 'FlutterBetterAuth/1.0.0',
          },
          validateStatus: (status) => status != null && status < 300,
        ),
      );
  final origin = scheme == null || scheme.isEmpty ? null : '$scheme://';
  dioClient.options.headers.putIfAbsent('content-type', () => 'application/json');
  if (!kIsWeb) {
    dioClient.options.headers.putIfAbsent(
      'user-agent',
      () => 'FlutterBetterAuth/1.0.0',
    );
  }
  dioClient.options.headers['x-skip-oauth-proxy'] = 'true';
  if (origin != null) {
    dioClient.options.headers['expo-origin'] = origin;
  }
  cookieJar = CustomPersistCookieJar(
    store: storage,
    storage: MemoryStorage(),
  );
  if (kIsWeb) {
    // The browser owns the Cookie header; let it persist/send cookies.
    enableWebCredentials(dioClient);
  } else {
    dioClient.interceptors.add(CookieManager(cookieJar));
  }
  // Bearer-token fallback (works cross-origin where cookies are blocked).
  try {
    _bearerToken = await _bearerStore.read(key: _bearerKey);
  } catch (_) {
    _bearerToken = null;
  }
  dioClient.interceptors.add(BearerTokenInterceptor());
  dioClient.interceptors.add(RemoveNullsInterceptor());
  dioClient.interceptors.add(
    InterceptorsWrapper(
      onResponse: (response, handler) async {
        final path = response.requestOptions.path;
        if (response.statusCode == 200) {
          if (path.contains('/sign-in') ||
              path.contains('/sign-up') ||
              path.contains('/update-user') ||
              path.contains('/change-email') ||
              path.contains('/change-password')) {
            unawaited(_refreshSession());
          } else if (path.contains('/sign-out')) {
            await cookieJar.clearFor(Uri.parse(baseUrl));
            setBearerToken(null);
            _authStreamController.add(null);
          }
        }
        handler.next(response);
      },
      onError: (error, handler) {
        if (error.response?.statusCode == 401) {
          _authStreamController.add(null);
        }
        handler.next(error);
      },
    ),
  );
  _client = BetterAuthClient(dioClient, baseUrl: baseUrl);
  _initialized = true;
  if (refreshSessionOnAppResume) {
    _lifecycleObserver = _BetterAuthLifecycleObserver();
    WidgetsBinding.instance.addObserver(_lifecycleObserver!);
  }
  if (refreshSessionOnReconnect && !kIsWeb) {
    _wasOnline = true;
    _connectivitySub = Connectivity().onConnectivityChanged.listen((results) {
      final online = results.any((r) => r != ConnectivityResult.none);
      // Only refetch on the offline -> online edge, not every change.
      if (online && !_wasOnline) {
        unawaited(_refreshSession());
      }
      _wasOnline = online;
    });
  }
}