## 2.1.0

### Authentication Service

- [NEW] Added `AuthenticationStatus.unknown` as the new default authentication state (replaces `unauthenticated` as default).
- [NEW] Added `AuthenticationStatus.isUnknown` getter to explicitly check for unknown state.
- [CHANGE] `AuthenticationStatus.isUnauthenticated` now returns `true` for both `unauthenticated` and `unknown` states (use `isUnknown` to distinguish).
- [CHANGE] `ArcaneAuthenticationService` now initializes with `AuthenticationStatus.unknown` instead of `unauthenticated`.
- [CHANGE] `ArcaneAuthenticationService.reset()` now resets status to `unknown`.
- [CHANGE] Updated tests to reflect new default status behavior.

## 2.0.6

### Arcane Framework

- [BREAKING] This package no longer exports the `Error` and `Ok` symbols from
  the `result_monad` package.

#### Migration Steps (`Error`/`Ok`)

1. Add the `result_monad` package to your `pubspec.yaml` file.
2. Use the import `import 'package:result_monad/result_monad.dart';` to access
   `Error` and `Ok` symbols.

## 2.0.5

### Arcane Framework

- [NEW] Added `Arcane.service` typed lookup entrypoint for provider-aware
  service access:
  - `Arcane.service.ofType<T>(context)`
  - `Arcane.service.requiredOfType<T>(context)`

## 2.0.4

### Logging Service

- [NEW] Added `LogInterceptorCallback` typedef and updated `LogInterceptor`
  callback-based APIs to use the shared callback type alias.

## 2.0.3

### Logging Service

- [CHANGE] `LogEvent` JSON serialization now delegates recursive nested
  `metadata` / `extra` encode-decode handling to `arcane_helper_utils` JSON
  extensions (`toJsonValue`, `toJsonMap`, `fromJsonValue`, `fromJsonMap`).
- [CHANGE] Refactored `LogInterceptor` to an interface-style contract with a
  factory constructor for callback interceptors, so reusable class-based
  interceptors can be implemented without superclass callback plumbing.

## 2.0.2

### Logging Service

- [BREAKING] Replaced the `@LoggingFeature(...)` annotation (compile-time only,
  not readable at runtime in Flutter) with the `LoggerName` mixin.
  Mix `LoggerName` into a `LoggingInterface` subclass and override
  `name` to expose a runtime-accessible name inside `log()`.

#### Migration Steps (LoggingFeature)

1. Replace any `@LoggingFeature("...")` annotation with `with LoggerName` and
   add an `@override String get name => '...';` getter to the class body.

Before:

```dart
@LoggingFeature("my-feature")
class MyLogger extends LoggingInterface {...}
```

After:

```dart
class MyLogger extends LoggingInterface with LoggerName {
  @override
  String get name => "my-feature";
}
```

## 2.0.1

### Arcane Framework

- [NEW] `ArcaneApp` now owns and publishes a live service registry for
  provider-aware static lookups.
- [CHANGE] `Arcane.features`, `Arcane.auth`, `Arcane.theme`, and
  `Arcane.environment` now prefer the live `ArcaneApp` registry instance when
  available, then fall back to built-in singletons.
- [BREAKING] `Arcane` is now a static utility surface (no instantiable
  singleton constructor).
- [BREAKING] Several `package:arcane_framework/src/...` import paths changed
  (for example, `src/providers/...` -> `src/service/...` and
  `src/services/reactive_theme/...` -> `src/services/theme/...`). Consumers
  importing from `src` directly must update import paths.
- [NEW] Added optional `ArcaneApp.builder` callback (TransitionBuilder style)
  for capturing provider-aware build contexts from within `ArcaneApp`.
- [DEPRECATED] `ArcaneApp.child` is now deprecated in favor of
  `ArcaneApp.builder` (legacy child usage remains supported during migration).
- [DEPRECATED] `BuildContext.serviceOfType<T>()` is now deprecated in favor of
  `BuildContext.service<T>()`.

### Environment Service

- [NEW] Added `ArcaneEnvironmentService` as a singleton `ArcaneService` instance.
- [CHANGE] Changed `ArcaneEnvironment` is no longer a `Cubit` and is now an
  `InheritedWidget`.
- [NEW] Added `Arcane.environment` shortcut for direct environment access.
- [NEW] Added environment service to `Arcane.services` built-in list.
- [CHANGE] `ArcaneEnvironmentProvider` is now a `StatefulWidget` instead of a
  `StatelessWidget` with a `BlocProvider`.
- [NEW] `ArcaneEnvironmentProvider` now provides methods for
  `enableDebugMode()`, `disableDebugMode()` and `setEnvironment()`.
- [NEW] Added `environmentChanges` stream for realtime environment updates.

#### Migration Steps (ArcaneEnvironment)

1. The `state` getter has been removed from `ArcaneEnvironment`. If you previously accessed environment state via `Arcane.environment.state`, update your code to use the new API:

   - **Before:**

     ```dart
     final env = Arcane.environment.state;
     ```

   - **After:**

     ```dart
     final env = Arcane.environment.current;
     ```

2. If you were using `Cubit`-style APIs, migrate to the new `InheritedWidget`/`ValueNotifier`-based approach. See the README for updated usage examples.

### Authentication Service

- [BREAKING] `ArcaneAuthInterface.logout` now accepts optional
  `onLoggedOut` callback parameters. `ArcaneAuthInterface` implementers must
  update logout signature to accept optional `onLoggedOut`. See the migration
  steps for further details.
- [NEW] Added `statusChanges` stream to observe `AuthenticationStatus` updates.
- [NEW] Added `signedInChanges` stream to observe sign-in state changes.
- [FIX] Added stream lifecycle cleanup in `dispose` with safe lazy recreation.

#### Migration Steps (ArcaneAuthInterface)

1. Update `ArcaneAuthInterface` implementations to accept the new optional
   `onLoggedOut` callback parameter in `logout(...)`.
2. If your implementation performs cleanup side effects on logout, invoke
   `onLoggedOut` when provided.
3. Run tests to confirm your authentication adapter still satisfies your
   login/logout flows.

Before:

```dart
@override
Future<Result<void, String>> logout() async {
  // ...
  return Result.ok(null);
}
```

After:

```dart
@override
Future<Result<void, String>> logout({
  Future<void> Function()? onLoggedOut,
}) async {
  // ...
  if (onLoggedOut != null) await onLoggedOut();
  return Result.ok(null);
}
```

### Feature Flag Service

- [CHANGE] Renamed service class `ArcaneFeatureFlags` to
  `ArcaneFeatureFlagService`.
- [NEW] Added backward compatibility typedef:
  `typedef ArcaneFeatureFlags = ArcaneFeatureFlagService`.
- [NEW] Added `enabledFeaturesChanges` stream to observe enabled feature
  updates in realtime.
- [FIX] Added stream lifecycle cleanup in `dispose` with safe lazy recreation.
- [NEW] Added `ArcaneFeatureFlagProvider` (`InheritedWidget`) and
  `ArcaneFeatureFlagsProvider` (`StatefulWidget`) for first-class feature-flag
  integration in the widget tree.
- [DEPRECATED] `ArcaneFeatureFlagsScope` has been renamed to
  `ArcaneFeatureFlagProvider`.
- [NEW] Added `BuildContext` convenience accessors for feature flags, including
  `context.featureFlags`, `context.maybeFeatureFlags`,
  `context.isFeatureEnabled(...)`, and `context.isFeatureDisabled(...)`.
- [NEW] `ArcaneApp` now includes `ArcaneFeatureFlagsProvider` by default,
  enabling rebuilds for widgets that depend on
  `ArcaneFeatureFlagProvider.of(context)`.
- [UPDATE] README now documents `ArcaneFeatureFlagProvider` and `ArcaneApp`
  provider composition.

### Theme Service

- [CHANGE] Renamed `ArcaneReactiveTheme` to `ArcaneThemeService` for clearer
  naming.
- [NEW] Added backward compatibility typedef:
  `typedef ArcaneReactiveTheme = ArcaneThemeService`.
- [FIX] Theme initialization now respects `ThemeMode.system` and initializes
  `ThemeData` using the effective brightness.
- [FIX] `ArcaneThemeSwitcher` now initializes system-follow behavior once on
  first dependency resolution.
- [FIX] `ArcaneThemeSwitcher` now defaults to `followSystemTheme(context)` when
  mounted under `ArcaneApp`, so system-follow is enabled by default and system
  brightness changes are handled framework-side (no app-level observer needed).
- [FIX] `switchTheme()` now toggles from the effective theme when current mode
  is `ThemeMode.system` (system dark -> light, system light -> dark).
- [CHANGE] `context.isDarkMode` now reflects effective app theme brightness
  (`Theme.of(context).brightness`) instead of raw platform brightness.
- [FIX] `followSystemTheme()` now reads platform brightness directly to avoid
  coupling system-follow behavior to app theme overrides.
- [NEW] Added assignment-style theme setters: `Arcane.theme.dark = ...` and
  `Arcane.theme.light = ...` (in addition to `setDarkTheme` /
  `setLightTheme`).
- [FIX] Reactive theme stream controllers now close only during service dispose,
  preventing stream shutdown when a single subscriber cancels.
- [FIX] Setting a theme (e.g., dark) while in the opposite mode (e.g., light) no
  longer changes the current brightness or rendered theme. Only the active
  mode's theme updates the rendered appearance.
- [NEW] Added `themeModeChanges` and `themeDataChanges` streams for realtime
  theme updates.

#### Migration Steps (ArcaneThemeService)

1. Replace legacy `ThemeMode` reads from `Arcane.theme.systemTheme.value` with
  `Arcane.theme.currentModeOf(context)` when configuring app `themeMode`.

Before:

```dart
MaterialApp(
  theme: Arcane.theme.light,
  darkTheme: Arcane.theme.dark,
  themeMode: Arcane.theme.systemTheme.value,
)
```

After:

```dart
MaterialApp(
  theme: Arcane.theme.light,
  darkTheme: Arcane.theme.dark,
  themeMode: Arcane.theme.currentModeOf(context),
)
```

### Arcane Logger

- [NEW] Added `logStream` for realtime log subscriptions.
- [NEW] Added explicit `dispose` cleanup for logger stream resources.
- [NEW] Added optional lifecycle capability via `LoggingInitializable` and
  `LoggingInitialization`.
- [NEW] Added optional `feature` tag support via `@LoggingFeature(...)`
  annotation.
- [NEW] Added a `skipAutodetection` parameter to `Arcane.log` (defaults to
  `false`) that, when enabled, skips detection of the `module`, `method`, and
  file/line number where logs originated from.
- [NEW] Added the `LogInterceptor` class which can (optionally) be added to
  `ArcaneLogger` to pre-process log messages before they are sent to the
  registered `ArcaneLoggingInterface`(s).
- [NEW] Added collection-style interceptor APIs:
  `Arcane.logger.interceptors.add(...)`,
  `Arcane.logger.interceptors.remove(...)`, and
  `Arcane.logger.interceptors.clear()` with an optional `matcher` for
  explicit type-scoped matching strategies, including subtype-inclusive
  matching.
- [CHANGE] Updated `Arcane.log` metadata type from `Map<String, String>?` to
  `Map<String, Object?>?` to support structured metadata values.
- [CHANGE] `initializeInterfaces()` now initializes only interfaces that
  implement `LoggingInitializable`; other interfaces are skipped.
- [BREAKING] `LoggingInterface` no longer includes built-in singleton-style
  initialization state.

#### Migration Steps (LoggingInterface)

1. Remove `initialized` and `init` from interfaces that do not require startup
  work.
2. If an interface requires startup/lifecycle management, add
  `LoggingInitialization` (or implement `LoggingInitializable`) and move
  setup logic into `init()`.
3. Update `log(...)` implementations to guard behavior with `initialized` only
  for interfaces that opted into initialization.
4. Run tests to verify interface registration and logging behavior still match
  expectations.

Before:

```dart
class DebugConsole implements LoggingInterface {
  @override
  bool get initialized => true;

  @override
  Future<LoggingInterface?> init() async => this;

  @override
  void log(String message, {Map<String, Object?>? metadata, Level? level}) {}
}
```

After:

```dart
class DebugConsole extends LoggingInterface {
  @override
  void log(String message, {Map<String, Object?>? metadata, Level? level}) {}
}
```

- For SDK-backed loggers, opt into initialization with the mixin.

```dart
class ExternalLogger extends LoggingInterface with LoggingInitialization {
  @override
  Future<void> init() async {
    if (initialized) return;
    // Start SDK.
    await super.init();
  }

  @override
  void log(String message, {Map<String, Object?>? metadata, Level? level}) {
    if (!initialized) return;
    // Send to SDK.
  }
}
```

- If desired, adopt `feature` for destination-aware filtering in interceptors.

#### Migration Steps (Arcane.log metadata)

1. Update `Arcane.log(...)` call sites that stringify metadata values only to
   satisfy the previous `Map<String, String>` type.
2. Prefer passing native values (for example `int`, `bool`, `List`, or nested
   `Map`) directly in `metadata` when useful.
3. If your logging destination expects only string metadata, convert
   `Object?` values to strings at your logging boundary.

Before:

```dart
Arcane.log(
  "Login attempt",
  metadata: {
    "attempt": attempt.toString(),
    "rememberMe": rememberMe.toString(),
  },
);
```

After:

```dart
Arcane.log(
  "Login attempt",
  metadata: {
    "attempt": attempt,
    "rememberMe": rememberMe,
  },
);
```

### Dependencies

- [CHANGE] Updated `result_monad` from `^2.3.2` to `^4.0.0`.
- [CHANGE] Removed direct `flutter_bloc` dependency.
- [CHANGE] Updated `collection` from `^1.18.0` to `^1.19.0`.

## 2.0.0

- Version redacted. Use v2.0.1.

## 1.2.7

- Updated dependencies to latest

## 1.2.6

- Updated dependencies to latest

## 1.2.5

- Improved automatic metadata detection in `ArcaneLogger`

## 1.2.4

- Update package dependencies

## 1.2.3

- Added `ValueNotifier`s to both the `ArcaneAuthenticationService` and
  `ArcaneFeatureFlags`. This enables the possibility of listening for changes to
  either service.

### Example

```dart
// Listen to changes in the authentication status
Arcane.auth.isSignedIn.addListener(() {
  if (Arcane.auth.isSignedIn.value) {
    Arcane.log("User is signed in");
  } else {
    Arcane.log("User is signed out");
  }
});

// Listen to changes in the enabled/disabled features
Arcane.features.notifier.addListener(() {
  Arcane.log("Enabled features have been updated: ${Arcane.features.notifier.value}");
});
```

## 1.2.2

- Lowered minimum required collection dependency version to prevent forcing
  users into the latest Flutter release

## 1.2.1

- Lowered minimum required SDK version to prevent forcing users into the latest
  Flutter release

## 1.2.0

- Removed flutter_secure_storage dependency as it was unused

### Breaking Changes

The following methods have been moved outside of the ArcaneAuthInterface base
class:

- resendVerificationCode
- register
- confirmSignup
- resetPassword

These methods have been moved to mixin classes. To continue using them, please
update your ArcaneAuthInterface implementations.

- To use `resendVerificationCode`, `register` and `confirmSignup`, use the new
  `ArcaneAuthAccountRegistration` mixin.
- To use `resetPassword`, use the new `ArcaneAuthPasswordManagement` mixin.

### Migration

In order to migrate your existing interfaces, update them from:

```dart
class MyAuthInterface implements ArcaneAuthInterface {}
```

to:

```dart
class MyAuthInterface
    with ArcaneAuthAccountRegistration, ArcaneAuthPasswordManagement
    implements ArcaneAuthInterface {}
```

If the methods that these mixins provide are not being used, the mixins can
safely be omitted. If only one of these mixins is required, the other can be
safely omitted.

This change should result in fewer lines of code for interface implementations
that do not require these additional features.

## 1.1.7

- Fixed an issue with the `ArcaneAuthenticationService` where an exception would
  be thrown when attempting to access an authentication token while no
  `ArcaneAuthInterface` was registered.

## 1.1.6

- Updated logging feature to indicate the feature which was enabled or disabled
  within the log message, instead of only in the metadata.

## 1.1.5

- Update package dependencies. No code changes.

## 1.1.4

- Update package dependencies. No code changes.

## 1.1.3

- Arcane Auth no longer throws exceptions when log out fails, instead returning
  a `Result<void, String>`. This behavior matches the login method.

## 1.1.2

- Removed Flutter exception handling from `ArcaneLoggingService`, as this
  functionality should be defined by a users' interface.

### Migration

Add the following to your `ArcaneLoggingInterface`'s `init` method to replicate
the previous behavior:

```dart
// Handles unhandled Flutter errors by logging them.
FlutterError.onError = (errorDetails) {
  Arcane.log(
    errorDetails.exceptionAsString(),
    level: Level.error,
    module: errorDetails.library,
    stackTrace: errorDetails.stack,
  );
};

// Handles unhandled platform-specific errors by logging them.
PlatformDispatcher.instance.onError = (error, stack) {
  Arcane.log(
    "$error",
    level: Level.error,
    stackTrace: stack,
  );
  return false;
};
```

## 1.1.1+2

- Updated example in README

## 1.1.1+1

- Updated example in README

## 1.1.1

- [BREAKING] Updated ArcaneAuthInterface to make the `resendVerificationCode`,
  `confirmSignup`, and `resetPassword` methods more versatile

Migration:

| Class               | Migration path                                                                                                                            |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| ArcaneAuthInterface | `resendVerificationCode(String email)` -> `resendVerificationCode<T>({T? input})`                                                         |
| ArcaneAuthInterface | `confirmSignup({String email, String password})` -> `confirmSignup({String? email, String? password})`                                    |
| ArcaneAuthInterface | `resetPassword({String email, String? newPassword, String? code})` -> `resetPassword({String? email, String? newPassword, String? code})` |

## 1.1.0

- [BREAKING] Updated the authentication service and interface to be more
  versatile

Migration:

| Class               | Migration path                                                                         |
| ------------------- | -------------------------------------------------------------------------------------- |
| ArcaneAuthInterface | `loginWtihEmailAndPassword({String email, String password})` -> `login<T>({T? input})` |
| ArcaneAuthInterface | `signup({String email, String password})` -> `register<T>({T? input})`                 |

## 1.0.8

- Added the `extra` parameter to the `Arcane.log` shortcut method

## 1.0.7

- Added the `extra` parameter to the `LoggingInterface`

## 1.0.6+1

- Migrated linting rules to new
  [arcane_analysis](https://pub.dev/packages/arcane_analysis) package.

## 1.0.6

- Removed get_it as a dependency

## 1.0.5+2

- Updated README and example project documentation

## 1.0.5+1

- Marked the `loginWithEmailAndPassword` method in `ArcaneAuthenticationService`
  as deprecated and updated example project

## 1.0.5

- Added the ability to use a generic type for the login method in
  ArcaneAuthenticationService
- Added the ability to reset the ArcaneAuthenticationService, which will
  unregister the current interface and clear the authentication state
- Removed unused testing tooling (e.g., `@visibleForTesting`) from the codebase
  - Migration guide: Remove usages of `setMocked` in your tests

## 1.0.4

- Resolved an issue with authentication using the ArcaneAuthenticationService
  when logging in with an email and password

## 1.0.3+1

- Added example project

## 1.0.3

- Added the ability to switch back to the normal environment from the debug
  environment in ArcaneEnvironment
- (breaking) Made the optional `onLoggedOut` callback a Future instead of a void
  function in ArcaneAuthenticationService
- Added additional error handling to the login method in
  ArcaneAuthenticationService
- Added support for following the system's theme in ArcaneTheme
- Removed the BuildContext parameter from the `switchTheme` method in
  ArcaneTheme

## 1.0.2

- Migrated ArcaneAuthenticationService's isSignedIn to a ValueListenable

## 1.0.1+1

- Removed ID and secure storage services to improve platform compatibility

## 1.0.0

- Initial release
