Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
14 changes: 14 additions & 0 deletions doc/basics/http-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<DioNetworkDriver>('network');
driver.configureDriver((dio) {
dio.addSentry(); // Full Sentry performance tracing
});
```

> [!NOTE]
> `configureDriver()` is specific to `DioNetworkDriver`. Resolve using `Magic.make<DioNetworkDriver>('network')` to access it.
15 changes: 15 additions & 0 deletions lib/src/network/drivers/dio_network_driver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<DioNetworkDriver>('network');
/// driver.configureDriver((dio) {
/// dio.addSentry();
/// });
/// ```
void configureDriver(void Function(Dio dio) configurator) {
configurator(_dio);
}

// ---------------------------------------------------------------------------
// RESTful Resource Methods
// ---------------------------------------------------------------------------
Expand Down
14 changes: 14 additions & 0 deletions skills/magic-framework/references/http-network.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,20 @@ await Magic.init();
Magic.make<NetworkDriver>('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<DioNetworkDriver>('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.
Expand Down
45 changes: 45 additions & 0 deletions test/network/network_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
}

Expand Down