# Session & Flash Data

The `Session` facade provides flash data that survives exactly one navigation hop, letting you pass form input and validation errors across a back-navigation without temporary controller state.

- [Introduction](#introduction)
- [Flashing Input](#flashing-input)
- [Flashing Errors](#flashing-errors)
- [Reading Old Input](#reading-old-input)
- [Automatic Flash in MagicFormData](#automatic-flash-in-magicformdata)
- [Advancing the Flash Bucket](#advancing-the-flash-bucket)
- [Testing](#testing)

## Introduction

The `Session` facade provides Laravel-style flash data that survives exactly one navigation hop. Use it to repopulate a form after a failed submit and a back navigation without wiring temporary state through controllers, the router, or global singletons.

The store has two buckets: the **current** bucket (readable by the view being built right now) and the **next** bucket (being collected by the currently-active handler). A call to `Session.tick()` promotes `next` into `current`, so flashed data is visible on exactly one frame.

## Flashing Input

Flash a map of values before navigating away:

```dart
Session.flash({
  'name': 'John',
  'email': 'john@test.com',
});
MagicRoute.back();
```

## Flashing Errors

Flash per-field error messages:

```dart
Session.flashErrors({
  'email': ['The email has already been taken.'],
});
```

## Reading Old Input

In the form view, repopulate via the `old()` helper:

```dart
WFormInput(
  initialValue: old('email') ?? '',
);

if (Session.hasError('email'))
  WText(Session.error('email')!, className: 'text-red-500');
```

`Session.oldRaw(field)` returns the original typed value (booleans, numbers, custom objects) instead of stringifying it.

## Automatic Flash in MagicFormData

`MagicFormData.validate()` automatically flashes the current form data when validation fails, so you never need to wire it manually:

```dart
void _submit() {
  if (!form.validate()) return; // form data is auto-flashed on failure
  controller.register(form.data);
}
```

After a back navigation and a `Session.tick()`, `old('email')` returns the last-submitted value.

## Advancing the Flash Bucket

Flash data survives exactly one navigation. Advance the bucket only when the router location actually changes. Do **not** wire `Session.tick` directly to the router delegate listener: the delegate can notify for more than real navigation (redirect re-evaluation, notifier rebuilds) and would expire flash data prematurely.

```dart
var lastLocation = MagicRouter.instance.currentLocation;

MagicRouter.instance.routerConfig.routerDelegate.addListener(() {
  final currentLocation = MagicRouter.instance.currentLocation;
  if (currentLocation == lastLocation) return;
  lastLocation = currentLocation;
  Session.tick();
});
```

Place this in a `ServiceProvider.boot()` after `Magic.init()` completes.

## Testing

In tests, always reset the store in `setUp()`:

```dart
setUp(() {
  MagicApp.reset();
  Magic.flush();
  Session.reset();
});
```

Swap the backing store with a custom `SessionStore` via `Session.setStore(store)` if you need isolated buckets per test group.
