diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a2d585..543461b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### ✨ Features - **Router Observers**: `MagicRouter.instance.addObserver()` enables NavigatorObserver integration for analytics/monitoring (Sentry, Firebase Analytics, custom observers). Observers are passed to GoRouter automatically. (#31) +- **Network Driver Plugin Hook**: `DioNetworkDriver.configureDriver()` exposes the underlying Dio instance for SDK integrations (sentry_dio, certificate pinning, custom adapters). (#32) ## [1.0.0-alpha.6] - 2026-04-05 diff --git a/doc/basics/http-client.md b/doc/basics/http-client.md index 034ba09..d4a254f 100644 --- a/doc/basics/http-client.md +++ b/doc/basics/http-client.md @@ -299,3 +299,17 @@ class NetworkServiceProvider extends ServiceProvider { } } ``` + +### Driver Plugin Hook + +For SDK integrations that need direct Dio access (e.g., `sentry_dio` for performance tracing, certificate pinning), use `configureDriver()`: + +```dart +final driver = Magic.make('network'); +driver.configureDriver((dio) { + dio.addSentry(); // Full Sentry performance tracing +}); +``` + +> [!NOTE] +> `configureDriver()` is specific to `DioNetworkDriver`. Resolve using `Magic.make('network')` to access it. diff --git a/lib/src/network/drivers/dio_network_driver.dart b/lib/src/network/drivers/dio_network_driver.dart index 6a2a9fb..f3ea815 100644 --- a/lib/src/network/drivers/dio_network_driver.dart +++ b/lib/src/network/drivers/dio_network_driver.dart @@ -109,6 +109,21 @@ class DioNetworkDriver implements NetworkDriver { ); } + /// Configure the underlying Dio instance directly. + /// + /// Use this for SDK integrations that need raw Dio access + /// (e.g., `sentry_dio`, certificate pinning, custom adapters). + /// + /// ```dart + /// final driver = Magic.make('network'); + /// driver.configureDriver((dio) { + /// dio.addSentry(); + /// }); + /// ``` + void configureDriver(void Function(Dio dio) configurator) { + configurator(_dio); + } + // --------------------------------------------------------------------------- // RESTful Resource Methods // --------------------------------------------------------------------------- diff --git a/skills/magic-framework/references/http-network.md b/skills/magic-framework/references/http-network.md index b812fc6..5d5c2ac 100644 --- a/skills/magic-framework/references/http-network.md +++ b/skills/magic-framework/references/http-network.md @@ -315,6 +315,20 @@ await Magic.init(); Magic.make('network').addInterceptor(LoggingInterceptor()); ``` +## Driver Plugin Hook + +For SDK integrations that need direct Dio access (e.g., `sentry_dio`, certificate pinning), use `configureDriver()`: + +```dart +// In a service provider boot() +final driver = Magic.make('network'); +driver.configureDriver((dio) { + dio.addSentry(); // sentry_dio integration +}); +``` + +This is a `DioNetworkDriver`-specific method (not on the `NetworkDriver` contract). Cast or resolve as `DioNetworkDriver` to access it. + ## ValidatesRequests Mixin Use the `ValidatesRequests` mixin in controllers to simplify validation error mapping from HTTP responses. diff --git a/test/network/network_test.dart b/test/network/network_test.dart index 4487979..0be9636 100644 --- a/test/network/network_test.dart +++ b/test/network/network_test.dart @@ -104,6 +104,51 @@ void main() { // Should not throw driver.addInterceptor(interceptor); }); + + test('configureDriver() mutates the driver-owned Dio instance', () { + late int countBefore; + + driver.configureDriver((dio) { + countBefore = dio.interceptors.length; + dio.interceptors.add( + InterceptorsWrapper( + onRequest: (options, handler) => handler.next(options), + ), + ); + }); + + // Verify interceptor persists on the same Dio instance. + late int countAfter; + driver.configureDriver((dio) { + countAfter = dio.interceptors.length; + }); + + expect(countAfter, countBefore + 1); + }); + + test('configureDriver() allows multiple configurators', () { + late int countAfterFirst; + late int countAfterSecond; + + driver.configureDriver((dio) { + dio.interceptors.add( + InterceptorsWrapper( + onRequest: (options, handler) => handler.next(options), + ), + ); + countAfterFirst = dio.interceptors.length; + }); + driver.configureDriver((dio) { + dio.interceptors.add( + InterceptorsWrapper( + onRequest: (options, handler) => handler.next(options), + ), + ); + countAfterSecond = dio.interceptors.length; + }); + + expect(countAfterSecond, countAfterFirst + 1); + }); }); }