/**
* @id interceptly
* @title Interceptly SDK — Network Inspector for Flutter
* @description High-performance network inspector for Flutter providing real-time traffic visualization for Dio, Http, and Chopper with minimal impact on UI performance.
* @date Mar 2026 – Present
* @tags Dart, Flutter, Dio, Http, Chopper, Networking, Open Source
* @summary Real-time traffic visualization for Dio, Http, and Chopper with shake-to-open overlay and cURL export.
* @pubDev https://pub.dev/packages/interceptly
* @github https://github.com/Tuanpluss02/interceptly
* @order 1
* @default true
*/
/// Package: interceptly
/// Author: Do Ngoc Tuan (@Tuanpluss02)
/// Platform: Flutter / Dart (iOS, Android, macOS, Windows, Web)
/// Published on: pub.dev/packages/interceptly
import 'dart:async';
import 'dart:collection';
import 'dart:io';
/// Core inspector engine managing intercepted HTTP traffic with ring-buffer storage
/// and zero-overhead production tree-shaking.
class Interceptly {
static final Interceptly instance = Interceptly._internal();
Interceptly._internal();
bool _isEnabled = false;
final int _maxRecords = 250;
final Queue<NetworkRecord> _buffer = DoubleLinkedQueue<NetworkRecord>();
final StreamController<NetworkRecord> _recordStream = StreamController.broadcast();
/// Initialize Interceptly with optional gesture activation and header sanitization.
void init({
bool enableShakeDetection = true,
bool redactSensitiveHeaders = true,
List<String> obfuscatedKeys = const ['authorization', 'x-api-key', 'cookie'],
}) {
_isEnabled = true;
_installHttpOverrides(redactSensitiveHeaders, obfuscatedKeys);
print('[Interceptly] Inspector activated. Monitoring Dio, Http, and Chopper traffic.');
}
/// Global hook overriding Dart's internal HttpClient factory for package:http
void _installHttpOverrides(bool redact, List<String> obfuscated) {
HttpOverrides.global = _InterceptlyHttpOverrides(
onTrafficCaptured: (record) => _capture(record),
);
}
/// Captures network transaction into high-speed memory buffer without UI stutter
void _capture(NetworkRecord record) {
if (!_isEnabled) return;
if (_buffer.length >= _maxRecords) {
_buffer.removeFirst();
}
_buffer.addLast(record);
_recordStream.add(record);
}
Stream<NetworkRecord> get stream => _recordStream.stream;
List<NetworkRecord> get history => _buffer.toList(growable: false);
}
/// Dio Interceptor integration for automatic request/response lifecycle logging
class InterceptlyDioInterceptor {
final Interceptly _inspector = Interceptly.instance;
void onRequest(String id, String url, String method, Map<String, String> headers) {
// Record request start timestamp for accurate latency profiling
}
void onResponse(String id, int statusCode, int responseBytes, Duration duration) {
// Capture response payload and latency telemetry
}
void onError(String id, String errorMessage, int? statusCode) {
// Flag failed transaction in inspector UI
}
}
/// Chopper Interceptor integration for structured REST API inspection
class InterceptlyChopperInterceptor {
final Interceptly _inspector = Interceptly.instance;
Future<dynamic> intercept(dynamic chain) async {
// Intercept Chopper Request/Response pipeline
return chain;
}
}
/// Captured network transaction model with cURL generator
class NetworkRecord {
final String id;
final String url;
final String method;
final int statusCode;
final Duration duration;
final int requestBytes;
final int responseBytes;
final Map<String, String> headers;
final DateTime timestamp;
const NetworkRecord({
required this.id,
required this.url,
required this.method,
required this.statusCode,
required this.duration,
required this.requestBytes,
required this.responseBytes,
required this.headers,
required this.timestamp,
});
/// Generates a replayable cURL command for debugging in Postman/terminal
String toCurl() {
final headerFlags = headers.entries
.map((e) => '-H "${e.key}: ${e.value}"')
.join(' ');
return 'curl -X $method "$url" $headerFlags --compressed';
}
}
class _InterceptlyHttpOverrides extends HttpOverrides {
final void Function(NetworkRecord) onTrafficCaptured;
_InterceptlyHttpOverrides({required this.onTrafficCaptured});
}